home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988, 1990 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement: ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * Neither the name of the University nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)sys_bsd.c 5.1 (Berkeley) 9/14/90";
- #endif /* not lint */
-
- /*
- * The following routines try to encapsulate what is system dependent
- * (at least between 4.x and dos) which is used in telnet.c.
- */
-
-
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <string.h>
- #include <sys/socket.h>
- #ifdef AMI_TCP
- #include <bsdsocket.h>
- #else
- #include <ss/socket.h>
- #endif
- #include <signal.h>
- #include <errno.h>
- #include <arpa/telnet.h>
- #ifdef __SASC
- #include <ios1.h>
- #endif
- #include "ring.h"
-
- #include "fdset.h"
-
- #include "defines.h"
- #include "externs.h"
- #include "types.h"
-
- #define SIG_FUNC_RET int
-
- int
- tout, /* Output file descriptor */
- tin, /* Input file descriptor */
- net;
-
- #ifndef AMI_TCP
- struct tchars otc = { 0 }, ntc = { 0 };
- struct sgttyb ottyb = { 0 }, nttyb = { 0 };
- #endif
- int olmode = 0;
- # define cfgetispeed(ptr) (ptr)->sg_ispeed
- # define cfgetospeed(ptr) (ptr)->sg_ospeed
- # define old_tc ottyb
-
- static fd_set ibits, obits, xbits;
-
- //void (*signal())()
- //{ return;
- //}
-
- init_sys()
- {
- tout = fileno(stdout);
- tin = fileno(stdin);
- FD_ZERO(&ibits);
- FD_ZERO(&obits);
- FD_ZERO(&xbits);
-
- errno = 0;
- }
-
-
- TerminalWrite(buf, n)
- char *buf;
- int n;
- {
- return write(tout, buf, n);
- }
-
- TerminalRead(buf, n)
- char *buf;
- int n;
- {
- return read(tin, buf, n);
- }
-
- /*
- *
- */
-
- int
- TerminalAutoFlush()
- {
- return 1;
- }
-
-
- /*
- * Flush output to the terminal
- */
-
- void
- TerminalFlushOutput()
- {
- fflush(stdout);
- }
-
- void
- TerminalSaveState()
- {
- return;
- }
-
- cc_t *
- tcval(func)
- register int func;
- {
- switch(func) {
- case SLC_SYNCH:
- case SLC_BRK:
- case SLC_EOR:
- default:
- return((cc_t *)0);
- }
- }
-
- void
- TerminalDefaultChars()
- {
- return;
- }
-
- #ifdef notdef
- void
- TerminalRestoreState()
- {
- }
- #endif
-
- /*
- * TerminalNewMode - set up terminal to a specific mode.
- * MODE_ECHO: do local terminal echo
- * MODE_FLOW: do local flow control
- * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
- * MODE_EDIT: do local line editing
- *
- * Command mode:
- * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
- * local echo
- * local editing
- * local xon/xoff
- * local signal mapping
- *
- * Linemode:
- * local/no editing
- * Both Linemode and Single Character mode:
- * local/remote echo
- * local/no xon/xoff
- * local/no signal mapping
- */
-
-
- void
- TerminalNewMode(f)
- register int f;
- {
- static int prevmode = 0;
- #ifndef USE_TERMIO
- #ifdef __SASC
- int ami_cbreak = 0;
- #else
- struct sgttyb sb;
- #endif
- #endif
- int lmode;
- int onoff;
- int old;
-
- globalmode = f&~MODE_FORCE;
- if (prevmode == f)
- return;
-
- /*
- * Write any outstanding data before switching modes
- * ttyflush() returns 0 only when there is no more data
- * left to write out, it returns -1 if it couldn't do
- * anything at all, otherwise it returns 1 + the number
- * of characters left to write.
- #ifndef USE_TERMIO
- * We would really like ask the kernel to wait for the output
- * to drain, like we can do with the TCSADRAIN, but we don't have
- * that option. The only ioctl that waits for the output to
- * drain, TIOCSETP, also flushes the input queue, which is NOT
- * what we want (TIOCSETP is like TCSADFLUSH).
- #endif
- */
- old = ttyflush(SYNCHing|flushout);
- if (old < 0 || old > 1) {
- do {
- /*
- * Wait for data to drain, then flush again.
- */
- old = ttyflush(SYNCHing|flushout);
- } while (old < 0 || old > 1);
- }
-
- old = prevmode;
- prevmode = f&~MODE_FORCE;
- lmode = olmode;
-
- if (f&MODE_ECHO) {
- #ifndef __SASC
- sb.sg_flags |= ECHO;
- #endif
- } else {
- #ifndef __SASC
- sb.sg_flags &= ~ECHO;
- #endif
- }
-
- if ((f&MODE_FLOW) == 0) {
- }
-
- if ((f&MODE_TRAPSIG) == 0) {
- localchars = 0;
- } else {
- localchars = 1;
- }
-
- if (f&MODE_EDIT) {
- #ifdef __SASC
- ami_cbreak = 0;
- #else
- sb.sg_flags &= ~CBREAK;
- sb.sg_flags &= ~RAW;
- sb.sg_flags |= CRMOD;
- #endif
- } else {
- #ifdef __SASC
- ami_cbreak = 1;
- #else
- sb.sg_flags |= CBREAK;
- sb.sg_flags |= RAW;
- if (f&MODE_ECHO)
- sb.sg_flags |= CRMOD;
- else
- sb.sg_flags &= ~CRMOD;
- #endif
- }
-
- if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
- }
-
- if (f&MODE_SOFT_TAB) {
- #ifndef __SASC
- sb.sg_flags |= XTABS;
- #endif
- } else {
- #ifndef __SASC
- sb.sg_flags &= ~XTABS;
- #endif
- }
-
- if (f&MODE_LIT_ECHO) {
- } else {
- }
-
- if (f == -1) {
- onoff = 0;
- } else {
- onoff = 1;
- }
-
- if (f != -1) {
- /*
- * We don't want to process ^Y here. It's just another
- * character that we'll pass on to the back end. It has
- * to process it because it will be processed when the
- * user attempts to read it, not when we send it.
- */
- } else {
- lmode = olmode;
- }
- #ifdef __SASC
- SetMode(chkufb(0)->ufbfh,ami_cbreak);
- #else
- SetMode(_devtab[0].fd,(sb.sg_flags & CBREAK) ? 1L : 0L);
- #endif
-
- ioctl(tin, FIONBIO, (char *)&onoff);
- ioctl(tout, FIONBIO, (char *)&onoff);
- }
-
-
- int
- TerminalWindowSize(rows, cols)
- long *rows, *cols;
- {
- return 0;
- }
-
- int
- NetClose(fd)
- int fd;
- {
- #ifdef AMI_TCP
- return CloseSocket(fd);
- #else
- return s_close(fd);
- #endif
- }
-
-
- void
- NetNonblockingIO(fd, onoff)
- int
- fd,
- onoff;
- {
- ioctl(fd, FIONBIO, (char *)&onoff);
- }
-
- /*
- * Various signal handling routines.
- */
-
- /* ARGSUSED */
- static SIG_FUNC_RET
- deadpeer(sig)
- int sig;
- {
- setcommandmode();
- longjmp(peerdied, -1);
- }
-
- /* ARGSUSED */
- static SIG_FUNC_RET
- intr(sig)
- int sig;
- {
- if (localchars) {
- intp();
- return;
- }
- setcommandmode();
- longjmp(toplevel, -1);
- }
-
- /* ARGSUSED */
- static SIG_FUNC_RET
- intr2(sig)
- int sig;
- {
- if (localchars) {
- sendabort();
- return;
- }
- }
-
- #ifdef SIGTSTP
- /* ARGSUSED */
- static SIG_FUNC_RET
- susp(sig)
- int sig;
- {
- if (localchars)
- sendsusp();
- }
- #endif
-
- #ifdef SIGWINCH
- /* ARGSUSED */
- static SIG_FUNC_RET
- sendwin(sig)
- int sig;
- {
- if (connected) {
- sendnaws();
- }
- }
- #endif
-
- #ifdef SIGINFO
- /* ARGSUSED */
- static SIG_FUNC_RET
- ayt(sig)
- int sig;
- {
- if (connected)
- sendayt();
- else
- ayt_status();
- }
- #endif
-
- void
- sys_telnet_init()
- {
- setconnmode(0);
-
- NetNonblockingIO(net, 1);
-
- #if defined(SO_OOBINLINE)
- { int one=1;
- #ifdef AMI_TCP
- if (setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &one,sizeof(one)) == -1)
- #else
- if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, &one,sizeof(one)) == -1)
- #endif
- {
- perror("SetSockOpt");
- }
- }
- #endif /* defined(SO_OOBINLINE) */
- }
-
- /*
- * Process rings -
- *
- * This routine tries to fill up/empty our various rings.
- *
- * The parameter specifies whether this is a poll operation,
- * or a block-until-something-happens operation.
- *
- * The return value is 1 if something happened, 0 if not.
- */
-
- int
- process_rings(netin, netout, netex, ttyin, ttyout, poll)
- int poll; /* If 0, then block until something to do */
- {
- register 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 };
- static struct timeval Quickie = {0L,20000L};
- extern long bytesin;
- if (netout) {
- FD_SET(net, &obits);
- }
- if (netin) {
- FD_SET(net, &ibits);
- }
- if (netex) {
- FD_SET(net, &xbits);
- }
- if ((c = select(16, &ibits, &obits, &xbits,
- (poll == 0)? (struct timeval *)&Quickie : &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;
- }
- /* 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, &xbits)) {
- FD_CLR(net, &xbits);
- SYNCHing = 1;
- (void) ttyflush(1); /* flush already enqueued data */
- }
-
- /*
- * Something to read from the network...
- */
- if (FD_ISSET(net, &ibits)) {
- int canread;
-
- FD_CLR(net, &ibits);
- 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;
-
- s_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 &&
- bcmp(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, 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)
- bytesin+=c;
- ring_supplied(&netiring, c);
- returnValue = 1;
- }
-
- /*
- * Something to read from the tty...
- */
- #ifdef __SASC
- if (WaitForChar(chkufb(0)->ufbfh,Quickie.tv_usec)) {
- #else
- if (WaitForChar(_devtab[0].fd,Quickie.tv_usec)) {
- #endif
- // FD_CLR(tin, &ibits);
- c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
- 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... */
- #ifndef __SASC
- *ttyiring.supply = termEofChar;
- #endif
- c = 1;
- }
- if (c <= 0) {
- return -1;
- }
- ring_supplied(&ttyiring, c);
- }
- returnValue = 1; /* did something useful */
- }
-
- if (FD_ISSET(net, &obits)) {
- FD_CLR(net, &obits);
- returnValue |= netflush();
- }
- returnValue |= (ttyflush(SYNCHing|flushout) > 0);
- return returnValue;
- }
-