slip.c

Go to the documentation of this file.
00001 /*      slip 1.1 - Serial line IP                       Author: Kees J. Bot
00002  *                                                              19 Jul 1997
00003  */
00004 #define nil 0
00005 #include <sys/types.h>
00006 #include <stdarg.h>
00007 #include <stdlib.h>
00008 #include <unistd.h>
00009 #include <fcntl.h>
00010 #include <string.h>
00011 #include <errno.h>
00012 #include <sys/asynchio.h>
00013 
00014 #if __minix && !__minix_vmd
00015 #define HAS_ASYN        0       /* Standard Minix doesn't have async I/O. */
00016 #else
00017 #define HAS_ASYN        1       /* Everyone else does in some way. */
00018 #endif
00019 
00020 #if !HAS_ASYN
00021 #include <signal.h>
00022 #endif
00023 
00024 #define END             0300            /* End of packet. */
00025 #define ESC             0333            /* Byte stuffing escape. */
00026 #define ESC_END         0334            /* END -> ESC ESC_END -> END. */
00027 #define ESC_ESC         0335            /* ESC -> ESC ESC_ESC -> ESC. */
00028 
00029 #define PACKLEN         2048            /* Max datagram size. */
00030 #define SLIPLEN   (1 + 2*PACKLEN + 1)   /* Max serial size when all escaped. */
00031 
00032 /* Pathetic fprintf() clone to avoid dragging in the stdio library. */
00033 static int fprintf(int fd, const char *format, ...);
00034 #define stderr  2
00035 
00036 int main(int argc, char **argv)
00037 {
00038     char *ps_device;
00039     int ps_fd;
00040     int doing[2], discard;
00041     ssize_t r;
00042 #if !HAS_ASYN
00043     pid_t other_pid;
00044 #endif
00045     size_t ps_len[2], sl_len[2];
00046     unsigned char *sl_end;
00047     unsigned char ps_buf[2][PACKLEN];
00048     unsigned char sl_buf[2][SLIPLEN];
00049     asynchio_t asyn;
00050 
00051     if (argc != 2) {
00052         fprintf(stderr, "Usage: slip psip-device\n");
00053         exit(1);
00054     }
00055     ps_device= argv[1];
00056 
00057     if ((ps_fd= open(ps_device, O_RDWR)) < 0) {
00058         fprintf(stderr, "slip: can't open %s: %s\n",
00059             ps_device, strerror(errno));
00060         exit(1);
00061     }
00062 
00063     doing[0]= 1;        /* We're doing serial -> psip. */
00064     discard= 0;         /* No input error. */
00065     sl_len[0]= 0;       /* Nothing read from serial line yet. */
00066     sl_end= nil;        /* No END marker seen. */
00067     ps_len[0]= 0;       /* Nothing to write to pseudo IP device. */
00068 
00069     doing[1]= 1;        /* We're doing psip -> serial. */
00070     sl_len[1]= 0;       /* Nothing read from pseudo IP device yet. */
00071     ps_len[1]= 0;       /* Nothing to write to serial line. */
00072 
00073 #if !HAS_ASYN
00074     /* Oops, standard Minix can't do asynchronous I/O.  Fork and let the parent
00075      * do serial -> psip, and the child do psip -> serial.  (Note that we have
00076      * to make sure that we're not reading and writing at the same time even
00077      * for standard Minix.  For Minix-vmd we do fill an input buffer while an
00078      * output buffer is waiting to be drained to improve performance a bit.)
00079      */
00080     switch ((other_pid= fork())) {
00081     case -1:
00082         fprintf(stderr, "slip: can't fork: %s\n", strerror(errno));
00083         exit(1);
00084     case 0:
00085         /* Child. */
00086         doing[0]= 0;    /* *Not* doing serial -> psip. */
00087         other_pid= getppid();
00088         break;
00089     default:
00090         /* Parent. */
00091         doing[1]= 0;    /* *Not* doing psip -> serial. */
00092     }
00093 #endif
00094 
00095     asyn_init(&asyn);
00096 
00097     for (;;) {
00098         if (doing[0]) {
00099             /* If there is an END marker in the serial input then create
00100              * an IP packet to be send to the TCP/IP task.
00101              */
00102             while (sl_end != nil && ps_len[0] == 0) {
00103                 unsigned char *sp= sl_buf[0];
00104                 unsigned char *pp= ps_buf[0];
00105 
00106                 while (sp < sl_end) {
00107                     int c= *sp++;
00108 
00109                     if (c == ESC) {
00110                         switch (*sp++) {
00111                         case ESC_ESC:   /* ESC ESC_ESC -> ESC. */
00112                             c= ESC;
00113                             break;
00114                         case ESC_END:   /* ESC ESC_END -> END. */
00115                             c= END;
00116                             break;
00117                         default:
00118                             /* Protocol error. */
00119                             discard= 1;
00120                         }
00121                     }
00122                     if (pp < ps_buf[0] + PACKLEN) {
00123                         *pp++ = c;
00124                     } else {
00125                         /* Packet too big, discard. */
00126                         discard= 1;
00127                     }
00128                 }
00129                 if (discard) {
00130                     discard= 0;
00131                 } else {
00132                     /* A new packet can be send to the TCP/IP server. */
00133                     ps_len[0]= (pp - ps_buf[0]);
00134                 }
00135                 /* Move what's beyond END to the front. */
00136                 sl_end++;
00137                 sl_len[0] -= (sl_end - sl_buf[0]);
00138                 memmove(sl_buf[0], sl_end, sl_len[0]);
00139                 sl_end= memchr(sl_buf[0], END, sl_len[0]);
00140             }
00141 
00142             /* Reading from serial input. */
00143             if (sl_end == nil && (HAS_ASYN || ps_len[0] == 0)) {
00144                 r= asyn_read(&asyn, 0, sl_buf[0] + sl_len[0],
00145                                                         SLIPLEN - sl_len[0]);
00146                 if (r > 0) {
00147                     sl_end= memchr(sl_buf[0] + sl_len[0], END, r);
00148                     sl_len[0]+= r;
00149                     if (sl_end == nil && sl_len[0] == SLIPLEN) {
00150                         /* Packet is idiotically big and no END in sight. */
00151                         sl_len[0]= 0;
00152                         discard= 1;
00153                     }
00154                 } else
00155                 if (r == 0) {
00156                     fprintf(stderr, "slip: EOF on serial input\n");
00157                     break;
00158                 } else
00159                 if (errno != ASYN_INPROGRESS) {
00160                     fprintf(stderr, "slip: serial input error: %s\n",
00161                         strerror(errno));
00162                     break;
00163                 }
00164             }
00165 
00166             /* Writing to the psip device. */
00167             if (ps_len[0] > 0) {
00168                 r= asyn_write(&asyn, ps_fd, ps_buf[0], ps_len[0]);
00169                 if (r == ps_len[0]) {
00170                     /* Packet written. */
00171                     ps_len[0]= 0;
00172                 } else
00173                 if (r >= 0) {
00174                     fprintf(stderr,
00175                         "slip: odd write to %s, tried %u, wrote %d\n",
00176                         ps_device, (unsigned) ps_len[0], (int) r);
00177                     break;
00178                 } else
00179                 if (errno != ASYN_INPROGRESS) {
00180                     fprintf(stderr, "slip: error writing %s: %s\n",
00181                         ps_device, strerror(errno));
00182                     break;
00183                 }
00184             }
00185         }
00186 
00187         if (doing[1]) {
00188             /* Transform an IP packet to a "byte stuffed" serial packet. */
00189             if (ps_len[1] > 0 && sl_len[1] == 0) {
00190                 unsigned char *pp= ps_buf[1];
00191                 unsigned char *sp= sl_buf[1];
00192 
00193                 *sp++ = END;
00194                 while (ps_len[1] > 0) {
00195                     int c= *pp++;
00196                     ps_len[1]--;
00197                     switch (c) {
00198                     case ESC:           /* ESC -> ESC ESC_ESC. */
00199                         *sp++ = ESC;
00200                         c= ESC_ESC;
00201                         break;
00202                     case END:           /* END -> ESC ESC_END. */
00203                         *sp++ = ESC;
00204                         c= ESC_END;
00205                         break;
00206                     }
00207                     *sp++ = c;
00208                 }
00209                 *sp++ = END;
00210                 sl_len[1]= (sp - sl_buf[1]);
00211             }
00212 
00213             /* Reading from the psip device. */
00214             if (ps_len[1] == 0 && (HAS_ASYN || sl_len[1] == 0)) {
00215                 r= asyn_read(&asyn, ps_fd, ps_buf[1], PACKLEN);
00216                 if (r > 0) {
00217                     /* One packet read. */
00218                     ps_len[1]= r;
00219                 } else
00220                 if (r == 0) {
00221                     fprintf(stderr, "slip: EOF on %s\n", ps_device);
00222                     break;
00223                 } else
00224                 if (errno != ASYN_INPROGRESS) {
00225                     fprintf(stderr, "slip: error reading %s: %s\n",
00226                         ps_device, strerror(errno));
00227                     break;
00228                 }
00229             }
00230 
00231             /* Writing to serial output. */
00232             if (sl_len[1] > 0) {
00233                 r= asyn_write(&asyn, 1, sl_buf[1], sl_len[1]);
00234                 if (r > 0) {
00235                     if ((sl_len[1]-= r) > 0) {
00236                         memmove(sl_buf[1], sl_buf[1] + r, sl_len[1]);
00237                     }
00238                 } else
00239                 if (r == 0) {
00240                     fprintf(stderr, "slip: EOF on serial output\n");
00241                     break;
00242                 } else
00243                 if (errno != ASYN_INPROGRESS) {
00244                     fprintf(stderr, "slip: serial output error: %s\n",
00245                         strerror(errno));
00246                     break;
00247                 }
00248             }
00249         }
00250 
00251         /* Wait for something to happen. */
00252         if (asyn_wait(&asyn, 0, nil) < 0) {
00253             fprintf(stderr,
00254                 "slip: error while waiting for I/O to happen: %s\n",
00255                 strerror(errno));
00256             break;
00257         }
00258     }
00259 #if !HAS_ASYN
00260     /* Tell my alter ego that the game is over. */
00261     kill(other_pid, SIGKILL);
00262 #endif
00263     return 1;
00264 }
00265 
00266 static int fprintf(int fd, const char *format, ...)
00267 /* Simple fprintf() to save a few bytes by not using the stdio library. */
00268 {
00269     int len;
00270     ssize_t r;
00271     const char *fp0, *fp;
00272     va_list ap;
00273 
00274     len= 0;
00275     fp= fp0= format;
00276     va_start(ap, format);
00277 
00278     while (*fp != 0) {
00279         if (*fp == '%' && memchr("sdu", fp[1], 3) != nil) {
00280             if (fp > fp0) {
00281                 if ((r= write(fd, fp0, (fp - fp0))) < 0) return -1;
00282                 len+= r;
00283             }
00284             fp++;
00285             fp0= fp+1;
00286 
00287             if (*fp == 's') {
00288                 char *s= va_arg(ap, char *);
00289 
00290                 if ((r= write(fd, s, strlen(s))) < 0) return -1;
00291                 len+= r;
00292             } else {
00293                 int d;
00294                 unsigned u;
00295                 char a[3 * sizeof(u) + 2];
00296                 char *p;
00297 
00298                 if (*fp == 'd') {
00299                     u= d= va_arg(ap, int);
00300                     if (d < 0) u= -u;
00301                 } else {
00302                     u= va_arg(ap, unsigned);
00303                     d= 0;
00304                 }
00305 
00306                 p= a + sizeof(a);
00307                 *--p= 0;
00308                 do *--p= '0' + (u % 10); while ((u /= 10) > 0);
00309 
00310                 if (d < 0) *--p= '-';
00311                 if ((r= write(fd, p, (a + sizeof(a)) - p)) < 0) return -1;
00312                 len+= r;
00313             }
00314         }
00315         fp++;
00316     }
00317     if (fp > fp0) {
00318         if ((r= write(fd, fp0, (fp - fp0))) < 0) return -1;
00319         len+= r;
00320     }
00321     va_end(ap);
00322     return len;
00323 }

Generated on Fri Apr 14 22:57:11 2006 for minix by  doxygen 1.4.6