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