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 | |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
11 | */ | |
12 | ||
13 | #ifndef lint | |
80a47e22 | 14 | static char sccsid[] = "@(#)sys_bsd.c 1.12 (Berkeley) %G%"; |
897ce52e KB |
15 | #endif /* not lint */ |
16 | ||
e767b7ab GM |
17 | /* |
18 | * The following routines try to encapsulate what is system dependent | |
19 | * (at least between 4.x and dos) which is used in telnet.c. | |
20 | */ | |
21 | ||
22 | #if defined(unix) | |
23 | ||
24 | #include <sys/ioctl.h> | |
115a5494 | 25 | #include <sys/types.h> |
e767b7ab | 26 | #include <sys/time.h> |
b307f09e | 27 | #include <sys/socket.h> |
e767b7ab | 28 | #include <signal.h> |
b307f09e | 29 | #include <errno.h> |
e767b7ab | 30 | |
115a5494 GM |
31 | #include "ring.h" |
32 | ||
807a3a7d GM |
33 | #include "fdset.h" |
34 | ||
e767b7ab GM |
35 | #include "defines.h" |
36 | #include "externs.h" | |
37 | #include "types.h" | |
38 | ||
39 | int | |
b307f09e GM |
40 | tout, /* Output file descriptor */ |
41 | tin, /* Input file descriptor */ | |
42 | net, | |
e767b7ab GM |
43 | HaveInput; /* There is input available to scan */ |
44 | ||
e767b7ab GM |
45 | static struct tchars otc = { 0 }, ntc = { 0 }; |
46 | static struct ltchars oltc = { 0 }, nltc = { 0 }; | |
47 | static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; | |
48 | ||
b307f09e GM |
49 | static fd_set ibits, obits, xbits; |
50 | ||
51 | ||
52 | init_sys() | |
53 | { | |
54 | tout = fileno(stdout); | |
55 | tin = fileno(stdin); | |
56 | FD_ZERO(&ibits); | |
57 | FD_ZERO(&obits); | |
58 | FD_ZERO(&xbits); | |
59 | ||
60 | errno = 0; | |
61 | } | |
62 | ||
e767b7ab | 63 | |
448f9c06 | 64 | TerminalWrite(buf, n) |
e767b7ab GM |
65 | char *buf; |
66 | int n; | |
67 | { | |
448f9c06 | 68 | return write(tout, buf, n); |
e767b7ab GM |
69 | } |
70 | ||
448f9c06 | 71 | TerminalRead(buf, n) |
e767b7ab GM |
72 | char *buf; |
73 | int n; | |
74 | { | |
448f9c06 | 75 | return read(tin, buf, n); |
e767b7ab GM |
76 | } |
77 | ||
78 | /* | |
79 | * | |
80 | */ | |
81 | ||
82 | int | |
310e7d0b | 83 | TerminalAutoFlush() |
e767b7ab GM |
84 | { |
85 | #if defined(LNOFLSH) | |
86 | int flush; | |
87 | ||
88 | ioctl(0, TIOCLGET, (char *)&flush); | |
89 | return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ | |
90 | #else /* LNOFLSH */ | |
91 | return 1; | |
92 | #endif /* LNOFLSH */ | |
93 | } | |
94 | ||
95 | /* | |
96 | * TerminalSpecialChars() | |
97 | * | |
98 | * Look at an input character to see if it is a special character | |
99 | * and decide what to do. | |
100 | * | |
101 | * Output: | |
102 | * | |
103 | * 0 Don't add this character. | |
104 | * 1 Do add this character | |
105 | */ | |
106 | ||
107 | int | |
310e7d0b | 108 | TerminalSpecialChars(c) |
e767b7ab GM |
109 | int c; |
110 | { | |
310e7d0b | 111 | void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); |
e767b7ab GM |
112 | |
113 | if (c == ntc.t_intrc) { | |
114 | intp(); | |
115 | return 0; | |
116 | } else if (c == ntc.t_quitc) { | |
117 | sendbrk(); | |
118 | return 0; | |
119 | } else if (c == nltc.t_flushc) { | |
120 | xmitAO(); /* Transmit Abort Output */ | |
121 | return 0; | |
122 | } else if (!MODE_LOCAL_CHARS(globalmode)) { | |
123 | if (c == nttyb.sg_kill) { | |
124 | xmitEL(); | |
125 | return 0; | |
126 | } else if (c == nttyb.sg_erase) { | |
127 | xmitEC(); /* Transmit Erase Character */ | |
128 | return 0; | |
129 | } | |
130 | } | |
131 | return 1; | |
132 | } | |
133 | ||
134 | ||
135 | /* | |
136 | * Flush output to the terminal | |
137 | */ | |
138 | ||
139 | void | |
310e7d0b | 140 | TerminalFlushOutput() |
e767b7ab GM |
141 | { |
142 | (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); | |
143 | } | |
144 | ||
145 | void | |
310e7d0b | 146 | TerminalSaveState() |
e767b7ab GM |
147 | { |
148 | ioctl(0, TIOCGETP, (char *)&ottyb); | |
149 | ioctl(0, TIOCGETC, (char *)&otc); | |
150 | ioctl(0, TIOCGLTC, (char *)&oltc); | |
151 | ||
152 | ntc = otc; | |
153 | nltc = oltc; | |
154 | nttyb = ottyb; | |
0e29050b GM |
155 | |
156 | termEofChar = ntc.t_eofc; | |
157 | termEraseChar = nttyb.sg_erase; | |
158 | termFlushChar = nltc.t_flushc; | |
159 | termIntChar = ntc.t_intrc; | |
160 | termKillChar = nttyb.sg_kill; | |
161 | termQuitChar = ntc.t_quitc; | |
e767b7ab GM |
162 | } |
163 | ||
164 | void | |
310e7d0b | 165 | TerminalRestoreState() |
e767b7ab GM |
166 | { |
167 | } | |
168 | ||
169 | /* | |
170 | * TerminalNewMode - set up terminal to a specific mode. | |
171 | */ | |
172 | ||
173 | ||
174 | void | |
448f9c06 | 175 | TerminalNewMode(f) |
e767b7ab GM |
176 | register int f; |
177 | { | |
178 | static int prevmode = 0; | |
179 | struct tchars *tc; | |
180 | struct tchars tc3; | |
181 | struct ltchars *ltc; | |
182 | struct sgttyb sb; | |
183 | int onoff; | |
184 | int old; | |
185 | struct tchars notc2; | |
186 | struct ltchars noltc2; | |
187 | static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; | |
188 | static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; | |
189 | ||
190 | globalmode = f; | |
191 | if (prevmode == f) | |
192 | return; | |
193 | old = prevmode; | |
194 | prevmode = f; | |
195 | sb = nttyb; | |
196 | ||
197 | switch (f) { | |
198 | ||
199 | case 0: | |
200 | onoff = 0; | |
201 | tc = &otc; | |
202 | ltc = &oltc; | |
203 | break; | |
204 | ||
205 | case 1: /* remote character processing, remote echo */ | |
206 | case 2: /* remote character processing, local echo */ | |
207 | case 6: /* 3270 mode - like 1, but with xon/xoff local */ | |
208 | /* (might be nice to have "6" in telnet also...) */ | |
209 | sb.sg_flags |= CBREAK; | |
210 | if ((f == 1) || (f == 6)) { | |
211 | sb.sg_flags &= ~(ECHO|CRMOD); | |
212 | } else { | |
213 | sb.sg_flags |= ECHO|CRMOD; | |
214 | } | |
215 | sb.sg_erase = sb.sg_kill = -1; | |
216 | if (f == 6) { | |
217 | tc = &tc3; | |
218 | tc3 = notc; | |
219 | /* get XON, XOFF characters */ | |
220 | tc3.t_startc = otc.t_startc; | |
221 | tc3.t_stopc = otc.t_stopc; | |
222 | } else { | |
223 | /* | |
224 | * If user hasn't specified one way or the other, | |
225 | * then default to not trapping signals. | |
226 | */ | |
227 | if (!donelclchars) { | |
228 | localchars = 0; | |
229 | } | |
230 | if (localchars) { | |
231 | notc2 = notc; | |
232 | notc2.t_intrc = ntc.t_intrc; | |
233 | notc2.t_quitc = ntc.t_quitc; | |
234 | tc = ¬c2; | |
235 | } else { | |
236 | tc = ¬c; | |
237 | } | |
238 | } | |
239 | ltc = &noltc; | |
240 | onoff = 1; | |
241 | break; | |
242 | case 3: /* local character processing, remote echo */ | |
243 | case 4: /* local character processing, local echo */ | |
244 | case 5: /* local character processing, no echo */ | |
245 | sb.sg_flags &= ~CBREAK; | |
246 | sb.sg_flags |= CRMOD; | |
247 | if (f == 4) | |
248 | sb.sg_flags |= ECHO; | |
249 | else | |
250 | sb.sg_flags &= ~ECHO; | |
251 | notc2 = ntc; | |
252 | tc = ¬c2; | |
253 | noltc2 = oltc; | |
254 | ltc = &noltc2; | |
255 | /* | |
256 | * If user hasn't specified one way or the other, | |
257 | * then default to trapping signals. | |
258 | */ | |
259 | if (!donelclchars) { | |
260 | localchars = 1; | |
261 | } | |
262 | if (localchars) { | |
263 | notc2.t_brkc = nltc.t_flushc; | |
264 | noltc2.t_flushc = -1; | |
265 | } else { | |
266 | notc2.t_intrc = notc2.t_quitc = -1; | |
267 | } | |
268 | noltc2.t_suspc = escape; | |
269 | noltc2.t_dsuspc = -1; | |
270 | onoff = 1; | |
271 | break; | |
272 | ||
273 | default: | |
274 | return; | |
275 | } | |
448f9c06 GM |
276 | ioctl(tin, TIOCSLTC, (char *)ltc); |
277 | ioctl(tin, TIOCSETC, (char *)tc); | |
278 | ioctl(tin, TIOCSETP, (char *)&sb); | |
e767b7ab | 279 | #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) |
448f9c06 GM |
280 | ioctl(tin, FIONBIO, (char *)&onoff); |
281 | ioctl(tout, FIONBIO, (char *)&onoff); | |
e767b7ab GM |
282 | #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ |
283 | #if defined(TN3270) | |
284 | if (noasynch == 0) { | |
448f9c06 | 285 | ioctl(tin, FIOASYNC, (char *)&onoff); |
e767b7ab GM |
286 | } |
287 | #endif /* defined(TN3270) */ | |
288 | ||
289 | if (MODE_LINE(f)) { | |
290 | void doescape(); | |
291 | ||
80a47e22 | 292 | (void) signal(SIGTSTP, (int (*)())doescape); |
e767b7ab | 293 | } else if (MODE_LINE(old)) { |
80a47e22 | 294 | (void) signal(SIGTSTP, SIG_DFL); |
e767b7ab GM |
295 | sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); |
296 | } | |
297 | } | |
298 | ||
299 | ||
300 | int | |
301 | NetClose(net) | |
302 | int net; | |
303 | { | |
304 | return close(net); | |
305 | } | |
306 | ||
307 | ||
308 | void | |
310e7d0b | 309 | NetNonblockingIO(fd, onoff) |
e767b7ab GM |
310 | int |
311 | fd, | |
312 | onoff; | |
313 | { | |
314 | ioctl(fd, FIONBIO, (char *)&onoff); | |
315 | } | |
316 | ||
80a47e22 | 317 | #if defined(TN3270) |
e767b7ab | 318 | void |
310e7d0b | 319 | NetSigIO(fd, onoff) |
e767b7ab GM |
320 | int |
321 | fd, | |
322 | onoff; | |
323 | { | |
324 | ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ | |
325 | } | |
326 | ||
327 | void | |
310e7d0b | 328 | NetSetPgrp(fd) |
e767b7ab GM |
329 | int fd; |
330 | { | |
331 | int myPid; | |
332 | ||
333 | myPid = getpid(); | |
334 | #if defined(NOT43) | |
335 | myPid = -myPid; | |
336 | #endif /* defined(NOT43) */ | |
337 | ioctl(fd, SIOCSPGRP, (char *)&myPid); /* set my pid */ | |
338 | } | |
80a47e22 | 339 | #endif /*defined(TN3270)*/ |
310e7d0b GM |
340 | \f |
341 | /* | |
342 | * Various signal handling routines. | |
343 | */ | |
344 | ||
448f9c06 | 345 | static void |
310e7d0b GM |
346 | deadpeer() |
347 | { | |
348 | setcommandmode(); | |
349 | longjmp(peerdied, -1); | |
350 | } | |
351 | ||
448f9c06 | 352 | static void |
310e7d0b GM |
353 | intr() |
354 | { | |
355 | if (localchars) { | |
356 | intp(); | |
357 | return; | |
358 | } | |
359 | setcommandmode(); | |
360 | longjmp(toplevel, -1); | |
361 | } | |
e767b7ab | 362 | |
448f9c06 | 363 | static void |
310e7d0b GM |
364 | intr2() |
365 | { | |
366 | if (localchars) { | |
367 | sendbrk(); | |
368 | return; | |
369 | } | |
370 | } | |
e767b7ab | 371 | |
448f9c06 | 372 | static void |
310e7d0b GM |
373 | doescape() |
374 | { | |
375 | command(0); | |
376 | } | |
377 | \f | |
b307f09e GM |
378 | void |
379 | sys_telnet_init() | |
380 | { | |
310e7d0b | 381 | #if defined(TN3270) |
b307f09e GM |
382 | int myPid; |
383 | #endif /* defined(TN3270) */ | |
384 | ||
80a47e22 GM |
385 | (void) signal(SIGINT, (int (*)())intr); |
386 | (void) signal(SIGQUIT, (int (*)())intr2); | |
387 | (void) signal(SIGPIPE, (int (*)())deadpeer); | |
310e7d0b | 388 | |
b307f09e GM |
389 | setconnmode(); |
390 | ||
391 | NetNonblockingIO(net, 1); | |
392 | ||
393 | #if defined(TN3270) | |
394 | if (noasynch == 0) { /* DBX can't handle! */ | |
395 | NetSigIO(net, 1); | |
396 | NetSetPgrp(net); | |
397 | } | |
398 | #endif /* defined(TN3270) */ | |
399 | ||
400 | #if defined(SO_OOBINLINE) | |
80a47e22 GM |
401 | if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { |
402 | perror("SetSockOpt"); | |
403 | } | |
b307f09e GM |
404 | #endif /* defined(SO_OOBINLINE) */ |
405 | } | |
406 | ||
407 | /* | |
408 | * Process rings - | |
409 | * | |
410 | * This routine tries to fill up/empty our various rings. | |
411 | * | |
412 | * The parameter specifies whether this is a poll operation, | |
413 | * or a block-until-something-happens operation. | |
414 | * | |
415 | * The return value is 1 if something happened, 0 if not. | |
416 | */ | |
417 | ||
418 | int | |
419 | process_rings(netin, netout, netex, ttyin, ttyout, poll) | |
420 | int poll; /* If 0, then block until something to do */ | |
421 | { | |
422 | register int c; | |
423 | /* One wants to be a bit careful about setting returnValue | |
424 | * to one, since a one implies we did some useful work, | |
425 | * and therefore probably won't be called to block next | |
426 | * time (TN3270 mode only). | |
427 | */ | |
428 | int returnValue = 0; | |
429 | static struct timeval TimeValue = { 0 }; | |
430 | ||
431 | if (netout) { | |
432 | FD_SET(net, &obits); | |
433 | } | |
434 | if (ttyout) { | |
435 | FD_SET(tout, &obits); | |
436 | } | |
437 | #if defined(TN3270) | |
438 | if (ttyin) { | |
439 | FD_SET(tin, &ibits); | |
440 | } | |
441 | #else /* defined(TN3270) */ | |
442 | if (ttyin) { | |
443 | FD_SET(tin, &ibits); | |
444 | } | |
445 | #endif /* defined(TN3270) */ | |
446 | #if defined(TN3270) | |
447 | if (netin) { | |
448 | FD_SET(net, &ibits); | |
449 | } | |
450 | # else /* !defined(TN3270) */ | |
451 | if (netin) { | |
452 | FD_SET(net, &ibits); | |
453 | } | |
454 | # endif /* !defined(TN3270) */ | |
455 | if (netex) { | |
456 | FD_SET(net, &xbits); | |
457 | } | |
458 | if ((c = select(16, &ibits, &obits, &xbits, | |
459 | (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { | |
460 | if (c == -1) { | |
461 | /* | |
462 | * we can get EINTR if we are in line mode, | |
463 | * and the user does an escape (TSTP), or | |
464 | * some other signal generator. | |
465 | */ | |
466 | if (errno == EINTR) { | |
467 | return 0; | |
468 | } | |
469 | # if defined(TN3270) | |
470 | /* | |
471 | * we can get EBADF if we were in transparent | |
472 | * mode, and the transcom process died. | |
473 | */ | |
474 | if (errno == EBADF) { | |
475 | /* | |
476 | * zero the bits (even though kernel does it) | |
477 | * to make sure we are selecting on the right | |
478 | * ones. | |
479 | */ | |
480 | FD_ZERO(&ibits); | |
481 | FD_ZERO(&obits); | |
482 | FD_ZERO(&xbits); | |
483 | return 0; | |
484 | } | |
485 | # endif /* defined(TN3270) */ | |
486 | /* I don't like this, does it ever happen? */ | |
487 | printf("sleep(5) from telnet, after select\r\n"); | |
b307f09e | 488 | sleep(5); |
b307f09e GM |
489 | } |
490 | return 0; | |
491 | } | |
492 | ||
493 | /* | |
494 | * Any urgent data? | |
495 | */ | |
496 | if (FD_ISSET(net, &xbits)) { | |
497 | FD_CLR(net, &xbits); | |
498 | SYNCHing = 1; | |
499 | ttyflush(1); /* flush already enqueued data */ | |
500 | } | |
501 | ||
502 | /* | |
503 | * Something to read from the network... | |
504 | */ | |
505 | if (FD_ISSET(net, &ibits)) { | |
506 | int canread; | |
507 | ||
508 | FD_CLR(net, &ibits); | |
509 | canread = ring_empty_consecutive(&netiring); | |
510 | #if !defined(SO_OOBINLINE) | |
511 | /* | |
512 | * In 4.2 (and some early 4.3) systems, the | |
513 | * OOB indication and data handling in the kernel | |
514 | * is such that if two separate TCP Urgent requests | |
515 | * come in, one byte of TCP data will be overlaid. | |
516 | * This is fatal for Telnet, but we try to live | |
517 | * with it. | |
518 | * | |
519 | * In addition, in 4.2 (and...), a special protocol | |
520 | * is needed to pick up the TCP Urgent data in | |
521 | * the correct sequence. | |
522 | * | |
523 | * What we do is: if we think we are in urgent | |
524 | * mode, we look to see if we are "at the mark". | |
525 | * If we are, we do an OOB receive. If we run | |
526 | * this twice, we will do the OOB receive twice, | |
527 | * but the second will fail, since the second | |
528 | * time we were "at the mark", but there wasn't | |
529 | * any data there (the kernel doesn't reset | |
530 | * "at the mark" until we do a normal read). | |
531 | * Once we've read the OOB data, we go ahead | |
532 | * and do normal reads. | |
533 | * | |
534 | * There is also another problem, which is that | |
535 | * since the OOB byte we read doesn't put us | |
536 | * out of OOB state, and since that byte is most | |
537 | * likely the TELNET DM (data mark), we would | |
538 | * stay in the TELNET SYNCH (SYNCHing) state. | |
539 | * So, clocks to the rescue. If we've "just" | |
540 | * received a DM, then we test for the | |
541 | * presence of OOB data when the receive OOB | |
542 | * fails (and AFTER we did the normal mode read | |
543 | * to clear "at the mark"). | |
544 | */ | |
545 | if (SYNCHing) { | |
546 | int atmark; | |
547 | ||
548 | ioctl(net, SIOCATMARK, (char *)&atmark); | |
549 | if (atmark) { | |
550 | c = recv(net, netiring.supply, canread, MSG_OOB); | |
551 | if ((c == -1) && (errno == EINVAL)) { | |
552 | c = recv(net, netiring.supply, canread, 0); | |
553 | if (clocks.didnetreceive < clocks.gotDM) { | |
554 | SYNCHing = stilloob(net); | |
555 | } | |
556 | } | |
557 | } else { | |
558 | c = recv(net, netiring.supply, canread, 0); | |
559 | } | |
560 | } else { | |
561 | c = recv(net, netiring.supply, canread, 0); | |
562 | } | |
563 | settimer(didnetreceive); | |
564 | #else /* !defined(SO_OOBINLINE) */ | |
565 | c = recv(net, netiring.supply, canread, 0); | |
566 | #endif /* !defined(SO_OOBINLINE) */ | |
567 | if (c < 0 && errno == EWOULDBLOCK) { | |
568 | c = 0; | |
569 | } else if (c <= 0) { | |
570 | return -1; | |
571 | } | |
572 | if (netdata) { | |
573 | Dump('<', netiring.supply, c); | |
574 | } | |
ad1c581e GM |
575 | if (c) |
576 | ring_supplied(&netiring, c); | |
b307f09e GM |
577 | returnValue = 1; |
578 | } | |
579 | ||
580 | /* | |
581 | * Something to read from the tty... | |
582 | */ | |
583 | if (FD_ISSET(tin, &ibits)) { | |
584 | FD_CLR(tin, &ibits); | |
448f9c06 | 585 | c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); |
b307f09e GM |
586 | if (c < 0 && errno == EWOULDBLOCK) { |
587 | c = 0; | |
588 | } else { | |
b307f09e | 589 | /* EOF detection for line mode!!!! */ |
75ec5474 | 590 | if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { |
b307f09e GM |
591 | /* must be an EOF... */ |
592 | *ttyiring.supply = termEofChar; | |
593 | c = 1; | |
594 | } | |
b307f09e GM |
595 | if (c <= 0) { |
596 | return -1; | |
597 | } | |
ad1c581e | 598 | ring_supplied(&ttyiring, c); |
b307f09e | 599 | } |
b307f09e GM |
600 | returnValue = 1; /* did something useful */ |
601 | } | |
602 | ||
603 | if (FD_ISSET(net, &obits)) { | |
604 | FD_CLR(net, &obits); | |
605 | returnValue |= netflush(); | |
606 | } | |
607 | if (FD_ISSET(tout, &obits)) { | |
608 | FD_CLR(tout, &obits); | |
609 | returnValue |= ttyflush(SYNCHing|flushout); | |
610 | } | |
611 | ||
612 | return returnValue; | |
613 | } | |
e767b7ab | 614 | #endif /* defined(unix) */ |