113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * 913498266Sopenharmony_ci * Trivial file transfer protocol server. 1013498266Sopenharmony_ci * 1113498266Sopenharmony_ci * This code includes many modifications by Jim Guyton <guyton@rand-unix> 1213498266Sopenharmony_ci * 1313498266Sopenharmony_ci * This source file was started based on netkit-tftpd 0.17 1413498266Sopenharmony_ci * Heavily modified for curl's test suite 1513498266Sopenharmony_ci */ 1613498266Sopenharmony_ci 1713498266Sopenharmony_ci/* 1813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 1913498266Sopenharmony_ci * Copyright (c) 1983, Regents of the University of California. 2013498266Sopenharmony_ci * All rights reserved. 2113498266Sopenharmony_ci * 2213498266Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 2313498266Sopenharmony_ci * modification, are permitted provided that the following conditions 2413498266Sopenharmony_ci * are met: 2513498266Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 2613498266Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 2713498266Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 2813498266Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 2913498266Sopenharmony_ci * documentation and/or other materials provided with the distribution. 3013498266Sopenharmony_ci * 3. All advertising materials mentioning features or use of this software 3113498266Sopenharmony_ci * must display the following acknowledgement: 3213498266Sopenharmony_ci * This product includes software developed by the University of 3313498266Sopenharmony_ci * California, Berkeley and its contributors. 3413498266Sopenharmony_ci * 4. Neither the name of the University nor the names of its contributors 3513498266Sopenharmony_ci * may be used to endorse or promote products derived from this software 3613498266Sopenharmony_ci * without specific prior written permission. 3713498266Sopenharmony_ci * 3813498266Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3913498266Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4013498266Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4113498266Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 4213498266Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4313498266Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4413498266Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4513498266Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4613498266Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4713498266Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4813498266Sopenharmony_ci * SUCH DAMAGE. 4913498266Sopenharmony_ci * 5013498266Sopenharmony_ci * SPDX-License-Identifier: BSD-4-Clause-UC 5113498266Sopenharmony_ci */ 5213498266Sopenharmony_ci 5313498266Sopenharmony_ci#include "server_setup.h" 5413498266Sopenharmony_ci 5513498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 5613498266Sopenharmony_ci#include <sys/ioctl.h> 5713498266Sopenharmony_ci#endif 5813498266Sopenharmony_ci#include <signal.h> 5913498266Sopenharmony_ci#ifdef HAVE_FCNTL_H 6013498266Sopenharmony_ci#include <fcntl.h> 6113498266Sopenharmony_ci#endif 6213498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 6313498266Sopenharmony_ci#include <netinet/in.h> 6413498266Sopenharmony_ci#endif 6513498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 6613498266Sopenharmony_ci#include <arpa/inet.h> 6713498266Sopenharmony_ci#endif 6813498266Sopenharmony_ci#ifdef HAVE_NETDB_H 6913498266Sopenharmony_ci#include <netdb.h> 7013498266Sopenharmony_ci#endif 7113498266Sopenharmony_ci#ifdef HAVE_SYS_FILIO_H 7213498266Sopenharmony_ci/* FIONREAD on Solaris 7 */ 7313498266Sopenharmony_ci#include <sys/filio.h> 7413498266Sopenharmony_ci#endif 7513498266Sopenharmony_ci 7613498266Sopenharmony_ci#include <setjmp.h> 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci#ifdef HAVE_PWD_H 7913498266Sopenharmony_ci#include <pwd.h> 8013498266Sopenharmony_ci#endif 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci#include <ctype.h> 8313498266Sopenharmony_ci 8413498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 8513498266Sopenharmony_ci/* make the curlx header define all printf() functions to use the curlx_* 8613498266Sopenharmony_ci versions instead */ 8713498266Sopenharmony_ci#include "curlx.h" /* from the private lib dir */ 8813498266Sopenharmony_ci#include "getpart.h" 8913498266Sopenharmony_ci#include "util.h" 9013498266Sopenharmony_ci#include "server_sockaddr.h" 9113498266Sopenharmony_ci#include "tftp.h" 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci/* include memdebug.h last */ 9413498266Sopenharmony_ci#include "memdebug.h" 9513498266Sopenharmony_ci 9613498266Sopenharmony_ci/***************************************************************************** 9713498266Sopenharmony_ci* STRUCT DECLARATIONS AND DEFINES * 9813498266Sopenharmony_ci*****************************************************************************/ 9913498266Sopenharmony_ci 10013498266Sopenharmony_ci#ifndef PKTSIZE 10113498266Sopenharmony_ci#define PKTSIZE (SEGSIZE + 4) /* SEGSIZE defined in arpa/tftp.h */ 10213498266Sopenharmony_ci#endif 10313498266Sopenharmony_ci 10413498266Sopenharmony_cistruct testcase { 10513498266Sopenharmony_ci char *buffer; /* holds the file data to send to the client */ 10613498266Sopenharmony_ci size_t bufsize; /* size of the data in buffer */ 10713498266Sopenharmony_ci char *rptr; /* read pointer into the buffer */ 10813498266Sopenharmony_ci size_t rcount; /* amount of data left to read of the file */ 10913498266Sopenharmony_ci long testno; /* test case number */ 11013498266Sopenharmony_ci int ofile; /* file descriptor for output file when uploading to us */ 11113498266Sopenharmony_ci 11213498266Sopenharmony_ci int writedelay; /* number of seconds between each packet */ 11313498266Sopenharmony_ci}; 11413498266Sopenharmony_ci 11513498266Sopenharmony_cistruct formats { 11613498266Sopenharmony_ci const char *f_mode; 11713498266Sopenharmony_ci int f_convert; 11813498266Sopenharmony_ci}; 11913498266Sopenharmony_ci 12013498266Sopenharmony_cistruct errmsg { 12113498266Sopenharmony_ci int e_code; 12213498266Sopenharmony_ci const char *e_msg; 12313498266Sopenharmony_ci}; 12413498266Sopenharmony_ci 12513498266Sopenharmony_citypedef union { 12613498266Sopenharmony_ci struct tftphdr hdr; 12713498266Sopenharmony_ci char storage[PKTSIZE]; 12813498266Sopenharmony_ci} tftphdr_storage_t; 12913498266Sopenharmony_ci 13013498266Sopenharmony_ci/* 13113498266Sopenharmony_ci * bf.counter values in range [-1 .. SEGSIZE] represents size of data in the 13213498266Sopenharmony_ci * bf.buf buffer. Additionally it can also hold flags BF_ALLOC or BF_FREE. 13313498266Sopenharmony_ci */ 13413498266Sopenharmony_ci 13513498266Sopenharmony_cistruct bf { 13613498266Sopenharmony_ci int counter; /* size of data in buffer, or flag */ 13713498266Sopenharmony_ci tftphdr_storage_t buf; /* room for data packet */ 13813498266Sopenharmony_ci}; 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci#define BF_ALLOC -3 /* alloc'd but not yet filled */ 14113498266Sopenharmony_ci#define BF_FREE -2 /* free */ 14213498266Sopenharmony_ci 14313498266Sopenharmony_ci#define opcode_RRQ 1 14413498266Sopenharmony_ci#define opcode_WRQ 2 14513498266Sopenharmony_ci#define opcode_DATA 3 14613498266Sopenharmony_ci#define opcode_ACK 4 14713498266Sopenharmony_ci#define opcode_ERROR 5 14813498266Sopenharmony_ci 14913498266Sopenharmony_ci#define TIMEOUT 5 15013498266Sopenharmony_ci 15113498266Sopenharmony_ci#undef MIN 15213498266Sopenharmony_ci#define MIN(x,y) ((x)<(y)?(x):(y)) 15313498266Sopenharmony_ci 15413498266Sopenharmony_ci#ifndef DEFAULT_LOGFILE 15513498266Sopenharmony_ci#define DEFAULT_LOGFILE "log/tftpd.log" 15613498266Sopenharmony_ci#endif 15713498266Sopenharmony_ci 15813498266Sopenharmony_ci#define REQUEST_DUMP "server.input" 15913498266Sopenharmony_ci 16013498266Sopenharmony_ci#define DEFAULT_PORT 8999 /* UDP */ 16113498266Sopenharmony_ci 16213498266Sopenharmony_ci/***************************************************************************** 16313498266Sopenharmony_ci* GLOBAL VARIABLES * 16413498266Sopenharmony_ci*****************************************************************************/ 16513498266Sopenharmony_ci 16613498266Sopenharmony_cistatic struct errmsg errmsgs[] = { 16713498266Sopenharmony_ci { EUNDEF, "Undefined error code" }, 16813498266Sopenharmony_ci { ENOTFOUND, "File not found" }, 16913498266Sopenharmony_ci { EACCESS, "Access violation" }, 17013498266Sopenharmony_ci { ENOSPACE, "Disk full or allocation exceeded" }, 17113498266Sopenharmony_ci { EBADOP, "Illegal TFTP operation" }, 17213498266Sopenharmony_ci { EBADID, "Unknown transfer ID" }, 17313498266Sopenharmony_ci { EEXISTS, "File already exists" }, 17413498266Sopenharmony_ci { ENOUSER, "No such user" }, 17513498266Sopenharmony_ci { -1, 0 } 17613498266Sopenharmony_ci}; 17713498266Sopenharmony_ci 17813498266Sopenharmony_cistatic const struct formats formata[] = { 17913498266Sopenharmony_ci { "netascii", 1 }, 18013498266Sopenharmony_ci { "octet", 0 }, 18113498266Sopenharmony_ci { NULL, 0 } 18213498266Sopenharmony_ci}; 18313498266Sopenharmony_ci 18413498266Sopenharmony_cistatic struct bf bfs[2]; 18513498266Sopenharmony_ci 18613498266Sopenharmony_cistatic int nextone; /* index of next buffer to use */ 18713498266Sopenharmony_cistatic int current; /* index of buffer in use */ 18813498266Sopenharmony_ci 18913498266Sopenharmony_ci /* control flags for crlf conversions */ 19013498266Sopenharmony_cistatic int newline = 0; /* fillbuf: in middle of newline expansion */ 19113498266Sopenharmony_cistatic int prevchar = -1; /* putbuf: previous char (cr check) */ 19213498266Sopenharmony_ci 19313498266Sopenharmony_cistatic tftphdr_storage_t buf; 19413498266Sopenharmony_cistatic tftphdr_storage_t ackbuf; 19513498266Sopenharmony_ci 19613498266Sopenharmony_cistatic srvr_sockaddr_union_t from; 19713498266Sopenharmony_cistatic curl_socklen_t fromlen; 19813498266Sopenharmony_ci 19913498266Sopenharmony_cistatic curl_socket_t peer = CURL_SOCKET_BAD; 20013498266Sopenharmony_ci 20113498266Sopenharmony_cistatic unsigned int timeout; 20213498266Sopenharmony_cistatic unsigned int maxtimeout = 5 * TIMEOUT; 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci#ifdef ENABLE_IPV6 20513498266Sopenharmony_cistatic bool use_ipv6 = FALSE; 20613498266Sopenharmony_ci#endif 20713498266Sopenharmony_cistatic const char *ipv_inuse = "IPv4"; 20813498266Sopenharmony_ci 20913498266Sopenharmony_ciconst char *serverlogfile = DEFAULT_LOGFILE; 21013498266Sopenharmony_cistatic const char *logdir = "log"; 21113498266Sopenharmony_cistatic char loglockfile[256]; 21213498266Sopenharmony_cistatic const char *pidname = ".tftpd.pid"; 21313498266Sopenharmony_cistatic const char *portname = NULL; /* none by default */ 21413498266Sopenharmony_cistatic int serverlogslocked = 0; 21513498266Sopenharmony_cistatic int wrotepidfile = 0; 21613498266Sopenharmony_cistatic int wroteportfile = 0; 21713498266Sopenharmony_ci 21813498266Sopenharmony_ci#ifdef HAVE_SIGSETJMP 21913498266Sopenharmony_cistatic sigjmp_buf timeoutbuf; 22013498266Sopenharmony_ci#endif 22113498266Sopenharmony_ci 22213498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 22313498266Sopenharmony_cistatic const unsigned int rexmtval = TIMEOUT; 22413498266Sopenharmony_ci#endif 22513498266Sopenharmony_ci 22613498266Sopenharmony_ci/***************************************************************************** 22713498266Sopenharmony_ci* FUNCTION PROTOTYPES * 22813498266Sopenharmony_ci*****************************************************************************/ 22913498266Sopenharmony_ci 23013498266Sopenharmony_cistatic struct tftphdr *rw_init(int); 23113498266Sopenharmony_ci 23213498266Sopenharmony_cistatic struct tftphdr *w_init(void); 23313498266Sopenharmony_ci 23413498266Sopenharmony_cistatic struct tftphdr *r_init(void); 23513498266Sopenharmony_ci 23613498266Sopenharmony_cistatic void read_ahead(struct testcase *test, int convert); 23713498266Sopenharmony_ci 23813498266Sopenharmony_cistatic ssize_t write_behind(struct testcase *test, int convert); 23913498266Sopenharmony_ci 24013498266Sopenharmony_cistatic int synchnet(curl_socket_t); 24113498266Sopenharmony_ci 24213498266Sopenharmony_cistatic int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size); 24313498266Sopenharmony_ci 24413498266Sopenharmony_cistatic int validate_access(struct testcase *test, const char *fname, int mode); 24513498266Sopenharmony_ci 24613498266Sopenharmony_cistatic void sendtftp(struct testcase *test, const struct formats *pf); 24713498266Sopenharmony_ci 24813498266Sopenharmony_cistatic void recvtftp(struct testcase *test, const struct formats *pf); 24913498266Sopenharmony_ci 25013498266Sopenharmony_cistatic void nak(int error); 25113498266Sopenharmony_ci 25213498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 25313498266Sopenharmony_ci 25413498266Sopenharmony_cistatic void mysignal(int sig, void (*handler)(int)); 25513498266Sopenharmony_ci 25613498266Sopenharmony_cistatic void timer(int signum); 25713498266Sopenharmony_ci 25813498266Sopenharmony_cistatic void justtimeout(int signum); 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci#endif /* HAVE_ALARM && SIGALRM */ 26113498266Sopenharmony_ci 26213498266Sopenharmony_ci/***************************************************************************** 26313498266Sopenharmony_ci* FUNCTION IMPLEMENTATIONS * 26413498266Sopenharmony_ci*****************************************************************************/ 26513498266Sopenharmony_ci 26613498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 26713498266Sopenharmony_ci 26813498266Sopenharmony_ci/* 26913498266Sopenharmony_ci * Like signal(), but with well-defined semantics. 27013498266Sopenharmony_ci */ 27113498266Sopenharmony_cistatic void mysignal(int sig, void (*handler)(int)) 27213498266Sopenharmony_ci{ 27313498266Sopenharmony_ci struct sigaction sa; 27413498266Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 27513498266Sopenharmony_ci sa.sa_handler = handler; 27613498266Sopenharmony_ci sigaction(sig, &sa, NULL); 27713498266Sopenharmony_ci} 27813498266Sopenharmony_ci 27913498266Sopenharmony_cistatic void timer(int signum) 28013498266Sopenharmony_ci{ 28113498266Sopenharmony_ci (void)signum; 28213498266Sopenharmony_ci 28313498266Sopenharmony_ci logmsg("alarm!"); 28413498266Sopenharmony_ci 28513498266Sopenharmony_ci timeout += rexmtval; 28613498266Sopenharmony_ci if(timeout >= maxtimeout) { 28713498266Sopenharmony_ci if(wrotepidfile) { 28813498266Sopenharmony_ci wrotepidfile = 0; 28913498266Sopenharmony_ci unlink(pidname); 29013498266Sopenharmony_ci } 29113498266Sopenharmony_ci if(wroteportfile) { 29213498266Sopenharmony_ci wroteportfile = 0; 29313498266Sopenharmony_ci unlink(portname); 29413498266Sopenharmony_ci } 29513498266Sopenharmony_ci if(serverlogslocked) { 29613498266Sopenharmony_ci serverlogslocked = 0; 29713498266Sopenharmony_ci clear_advisor_read_lock(loglockfile); 29813498266Sopenharmony_ci } 29913498266Sopenharmony_ci exit(1); 30013498266Sopenharmony_ci } 30113498266Sopenharmony_ci#ifdef HAVE_SIGSETJMP 30213498266Sopenharmony_ci siglongjmp(timeoutbuf, 1); 30313498266Sopenharmony_ci#endif 30413498266Sopenharmony_ci} 30513498266Sopenharmony_ci 30613498266Sopenharmony_cistatic void justtimeout(int signum) 30713498266Sopenharmony_ci{ 30813498266Sopenharmony_ci (void)signum; 30913498266Sopenharmony_ci} 31013498266Sopenharmony_ci 31113498266Sopenharmony_ci#endif /* HAVE_ALARM && SIGALRM */ 31213498266Sopenharmony_ci 31313498266Sopenharmony_ci/* 31413498266Sopenharmony_ci * init for either read-ahead or write-behind. 31513498266Sopenharmony_ci * zero for write-behind, one for read-head. 31613498266Sopenharmony_ci */ 31713498266Sopenharmony_cistatic struct tftphdr *rw_init(int x) 31813498266Sopenharmony_ci{ 31913498266Sopenharmony_ci newline = 0; /* init crlf flag */ 32013498266Sopenharmony_ci prevchar = -1; 32113498266Sopenharmony_ci bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ 32213498266Sopenharmony_ci current = 0; 32313498266Sopenharmony_ci bfs[1].counter = BF_FREE; 32413498266Sopenharmony_ci nextone = x; /* ahead or behind? */ 32513498266Sopenharmony_ci return &bfs[0].buf.hdr; 32613498266Sopenharmony_ci} 32713498266Sopenharmony_ci 32813498266Sopenharmony_cistatic struct tftphdr *w_init(void) 32913498266Sopenharmony_ci{ 33013498266Sopenharmony_ci return rw_init(0); /* write-behind */ 33113498266Sopenharmony_ci} 33213498266Sopenharmony_ci 33313498266Sopenharmony_cistatic struct tftphdr *r_init(void) 33413498266Sopenharmony_ci{ 33513498266Sopenharmony_ci return rw_init(1); /* read-ahead */ 33613498266Sopenharmony_ci} 33713498266Sopenharmony_ci 33813498266Sopenharmony_ci/* Have emptied current buffer by sending to net and getting ack. 33913498266Sopenharmony_ci Free it and return next buffer filled with data. 34013498266Sopenharmony_ci */ 34113498266Sopenharmony_cistatic int readit(struct testcase *test, struct tftphdr **dpp, 34213498266Sopenharmony_ci int convert /* if true, convert to ascii */) 34313498266Sopenharmony_ci{ 34413498266Sopenharmony_ci struct bf *b; 34513498266Sopenharmony_ci 34613498266Sopenharmony_ci bfs[current].counter = BF_FREE; /* free old one */ 34713498266Sopenharmony_ci current = !current; /* "incr" current */ 34813498266Sopenharmony_ci 34913498266Sopenharmony_ci b = &bfs[current]; /* look at new buffer */ 35013498266Sopenharmony_ci if(b->counter == BF_FREE) /* if it's empty */ 35113498266Sopenharmony_ci read_ahead(test, convert); /* fill it */ 35213498266Sopenharmony_ci 35313498266Sopenharmony_ci *dpp = &b->buf.hdr; /* set caller's ptr */ 35413498266Sopenharmony_ci return b->counter; 35513498266Sopenharmony_ci} 35613498266Sopenharmony_ci 35713498266Sopenharmony_ci/* 35813498266Sopenharmony_ci * fill the input buffer, doing ascii conversions if requested 35913498266Sopenharmony_ci * conversions are lf -> cr, lf and cr -> cr, nul 36013498266Sopenharmony_ci */ 36113498266Sopenharmony_cistatic void read_ahead(struct testcase *test, 36213498266Sopenharmony_ci int convert /* if true, convert to ascii */) 36313498266Sopenharmony_ci{ 36413498266Sopenharmony_ci int i; 36513498266Sopenharmony_ci char *p; 36613498266Sopenharmony_ci int c; 36713498266Sopenharmony_ci struct bf *b; 36813498266Sopenharmony_ci struct tftphdr *dp; 36913498266Sopenharmony_ci 37013498266Sopenharmony_ci b = &bfs[nextone]; /* look at "next" buffer */ 37113498266Sopenharmony_ci if(b->counter != BF_FREE) /* nop if not free */ 37213498266Sopenharmony_ci return; 37313498266Sopenharmony_ci nextone = !nextone; /* "incr" next buffer ptr */ 37413498266Sopenharmony_ci 37513498266Sopenharmony_ci dp = &b->buf.hdr; 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci if(convert == 0) { 37813498266Sopenharmony_ci /* The former file reading code did this: 37913498266Sopenharmony_ci b->counter = read(fileno(file), dp->th_data, SEGSIZE); */ 38013498266Sopenharmony_ci size_t copy_n = MIN(SEGSIZE, test->rcount); 38113498266Sopenharmony_ci memcpy(dp->th_data, test->rptr, copy_n); 38213498266Sopenharmony_ci 38313498266Sopenharmony_ci /* decrease amount, advance pointer */ 38413498266Sopenharmony_ci test->rcount -= copy_n; 38513498266Sopenharmony_ci test->rptr += copy_n; 38613498266Sopenharmony_ci b->counter = (int)copy_n; 38713498266Sopenharmony_ci return; 38813498266Sopenharmony_ci } 38913498266Sopenharmony_ci 39013498266Sopenharmony_ci p = dp->th_data; 39113498266Sopenharmony_ci for(i = 0 ; i < SEGSIZE; i++) { 39213498266Sopenharmony_ci if(newline) { 39313498266Sopenharmony_ci if(prevchar == '\n') 39413498266Sopenharmony_ci c = '\n'; /* lf to cr,lf */ 39513498266Sopenharmony_ci else 39613498266Sopenharmony_ci c = '\0'; /* cr to cr,nul */ 39713498266Sopenharmony_ci newline = 0; 39813498266Sopenharmony_ci } 39913498266Sopenharmony_ci else { 40013498266Sopenharmony_ci if(test->rcount) { 40113498266Sopenharmony_ci c = test->rptr[0]; 40213498266Sopenharmony_ci test->rptr++; 40313498266Sopenharmony_ci test->rcount--; 40413498266Sopenharmony_ci } 40513498266Sopenharmony_ci else 40613498266Sopenharmony_ci break; 40713498266Sopenharmony_ci if(c == '\n' || c == '\r') { 40813498266Sopenharmony_ci prevchar = c; 40913498266Sopenharmony_ci c = '\r'; 41013498266Sopenharmony_ci newline = 1; 41113498266Sopenharmony_ci } 41213498266Sopenharmony_ci } 41313498266Sopenharmony_ci *p++ = (char)c; 41413498266Sopenharmony_ci } 41513498266Sopenharmony_ci b->counter = (int)(p - dp->th_data); 41613498266Sopenharmony_ci} 41713498266Sopenharmony_ci 41813498266Sopenharmony_ci/* Update count associated with the buffer, get new buffer from the queue. 41913498266Sopenharmony_ci Calls write_behind only if next buffer not available. 42013498266Sopenharmony_ci */ 42113498266Sopenharmony_cistatic int writeit(struct testcase *test, struct tftphdr * volatile *dpp, 42213498266Sopenharmony_ci int ct, int convert) 42313498266Sopenharmony_ci{ 42413498266Sopenharmony_ci bfs[current].counter = ct; /* set size of data to write */ 42513498266Sopenharmony_ci current = !current; /* switch to other buffer */ 42613498266Sopenharmony_ci if(bfs[current].counter != BF_FREE) /* if not free */ 42713498266Sopenharmony_ci write_behind(test, convert); /* flush it */ 42813498266Sopenharmony_ci bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ 42913498266Sopenharmony_ci *dpp = &bfs[current].buf.hdr; 43013498266Sopenharmony_ci return ct; /* this is a lie of course */ 43113498266Sopenharmony_ci} 43213498266Sopenharmony_ci 43313498266Sopenharmony_ci/* 43413498266Sopenharmony_ci * Output a buffer to a file, converting from netascii if requested. 43513498266Sopenharmony_ci * CR, NUL -> CR and CR, LF => LF. 43613498266Sopenharmony_ci * Note spec is undefined if we get CR as last byte of file or a 43713498266Sopenharmony_ci * CR followed by anything else. In this case we leave it alone. 43813498266Sopenharmony_ci */ 43913498266Sopenharmony_cistatic ssize_t write_behind(struct testcase *test, int convert) 44013498266Sopenharmony_ci{ 44113498266Sopenharmony_ci char *writebuf; 44213498266Sopenharmony_ci int count; 44313498266Sopenharmony_ci int ct; 44413498266Sopenharmony_ci char *p; 44513498266Sopenharmony_ci int c; /* current character */ 44613498266Sopenharmony_ci struct bf *b; 44713498266Sopenharmony_ci struct tftphdr *dp; 44813498266Sopenharmony_ci 44913498266Sopenharmony_ci b = &bfs[nextone]; 45013498266Sopenharmony_ci if(b->counter < -1) /* anything to flush? */ 45113498266Sopenharmony_ci return 0; /* just nop if nothing to do */ 45213498266Sopenharmony_ci 45313498266Sopenharmony_ci if(!test->ofile) { 45413498266Sopenharmony_ci char outfile[256]; 45513498266Sopenharmony_ci msnprintf(outfile, sizeof(outfile), "%s/upload.%ld", logdir, test->testno); 45613498266Sopenharmony_ci#ifdef _WIN32 45713498266Sopenharmony_ci test->ofile = open(outfile, O_CREAT|O_RDWR|O_BINARY, 0777); 45813498266Sopenharmony_ci#else 45913498266Sopenharmony_ci test->ofile = open(outfile, O_CREAT|O_RDWR, 0777); 46013498266Sopenharmony_ci#endif 46113498266Sopenharmony_ci if(test->ofile == -1) { 46213498266Sopenharmony_ci logmsg("Couldn't create and/or open file %s for upload!", outfile); 46313498266Sopenharmony_ci return -1; /* failure! */ 46413498266Sopenharmony_ci } 46513498266Sopenharmony_ci } 46613498266Sopenharmony_ci 46713498266Sopenharmony_ci count = b->counter; /* remember byte count */ 46813498266Sopenharmony_ci b->counter = BF_FREE; /* reset flag */ 46913498266Sopenharmony_ci dp = &b->buf.hdr; 47013498266Sopenharmony_ci nextone = !nextone; /* incr for next time */ 47113498266Sopenharmony_ci writebuf = dp->th_data; 47213498266Sopenharmony_ci 47313498266Sopenharmony_ci if(count <= 0) 47413498266Sopenharmony_ci return -1; /* nak logic? */ 47513498266Sopenharmony_ci 47613498266Sopenharmony_ci if(convert == 0) 47713498266Sopenharmony_ci return write(test->ofile, writebuf, count); 47813498266Sopenharmony_ci 47913498266Sopenharmony_ci p = writebuf; 48013498266Sopenharmony_ci ct = count; 48113498266Sopenharmony_ci while(ct--) { /* loop over the buffer */ 48213498266Sopenharmony_ci c = *p++; /* pick up a character */ 48313498266Sopenharmony_ci if(prevchar == '\r') { /* if prev char was cr */ 48413498266Sopenharmony_ci if(c == '\n') /* if have cr,lf then just */ 48513498266Sopenharmony_ci lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */ 48613498266Sopenharmony_ci else 48713498266Sopenharmony_ci if(c == '\0') /* if have cr,nul then */ 48813498266Sopenharmony_ci goto skipit; /* just skip over the putc */ 48913498266Sopenharmony_ci /* else just fall through and allow it */ 49013498266Sopenharmony_ci } 49113498266Sopenharmony_ci /* formerly 49213498266Sopenharmony_ci putc(c, file); */ 49313498266Sopenharmony_ci if(1 != write(test->ofile, &c, 1)) 49413498266Sopenharmony_ci break; 49513498266Sopenharmony_ciskipit: 49613498266Sopenharmony_ci prevchar = c; 49713498266Sopenharmony_ci } 49813498266Sopenharmony_ci return count; 49913498266Sopenharmony_ci} 50013498266Sopenharmony_ci 50113498266Sopenharmony_ci/* When an error has occurred, it is possible that the two sides are out of 50213498266Sopenharmony_ci * synch. Ie: that what I think is the other side's response to packet N is 50313498266Sopenharmony_ci * really their response to packet N-1. 50413498266Sopenharmony_ci * 50513498266Sopenharmony_ci * So, to try to prevent that, we flush all the input queued up for us on the 50613498266Sopenharmony_ci * network connection on our host. 50713498266Sopenharmony_ci * 50813498266Sopenharmony_ci * We return the number of packets we flushed (mostly for reporting when trace 50913498266Sopenharmony_ci * is active). 51013498266Sopenharmony_ci */ 51113498266Sopenharmony_ci 51213498266Sopenharmony_cistatic int synchnet(curl_socket_t f /* socket to flush */) 51313498266Sopenharmony_ci{ 51413498266Sopenharmony_ci 51513498266Sopenharmony_ci#if defined(HAVE_IOCTLSOCKET) 51613498266Sopenharmony_ci unsigned long i; 51713498266Sopenharmony_ci#else 51813498266Sopenharmony_ci int i; 51913498266Sopenharmony_ci#endif 52013498266Sopenharmony_ci int j = 0; 52113498266Sopenharmony_ci char rbuf[PKTSIZE]; 52213498266Sopenharmony_ci srvr_sockaddr_union_t fromaddr; 52313498266Sopenharmony_ci curl_socklen_t fromaddrlen; 52413498266Sopenharmony_ci 52513498266Sopenharmony_ci for(;;) { 52613498266Sopenharmony_ci#if defined(HAVE_IOCTLSOCKET) 52713498266Sopenharmony_ci (void) ioctlsocket(f, FIONREAD, &i); 52813498266Sopenharmony_ci#else 52913498266Sopenharmony_ci (void) ioctl(f, FIONREAD, &i); 53013498266Sopenharmony_ci#endif 53113498266Sopenharmony_ci if(i) { 53213498266Sopenharmony_ci j++; 53313498266Sopenharmony_ci#ifdef ENABLE_IPV6 53413498266Sopenharmony_ci if(!use_ipv6) 53513498266Sopenharmony_ci#endif 53613498266Sopenharmony_ci fromaddrlen = sizeof(fromaddr.sa4); 53713498266Sopenharmony_ci#ifdef ENABLE_IPV6 53813498266Sopenharmony_ci else 53913498266Sopenharmony_ci fromaddrlen = sizeof(fromaddr.sa6); 54013498266Sopenharmony_ci#endif 54113498266Sopenharmony_ci (void) recvfrom(f, rbuf, sizeof(rbuf), 0, 54213498266Sopenharmony_ci &fromaddr.sa, &fromaddrlen); 54313498266Sopenharmony_ci } 54413498266Sopenharmony_ci else 54513498266Sopenharmony_ci break; 54613498266Sopenharmony_ci } 54713498266Sopenharmony_ci return j; 54813498266Sopenharmony_ci} 54913498266Sopenharmony_ci 55013498266Sopenharmony_ciint main(int argc, char **argv) 55113498266Sopenharmony_ci{ 55213498266Sopenharmony_ci srvr_sockaddr_union_t me; 55313498266Sopenharmony_ci struct tftphdr *tp; 55413498266Sopenharmony_ci ssize_t n = 0; 55513498266Sopenharmony_ci int arg = 1; 55613498266Sopenharmony_ci unsigned short port = DEFAULT_PORT; 55713498266Sopenharmony_ci curl_socket_t sock = CURL_SOCKET_BAD; 55813498266Sopenharmony_ci int flag; 55913498266Sopenharmony_ci int rc; 56013498266Sopenharmony_ci int error; 56113498266Sopenharmony_ci struct testcase test; 56213498266Sopenharmony_ci int result = 0; 56313498266Sopenharmony_ci 56413498266Sopenharmony_ci memset(&test, 0, sizeof(test)); 56513498266Sopenharmony_ci 56613498266Sopenharmony_ci while(argc>arg) { 56713498266Sopenharmony_ci if(!strcmp("--version", argv[arg])) { 56813498266Sopenharmony_ci printf("tftpd IPv4%s\n", 56913498266Sopenharmony_ci#ifdef ENABLE_IPV6 57013498266Sopenharmony_ci "/IPv6" 57113498266Sopenharmony_ci#else 57213498266Sopenharmony_ci "" 57313498266Sopenharmony_ci#endif 57413498266Sopenharmony_ci ); 57513498266Sopenharmony_ci return 0; 57613498266Sopenharmony_ci } 57713498266Sopenharmony_ci else if(!strcmp("--pidfile", argv[arg])) { 57813498266Sopenharmony_ci arg++; 57913498266Sopenharmony_ci if(argc>arg) 58013498266Sopenharmony_ci pidname = argv[arg++]; 58113498266Sopenharmony_ci } 58213498266Sopenharmony_ci else if(!strcmp("--portfile", argv[arg])) { 58313498266Sopenharmony_ci arg++; 58413498266Sopenharmony_ci if(argc>arg) 58513498266Sopenharmony_ci portname = argv[arg++]; 58613498266Sopenharmony_ci } 58713498266Sopenharmony_ci else if(!strcmp("--logfile", argv[arg])) { 58813498266Sopenharmony_ci arg++; 58913498266Sopenharmony_ci if(argc>arg) 59013498266Sopenharmony_ci serverlogfile = argv[arg++]; 59113498266Sopenharmony_ci } 59213498266Sopenharmony_ci else if(!strcmp("--logdir", argv[arg])) { 59313498266Sopenharmony_ci arg++; 59413498266Sopenharmony_ci if(argc>arg) 59513498266Sopenharmony_ci logdir = argv[arg++]; 59613498266Sopenharmony_ci } 59713498266Sopenharmony_ci else if(!strcmp("--ipv4", argv[arg])) { 59813498266Sopenharmony_ci#ifdef ENABLE_IPV6 59913498266Sopenharmony_ci ipv_inuse = "IPv4"; 60013498266Sopenharmony_ci use_ipv6 = FALSE; 60113498266Sopenharmony_ci#endif 60213498266Sopenharmony_ci arg++; 60313498266Sopenharmony_ci } 60413498266Sopenharmony_ci else if(!strcmp("--ipv6", argv[arg])) { 60513498266Sopenharmony_ci#ifdef ENABLE_IPV6 60613498266Sopenharmony_ci ipv_inuse = "IPv6"; 60713498266Sopenharmony_ci use_ipv6 = TRUE; 60813498266Sopenharmony_ci#endif 60913498266Sopenharmony_ci arg++; 61013498266Sopenharmony_ci } 61113498266Sopenharmony_ci else if(!strcmp("--port", argv[arg])) { 61213498266Sopenharmony_ci arg++; 61313498266Sopenharmony_ci if(argc>arg) { 61413498266Sopenharmony_ci char *endptr; 61513498266Sopenharmony_ci unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 61613498266Sopenharmony_ci port = curlx_ultous(ulnum); 61713498266Sopenharmony_ci arg++; 61813498266Sopenharmony_ci } 61913498266Sopenharmony_ci } 62013498266Sopenharmony_ci else if(!strcmp("--srcdir", argv[arg])) { 62113498266Sopenharmony_ci arg++; 62213498266Sopenharmony_ci if(argc>arg) { 62313498266Sopenharmony_ci path = argv[arg]; 62413498266Sopenharmony_ci arg++; 62513498266Sopenharmony_ci } 62613498266Sopenharmony_ci } 62713498266Sopenharmony_ci else { 62813498266Sopenharmony_ci puts("Usage: tftpd [option]\n" 62913498266Sopenharmony_ci " --version\n" 63013498266Sopenharmony_ci " --logfile [file]\n" 63113498266Sopenharmony_ci " --logdir [directory]\n" 63213498266Sopenharmony_ci " --pidfile [file]\n" 63313498266Sopenharmony_ci " --portfile [file]\n" 63413498266Sopenharmony_ci " --ipv4\n" 63513498266Sopenharmony_ci " --ipv6\n" 63613498266Sopenharmony_ci " --port [port]\n" 63713498266Sopenharmony_ci " --srcdir [path]"); 63813498266Sopenharmony_ci return 0; 63913498266Sopenharmony_ci } 64013498266Sopenharmony_ci } 64113498266Sopenharmony_ci 64213498266Sopenharmony_ci msnprintf(loglockfile, sizeof(loglockfile), "%s/%s/tftp-%s.lock", 64313498266Sopenharmony_ci logdir, SERVERLOGS_LOCKDIR, ipv_inuse); 64413498266Sopenharmony_ci 64513498266Sopenharmony_ci#ifdef _WIN32 64613498266Sopenharmony_ci win32_init(); 64713498266Sopenharmony_ci atexit(win32_cleanup); 64813498266Sopenharmony_ci#endif 64913498266Sopenharmony_ci 65013498266Sopenharmony_ci install_signal_handlers(true); 65113498266Sopenharmony_ci 65213498266Sopenharmony_ci#ifdef ENABLE_IPV6 65313498266Sopenharmony_ci if(!use_ipv6) 65413498266Sopenharmony_ci#endif 65513498266Sopenharmony_ci sock = socket(AF_INET, SOCK_DGRAM, 0); 65613498266Sopenharmony_ci#ifdef ENABLE_IPV6 65713498266Sopenharmony_ci else 65813498266Sopenharmony_ci sock = socket(AF_INET6, SOCK_DGRAM, 0); 65913498266Sopenharmony_ci#endif 66013498266Sopenharmony_ci 66113498266Sopenharmony_ci if(CURL_SOCKET_BAD == sock) { 66213498266Sopenharmony_ci error = SOCKERRNO; 66313498266Sopenharmony_ci logmsg("Error creating socket: (%d) %s", error, sstrerror(error)); 66413498266Sopenharmony_ci result = 1; 66513498266Sopenharmony_ci goto tftpd_cleanup; 66613498266Sopenharmony_ci } 66713498266Sopenharmony_ci 66813498266Sopenharmony_ci flag = 1; 66913498266Sopenharmony_ci if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 67013498266Sopenharmony_ci (void *)&flag, sizeof(flag))) { 67113498266Sopenharmony_ci error = SOCKERRNO; 67213498266Sopenharmony_ci logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", 67313498266Sopenharmony_ci error, sstrerror(error)); 67413498266Sopenharmony_ci result = 1; 67513498266Sopenharmony_ci goto tftpd_cleanup; 67613498266Sopenharmony_ci } 67713498266Sopenharmony_ci 67813498266Sopenharmony_ci#ifdef ENABLE_IPV6 67913498266Sopenharmony_ci if(!use_ipv6) { 68013498266Sopenharmony_ci#endif 68113498266Sopenharmony_ci memset(&me.sa4, 0, sizeof(me.sa4)); 68213498266Sopenharmony_ci me.sa4.sin_family = AF_INET; 68313498266Sopenharmony_ci me.sa4.sin_addr.s_addr = INADDR_ANY; 68413498266Sopenharmony_ci me.sa4.sin_port = htons(port); 68513498266Sopenharmony_ci rc = bind(sock, &me.sa, sizeof(me.sa4)); 68613498266Sopenharmony_ci#ifdef ENABLE_IPV6 68713498266Sopenharmony_ci } 68813498266Sopenharmony_ci else { 68913498266Sopenharmony_ci memset(&me.sa6, 0, sizeof(me.sa6)); 69013498266Sopenharmony_ci me.sa6.sin6_family = AF_INET6; 69113498266Sopenharmony_ci me.sa6.sin6_addr = in6addr_any; 69213498266Sopenharmony_ci me.sa6.sin6_port = htons(port); 69313498266Sopenharmony_ci rc = bind(sock, &me.sa, sizeof(me.sa6)); 69413498266Sopenharmony_ci } 69513498266Sopenharmony_ci#endif /* ENABLE_IPV6 */ 69613498266Sopenharmony_ci if(0 != rc) { 69713498266Sopenharmony_ci error = SOCKERRNO; 69813498266Sopenharmony_ci logmsg("Error binding socket on port %hu: (%d) %s", port, error, 69913498266Sopenharmony_ci sstrerror(error)); 70013498266Sopenharmony_ci result = 1; 70113498266Sopenharmony_ci goto tftpd_cleanup; 70213498266Sopenharmony_ci } 70313498266Sopenharmony_ci 70413498266Sopenharmony_ci if(!port) { 70513498266Sopenharmony_ci /* The system was supposed to choose a port number, figure out which 70613498266Sopenharmony_ci port we actually got and update the listener port value with it. */ 70713498266Sopenharmony_ci curl_socklen_t la_size; 70813498266Sopenharmony_ci srvr_sockaddr_union_t localaddr; 70913498266Sopenharmony_ci#ifdef ENABLE_IPV6 71013498266Sopenharmony_ci if(!use_ipv6) 71113498266Sopenharmony_ci#endif 71213498266Sopenharmony_ci la_size = sizeof(localaddr.sa4); 71313498266Sopenharmony_ci#ifdef ENABLE_IPV6 71413498266Sopenharmony_ci else 71513498266Sopenharmony_ci la_size = sizeof(localaddr.sa6); 71613498266Sopenharmony_ci#endif 71713498266Sopenharmony_ci memset(&localaddr.sa, 0, (size_t)la_size); 71813498266Sopenharmony_ci if(getsockname(sock, &localaddr.sa, &la_size) < 0) { 71913498266Sopenharmony_ci error = SOCKERRNO; 72013498266Sopenharmony_ci logmsg("getsockname() failed with error: (%d) %s", 72113498266Sopenharmony_ci error, sstrerror(error)); 72213498266Sopenharmony_ci sclose(sock); 72313498266Sopenharmony_ci goto tftpd_cleanup; 72413498266Sopenharmony_ci } 72513498266Sopenharmony_ci switch(localaddr.sa.sa_family) { 72613498266Sopenharmony_ci case AF_INET: 72713498266Sopenharmony_ci port = ntohs(localaddr.sa4.sin_port); 72813498266Sopenharmony_ci break; 72913498266Sopenharmony_ci#ifdef ENABLE_IPV6 73013498266Sopenharmony_ci case AF_INET6: 73113498266Sopenharmony_ci port = ntohs(localaddr.sa6.sin6_port); 73213498266Sopenharmony_ci break; 73313498266Sopenharmony_ci#endif 73413498266Sopenharmony_ci default: 73513498266Sopenharmony_ci break; 73613498266Sopenharmony_ci } 73713498266Sopenharmony_ci if(!port) { 73813498266Sopenharmony_ci /* Real failure, listener port shall not be zero beyond this point. */ 73913498266Sopenharmony_ci logmsg("Apparently getsockname() succeeded, with listener port zero."); 74013498266Sopenharmony_ci logmsg("A valid reason for this failure is a binary built without"); 74113498266Sopenharmony_ci logmsg("proper network library linkage. This might not be the only"); 74213498266Sopenharmony_ci logmsg("reason, but double check it before anything else."); 74313498266Sopenharmony_ci result = 2; 74413498266Sopenharmony_ci goto tftpd_cleanup; 74513498266Sopenharmony_ci } 74613498266Sopenharmony_ci } 74713498266Sopenharmony_ci 74813498266Sopenharmony_ci wrotepidfile = write_pidfile(pidname); 74913498266Sopenharmony_ci if(!wrotepidfile) { 75013498266Sopenharmony_ci result = 1; 75113498266Sopenharmony_ci goto tftpd_cleanup; 75213498266Sopenharmony_ci } 75313498266Sopenharmony_ci 75413498266Sopenharmony_ci if(portname) { 75513498266Sopenharmony_ci wroteportfile = write_portfile(portname, port); 75613498266Sopenharmony_ci if(!wroteportfile) { 75713498266Sopenharmony_ci result = 1; 75813498266Sopenharmony_ci goto tftpd_cleanup; 75913498266Sopenharmony_ci } 76013498266Sopenharmony_ci } 76113498266Sopenharmony_ci 76213498266Sopenharmony_ci logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port); 76313498266Sopenharmony_ci 76413498266Sopenharmony_ci for(;;) { 76513498266Sopenharmony_ci fromlen = sizeof(from); 76613498266Sopenharmony_ci#ifdef ENABLE_IPV6 76713498266Sopenharmony_ci if(!use_ipv6) 76813498266Sopenharmony_ci#endif 76913498266Sopenharmony_ci fromlen = sizeof(from.sa4); 77013498266Sopenharmony_ci#ifdef ENABLE_IPV6 77113498266Sopenharmony_ci else 77213498266Sopenharmony_ci fromlen = sizeof(from.sa6); 77313498266Sopenharmony_ci#endif 77413498266Sopenharmony_ci n = (ssize_t)recvfrom(sock, &buf.storage[0], sizeof(buf.storage), 0, 77513498266Sopenharmony_ci &from.sa, &fromlen); 77613498266Sopenharmony_ci if(got_exit_signal) 77713498266Sopenharmony_ci break; 77813498266Sopenharmony_ci if(n < 0) { 77913498266Sopenharmony_ci logmsg("recvfrom"); 78013498266Sopenharmony_ci result = 3; 78113498266Sopenharmony_ci break; 78213498266Sopenharmony_ci } 78313498266Sopenharmony_ci 78413498266Sopenharmony_ci set_advisor_read_lock(loglockfile); 78513498266Sopenharmony_ci serverlogslocked = 1; 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci#ifdef ENABLE_IPV6 78813498266Sopenharmony_ci if(!use_ipv6) { 78913498266Sopenharmony_ci#endif 79013498266Sopenharmony_ci from.sa4.sin_family = AF_INET; 79113498266Sopenharmony_ci peer = socket(AF_INET, SOCK_DGRAM, 0); 79213498266Sopenharmony_ci if(CURL_SOCKET_BAD == peer) { 79313498266Sopenharmony_ci logmsg("socket"); 79413498266Sopenharmony_ci result = 2; 79513498266Sopenharmony_ci break; 79613498266Sopenharmony_ci } 79713498266Sopenharmony_ci if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) { 79813498266Sopenharmony_ci logmsg("connect: fail"); 79913498266Sopenharmony_ci result = 1; 80013498266Sopenharmony_ci break; 80113498266Sopenharmony_ci } 80213498266Sopenharmony_ci#ifdef ENABLE_IPV6 80313498266Sopenharmony_ci } 80413498266Sopenharmony_ci else { 80513498266Sopenharmony_ci from.sa6.sin6_family = AF_INET6; 80613498266Sopenharmony_ci peer = socket(AF_INET6, SOCK_DGRAM, 0); 80713498266Sopenharmony_ci if(CURL_SOCKET_BAD == peer) { 80813498266Sopenharmony_ci logmsg("socket"); 80913498266Sopenharmony_ci result = 2; 81013498266Sopenharmony_ci break; 81113498266Sopenharmony_ci } 81213498266Sopenharmony_ci if(connect(peer, &from.sa, sizeof(from.sa6)) < 0) { 81313498266Sopenharmony_ci logmsg("connect: fail"); 81413498266Sopenharmony_ci result = 1; 81513498266Sopenharmony_ci break; 81613498266Sopenharmony_ci } 81713498266Sopenharmony_ci } 81813498266Sopenharmony_ci#endif 81913498266Sopenharmony_ci 82013498266Sopenharmony_ci maxtimeout = 5*TIMEOUT; 82113498266Sopenharmony_ci 82213498266Sopenharmony_ci tp = &buf.hdr; 82313498266Sopenharmony_ci tp->th_opcode = ntohs(tp->th_opcode); 82413498266Sopenharmony_ci if(tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) { 82513498266Sopenharmony_ci memset(&test, 0, sizeof(test)); 82613498266Sopenharmony_ci if(do_tftp(&test, tp, n) < 0) 82713498266Sopenharmony_ci break; 82813498266Sopenharmony_ci free(test.buffer); 82913498266Sopenharmony_ci } 83013498266Sopenharmony_ci sclose(peer); 83113498266Sopenharmony_ci peer = CURL_SOCKET_BAD; 83213498266Sopenharmony_ci 83313498266Sopenharmony_ci if(got_exit_signal) 83413498266Sopenharmony_ci break; 83513498266Sopenharmony_ci 83613498266Sopenharmony_ci if(serverlogslocked) { 83713498266Sopenharmony_ci serverlogslocked = 0; 83813498266Sopenharmony_ci clear_advisor_read_lock(loglockfile); 83913498266Sopenharmony_ci } 84013498266Sopenharmony_ci 84113498266Sopenharmony_ci logmsg("end of one transfer"); 84213498266Sopenharmony_ci 84313498266Sopenharmony_ci } 84413498266Sopenharmony_ci 84513498266Sopenharmony_citftpd_cleanup: 84613498266Sopenharmony_ci 84713498266Sopenharmony_ci if(test.ofile > 0) 84813498266Sopenharmony_ci close(test.ofile); 84913498266Sopenharmony_ci 85013498266Sopenharmony_ci if((peer != sock) && (peer != CURL_SOCKET_BAD)) 85113498266Sopenharmony_ci sclose(peer); 85213498266Sopenharmony_ci 85313498266Sopenharmony_ci if(sock != CURL_SOCKET_BAD) 85413498266Sopenharmony_ci sclose(sock); 85513498266Sopenharmony_ci 85613498266Sopenharmony_ci if(got_exit_signal) 85713498266Sopenharmony_ci logmsg("signalled to die"); 85813498266Sopenharmony_ci 85913498266Sopenharmony_ci if(wrotepidfile) 86013498266Sopenharmony_ci unlink(pidname); 86113498266Sopenharmony_ci if(wroteportfile) 86213498266Sopenharmony_ci unlink(portname); 86313498266Sopenharmony_ci 86413498266Sopenharmony_ci if(serverlogslocked) { 86513498266Sopenharmony_ci serverlogslocked = 0; 86613498266Sopenharmony_ci clear_advisor_read_lock(loglockfile); 86713498266Sopenharmony_ci } 86813498266Sopenharmony_ci 86913498266Sopenharmony_ci restore_signal_handlers(true); 87013498266Sopenharmony_ci 87113498266Sopenharmony_ci if(got_exit_signal) { 87213498266Sopenharmony_ci logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)", 87313498266Sopenharmony_ci ipv_inuse, (int)port, (long)getpid(), exit_signal); 87413498266Sopenharmony_ci /* 87513498266Sopenharmony_ci * To properly set the return status of the process we 87613498266Sopenharmony_ci * must raise the same signal SIGINT or SIGTERM that we 87713498266Sopenharmony_ci * caught and let the old handler take care of it. 87813498266Sopenharmony_ci */ 87913498266Sopenharmony_ci raise(exit_signal); 88013498266Sopenharmony_ci } 88113498266Sopenharmony_ci 88213498266Sopenharmony_ci logmsg("========> tftpd quits"); 88313498266Sopenharmony_ci return result; 88413498266Sopenharmony_ci} 88513498266Sopenharmony_ci 88613498266Sopenharmony_ci/* 88713498266Sopenharmony_ci * Handle initial connection protocol. 88813498266Sopenharmony_ci */ 88913498266Sopenharmony_cistatic int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) 89013498266Sopenharmony_ci{ 89113498266Sopenharmony_ci char *cp; 89213498266Sopenharmony_ci int first = 1, ecode; 89313498266Sopenharmony_ci const struct formats *pf; 89413498266Sopenharmony_ci char *filename, *mode = NULL; 89513498266Sopenharmony_ci#ifdef USE_WINSOCK 89613498266Sopenharmony_ci DWORD recvtimeout, recvtimeoutbak; 89713498266Sopenharmony_ci#endif 89813498266Sopenharmony_ci const char *option = "mode"; /* mode is implicit */ 89913498266Sopenharmony_ci int toggle = 1; 90013498266Sopenharmony_ci FILE *server; 90113498266Sopenharmony_ci char dumpfile[256]; 90213498266Sopenharmony_ci 90313498266Sopenharmony_ci msnprintf(dumpfile, sizeof(dumpfile), "%s/%s", logdir, REQUEST_DUMP); 90413498266Sopenharmony_ci 90513498266Sopenharmony_ci /* Open request dump file. */ 90613498266Sopenharmony_ci server = fopen(dumpfile, "ab"); 90713498266Sopenharmony_ci if(!server) { 90813498266Sopenharmony_ci int error = errno; 90913498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 91013498266Sopenharmony_ci logmsg("Error opening file: %s", dumpfile); 91113498266Sopenharmony_ci return -1; 91213498266Sopenharmony_ci } 91313498266Sopenharmony_ci 91413498266Sopenharmony_ci /* store input protocol */ 91513498266Sopenharmony_ci fprintf(server, "opcode = %x\n", tp->th_opcode); 91613498266Sopenharmony_ci 91713498266Sopenharmony_ci cp = (char *)&tp->th_stuff; 91813498266Sopenharmony_ci filename = cp; 91913498266Sopenharmony_ci do { 92013498266Sopenharmony_ci bool endofit = true; 92113498266Sopenharmony_ci while(cp < &buf.storage[size]) { 92213498266Sopenharmony_ci if(*cp == '\0') { 92313498266Sopenharmony_ci endofit = false; 92413498266Sopenharmony_ci break; 92513498266Sopenharmony_ci } 92613498266Sopenharmony_ci cp++; 92713498266Sopenharmony_ci } 92813498266Sopenharmony_ci if(endofit) 92913498266Sopenharmony_ci /* no more options */ 93013498266Sopenharmony_ci break; 93113498266Sopenharmony_ci 93213498266Sopenharmony_ci /* before increasing pointer, make sure it is still within the legal 93313498266Sopenharmony_ci space */ 93413498266Sopenharmony_ci if((cp + 1) < &buf.storage[size]) { 93513498266Sopenharmony_ci ++cp; 93613498266Sopenharmony_ci if(first) { 93713498266Sopenharmony_ci /* store the mode since we need it later */ 93813498266Sopenharmony_ci mode = cp; 93913498266Sopenharmony_ci first = 0; 94013498266Sopenharmony_ci } 94113498266Sopenharmony_ci if(toggle) 94213498266Sopenharmony_ci /* name/value pair: */ 94313498266Sopenharmony_ci fprintf(server, "%s = %s\n", option, cp); 94413498266Sopenharmony_ci else { 94513498266Sopenharmony_ci /* store the name pointer */ 94613498266Sopenharmony_ci option = cp; 94713498266Sopenharmony_ci } 94813498266Sopenharmony_ci toggle ^= 1; 94913498266Sopenharmony_ci } 95013498266Sopenharmony_ci else 95113498266Sopenharmony_ci /* No more options */ 95213498266Sopenharmony_ci break; 95313498266Sopenharmony_ci } while(1); 95413498266Sopenharmony_ci 95513498266Sopenharmony_ci if(*cp) { 95613498266Sopenharmony_ci nak(EBADOP); 95713498266Sopenharmony_ci fclose(server); 95813498266Sopenharmony_ci return 3; 95913498266Sopenharmony_ci } 96013498266Sopenharmony_ci 96113498266Sopenharmony_ci /* store input protocol */ 96213498266Sopenharmony_ci fprintf(server, "filename = %s\n", filename); 96313498266Sopenharmony_ci 96413498266Sopenharmony_ci for(cp = mode; cp && *cp; cp++) 96513498266Sopenharmony_ci if(ISUPPER(*cp)) 96613498266Sopenharmony_ci *cp = (char)tolower((int)*cp); 96713498266Sopenharmony_ci 96813498266Sopenharmony_ci /* store input protocol */ 96913498266Sopenharmony_ci fclose(server); 97013498266Sopenharmony_ci 97113498266Sopenharmony_ci for(pf = formata; pf->f_mode; pf++) 97213498266Sopenharmony_ci if(strcmp(pf->f_mode, mode) == 0) 97313498266Sopenharmony_ci break; 97413498266Sopenharmony_ci if(!pf->f_mode) { 97513498266Sopenharmony_ci nak(EBADOP); 97613498266Sopenharmony_ci return 2; 97713498266Sopenharmony_ci } 97813498266Sopenharmony_ci ecode = validate_access(test, filename, tp->th_opcode); 97913498266Sopenharmony_ci if(ecode) { 98013498266Sopenharmony_ci nak(ecode); 98113498266Sopenharmony_ci return 1; 98213498266Sopenharmony_ci } 98313498266Sopenharmony_ci 98413498266Sopenharmony_ci#ifdef USE_WINSOCK 98513498266Sopenharmony_ci recvtimeout = sizeof(recvtimeoutbak); 98613498266Sopenharmony_ci getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 98713498266Sopenharmony_ci (char *)&recvtimeoutbak, (int *)&recvtimeout); 98813498266Sopenharmony_ci recvtimeout = TIMEOUT*1000; 98913498266Sopenharmony_ci setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 99013498266Sopenharmony_ci (const char *)&recvtimeout, sizeof(recvtimeout)); 99113498266Sopenharmony_ci#endif 99213498266Sopenharmony_ci 99313498266Sopenharmony_ci if(tp->th_opcode == opcode_WRQ) 99413498266Sopenharmony_ci recvtftp(test, pf); 99513498266Sopenharmony_ci else 99613498266Sopenharmony_ci sendtftp(test, pf); 99713498266Sopenharmony_ci 99813498266Sopenharmony_ci#ifdef USE_WINSOCK 99913498266Sopenharmony_ci recvtimeout = recvtimeoutbak; 100013498266Sopenharmony_ci setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 100113498266Sopenharmony_ci (const char *)&recvtimeout, sizeof(recvtimeout)); 100213498266Sopenharmony_ci#endif 100313498266Sopenharmony_ci 100413498266Sopenharmony_ci return 0; 100513498266Sopenharmony_ci} 100613498266Sopenharmony_ci 100713498266Sopenharmony_ci/* Based on the testno, parse the correct server commands. */ 100813498266Sopenharmony_cistatic int parse_servercmd(struct testcase *req) 100913498266Sopenharmony_ci{ 101013498266Sopenharmony_ci FILE *stream; 101113498266Sopenharmony_ci int error; 101213498266Sopenharmony_ci 101313498266Sopenharmony_ci stream = test2fopen(req->testno, logdir); 101413498266Sopenharmony_ci if(!stream) { 101513498266Sopenharmony_ci error = errno; 101613498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 101713498266Sopenharmony_ci logmsg(" Couldn't open test file %ld", req->testno); 101813498266Sopenharmony_ci return 1; /* done */ 101913498266Sopenharmony_ci } 102013498266Sopenharmony_ci else { 102113498266Sopenharmony_ci char *orgcmd = NULL; 102213498266Sopenharmony_ci char *cmd = NULL; 102313498266Sopenharmony_ci size_t cmdsize = 0; 102413498266Sopenharmony_ci int num = 0; 102513498266Sopenharmony_ci 102613498266Sopenharmony_ci /* get the custom server control "commands" */ 102713498266Sopenharmony_ci error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream); 102813498266Sopenharmony_ci fclose(stream); 102913498266Sopenharmony_ci if(error) { 103013498266Sopenharmony_ci logmsg("getpart() failed with error: %d", error); 103113498266Sopenharmony_ci return 1; /* done */ 103213498266Sopenharmony_ci } 103313498266Sopenharmony_ci 103413498266Sopenharmony_ci cmd = orgcmd; 103513498266Sopenharmony_ci while(cmd && cmdsize) { 103613498266Sopenharmony_ci char *check; 103713498266Sopenharmony_ci if(1 == sscanf(cmd, "writedelay: %d", &num)) { 103813498266Sopenharmony_ci logmsg("instructed to delay %d secs between packets", num); 103913498266Sopenharmony_ci req->writedelay = num; 104013498266Sopenharmony_ci } 104113498266Sopenharmony_ci else { 104213498266Sopenharmony_ci logmsg("Unknown <servercmd> instruction found: %s", cmd); 104313498266Sopenharmony_ci } 104413498266Sopenharmony_ci /* try to deal with CRLF or just LF */ 104513498266Sopenharmony_ci check = strchr(cmd, '\r'); 104613498266Sopenharmony_ci if(!check) 104713498266Sopenharmony_ci check = strchr(cmd, '\n'); 104813498266Sopenharmony_ci 104913498266Sopenharmony_ci if(check) { 105013498266Sopenharmony_ci /* get to the letter following the newline */ 105113498266Sopenharmony_ci while((*check == '\r') || (*check == '\n')) 105213498266Sopenharmony_ci check++; 105313498266Sopenharmony_ci 105413498266Sopenharmony_ci if(!*check) 105513498266Sopenharmony_ci /* if we reached a zero, get out */ 105613498266Sopenharmony_ci break; 105713498266Sopenharmony_ci cmd = check; 105813498266Sopenharmony_ci } 105913498266Sopenharmony_ci else 106013498266Sopenharmony_ci break; 106113498266Sopenharmony_ci } 106213498266Sopenharmony_ci free(orgcmd); 106313498266Sopenharmony_ci } 106413498266Sopenharmony_ci 106513498266Sopenharmony_ci return 0; /* OK! */ 106613498266Sopenharmony_ci} 106713498266Sopenharmony_ci 106813498266Sopenharmony_ci 106913498266Sopenharmony_ci/* 107013498266Sopenharmony_ci * Validate file access. 107113498266Sopenharmony_ci */ 107213498266Sopenharmony_cistatic int validate_access(struct testcase *test, 107313498266Sopenharmony_ci const char *filename, int mode) 107413498266Sopenharmony_ci{ 107513498266Sopenharmony_ci char *ptr; 107613498266Sopenharmony_ci 107713498266Sopenharmony_ci logmsg("trying to get file: %s mode %x", filename, mode); 107813498266Sopenharmony_ci 107913498266Sopenharmony_ci if(!strncmp("verifiedserver", filename, 14)) { 108013498266Sopenharmony_ci char weare[128]; 108113498266Sopenharmony_ci size_t count = msnprintf(weare, sizeof(weare), "WE ROOLZ: %" 108213498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T "\r\n", our_getpid()); 108313498266Sopenharmony_ci 108413498266Sopenharmony_ci logmsg("Are-we-friendly question received"); 108513498266Sopenharmony_ci test->buffer = strdup(weare); 108613498266Sopenharmony_ci test->rptr = test->buffer; /* set read pointer */ 108713498266Sopenharmony_ci test->bufsize = count; /* set total count */ 108813498266Sopenharmony_ci test->rcount = count; /* set data left to read */ 108913498266Sopenharmony_ci return 0; /* fine */ 109013498266Sopenharmony_ci } 109113498266Sopenharmony_ci 109213498266Sopenharmony_ci /* find the last slash */ 109313498266Sopenharmony_ci ptr = strrchr(filename, '/'); 109413498266Sopenharmony_ci 109513498266Sopenharmony_ci if(ptr) { 109613498266Sopenharmony_ci char partbuf[80]="data"; 109713498266Sopenharmony_ci long partno; 109813498266Sopenharmony_ci long testno; 109913498266Sopenharmony_ci FILE *stream; 110013498266Sopenharmony_ci 110113498266Sopenharmony_ci ptr++; /* skip the slash */ 110213498266Sopenharmony_ci 110313498266Sopenharmony_ci /* skip all non-numericals following the slash */ 110413498266Sopenharmony_ci while(*ptr && !ISDIGIT(*ptr)) 110513498266Sopenharmony_ci ptr++; 110613498266Sopenharmony_ci 110713498266Sopenharmony_ci /* get the number */ 110813498266Sopenharmony_ci testno = strtol(ptr, &ptr, 10); 110913498266Sopenharmony_ci 111013498266Sopenharmony_ci if(testno > 10000) { 111113498266Sopenharmony_ci partno = testno % 10000; 111213498266Sopenharmony_ci testno /= 10000; 111313498266Sopenharmony_ci } 111413498266Sopenharmony_ci else 111513498266Sopenharmony_ci partno = 0; 111613498266Sopenharmony_ci 111713498266Sopenharmony_ci 111813498266Sopenharmony_ci logmsg("requested test number %ld part %ld", testno, partno); 111913498266Sopenharmony_ci 112013498266Sopenharmony_ci test->testno = testno; 112113498266Sopenharmony_ci 112213498266Sopenharmony_ci (void)parse_servercmd(test); 112313498266Sopenharmony_ci 112413498266Sopenharmony_ci stream = test2fopen(testno, logdir); 112513498266Sopenharmony_ci 112613498266Sopenharmony_ci if(0 != partno) 112713498266Sopenharmony_ci msnprintf(partbuf, sizeof(partbuf), "data%ld", partno); 112813498266Sopenharmony_ci 112913498266Sopenharmony_ci if(!stream) { 113013498266Sopenharmony_ci int error = errno; 113113498266Sopenharmony_ci logmsg("fopen() failed with error: %d %s", error, strerror(error)); 113213498266Sopenharmony_ci logmsg("Couldn't open test file for test: %ld", testno); 113313498266Sopenharmony_ci return EACCESS; 113413498266Sopenharmony_ci } 113513498266Sopenharmony_ci else { 113613498266Sopenharmony_ci size_t count; 113713498266Sopenharmony_ci int error = getpart(&test->buffer, &count, "reply", partbuf, stream); 113813498266Sopenharmony_ci fclose(stream); 113913498266Sopenharmony_ci if(error) { 114013498266Sopenharmony_ci logmsg("getpart() failed with error: %d", error); 114113498266Sopenharmony_ci return EACCESS; 114213498266Sopenharmony_ci } 114313498266Sopenharmony_ci if(test->buffer) { 114413498266Sopenharmony_ci test->rptr = test->buffer; /* set read pointer */ 114513498266Sopenharmony_ci test->bufsize = count; /* set total count */ 114613498266Sopenharmony_ci test->rcount = count; /* set data left to read */ 114713498266Sopenharmony_ci } 114813498266Sopenharmony_ci else 114913498266Sopenharmony_ci return EACCESS; 115013498266Sopenharmony_ci } 115113498266Sopenharmony_ci } 115213498266Sopenharmony_ci else { 115313498266Sopenharmony_ci logmsg("no slash found in path"); 115413498266Sopenharmony_ci return EACCESS; /* failure */ 115513498266Sopenharmony_ci } 115613498266Sopenharmony_ci 115713498266Sopenharmony_ci logmsg("file opened and all is good"); 115813498266Sopenharmony_ci return 0; 115913498266Sopenharmony_ci} 116013498266Sopenharmony_ci 116113498266Sopenharmony_ci/* 116213498266Sopenharmony_ci * Send the requested file. 116313498266Sopenharmony_ci */ 116413498266Sopenharmony_cistatic void sendtftp(struct testcase *test, const struct formats *pf) 116513498266Sopenharmony_ci{ 116613498266Sopenharmony_ci int size; 116713498266Sopenharmony_ci ssize_t n; 116813498266Sopenharmony_ci /* These are volatile to live through a siglongjmp */ 116913498266Sopenharmony_ci volatile unsigned short sendblock; /* block count */ 117013498266Sopenharmony_ci struct tftphdr * volatile sdp = r_init(); /* data buffer */ 117113498266Sopenharmony_ci struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */ 117213498266Sopenharmony_ci 117313498266Sopenharmony_ci sendblock = 1; 117413498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 117513498266Sopenharmony_ci mysignal(SIGALRM, timer); 117613498266Sopenharmony_ci#endif 117713498266Sopenharmony_ci do { 117813498266Sopenharmony_ci size = readit(test, (struct tftphdr **)&sdp, pf->f_convert); 117913498266Sopenharmony_ci if(size < 0) { 118013498266Sopenharmony_ci nak(errno + 100); 118113498266Sopenharmony_ci return; 118213498266Sopenharmony_ci } 118313498266Sopenharmony_ci sdp->th_opcode = htons((unsigned short)opcode_DATA); 118413498266Sopenharmony_ci sdp->th_block = htons(sendblock); 118513498266Sopenharmony_ci timeout = 0; 118613498266Sopenharmony_ci#ifdef HAVE_SIGSETJMP 118713498266Sopenharmony_ci (void) sigsetjmp(timeoutbuf, 1); 118813498266Sopenharmony_ci#endif 118913498266Sopenharmony_ci if(test->writedelay) { 119013498266Sopenharmony_ci logmsg("Pausing %d seconds before %d bytes", test->writedelay, 119113498266Sopenharmony_ci size); 119213498266Sopenharmony_ci wait_ms(1000*test->writedelay); 119313498266Sopenharmony_ci } 119413498266Sopenharmony_ci 119513498266Sopenharmony_cisend_data: 119613498266Sopenharmony_ci logmsg("write"); 119713498266Sopenharmony_ci if(swrite(peer, sdp, size + 4) != size + 4) { 119813498266Sopenharmony_ci logmsg("write: fail"); 119913498266Sopenharmony_ci return; 120013498266Sopenharmony_ci } 120113498266Sopenharmony_ci read_ahead(test, pf->f_convert); 120213498266Sopenharmony_ci for(;;) { 120313498266Sopenharmony_ci#ifdef HAVE_ALARM 120413498266Sopenharmony_ci alarm(rexmtval); /* read the ack */ 120513498266Sopenharmony_ci#endif 120613498266Sopenharmony_ci logmsg("read"); 120713498266Sopenharmony_ci n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage)); 120813498266Sopenharmony_ci logmsg("read: %zd", n); 120913498266Sopenharmony_ci#ifdef HAVE_ALARM 121013498266Sopenharmony_ci alarm(0); 121113498266Sopenharmony_ci#endif 121213498266Sopenharmony_ci if(got_exit_signal) 121313498266Sopenharmony_ci return; 121413498266Sopenharmony_ci if(n < 0) { 121513498266Sopenharmony_ci logmsg("read: fail"); 121613498266Sopenharmony_ci return; 121713498266Sopenharmony_ci } 121813498266Sopenharmony_ci sap->th_opcode = ntohs((unsigned short)sap->th_opcode); 121913498266Sopenharmony_ci sap->th_block = ntohs(sap->th_block); 122013498266Sopenharmony_ci 122113498266Sopenharmony_ci if(sap->th_opcode == opcode_ERROR) { 122213498266Sopenharmony_ci logmsg("got ERROR"); 122313498266Sopenharmony_ci return; 122413498266Sopenharmony_ci } 122513498266Sopenharmony_ci 122613498266Sopenharmony_ci if(sap->th_opcode == opcode_ACK) { 122713498266Sopenharmony_ci if(sap->th_block == sendblock) { 122813498266Sopenharmony_ci break; 122913498266Sopenharmony_ci } 123013498266Sopenharmony_ci /* Re-synchronize with the other side */ 123113498266Sopenharmony_ci (void) synchnet(peer); 123213498266Sopenharmony_ci if(sap->th_block == (sendblock-1)) { 123313498266Sopenharmony_ci goto send_data; 123413498266Sopenharmony_ci } 123513498266Sopenharmony_ci } 123613498266Sopenharmony_ci 123713498266Sopenharmony_ci } 123813498266Sopenharmony_ci sendblock++; 123913498266Sopenharmony_ci } while(size == SEGSIZE); 124013498266Sopenharmony_ci} 124113498266Sopenharmony_ci 124213498266Sopenharmony_ci/* 124313498266Sopenharmony_ci * Receive a file. 124413498266Sopenharmony_ci */ 124513498266Sopenharmony_cistatic void recvtftp(struct testcase *test, const struct formats *pf) 124613498266Sopenharmony_ci{ 124713498266Sopenharmony_ci ssize_t n, size; 124813498266Sopenharmony_ci /* These are volatile to live through a siglongjmp */ 124913498266Sopenharmony_ci volatile unsigned short recvblock; /* block count */ 125013498266Sopenharmony_ci struct tftphdr * volatile rdp; /* data buffer */ 125113498266Sopenharmony_ci struct tftphdr *rap; /* ack buffer */ 125213498266Sopenharmony_ci 125313498266Sopenharmony_ci recvblock = 0; 125413498266Sopenharmony_ci rdp = w_init(); 125513498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 125613498266Sopenharmony_ci mysignal(SIGALRM, timer); 125713498266Sopenharmony_ci#endif 125813498266Sopenharmony_ci rap = &ackbuf.hdr; 125913498266Sopenharmony_ci do { 126013498266Sopenharmony_ci timeout = 0; 126113498266Sopenharmony_ci rap->th_opcode = htons((unsigned short)opcode_ACK); 126213498266Sopenharmony_ci rap->th_block = htons(recvblock); 126313498266Sopenharmony_ci recvblock++; 126413498266Sopenharmony_ci#ifdef HAVE_SIGSETJMP 126513498266Sopenharmony_ci (void) sigsetjmp(timeoutbuf, 1); 126613498266Sopenharmony_ci#endif 126713498266Sopenharmony_cisend_ack: 126813498266Sopenharmony_ci logmsg("write"); 126913498266Sopenharmony_ci if(swrite(peer, &ackbuf.storage[0], 4) != 4) { 127013498266Sopenharmony_ci logmsg("write: fail"); 127113498266Sopenharmony_ci goto abort; 127213498266Sopenharmony_ci } 127313498266Sopenharmony_ci write_behind(test, pf->f_convert); 127413498266Sopenharmony_ci for(;;) { 127513498266Sopenharmony_ci#ifdef HAVE_ALARM 127613498266Sopenharmony_ci alarm(rexmtval); 127713498266Sopenharmony_ci#endif 127813498266Sopenharmony_ci logmsg("read"); 127913498266Sopenharmony_ci n = sread(peer, rdp, PKTSIZE); 128013498266Sopenharmony_ci logmsg("read: %zd", n); 128113498266Sopenharmony_ci#ifdef HAVE_ALARM 128213498266Sopenharmony_ci alarm(0); 128313498266Sopenharmony_ci#endif 128413498266Sopenharmony_ci if(got_exit_signal) 128513498266Sopenharmony_ci goto abort; 128613498266Sopenharmony_ci if(n < 0) { /* really? */ 128713498266Sopenharmony_ci logmsg("read: fail"); 128813498266Sopenharmony_ci goto abort; 128913498266Sopenharmony_ci } 129013498266Sopenharmony_ci rdp->th_opcode = ntohs((unsigned short)rdp->th_opcode); 129113498266Sopenharmony_ci rdp->th_block = ntohs(rdp->th_block); 129213498266Sopenharmony_ci if(rdp->th_opcode == opcode_ERROR) 129313498266Sopenharmony_ci goto abort; 129413498266Sopenharmony_ci if(rdp->th_opcode == opcode_DATA) { 129513498266Sopenharmony_ci if(rdp->th_block == recvblock) { 129613498266Sopenharmony_ci break; /* normal */ 129713498266Sopenharmony_ci } 129813498266Sopenharmony_ci /* Re-synchronize with the other side */ 129913498266Sopenharmony_ci (void) synchnet(peer); 130013498266Sopenharmony_ci if(rdp->th_block == (recvblock-1)) 130113498266Sopenharmony_ci goto send_ack; /* rexmit */ 130213498266Sopenharmony_ci } 130313498266Sopenharmony_ci } 130413498266Sopenharmony_ci 130513498266Sopenharmony_ci size = writeit(test, &rdp, (int)(n - 4), pf->f_convert); 130613498266Sopenharmony_ci if(size != (n-4)) { /* ahem */ 130713498266Sopenharmony_ci if(size < 0) 130813498266Sopenharmony_ci nak(errno + 100); 130913498266Sopenharmony_ci else 131013498266Sopenharmony_ci nak(ENOSPACE); 131113498266Sopenharmony_ci goto abort; 131213498266Sopenharmony_ci } 131313498266Sopenharmony_ci } while(size == SEGSIZE); 131413498266Sopenharmony_ci write_behind(test, pf->f_convert); 131513498266Sopenharmony_ci /* close the output file as early as possible after upload completion */ 131613498266Sopenharmony_ci if(test->ofile > 0) { 131713498266Sopenharmony_ci close(test->ofile); 131813498266Sopenharmony_ci test->ofile = 0; 131913498266Sopenharmony_ci } 132013498266Sopenharmony_ci 132113498266Sopenharmony_ci rap->th_opcode = htons((unsigned short)opcode_ACK); /* send the "final" 132213498266Sopenharmony_ci ack */ 132313498266Sopenharmony_ci rap->th_block = htons(recvblock); 132413498266Sopenharmony_ci (void) swrite(peer, &ackbuf.storage[0], 4); 132513498266Sopenharmony_ci#if defined(HAVE_ALARM) && defined(SIGALRM) 132613498266Sopenharmony_ci mysignal(SIGALRM, justtimeout); /* just abort read on timeout */ 132713498266Sopenharmony_ci alarm(rexmtval); 132813498266Sopenharmony_ci#endif 132913498266Sopenharmony_ci /* normally times out and quits */ 133013498266Sopenharmony_ci n = sread(peer, &buf.storage[0], sizeof(buf.storage)); 133113498266Sopenharmony_ci#ifdef HAVE_ALARM 133213498266Sopenharmony_ci alarm(0); 133313498266Sopenharmony_ci#endif 133413498266Sopenharmony_ci if(got_exit_signal) 133513498266Sopenharmony_ci goto abort; 133613498266Sopenharmony_ci if(n >= 4 && /* if read some data */ 133713498266Sopenharmony_ci rdp->th_opcode == opcode_DATA && /* and got a data block */ 133813498266Sopenharmony_ci recvblock == rdp->th_block) { /* then my last ack was lost */ 133913498266Sopenharmony_ci (void) swrite(peer, &ackbuf.storage[0], 4); /* resend final ack */ 134013498266Sopenharmony_ci } 134113498266Sopenharmony_ciabort: 134213498266Sopenharmony_ci /* make sure the output file is closed in case of abort */ 134313498266Sopenharmony_ci if(test->ofile > 0) { 134413498266Sopenharmony_ci close(test->ofile); 134513498266Sopenharmony_ci test->ofile = 0; 134613498266Sopenharmony_ci } 134713498266Sopenharmony_ci return; 134813498266Sopenharmony_ci} 134913498266Sopenharmony_ci 135013498266Sopenharmony_ci/* 135113498266Sopenharmony_ci * Send a nak packet (error message). Error code passed in is one of the 135213498266Sopenharmony_ci * standard TFTP codes, or a Unix errno offset by 100. 135313498266Sopenharmony_ci */ 135413498266Sopenharmony_cistatic void nak(int error) 135513498266Sopenharmony_ci{ 135613498266Sopenharmony_ci struct tftphdr *tp; 135713498266Sopenharmony_ci int length; 135813498266Sopenharmony_ci struct errmsg *pe; 135913498266Sopenharmony_ci 136013498266Sopenharmony_ci tp = &buf.hdr; 136113498266Sopenharmony_ci tp->th_opcode = htons((unsigned short)opcode_ERROR); 136213498266Sopenharmony_ci tp->th_code = htons((unsigned short)error); 136313498266Sopenharmony_ci for(pe = errmsgs; pe->e_code >= 0; pe++) 136413498266Sopenharmony_ci if(pe->e_code == error) 136513498266Sopenharmony_ci break; 136613498266Sopenharmony_ci if(pe->e_code < 0) { 136713498266Sopenharmony_ci pe->e_msg = strerror(error - 100); 136813498266Sopenharmony_ci tp->th_code = EUNDEF; /* set 'undef' errorcode */ 136913498266Sopenharmony_ci } 137013498266Sopenharmony_ci length = (int)strlen(pe->e_msg); 137113498266Sopenharmony_ci 137213498266Sopenharmony_ci /* we use memcpy() instead of strcpy() in order to avoid buffer overflow 137313498266Sopenharmony_ci * report from glibc with FORTIFY_SOURCE */ 137413498266Sopenharmony_ci memcpy(tp->th_msg, pe->e_msg, length + 1); 137513498266Sopenharmony_ci length += 5; 137613498266Sopenharmony_ci if(swrite(peer, &buf.storage[0], length) != length) 137713498266Sopenharmony_ci logmsg("nak: fail\n"); 137813498266Sopenharmony_ci} 1379