Commit | Line | Data |
---|---|---|
897ce52e KB |
1 | /* |
2 | * Copyright (c) 1988 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
cb956e54 | 5 | * %sccs.include.redist.c% |
897ce52e KB |
6 | */ |
7 | ||
8 | #ifndef lint | |
d41ff260 | 9 | static char sccsid[] = "@(#)sys_bsd.c 1.26 (Berkeley) %G%"; |
897ce52e KB |
10 | #endif /* not lint */ |
11 | ||
e767b7ab GM |
12 | /* |
13 | * The following routines try to encapsulate what is system dependent | |
14 | * (at least between 4.x and dos) which is used in telnet.c. | |
15 | */ | |
16 | ||
e767b7ab | 17 | |
344def17 | 18 | #include <fcntl.h> |
115a5494 | 19 | #include <sys/types.h> |
e767b7ab | 20 | #include <sys/time.h> |
b307f09e | 21 | #include <sys/socket.h> |
e767b7ab | 22 | #include <signal.h> |
b307f09e | 23 | #include <errno.h> |
6055a9f6 | 24 | #include <arpa/telnet.h> |
e767b7ab | 25 | |
115a5494 GM |
26 | #include "ring.h" |
27 | ||
807a3a7d GM |
28 | #include "fdset.h" |
29 | ||
e767b7ab GM |
30 | #include "defines.h" |
31 | #include "externs.h" | |
32 | #include "types.h" | |
33 | ||
87b60187 PB |
34 | #if defined(CRAY) |
35 | #define SIG_FUNC_RET void | |
36 | #else | |
37 | #define SIG_FUNC_RET int | |
38 | #endif | |
39 | ||
e767b7ab | 40 | int |
b307f09e GM |
41 | tout, /* Output file descriptor */ |
42 | tin, /* Input file descriptor */ | |
4ad36dea | 43 | net; |
e767b7ab | 44 | |
6055a9f6 PB |
45 | #ifndef USE_TERMIO |
46 | struct tchars otc = { 0 }, ntc = { 0 }; | |
47 | struct ltchars oltc = { 0 }, nltc = { 0 }; | |
48 | struct sgttyb ottyb = { 0 }, nttyb = { 0 }; | |
6570c863 | 49 | int olmode = 0; |
6055a9f6 | 50 | |
6055a9f6 PB |
51 | #else /* USE_TERMIO */ |
52 | struct termio old_tc = { 0 }; | |
53 | extern struct termio new_tc; | |
54 | ||
87b60187 PB |
55 | #ifndef TCGETA |
56 | #define TCGETA TIOCGETA | |
57 | #define TCSETA TIOCSETA | |
58 | #define TCSETAW TIOCSETAW | |
59 | #endif /* TCGETA */ | |
6055a9f6 | 60 | #endif /* USE_TERMIO */ |
e767b7ab | 61 | |
b307f09e GM |
62 | static fd_set ibits, obits, xbits; |
63 | ||
64 | ||
65 | init_sys() | |
66 | { | |
67 | tout = fileno(stdout); | |
68 | tin = fileno(stdin); | |
69 | FD_ZERO(&ibits); | |
70 | FD_ZERO(&obits); | |
71 | FD_ZERO(&xbits); | |
72 | ||
73 | errno = 0; | |
74 | } | |
75 | ||
e767b7ab | 76 | |
448f9c06 | 77 | TerminalWrite(buf, n) |
e767b7ab GM |
78 | char *buf; |
79 | int n; | |
80 | { | |
448f9c06 | 81 | return write(tout, buf, n); |
e767b7ab GM |
82 | } |
83 | ||
448f9c06 | 84 | TerminalRead(buf, n) |
e767b7ab GM |
85 | char *buf; |
86 | int n; | |
87 | { | |
448f9c06 | 88 | return read(tin, buf, n); |
e767b7ab GM |
89 | } |
90 | ||
91 | /* | |
92 | * | |
93 | */ | |
94 | ||
95 | int | |
310e7d0b | 96 | TerminalAutoFlush() |
e767b7ab GM |
97 | { |
98 | #if defined(LNOFLSH) | |
99 | int flush; | |
100 | ||
101 | ioctl(0, TIOCLGET, (char *)&flush); | |
102 | return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ | |
103 | #else /* LNOFLSH */ | |
104 | return 1; | |
105 | #endif /* LNOFLSH */ | |
106 | } | |
107 | ||
6055a9f6 PB |
108 | #ifdef KLUDGELINEMODE |
109 | extern int kludgelinemode; | |
110 | #endif | |
e767b7ab GM |
111 | /* |
112 | * TerminalSpecialChars() | |
113 | * | |
114 | * Look at an input character to see if it is a special character | |
115 | * and decide what to do. | |
116 | * | |
117 | * Output: | |
118 | * | |
119 | * 0 Don't add this character. | |
120 | * 1 Do add this character | |
121 | */ | |
122 | ||
123 | int | |
310e7d0b | 124 | TerminalSpecialChars(c) |
e767b7ab GM |
125 | int c; |
126 | { | |
310e7d0b | 127 | void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); |
e767b7ab | 128 | |
6055a9f6 | 129 | if (c == termIntChar) { |
e767b7ab GM |
130 | intp(); |
131 | return 0; | |
6055a9f6 PB |
132 | } else if (c == termQuitChar) { |
133 | #ifdef KLUDGELINEMODE | |
134 | if (kludgelinemode) | |
135 | sendbrk(); | |
136 | else | |
137 | #endif | |
138 | sendabort(); | |
e767b7ab | 139 | return 0; |
6055a9f6 PB |
140 | } else if (c == termEofChar) { |
141 | if (my_want_state_is_will(TELOPT_LINEMODE)) { | |
142 | sendeof(); | |
143 | return 0; | |
144 | } | |
145 | return 1; | |
146 | } else if (c == termSuspChar) { | |
147 | sendsusp(); | |
148 | return(0); | |
149 | } else if (c == termFlushChar) { | |
e767b7ab GM |
150 | xmitAO(); /* Transmit Abort Output */ |
151 | return 0; | |
152 | } else if (!MODE_LOCAL_CHARS(globalmode)) { | |
6055a9f6 | 153 | if (c == termKillChar) { |
e767b7ab GM |
154 | xmitEL(); |
155 | return 0; | |
6055a9f6 | 156 | } else if (c == termEraseChar) { |
e767b7ab GM |
157 | xmitEC(); /* Transmit Erase Character */ |
158 | return 0; | |
159 | } | |
160 | } | |
161 | return 1; | |
162 | } | |
163 | ||
164 | ||
165 | /* | |
166 | * Flush output to the terminal | |
167 | */ | |
168 | ||
169 | void | |
310e7d0b | 170 | TerminalFlushOutput() |
e767b7ab | 171 | { |
7daa10bf | 172 | #ifdef TIOCFLUSH |
e767b7ab | 173 | (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); |
6055a9f6 PB |
174 | #else |
175 | (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); | |
176 | #endif | |
e767b7ab GM |
177 | } |
178 | ||
179 | void | |
310e7d0b | 180 | TerminalSaveState() |
e767b7ab | 181 | { |
6055a9f6 | 182 | #ifndef USE_TERMIO |
e767b7ab GM |
183 | ioctl(0, TIOCGETP, (char *)&ottyb); |
184 | ioctl(0, TIOCGETC, (char *)&otc); | |
185 | ioctl(0, TIOCGLTC, (char *)&oltc); | |
6570c863 | 186 | ioctl(0, TIOCLGET, (char *)&olmode); |
e767b7ab GM |
187 | |
188 | ntc = otc; | |
189 | nltc = oltc; | |
190 | nttyb = ottyb; | |
0e29050b | 191 | |
6055a9f6 PB |
192 | #else /* USE_TERMIO */ |
193 | ioctl(0, TCGETA, &old_tc); | |
194 | ||
195 | new_tc = old_tc; | |
196 | ||
197 | termFlushChar = 'O'&0x37; | |
198 | termWerasChar = 'W'&0x37; | |
199 | termRprntChar = 'R'&0x37; | |
200 | termLiteralNextChar = 'V'&0x37; | |
201 | termStartChar = 'Q'&0x37; | |
202 | termStopChar = 'S'&0x37; | |
203 | #endif /* USE_TERMIO */ | |
204 | } | |
205 | ||
87b60187 | 206 | cc_t * |
6055a9f6 PB |
207 | tcval(func) |
208 | register int func; | |
209 | { | |
210 | switch(func) { | |
87b60187 PB |
211 | case SLC_IP: return(&termIntChar); |
212 | case SLC_ABORT: return(&termQuitChar); | |
213 | case SLC_EOF: return(&termEofChar); | |
214 | case SLC_EC: return(&termEraseChar); | |
215 | case SLC_EL: return(&termKillChar); | |
216 | case SLC_XON: return(&termStartChar); | |
217 | case SLC_XOFF: return(&termStopChar); | |
7daa10bf | 218 | #ifndef SYSV_TERMIO |
87b60187 PB |
219 | case SLC_AO: return(&termFlushChar); |
220 | case SLC_SUSP: return(&termSuspChar); | |
221 | case SLC_EW: return(&termWerasChar); | |
222 | case SLC_RP: return(&termRprntChar); | |
223 | case SLC_LNEXT: return(&termLiteralNextChar); | |
7daa10bf | 224 | #endif /* SYSV_TERMIO */ |
6055a9f6 PB |
225 | |
226 | case SLC_SYNCH: | |
227 | case SLC_BRK: | |
228 | case SLC_AYT: | |
229 | case SLC_EOR: | |
230 | case SLC_FORW1: | |
231 | case SLC_FORW2: | |
232 | default: | |
87b60187 | 233 | return((cc_t *)0); |
6055a9f6 PB |
234 | } |
235 | } | |
236 | ||
237 | void | |
238 | TerminalDefaultChars() | |
239 | { | |
240 | #ifndef USE_TERMIO | |
241 | ntc = otc; | |
242 | nltc = oltc; | |
243 | nttyb.sg_kill = ottyb.sg_kill; | |
244 | nttyb.sg_erase = ottyb.sg_erase; | |
245 | #else /* USE_TERMIO */ | |
246 | memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); | |
d41ff260 | 247 | # ifndef VDISCARD |
6055a9f6 | 248 | termFlushChar = 'O'&0x37; |
7daa10bf PB |
249 | # endif |
250 | # ifndef VWERASE | |
6055a9f6 | 251 | termWerasChar = 'W'&0x37; |
7daa10bf PB |
252 | # endif |
253 | # ifndef VREPRINT | |
6055a9f6 | 254 | termRprntChar = 'R'&0x37; |
7daa10bf PB |
255 | # endif |
256 | # ifndef VLNEXT | |
6055a9f6 | 257 | termLiteralNextChar = 'V'&0x37; |
7daa10bf PB |
258 | # endif |
259 | # ifndef VSTART | |
6055a9f6 | 260 | termStartChar = 'Q'&0x37; |
7daa10bf PB |
261 | # endif |
262 | # ifndef VSTOP | |
6055a9f6 | 263 | termStopChar = 'S'&0x37; |
7daa10bf | 264 | # endif |
6055a9f6 | 265 | #endif /* USE_TERMIO */ |
e767b7ab GM |
266 | } |
267 | ||
268 | void | |
310e7d0b | 269 | TerminalRestoreState() |
e767b7ab GM |
270 | { |
271 | } | |
272 | ||
273 | /* | |
274 | * TerminalNewMode - set up terminal to a specific mode. | |
6055a9f6 PB |
275 | * MODE_ECHO: do local terminal echo |
276 | * MODE_FLOW: do local flow control | |
277 | * MODE_TRAPSIG: do local mapping to TELNET IAC sequences | |
278 | * MODE_EDIT: do local line editing | |
279 | * | |
280 | * Command mode: | |
281 | * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG | |
282 | * local echo | |
283 | * local editing | |
284 | * local xon/xoff | |
285 | * local signal mapping | |
286 | * | |
287 | * Linemode: | |
288 | * local/no editing | |
289 | * Both Linemode and Single Character mode: | |
290 | * local/remote echo | |
291 | * local/no xon/xoff | |
292 | * local/no signal mapping | |
e767b7ab GM |
293 | */ |
294 | ||
295 | ||
296 | void | |
448f9c06 | 297 | TerminalNewMode(f) |
e767b7ab GM |
298 | register int f; |
299 | { | |
300 | static int prevmode = 0; | |
6055a9f6 PB |
301 | #ifndef USE_TERMIO |
302 | struct tchars tc; | |
303 | struct ltchars ltc; | |
e767b7ab | 304 | struct sgttyb sb; |
6570c863 | 305 | int lmode; |
6055a9f6 PB |
306 | #else /* USE_TERMIO */ |
307 | struct termio tmp_tc; | |
308 | #endif /* USE_TERMIO */ | |
e767b7ab GM |
309 | int onoff; |
310 | int old; | |
e767b7ab | 311 | |
6055a9f6 | 312 | globalmode = f&~MODE_FORCE; |
e767b7ab GM |
313 | if (prevmode == f) |
314 | return; | |
6055a9f6 PB |
315 | |
316 | /* | |
317 | * Write any outstanding data before switching modes | |
318 | * ttyflush() returns 0 only when there is no more data | |
319 | * left to write out, it returns -1 if it couldn't do | |
320 | * anything at all, otherwise it returns 1 + the number | |
321 | * of characters left to write. | |
322 | */ | |
323 | old = ttyflush(SYNCHing|flushout); | |
324 | if (old < 0 || old > 1) { | |
325 | #ifndef USE_TERMIO | |
326 | ioctl(tin, TIOCGETP, (char *)&sb); | |
327 | #else /* USE_TERMIO */ | |
328 | ioctl(tin, TCGETA, (char *)&tmp_tc); | |
329 | #endif /* USE_TERMIO */ | |
330 | do { | |
331 | /* | |
332 | * Wait for data to drain, then flush again. | |
333 | */ | |
334 | #ifndef USE_TERMIO | |
335 | ioctl(tin, TIOCSETP, (char *)&sb); | |
336 | #else /* USE_TERMIO */ | |
337 | ioctl(tin, TCSETAW, (char *)&tmp_tc); | |
338 | #endif /* USE_TERMIO */ | |
339 | old = ttyflush(SYNCHing|flushout); | |
340 | } while (old < 0 || old > 1); | |
341 | } | |
342 | ||
e767b7ab | 343 | old = prevmode; |
6055a9f6 PB |
344 | prevmode = f&~MODE_FORCE; |
345 | #ifndef USE_TERMIO | |
e767b7ab | 346 | sb = nttyb; |
6055a9f6 PB |
347 | tc = ntc; |
348 | ltc = nltc; | |
6570c863 | 349 | lmode = olmode; |
6055a9f6 PB |
350 | #else |
351 | tmp_tc = new_tc; | |
352 | #endif | |
353 | ||
354 | if (f&MODE_ECHO) { | |
355 | #ifndef USE_TERMIO | |
356 | sb.sg_flags |= ECHO; | |
357 | #else | |
358 | tmp_tc.c_lflag |= ECHO; | |
359 | tmp_tc.c_oflag |= ONLCR; | |
7daa10bf | 360 | # ifdef notdef |
6055a9f6 | 361 | tmp_tc.c_iflag |= ICRNL; |
7daa10bf | 362 | # endif |
6055a9f6 PB |
363 | #endif |
364 | } else { | |
365 | #ifndef USE_TERMIO | |
366 | sb.sg_flags &= ~ECHO; | |
367 | #else | |
368 | tmp_tc.c_lflag &= ~ECHO; | |
369 | tmp_tc.c_oflag &= ~ONLCR; | |
7daa10bf | 370 | # ifdef notdef |
6055a9f6 | 371 | tmp_tc.c_iflag &= ~ICRNL; |
7daa10bf | 372 | # endif |
6055a9f6 PB |
373 | #endif |
374 | } | |
e767b7ab | 375 | |
6055a9f6 PB |
376 | if ((f&MODE_FLOW) == 0) { |
377 | #ifndef USE_TERMIO | |
378 | tc.t_startc = -1; | |
379 | tc.t_stopc = -1; | |
380 | #else | |
381 | tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); | |
382 | } else { | |
383 | tmp_tc.c_iflag |= IXANY|IXOFF|IXON; | |
384 | #endif | |
385 | } | |
e767b7ab | 386 | |
6055a9f6 PB |
387 | if ((f&MODE_TRAPSIG) == 0) { |
388 | #ifndef USE_TERMIO | |
389 | tc.t_intrc = -1; | |
390 | tc.t_quitc = -1; | |
391 | tc.t_eofc = -1; | |
392 | ltc.t_suspc = -1; | |
393 | ltc.t_dsuspc = -1; | |
394 | #else | |
395 | tmp_tc.c_lflag &= ~ISIG; | |
396 | #endif | |
397 | localchars = 0; | |
398 | } else { | |
399 | #ifdef USE_TERMIO | |
400 | tmp_tc.c_lflag |= ISIG; | |
401 | #endif | |
402 | localchars = 1; | |
403 | } | |
404 | ||
405 | if (f&MODE_EDIT) { | |
406 | #ifndef USE_TERMIO | |
407 | sb.sg_flags &= ~CBREAK; | |
408 | sb.sg_flags |= CRMOD; | |
409 | #else | |
410 | tmp_tc.c_lflag |= ICANON; | |
411 | #endif | |
412 | } else { | |
413 | #ifndef USE_TERMIO | |
414 | sb.sg_flags |= CBREAK; | |
415 | if (f&MODE_ECHO) | |
e767b7ab | 416 | sb.sg_flags |= CRMOD; |
6055a9f6 PB |
417 | else |
418 | sb.sg_flags &= ~CRMOD; | |
419 | #else | |
420 | tmp_tc.c_lflag &= ~ICANON; | |
421 | tmp_tc.c_iflag &= ~ICRNL; | |
422 | tmp_tc.c_cc[VMIN] = 1; | |
423 | tmp_tc.c_cc[VTIME] = 0; | |
424 | #endif | |
425 | } | |
e767b7ab | 426 | |
6055a9f6 PB |
427 | if (f == -1) { |
428 | onoff = 0; | |
429 | } else { | |
6570c863 | 430 | #ifndef USE_TERMIO |
7daa10bf | 431 | if (f & MODE_OUTBIN) |
6570c863 PB |
432 | lmode |= LLITOUT; |
433 | else | |
434 | lmode &= ~LLITOUT; | |
7daa10bf PB |
435 | |
436 | if (f & MODE_INBIN) | |
6570c863 PB |
437 | lmode |= LPASS8; |
438 | else | |
439 | lmode &= ~LPASS8; | |
440 | #else | |
7daa10bf PB |
441 | if (f & MODE_OUTBIN) |
442 | tmp_tc.c_lflag &= ~ISTRIP; | |
6570c863 | 443 | else |
7daa10bf PB |
444 | tmp_tc.c_lflag |= ISTRIP; |
445 | if (f & MODE_INBIN) { | |
446 | tmp_tc.c_cflag &= ~(CSIZE|PARENB); | |
447 | tmp_tc.c_cflag |= CS8; | |
448 | tmp_tc.c_cflag &= ~OPOST; | |
449 | } else { | |
450 | tmp_tc.c_cflag &= ~CSIZE; | |
451 | tmp_tc.c_cflag |= CS7|PARENB; | |
452 | tmp_tc.c_cflag |= OPOST; | |
453 | } | |
6570c863 | 454 | #endif |
6055a9f6 PB |
455 | onoff = 1; |
456 | } | |
457 | ||
6055a9f6 | 458 | if (f != -1) { |
7daa10bf | 459 | #ifdef SIGTSTP |
87b60187 | 460 | void susp(); |
6055a9f6 | 461 | |
87b60187 | 462 | (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); |
7daa10bf | 463 | #endif /* SIGTSTP */ |
87b60187 PB |
464 | #ifdef USE_TERMIO |
465 | #ifdef VEOL2 | |
466 | /* | |
467 | * If the VEOL character is already set, then use VEOL2, | |
468 | * otherwise use VEOL. | |
469 | */ | |
470 | if (tmp_tc.c_cc[VEOL] != (cc_t)(-1)) | |
471 | tmp_tc.c_cc[VEOL2] = escape; | |
472 | else | |
473 | #endif | |
474 | tmp_tc.c_cc[VEOL] = escape; | |
475 | #else | |
476 | tc.t_brkc = escape; | |
477 | #endif | |
6055a9f6 | 478 | } else { |
7daa10bf | 479 | #ifdef SIGTSTP |
6055a9f6 PB |
480 | (void) signal(SIGTSTP, SIG_DFL); |
481 | sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); | |
7daa10bf PB |
482 | #endif /* SIGTSTP */ |
483 | #ifndef USE_TERMIO | |
484 | ltc = oltc; | |
485 | tc = otc; | |
486 | sb = ottyb; | |
487 | #endif | |
e767b7ab | 488 | } |
7daa10bf PB |
489 | #ifndef USE_TERMIO |
490 | ioctl(tin, TIOCLSET, (char *)&lmode); | |
491 | ioctl(tin, TIOCSLTC, (char *)<c); | |
492 | ioctl(tin, TIOCSETC, (char *)&tc); | |
493 | ioctl(tin, TIOCSETP, (char *)&sb); | |
494 | #else | |
495 | if (ioctl(tin, TCSETAW, &tmp_tc) < 0) | |
496 | ioctl(tin, TCSETA, &tmp_tc); | |
497 | #endif | |
498 | ||
e767b7ab | 499 | #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) |
448f9c06 GM |
500 | ioctl(tin, FIONBIO, (char *)&onoff); |
501 | ioctl(tout, FIONBIO, (char *)&onoff); | |
e767b7ab GM |
502 | #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ |
503 | #if defined(TN3270) | |
4ad36dea | 504 | if (noasynchtty == 0) { |
448f9c06 | 505 | ioctl(tin, FIOASYNC, (char *)&onoff); |
e767b7ab GM |
506 | } |
507 | #endif /* defined(TN3270) */ | |
e767b7ab GM |
508 | } |
509 | ||
7daa10bf PB |
510 | #ifndef B19200 |
511 | # define B19200 B9600 | |
512 | #endif | |
513 | ||
514 | #ifndef B38400 | |
515 | # define B38400 B19200 | |
516 | #endif | |
517 | ||
518 | /* | |
519 | * This code assumes that the values B0, B50, B75... | |
520 | * are in ascending order. They do not have to be | |
521 | * contiguous. | |
522 | */ | |
523 | struct termspeeds { | |
524 | long speed; | |
525 | long value; | |
526 | } termspeeds[] = { | |
527 | { 0, B0 }, { 50, B50 }, { 75, B75 }, | |
528 | { 110, B110 }, { 134, B134 }, { 150, B150 }, | |
529 | { 200, B200 }, { 300, B300 }, { 600, B600 }, | |
530 | { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, | |
531 | { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, | |
532 | { 38400, B38400 }, { -1, B38400 } | |
533 | }; | |
534 | ||
535 | #ifndef USE_TERMIO | |
536 | # define ISPEED ottyb.sg_ispeed | |
537 | # define OSPEED ottyb.sg_ospeed | |
538 | #else | |
539 | # ifdef SYSV_TERMIO | |
540 | # define ISPEED (old_tc.c_cflag&CBAUD) | |
541 | # define OSPEED ISPEED | |
542 | # else | |
543 | # define ISPEED old_tc.c_ispeed | |
544 | # define OSPEED old_tc.c_ospeed | |
545 | # endif | |
546 | #endif | |
547 | ||
445e62ba GM |
548 | void |
549 | TerminalSpeeds(ispeed, ospeed) | |
550 | long *ispeed; | |
551 | long *ospeed; | |
552 | { | |
7daa10bf PB |
553 | register struct termspeeds *tp; |
554 | ||
555 | tp = termspeeds; | |
556 | while ((tp->speed != -1) && (tp->value < ISPEED)) | |
557 | tp++; | |
558 | *ispeed = tp->speed; | |
559 | ||
560 | tp = termspeeds; | |
561 | while ((tp->speed != -1) && (tp->value < OSPEED)) | |
562 | tp++; | |
563 | *ospeed = tp->speed; | |
445e62ba GM |
564 | } |
565 | ||
566 | int | |
567 | TerminalWindowSize(rows, cols) | |
568 | long *rows, *cols; | |
569 | { | |
6055a9f6 | 570 | #ifdef TIOCGWINSZ |
445e62ba GM |
571 | struct winsize ws; |
572 | ||
6055a9f6 PB |
573 | if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { |
574 | *rows = ws.ws_row; | |
575 | *cols = ws.ws_col; | |
576 | return 1; | |
445e62ba | 577 | } |
3942e0c3 | 578 | #endif /* TIOCGWINSZ */ |
6055a9f6 | 579 | return 0; |
445e62ba | 580 | } |
e767b7ab GM |
581 | |
582 | int | |
0ea35455 GM |
583 | NetClose(fd) |
584 | int fd; | |
e767b7ab | 585 | { |
0ea35455 | 586 | return close(fd); |
e767b7ab GM |
587 | } |
588 | ||
589 | ||
590 | void | |
310e7d0b | 591 | NetNonblockingIO(fd, onoff) |
e767b7ab GM |
592 | int |
593 | fd, | |
594 | onoff; | |
595 | { | |
596 | ioctl(fd, FIONBIO, (char *)&onoff); | |
597 | } | |
598 | ||
80a47e22 | 599 | #if defined(TN3270) |
e767b7ab | 600 | void |
310e7d0b | 601 | NetSigIO(fd, onoff) |
e767b7ab GM |
602 | int |
603 | fd, | |
604 | onoff; | |
605 | { | |
606 | ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ | |
607 | } | |
608 | ||
609 | void | |
310e7d0b | 610 | NetSetPgrp(fd) |
e767b7ab GM |
611 | int fd; |
612 | { | |
613 | int myPid; | |
614 | ||
615 | myPid = getpid(); | |
344def17 | 616 | fcntl(fd, F_SETOWN, myPid); |
e767b7ab | 617 | } |
80a47e22 | 618 | #endif /*defined(TN3270)*/ |
310e7d0b GM |
619 | \f |
620 | /* | |
621 | * Various signal handling routines. | |
622 | */ | |
623 | ||
448f9c06 | 624 | static void |
310e7d0b GM |
625 | deadpeer() |
626 | { | |
627 | setcommandmode(); | |
628 | longjmp(peerdied, -1); | |
629 | } | |
630 | ||
448f9c06 | 631 | static void |
310e7d0b GM |
632 | intr() |
633 | { | |
634 | if (localchars) { | |
635 | intp(); | |
636 | return; | |
637 | } | |
638 | setcommandmode(); | |
639 | longjmp(toplevel, -1); | |
640 | } | |
e767b7ab | 641 | |
448f9c06 | 642 | static void |
310e7d0b GM |
643 | intr2() |
644 | { | |
645 | if (localchars) { | |
6055a9f6 PB |
646 | #ifdef KLUDGELINEMODE |
647 | if (kludgelinemode) | |
648 | sendbrk(); | |
649 | else | |
650 | #endif | |
651 | sendabort(); | |
310e7d0b GM |
652 | return; |
653 | } | |
654 | } | |
e767b7ab | 655 | |
87b60187 PB |
656 | static void |
657 | susp() | |
658 | { | |
659 | if (localchars) | |
660 | sendsusp(); | |
661 | } | |
662 | ||
445e62ba GM |
663 | static void |
664 | sendwin() | |
665 | { | |
666 | if (connected) { | |
667 | sendnaws(); | |
668 | } | |
669 | } | |
670 | ||
448f9c06 | 671 | static void |
310e7d0b GM |
672 | doescape() |
673 | { | |
6055a9f6 | 674 | command(0, 0, 0); |
310e7d0b GM |
675 | } |
676 | \f | |
b307f09e GM |
677 | void |
678 | sys_telnet_init() | |
679 | { | |
87b60187 PB |
680 | (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr); |
681 | (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2); | |
682 | (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer); | |
6055a9f6 | 683 | #ifdef SIGWINCH |
87b60187 PB |
684 | (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin); |
685 | #endif | |
686 | #ifdef SIGTSTP | |
687 | (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); | |
6055a9f6 | 688 | #endif |
310e7d0b | 689 | |
6055a9f6 | 690 | setconnmode(0); |
b307f09e GM |
691 | |
692 | NetNonblockingIO(net, 1); | |
693 | ||
694 | #if defined(TN3270) | |
4ad36dea | 695 | if (noasynchnet == 0) { /* DBX can't handle! */ |
b307f09e GM |
696 | NetSigIO(net, 1); |
697 | NetSetPgrp(net); | |
698 | } | |
699 | #endif /* defined(TN3270) */ | |
700 | ||
701 | #if defined(SO_OOBINLINE) | |
80a47e22 GM |
702 | if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { |
703 | perror("SetSockOpt"); | |
704 | } | |
b307f09e GM |
705 | #endif /* defined(SO_OOBINLINE) */ |
706 | } | |
707 | ||
708 | /* | |
709 | * Process rings - | |
710 | * | |
711 | * This routine tries to fill up/empty our various rings. | |
712 | * | |
713 | * The parameter specifies whether this is a poll operation, | |
714 | * or a block-until-something-happens operation. | |
715 | * | |
716 | * The return value is 1 if something happened, 0 if not. | |
717 | */ | |
718 | ||
719 | int | |
720 | process_rings(netin, netout, netex, ttyin, ttyout, poll) | |
721 | int poll; /* If 0, then block until something to do */ | |
722 | { | |
723 | register int c; | |
724 | /* One wants to be a bit careful about setting returnValue | |
725 | * to one, since a one implies we did some useful work, | |
726 | * and therefore probably won't be called to block next | |
727 | * time (TN3270 mode only). | |
728 | */ | |
729 | int returnValue = 0; | |
730 | static struct timeval TimeValue = { 0 }; | |
731 | ||
732 | if (netout) { | |
733 | FD_SET(net, &obits); | |
734 | } | |
735 | if (ttyout) { | |
736 | FD_SET(tout, &obits); | |
737 | } | |
738 | #if defined(TN3270) | |
739 | if (ttyin) { | |
740 | FD_SET(tin, &ibits); | |
741 | } | |
742 | #else /* defined(TN3270) */ | |
743 | if (ttyin) { | |
744 | FD_SET(tin, &ibits); | |
745 | } | |
746 | #endif /* defined(TN3270) */ | |
747 | #if defined(TN3270) | |
748 | if (netin) { | |
749 | FD_SET(net, &ibits); | |
750 | } | |
751 | # else /* !defined(TN3270) */ | |
752 | if (netin) { | |
753 | FD_SET(net, &ibits); | |
754 | } | |
755 | # endif /* !defined(TN3270) */ | |
756 | if (netex) { | |
757 | FD_SET(net, &xbits); | |
758 | } | |
759 | if ((c = select(16, &ibits, &obits, &xbits, | |
760 | (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { | |
761 | if (c == -1) { | |
762 | /* | |
763 | * we can get EINTR if we are in line mode, | |
764 | * and the user does an escape (TSTP), or | |
765 | * some other signal generator. | |
766 | */ | |
767 | if (errno == EINTR) { | |
768 | return 0; | |
769 | } | |
770 | # if defined(TN3270) | |
771 | /* | |
772 | * we can get EBADF if we were in transparent | |
773 | * mode, and the transcom process died. | |
774 | */ | |
775 | if (errno == EBADF) { | |
776 | /* | |
777 | * zero the bits (even though kernel does it) | |
778 | * to make sure we are selecting on the right | |
779 | * ones. | |
780 | */ | |
781 | FD_ZERO(&ibits); | |
782 | FD_ZERO(&obits); | |
783 | FD_ZERO(&xbits); | |
784 | return 0; | |
785 | } | |
786 | # endif /* defined(TN3270) */ | |
787 | /* I don't like this, does it ever happen? */ | |
788 | printf("sleep(5) from telnet, after select\r\n"); | |
b307f09e | 789 | sleep(5); |
b307f09e GM |
790 | } |
791 | return 0; | |
792 | } | |
793 | ||
794 | /* | |
795 | * Any urgent data? | |
796 | */ | |
797 | if (FD_ISSET(net, &xbits)) { | |
798 | FD_CLR(net, &xbits); | |
799 | SYNCHing = 1; | |
800 | ttyflush(1); /* flush already enqueued data */ | |
801 | } | |
802 | ||
803 | /* | |
804 | * Something to read from the network... | |
805 | */ | |
806 | if (FD_ISSET(net, &ibits)) { | |
807 | int canread; | |
808 | ||
809 | FD_CLR(net, &ibits); | |
810 | canread = ring_empty_consecutive(&netiring); | |
811 | #if !defined(SO_OOBINLINE) | |
812 | /* | |
813 | * In 4.2 (and some early 4.3) systems, the | |
814 | * OOB indication and data handling in the kernel | |
815 | * is such that if two separate TCP Urgent requests | |
816 | * come in, one byte of TCP data will be overlaid. | |
817 | * This is fatal for Telnet, but we try to live | |
818 | * with it. | |
819 | * | |
820 | * In addition, in 4.2 (and...), a special protocol | |
821 | * is needed to pick up the TCP Urgent data in | |
822 | * the correct sequence. | |
823 | * | |
824 | * What we do is: if we think we are in urgent | |
825 | * mode, we look to see if we are "at the mark". | |
826 | * If we are, we do an OOB receive. If we run | |
827 | * this twice, we will do the OOB receive twice, | |
828 | * but the second will fail, since the second | |
829 | * time we were "at the mark", but there wasn't | |
830 | * any data there (the kernel doesn't reset | |
831 | * "at the mark" until we do a normal read). | |
832 | * Once we've read the OOB data, we go ahead | |
833 | * and do normal reads. | |
834 | * | |
835 | * There is also another problem, which is that | |
836 | * since the OOB byte we read doesn't put us | |
837 | * out of OOB state, and since that byte is most | |
838 | * likely the TELNET DM (data mark), we would | |
839 | * stay in the TELNET SYNCH (SYNCHing) state. | |
840 | * So, clocks to the rescue. If we've "just" | |
841 | * received a DM, then we test for the | |
842 | * presence of OOB data when the receive OOB | |
843 | * fails (and AFTER we did the normal mode read | |
844 | * to clear "at the mark"). | |
845 | */ | |
846 | if (SYNCHing) { | |
847 | int atmark; | |
49e7660e | 848 | static int bogus_oob = 0, first = 1; |
b307f09e GM |
849 | |
850 | ioctl(net, SIOCATMARK, (char *)&atmark); | |
851 | if (atmark) { | |
852 | c = recv(net, netiring.supply, canread, MSG_OOB); | |
853 | if ((c == -1) && (errno == EINVAL)) { | |
854 | c = recv(net, netiring.supply, canread, 0); | |
855 | if (clocks.didnetreceive < clocks.gotDM) { | |
856 | SYNCHing = stilloob(net); | |
857 | } | |
49e7660e PB |
858 | } else if (first && c > 0) { |
859 | /* | |
860 | * Bogosity check. Systems based on 4.2BSD | |
861 | * do not return an error if you do a second | |
862 | * recv(MSG_OOB). So, we do one. If it | |
863 | * succeeds and returns exactly the same | |
864 | * data, then assume that we are running | |
865 | * on a broken system and set the bogus_oob | |
866 | * flag. (If the data was different, then | |
867 | * we probably got some valid new data, so | |
868 | * increment the count...) | |
869 | */ | |
870 | int i; | |
871 | i = recv(net, netiring.supply + c, canread - c, MSG_OOB); | |
872 | if (i == c && | |
873 | bcmp(netiring.supply, netiring.supply + c, i) == 0) { | |
874 | bogus_oob = 1; | |
875 | first = 0; | |
876 | } else if (i < 0) { | |
877 | bogus_oob = 0; | |
878 | first = 0; | |
879 | } else | |
880 | c += i; | |
881 | } | |
882 | if (bogus_oob && c > 0) { | |
883 | int i; | |
884 | /* | |
885 | * Bogosity. We have to do the read | |
886 | * to clear the atmark to get out of | |
887 | * an infinate loop. | |
888 | */ | |
889 | i = read(net, netiring.supply + c, canread - c); | |
890 | if (i > 0) | |
891 | c += i; | |
b307f09e GM |
892 | } |
893 | } else { | |
894 | c = recv(net, netiring.supply, canread, 0); | |
895 | } | |
896 | } else { | |
897 | c = recv(net, netiring.supply, canread, 0); | |
898 | } | |
899 | settimer(didnetreceive); | |
900 | #else /* !defined(SO_OOBINLINE) */ | |
901 | c = recv(net, netiring.supply, canread, 0); | |
902 | #endif /* !defined(SO_OOBINLINE) */ | |
903 | if (c < 0 && errno == EWOULDBLOCK) { | |
904 | c = 0; | |
905 | } else if (c <= 0) { | |
906 | return -1; | |
907 | } | |
908 | if (netdata) { | |
909 | Dump('<', netiring.supply, c); | |
910 | } | |
ad1c581e GM |
911 | if (c) |
912 | ring_supplied(&netiring, c); | |
b307f09e GM |
913 | returnValue = 1; |
914 | } | |
915 | ||
916 | /* | |
917 | * Something to read from the tty... | |
918 | */ | |
919 | if (FD_ISSET(tin, &ibits)) { | |
920 | FD_CLR(tin, &ibits); | |
448f9c06 | 921 | c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); |
b307f09e GM |
922 | if (c < 0 && errno == EWOULDBLOCK) { |
923 | c = 0; | |
924 | } else { | |
b307f09e | 925 | /* EOF detection for line mode!!!! */ |
75ec5474 | 926 | if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { |
b307f09e GM |
927 | /* must be an EOF... */ |
928 | *ttyiring.supply = termEofChar; | |
929 | c = 1; | |
930 | } | |
b307f09e GM |
931 | if (c <= 0) { |
932 | return -1; | |
933 | } | |
40cc3fc2 GM |
934 | if (termdata) { |
935 | Dump('<', ttyiring.supply, c); | |
936 | } | |
ad1c581e | 937 | ring_supplied(&ttyiring, c); |
b307f09e | 938 | } |
b307f09e GM |
939 | returnValue = 1; /* did something useful */ |
940 | } | |
941 | ||
942 | if (FD_ISSET(net, &obits)) { | |
943 | FD_CLR(net, &obits); | |
944 | returnValue |= netflush(); | |
945 | } | |
946 | if (FD_ISSET(tout, &obits)) { | |
947 | FD_CLR(tout, &obits); | |
6055a9f6 | 948 | returnValue |= (ttyflush(SYNCHing|flushout) > 0); |
b307f09e GM |
949 | } |
950 | ||
951 | return returnValue; | |
952 | } |