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