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