add socket and datarate options
authorPaul Mackerras <paulus@samba.org>
Mon, 13 Mar 2000 23:39:58 +0000 (23:39 +0000)
committerPaul Mackerras <paulus@samba.org>
Mon, 13 Mar 2000 23:39:58 +0000 (23:39 +0000)
fix n_children bug

pppd/main.c
pppd/options.c
pppd/pppd.h

index 954fc2b6b977df84133bee29ffa5125095af7011..2e0604b4e55be95dd97da6aa648f549fcf2a90cd 100644 (file)
@@ -17,7 +17,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: main.c,v 1.89 2000/01/18 19:49:52 masputra Exp $"
+#define RCSID  "$Id: main.c,v 1.90 2000/03/13 23:39:58 paulus Exp $"
 
 #include <stdio.h>
 #include <ctype.h>
@@ -40,6 +40,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "pppd.h"
 #include "magic.h"
@@ -171,6 +172,7 @@ static void holdoff_end __P((void *));
 static int device_script __P((char *, int, int, int));
 static int reap_kids __P((int waitfor));
 static void record_child __P((int, char *, void (*) (void *), void *));
+static int open_socket __P((char *));
 static int start_charshunt __P((int, int));
 static void charshunt_done __P((void *));
 static void charshunt __P((int, int, char *));
@@ -295,7 +297,7 @@ main(argc, argv)
     /*
      * Work out the device name, if it hasn't already been specified.
      */
-    using_pty = notty || ptycommand != NULL;
+    using_pty = notty || ptycommand != NULL || pty_socket != NULL;
     if (!using_pty && default_device) {
        char *p;
        if (!isatty(0) || (p = ttyname(0)) == NULL) {
@@ -310,7 +312,7 @@ main(argc, argv)
     /*
      * Parse the tty options file and the command line.
      * The per-tty options file should not change
-     * ptycommand, notty or devnam.
+     * ptycommand, pty_socket, notty or devnam.
      */
     devnam_fixed = 1;
     if (!using_pty) {
@@ -363,6 +365,10 @@ main(argc, argv)
            option_error("pty option is incompatible with notty option");
            exit(EXIT_OPTION_ERROR);
        }
+       if (pty_socket != NULL && (ptycommand != NULL || notty)) {
+           option_error("socket option is incompatible with pty and notty");
+           exit(EXIT_OPTION_ERROR);
+       }
        default_device = notty;
        lockflag = 0;
        modem = 0;
@@ -576,13 +582,13 @@ main(argc, argv)
        new_phase(PHASE_SERIALCONN);
 
        /*
-        * Get a pty master/slave pair if the pty, notty, or record
-        * options were specified.
+        * Get a pty master/slave pair if the pty, notty, socket,
+        * or record options were specified.
         */
        strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
        pty_master = -1;
        pty_slave = -1;
-       if (ptycommand != NULL || notty || record_file != NULL) {
+       if (using_pty || record_file != NULL) {
            if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
                error("Couldn't allocate pseudo-tty");
                status = EXIT_FATAL_ERROR;
@@ -661,7 +667,7 @@ main(argc, argv)
        }
 
        /*
-        * If the notty and/or record option was specified,
+        * If the pty, socket, notty and/or record option was specified,
         * start up the character shunt now.
         */
        status = EXIT_PTYCMD_FAILED;
@@ -686,6 +692,12 @@ main(argc, argv)
                close(pty_master);
                pty_master = -1;
            }
+       } else if (pty_socket != NULL) {
+           int fd = open_socket(pty_socket);
+           if (fd < 0)
+               goto fail;
+           if (!start_charshunt(fd, fd))
+               goto fail;
        } else if (notty) {
            if (!start_charshunt(0, 1))
                goto fail;
@@ -1826,9 +1838,9 @@ reap_kids(waitfor)
        return 0;
     while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1
           && pid != 0) {
-       --n_children;
        for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) {
            if (chp->pid == pid) {
+               --n_children;
                *prevp = chp->next;
                break;
            }
@@ -1938,6 +1950,60 @@ script_unsetenv(var)
     }
 }
 
+/*
+ * open_socket - establish a stream socket connection to the nominated
+ * host and port.
+ */
+static int
+open_socket(dest)
+    char *dest;
+{
+    char *sep, *endp = NULL;
+    int sock, port = -1;
+    u_int32_t host;
+    struct hostent *hent;
+    struct sockaddr_in sad;
+
+    /* parse host:port and resolve host to an IP address */
+    sep = strchr(dest, ':');
+    if (sep != NULL)
+       port = strtol(sep+1, &endp, 10);
+    if (port < 0 || endp == sep+1 || sep == dest) {
+       error("Can't parse host:port for socket destination");
+       return -1;
+    }
+    *sep = 0;
+    host = inet_addr(dest);
+    if (host == (u_int32_t) -1) {
+       hent = gethostbyname(dest);
+       if (hent == NULL) {
+           error("%s: unknown host in socket option", dest);
+           *sep = ':';
+           return -1;
+       }
+       host = *(u_int32_t *)(hent->h_addr_list[0]);
+    }
+    *sep = ':';
+
+    /* get a socket and connect it to the other end */
+    sock = socket(PF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+       error("Can't create socket: %m");
+       return -1;
+    }
+    memset(&sad, 0, sizeof(sad));
+    sad.sin_family = AF_INET;
+    sad.sin_port = htons(port);
+    sad.sin_addr.s_addr = host;
+    if (connect(sock, &sad, sizeof(sad)) < 0) {
+       error("Can't connect to %s: %m", dest);
+       close(sock);
+       return -1;
+    }
+
+    return sock;
+}
+
 /*
  * start_charshunt - create a child process to run the character shunt.
  */
@@ -1998,6 +2064,8 @@ charshunt(ifd, ofd, record_file)
     int pty_readable, stdin_readable;
     struct timeval lasttime;
     FILE *recordf = NULL;
+    int ilevel, olevel, max_level;
+    struct timeval levelt, tout, *top;
 
     /*
      * Reset signal handlers.
@@ -2071,6 +2139,16 @@ charshunt(ifd, ofd, record_file)
     nibuf = nobuf = 0;
     ibufp = obufp = NULL;
     pty_readable = stdin_readable = 1;
+
+    ilevel = olevel = 0;
+    gettimeofday(&levelt, NULL);
+    if (max_data_rate) {
+       max_level = max_data_rate / 10;
+       if (max_level < 100)
+           max_level = 100;
+    } else
+       max_level = sizeof(inpacket_buf) + 1;
+
     nfds = (ofd > pty_master? ofd: pty_master) + 1;
     if (recordf != NULL) {
        gettimeofday(&lasttime, NULL);
@@ -2083,21 +2161,44 @@ charshunt(ifd, ofd, record_file)
     }
 
     while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
+       top = 0;
+       tout.tv_sec = 0;
+       tout.tv_usec = 10000;
        FD_ZERO(&ready);
        FD_ZERO(&writey);
-       if (nibuf != 0)
-           FD_SET(pty_master, &writey);
-       else if (stdin_readable)
+       if (nibuf != 0) {
+           if (ilevel >= max_level)
+               top = &tout;
+           else
+               FD_SET(pty_master, &writey);
+       } else if (stdin_readable)
            FD_SET(ifd, &ready);
-       if (nobuf != 0)
-           FD_SET(ofd, &writey);
-       else if (pty_readable)
+       if (nobuf != 0) {
+           if (olevel >= max_level)
+               top = &tout;
+           else
+               FD_SET(ofd, &writey);
+       } else if (pty_readable)
            FD_SET(pty_master, &ready);
-       if (select(nfds, &ready, &writey, NULL, NULL) < 0) {
+       if (select(nfds, &ready, &writey, NULL, top) < 0) {
            if (errno != EINTR)
                fatal("select");
            continue;
        }
+       if (max_data_rate) {
+           double dt;
+           int nbt;
+           struct timeval now;
+
+           gettimeofday(&now, NULL);
+           dt = (now.tv_sec - levelt.tv_sec
+                 + (now.tv_usec - levelt.tv_usec) / 1e6);
+           nbt = (int)(dt * max_data_rate);
+           ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt;
+           olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt;
+           levelt = now;
+       } else
+           ilevel = olevel = 0;
        if (FD_ISSET(ifd, &ready)) {
            ibufp = inpacket_buf;
            nibuf = read(ifd, ibufp, sizeof(inpacket_buf));
@@ -2153,7 +2254,10 @@ charshunt(ifd, ofd, record_file)
            }
        }
        if (FD_ISSET(ofd, &writey)) {
-           n = write(ofd, obufp, nobuf);
+           n = nobuf;
+           if (olevel + n > max_level)
+               n = max_level - olevel;
+           n = write(ofd, obufp, n);
            if (n < 0) {
                if (errno != EIO) {
                    error("Error writing standard output: %m");
@@ -2164,10 +2268,14 @@ charshunt(ifd, ofd, record_file)
            } else {
                obufp += n;
                nobuf -= n;
+               olevel += n;
            }
        }
        if (FD_ISSET(pty_master, &writey)) {
-           n = write(pty_master, ibufp, nibuf);
+           n = nibuf;
+           if (ilevel + n > max_level)
+               n = max_level - ilevel;
+           n = write(pty_master, ibufp, n);
            if (n < 0) {
                if (errno != EIO) {
                    error("Error writing pseudo-tty master: %m");
@@ -2178,6 +2286,7 @@ charshunt(ifd, ofd, record_file)
            } else {
                ibufp += n;
                nibuf -= n;
+               ilevel += n;
            }
        }
     }
index af2116dac2711dca610298ad80c2adb1ee9c1189..d9e794b23ac5d7be0b5d734c220dfb89c77bb2dd 100644 (file)
@@ -17,7 +17,7 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#define RCSID  "$Id: options.c,v 1.69 1999/12/23 01:28:52 paulus Exp $"
+#define RCSID  "$Id: options.c,v 1.70 2000/03/13 23:39:58 paulus Exp $"
 
 #include <ctype.h>
 #include <stdio.h>
@@ -93,6 +93,7 @@ int   idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
 int    holdoff = 30;           /* # seconds to pause before reconnecting */
 bool   holdoff_specified;      /* true if a holdoff value has been given */
 bool   notty = 0;              /* Stdin/out is not a tty */
+char   *pty_socket = NULL;     /* Socket to connect to pty */
 char   *record_file = NULL;    /* File to record chars sent/received */
 int    using_pty = 0;
 bool   sync_serial = 0;        /* Device is synchronous serial device */
@@ -101,6 +102,7 @@ int maxfail = 10;           /* max # of unsuccessful connection attempts */
 char   linkname[MAXPATHLEN];   /* logical name for link */
 bool   tune_kernel;            /* may alter kernel settings */
 int    connect_delay = 1000;   /* wait this many ms after connect script */
+int    max_data_rate;          /* max bytes/sec through charshunt */
 
 extern option_t auth_options[];
 extern struct stat devstat;
@@ -205,6 +207,8 @@ option_t general_options[] = {
       OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
     { "notty", o_bool, &notty,
       "Input/output is not a tty", OPT_DEVNAM | 1 },
+    { "socket", o_string, &pty_socket,
+      "Send and receive over socket, arg is host:port", OPT_DEVNAM },
     { "record", o_string, &record_file,
       "Record characters sent/received to file" },
     { "maxconnect", o_int, &maxconnect,
@@ -270,6 +274,8 @@ option_t general_options[] = {
       "Don't alter kernel settings", 0 },
     { "connect-delay", o_int, &connect_delay,
       "Maximum time (in ms) to wait after connect script finishes" },
+    { "datarate", o_int, &max_data_rate,
+      "Maximum data rate in bytes/sec (with pty, notty or record option)" },
 #ifdef PLUGIN
     { "plugin", o_special, loadplugin,
       "Load a plug-in module into pppd", OPT_PRIV },
index 4e094c87f06b4897c3d4129c12a3fab51a57daaa..5dfe83b5dec6b639cafdf6a01819b65cb80e079e 100644 (file)
@@ -16,7 +16,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: pppd.h,v 1.49 1999/12/23 01:29:42 paulus Exp $
+ * $Id: pppd.h,v 1.50 2000/03/13 23:39:58 paulus Exp $
  */
 
 /*
@@ -209,12 +209,14 @@ extern int        idle_time_limit;/* Shut down link if idle for this long */
 extern int     holdoff;        /* Dead time before restarting */
 extern bool    holdoff_specified; /* true if user gave a holdoff value */
 extern bool    notty;          /* Stdin/out is not a tty */
+extern char    *pty_socket;    /* Socket to connect to pty */
 extern char    *record_file;   /* File to record chars sent/received */
 extern bool    sync_serial;    /* Device is synchronous serial device */
 extern int     maxfail;        /* Max # of unsuccessful connection attempts */
 extern char    linkname[MAXPATHLEN]; /* logical name for link */
 extern bool    tune_kernel;    /* May alter kernel settings as necessary */
 extern int     connect_delay;  /* Time to delay after connect script */
+extern int     max_data_rate;  /* max bytes/sec through charshunt */
 
 #ifdef PPP_FILTER
 extern struct  bpf_program pass_filter;   /* Filter for pkts to pass */