virtual int read(char *buf, int maxlen) { int l = TerminalRead(buf, maxlen); if (l<0 && errno==WSAEWOULDBLOCK) l = 0; else if (l==0 && MODE_LOCAL_CHARS(globalmode) && (GetFileType(tin) == FILE_TYPE_CHAR)) { /* EOF detection for line mode!!!! */ /* must be an EOF... */ *buf = termEofChar; l = 1; } return l; }
int TerminalSpecialChars (int c) { if (c == termIntChar) { intp (); return 0; } else if (c == termQuitChar) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk (); else #endif sendabort (); return 0; } else if (c == termEofChar) { if (my_want_state_is_will (TELOPT_LINEMODE)) { sendeof (); return 0; } return 1; } else if (c == termSuspChar) { sendsusp (); return (0); } else if (c == termFlushChar) { xmitAO (); /* Transmit Abort Output */ return 0; } else if (!MODE_LOCAL_CHARS (globalmode)) { if (c == termKillChar) { xmitEL (); return 0; } else if (c == termEraseChar) { xmitEC (); /* Transmit Erase Character */ return 0; } } return 1; }
static int telsnd(void) { int tcc; int count; int returnValue = 0; unsigned char *tbp; tcc = 0; count = 0; while (NETROOM() > 2) { int sc; int c; if (tcc == 0) { if (count) { ring_consumed(&ttyiring, count); returnValue = 1; count = 0; } tbp = ttyiring.consume; tcc = ring_full_consecutive(&ttyiring); if (tcc == 0) { break; } } c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; if (rlogin != _POSIX_VDISABLE) { if (bol) { bol = 0; if (sc == rlogin) { local = 1; continue; } } else if (local) { local = 0; if (sc == '.' || c == termEofChar) { bol = 1; command(0, "close\n", 6); continue; } if (sc == termSuspChar) { bol = 1; command(0, "z\n", 2); continue; } if (sc == escape) { command(0, tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } if (sc != rlogin) { ++tcc; --tbp; --count; c = sc = rlogin; } } if ((sc == '\n') || (sc == '\r')) bol = 1; } else if (escape != _POSIX_VDISABLE && sc == escape) { /* * Double escape is a pass through of a single escape character. */ if (tcc && strip(*tbp) == escape) { tbp++; tcc--; count++; bol = 0; } else { command(0, (char *)tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } } else bol = 0; #ifdef KLUDGELINEMODE if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { if (tcc > 0 && strip(*tbp) == echoc) { tcc--; tbp++; count++; } else { dontlecho = !dontlecho; settimer(echotoggle); setconnmode(0); flushline = 1; break; } } #endif if (MODE_LOCAL_CHARS(globalmode)) { if (TerminalSpecialChars(sc) == 0) { bol = 1; break; } } if (my_want_state_is_wont(TELOPT_BINARY)) { switch (c) { case '\n': /* * If we are in CRMOD mode (\r ==> \n) * on our local machine, then probably * a newline (unix) is CRLF (TELNET). */ if (MODE_LOCAL_CHARS(globalmode)) { NETADD('\r'); } NETADD('\n'); bol = flushline = 1; break; case '\r': if (!crlf) { NET2ADD('\r', '\0'); } else { NET2ADD('\r', '\n'); } bol = flushline = 1; break; case IAC: NET2ADD(IAC, IAC); break; default: NETADD(c); break; } } else if (c == IAC) { NET2ADD(IAC, IAC); } else { NETADD(c); } } if (count) ring_consumed(&ttyiring, count); return returnValue||count; /* Non-zero if we did anything */ }
int process_rings (int netin, int netout, int netex, int ttyin, int ttyout, int poll) /* If poll == 0, then block until something to do */ { int c; /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue = 0; static struct timeval TimeValue = { 0, 0 }; int maxfd = -1; int tmp; if ((netout || netin || netex) && net > maxfd) maxfd = net; if (ttyout && tout > maxfd) maxfd = tout; if (ttyin && tin > maxfd) maxfd = tin; tmp = howmany (maxfd + 1, NFDBITS) * sizeof (fd_mask); if (tmp > fdsn) { if (ibitsp) free (ibitsp); if (obitsp) free (obitsp); if (xbitsp) free (xbitsp); fdsn = tmp; if ((ibitsp = (fd_set *) malloc (fdsn)) == NULL) err (1, "malloc"); if ((obitsp = (fd_set *) malloc (fdsn)) == NULL) err (1, "malloc"); if ((xbitsp = (fd_set *) malloc (fdsn)) == NULL) err (1, "malloc"); memset (ibitsp, 0, fdsn); memset (obitsp, 0, fdsn); memset (xbitsp, 0, fdsn); } if (netout) FD_SET (net, obitsp); if (ttyout) FD_SET (tout, obitsp); if (ttyin) FD_SET (tin, ibitsp); if (netin) FD_SET (net, ibitsp); if (netex) FD_SET (net, xbitsp); if ((c = select (maxfd + 1, ibitsp, obitsp, xbitsp, (poll == 0) ? (struct timeval *) 0 : &TimeValue)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, * and the user does an escape (TSTP), or * some other signal generator. */ if (errno == EINTR) { return 0; } # if defined(TN3270) /* * we can get EBADF if we were in transparent * mode, and the transcom process died. */ if (errno == EBADF) { /* * zero the bits (even though kernel does it) * to make sure we are selecting on the right * ones. */ memset (ibitsp, 0, fdsn); memset (obitsp, 0, fdsn); memset (xbitsp, 0, fdsn); return 0; } # endif /* defined(TN3270) */ /* I don't like this, does it ever happen? */ printf ("sleep(5) from telnet, after select\r\n"); sleep (5); } return 0; } /* * Any urgent data? */ if (FD_ISSET (net, xbitsp)) { FD_CLR (net, xbitsp); SYNCHing = 1; (void) ttyflush (1); /* flush already enqueued data */ } /* * Something to read from the network... */ if (FD_ISSET (net, ibitsp)) { int canread; FD_CLR (net, ibitsp); canread = ring_empty_consecutive (&netiring); #if !defined(SO_OOBINLINE) /* * In 4.2 (and some early 4.3) systems, the * OOB indication and data handling in the kernel * is such that if two separate TCP Urgent requests * come in, one byte of TCP data will be overlaid. * This is fatal for Telnet, but we try to live * with it. * * In addition, in 4.2 (and...), a special protocol * is needed to pick up the TCP Urgent data in * the correct sequence. * * What we do is: if we think we are in urgent * mode, we look to see if we are "at the mark". * If we are, we do an OOB receive. If we run * this twice, we will do the OOB receive twice, * but the second will fail, since the second * time we were "at the mark", but there wasn't * any data there (the kernel doesn't reset * "at the mark" until we do a normal read). * Once we've read the OOB data, we go ahead * and do normal reads. * * There is also another problem, which is that * since the OOB byte we read doesn't put us * out of OOB state, and since that byte is most * likely the TELNET DM (data mark), we would * stay in the TELNET SYNCH (SYNCHing) state. * So, clocks to the rescue. If we've "just" * received a DM, then we test for the * presence of OOB data when the receive OOB * fails (and AFTER we did the normal mode read * to clear "at the mark"). */ if (SYNCHing) { int atmark; static int bogus_oob = 0, first = 1; ioctl (net, SIOCATMARK, (char *) &atmark); if (atmark) { c = recv (net, netiring.supply, canread, MSG_OOB); if ((c == -1) && (errno == EINVAL)) { c = recv (net, netiring.supply, canread, 0); if (clocks.didnetreceive < clocks.gotDM) { SYNCHing = stilloob (net); } } else if (first && c > 0) { /* * Bogosity check. Systems based on 4.2BSD * do not return an error if you do a second * recv(MSG_OOB). So, we do one. If it * succeeds and returns exactly the same * data, then assume that we are running * on a broken system and set the bogus_oob * flag. (If the data was different, then * we probably got some valid new data, so * increment the count...) */ int i; i = recv (net, netiring.supply + c, canread - c, MSG_OOB); if (i == c && memcmp (netiring.supply, netiring.supply + c, i) == 0) { bogus_oob = 1; first = 0; } else if (i < 0) { bogus_oob = 0; first = 0; } else c += i; } if (bogus_oob && c > 0) { int i; /* * Bogosity. We have to do the read * to clear the atmark to get out of * an infinate loop. */ i = read (net, netiring.supply + c, canread - c); if (i > 0) c += i; } } else { c = recv (net, netiring.supply, canread, 0); } } else { c = recv (net, netiring.supply, canread, 0); } settimer (didnetreceive); #else /* !defined(SO_OOBINLINE) */ c = recv (net, (char *) netiring.supply, canread, 0); #endif /* !defined(SO_OOBINLINE) */ if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else if (c <= 0) { return -1; } if (netdata) { Dump ('<', netiring.supply, c); } if (c) ring_supplied (&netiring, c); returnValue = 1; } /* * Something to read from the tty... */ if (FD_ISSET (tin, ibitsp)) { FD_CLR (tin, ibitsp); c = TerminalRead (ttyiring.supply, ring_empty_consecutive (&ttyiring)); if (c < 0 && errno == EIO) c = 0; if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else { /* EOF detection for line mode!!!! */ if ((c == 0) && MODE_LOCAL_CHARS (globalmode) && isatty (tin)) { /* must be an EOF... */ *ttyiring.supply = termEofChar; c = 1; } if (c <= 0) { return -1; } if (termdata) { Dump ('<', ttyiring.supply, c); } ring_supplied (&ttyiring, c); } returnValue = 1; /* did something useful */ } if (FD_ISSET (net, obitsp)) { FD_CLR (net, obitsp); returnValue |= netflush (); } if (FD_ISSET (tout, obitsp)) { FD_CLR (tout, obitsp); returnValue |= (ttyflush (SYNCHing | flushout) > 0); } return returnValue; }
int process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int dopoll) /* If 0, then block until something to do */ { struct pollfd set[3]; int c; /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue = 0; set[0].fd = net; set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) | (netex ? POLLPRI : 0); set[1].fd = tout; set[1].events = ttyout ? POLLOUT : 0; set[2].fd = tin; set[2].events = ttyin ? POLLIN : 0; if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, * and the user does an escape (TSTP), or * some other signal generator. */ if (errno == EINTR) { return 0; } #ifdef TN3270 /* * we can get EBADF if we were in transparent * mode, and the transcom process died. */ if (errno == EBADF) return 0; #endif /* defined(TN3270) */ /* I don't like this, does it ever happen? */ printf("sleep(5) from telnet, after poll\r\n"); sleep(5); } return 0; } /* * Any urgent data? */ if (set[0].revents & POLLPRI) { SYNCHing = 1; (void) ttyflush(1); /* flush already enqueued data */ } /* * Something to read from the network... */ if (set[0].revents & POLLIN) { int canread; canread = ring_empty_consecutive(&netiring); c = recv(net, (char *)netiring.supply, canread, 0); if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else if (c <= 0) { return -1; } if (netdata) { Dump('<', netiring.supply, c); } if (c) ring_supplied(&netiring, c); returnValue = 1; } /* * Something to read from the tty... */ if (set[2].revents & POLLIN) { c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); if (c < 0 && errno == EIO) c = 0; if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else { if (c < 0) { return -1; } if (c == 0) { /* must be an EOF... */ if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { *ttyiring.supply = termEofChar; c = 1; } else { clienteof = 1; shutdown(net, 1); return 0; } } if (termdata) { Dump('<', ttyiring.supply, c); } ring_supplied(&ttyiring, c); } returnValue = 1; /* did something useful */ } if (set[0].revents & POLLOUT) { returnValue |= netflush(); } if (set[1].revents & (POLLHUP|POLLNVAL)) return(-1); if (set[1].revents & POLLOUT) { returnValue |= (ttyflush(SYNCHing|flushout) > 0); } return returnValue; }