Annotation of embedaddon/curl/tests/server/tftpd.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  *
                      9:  * Trivial file transfer protocol server.
                     10:  *
                     11:  * This code includes many modifications by Jim Guyton <guyton@rand-unix>
                     12:  *
                     13:  * This source file was started based on netkit-tftpd 0.17
                     14:  * Heavily modified for curl's test suite
                     15:  */
                     16: 
                     17: /*
                     18:  * Copyright (C) 2005 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
                     19:  * Copyright (c) 1983, Regents of the University of California.
                     20:  * All rights reserved.
                     21:  *
                     22:  * Redistribution and use in source and binary forms, with or without
                     23:  * modification, are permitted provided that the following conditions
                     24:  * are met:
                     25:  * 1. Redistributions of source code must retain the above copyright
                     26:  *    notice, this list of conditions and the following disclaimer.
                     27:  * 2. Redistributions in binary form must reproduce the above copyright
                     28:  *    notice, this list of conditions and the following disclaimer in the
                     29:  *    documentation and/or other materials provided with the distribution.
                     30:  * 3. All advertising materials mentioning features or use of this software
                     31:  *    must display the following acknowledgement:
                     32:  *      This product includes software developed by the University of
                     33:  *      California, Berkeley and its contributors.
                     34:  * 4. Neither the name of the University nor the names of its contributors
                     35:  *    may be used to endorse or promote products derived from this software
                     36:  *    without specific prior written permission.
                     37:  *
                     38:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     39:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     40:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     41:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     42:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     43:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     44:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     45:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     46:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     47:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     48:  * SUCH DAMAGE.
                     49:  */
                     50: 
                     51: #include "server_setup.h"
                     52: 
                     53: #ifdef HAVE_SYS_IOCTL_H
                     54: #include <sys/ioctl.h>
                     55: #endif
                     56: #ifdef HAVE_SIGNAL_H
                     57: #include <signal.h>
                     58: #endif
                     59: #ifdef HAVE_FCNTL_H
                     60: #include <fcntl.h>
                     61: #endif
                     62: #ifdef HAVE_NETINET_IN_H
                     63: #include <netinet/in.h>
                     64: #endif
                     65: #ifdef HAVE_ARPA_INET_H
                     66: #include <arpa/inet.h>
                     67: #endif
                     68: #ifdef HAVE_ARPA_TFTP_H
                     69: #include <arpa/tftp.h>
                     70: #else
                     71: #include "tftp.h"
                     72: #endif
                     73: #ifdef HAVE_NETDB_H
                     74: #include <netdb.h>
                     75: #endif
                     76: #ifdef HAVE_SYS_FILIO_H
                     77: /* FIONREAD on Solaris 7 */
                     78: #include <sys/filio.h>
                     79: #endif
                     80: 
                     81: #include <setjmp.h>
                     82: 
                     83: #ifdef HAVE_PWD_H
                     84: #include <pwd.h>
                     85: #endif
                     86: 
                     87: #define ENABLE_CURLX_PRINTF
                     88: /* make the curlx header define all printf() functions to use the curlx_*
                     89:    versions instead */
                     90: #include "curlx.h" /* from the private lib dir */
                     91: #include "getpart.h"
                     92: #include "util.h"
                     93: #include "server_sockaddr.h"
                     94: 
                     95: /* include memdebug.h last */
                     96: #include "memdebug.h"
                     97: 
                     98: /*****************************************************************************
                     99: *                      STRUCT DECLARATIONS AND DEFINES                       *
                    100: *****************************************************************************/
                    101: 
                    102: #ifndef PKTSIZE
                    103: #define PKTSIZE (SEGSIZE + 4)  /* SEGSIZE defined in arpa/tftp.h */
                    104: #endif
                    105: 
                    106: struct testcase {
                    107:   char *buffer;   /* holds the file data to send to the client */
                    108:   size_t bufsize; /* size of the data in buffer */
                    109:   char *rptr;     /* read pointer into the buffer */
                    110:   size_t rcount;  /* amount of data left to read of the file */
                    111:   long testno;    /* test case number */
                    112:   int ofile;      /* file descriptor for output file when uploading to us */
                    113: 
                    114:   int writedelay; /* number of seconds between each packet */
                    115: };
                    116: 
                    117: struct formats {
                    118:   const char *f_mode;
                    119:   int f_convert;
                    120: };
                    121: 
                    122: struct errmsg {
                    123:   int e_code;
                    124:   const char *e_msg;
                    125: };
                    126: 
                    127: typedef union {
                    128:   struct tftphdr hdr;
                    129:   char storage[PKTSIZE];
                    130: } tftphdr_storage_t;
                    131: 
                    132: /*
                    133:  * bf.counter values in range [-1 .. SEGSIZE] represents size of data in the
                    134:  * bf.buf buffer. Additionally it can also hold flags BF_ALLOC or BF_FREE.
                    135:  */
                    136: 
                    137: struct bf {
                    138:   int counter;            /* size of data in buffer, or flag */
                    139:   tftphdr_storage_t buf;  /* room for data packet */
                    140: };
                    141: 
                    142: #define BF_ALLOC -3       /* alloc'd but not yet filled */
                    143: #define BF_FREE  -2       /* free */
                    144: 
                    145: #define opcode_RRQ   1
                    146: #define opcode_WRQ   2
                    147: #define opcode_DATA  3
                    148: #define opcode_ACK   4
                    149: #define opcode_ERROR 5
                    150: 
                    151: #define TIMEOUT      5
                    152: 
                    153: #undef MIN
                    154: #define MIN(x,y) ((x)<(y)?(x):(y))
                    155: 
                    156: #ifndef DEFAULT_LOGFILE
                    157: #define DEFAULT_LOGFILE "log/tftpd.log"
                    158: #endif
                    159: 
                    160: #define REQUEST_DUMP  "log/server.input"
                    161: 
                    162: #define DEFAULT_PORT 8999 /* UDP */
                    163: 
                    164: /*****************************************************************************
                    165: *                              GLOBAL VARIABLES                              *
                    166: *****************************************************************************/
                    167: 
                    168: static struct errmsg errmsgs[] = {
                    169:   { EUNDEF,       "Undefined error code" },
                    170:   { ENOTFOUND,    "File not found" },
                    171:   { EACCESS,      "Access violation" },
                    172:   { ENOSPACE,     "Disk full or allocation exceeded" },
                    173:   { EBADOP,       "Illegal TFTP operation" },
                    174:   { EBADID,       "Unknown transfer ID" },
                    175:   { EEXISTS,      "File already exists" },
                    176:   { ENOUSER,      "No such user" },
                    177:   { -1,           0 }
                    178: };
                    179: 
                    180: static struct formats formata[] = {
                    181:   { "netascii",   1 },
                    182:   { "octet",      0 },
                    183:   { NULL,         0 }
                    184: };
                    185: 
                    186: static struct bf bfs[2];
                    187: 
                    188: static int nextone;     /* index of next buffer to use */
                    189: static int current;     /* index of buffer in use */
                    190: 
                    191:                            /* control flags for crlf conversions */
                    192: static int newline = 0;    /* fillbuf: in middle of newline expansion */
                    193: static int prevchar = -1;  /* putbuf: previous char (cr check) */
                    194: 
                    195: static tftphdr_storage_t buf;
                    196: static tftphdr_storage_t ackbuf;
                    197: 
                    198: static srvr_sockaddr_union_t from;
                    199: static curl_socklen_t fromlen;
                    200: 
                    201: static curl_socket_t peer = CURL_SOCKET_BAD;
                    202: 
                    203: static unsigned int timeout;
                    204: static unsigned int maxtimeout = 5 * TIMEOUT;
                    205: 
                    206: #ifdef ENABLE_IPV6
                    207: static bool use_ipv6 = FALSE;
                    208: #endif
                    209: static const char *ipv_inuse = "IPv4";
                    210: 
                    211: const  char *serverlogfile = DEFAULT_LOGFILE;
                    212: static const char *pidname = ".tftpd.pid";
                    213: static const char *portfile = NULL;
                    214: static int serverlogslocked = 0;
                    215: static int wrotepidfile = 0;
                    216: 
                    217: #ifdef HAVE_SIGSETJMP
                    218: static sigjmp_buf timeoutbuf;
                    219: #endif
                    220: 
                    221: #if defined(HAVE_ALARM) && defined(SIGALRM)
                    222: static const unsigned int rexmtval = TIMEOUT;
                    223: #endif
                    224: 
                    225: /*****************************************************************************
                    226: *                            FUNCTION PROTOTYPES                             *
                    227: *****************************************************************************/
                    228: 
                    229: static struct tftphdr *rw_init(int);
                    230: 
                    231: static struct tftphdr *w_init(void);
                    232: 
                    233: static struct tftphdr *r_init(void);
                    234: 
                    235: static void read_ahead(struct testcase *test, int convert);
                    236: 
                    237: static ssize_t write_behind(struct testcase *test, int convert);
                    238: 
                    239: static int synchnet(curl_socket_t);
                    240: 
                    241: static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size);
                    242: 
                    243: static int validate_access(struct testcase *test, const char *fname, int mode);
                    244: 
                    245: static void sendtftp(struct testcase *test, struct formats *pf);
                    246: 
                    247: static void recvtftp(struct testcase *test, struct formats *pf);
                    248: 
                    249: static void nak(int error);
                    250: 
                    251: #if defined(HAVE_ALARM) && defined(SIGALRM)
                    252: 
                    253: static void mysignal(int sig, void (*handler)(int));
                    254: 
                    255: static void timer(int signum);
                    256: 
                    257: static void justtimeout(int signum);
                    258: 
                    259: #endif /* HAVE_ALARM && SIGALRM */
                    260: 
                    261: /*****************************************************************************
                    262: *                          FUNCTION IMPLEMENTATIONS                          *
                    263: *****************************************************************************/
                    264: 
                    265: #if defined(HAVE_ALARM) && defined(SIGALRM)
                    266: 
                    267: /*
                    268:  * Like signal(), but with well-defined semantics.
                    269:  */
                    270: static void mysignal(int sig, void (*handler)(int))
                    271: {
                    272:   struct sigaction sa;
                    273:   memset(&sa, 0, sizeof(sa));
                    274:   sa.sa_handler = handler;
                    275:   sigaction(sig, &sa, NULL);
                    276: }
                    277: 
                    278: static void timer(int signum)
                    279: {
                    280:   (void)signum;
                    281: 
                    282:   logmsg("alarm!");
                    283: 
                    284:   timeout += rexmtval;
                    285:   if(timeout >= maxtimeout) {
                    286:     if(wrotepidfile) {
                    287:       wrotepidfile = 0;
                    288:       unlink(pidname);
                    289:     }
                    290:     if(serverlogslocked) {
                    291:       serverlogslocked = 0;
                    292:       clear_advisor_read_lock(SERVERLOGS_LOCK);
                    293:     }
                    294:     exit(1);
                    295:   }
                    296: #ifdef HAVE_SIGSETJMP
                    297:   siglongjmp(timeoutbuf, 1);
                    298: #endif
                    299: }
                    300: 
                    301: static void justtimeout(int signum)
                    302: {
                    303:   (void)signum;
                    304: }
                    305: 
                    306: #endif /* HAVE_ALARM && SIGALRM */
                    307: 
                    308: /*
                    309:  * init for either read-ahead or write-behind.
                    310:  * zero for write-behind, one for read-head.
                    311:  */
                    312: static struct tftphdr *rw_init(int x)
                    313: {
                    314:   newline = 0;                    /* init crlf flag */
                    315:   prevchar = -1;
                    316:   bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
                    317:   current = 0;
                    318:   bfs[1].counter = BF_FREE;
                    319:   nextone = x;                    /* ahead or behind? */
                    320:   return &bfs[0].buf.hdr;
                    321: }
                    322: 
                    323: static struct tftphdr *w_init(void)
                    324: {
                    325:   return rw_init(0); /* write-behind */
                    326: }
                    327: 
                    328: static struct tftphdr *r_init(void)
                    329: {
                    330:   return rw_init(1); /* read-ahead */
                    331: }
                    332: 
                    333: /* Have emptied current buffer by sending to net and getting ack.
                    334:    Free it and return next buffer filled with data.
                    335:  */
                    336: static int readit(struct testcase *test, struct tftphdr **dpp,
                    337:                   int convert /* if true, convert to ascii */)
                    338: {
                    339:   struct bf *b;
                    340: 
                    341:   bfs[current].counter = BF_FREE; /* free old one */
                    342:   current = !current;             /* "incr" current */
                    343: 
                    344:   b = &bfs[current];              /* look at new buffer */
                    345:   if(b->counter == BF_FREE)      /* if it's empty */
                    346:     read_ahead(test, convert);    /* fill it */
                    347: 
                    348:   *dpp = &b->buf.hdr;             /* set caller's ptr */
                    349:   return b->counter;
                    350: }
                    351: 
                    352: /*
                    353:  * fill the input buffer, doing ascii conversions if requested
                    354:  * conversions are  lf -> cr, lf  and cr -> cr, nul
                    355:  */
                    356: static void read_ahead(struct testcase *test,
                    357:                        int convert /* if true, convert to ascii */)
                    358: {
                    359:   int i;
                    360:   char *p;
                    361:   int c;
                    362:   struct bf *b;
                    363:   struct tftphdr *dp;
                    364: 
                    365:   b = &bfs[nextone];              /* look at "next" buffer */
                    366:   if(b->counter != BF_FREE)      /* nop if not free */
                    367:     return;
                    368:   nextone = !nextone;             /* "incr" next buffer ptr */
                    369: 
                    370:   dp = &b->buf.hdr;
                    371: 
                    372:   if(convert == 0) {
                    373:     /* The former file reading code did this:
                    374:        b->counter = read(fileno(file), dp->th_data, SEGSIZE); */
                    375:     size_t copy_n = MIN(SEGSIZE, test->rcount);
                    376:     memcpy(dp->th_data, test->rptr, copy_n);
                    377: 
                    378:     /* decrease amount, advance pointer */
                    379:     test->rcount -= copy_n;
                    380:     test->rptr += copy_n;
                    381:     b->counter = (int)copy_n;
                    382:     return;
                    383:   }
                    384: 
                    385:   p = dp->th_data;
                    386:   for(i = 0 ; i < SEGSIZE; i++) {
                    387:     if(newline) {
                    388:       if(prevchar == '\n')
                    389:         c = '\n';       /* lf to cr,lf */
                    390:       else
                    391:         c = '\0';       /* cr to cr,nul */
                    392:       newline = 0;
                    393:     }
                    394:     else {
                    395:       if(test->rcount) {
                    396:         c = test->rptr[0];
                    397:         test->rptr++;
                    398:         test->rcount--;
                    399:       }
                    400:       else
                    401:         break;
                    402:       if(c == '\n' || c == '\r') {
                    403:         prevchar = c;
                    404:         c = '\r';
                    405:         newline = 1;
                    406:       }
                    407:     }
                    408:     *p++ = (char)c;
                    409:   }
                    410:   b->counter = (int)(p - dp->th_data);
                    411: }
                    412: 
                    413: /* Update count associated with the buffer, get new buffer from the queue.
                    414:    Calls write_behind only if next buffer not available.
                    415:  */
                    416: static int writeit(struct testcase *test, struct tftphdr * volatile *dpp,
                    417:                    int ct, int convert)
                    418: {
                    419:   bfs[current].counter = ct;      /* set size of data to write */
                    420:   current = !current;             /* switch to other buffer */
                    421:   if(bfs[current].counter != BF_FREE)     /* if not free */
                    422:     write_behind(test, convert);     /* flush it */
                    423:   bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
                    424:   *dpp =  &bfs[current].buf.hdr;
                    425:   return ct;                      /* this is a lie of course */
                    426: }
                    427: 
                    428: /*
                    429:  * Output a buffer to a file, converting from netascii if requested.
                    430:  * CR, NUL -> CR  and CR, LF => LF.
                    431:  * Note spec is undefined if we get CR as last byte of file or a
                    432:  * CR followed by anything else.  In this case we leave it alone.
                    433:  */
                    434: static ssize_t write_behind(struct testcase *test, int convert)
                    435: {
                    436:   char *writebuf;
                    437:   int count;
                    438:   int ct;
                    439:   char *p;
                    440:   int c;                          /* current character */
                    441:   struct bf *b;
                    442:   struct tftphdr *dp;
                    443: 
                    444:   b = &bfs[nextone];
                    445:   if(b->counter < -1)            /* anything to flush? */
                    446:     return 0;                     /* just nop if nothing to do */
                    447: 
                    448:   if(!test->ofile) {
                    449:     char outfile[256];
                    450:     msnprintf(outfile, sizeof(outfile), "log/upload.%ld", test->testno);
                    451: #ifdef WIN32
                    452:     test->ofile = open(outfile, O_CREAT|O_RDWR|O_BINARY, 0777);
                    453: #else
                    454:     test->ofile = open(outfile, O_CREAT|O_RDWR, 0777);
                    455: #endif
                    456:     if(test->ofile == -1) {
                    457:       logmsg("Couldn't create and/or open file %s for upload!", outfile);
                    458:       return -1; /* failure! */
                    459:     }
                    460:   }
                    461: 
                    462:   count = b->counter;             /* remember byte count */
                    463:   b->counter = BF_FREE;           /* reset flag */
                    464:   dp = &b->buf.hdr;
                    465:   nextone = !nextone;             /* incr for next time */
                    466:   writebuf = dp->th_data;
                    467: 
                    468:   if(count <= 0)
                    469:     return -1;                    /* nak logic? */
                    470: 
                    471:   if(convert == 0)
                    472:     return write(test->ofile, writebuf, count);
                    473: 
                    474:   p = writebuf;
                    475:   ct = count;
                    476:   while(ct--) {                   /* loop over the buffer */
                    477:     c = *p++;                     /* pick up a character */
                    478:     if(prevchar == '\r') {        /* if prev char was cr */
                    479:       if(c == '\n')               /* if have cr,lf then just */
                    480:         lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */
                    481:       else
                    482:         if(c == '\0')             /* if have cr,nul then */
                    483:           goto skipit;            /* just skip over the putc */
                    484:       /* else just fall through and allow it */
                    485:     }
                    486:     /* formerly
                    487:        putc(c, file); */
                    488:     if(1 != write(test->ofile, &c, 1))
                    489:       break;
                    490:     skipit:
                    491:     prevchar = c;
                    492:   }
                    493:   return count;
                    494: }
                    495: 
                    496: /* When an error has occurred, it is possible that the two sides are out of
                    497:  * synch.  Ie: that what I think is the other side's response to packet N is
                    498:  * really their response to packet N-1.
                    499:  *
                    500:  * So, to try to prevent that, we flush all the input queued up for us on the
                    501:  * network connection on our host.
                    502:  *
                    503:  * We return the number of packets we flushed (mostly for reporting when trace
                    504:  * is active).
                    505:  */
                    506: 
                    507: static int synchnet(curl_socket_t f /* socket to flush */)
                    508: {
                    509: 
                    510: #if defined(HAVE_IOCTLSOCKET)
                    511:   unsigned long i;
                    512: #else
                    513:   int i;
                    514: #endif
                    515:   int j = 0;
                    516:   char rbuf[PKTSIZE];
                    517:   srvr_sockaddr_union_t fromaddr;
                    518:   curl_socklen_t fromaddrlen;
                    519: 
                    520:   for(;;) {
                    521: #if defined(HAVE_IOCTLSOCKET)
                    522:     (void) ioctlsocket(f, FIONREAD, &i);
                    523: #else
                    524:     (void) ioctl(f, FIONREAD, &i);
                    525: #endif
                    526:     if(i) {
                    527:       j++;
                    528: #ifdef ENABLE_IPV6
                    529:       if(!use_ipv6)
                    530: #endif
                    531:         fromaddrlen = sizeof(fromaddr.sa4);
                    532: #ifdef ENABLE_IPV6
                    533:       else
                    534:         fromaddrlen = sizeof(fromaddr.sa6);
                    535: #endif
                    536:       (void) recvfrom(f, rbuf, sizeof(rbuf), 0,
                    537:                       &fromaddr.sa, &fromaddrlen);
                    538:     }
                    539:     else
                    540:       break;
                    541:   }
                    542:   return j;
                    543: }
                    544: 
                    545: int main(int argc, char **argv)
                    546: {
                    547:   srvr_sockaddr_union_t me;
                    548:   struct tftphdr *tp;
                    549:   ssize_t n = 0;
                    550:   int arg = 1;
                    551:   unsigned short port = DEFAULT_PORT;
                    552:   curl_socket_t sock = CURL_SOCKET_BAD;
                    553:   int flag;
                    554:   int rc;
                    555:   int error;
                    556:   long pid;
                    557:   struct testcase test;
                    558:   int result = 0;
                    559: 
                    560:   memset(&test, 0, sizeof(test));
                    561: 
                    562:   while(argc>arg) {
                    563:     if(!strcmp("--version", argv[arg])) {
                    564:       printf("tftpd IPv4%s\n",
                    565: #ifdef ENABLE_IPV6
                    566:              "/IPv6"
                    567: #else
                    568:              ""
                    569: #endif
                    570:              );
                    571:       return 0;
                    572:     }
                    573:     else if(!strcmp("--pidfile", argv[arg])) {
                    574:       arg++;
                    575:       if(argc>arg)
                    576:         pidname = argv[arg++];
                    577:     }
                    578:     else if(!strcmp("--portfile", argv[arg])) {
                    579:       arg++;
                    580:       if(argc>arg)
                    581:         portfile = argv[arg++];
                    582:     }
                    583:     else if(!strcmp("--logfile", argv[arg])) {
                    584:       arg++;
                    585:       if(argc>arg)
                    586:         serverlogfile = argv[arg++];
                    587:     }
                    588:     else if(!strcmp("--ipv4", argv[arg])) {
                    589: #ifdef ENABLE_IPV6
                    590:       ipv_inuse = "IPv4";
                    591:       use_ipv6 = FALSE;
                    592: #endif
                    593:       arg++;
                    594:     }
                    595:     else if(!strcmp("--ipv6", argv[arg])) {
                    596: #ifdef ENABLE_IPV6
                    597:       ipv_inuse = "IPv6";
                    598:       use_ipv6 = TRUE;
                    599: #endif
                    600:       arg++;
                    601:     }
                    602:     else if(!strcmp("--port", argv[arg])) {
                    603:       arg++;
                    604:       if(argc>arg) {
                    605:         char *endptr;
                    606:         unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
                    607:         port = curlx_ultous(ulnum);
                    608:         arg++;
                    609:       }
                    610:     }
                    611:     else if(!strcmp("--srcdir", argv[arg])) {
                    612:       arg++;
                    613:       if(argc>arg) {
                    614:         path = argv[arg];
                    615:         arg++;
                    616:       }
                    617:     }
                    618:     else {
                    619:       puts("Usage: tftpd [option]\n"
                    620:            " --version\n"
                    621:            " --logfile [file]\n"
                    622:            " --pidfile [file]\n"
                    623:            " --ipv4\n"
                    624:            " --ipv6\n"
                    625:            " --port [port]\n"
                    626:            " --srcdir [path]");
                    627:       return 0;
                    628:     }
                    629:   }
                    630: 
                    631: #ifdef WIN32
                    632:   win32_init();
                    633:   atexit(win32_cleanup);
                    634: #endif
                    635: 
                    636:   install_signal_handlers(true);
                    637: 
                    638:   pid = (long)getpid();
                    639: 
                    640: #ifdef ENABLE_IPV6
                    641:   if(!use_ipv6)
                    642: #endif
                    643:     sock = socket(AF_INET, SOCK_DGRAM, 0);
                    644: #ifdef ENABLE_IPV6
                    645:   else
                    646:     sock = socket(AF_INET6, SOCK_DGRAM, 0);
                    647: #endif
                    648: 
                    649:   if(CURL_SOCKET_BAD == sock) {
                    650:     error = SOCKERRNO;
                    651:     logmsg("Error creating socket: (%d) %s",
                    652:            error, strerror(error));
                    653:     result = 1;
                    654:     goto tftpd_cleanup;
                    655:   }
                    656: 
                    657:   flag = 1;
                    658:   if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    659:             (void *)&flag, sizeof(flag))) {
                    660:     error = SOCKERRNO;
                    661:     logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
                    662:            error, strerror(error));
                    663:     result = 1;
                    664:     goto tftpd_cleanup;
                    665:   }
                    666: 
                    667: #ifdef ENABLE_IPV6
                    668:   if(!use_ipv6) {
                    669: #endif
                    670:     memset(&me.sa4, 0, sizeof(me.sa4));
                    671:     me.sa4.sin_family = AF_INET;
                    672:     me.sa4.sin_addr.s_addr = INADDR_ANY;
                    673:     me.sa4.sin_port = htons(port);
                    674:     rc = bind(sock, &me.sa, sizeof(me.sa4));
                    675: #ifdef ENABLE_IPV6
                    676:   }
                    677:   else {
                    678:     memset(&me.sa6, 0, sizeof(me.sa6));
                    679:     me.sa6.sin6_family = AF_INET6;
                    680:     me.sa6.sin6_addr = in6addr_any;
                    681:     me.sa6.sin6_port = htons(port);
                    682:     rc = bind(sock, &me.sa, sizeof(me.sa6));
                    683:   }
                    684: #endif /* ENABLE_IPV6 */
                    685:   if(0 != rc) {
                    686:     error = SOCKERRNO;
                    687:     logmsg("Error binding socket on port %hu: (%d) %s",
                    688:            port, error, strerror(error));
                    689:     result = 1;
                    690:     goto tftpd_cleanup;
                    691:   }
                    692: 
                    693:   if(!port) {
                    694:     /* The system was supposed to choose a port number, figure out which
                    695:        port we actually got and update the listener port value with it. */
                    696:     curl_socklen_t la_size;
                    697:     srvr_sockaddr_union_t localaddr;
                    698: #ifdef ENABLE_IPV6
                    699:     if(!use_ipv6)
                    700: #endif
                    701:       la_size = sizeof(localaddr.sa4);
                    702: #ifdef ENABLE_IPV6
                    703:     else
                    704:       la_size = sizeof(localaddr.sa6);
                    705: #endif
                    706:     memset(&localaddr.sa, 0, (size_t)la_size);
                    707:     if(getsockname(sock, &localaddr.sa, &la_size) < 0) {
                    708:       error = SOCKERRNO;
                    709:       logmsg("getsockname() failed with error: (%d) %s",
                    710:              error, strerror(error));
                    711:       sclose(sock);
                    712:       goto tftpd_cleanup;
                    713:     }
                    714:     switch(localaddr.sa.sa_family) {
                    715:     case AF_INET:
                    716:       port = ntohs(localaddr.sa4.sin_port);
                    717:       break;
                    718: #ifdef ENABLE_IPV6
                    719:     case AF_INET6:
                    720:       port = ntohs(localaddr.sa6.sin6_port);
                    721:       break;
                    722: #endif
                    723:     default:
                    724:       break;
                    725:     }
                    726:     if(!port) {
                    727:       /* Real failure, listener port shall not be zero beyond this point. */
                    728:       logmsg("Apparently getsockname() succeeded, with listener port zero.");
                    729:       logmsg("A valid reason for this failure is a binary built without");
                    730:       logmsg("proper network library linkage. This might not be the only");
                    731:       logmsg("reason, but double check it before anything else.");
                    732:       result = 2;
                    733:       goto tftpd_cleanup;
                    734:     }
                    735:   }
                    736: 
                    737:   wrotepidfile = write_pidfile(pidname);
                    738:   if(!wrotepidfile) {
                    739:     result = 1;
                    740:     goto tftpd_cleanup;
                    741:   }
                    742: 
                    743:   if(portfile) {
                    744:     wrotepidfile = write_portfile(portfile, port);
                    745:     if(!wrotepidfile) {
                    746:       result = 1;
                    747:       goto tftpd_cleanup;
                    748:     }
                    749:   }
                    750: 
                    751:   logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port);
                    752: 
                    753:   for(;;) {
                    754:     fromlen = sizeof(from);
                    755: #ifdef ENABLE_IPV6
                    756:     if(!use_ipv6)
                    757: #endif
                    758:       fromlen = sizeof(from.sa4);
                    759: #ifdef ENABLE_IPV6
                    760:     else
                    761:       fromlen = sizeof(from.sa6);
                    762: #endif
                    763:     n = (ssize_t)recvfrom(sock, &buf.storage[0], sizeof(buf.storage), 0,
                    764:                           &from.sa, &fromlen);
                    765:     if(got_exit_signal)
                    766:       break;
                    767:     if(n < 0) {
                    768:       logmsg("recvfrom");
                    769:       result = 3;
                    770:       break;
                    771:     }
                    772: 
                    773:     set_advisor_read_lock(SERVERLOGS_LOCK);
                    774:     serverlogslocked = 1;
                    775: 
                    776: #ifdef ENABLE_IPV6
                    777:     if(!use_ipv6) {
                    778: #endif
                    779:       from.sa4.sin_family = AF_INET;
                    780:       peer = socket(AF_INET, SOCK_DGRAM, 0);
                    781:       if(CURL_SOCKET_BAD == peer) {
                    782:         logmsg("socket");
                    783:         result = 2;
                    784:         break;
                    785:       }
                    786:       if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) {
                    787:         logmsg("connect: fail");
                    788:         result = 1;
                    789:         break;
                    790:       }
                    791: #ifdef ENABLE_IPV6
                    792:     }
                    793:     else {
                    794:       from.sa6.sin6_family = AF_INET6;
                    795:       peer = socket(AF_INET6, SOCK_DGRAM, 0);
                    796:       if(CURL_SOCKET_BAD == peer) {
                    797:         logmsg("socket");
                    798:         result = 2;
                    799:         break;
                    800:       }
                    801:       if(connect(peer, &from.sa, sizeof(from.sa6)) < 0) {
                    802:         logmsg("connect: fail");
                    803:         result = 1;
                    804:         break;
                    805:       }
                    806:     }
                    807: #endif
                    808: 
                    809:     maxtimeout = 5*TIMEOUT;
                    810: 
                    811:     tp = &buf.hdr;
                    812:     tp->th_opcode = ntohs(tp->th_opcode);
                    813:     if(tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) {
                    814:       memset(&test, 0, sizeof(test));
                    815:       if(do_tftp(&test, tp, n) < 0)
                    816:         break;
                    817:       free(test.buffer);
                    818:     }
                    819:     sclose(peer);
                    820:     peer = CURL_SOCKET_BAD;
                    821: 
                    822:     if(test.ofile > 0) {
                    823:       close(test.ofile);
                    824:       test.ofile = 0;
                    825:     }
                    826: 
                    827:     if(got_exit_signal)
                    828:       break;
                    829: 
                    830:     if(serverlogslocked) {
                    831:       serverlogslocked = 0;
                    832:       clear_advisor_read_lock(SERVERLOGS_LOCK);
                    833:     }
                    834: 
                    835:     logmsg("end of one transfer");
                    836: 
                    837:   }
                    838: 
                    839: tftpd_cleanup:
                    840: 
                    841:   if(test.ofile > 0)
                    842:     close(test.ofile);
                    843: 
                    844:   if((peer != sock) && (peer != CURL_SOCKET_BAD))
                    845:     sclose(peer);
                    846: 
                    847:   if(sock != CURL_SOCKET_BAD)
                    848:     sclose(sock);
                    849: 
                    850:   if(got_exit_signal)
                    851:     logmsg("signalled to die");
                    852: 
                    853:   if(wrotepidfile)
                    854:     unlink(pidname);
                    855:   if(portfile)
                    856:     unlink(portfile);
                    857: 
                    858:   if(serverlogslocked) {
                    859:     serverlogslocked = 0;
                    860:     clear_advisor_read_lock(SERVERLOGS_LOCK);
                    861:   }
                    862: 
                    863:   restore_signal_handlers(true);
                    864: 
                    865:   if(got_exit_signal) {
                    866:     logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)",
                    867:            ipv_inuse, (int)port, pid, exit_signal);
                    868:     /*
                    869:      * To properly set the return status of the process we
                    870:      * must raise the same signal SIGINT or SIGTERM that we
                    871:      * caught and let the old handler take care of it.
                    872:      */
                    873:     raise(exit_signal);
                    874:   }
                    875: 
                    876:   logmsg("========> tftpd quits");
                    877:   return result;
                    878: }
                    879: 
                    880: /*
                    881:  * Handle initial connection protocol.
                    882:  */
                    883: static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size)
                    884: {
                    885:   char *cp;
                    886:   int first = 1, ecode;
                    887:   struct formats *pf;
                    888:   char *filename, *mode = NULL;
                    889: #ifdef USE_WINSOCK
                    890:   DWORD recvtimeout, recvtimeoutbak;
                    891: #endif
                    892:   const char *option = "mode"; /* mode is implicit */
                    893:   int toggle = 1;
                    894: 
                    895:   /* Open request dump file. */
                    896:   FILE *server = fopen(REQUEST_DUMP, "ab");
                    897:   if(!server) {
                    898:     int error = errno;
                    899:     logmsg("fopen() failed with error: %d %s", error, strerror(error));
                    900:     logmsg("Error opening file: %s", REQUEST_DUMP);
                    901:     return -1;
                    902:   }
                    903: 
                    904:   /* store input protocol */
                    905:   fprintf(server, "opcode: %x\n", tp->th_opcode);
                    906: 
                    907:   cp = (char *)&tp->th_stuff;
                    908:   filename = cp;
                    909:   do {
                    910:     bool endofit = true;
                    911:     while(cp < &buf.storage[size]) {
                    912:       if(*cp == '\0') {
                    913:         endofit = false;
                    914:         break;
                    915:       }
                    916:       cp++;
                    917:     }
                    918:     if(endofit)
                    919:       /* no more options */
                    920:       break;
                    921: 
                    922:     /* before increasing pointer, make sure it is still within the legal
                    923:        space */
                    924:     if((cp + 1) < &buf.storage[size]) {
                    925:       ++cp;
                    926:       if(first) {
                    927:         /* store the mode since we need it later */
                    928:         mode = cp;
                    929:         first = 0;
                    930:       }
                    931:       if(toggle)
                    932:         /* name/value pair: */
                    933:         fprintf(server, "%s: %s\n", option, cp);
                    934:       else {
                    935:         /* store the name pointer */
                    936:         option = cp;
                    937:       }
                    938:       toggle ^= 1;
                    939:     }
                    940:     else
                    941:       /* No more options */
                    942:       break;
                    943:   } while(1);
                    944: 
                    945:   if(*cp) {
                    946:     nak(EBADOP);
                    947:     fclose(server);
                    948:     return 3;
                    949:   }
                    950: 
                    951:   /* store input protocol */
                    952:   fprintf(server, "filename: %s\n", filename);
                    953: 
                    954:   for(cp = mode; cp && *cp; cp++)
                    955:     if(ISUPPER(*cp))
                    956:       *cp = (char)tolower((int)*cp);
                    957: 
                    958:   /* store input protocol */
                    959:   fclose(server);
                    960: 
                    961:   for(pf = formata; pf->f_mode; pf++)
                    962:     if(strcmp(pf->f_mode, mode) == 0)
                    963:       break;
                    964:   if(!pf->f_mode) {
                    965:     nak(EBADOP);
                    966:     return 2;
                    967:   }
                    968:   ecode = validate_access(test, filename, tp->th_opcode);
                    969:   if(ecode) {
                    970:     nak(ecode);
                    971:     return 1;
                    972:   }
                    973: 
                    974: #ifdef USE_WINSOCK
                    975:   recvtimeout = sizeof(recvtimeoutbak);
                    976:   getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
                    977:              (char *)&recvtimeoutbak, (int *)&recvtimeout);
                    978:   recvtimeout = TIMEOUT*1000;
                    979:   setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
                    980:              (const char *)&recvtimeout, sizeof(recvtimeout));
                    981: #endif
                    982: 
                    983:   if(tp->th_opcode == opcode_WRQ)
                    984:     recvtftp(test, pf);
                    985:   else
                    986:     sendtftp(test, pf);
                    987: 
                    988: #ifdef USE_WINSOCK
                    989:   recvtimeout = recvtimeoutbak;
                    990:   setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO,
                    991:              (const char *)&recvtimeout, sizeof(recvtimeout));
                    992: #endif
                    993: 
                    994:   return 0;
                    995: }
                    996: 
                    997: /* Based on the testno, parse the correct server commands. */
                    998: static int parse_servercmd(struct testcase *req)
                    999: {
                   1000:   FILE *stream;
                   1001:   int error;
                   1002: 
                   1003:   stream = test2fopen(req->testno);
                   1004:   if(!stream) {
                   1005:     error = errno;
                   1006:     logmsg("fopen() failed with error: %d %s", error, strerror(error));
                   1007:     logmsg("  Couldn't open test file %ld", req->testno);
                   1008:     return 1; /* done */
                   1009:   }
                   1010:   else {
                   1011:     char *orgcmd = NULL;
                   1012:     char *cmd = NULL;
                   1013:     size_t cmdsize = 0;
                   1014:     int num = 0;
                   1015: 
                   1016:     /* get the custom server control "commands" */
                   1017:     error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream);
                   1018:     fclose(stream);
                   1019:     if(error) {
                   1020:       logmsg("getpart() failed with error: %d", error);
                   1021:       return 1; /* done */
                   1022:     }
                   1023: 
                   1024:     cmd = orgcmd;
                   1025:     while(cmd && cmdsize) {
                   1026:       char *check;
                   1027:       if(1 == sscanf(cmd, "writedelay: %d", &num)) {
                   1028:         logmsg("instructed to delay %d secs between packets", num);
                   1029:         req->writedelay = num;
                   1030:       }
                   1031:       else {
                   1032:         logmsg("Unknown <servercmd> instruction found: %s", cmd);
                   1033:       }
                   1034:       /* try to deal with CRLF or just LF */
                   1035:       check = strchr(cmd, '\r');
                   1036:       if(!check)
                   1037:         check = strchr(cmd, '\n');
                   1038: 
                   1039:       if(check) {
                   1040:         /* get to the letter following the newline */
                   1041:         while((*check == '\r') || (*check == '\n'))
                   1042:           check++;
                   1043: 
                   1044:         if(!*check)
                   1045:           /* if we reached a zero, get out */
                   1046:           break;
                   1047:         cmd = check;
                   1048:       }
                   1049:       else
                   1050:         break;
                   1051:     }
                   1052:     free(orgcmd);
                   1053:   }
                   1054: 
                   1055:   return 0; /* OK! */
                   1056: }
                   1057: 
                   1058: 
                   1059: /*
                   1060:  * Validate file access.
                   1061:  */
                   1062: static int validate_access(struct testcase *test,
                   1063:                            const char *filename, int mode)
                   1064: {
                   1065:   char *ptr;
                   1066: 
                   1067:   logmsg("trying to get file: %s mode %x", filename, mode);
                   1068: 
                   1069:   if(!strncmp("verifiedserver", filename, 14)) {
                   1070:     char weare[128];
                   1071:     size_t count = msnprintf(weare, sizeof(weare),
                   1072:                              "WE ROOLZ: %ld\r\n", (long)getpid());
                   1073: 
                   1074:     logmsg("Are-we-friendly question received");
                   1075:     test->buffer = strdup(weare);
                   1076:     test->rptr = test->buffer; /* set read pointer */
                   1077:     test->bufsize = count;    /* set total count */
                   1078:     test->rcount = count;     /* set data left to read */
                   1079:     return 0; /* fine */
                   1080:   }
                   1081: 
                   1082:   /* find the last slash */
                   1083:   ptr = strrchr(filename, '/');
                   1084: 
                   1085:   if(ptr) {
                   1086:     char partbuf[80]="data";
                   1087:     long partno;
                   1088:     long testno;
                   1089:     FILE *stream;
                   1090: 
                   1091:     ptr++; /* skip the slash */
                   1092: 
                   1093:     /* skip all non-numericals following the slash */
                   1094:     while(*ptr && !ISDIGIT(*ptr))
                   1095:       ptr++;
                   1096: 
                   1097:     /* get the number */
                   1098:     testno = strtol(ptr, &ptr, 10);
                   1099: 
                   1100:     if(testno > 10000) {
                   1101:       partno = testno % 10000;
                   1102:       testno /= 10000;
                   1103:     }
                   1104:     else
                   1105:       partno = 0;
                   1106: 
                   1107: 
                   1108:     logmsg("requested test number %ld part %ld", testno, partno);
                   1109: 
                   1110:     test->testno = testno;
                   1111: 
                   1112:     (void)parse_servercmd(test);
                   1113: 
                   1114:     stream = test2fopen(testno);
                   1115: 
                   1116:     if(0 != partno)
                   1117:       msnprintf(partbuf, sizeof(partbuf), "data%ld", partno);
                   1118: 
                   1119:     if(!stream) {
                   1120:       int error = errno;
                   1121:       logmsg("fopen() failed with error: %d %s", error, strerror(error));
                   1122:       logmsg("Couldn't open test file for test : %d", testno);
                   1123:       return EACCESS;
                   1124:     }
                   1125:     else {
                   1126:       size_t count;
                   1127:       int error = getpart(&test->buffer, &count, "reply", partbuf, stream);
                   1128:       fclose(stream);
                   1129:       if(error) {
                   1130:         logmsg("getpart() failed with error: %d", error);
                   1131:         return EACCESS;
                   1132:       }
                   1133:       if(test->buffer) {
                   1134:         test->rptr = test->buffer; /* set read pointer */
                   1135:         test->bufsize = count;    /* set total count */
                   1136:         test->rcount = count;     /* set data left to read */
                   1137:       }
                   1138:       else
                   1139:         return EACCESS;
                   1140:     }
                   1141:   }
                   1142:   else {
                   1143:     logmsg("no slash found in path");
                   1144:     return EACCESS; /* failure */
                   1145:   }
                   1146: 
                   1147:   logmsg("file opened and all is good");
                   1148:   return 0;
                   1149: }
                   1150: 
                   1151: /*
                   1152:  * Send the requested file.
                   1153:  */
                   1154: static void sendtftp(struct testcase *test, struct formats *pf)
                   1155: {
                   1156:   int size;
                   1157:   ssize_t n;
                   1158:   /* These are volatile to live through a siglongjmp */
                   1159:   volatile unsigned short sendblock; /* block count */
                   1160:   struct tftphdr * volatile sdp = r_init(); /* data buffer */
                   1161:   struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */
                   1162: 
                   1163:   sendblock = 1;
                   1164: #if defined(HAVE_ALARM) && defined(SIGALRM)
                   1165:   mysignal(SIGALRM, timer);
                   1166: #endif
                   1167:   do {
                   1168:     size = readit(test, (struct tftphdr **)&sdp, pf->f_convert);
                   1169:     if(size < 0) {
                   1170:       nak(errno + 100);
                   1171:       return;
                   1172:     }
                   1173:     sdp->th_opcode = htons((unsigned short)opcode_DATA);
                   1174:     sdp->th_block = htons(sendblock);
                   1175:     timeout = 0;
                   1176: #ifdef HAVE_SIGSETJMP
                   1177:     (void) sigsetjmp(timeoutbuf, 1);
                   1178: #endif
                   1179:     if(test->writedelay) {
                   1180:       logmsg("Pausing %d seconds before %d bytes", test->writedelay,
                   1181:              size);
                   1182:       wait_ms(1000*test->writedelay);
                   1183:     }
                   1184: 
                   1185:     send_data:
                   1186:     if(swrite(peer, sdp, size + 4) != size + 4) {
                   1187:       logmsg("write");
                   1188:       return;
                   1189:     }
                   1190:     read_ahead(test, pf->f_convert);
                   1191:     for(;;) {
                   1192: #ifdef HAVE_ALARM
                   1193:       alarm(rexmtval);        /* read the ack */
                   1194: #endif
                   1195:       n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage));
                   1196: #ifdef HAVE_ALARM
                   1197:       alarm(0);
                   1198: #endif
                   1199:       if(got_exit_signal)
                   1200:         return;
                   1201:       if(n < 0) {
                   1202:         logmsg("read: fail");
                   1203:         return;
                   1204:       }
                   1205:       sap->th_opcode = ntohs((unsigned short)sap->th_opcode);
                   1206:       sap->th_block = ntohs(sap->th_block);
                   1207: 
                   1208:       if(sap->th_opcode == opcode_ERROR) {
                   1209:         logmsg("got ERROR");
                   1210:         return;
                   1211:       }
                   1212: 
                   1213:       if(sap->th_opcode == opcode_ACK) {
                   1214:         if(sap->th_block == sendblock) {
                   1215:           break;
                   1216:         }
                   1217:         /* Re-synchronize with the other side */
                   1218:         (void) synchnet(peer);
                   1219:         if(sap->th_block == (sendblock-1)) {
                   1220:           goto send_data;
                   1221:         }
                   1222:       }
                   1223: 
                   1224:     }
                   1225:     sendblock++;
                   1226:   } while(size == SEGSIZE);
                   1227: }
                   1228: 
                   1229: /*
                   1230:  * Receive a file.
                   1231:  */
                   1232: static void recvtftp(struct testcase *test, struct formats *pf)
                   1233: {
                   1234:   ssize_t n, size;
                   1235:   /* These are volatile to live through a siglongjmp */
                   1236:   volatile unsigned short recvblock; /* block count */
                   1237:   struct tftphdr * volatile rdp;     /* data buffer */
                   1238:   struct tftphdr *rap;      /* ack buffer */
                   1239: 
                   1240:   recvblock = 0;
                   1241:   rdp = w_init();
                   1242: #if defined(HAVE_ALARM) && defined(SIGALRM)
                   1243:   mysignal(SIGALRM, timer);
                   1244: #endif
                   1245:   rap = &ackbuf.hdr;
                   1246:   do {
                   1247:     timeout = 0;
                   1248:     rap->th_opcode = htons((unsigned short)opcode_ACK);
                   1249:     rap->th_block = htons(recvblock);
                   1250:     recvblock++;
                   1251: #ifdef HAVE_SIGSETJMP
                   1252:     (void) sigsetjmp(timeoutbuf, 1);
                   1253: #endif
                   1254: send_ack:
                   1255:     if(swrite(peer, &ackbuf.storage[0], 4) != 4) {
                   1256:       logmsg("write: fail\n");
                   1257:       goto abort;
                   1258:     }
                   1259:     write_behind(test, pf->f_convert);
                   1260:     for(;;) {
                   1261: #ifdef HAVE_ALARM
                   1262:       alarm(rexmtval);
                   1263: #endif
                   1264:       n = sread(peer, rdp, PKTSIZE);
                   1265: #ifdef HAVE_ALARM
                   1266:       alarm(0);
                   1267: #endif
                   1268:       if(got_exit_signal)
                   1269:         goto abort;
                   1270:       if(n < 0) {                       /* really? */
                   1271:         logmsg("read: fail\n");
                   1272:         goto abort;
                   1273:       }
                   1274:       rdp->th_opcode = ntohs((unsigned short)rdp->th_opcode);
                   1275:       rdp->th_block = ntohs(rdp->th_block);
                   1276:       if(rdp->th_opcode == opcode_ERROR)
                   1277:         goto abort;
                   1278:       if(rdp->th_opcode == opcode_DATA) {
                   1279:         if(rdp->th_block == recvblock) {
                   1280:           break;                         /* normal */
                   1281:         }
                   1282:         /* Re-synchronize with the other side */
                   1283:         (void) synchnet(peer);
                   1284:         if(rdp->th_block == (recvblock-1))
                   1285:           goto send_ack;                 /* rexmit */
                   1286:       }
                   1287:     }
                   1288: 
                   1289:     size = writeit(test, &rdp, (int)(n - 4), pf->f_convert);
                   1290:     if(size != (n-4)) {                 /* ahem */
                   1291:       if(size < 0)
                   1292:         nak(errno + 100);
                   1293:       else
                   1294:         nak(ENOSPACE);
                   1295:       goto abort;
                   1296:     }
                   1297:   } while(size == SEGSIZE);
                   1298:   write_behind(test, pf->f_convert);
                   1299: 
                   1300:   rap->th_opcode = htons((unsigned short)opcode_ACK);  /* send the "final"
                   1301:                                                           ack */
                   1302:   rap->th_block = htons(recvblock);
                   1303:   (void) swrite(peer, &ackbuf.storage[0], 4);
                   1304: #if defined(HAVE_ALARM) && defined(SIGALRM)
                   1305:   mysignal(SIGALRM, justtimeout);        /* just abort read on timeout */
                   1306:   alarm(rexmtval);
                   1307: #endif
                   1308:   /* normally times out and quits */
                   1309:   n = sread(peer, &buf.storage[0], sizeof(buf.storage));
                   1310: #ifdef HAVE_ALARM
                   1311:   alarm(0);
                   1312: #endif
                   1313:   if(got_exit_signal)
                   1314:     goto abort;
                   1315:   if(n >= 4 &&                               /* if read some data */
                   1316:      rdp->th_opcode == opcode_DATA &&        /* and got a data block */
                   1317:      recvblock == rdp->th_block) {           /* then my last ack was lost */
                   1318:     (void) swrite(peer, &ackbuf.storage[0], 4);  /* resend final ack */
                   1319:   }
                   1320: abort:
                   1321:   return;
                   1322: }
                   1323: 
                   1324: /*
                   1325:  * Send a nak packet (error message).  Error code passed in is one of the
                   1326:  * standard TFTP codes, or a Unix errno offset by 100.
                   1327:  */
                   1328: static void nak(int error)
                   1329: {
                   1330:   struct tftphdr *tp;
                   1331:   int length;
                   1332:   struct errmsg *pe;
                   1333: 
                   1334:   tp = &buf.hdr;
                   1335:   tp->th_opcode = htons((unsigned short)opcode_ERROR);
                   1336:   tp->th_code = htons((unsigned short)error);
                   1337:   for(pe = errmsgs; pe->e_code >= 0; pe++)
                   1338:     if(pe->e_code == error)
                   1339:       break;
                   1340:   if(pe->e_code < 0) {
                   1341:     pe->e_msg = strerror(error - 100);
                   1342:     tp->th_code = EUNDEF;   /* set 'undef' errorcode */
                   1343:   }
                   1344:   length = (int)strlen(pe->e_msg);
                   1345: 
                   1346:   /* we use memcpy() instead of strcpy() in order to avoid buffer overflow
                   1347:    * report from glibc with FORTIFY_SOURCE */
                   1348:   memcpy(tp->th_msg, pe->e_msg, length + 1);
                   1349:   length += 5;
                   1350:   if(swrite(peer, &buf.storage[0], length) != length)
                   1351:     logmsg("nak: fail\n");
                   1352: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>