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