cleanups, add manual page
[unix-history] / usr / src / usr.bin / telnet / sys_bsd.c
index 26de648..b010b84 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)sys_bsd.c  1.14 (Berkeley) %G%";
+#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.
 /*
  * The following routines try to encapsulate what is system dependent
  * (at least between 4.x and dos) which is used in telnet.c.
 #if    defined(unix)
 
 #include <sys/ioctl.h>
 #if    defined(unix)
 
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <sys/time.h>
 #include <sys/time.h>
+#include <sys/socket.h>
 #include <signal.h>
 #include <signal.h>
+#include <errno.h>
+
+#include "ring.h"
+
+#include "fdset.h"
 
 #include "defines.h"
 #include "externs.h"
 #include "types.h"
 
 int
 
 #include "defines.h"
 #include "externs.h"
 #include "types.h"
 
 int
+       tout,                   /* Output file descriptor */
+       tin,                    /* Input file descriptor */
+       net,
        HaveInput;              /* There is input available to scan */
 
        HaveInput;              /* There is input available to scan */
 
-#if    defined(TN3270)
-static char    tline[200];
-char   *transcom = 0;  /* transparent mode command (default: none) */
-#endif /* defined(TN3270) */
-
 static struct  tchars otc = { 0 }, ntc = { 0 };
 static struct  ltchars oltc = { 0 }, nltc = { 0 };
 static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
 
 static struct  tchars otc = { 0 }, ntc = { 0 };
 static struct  ltchars oltc = { 0 }, nltc = { 0 };
 static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
 
+static fd_set ibits, obits, xbits;
 
 
-TerminalWrite(fd, buf, n)
-int    fd;
+
+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;
 {
 char   *buf;
 int    n;
 {
-    return write(fd, buf, n);
+    return write(tout, buf, n);
 }
 
 }
 
-TerminalRead(fd, buf, n)
-int    fd;
+TerminalRead(buf, n)
 char   *buf;
 int    n;
 {
 char   *buf;
 int    n;
 {
-    return read(fd, buf, n);
+    return read(tin, buf, n);
 }
 
 /*
 }
 
 /*
@@ -47,7 +85,7 @@ int   n;
  */
 
 int
  */
 
 int
-TerminalAutoFlush()                                    /* unix */
+TerminalAutoFlush()
 {
 #if    defined(LNOFLSH)
     int flush;
 {
 #if    defined(LNOFLSH)
     int flush;
@@ -72,10 +110,10 @@ TerminalAutoFlush()                                        /* unix */
  */
 
 int
  */
 
 int
-TerminalSpecialChars(c)                        /* unix */
+TerminalSpecialChars(c)
 int    c;
 {
 int    c;
 {
-    void doflush(), intp(), sendbrk();
+    void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
 
     if (c == ntc.t_intrc) {
        intp();
 
     if (c == ntc.t_intrc) {
        intp();
@@ -104,13 +142,13 @@ int       c;
  */
  
 void
  */
  
 void
-TerminalFlushOutput()                          /* unix */
+TerminalFlushOutput()
 {
     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
 }
 
 void
 {
     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
 }
 
 void
-TerminalSaveState()                            /* unix */
+TerminalSaveState()
 {
     ioctl(0, TIOCGETP, (char *)&ottyb);
     ioctl(0, TIOCGETC, (char *)&otc);
 {
     ioctl(0, TIOCGETP, (char *)&ottyb);
     ioctl(0, TIOCGETC, (char *)&otc);
@@ -119,10 +157,17 @@ TerminalSaveState()                               /* unix */
     ntc = otc;
     nltc = oltc;
     nttyb = ottyb;
     ntc = otc;
     nltc = oltc;
     nttyb = ottyb;
+
+    termEofChar = ntc.t_eofc;
+    termEraseChar = nttyb.sg_erase;
+    termFlushChar = nltc.t_flushc;
+    termIntChar = ntc.t_intrc;
+    termKillChar = nttyb.sg_kill;
+    termQuitChar = ntc.t_quitc;
 }
 
 void
 }
 
 void
-TerminalRestoreState()                         /* unix */
+TerminalRestoreState()
 {
 }
 
 {
 }
 
@@ -132,8 +177,7 @@ TerminalRestoreState()                              /* unix */
 
 
 void
 
 
 void
-TerminalNewMode(fd_in, fd_out, f)                      /* unix */
-int    fd_in, fd_out;          /* File descriptor */
+TerminalNewMode(f)
 register int f;
 {
     static int prevmode = 0;
 register int f;
 {
     static int prevmode = 0;
@@ -234,40 +278,40 @@ register int f;
     default:
            return;
     }
     default:
            return;
     }
-    ioctl(fd_in, TIOCSLTC, (char *)ltc);
-    ioctl(fd_in, TIOCSETC, (char *)tc);
-    ioctl(fd_in, TIOCSETP, (char *)&sb);
+    ioctl(tin, TIOCSLTC, (char *)ltc);
+    ioctl(tin, TIOCSETC, (char *)tc);
+    ioctl(tin, TIOCSETP, (char *)&sb);
 #if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
 #if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
-    ioctl(fd_in, FIONBIO, (char *)&onoff);
-    ioctl(fd_out, FIONBIO, (char *)&onoff);
+    ioctl(tin, FIONBIO, (char *)&onoff);
+    ioctl(tout, FIONBIO, (char *)&onoff);
 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
 #if    defined(TN3270)
     if (noasynch == 0) {
 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
 #if    defined(TN3270)
     if (noasynch == 0) {
-       ioctl(fd_in, FIOASYNC, (char *)&onoff);
+       ioctl(tin, FIOASYNC, (char *)&onoff);
     }
 #endif /* defined(TN3270) */
 
     if (MODE_LINE(f)) {
        void doescape();
 
     }
 #endif /* defined(TN3270) */
 
     if (MODE_LINE(f)) {
        void doescape();
 
-       signal(SIGTSTP, doescape);
+       (void) signal(SIGTSTP, (int (*)())doescape);
     } else if (MODE_LINE(old)) {
     } else if (MODE_LINE(old)) {
-       signal(SIGTSTP, SIG_DFL);
+       (void) signal(SIGTSTP, SIG_DFL);
        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
     }
 }
 
 
 int
        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
     }
 }
 
 
 int
-NetClose(net)
-int    net;
+NetClose(fd)
+int    fd;
 {
 {
-    return close(net);
+    return close(fd);
 }
 
 
 void
 }
 
 
 void
-NetNonblockingIO(fd, onoff)                            /* unix */
+NetNonblockingIO(fd, onoff)
 int
        fd,
        onoff;
 int
        fd,
        onoff;
@@ -275,8 +319,9 @@ int
     ioctl(fd, FIONBIO, (char *)&onoff);
 }
 
     ioctl(fd, FIONBIO, (char *)&onoff);
 }
 
+#if    defined(TN3270)
 void
 void
-NetSigIO(fd, onoff)                            /* unix */
+NetSigIO(fd, onoff)
 int
        fd,
        onoff;
 int
        fd,
        onoff;
@@ -285,7 +330,7 @@ int
 }
 
 void
 }
 
 void
-NetSetPgrp(fd)                         /* unix */
+NetSetPgrp(fd)
 int fd;
 {
     int myPid;
 int fd;
 {
     int myPid;
@@ -296,6 +341,275 @@ int fd;
 #endif /* defined(NOT43) */
     ioctl(fd, SIOCSPGRP, (char *)&myPid);      /* set my pid */
 }
 #endif /* defined(NOT43) */
     ioctl(fd, SIOCSPGRP, (char *)&myPid);      /* set my pid */
 }
+#endif /*defined(TN3270)*/
+\f
+/*
+ * Various signal handling routines.
+ */
 
 
+static void
+deadpeer()
+{
+       setcommandmode();
+       longjmp(peerdied, -1);
+}
 
 
+static void
+intr()
+{
+    if (localchars) {
+       intp();
+       return;
+    }
+    setcommandmode();
+    longjmp(toplevel, -1);
+}
+
+static void
+intr2()
+{
+    if (localchars) {
+       sendbrk();
+       return;
+    }
+}
+
+static void
+doescape()
+{
+    command(0);
+}
+\f
+void
+sys_telnet_init()
+{
+    (void) signal(SIGINT, (int (*)())intr);
+    (void) signal(SIGQUIT, (int (*)())intr2);
+    (void) signal(SIGPIPE, (int (*)())deadpeer);
+
+    setconnmode();
+
+    NetNonblockingIO(net, 1);
+
+#if    defined(TN3270)
+    if (noasynch == 0) {                       /* DBX can't handle! */
+       NetSigIO(net, 1);
+       NetSetPgrp(net);
+    }
+#endif /* defined(TN3270) */
+
+#if    defined(SO_OOBINLINE)
+    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
+       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 };
+
+    if (netout) {
+       FD_SET(net, &obits);
+    } 
+    if (ttyout) {
+       FD_SET(tout, &obits);
+    }
+#if    defined(TN3270)
+    if (ttyin) {
+       FD_SET(tin, &ibits);
+    }
+#else  /* defined(TN3270) */
+    if (ttyin) {
+       FD_SET(tin, &ibits);
+    }
+#endif /* defined(TN3270) */
+#if    defined(TN3270)
+    if (netin) {
+       FD_SET(net, &ibits);
+    }
+#   else /* !defined(TN3270) */
+    if (netin) {
+       FD_SET(net, &ibits);
+    }
+#   endif /* !defined(TN3270) */
+    if (netex) {
+       FD_SET(net, &xbits);
+    }
+    if ((c = select(16, &ibits, &obits, &xbits,
+                       (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.
+                       */
+               FD_ZERO(&ibits);
+               FD_ZERO(&obits);
+               FD_ZERO(&xbits);
+               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, &xbits)) {
+       FD_CLR(net, &xbits);
+       SYNCHing = 1;
+       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;
+
+           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 {
+               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)
+           ring_supplied(&netiring, c);
+       returnValue = 1;
+    }
+
+    /*
+     * Something to read from the tty...
+     */
+    if (FD_ISSET(tin, &ibits)) {
+       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... */
+               *ttyiring.supply = termEofChar;
+               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();
+    }
+    if (FD_ISSET(tout, &obits)) {
+       FD_CLR(tout, &obits);
+       returnValue |= ttyflush(SYNCHing|flushout);
+    }
+
+    return returnValue;
+}
 #endif /* defined(unix) */
 #endif /* defined(unix) */