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