URI:
       tlpsend.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tlpsend.c (6202B)
       ---
            1 #ifdef plan9
            2 
            3 #include <u.h>
            4 #include <libc.h>
            5 #define         stderr        2
            6 
            7 #define RDNETIMEOUT        60000
            8 #define WRNETIMEOUT        60000
            9 
           10 #else
           11 
           12 /* not for plan 9 */
           13 #include <stdio.h>
           14 #include <errno.h>
           15 #include <time.h>
           16 #include <fcntl.h>
           17 #include <signal.h>
           18 
           19 #define        create        creat
           20 #define        seek        lseek
           21 #define        fprint        fprintf
           22 #define        sprint        sprintf
           23 #define        exits        exit
           24 
           25 #define        ORDWR        O_RDWR
           26 #define        OTRUNC        O_TRUNC
           27 #define        ORCLOSE        0
           28 
           29 #define RDNETIMEOUT        60
           30 #define WRNETIMEOUT        60
           31 
           32 #endif
           33 
           34 #define MIN(a,b)        ((a<b)?a:b)
           35 
           36 #define        ACK(a)        write(a, "", 1)
           37 #define NAK(a)        write(a, "\001", 1)
           38 
           39 #define LPDAEMONLOG        "/tmp/lpdaemonl"
           40 
           41 #define LNBFSZ        4096
           42 char lnbuf[LNBFSZ];
           43 int dbgstate = 0;
           44 char *dbgstrings[] = {
           45         "",
           46         "rcvack1",
           47         "send",
           48         "rcvack2",
           49         "response",
           50         "done"
           51 };
           52 
           53 #ifdef plan9
           54 
           55 void
           56 error(int level, char *s1, ...)
           57 {
           58         va_list ap;
           59         long thetime;
           60         char *chartime;
           61         char *args[8];
           62         int argno = 0;
           63 
           64         if (level == 0) {
           65                 time(&thetime);
           66                 chartime = ctime(thetime);
           67                 fprint(stderr, "%.15s ", &(chartime[4]));
           68         }
           69         va_start(ap, s1);
           70         while(args[argno++] = va_arg(ap, char*));
           71         va_end(ap);
           72         fprint(stderr, s1, *args);
           73         return;
           74 }
           75 
           76 int
           77 alarmhandler(void *foo, char *note) {
           78         USED(foo);
           79         if(strcmp(note, "alarm")==0) {
           80                 fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
           81                 return(1);
           82         } else return(0);
           83 }
           84 
           85 #else
           86 
           87 void
           88 error(int level, char *s1, ...)
           89 {
           90         time_t thetime;
           91         char *chartime;
           92 
           93         if (level == 0) {
           94                 time(&thetime);
           95                 chartime = ctime(&thetime);
           96                 fprintf(stderr, "%.15s ", &(chartime[4]));
           97         }
           98         fprintf(stderr, s1, (&s1+1));
           99         return;
          100 }
          101 
          102 void
          103 alarmhandler() {
          104         fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
          105 }
          106 
          107 #endif
          108 
          109 /* get a line from inpfd using nonbuffered input.  The line is truncated if it is too
          110  * long for the buffer.  The result is left in lnbuf and the number of characters
          111  * read in is returned.
          112  */
          113 int
          114 readline(int inpfd)
          115 {
          116         register char *ap;
          117         register int i;
          118 
          119         ap = lnbuf;
          120         i = 0;
          121         do {
          122                 if (read(inpfd, ap, 1) != 1) {
          123                         error(0, "read error in readline, fd=%d\n", inpfd);
          124                         break;
          125                 }
          126         } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
          127         if (i == LNBFSZ - 2) {
          128                 *ap = '\n';
          129                 i++;
          130         }
          131         *ap = '\0';
          132         return(i);
          133 }
          134 
          135 #define        RDSIZE 512
          136 char jobbuf[RDSIZE];
          137 
          138 int
          139 pass(int inpfd, int outfd, int bsize)
          140 {
          141         int bcnt = 0;
          142         int rv = 0;
          143 
          144         for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
          145                 alarm(WRNETIMEOUT);        /* to break hanging */
          146                 if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
          147                         error(0, "read error during pass, %d remaining\n", bcnt);
          148                         break;
          149                 } else if((write(outfd, jobbuf, rv)) != rv) {
          150                         error(0, "write error during pass, %d remaining\n", bcnt);
          151                         break;
          152                 }
          153         }
          154         alarm(0);
          155         return(bcnt);
          156 }
          157 
          158 /* get whatever stdin has and put it into the temporary file.
          159  * return the file size.
          160  */
          161 int
          162 prereadfile(int inpfd)
          163 {
          164         int rv, bsize;
          165 
          166         bsize = 0;
          167         do {
          168                 if((rv=read(0, jobbuf, RDSIZE))<0) {
          169                         error(0, "read error while making temp file\n");
          170                         exits("read error while making temp file");
          171                 } else if((write(inpfd, jobbuf, rv)) != rv) {
          172                         error(0, "write error while making temp file\n");
          173                         exits("write error while making temp file");
          174                 }
          175                 bsize += rv;
          176         } while (rv!=0);
          177         return(bsize);
          178 }
          179 
          180 int
          181 tempfile(void)
          182 {
          183         static int tindx = 0;
          184         char tmpf[20];
          185         int tmpfd;
          186 
          187         sprint(tmpf, "/var/tmp/lp%d.%d", getpid(), tindx++);
          188         if((tmpfd=create(tmpf,
          189 
          190 #ifdef plan9
          191 
          192                                                 ORDWR|OTRUNC,
          193 
          194 #endif
          195 
          196                                                                                                 0666)) < 0) {
          197                 error(0, "cannot create temp file %s\n", tmpf);
          198                 exits("cannot create temp file");
          199         }
          200         close(tmpfd);
          201         if((tmpfd=open(tmpf, ORDWR
          202 
          203 #ifdef plan9
          204 
          205                                                 |ORCLOSE|OTRUNC
          206 
          207 #endif
          208 
          209                                                                         )) < 0) {
          210                 error(0, "cannot open temp file %s\n", tmpf);
          211                 exits("cannot open temp file");
          212         }
          213         return(tmpfd);
          214 }
          215 
          216 int
          217 recvACK(int netfd)
          218 {
          219         int rv;
          220 
          221         *jobbuf = '\0';
          222         alarm(RDNETIMEOUT);
          223         if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
          224                 error(0, "failed to receive ACK, ");
          225                 if (*jobbuf == '\0')
          226                         error(1, "read failed\n");
          227                 else
          228                         error(1, "received <0x%x> instead\n", *jobbuf);
          229                 rv = 0;
          230         } else rv = 1;
          231         alarm(0);
          232         return(rv);
          233 }
          234 
          235 void
          236 main(int argc, char *argv[])
          237 {
          238         char *devdir;
          239         int i, rv, netfd, bsize;
          240         int datafd;
          241 
          242 #ifndef plan9
          243 
          244         void (*oldhandler)();
          245 
          246 #endif
          247 
          248         devdir = nil;
          249         /* make connection */
          250         if (argc != 2) {
          251                 fprint(stderr, "usage: %s network!destination!service\n", argv[0]);
          252                 exits("incorrect number of arguments");
          253         }
          254 
          255         /* read options line from stdin into lnbuf */
          256         i = readline(0);
          257 
          258         /* read stdin into tempfile to get size */
          259         datafd = tempfile();
          260         bsize = prereadfile(datafd);
          261 
          262         /* network connection is opened after data is in to avoid timeout */
          263         if ((netfd=dial(argv[1], 0, 0, 0)) < 0) {
          264                 fprint(stderr, "dialing %s\n", devdir);
          265                 perror("dial");
          266                 exits("can't dial");
          267         }
          268 
          269         /* write out the options we read above */
          270         if (write(netfd, lnbuf, i) != i) {
          271                 error(0, "write error while sending options\n");
          272                 exits("write error while sending options");
          273         }
          274 
          275         /* send the size of the file to be sent */
          276         sprint(lnbuf, "%d\n", bsize);
          277         i = strlen(lnbuf);
          278         if ((rv=write(netfd, lnbuf, i)) != i) {
          279                 perror("write error while sending size");
          280                 error(0, "write returned %d\n", rv);
          281                 exits("write error while sending size");
          282         }
          283 
          284         if (seek(datafd, 0L, 0) < 0) {
          285                 error(0, "error seeking temp file\n");
          286                 exits("seek error");
          287         }
          288         /* mirror performance in readfile() in lpdaemon */
          289 
          290 #ifdef plan9
          291 
          292         atnotify(alarmhandler, 1);
          293 
          294 #else
          295 
          296         oldhandler = signal(SIGALRM, alarmhandler);
          297 
          298 #endif
          299 
          300         dbgstate = 1;
          301         if(!recvACK(netfd)) {
          302                 error(0, "failed to receive ACK before sending data\n");
          303                 exits("recv ack1 failed");
          304         }
          305         dbgstate = 2;
          306         if ((i=pass(datafd, netfd, bsize)) != 0) {
          307                 NAK(netfd);
          308                 error(0, "failed to send %d bytes\n", i);
          309                 exits("send data failed");
          310         }
          311         ACK(netfd);
          312         dbgstate = 3;
          313         if(!recvACK(netfd)) {
          314                 error(0, "failed to receive ACK after sending data\n");
          315                 exits("recv ack2 failed");
          316         }
          317 
          318         /* get response, as from lp -q */
          319         dbgstate = 4;
          320         while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
          321                 if((write(1, jobbuf, rv)) != rv) {
          322                         error(0, "write error while sending to stdout\n");
          323                         exits("write error while sending to stdout");
          324                 }
          325         }
          326         dbgstate = 5;
          327 
          328 #ifdef plan9
          329 
          330         atnotify(alarmhandler, 0);
          331         /* close down network connections and go away */
          332         exits("");
          333 
          334 #else
          335 
          336         signal(SIGALRM, oldhandler);
          337         exit(0);
          338 
          339 #endif
          340 
          341 }