xref: /aosp_15_r20/external/curl/lib/tftp.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_TFTP
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
30*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
31*6236dae4SAndroid Build Coastguard Worker #endif
32*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
33*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
34*6236dae4SAndroid Build Coastguard Worker #endif
35*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
36*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NET_IF_H
39*6236dae4SAndroid Build Coastguard Worker #include <net/if.h>
40*6236dae4SAndroid Build Coastguard Worker #endif
41*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_IOCTL_H
42*6236dae4SAndroid Build Coastguard Worker #include <sys/ioctl.h>
43*6236dae4SAndroid Build Coastguard Worker #endif
44*6236dae4SAndroid Build Coastguard Worker 
45*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_PARAM_H
46*6236dae4SAndroid Build Coastguard Worker #include <sys/param.h>
47*6236dae4SAndroid Build Coastguard Worker #endif
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
50*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
51*6236dae4SAndroid Build Coastguard Worker #include "cf-socket.h"
52*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
53*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
54*6236dae4SAndroid Build Coastguard Worker #include "tftp.h"
55*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
56*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
57*6236dae4SAndroid Build Coastguard Worker #include "strerror.h"
58*6236dae4SAndroid Build Coastguard Worker #include "sockaddr.h" /* required for Curl_sockaddr_storage */
59*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
60*6236dae4SAndroid Build Coastguard Worker #include "url.h"
61*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
62*6236dae4SAndroid Build Coastguard Worker #include "speedcheck.h"
63*6236dae4SAndroid Build Coastguard Worker #include "select.h"
64*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
65*6236dae4SAndroid Build Coastguard Worker 
66*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
67*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
68*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
69*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
70*6236dae4SAndroid Build Coastguard Worker 
71*6236dae4SAndroid Build Coastguard Worker /* RFC2348 allows the block size to be negotiated */
72*6236dae4SAndroid Build Coastguard Worker #define TFTP_BLKSIZE_DEFAULT 512
73*6236dae4SAndroid Build Coastguard Worker #define TFTP_OPTION_BLKSIZE "blksize"
74*6236dae4SAndroid Build Coastguard Worker 
75*6236dae4SAndroid Build Coastguard Worker /* from RFC2349: */
76*6236dae4SAndroid Build Coastguard Worker #define TFTP_OPTION_TSIZE    "tsize"
77*6236dae4SAndroid Build Coastguard Worker #define TFTP_OPTION_INTERVAL "timeout"
78*6236dae4SAndroid Build Coastguard Worker 
79*6236dae4SAndroid Build Coastguard Worker typedef enum {
80*6236dae4SAndroid Build Coastguard Worker   TFTP_MODE_NETASCII = 0,
81*6236dae4SAndroid Build Coastguard Worker   TFTP_MODE_OCTET
82*6236dae4SAndroid Build Coastguard Worker } tftp_mode_t;
83*6236dae4SAndroid Build Coastguard Worker 
84*6236dae4SAndroid Build Coastguard Worker typedef enum {
85*6236dae4SAndroid Build Coastguard Worker   TFTP_STATE_START = 0,
86*6236dae4SAndroid Build Coastguard Worker   TFTP_STATE_RX,
87*6236dae4SAndroid Build Coastguard Worker   TFTP_STATE_TX,
88*6236dae4SAndroid Build Coastguard Worker   TFTP_STATE_FIN
89*6236dae4SAndroid Build Coastguard Worker } tftp_state_t;
90*6236dae4SAndroid Build Coastguard Worker 
91*6236dae4SAndroid Build Coastguard Worker typedef enum {
92*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_NONE = -1,
93*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_INIT = 0,
94*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_RRQ = 1,
95*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_WRQ = 2,
96*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_DATA = 3,
97*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_ACK = 4,
98*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_ERROR = 5,
99*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_OACK = 6,
100*6236dae4SAndroid Build Coastguard Worker   TFTP_EVENT_TIMEOUT
101*6236dae4SAndroid Build Coastguard Worker } tftp_event_t;
102*6236dae4SAndroid Build Coastguard Worker 
103*6236dae4SAndroid Build Coastguard Worker typedef enum {
104*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_UNDEF = 0,
105*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_NOTFOUND,
106*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_PERM,
107*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_DISKFULL,
108*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_ILLEGAL,
109*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_UNKNOWNID,
110*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_EXISTS,
111*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
112*6236dae4SAndroid Build Coastguard Worker 
113*6236dae4SAndroid Build Coastguard Worker   /* The remaining error codes are internal to curl */
114*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_NONE = -100,
115*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_TIMEOUT,
116*6236dae4SAndroid Build Coastguard Worker   TFTP_ERR_NORESPONSE
117*6236dae4SAndroid Build Coastguard Worker } tftp_error_t;
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker struct tftp_packet {
120*6236dae4SAndroid Build Coastguard Worker   unsigned char *data;
121*6236dae4SAndroid Build Coastguard Worker };
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker struct tftp_state_data {
124*6236dae4SAndroid Build Coastguard Worker   tftp_state_t    state;
125*6236dae4SAndroid Build Coastguard Worker   tftp_mode_t     mode;
126*6236dae4SAndroid Build Coastguard Worker   tftp_error_t    error;
127*6236dae4SAndroid Build Coastguard Worker   tftp_event_t    event;
128*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data;
129*6236dae4SAndroid Build Coastguard Worker   curl_socket_t   sockfd;
130*6236dae4SAndroid Build Coastguard Worker   int             retries;
131*6236dae4SAndroid Build Coastguard Worker   int             retry_time;
132*6236dae4SAndroid Build Coastguard Worker   int             retry_max;
133*6236dae4SAndroid Build Coastguard Worker   time_t          rx_time;
134*6236dae4SAndroid Build Coastguard Worker   struct Curl_sockaddr_storage   local_addr;
135*6236dae4SAndroid Build Coastguard Worker   struct Curl_sockaddr_storage   remote_addr;
136*6236dae4SAndroid Build Coastguard Worker   curl_socklen_t  remote_addrlen;
137*6236dae4SAndroid Build Coastguard Worker   int             rbytes;
138*6236dae4SAndroid Build Coastguard Worker   int             sbytes;
139*6236dae4SAndroid Build Coastguard Worker   int             blksize;
140*6236dae4SAndroid Build Coastguard Worker   int             requested_blksize;
141*6236dae4SAndroid Build Coastguard Worker   unsigned short  block;
142*6236dae4SAndroid Build Coastguard Worker   struct tftp_packet rpacket;
143*6236dae4SAndroid Build Coastguard Worker   struct tftp_packet spacket;
144*6236dae4SAndroid Build Coastguard Worker };
145*6236dae4SAndroid Build Coastguard Worker 
146*6236dae4SAndroid Build Coastguard Worker 
147*6236dae4SAndroid Build Coastguard Worker /* Forward declarations */
148*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
149*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
150*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
151*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_disconnect(struct Curl_easy *data,
152*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn,
153*6236dae4SAndroid Build Coastguard Worker                                 bool dead_connection);
154*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_do(struct Curl_easy *data, bool *done);
155*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_done(struct Curl_easy *data,
156*6236dae4SAndroid Build Coastguard Worker                           CURLcode, bool premature);
157*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_setup_connection(struct Curl_easy *data,
158*6236dae4SAndroid Build Coastguard Worker                                       struct connectdata *conn);
159*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
160*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
161*6236dae4SAndroid Build Coastguard Worker static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
162*6236dae4SAndroid Build Coastguard Worker                         curl_socket_t *socks);
163*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_translate_code(tftp_error_t error);
164*6236dae4SAndroid Build Coastguard Worker 
165*6236dae4SAndroid Build Coastguard Worker 
166*6236dae4SAndroid Build Coastguard Worker /*
167*6236dae4SAndroid Build Coastguard Worker  * TFTP protocol handler.
168*6236dae4SAndroid Build Coastguard Worker  */
169*6236dae4SAndroid Build Coastguard Worker 
170*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_tftp = {
171*6236dae4SAndroid Build Coastguard Worker   "tftp",                               /* scheme */
172*6236dae4SAndroid Build Coastguard Worker   tftp_setup_connection,                /* setup_connection */
173*6236dae4SAndroid Build Coastguard Worker   tftp_do,                              /* do_it */
174*6236dae4SAndroid Build Coastguard Worker   tftp_done,                            /* done */
175*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* do_more */
176*6236dae4SAndroid Build Coastguard Worker   tftp_connect,                         /* connect_it */
177*6236dae4SAndroid Build Coastguard Worker   tftp_multi_statemach,                 /* connecting */
178*6236dae4SAndroid Build Coastguard Worker   tftp_doing,                           /* doing */
179*6236dae4SAndroid Build Coastguard Worker   tftp_getsock,                         /* proto_getsock */
180*6236dae4SAndroid Build Coastguard Worker   tftp_getsock,                         /* doing_getsock */
181*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* domore_getsock */
182*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* perform_getsock */
183*6236dae4SAndroid Build Coastguard Worker   tftp_disconnect,                      /* disconnect */
184*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* write_resp */
185*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* write_resp_hd */
186*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* connection_check */
187*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* attach connection */
188*6236dae4SAndroid Build Coastguard Worker   PORT_TFTP,                            /* defport */
189*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_TFTP,                       /* protocol */
190*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_TFTP,                       /* family */
191*6236dae4SAndroid Build Coastguard Worker   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
192*6236dae4SAndroid Build Coastguard Worker };
193*6236dae4SAndroid Build Coastguard Worker 
194*6236dae4SAndroid Build Coastguard Worker /**********************************************************
195*6236dae4SAndroid Build Coastguard Worker  *
196*6236dae4SAndroid Build Coastguard Worker  * tftp_set_timeouts -
197*6236dae4SAndroid Build Coastguard Worker  *
198*6236dae4SAndroid Build Coastguard Worker  * Set timeouts based on state machine state.
199*6236dae4SAndroid Build Coastguard Worker  * Use user provided connect timeouts until DATA or ACK
200*6236dae4SAndroid Build Coastguard Worker  * packet is received, then use user-provided transfer timeouts
201*6236dae4SAndroid Build Coastguard Worker  *
202*6236dae4SAndroid Build Coastguard Worker  *
203*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_set_timeouts(struct tftp_state_data * state)204*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
205*6236dae4SAndroid Build Coastguard Worker {
206*6236dae4SAndroid Build Coastguard Worker   time_t maxtime, timeout;
207*6236dae4SAndroid Build Coastguard Worker   timediff_t timeout_ms;
208*6236dae4SAndroid Build Coastguard Worker   bool start = (state->state == TFTP_STATE_START);
209*6236dae4SAndroid Build Coastguard Worker 
210*6236dae4SAndroid Build Coastguard Worker   /* Compute drop-dead time */
211*6236dae4SAndroid Build Coastguard Worker   timeout_ms = Curl_timeleft(state->data, NULL, start);
212*6236dae4SAndroid Build Coastguard Worker 
213*6236dae4SAndroid Build Coastguard Worker   if(timeout_ms < 0) {
214*6236dae4SAndroid Build Coastguard Worker     /* time-out, bail out, go home */
215*6236dae4SAndroid Build Coastguard Worker     failf(state->data, "Connection time-out");
216*6236dae4SAndroid Build Coastguard Worker     return CURLE_OPERATION_TIMEDOUT;
217*6236dae4SAndroid Build Coastguard Worker   }
218*6236dae4SAndroid Build Coastguard Worker 
219*6236dae4SAndroid Build Coastguard Worker   if(timeout_ms > 0)
220*6236dae4SAndroid Build Coastguard Worker     maxtime = (time_t)(timeout_ms + 500) / 1000;
221*6236dae4SAndroid Build Coastguard Worker   else
222*6236dae4SAndroid Build Coastguard Worker     maxtime = 3600; /* use for calculating block timeouts */
223*6236dae4SAndroid Build Coastguard Worker 
224*6236dae4SAndroid Build Coastguard Worker   /* Set per-block timeout to total */
225*6236dae4SAndroid Build Coastguard Worker   timeout = maxtime;
226*6236dae4SAndroid Build Coastguard Worker 
227*6236dae4SAndroid Build Coastguard Worker   /* Average reposting an ACK after 5 seconds */
228*6236dae4SAndroid Build Coastguard Worker   state->retry_max = (int)timeout/5;
229*6236dae4SAndroid Build Coastguard Worker 
230*6236dae4SAndroid Build Coastguard Worker   /* But bound the total number */
231*6236dae4SAndroid Build Coastguard Worker   if(state->retry_max < 3)
232*6236dae4SAndroid Build Coastguard Worker     state->retry_max = 3;
233*6236dae4SAndroid Build Coastguard Worker 
234*6236dae4SAndroid Build Coastguard Worker   if(state->retry_max > 50)
235*6236dae4SAndroid Build Coastguard Worker     state->retry_max = 50;
236*6236dae4SAndroid Build Coastguard Worker 
237*6236dae4SAndroid Build Coastguard Worker   /* Compute the re-ACK interval to suit the timeout */
238*6236dae4SAndroid Build Coastguard Worker   state->retry_time = (int)(timeout/state->retry_max);
239*6236dae4SAndroid Build Coastguard Worker   if(state->retry_time < 1)
240*6236dae4SAndroid Build Coastguard Worker     state->retry_time = 1;
241*6236dae4SAndroid Build Coastguard Worker 
242*6236dae4SAndroid Build Coastguard Worker   infof(state->data,
243*6236dae4SAndroid Build Coastguard Worker         "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
244*6236dae4SAndroid Build Coastguard Worker         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker   /* init RX time */
247*6236dae4SAndroid Build Coastguard Worker   state->rx_time = time(NULL);
248*6236dae4SAndroid Build Coastguard Worker 
249*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
250*6236dae4SAndroid Build Coastguard Worker }
251*6236dae4SAndroid Build Coastguard Worker 
252*6236dae4SAndroid Build Coastguard Worker /**********************************************************
253*6236dae4SAndroid Build Coastguard Worker  *
254*6236dae4SAndroid Build Coastguard Worker  * tftp_set_send_first
255*6236dae4SAndroid Build Coastguard Worker  *
256*6236dae4SAndroid Build Coastguard Worker  * Event handler for the START state
257*6236dae4SAndroid Build Coastguard Worker  *
258*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
259*6236dae4SAndroid Build Coastguard Worker 
setpacketevent(struct tftp_packet * packet,unsigned short num)260*6236dae4SAndroid Build Coastguard Worker static void setpacketevent(struct tftp_packet *packet, unsigned short num)
261*6236dae4SAndroid Build Coastguard Worker {
262*6236dae4SAndroid Build Coastguard Worker   packet->data[0] = (unsigned char)(num >> 8);
263*6236dae4SAndroid Build Coastguard Worker   packet->data[1] = (unsigned char)(num & 0xff);
264*6236dae4SAndroid Build Coastguard Worker }
265*6236dae4SAndroid Build Coastguard Worker 
266*6236dae4SAndroid Build Coastguard Worker 
setpacketblock(struct tftp_packet * packet,unsigned short num)267*6236dae4SAndroid Build Coastguard Worker static void setpacketblock(struct tftp_packet *packet, unsigned short num)
268*6236dae4SAndroid Build Coastguard Worker {
269*6236dae4SAndroid Build Coastguard Worker   packet->data[2] = (unsigned char)(num >> 8);
270*6236dae4SAndroid Build Coastguard Worker   packet->data[3] = (unsigned char)(num & 0xff);
271*6236dae4SAndroid Build Coastguard Worker }
272*6236dae4SAndroid Build Coastguard Worker 
getrpacketevent(const struct tftp_packet * packet)273*6236dae4SAndroid Build Coastguard Worker static unsigned short getrpacketevent(const struct tftp_packet *packet)
274*6236dae4SAndroid Build Coastguard Worker {
275*6236dae4SAndroid Build Coastguard Worker   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
276*6236dae4SAndroid Build Coastguard Worker }
277*6236dae4SAndroid Build Coastguard Worker 
getrpacketblock(const struct tftp_packet * packet)278*6236dae4SAndroid Build Coastguard Worker static unsigned short getrpacketblock(const struct tftp_packet *packet)
279*6236dae4SAndroid Build Coastguard Worker {
280*6236dae4SAndroid Build Coastguard Worker   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
281*6236dae4SAndroid Build Coastguard Worker }
282*6236dae4SAndroid Build Coastguard Worker 
tftp_strnlen(const char * string,size_t maxlen)283*6236dae4SAndroid Build Coastguard Worker static size_t tftp_strnlen(const char *string, size_t maxlen)
284*6236dae4SAndroid Build Coastguard Worker {
285*6236dae4SAndroid Build Coastguard Worker   const char *end = memchr(string, '\0', maxlen);
286*6236dae4SAndroid Build Coastguard Worker   return end ? (size_t) (end - string) : maxlen;
287*6236dae4SAndroid Build Coastguard Worker }
288*6236dae4SAndroid Build Coastguard Worker 
tftp_option_get(const char * buf,size_t len,const char ** option,const char ** value)289*6236dae4SAndroid Build Coastguard Worker static const char *tftp_option_get(const char *buf, size_t len,
290*6236dae4SAndroid Build Coastguard Worker                                    const char **option, const char **value)
291*6236dae4SAndroid Build Coastguard Worker {
292*6236dae4SAndroid Build Coastguard Worker   size_t loc;
293*6236dae4SAndroid Build Coastguard Worker 
294*6236dae4SAndroid Build Coastguard Worker   loc = tftp_strnlen(buf, len);
295*6236dae4SAndroid Build Coastguard Worker   loc++; /* NULL term */
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker   if(loc >= len)
298*6236dae4SAndroid Build Coastguard Worker     return NULL;
299*6236dae4SAndroid Build Coastguard Worker   *option = buf;
300*6236dae4SAndroid Build Coastguard Worker 
301*6236dae4SAndroid Build Coastguard Worker   loc += tftp_strnlen(buf + loc, len-loc);
302*6236dae4SAndroid Build Coastguard Worker   loc++; /* NULL term */
303*6236dae4SAndroid Build Coastguard Worker 
304*6236dae4SAndroid Build Coastguard Worker   if(loc > len)
305*6236dae4SAndroid Build Coastguard Worker     return NULL;
306*6236dae4SAndroid Build Coastguard Worker   *value = &buf[strlen(*option) + 1];
307*6236dae4SAndroid Build Coastguard Worker 
308*6236dae4SAndroid Build Coastguard Worker   return &buf[loc];
309*6236dae4SAndroid Build Coastguard Worker }
310*6236dae4SAndroid Build Coastguard Worker 
tftp_parse_option_ack(struct tftp_state_data * state,const char * ptr,int len)311*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
312*6236dae4SAndroid Build Coastguard Worker                                       const char *ptr, int len)
313*6236dae4SAndroid Build Coastguard Worker {
314*6236dae4SAndroid Build Coastguard Worker   const char *tmp = ptr;
315*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
316*6236dae4SAndroid Build Coastguard Worker 
317*6236dae4SAndroid Build Coastguard Worker   /* if OACK does not contain blksize option, the default (512) must be used */
318*6236dae4SAndroid Build Coastguard Worker   state->blksize = TFTP_BLKSIZE_DEFAULT;
319*6236dae4SAndroid Build Coastguard Worker 
320*6236dae4SAndroid Build Coastguard Worker   while(tmp < ptr + len) {
321*6236dae4SAndroid Build Coastguard Worker     const char *option, *value;
322*6236dae4SAndroid Build Coastguard Worker 
323*6236dae4SAndroid Build Coastguard Worker     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
324*6236dae4SAndroid Build Coastguard Worker     if(!tmp) {
325*6236dae4SAndroid Build Coastguard Worker       failf(data, "Malformed ACK packet, rejecting");
326*6236dae4SAndroid Build Coastguard Worker       return CURLE_TFTP_ILLEGAL;
327*6236dae4SAndroid Build Coastguard Worker     }
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker     infof(data, "got option=(%s) value=(%s)", option, value);
330*6236dae4SAndroid Build Coastguard Worker 
331*6236dae4SAndroid Build Coastguard Worker     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
332*6236dae4SAndroid Build Coastguard Worker       long blksize;
333*6236dae4SAndroid Build Coastguard Worker 
334*6236dae4SAndroid Build Coastguard Worker       blksize = strtol(value, NULL, 10);
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker       if(!blksize) {
337*6236dae4SAndroid Build Coastguard Worker         failf(data, "invalid blocksize value in OACK packet");
338*6236dae4SAndroid Build Coastguard Worker         return CURLE_TFTP_ILLEGAL;
339*6236dae4SAndroid Build Coastguard Worker       }
340*6236dae4SAndroid Build Coastguard Worker       if(blksize > TFTP_BLKSIZE_MAX) {
341*6236dae4SAndroid Build Coastguard Worker         failf(data, "%s (%d)", "blksize is larger than max supported",
342*6236dae4SAndroid Build Coastguard Worker               TFTP_BLKSIZE_MAX);
343*6236dae4SAndroid Build Coastguard Worker         return CURLE_TFTP_ILLEGAL;
344*6236dae4SAndroid Build Coastguard Worker       }
345*6236dae4SAndroid Build Coastguard Worker       else if(blksize < TFTP_BLKSIZE_MIN) {
346*6236dae4SAndroid Build Coastguard Worker         failf(data, "%s (%d)", "blksize is smaller than min supported",
347*6236dae4SAndroid Build Coastguard Worker               TFTP_BLKSIZE_MIN);
348*6236dae4SAndroid Build Coastguard Worker         return CURLE_TFTP_ILLEGAL;
349*6236dae4SAndroid Build Coastguard Worker       }
350*6236dae4SAndroid Build Coastguard Worker       else if(blksize > state->requested_blksize) {
351*6236dae4SAndroid Build Coastguard Worker         /* could realloc pkt buffers here, but the spec does not call out
352*6236dae4SAndroid Build Coastguard Worker          * support for the server requesting a bigger blksize than the client
353*6236dae4SAndroid Build Coastguard Worker          * requests */
354*6236dae4SAndroid Build Coastguard Worker         failf(data, "%s (%ld)",
355*6236dae4SAndroid Build Coastguard Worker               "server requested blksize larger than allocated", blksize);
356*6236dae4SAndroid Build Coastguard Worker         return CURLE_TFTP_ILLEGAL;
357*6236dae4SAndroid Build Coastguard Worker       }
358*6236dae4SAndroid Build Coastguard Worker 
359*6236dae4SAndroid Build Coastguard Worker       state->blksize = (int)blksize;
360*6236dae4SAndroid Build Coastguard Worker       infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
361*6236dae4SAndroid Build Coastguard Worker             state->blksize, "requested", state->requested_blksize);
362*6236dae4SAndroid Build Coastguard Worker     }
363*6236dae4SAndroid Build Coastguard Worker     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
364*6236dae4SAndroid Build Coastguard Worker       long tsize = 0;
365*6236dae4SAndroid Build Coastguard Worker 
366*6236dae4SAndroid Build Coastguard Worker       tsize = strtol(value, NULL, 10);
367*6236dae4SAndroid Build Coastguard Worker       infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
368*6236dae4SAndroid Build Coastguard Worker 
369*6236dae4SAndroid Build Coastguard Worker       /* tsize should be ignored on upload: Who cares about the size of the
370*6236dae4SAndroid Build Coastguard Worker          remote file? */
371*6236dae4SAndroid Build Coastguard Worker       if(!data->state.upload) {
372*6236dae4SAndroid Build Coastguard Worker         if(!tsize) {
373*6236dae4SAndroid Build Coastguard Worker           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
374*6236dae4SAndroid Build Coastguard Worker           return CURLE_TFTP_ILLEGAL;
375*6236dae4SAndroid Build Coastguard Worker         }
376*6236dae4SAndroid Build Coastguard Worker         Curl_pgrsSetDownloadSize(data, tsize);
377*6236dae4SAndroid Build Coastguard Worker       }
378*6236dae4SAndroid Build Coastguard Worker     }
379*6236dae4SAndroid Build Coastguard Worker   }
380*6236dae4SAndroid Build Coastguard Worker 
381*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
382*6236dae4SAndroid Build Coastguard Worker }
383*6236dae4SAndroid Build Coastguard Worker 
tftp_option_add(struct tftp_state_data * state,size_t * csize,char * buf,const char * option)384*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
385*6236dae4SAndroid Build Coastguard Worker                                 char *buf, const char *option)
386*6236dae4SAndroid Build Coastguard Worker {
387*6236dae4SAndroid Build Coastguard Worker   if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
388*6236dae4SAndroid Build Coastguard Worker     return CURLE_TFTP_ILLEGAL;
389*6236dae4SAndroid Build Coastguard Worker   strcpy(buf, option);
390*6236dae4SAndroid Build Coastguard Worker   *csize += strlen(option) + 1;
391*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
392*6236dae4SAndroid Build Coastguard Worker }
393*6236dae4SAndroid Build Coastguard Worker 
tftp_connect_for_tx(struct tftp_state_data * state,tftp_event_t event)394*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
395*6236dae4SAndroid Build Coastguard Worker                                     tftp_event_t event)
396*6236dae4SAndroid Build Coastguard Worker {
397*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
398*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
399*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
400*6236dae4SAndroid Build Coastguard Worker 
401*6236dae4SAndroid Build Coastguard Worker   infof(data, "%s", "Connected for transmit");
402*6236dae4SAndroid Build Coastguard Worker #endif
403*6236dae4SAndroid Build Coastguard Worker   state->state = TFTP_STATE_TX;
404*6236dae4SAndroid Build Coastguard Worker   result = tftp_set_timeouts(state);
405*6236dae4SAndroid Build Coastguard Worker   if(result)
406*6236dae4SAndroid Build Coastguard Worker     return result;
407*6236dae4SAndroid Build Coastguard Worker   return tftp_tx(state, event);
408*6236dae4SAndroid Build Coastguard Worker }
409*6236dae4SAndroid Build Coastguard Worker 
tftp_connect_for_rx(struct tftp_state_data * state,tftp_event_t event)410*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
411*6236dae4SAndroid Build Coastguard Worker                                     tftp_event_t event)
412*6236dae4SAndroid Build Coastguard Worker {
413*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
414*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
415*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
416*6236dae4SAndroid Build Coastguard Worker 
417*6236dae4SAndroid Build Coastguard Worker   infof(data, "%s", "Connected for receive");
418*6236dae4SAndroid Build Coastguard Worker #endif
419*6236dae4SAndroid Build Coastguard Worker   state->state = TFTP_STATE_RX;
420*6236dae4SAndroid Build Coastguard Worker   result = tftp_set_timeouts(state);
421*6236dae4SAndroid Build Coastguard Worker   if(result)
422*6236dae4SAndroid Build Coastguard Worker     return result;
423*6236dae4SAndroid Build Coastguard Worker   return tftp_rx(state, event);
424*6236dae4SAndroid Build Coastguard Worker }
425*6236dae4SAndroid Build Coastguard Worker 
tftp_send_first(struct tftp_state_data * state,tftp_event_t event)426*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_send_first(struct tftp_state_data *state,
427*6236dae4SAndroid Build Coastguard Worker                                 tftp_event_t event)
428*6236dae4SAndroid Build Coastguard Worker {
429*6236dae4SAndroid Build Coastguard Worker   size_t sbytes;
430*6236dae4SAndroid Build Coastguard Worker   ssize_t senddata;
431*6236dae4SAndroid Build Coastguard Worker   const char *mode = "octet";
432*6236dae4SAndroid Build Coastguard Worker   char *filename;
433*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
434*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
435*6236dae4SAndroid Build Coastguard Worker 
436*6236dae4SAndroid Build Coastguard Worker   /* Set ASCII mode if -B flag was used */
437*6236dae4SAndroid Build Coastguard Worker   if(data->state.prefer_ascii)
438*6236dae4SAndroid Build Coastguard Worker     mode = "netascii";
439*6236dae4SAndroid Build Coastguard Worker 
440*6236dae4SAndroid Build Coastguard Worker   switch(event) {
441*6236dae4SAndroid Build Coastguard Worker 
442*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_INIT:    /* Send the first packet out */
443*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
444*6236dae4SAndroid Build Coastguard Worker     /* Increment the retry counter, quit if over the limit */
445*6236dae4SAndroid Build Coastguard Worker     state->retries++;
446*6236dae4SAndroid Build Coastguard Worker     if(state->retries > state->retry_max) {
447*6236dae4SAndroid Build Coastguard Worker       state->error = TFTP_ERR_NORESPONSE;
448*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_FIN;
449*6236dae4SAndroid Build Coastguard Worker       return result;
450*6236dae4SAndroid Build Coastguard Worker     }
451*6236dae4SAndroid Build Coastguard Worker 
452*6236dae4SAndroid Build Coastguard Worker     if(data->state.upload) {
453*6236dae4SAndroid Build Coastguard Worker       /* If we are uploading, send an WRQ */
454*6236dae4SAndroid Build Coastguard Worker       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
455*6236dae4SAndroid Build Coastguard Worker       if(data->state.infilesize != -1)
456*6236dae4SAndroid Build Coastguard Worker         Curl_pgrsSetUploadSize(data, data->state.infilesize);
457*6236dae4SAndroid Build Coastguard Worker     }
458*6236dae4SAndroid Build Coastguard Worker     else {
459*6236dae4SAndroid Build Coastguard Worker       /* If we are downloading, send an RRQ */
460*6236dae4SAndroid Build Coastguard Worker       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
461*6236dae4SAndroid Build Coastguard Worker     }
462*6236dae4SAndroid Build Coastguard Worker     /* As RFC3617 describes the separator slash is not actually part of the
463*6236dae4SAndroid Build Coastguard Worker        filename so we skip the always-present first letter of the path
464*6236dae4SAndroid Build Coastguard Worker        string. */
465*6236dae4SAndroid Build Coastguard Worker     result = Curl_urldecode(&state->data->state.up.path[1], 0,
466*6236dae4SAndroid Build Coastguard Worker                             &filename, NULL, REJECT_ZERO);
467*6236dae4SAndroid Build Coastguard Worker     if(result)
468*6236dae4SAndroid Build Coastguard Worker       return result;
469*6236dae4SAndroid Build Coastguard Worker 
470*6236dae4SAndroid Build Coastguard Worker     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
471*6236dae4SAndroid Build Coastguard Worker       failf(data, "TFTP filename too long");
472*6236dae4SAndroid Build Coastguard Worker       free(filename);
473*6236dae4SAndroid Build Coastguard Worker       return CURLE_TFTP_ILLEGAL; /* too long filename field */
474*6236dae4SAndroid Build Coastguard Worker     }
475*6236dae4SAndroid Build Coastguard Worker 
476*6236dae4SAndroid Build Coastguard Worker     msnprintf((char *)state->spacket.data + 2,
477*6236dae4SAndroid Build Coastguard Worker               state->blksize,
478*6236dae4SAndroid Build Coastguard Worker               "%s%c%s%c", filename, '\0',  mode, '\0');
479*6236dae4SAndroid Build Coastguard Worker     sbytes = 4 + strlen(filename) + strlen(mode);
480*6236dae4SAndroid Build Coastguard Worker 
481*6236dae4SAndroid Build Coastguard Worker     /* optional addition of TFTP options */
482*6236dae4SAndroid Build Coastguard Worker     if(!data->set.tftp_no_options) {
483*6236dae4SAndroid Build Coastguard Worker       char buf[64];
484*6236dae4SAndroid Build Coastguard Worker       /* add tsize option */
485*6236dae4SAndroid Build Coastguard Worker       msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
486*6236dae4SAndroid Build Coastguard Worker                 data->state.upload && (data->state.infilesize != -1) ?
487*6236dae4SAndroid Build Coastguard Worker                 data->state.infilesize : 0);
488*6236dae4SAndroid Build Coastguard Worker 
489*6236dae4SAndroid Build Coastguard Worker       result = tftp_option_add(state, &sbytes,
490*6236dae4SAndroid Build Coastguard Worker                                (char *)state->spacket.data + sbytes,
491*6236dae4SAndroid Build Coastguard Worker                                TFTP_OPTION_TSIZE);
492*6236dae4SAndroid Build Coastguard Worker       if(result == CURLE_OK)
493*6236dae4SAndroid Build Coastguard Worker         result = tftp_option_add(state, &sbytes,
494*6236dae4SAndroid Build Coastguard Worker                                  (char *)state->spacket.data + sbytes, buf);
495*6236dae4SAndroid Build Coastguard Worker 
496*6236dae4SAndroid Build Coastguard Worker       /* add blksize option */
497*6236dae4SAndroid Build Coastguard Worker       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
498*6236dae4SAndroid Build Coastguard Worker       if(result == CURLE_OK)
499*6236dae4SAndroid Build Coastguard Worker         result = tftp_option_add(state, &sbytes,
500*6236dae4SAndroid Build Coastguard Worker                                  (char *)state->spacket.data + sbytes,
501*6236dae4SAndroid Build Coastguard Worker                                  TFTP_OPTION_BLKSIZE);
502*6236dae4SAndroid Build Coastguard Worker       if(result == CURLE_OK)
503*6236dae4SAndroid Build Coastguard Worker         result = tftp_option_add(state, &sbytes,
504*6236dae4SAndroid Build Coastguard Worker                                  (char *)state->spacket.data + sbytes, buf);
505*6236dae4SAndroid Build Coastguard Worker 
506*6236dae4SAndroid Build Coastguard Worker       /* add timeout option */
507*6236dae4SAndroid Build Coastguard Worker       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
508*6236dae4SAndroid Build Coastguard Worker       if(result == CURLE_OK)
509*6236dae4SAndroid Build Coastguard Worker         result = tftp_option_add(state, &sbytes,
510*6236dae4SAndroid Build Coastguard Worker                                  (char *)state->spacket.data + sbytes,
511*6236dae4SAndroid Build Coastguard Worker                                  TFTP_OPTION_INTERVAL);
512*6236dae4SAndroid Build Coastguard Worker       if(result == CURLE_OK)
513*6236dae4SAndroid Build Coastguard Worker         result = tftp_option_add(state, &sbytes,
514*6236dae4SAndroid Build Coastguard Worker                                  (char *)state->spacket.data + sbytes, buf);
515*6236dae4SAndroid Build Coastguard Worker 
516*6236dae4SAndroid Build Coastguard Worker       if(result != CURLE_OK) {
517*6236dae4SAndroid Build Coastguard Worker         failf(data, "TFTP buffer too small for options");
518*6236dae4SAndroid Build Coastguard Worker         free(filename);
519*6236dae4SAndroid Build Coastguard Worker         return CURLE_TFTP_ILLEGAL;
520*6236dae4SAndroid Build Coastguard Worker       }
521*6236dae4SAndroid Build Coastguard Worker     }
522*6236dae4SAndroid Build Coastguard Worker 
523*6236dae4SAndroid Build Coastguard Worker     /* the typecase for the 3rd argument is mostly for systems that do
524*6236dae4SAndroid Build Coastguard Worker        not have a size_t argument, like older unixes that want an 'int' */
525*6236dae4SAndroid Build Coastguard Worker     senddata = sendto(state->sockfd, (void *)state->spacket.data,
526*6236dae4SAndroid Build Coastguard Worker                       (SEND_TYPE_ARG3)sbytes, 0,
527*6236dae4SAndroid Build Coastguard Worker                       &data->conn->remote_addr->curl_sa_addr,
528*6236dae4SAndroid Build Coastguard Worker                       (curl_socklen_t)data->conn->remote_addr->addrlen);
529*6236dae4SAndroid Build Coastguard Worker     if(senddata != (ssize_t)sbytes) {
530*6236dae4SAndroid Build Coastguard Worker       char buffer[STRERROR_LEN];
531*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
532*6236dae4SAndroid Build Coastguard Worker     }
533*6236dae4SAndroid Build Coastguard Worker     free(filename);
534*6236dae4SAndroid Build Coastguard Worker     break;
535*6236dae4SAndroid Build Coastguard Worker 
536*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_OACK:
537*6236dae4SAndroid Build Coastguard Worker     if(data->state.upload) {
538*6236dae4SAndroid Build Coastguard Worker       result = tftp_connect_for_tx(state, event);
539*6236dae4SAndroid Build Coastguard Worker     }
540*6236dae4SAndroid Build Coastguard Worker     else {
541*6236dae4SAndroid Build Coastguard Worker       result = tftp_connect_for_rx(state, event);
542*6236dae4SAndroid Build Coastguard Worker     }
543*6236dae4SAndroid Build Coastguard Worker     break;
544*6236dae4SAndroid Build Coastguard Worker 
545*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_ACK: /* Connected for transmit */
546*6236dae4SAndroid Build Coastguard Worker     result = tftp_connect_for_tx(state, event);
547*6236dae4SAndroid Build Coastguard Worker     break;
548*6236dae4SAndroid Build Coastguard Worker 
549*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_DATA: /* Connected for receive */
550*6236dae4SAndroid Build Coastguard Worker     result = tftp_connect_for_rx(state, event);
551*6236dae4SAndroid Build Coastguard Worker     break;
552*6236dae4SAndroid Build Coastguard Worker 
553*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_ERROR:
554*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_FIN;
555*6236dae4SAndroid Build Coastguard Worker     break;
556*6236dae4SAndroid Build Coastguard Worker 
557*6236dae4SAndroid Build Coastguard Worker   default:
558*6236dae4SAndroid Build Coastguard Worker     failf(state->data, "tftp_send_first: internal error");
559*6236dae4SAndroid Build Coastguard Worker     break;
560*6236dae4SAndroid Build Coastguard Worker   }
561*6236dae4SAndroid Build Coastguard Worker 
562*6236dae4SAndroid Build Coastguard Worker   return result;
563*6236dae4SAndroid Build Coastguard Worker }
564*6236dae4SAndroid Build Coastguard Worker 
565*6236dae4SAndroid Build Coastguard Worker /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
566*6236dae4SAndroid Build Coastguard Worker    boundary */
567*6236dae4SAndroid Build Coastguard Worker #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
568*6236dae4SAndroid Build Coastguard Worker 
569*6236dae4SAndroid Build Coastguard Worker /**********************************************************
570*6236dae4SAndroid Build Coastguard Worker  *
571*6236dae4SAndroid Build Coastguard Worker  * tftp_rx
572*6236dae4SAndroid Build Coastguard Worker  *
573*6236dae4SAndroid Build Coastguard Worker  * Event handler for the RX state
574*6236dae4SAndroid Build Coastguard Worker  *
575*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_rx(struct tftp_state_data * state,tftp_event_t event)576*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_rx(struct tftp_state_data *state,
577*6236dae4SAndroid Build Coastguard Worker                         tftp_event_t event)
578*6236dae4SAndroid Build Coastguard Worker {
579*6236dae4SAndroid Build Coastguard Worker   ssize_t sbytes;
580*6236dae4SAndroid Build Coastguard Worker   int rblock;
581*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
582*6236dae4SAndroid Build Coastguard Worker   char buffer[STRERROR_LEN];
583*6236dae4SAndroid Build Coastguard Worker 
584*6236dae4SAndroid Build Coastguard Worker   switch(event) {
585*6236dae4SAndroid Build Coastguard Worker 
586*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_DATA:
587*6236dae4SAndroid Build Coastguard Worker     /* Is this the block we expect? */
588*6236dae4SAndroid Build Coastguard Worker     rblock = getrpacketblock(&state->rpacket);
589*6236dae4SAndroid Build Coastguard Worker     if(NEXT_BLOCKNUM(state->block) == rblock) {
590*6236dae4SAndroid Build Coastguard Worker       /* This is the expected block. Reset counters and ACK it. */
591*6236dae4SAndroid Build Coastguard Worker       state->retries = 0;
592*6236dae4SAndroid Build Coastguard Worker     }
593*6236dae4SAndroid Build Coastguard Worker     else if(state->block == rblock) {
594*6236dae4SAndroid Build Coastguard Worker       /* This is the last recently received block again. Log it and ACK it
595*6236dae4SAndroid Build Coastguard Worker          again. */
596*6236dae4SAndroid Build Coastguard Worker       infof(data, "Received last DATA packet block %d again.", rblock);
597*6236dae4SAndroid Build Coastguard Worker     }
598*6236dae4SAndroid Build Coastguard Worker     else {
599*6236dae4SAndroid Build Coastguard Worker       /* totally unexpected, just log it */
600*6236dae4SAndroid Build Coastguard Worker       infof(data,
601*6236dae4SAndroid Build Coastguard Worker             "Received unexpected DATA packet block %d, expecting block %d",
602*6236dae4SAndroid Build Coastguard Worker             rblock, NEXT_BLOCKNUM(state->block));
603*6236dae4SAndroid Build Coastguard Worker       break;
604*6236dae4SAndroid Build Coastguard Worker     }
605*6236dae4SAndroid Build Coastguard Worker 
606*6236dae4SAndroid Build Coastguard Worker     /* ACK this block. */
607*6236dae4SAndroid Build Coastguard Worker     state->block = (unsigned short)rblock;
608*6236dae4SAndroid Build Coastguard Worker     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
609*6236dae4SAndroid Build Coastguard Worker     setpacketblock(&state->spacket, state->block);
610*6236dae4SAndroid Build Coastguard Worker     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
611*6236dae4SAndroid Build Coastguard Worker                     4, SEND_4TH_ARG,
612*6236dae4SAndroid Build Coastguard Worker                     (struct sockaddr *)&state->remote_addr,
613*6236dae4SAndroid Build Coastguard Worker                     state->remote_addrlen);
614*6236dae4SAndroid Build Coastguard Worker     if(sbytes < 0) {
615*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
616*6236dae4SAndroid Build Coastguard Worker       return CURLE_SEND_ERROR;
617*6236dae4SAndroid Build Coastguard Worker     }
618*6236dae4SAndroid Build Coastguard Worker 
619*6236dae4SAndroid Build Coastguard Worker     /* Check if completed (That is, a less than full packet is received) */
620*6236dae4SAndroid Build Coastguard Worker     if(state->rbytes < (ssize_t)state->blksize + 4) {
621*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_FIN;
622*6236dae4SAndroid Build Coastguard Worker     }
623*6236dae4SAndroid Build Coastguard Worker     else {
624*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_RX;
625*6236dae4SAndroid Build Coastguard Worker     }
626*6236dae4SAndroid Build Coastguard Worker     state->rx_time = time(NULL);
627*6236dae4SAndroid Build Coastguard Worker     break;
628*6236dae4SAndroid Build Coastguard Worker 
629*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_OACK:
630*6236dae4SAndroid Build Coastguard Worker     /* ACK option acknowledgement so we can move on to data */
631*6236dae4SAndroid Build Coastguard Worker     state->block = 0;
632*6236dae4SAndroid Build Coastguard Worker     state->retries = 0;
633*6236dae4SAndroid Build Coastguard Worker     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
634*6236dae4SAndroid Build Coastguard Worker     setpacketblock(&state->spacket, state->block);
635*6236dae4SAndroid Build Coastguard Worker     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
636*6236dae4SAndroid Build Coastguard Worker                     4, SEND_4TH_ARG,
637*6236dae4SAndroid Build Coastguard Worker                     (struct sockaddr *)&state->remote_addr,
638*6236dae4SAndroid Build Coastguard Worker                     state->remote_addrlen);
639*6236dae4SAndroid Build Coastguard Worker     if(sbytes < 0) {
640*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
641*6236dae4SAndroid Build Coastguard Worker       return CURLE_SEND_ERROR;
642*6236dae4SAndroid Build Coastguard Worker     }
643*6236dae4SAndroid Build Coastguard Worker 
644*6236dae4SAndroid Build Coastguard Worker     /* we are ready to RX data */
645*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_RX;
646*6236dae4SAndroid Build Coastguard Worker     state->rx_time = time(NULL);
647*6236dae4SAndroid Build Coastguard Worker     break;
648*6236dae4SAndroid Build Coastguard Worker 
649*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_TIMEOUT:
650*6236dae4SAndroid Build Coastguard Worker     /* Increment the retry count and fail if over the limit */
651*6236dae4SAndroid Build Coastguard Worker     state->retries++;
652*6236dae4SAndroid Build Coastguard Worker     infof(data,
653*6236dae4SAndroid Build Coastguard Worker           "Timeout waiting for block %d ACK. Retries = %d",
654*6236dae4SAndroid Build Coastguard Worker           NEXT_BLOCKNUM(state->block), state->retries);
655*6236dae4SAndroid Build Coastguard Worker     if(state->retries > state->retry_max) {
656*6236dae4SAndroid Build Coastguard Worker       state->error = TFTP_ERR_TIMEOUT;
657*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_FIN;
658*6236dae4SAndroid Build Coastguard Worker     }
659*6236dae4SAndroid Build Coastguard Worker     else {
660*6236dae4SAndroid Build Coastguard Worker       /* Resend the previous ACK */
661*6236dae4SAndroid Build Coastguard Worker       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
662*6236dae4SAndroid Build Coastguard Worker                       4, SEND_4TH_ARG,
663*6236dae4SAndroid Build Coastguard Worker                       (struct sockaddr *)&state->remote_addr,
664*6236dae4SAndroid Build Coastguard Worker                       state->remote_addrlen);
665*6236dae4SAndroid Build Coastguard Worker       if(sbytes < 0) {
666*6236dae4SAndroid Build Coastguard Worker         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
667*6236dae4SAndroid Build Coastguard Worker         return CURLE_SEND_ERROR;
668*6236dae4SAndroid Build Coastguard Worker       }
669*6236dae4SAndroid Build Coastguard Worker     }
670*6236dae4SAndroid Build Coastguard Worker     break;
671*6236dae4SAndroid Build Coastguard Worker 
672*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_ERROR:
673*6236dae4SAndroid Build Coastguard Worker     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
674*6236dae4SAndroid Build Coastguard Worker     setpacketblock(&state->spacket, state->block);
675*6236dae4SAndroid Build Coastguard Worker     (void)sendto(state->sockfd, (void *)state->spacket.data,
676*6236dae4SAndroid Build Coastguard Worker                  4, SEND_4TH_ARG,
677*6236dae4SAndroid Build Coastguard Worker                  (struct sockaddr *)&state->remote_addr,
678*6236dae4SAndroid Build Coastguard Worker                  state->remote_addrlen);
679*6236dae4SAndroid Build Coastguard Worker     /* do not bother with the return code, but if the socket is still up we
680*6236dae4SAndroid Build Coastguard Worker      * should be a good TFTP client and let the server know we are done */
681*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_FIN;
682*6236dae4SAndroid Build Coastguard Worker     break;
683*6236dae4SAndroid Build Coastguard Worker 
684*6236dae4SAndroid Build Coastguard Worker   default:
685*6236dae4SAndroid Build Coastguard Worker     failf(data, "%s", "tftp_rx: internal error");
686*6236dae4SAndroid Build Coastguard Worker     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
687*6236dae4SAndroid Build Coastguard Worker                                   this */
688*6236dae4SAndroid Build Coastguard Worker   }
689*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
690*6236dae4SAndroid Build Coastguard Worker }
691*6236dae4SAndroid Build Coastguard Worker 
692*6236dae4SAndroid Build Coastguard Worker /**********************************************************
693*6236dae4SAndroid Build Coastguard Worker  *
694*6236dae4SAndroid Build Coastguard Worker  * tftp_tx
695*6236dae4SAndroid Build Coastguard Worker  *
696*6236dae4SAndroid Build Coastguard Worker  * Event handler for the TX state
697*6236dae4SAndroid Build Coastguard Worker  *
698*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_tx(struct tftp_state_data * state,tftp_event_t event)699*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
700*6236dae4SAndroid Build Coastguard Worker {
701*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
702*6236dae4SAndroid Build Coastguard Worker   ssize_t sbytes;
703*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
704*6236dae4SAndroid Build Coastguard Worker   struct SingleRequest *k = &data->req;
705*6236dae4SAndroid Build Coastguard Worker   size_t cb; /* Bytes currently read */
706*6236dae4SAndroid Build Coastguard Worker   char buffer[STRERROR_LEN];
707*6236dae4SAndroid Build Coastguard Worker   char *bufptr;
708*6236dae4SAndroid Build Coastguard Worker   bool eos;
709*6236dae4SAndroid Build Coastguard Worker 
710*6236dae4SAndroid Build Coastguard Worker   switch(event) {
711*6236dae4SAndroid Build Coastguard Worker 
712*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_ACK:
713*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_OACK:
714*6236dae4SAndroid Build Coastguard Worker     if(event == TFTP_EVENT_ACK) {
715*6236dae4SAndroid Build Coastguard Worker       /* Ack the packet */
716*6236dae4SAndroid Build Coastguard Worker       int rblock = getrpacketblock(&state->rpacket);
717*6236dae4SAndroid Build Coastguard Worker 
718*6236dae4SAndroid Build Coastguard Worker       if(rblock != state->block &&
719*6236dae4SAndroid Build Coastguard Worker          /* There is a bug in tftpd-hpa that causes it to send us an ack for
720*6236dae4SAndroid Build Coastguard Worker           * 65535 when the block number wraps to 0. So when we are expecting
721*6236dae4SAndroid Build Coastguard Worker           * 0, also accept 65535. See
722*6236dae4SAndroid Build Coastguard Worker           * https://www.syslinux.org/archives/2010-September/015612.html
723*6236dae4SAndroid Build Coastguard Worker           * */
724*6236dae4SAndroid Build Coastguard Worker          !(state->block == 0 && rblock == 65535)) {
725*6236dae4SAndroid Build Coastguard Worker         /* This is not the expected block. Log it and up the retry counter */
726*6236dae4SAndroid Build Coastguard Worker         infof(data, "Received ACK for block %d, expecting %d",
727*6236dae4SAndroid Build Coastguard Worker               rblock, state->block);
728*6236dae4SAndroid Build Coastguard Worker         state->retries++;
729*6236dae4SAndroid Build Coastguard Worker         /* Bail out if over the maximum */
730*6236dae4SAndroid Build Coastguard Worker         if(state->retries > state->retry_max) {
731*6236dae4SAndroid Build Coastguard Worker           failf(data, "tftp_tx: giving up waiting for block %d ack",
732*6236dae4SAndroid Build Coastguard Worker                 state->block);
733*6236dae4SAndroid Build Coastguard Worker           result = CURLE_SEND_ERROR;
734*6236dae4SAndroid Build Coastguard Worker         }
735*6236dae4SAndroid Build Coastguard Worker         else {
736*6236dae4SAndroid Build Coastguard Worker           /* Re-send the data packet */
737*6236dae4SAndroid Build Coastguard Worker           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
738*6236dae4SAndroid Build Coastguard Worker                           4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
739*6236dae4SAndroid Build Coastguard Worker                           (struct sockaddr *)&state->remote_addr,
740*6236dae4SAndroid Build Coastguard Worker                           state->remote_addrlen);
741*6236dae4SAndroid Build Coastguard Worker           /* Check all sbytes were sent */
742*6236dae4SAndroid Build Coastguard Worker           if(sbytes < 0) {
743*6236dae4SAndroid Build Coastguard Worker             failf(data, "%s", Curl_strerror(SOCKERRNO,
744*6236dae4SAndroid Build Coastguard Worker                                             buffer, sizeof(buffer)));
745*6236dae4SAndroid Build Coastguard Worker             result = CURLE_SEND_ERROR;
746*6236dae4SAndroid Build Coastguard Worker           }
747*6236dae4SAndroid Build Coastguard Worker         }
748*6236dae4SAndroid Build Coastguard Worker 
749*6236dae4SAndroid Build Coastguard Worker         return result;
750*6236dae4SAndroid Build Coastguard Worker       }
751*6236dae4SAndroid Build Coastguard Worker       /* This is the expected packet. Reset the counters and send the next
752*6236dae4SAndroid Build Coastguard Worker          block */
753*6236dae4SAndroid Build Coastguard Worker       state->rx_time = time(NULL);
754*6236dae4SAndroid Build Coastguard Worker       state->block++;
755*6236dae4SAndroid Build Coastguard Worker     }
756*6236dae4SAndroid Build Coastguard Worker     else
757*6236dae4SAndroid Build Coastguard Worker       state->block = 1; /* first data block is 1 when using OACK */
758*6236dae4SAndroid Build Coastguard Worker 
759*6236dae4SAndroid Build Coastguard Worker     state->retries = 0;
760*6236dae4SAndroid Build Coastguard Worker     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
761*6236dae4SAndroid Build Coastguard Worker     setpacketblock(&state->spacket, state->block);
762*6236dae4SAndroid Build Coastguard Worker     if(state->block > 1 && state->sbytes < state->blksize) {
763*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_FIN;
764*6236dae4SAndroid Build Coastguard Worker       return CURLE_OK;
765*6236dae4SAndroid Build Coastguard Worker     }
766*6236dae4SAndroid Build Coastguard Worker 
767*6236dae4SAndroid Build Coastguard Worker     /* TFTP considers data block size < 512 bytes as an end of session. So
768*6236dae4SAndroid Build Coastguard Worker      * in some cases we must wait for additional data to build full (512 bytes)
769*6236dae4SAndroid Build Coastguard Worker      * data block.
770*6236dae4SAndroid Build Coastguard Worker      * */
771*6236dae4SAndroid Build Coastguard Worker     state->sbytes = 0;
772*6236dae4SAndroid Build Coastguard Worker     bufptr = (char *)state->spacket.data + 4;
773*6236dae4SAndroid Build Coastguard Worker     do {
774*6236dae4SAndroid Build Coastguard Worker       result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
775*6236dae4SAndroid Build Coastguard Worker                                 &cb, &eos);
776*6236dae4SAndroid Build Coastguard Worker       if(result)
777*6236dae4SAndroid Build Coastguard Worker         return result;
778*6236dae4SAndroid Build Coastguard Worker       state->sbytes += (int)cb;
779*6236dae4SAndroid Build Coastguard Worker       bufptr += cb;
780*6236dae4SAndroid Build Coastguard Worker     } while(state->sbytes < state->blksize && cb);
781*6236dae4SAndroid Build Coastguard Worker 
782*6236dae4SAndroid Build Coastguard Worker     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
783*6236dae4SAndroid Build Coastguard Worker                     4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
784*6236dae4SAndroid Build Coastguard Worker                     (struct sockaddr *)&state->remote_addr,
785*6236dae4SAndroid Build Coastguard Worker                     state->remote_addrlen);
786*6236dae4SAndroid Build Coastguard Worker     /* Check all sbytes were sent */
787*6236dae4SAndroid Build Coastguard Worker     if(sbytes < 0) {
788*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
789*6236dae4SAndroid Build Coastguard Worker       return CURLE_SEND_ERROR;
790*6236dae4SAndroid Build Coastguard Worker     }
791*6236dae4SAndroid Build Coastguard Worker     /* Update the progress meter */
792*6236dae4SAndroid Build Coastguard Worker     k->writebytecount += state->sbytes;
793*6236dae4SAndroid Build Coastguard Worker     Curl_pgrsSetUploadCounter(data, k->writebytecount);
794*6236dae4SAndroid Build Coastguard Worker     break;
795*6236dae4SAndroid Build Coastguard Worker 
796*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_TIMEOUT:
797*6236dae4SAndroid Build Coastguard Worker     /* Increment the retry counter and log the timeout */
798*6236dae4SAndroid Build Coastguard Worker     state->retries++;
799*6236dae4SAndroid Build Coastguard Worker     infof(data, "Timeout waiting for block %d ACK. "
800*6236dae4SAndroid Build Coastguard Worker           " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
801*6236dae4SAndroid Build Coastguard Worker     /* Decide if we have had enough */
802*6236dae4SAndroid Build Coastguard Worker     if(state->retries > state->retry_max) {
803*6236dae4SAndroid Build Coastguard Worker       state->error = TFTP_ERR_TIMEOUT;
804*6236dae4SAndroid Build Coastguard Worker       state->state = TFTP_STATE_FIN;
805*6236dae4SAndroid Build Coastguard Worker     }
806*6236dae4SAndroid Build Coastguard Worker     else {
807*6236dae4SAndroid Build Coastguard Worker       /* Re-send the data packet */
808*6236dae4SAndroid Build Coastguard Worker       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
809*6236dae4SAndroid Build Coastguard Worker                       4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
810*6236dae4SAndroid Build Coastguard Worker                       (struct sockaddr *)&state->remote_addr,
811*6236dae4SAndroid Build Coastguard Worker                       state->remote_addrlen);
812*6236dae4SAndroid Build Coastguard Worker       /* Check all sbytes were sent */
813*6236dae4SAndroid Build Coastguard Worker       if(sbytes < 0) {
814*6236dae4SAndroid Build Coastguard Worker         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
815*6236dae4SAndroid Build Coastguard Worker         return CURLE_SEND_ERROR;
816*6236dae4SAndroid Build Coastguard Worker       }
817*6236dae4SAndroid Build Coastguard Worker       /* since this was a re-send, we remain at the still byte position */
818*6236dae4SAndroid Build Coastguard Worker       Curl_pgrsSetUploadCounter(data, k->writebytecount);
819*6236dae4SAndroid Build Coastguard Worker     }
820*6236dae4SAndroid Build Coastguard Worker     break;
821*6236dae4SAndroid Build Coastguard Worker 
822*6236dae4SAndroid Build Coastguard Worker   case TFTP_EVENT_ERROR:
823*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_FIN;
824*6236dae4SAndroid Build Coastguard Worker     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
825*6236dae4SAndroid Build Coastguard Worker     setpacketblock(&state->spacket, state->block);
826*6236dae4SAndroid Build Coastguard Worker     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
827*6236dae4SAndroid Build Coastguard Worker                  (struct sockaddr *)&state->remote_addr,
828*6236dae4SAndroid Build Coastguard Worker                  state->remote_addrlen);
829*6236dae4SAndroid Build Coastguard Worker     /* do not bother with the return code, but if the socket is still up we
830*6236dae4SAndroid Build Coastguard Worker      * should be a good TFTP client and let the server know we are done */
831*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_FIN;
832*6236dae4SAndroid Build Coastguard Worker     break;
833*6236dae4SAndroid Build Coastguard Worker 
834*6236dae4SAndroid Build Coastguard Worker   default:
835*6236dae4SAndroid Build Coastguard Worker     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
836*6236dae4SAndroid Build Coastguard Worker     break;
837*6236dae4SAndroid Build Coastguard Worker   }
838*6236dae4SAndroid Build Coastguard Worker 
839*6236dae4SAndroid Build Coastguard Worker   return result;
840*6236dae4SAndroid Build Coastguard Worker }
841*6236dae4SAndroid Build Coastguard Worker 
842*6236dae4SAndroid Build Coastguard Worker /**********************************************************
843*6236dae4SAndroid Build Coastguard Worker  *
844*6236dae4SAndroid Build Coastguard Worker  * tftp_translate_code
845*6236dae4SAndroid Build Coastguard Worker  *
846*6236dae4SAndroid Build Coastguard Worker  * Translate internal error codes to CURL error codes
847*6236dae4SAndroid Build Coastguard Worker  *
848*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_translate_code(tftp_error_t error)849*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_translate_code(tftp_error_t error)
850*6236dae4SAndroid Build Coastguard Worker {
851*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
852*6236dae4SAndroid Build Coastguard Worker 
853*6236dae4SAndroid Build Coastguard Worker   if(error != TFTP_ERR_NONE) {
854*6236dae4SAndroid Build Coastguard Worker     switch(error) {
855*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_NOTFOUND:
856*6236dae4SAndroid Build Coastguard Worker       result = CURLE_TFTP_NOTFOUND;
857*6236dae4SAndroid Build Coastguard Worker       break;
858*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_PERM:
859*6236dae4SAndroid Build Coastguard Worker       result = CURLE_TFTP_PERM;
860*6236dae4SAndroid Build Coastguard Worker       break;
861*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_DISKFULL:
862*6236dae4SAndroid Build Coastguard Worker       result = CURLE_REMOTE_DISK_FULL;
863*6236dae4SAndroid Build Coastguard Worker       break;
864*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_UNDEF:
865*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_ILLEGAL:
866*6236dae4SAndroid Build Coastguard Worker       result = CURLE_TFTP_ILLEGAL;
867*6236dae4SAndroid Build Coastguard Worker       break;
868*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_UNKNOWNID:
869*6236dae4SAndroid Build Coastguard Worker       result = CURLE_TFTP_UNKNOWNID;
870*6236dae4SAndroid Build Coastguard Worker       break;
871*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_EXISTS:
872*6236dae4SAndroid Build Coastguard Worker       result = CURLE_REMOTE_FILE_EXISTS;
873*6236dae4SAndroid Build Coastguard Worker       break;
874*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_NOSUCHUSER:
875*6236dae4SAndroid Build Coastguard Worker       result = CURLE_TFTP_NOSUCHUSER;
876*6236dae4SAndroid Build Coastguard Worker       break;
877*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_TIMEOUT:
878*6236dae4SAndroid Build Coastguard Worker       result = CURLE_OPERATION_TIMEDOUT;
879*6236dae4SAndroid Build Coastguard Worker       break;
880*6236dae4SAndroid Build Coastguard Worker     case TFTP_ERR_NORESPONSE:
881*6236dae4SAndroid Build Coastguard Worker       result = CURLE_COULDNT_CONNECT;
882*6236dae4SAndroid Build Coastguard Worker       break;
883*6236dae4SAndroid Build Coastguard Worker     default:
884*6236dae4SAndroid Build Coastguard Worker       result = CURLE_ABORTED_BY_CALLBACK;
885*6236dae4SAndroid Build Coastguard Worker       break;
886*6236dae4SAndroid Build Coastguard Worker     }
887*6236dae4SAndroid Build Coastguard Worker   }
888*6236dae4SAndroid Build Coastguard Worker   else
889*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OK;
890*6236dae4SAndroid Build Coastguard Worker 
891*6236dae4SAndroid Build Coastguard Worker   return result;
892*6236dae4SAndroid Build Coastguard Worker }
893*6236dae4SAndroid Build Coastguard Worker 
894*6236dae4SAndroid Build Coastguard Worker /**********************************************************
895*6236dae4SAndroid Build Coastguard Worker  *
896*6236dae4SAndroid Build Coastguard Worker  * tftp_state_machine
897*6236dae4SAndroid Build Coastguard Worker  *
898*6236dae4SAndroid Build Coastguard Worker  * The tftp state machine event dispatcher
899*6236dae4SAndroid Build Coastguard Worker  *
900*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_state_machine(struct tftp_state_data * state,tftp_event_t event)901*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_state_machine(struct tftp_state_data *state,
902*6236dae4SAndroid Build Coastguard Worker                                    tftp_event_t event)
903*6236dae4SAndroid Build Coastguard Worker {
904*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
905*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = state->data;
906*6236dae4SAndroid Build Coastguard Worker 
907*6236dae4SAndroid Build Coastguard Worker   switch(state->state) {
908*6236dae4SAndroid Build Coastguard Worker   case TFTP_STATE_START:
909*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "TFTP_STATE_START"));
910*6236dae4SAndroid Build Coastguard Worker     result = tftp_send_first(state, event);
911*6236dae4SAndroid Build Coastguard Worker     break;
912*6236dae4SAndroid Build Coastguard Worker   case TFTP_STATE_RX:
913*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "TFTP_STATE_RX"));
914*6236dae4SAndroid Build Coastguard Worker     result = tftp_rx(state, event);
915*6236dae4SAndroid Build Coastguard Worker     break;
916*6236dae4SAndroid Build Coastguard Worker   case TFTP_STATE_TX:
917*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "TFTP_STATE_TX"));
918*6236dae4SAndroid Build Coastguard Worker     result = tftp_tx(state, event);
919*6236dae4SAndroid Build Coastguard Worker     break;
920*6236dae4SAndroid Build Coastguard Worker   case TFTP_STATE_FIN:
921*6236dae4SAndroid Build Coastguard Worker     infof(data, "%s", "TFTP finished");
922*6236dae4SAndroid Build Coastguard Worker     break;
923*6236dae4SAndroid Build Coastguard Worker   default:
924*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "STATE: %d", state->state));
925*6236dae4SAndroid Build Coastguard Worker     failf(data, "%s", "Internal state machine error");
926*6236dae4SAndroid Build Coastguard Worker     result = CURLE_TFTP_ILLEGAL;
927*6236dae4SAndroid Build Coastguard Worker     break;
928*6236dae4SAndroid Build Coastguard Worker   }
929*6236dae4SAndroid Build Coastguard Worker 
930*6236dae4SAndroid Build Coastguard Worker   return result;
931*6236dae4SAndroid Build Coastguard Worker }
932*6236dae4SAndroid Build Coastguard Worker 
933*6236dae4SAndroid Build Coastguard Worker /**********************************************************
934*6236dae4SAndroid Build Coastguard Worker  *
935*6236dae4SAndroid Build Coastguard Worker  * tftp_disconnect
936*6236dae4SAndroid Build Coastguard Worker  *
937*6236dae4SAndroid Build Coastguard Worker  * The disconnect callback
938*6236dae4SAndroid Build Coastguard Worker  *
939*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)940*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_disconnect(struct Curl_easy *data,
941*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn, bool dead_connection)
942*6236dae4SAndroid Build Coastguard Worker {
943*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
944*6236dae4SAndroid Build Coastguard Worker   (void) data;
945*6236dae4SAndroid Build Coastguard Worker   (void) dead_connection;
946*6236dae4SAndroid Build Coastguard Worker 
947*6236dae4SAndroid Build Coastguard Worker   /* done, free dynamically allocated pkt buffers */
948*6236dae4SAndroid Build Coastguard Worker   if(state) {
949*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(state->rpacket.data);
950*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(state->spacket.data);
951*6236dae4SAndroid Build Coastguard Worker     free(state);
952*6236dae4SAndroid Build Coastguard Worker   }
953*6236dae4SAndroid Build Coastguard Worker 
954*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
955*6236dae4SAndroid Build Coastguard Worker }
956*6236dae4SAndroid Build Coastguard Worker 
957*6236dae4SAndroid Build Coastguard Worker /**********************************************************
958*6236dae4SAndroid Build Coastguard Worker  *
959*6236dae4SAndroid Build Coastguard Worker  * tftp_connect
960*6236dae4SAndroid Build Coastguard Worker  *
961*6236dae4SAndroid Build Coastguard Worker  * The connect callback
962*6236dae4SAndroid Build Coastguard Worker  *
963*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_connect(struct Curl_easy * data,bool * done)964*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
965*6236dae4SAndroid Build Coastguard Worker {
966*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state;
967*6236dae4SAndroid Build Coastguard Worker   int blksize;
968*6236dae4SAndroid Build Coastguard Worker   int need_blksize;
969*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
970*6236dae4SAndroid Build Coastguard Worker 
971*6236dae4SAndroid Build Coastguard Worker   blksize = TFTP_BLKSIZE_DEFAULT;
972*6236dae4SAndroid Build Coastguard Worker 
973*6236dae4SAndroid Build Coastguard Worker   state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
974*6236dae4SAndroid Build Coastguard Worker   if(!state)
975*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
976*6236dae4SAndroid Build Coastguard Worker 
977*6236dae4SAndroid Build Coastguard Worker   /* alloc pkt buffers based on specified blksize */
978*6236dae4SAndroid Build Coastguard Worker   if(data->set.tftp_blksize)
979*6236dae4SAndroid Build Coastguard Worker     /* range checked when set */
980*6236dae4SAndroid Build Coastguard Worker     blksize = (int)data->set.tftp_blksize;
981*6236dae4SAndroid Build Coastguard Worker 
982*6236dae4SAndroid Build Coastguard Worker   need_blksize = blksize;
983*6236dae4SAndroid Build Coastguard Worker   /* default size is the fallback when no OACK is received */
984*6236dae4SAndroid Build Coastguard Worker   if(need_blksize < TFTP_BLKSIZE_DEFAULT)
985*6236dae4SAndroid Build Coastguard Worker     need_blksize = TFTP_BLKSIZE_DEFAULT;
986*6236dae4SAndroid Build Coastguard Worker 
987*6236dae4SAndroid Build Coastguard Worker   if(!state->rpacket.data) {
988*6236dae4SAndroid Build Coastguard Worker     state->rpacket.data = calloc(1, need_blksize + 2 + 2);
989*6236dae4SAndroid Build Coastguard Worker 
990*6236dae4SAndroid Build Coastguard Worker     if(!state->rpacket.data)
991*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
992*6236dae4SAndroid Build Coastguard Worker   }
993*6236dae4SAndroid Build Coastguard Worker 
994*6236dae4SAndroid Build Coastguard Worker   if(!state->spacket.data) {
995*6236dae4SAndroid Build Coastguard Worker     state->spacket.data = calloc(1, need_blksize + 2 + 2);
996*6236dae4SAndroid Build Coastguard Worker 
997*6236dae4SAndroid Build Coastguard Worker     if(!state->spacket.data)
998*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
999*6236dae4SAndroid Build Coastguard Worker   }
1000*6236dae4SAndroid Build Coastguard Worker 
1001*6236dae4SAndroid Build Coastguard Worker   /* we do not keep TFTP connections up basically because there is none or
1002*6236dae4SAndroid Build Coastguard Worker    * little gain for UDP */
1003*6236dae4SAndroid Build Coastguard Worker   connclose(conn, "TFTP");
1004*6236dae4SAndroid Build Coastguard Worker 
1005*6236dae4SAndroid Build Coastguard Worker   state->data = data;
1006*6236dae4SAndroid Build Coastguard Worker   state->sockfd = conn->sock[FIRSTSOCKET];
1007*6236dae4SAndroid Build Coastguard Worker   state->state = TFTP_STATE_START;
1008*6236dae4SAndroid Build Coastguard Worker   state->error = TFTP_ERR_NONE;
1009*6236dae4SAndroid Build Coastguard Worker   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
1010*6236dae4SAndroid Build Coastguard Worker   state->requested_blksize = blksize;
1011*6236dae4SAndroid Build Coastguard Worker 
1012*6236dae4SAndroid Build Coastguard Worker   ((struct sockaddr *)&state->local_addr)->sa_family =
1013*6236dae4SAndroid Build Coastguard Worker     (CURL_SA_FAMILY_T)(conn->remote_addr->family);
1014*6236dae4SAndroid Build Coastguard Worker 
1015*6236dae4SAndroid Build Coastguard Worker   tftp_set_timeouts(state);
1016*6236dae4SAndroid Build Coastguard Worker 
1017*6236dae4SAndroid Build Coastguard Worker   if(!conn->bits.bound) {
1018*6236dae4SAndroid Build Coastguard Worker     /* If not already bound, bind to any interface, random UDP port. If it is
1019*6236dae4SAndroid Build Coastguard Worker      * reused or a custom local port was desired, this has already been done!
1020*6236dae4SAndroid Build Coastguard Worker      *
1021*6236dae4SAndroid Build Coastguard Worker      * We once used the size of the local_addr struct as the third argument
1022*6236dae4SAndroid Build Coastguard Worker      * for bind() to better work with IPv6 or whatever size the struct could
1023*6236dae4SAndroid Build Coastguard Worker      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1024*6236dae4SAndroid Build Coastguard Worker      * size of that argument to match the exact size of a 'sockaddr_in' struct
1025*6236dae4SAndroid Build Coastguard Worker      * when running IPv4-only.
1026*6236dae4SAndroid Build Coastguard Worker      *
1027*6236dae4SAndroid Build Coastguard Worker      * Therefore we use the size from the address we connected to, which we
1028*6236dae4SAndroid Build Coastguard Worker      * assume uses the same IP version and thus hopefully this works for both
1029*6236dae4SAndroid Build Coastguard Worker      * IPv4 and IPv6...
1030*6236dae4SAndroid Build Coastguard Worker      */
1031*6236dae4SAndroid Build Coastguard Worker     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1032*6236dae4SAndroid Build Coastguard Worker                   (curl_socklen_t)conn->remote_addr->addrlen);
1033*6236dae4SAndroid Build Coastguard Worker     if(rc) {
1034*6236dae4SAndroid Build Coastguard Worker       char buffer[STRERROR_LEN];
1035*6236dae4SAndroid Build Coastguard Worker       failf(data, "bind() failed; %s",
1036*6236dae4SAndroid Build Coastguard Worker             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1037*6236dae4SAndroid Build Coastguard Worker       return CURLE_COULDNT_CONNECT;
1038*6236dae4SAndroid Build Coastguard Worker     }
1039*6236dae4SAndroid Build Coastguard Worker     conn->bits.bound = TRUE;
1040*6236dae4SAndroid Build Coastguard Worker   }
1041*6236dae4SAndroid Build Coastguard Worker 
1042*6236dae4SAndroid Build Coastguard Worker   Curl_pgrsStartNow(data);
1043*6236dae4SAndroid Build Coastguard Worker 
1044*6236dae4SAndroid Build Coastguard Worker   *done = TRUE;
1045*6236dae4SAndroid Build Coastguard Worker 
1046*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1047*6236dae4SAndroid Build Coastguard Worker }
1048*6236dae4SAndroid Build Coastguard Worker 
1049*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1050*6236dae4SAndroid Build Coastguard Worker  *
1051*6236dae4SAndroid Build Coastguard Worker  * tftp_done
1052*6236dae4SAndroid Build Coastguard Worker  *
1053*6236dae4SAndroid Build Coastguard Worker  * The done callback
1054*6236dae4SAndroid Build Coastguard Worker  *
1055*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_done(struct Curl_easy * data,CURLcode status,bool premature)1056*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
1057*6236dae4SAndroid Build Coastguard Worker                           bool premature)
1058*6236dae4SAndroid Build Coastguard Worker {
1059*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1060*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1061*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
1062*6236dae4SAndroid Build Coastguard Worker 
1063*6236dae4SAndroid Build Coastguard Worker   (void)status; /* unused */
1064*6236dae4SAndroid Build Coastguard Worker   (void)premature; /* not used */
1065*6236dae4SAndroid Build Coastguard Worker 
1066*6236dae4SAndroid Build Coastguard Worker   if(Curl_pgrsDone(data))
1067*6236dae4SAndroid Build Coastguard Worker     return CURLE_ABORTED_BY_CALLBACK;
1068*6236dae4SAndroid Build Coastguard Worker 
1069*6236dae4SAndroid Build Coastguard Worker   /* If we have encountered an error */
1070*6236dae4SAndroid Build Coastguard Worker   if(state)
1071*6236dae4SAndroid Build Coastguard Worker     result = tftp_translate_code(state->error);
1072*6236dae4SAndroid Build Coastguard Worker 
1073*6236dae4SAndroid Build Coastguard Worker   return result;
1074*6236dae4SAndroid Build Coastguard Worker }
1075*6236dae4SAndroid Build Coastguard Worker 
1076*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1077*6236dae4SAndroid Build Coastguard Worker  *
1078*6236dae4SAndroid Build Coastguard Worker  * tftp_getsock
1079*6236dae4SAndroid Build Coastguard Worker  *
1080*6236dae4SAndroid Build Coastguard Worker  * The getsock callback
1081*6236dae4SAndroid Build Coastguard Worker  *
1082*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * socks)1083*6236dae4SAndroid Build Coastguard Worker static int tftp_getsock(struct Curl_easy *data,
1084*6236dae4SAndroid Build Coastguard Worker                         struct connectdata *conn, curl_socket_t *socks)
1085*6236dae4SAndroid Build Coastguard Worker {
1086*6236dae4SAndroid Build Coastguard Worker   (void)data;
1087*6236dae4SAndroid Build Coastguard Worker   socks[0] = conn->sock[FIRSTSOCKET];
1088*6236dae4SAndroid Build Coastguard Worker   return GETSOCK_READSOCK(0);
1089*6236dae4SAndroid Build Coastguard Worker }
1090*6236dae4SAndroid Build Coastguard Worker 
1091*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1092*6236dae4SAndroid Build Coastguard Worker  *
1093*6236dae4SAndroid Build Coastguard Worker  * tftp_receive_packet
1094*6236dae4SAndroid Build Coastguard Worker  *
1095*6236dae4SAndroid Build Coastguard Worker  * Called once select fires and data is ready on the socket
1096*6236dae4SAndroid Build Coastguard Worker  *
1097*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_receive_packet(struct Curl_easy * data)1098*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_receive_packet(struct Curl_easy *data)
1099*6236dae4SAndroid Build Coastguard Worker {
1100*6236dae4SAndroid Build Coastguard Worker   curl_socklen_t        fromlen;
1101*6236dae4SAndroid Build Coastguard Worker   CURLcode              result = CURLE_OK;
1102*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1103*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
1104*6236dae4SAndroid Build Coastguard Worker 
1105*6236dae4SAndroid Build Coastguard Worker   /* Receive the packet */
1106*6236dae4SAndroid Build Coastguard Worker   fromlen = sizeof(state->remote_addr);
1107*6236dae4SAndroid Build Coastguard Worker   state->rbytes = (int)recvfrom(state->sockfd,
1108*6236dae4SAndroid Build Coastguard Worker                                 (void *)state->rpacket.data,
1109*6236dae4SAndroid Build Coastguard Worker                                 (RECV_TYPE_ARG3)state->blksize + 4,
1110*6236dae4SAndroid Build Coastguard Worker                                 0,
1111*6236dae4SAndroid Build Coastguard Worker                                 (struct sockaddr *)&state->remote_addr,
1112*6236dae4SAndroid Build Coastguard Worker                                 &fromlen);
1113*6236dae4SAndroid Build Coastguard Worker   state->remote_addrlen = fromlen;
1114*6236dae4SAndroid Build Coastguard Worker 
1115*6236dae4SAndroid Build Coastguard Worker   /* Sanity check packet length */
1116*6236dae4SAndroid Build Coastguard Worker   if(state->rbytes < 4) {
1117*6236dae4SAndroid Build Coastguard Worker     failf(data, "Received too short packet");
1118*6236dae4SAndroid Build Coastguard Worker     /* Not a timeout, but how best to handle it? */
1119*6236dae4SAndroid Build Coastguard Worker     state->event = TFTP_EVENT_TIMEOUT;
1120*6236dae4SAndroid Build Coastguard Worker   }
1121*6236dae4SAndroid Build Coastguard Worker   else {
1122*6236dae4SAndroid Build Coastguard Worker     /* The event is given by the TFTP packet time */
1123*6236dae4SAndroid Build Coastguard Worker     unsigned short event = getrpacketevent(&state->rpacket);
1124*6236dae4SAndroid Build Coastguard Worker     state->event = (tftp_event_t)event;
1125*6236dae4SAndroid Build Coastguard Worker 
1126*6236dae4SAndroid Build Coastguard Worker     switch(state->event) {
1127*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_DATA:
1128*6236dae4SAndroid Build Coastguard Worker       /* Do not pass to the client empty or retransmitted packets */
1129*6236dae4SAndroid Build Coastguard Worker       if(state->rbytes > 4 &&
1130*6236dae4SAndroid Build Coastguard Worker          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1131*6236dae4SAndroid Build Coastguard Worker         result = Curl_client_write(data, CLIENTWRITE_BODY,
1132*6236dae4SAndroid Build Coastguard Worker                                    (char *)state->rpacket.data + 4,
1133*6236dae4SAndroid Build Coastguard Worker                                    state->rbytes-4);
1134*6236dae4SAndroid Build Coastguard Worker         if(result) {
1135*6236dae4SAndroid Build Coastguard Worker           tftp_state_machine(state, TFTP_EVENT_ERROR);
1136*6236dae4SAndroid Build Coastguard Worker           return result;
1137*6236dae4SAndroid Build Coastguard Worker         }
1138*6236dae4SAndroid Build Coastguard Worker       }
1139*6236dae4SAndroid Build Coastguard Worker       break;
1140*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_ERROR:
1141*6236dae4SAndroid Build Coastguard Worker     {
1142*6236dae4SAndroid Build Coastguard Worker       unsigned short error = getrpacketblock(&state->rpacket);
1143*6236dae4SAndroid Build Coastguard Worker       char *str = (char *)state->rpacket.data + 4;
1144*6236dae4SAndroid Build Coastguard Worker       size_t strn = state->rbytes - 4;
1145*6236dae4SAndroid Build Coastguard Worker       state->error = (tftp_error_t)error;
1146*6236dae4SAndroid Build Coastguard Worker       if(tftp_strnlen(str, strn) < strn)
1147*6236dae4SAndroid Build Coastguard Worker         infof(data, "TFTP error: %s", str);
1148*6236dae4SAndroid Build Coastguard Worker       break;
1149*6236dae4SAndroid Build Coastguard Worker     }
1150*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_ACK:
1151*6236dae4SAndroid Build Coastguard Worker       break;
1152*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_OACK:
1153*6236dae4SAndroid Build Coastguard Worker       result = tftp_parse_option_ack(state,
1154*6236dae4SAndroid Build Coastguard Worker                                      (const char *)state->rpacket.data + 2,
1155*6236dae4SAndroid Build Coastguard Worker                                      state->rbytes-2);
1156*6236dae4SAndroid Build Coastguard Worker       if(result)
1157*6236dae4SAndroid Build Coastguard Worker         return result;
1158*6236dae4SAndroid Build Coastguard Worker       break;
1159*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_RRQ:
1160*6236dae4SAndroid Build Coastguard Worker     case TFTP_EVENT_WRQ:
1161*6236dae4SAndroid Build Coastguard Worker     default:
1162*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", "Internal error: Unexpected packet");
1163*6236dae4SAndroid Build Coastguard Worker       break;
1164*6236dae4SAndroid Build Coastguard Worker     }
1165*6236dae4SAndroid Build Coastguard Worker 
1166*6236dae4SAndroid Build Coastguard Worker     /* Update the progress meter */
1167*6236dae4SAndroid Build Coastguard Worker     if(Curl_pgrsUpdate(data)) {
1168*6236dae4SAndroid Build Coastguard Worker       tftp_state_machine(state, TFTP_EVENT_ERROR);
1169*6236dae4SAndroid Build Coastguard Worker       return CURLE_ABORTED_BY_CALLBACK;
1170*6236dae4SAndroid Build Coastguard Worker     }
1171*6236dae4SAndroid Build Coastguard Worker   }
1172*6236dae4SAndroid Build Coastguard Worker   return result;
1173*6236dae4SAndroid Build Coastguard Worker }
1174*6236dae4SAndroid Build Coastguard Worker 
1175*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1176*6236dae4SAndroid Build Coastguard Worker  *
1177*6236dae4SAndroid Build Coastguard Worker  * tftp_state_timeout
1178*6236dae4SAndroid Build Coastguard Worker  *
1179*6236dae4SAndroid Build Coastguard Worker  * Check if timeouts have been reached
1180*6236dae4SAndroid Build Coastguard Worker  *
1181*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_state_timeout(struct Curl_easy * data,tftp_event_t * event)1182*6236dae4SAndroid Build Coastguard Worker static timediff_t tftp_state_timeout(struct Curl_easy *data,
1183*6236dae4SAndroid Build Coastguard Worker                                      tftp_event_t *event)
1184*6236dae4SAndroid Build Coastguard Worker {
1185*6236dae4SAndroid Build Coastguard Worker   time_t current;
1186*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1187*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
1188*6236dae4SAndroid Build Coastguard Worker   timediff_t timeout_ms;
1189*6236dae4SAndroid Build Coastguard Worker 
1190*6236dae4SAndroid Build Coastguard Worker   if(event)
1191*6236dae4SAndroid Build Coastguard Worker     *event = TFTP_EVENT_NONE;
1192*6236dae4SAndroid Build Coastguard Worker 
1193*6236dae4SAndroid Build Coastguard Worker   timeout_ms = Curl_timeleft(state->data, NULL,
1194*6236dae4SAndroid Build Coastguard Worker                              (state->state == TFTP_STATE_START));
1195*6236dae4SAndroid Build Coastguard Worker   if(timeout_ms < 0) {
1196*6236dae4SAndroid Build Coastguard Worker     state->error = TFTP_ERR_TIMEOUT;
1197*6236dae4SAndroid Build Coastguard Worker     state->state = TFTP_STATE_FIN;
1198*6236dae4SAndroid Build Coastguard Worker     return 0;
1199*6236dae4SAndroid Build Coastguard Worker   }
1200*6236dae4SAndroid Build Coastguard Worker   current = time(NULL);
1201*6236dae4SAndroid Build Coastguard Worker   if(current > state->rx_time + state->retry_time) {
1202*6236dae4SAndroid Build Coastguard Worker     if(event)
1203*6236dae4SAndroid Build Coastguard Worker       *event = TFTP_EVENT_TIMEOUT;
1204*6236dae4SAndroid Build Coastguard Worker     state->rx_time = time(NULL); /* update even though we received nothing */
1205*6236dae4SAndroid Build Coastguard Worker   }
1206*6236dae4SAndroid Build Coastguard Worker 
1207*6236dae4SAndroid Build Coastguard Worker   return timeout_ms;
1208*6236dae4SAndroid Build Coastguard Worker }
1209*6236dae4SAndroid Build Coastguard Worker 
1210*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1211*6236dae4SAndroid Build Coastguard Worker  *
1212*6236dae4SAndroid Build Coastguard Worker  * tftp_multi_statemach
1213*6236dae4SAndroid Build Coastguard Worker  *
1214*6236dae4SAndroid Build Coastguard Worker  * Handle single RX socket event and return
1215*6236dae4SAndroid Build Coastguard Worker  *
1216*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_multi_statemach(struct Curl_easy * data,bool * done)1217*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1218*6236dae4SAndroid Build Coastguard Worker {
1219*6236dae4SAndroid Build Coastguard Worker   tftp_event_t event;
1220*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1221*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1222*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
1223*6236dae4SAndroid Build Coastguard Worker   timediff_t timeout_ms = tftp_state_timeout(data, &event);
1224*6236dae4SAndroid Build Coastguard Worker 
1225*6236dae4SAndroid Build Coastguard Worker   *done = FALSE;
1226*6236dae4SAndroid Build Coastguard Worker 
1227*6236dae4SAndroid Build Coastguard Worker   if(timeout_ms < 0) {
1228*6236dae4SAndroid Build Coastguard Worker     failf(data, "TFTP response timeout");
1229*6236dae4SAndroid Build Coastguard Worker     return CURLE_OPERATION_TIMEDOUT;
1230*6236dae4SAndroid Build Coastguard Worker   }
1231*6236dae4SAndroid Build Coastguard Worker   if(event != TFTP_EVENT_NONE) {
1232*6236dae4SAndroid Build Coastguard Worker     result = tftp_state_machine(state, event);
1233*6236dae4SAndroid Build Coastguard Worker     if(result)
1234*6236dae4SAndroid Build Coastguard Worker       return result;
1235*6236dae4SAndroid Build Coastguard Worker     *done = (state->state == TFTP_STATE_FIN);
1236*6236dae4SAndroid Build Coastguard Worker     if(*done)
1237*6236dae4SAndroid Build Coastguard Worker       /* Tell curl we are done */
1238*6236dae4SAndroid Build Coastguard Worker       Curl_xfer_setup_nop(data);
1239*6236dae4SAndroid Build Coastguard Worker   }
1240*6236dae4SAndroid Build Coastguard Worker   else {
1241*6236dae4SAndroid Build Coastguard Worker     /* no timeouts to handle, check our socket */
1242*6236dae4SAndroid Build Coastguard Worker     int rc = SOCKET_READABLE(state->sockfd, 0);
1243*6236dae4SAndroid Build Coastguard Worker 
1244*6236dae4SAndroid Build Coastguard Worker     if(rc == -1) {
1245*6236dae4SAndroid Build Coastguard Worker       /* bail out */
1246*6236dae4SAndroid Build Coastguard Worker       int error = SOCKERRNO;
1247*6236dae4SAndroid Build Coastguard Worker       char buffer[STRERROR_LEN];
1248*6236dae4SAndroid Build Coastguard Worker       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1249*6236dae4SAndroid Build Coastguard Worker       state->event = TFTP_EVENT_ERROR;
1250*6236dae4SAndroid Build Coastguard Worker     }
1251*6236dae4SAndroid Build Coastguard Worker     else if(rc) {
1252*6236dae4SAndroid Build Coastguard Worker       result = tftp_receive_packet(data);
1253*6236dae4SAndroid Build Coastguard Worker       if(result)
1254*6236dae4SAndroid Build Coastguard Worker         return result;
1255*6236dae4SAndroid Build Coastguard Worker       result = tftp_state_machine(state, state->event);
1256*6236dae4SAndroid Build Coastguard Worker       if(result)
1257*6236dae4SAndroid Build Coastguard Worker         return result;
1258*6236dae4SAndroid Build Coastguard Worker       *done = (state->state == TFTP_STATE_FIN);
1259*6236dae4SAndroid Build Coastguard Worker       if(*done)
1260*6236dae4SAndroid Build Coastguard Worker         /* Tell curl we are done */
1261*6236dae4SAndroid Build Coastguard Worker         Curl_xfer_setup_nop(data);
1262*6236dae4SAndroid Build Coastguard Worker     }
1263*6236dae4SAndroid Build Coastguard Worker     /* if rc == 0, then select() timed out */
1264*6236dae4SAndroid Build Coastguard Worker   }
1265*6236dae4SAndroid Build Coastguard Worker 
1266*6236dae4SAndroid Build Coastguard Worker   return result;
1267*6236dae4SAndroid Build Coastguard Worker }
1268*6236dae4SAndroid Build Coastguard Worker 
1269*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1270*6236dae4SAndroid Build Coastguard Worker  *
1271*6236dae4SAndroid Build Coastguard Worker  * tftp_doing
1272*6236dae4SAndroid Build Coastguard Worker  *
1273*6236dae4SAndroid Build Coastguard Worker  * Called from multi.c while DOing
1274*6236dae4SAndroid Build Coastguard Worker  *
1275*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_doing(struct Curl_easy * data,bool * dophase_done)1276*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1277*6236dae4SAndroid Build Coastguard Worker {
1278*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1279*6236dae4SAndroid Build Coastguard Worker   result = tftp_multi_statemach(data, dophase_done);
1280*6236dae4SAndroid Build Coastguard Worker 
1281*6236dae4SAndroid Build Coastguard Worker   if(*dophase_done) {
1282*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "DO phase is complete"));
1283*6236dae4SAndroid Build Coastguard Worker   }
1284*6236dae4SAndroid Build Coastguard Worker   else if(!result) {
1285*6236dae4SAndroid Build Coastguard Worker     /* The multi code does not have this logic for the DOING state so we
1286*6236dae4SAndroid Build Coastguard Worker        provide it for TFTP since it may do the entire transfer in this
1287*6236dae4SAndroid Build Coastguard Worker        state. */
1288*6236dae4SAndroid Build Coastguard Worker     if(Curl_pgrsUpdate(data))
1289*6236dae4SAndroid Build Coastguard Worker       result = CURLE_ABORTED_BY_CALLBACK;
1290*6236dae4SAndroid Build Coastguard Worker     else
1291*6236dae4SAndroid Build Coastguard Worker       result = Curl_speedcheck(data, Curl_now());
1292*6236dae4SAndroid Build Coastguard Worker   }
1293*6236dae4SAndroid Build Coastguard Worker   return result;
1294*6236dae4SAndroid Build Coastguard Worker }
1295*6236dae4SAndroid Build Coastguard Worker 
1296*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1297*6236dae4SAndroid Build Coastguard Worker  *
1298*6236dae4SAndroid Build Coastguard Worker  * tftp_perform
1299*6236dae4SAndroid Build Coastguard Worker  *
1300*6236dae4SAndroid Build Coastguard Worker  * Entry point for transfer from tftp_do, starts state mach
1301*6236dae4SAndroid Build Coastguard Worker  *
1302*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
tftp_perform(struct Curl_easy * data,bool * dophase_done)1303*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1304*6236dae4SAndroid Build Coastguard Worker {
1305*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1306*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1307*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state = conn->proto.tftpc;
1308*6236dae4SAndroid Build Coastguard Worker 
1309*6236dae4SAndroid Build Coastguard Worker   *dophase_done = FALSE;
1310*6236dae4SAndroid Build Coastguard Worker 
1311*6236dae4SAndroid Build Coastguard Worker   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1312*6236dae4SAndroid Build Coastguard Worker 
1313*6236dae4SAndroid Build Coastguard Worker   if((state->state == TFTP_STATE_FIN) || result)
1314*6236dae4SAndroid Build Coastguard Worker     return result;
1315*6236dae4SAndroid Build Coastguard Worker 
1316*6236dae4SAndroid Build Coastguard Worker   tftp_multi_statemach(data, dophase_done);
1317*6236dae4SAndroid Build Coastguard Worker 
1318*6236dae4SAndroid Build Coastguard Worker   if(*dophase_done)
1319*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "DO phase is complete"));
1320*6236dae4SAndroid Build Coastguard Worker 
1321*6236dae4SAndroid Build Coastguard Worker   return result;
1322*6236dae4SAndroid Build Coastguard Worker }
1323*6236dae4SAndroid Build Coastguard Worker 
1324*6236dae4SAndroid Build Coastguard Worker 
1325*6236dae4SAndroid Build Coastguard Worker /**********************************************************
1326*6236dae4SAndroid Build Coastguard Worker  *
1327*6236dae4SAndroid Build Coastguard Worker  * tftp_do
1328*6236dae4SAndroid Build Coastguard Worker  *
1329*6236dae4SAndroid Build Coastguard Worker  * The do callback
1330*6236dae4SAndroid Build Coastguard Worker  *
1331*6236dae4SAndroid Build Coastguard Worker  * This callback initiates the TFTP transfer
1332*6236dae4SAndroid Build Coastguard Worker  *
1333*6236dae4SAndroid Build Coastguard Worker  **********************************************************/
1334*6236dae4SAndroid Build Coastguard Worker 
tftp_do(struct Curl_easy * data,bool * done)1335*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1336*6236dae4SAndroid Build Coastguard Worker {
1337*6236dae4SAndroid Build Coastguard Worker   struct tftp_state_data *state;
1338*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1339*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1340*6236dae4SAndroid Build Coastguard Worker 
1341*6236dae4SAndroid Build Coastguard Worker   *done = FALSE;
1342*6236dae4SAndroid Build Coastguard Worker 
1343*6236dae4SAndroid Build Coastguard Worker   if(!conn->proto.tftpc) {
1344*6236dae4SAndroid Build Coastguard Worker     result = tftp_connect(data, done);
1345*6236dae4SAndroid Build Coastguard Worker     if(result)
1346*6236dae4SAndroid Build Coastguard Worker       return result;
1347*6236dae4SAndroid Build Coastguard Worker   }
1348*6236dae4SAndroid Build Coastguard Worker 
1349*6236dae4SAndroid Build Coastguard Worker   state = conn->proto.tftpc;
1350*6236dae4SAndroid Build Coastguard Worker   if(!state)
1351*6236dae4SAndroid Build Coastguard Worker     return CURLE_TFTP_ILLEGAL;
1352*6236dae4SAndroid Build Coastguard Worker 
1353*6236dae4SAndroid Build Coastguard Worker   result = tftp_perform(data, done);
1354*6236dae4SAndroid Build Coastguard Worker 
1355*6236dae4SAndroid Build Coastguard Worker   /* If tftp_perform() returned an error, use that for return code. If it
1356*6236dae4SAndroid Build Coastguard Worker      was OK, see if tftp_translate_code() has an error. */
1357*6236dae4SAndroid Build Coastguard Worker   if(!result)
1358*6236dae4SAndroid Build Coastguard Worker     /* If we have encountered an internal tftp error, translate it. */
1359*6236dae4SAndroid Build Coastguard Worker     result = tftp_translate_code(state->error);
1360*6236dae4SAndroid Build Coastguard Worker 
1361*6236dae4SAndroid Build Coastguard Worker   return result;
1362*6236dae4SAndroid Build Coastguard Worker }
1363*6236dae4SAndroid Build Coastguard Worker 
tftp_setup_connection(struct Curl_easy * data,struct connectdata * conn)1364*6236dae4SAndroid Build Coastguard Worker static CURLcode tftp_setup_connection(struct Curl_easy *data,
1365*6236dae4SAndroid Build Coastguard Worker                                       struct connectdata *conn)
1366*6236dae4SAndroid Build Coastguard Worker {
1367*6236dae4SAndroid Build Coastguard Worker   char *type;
1368*6236dae4SAndroid Build Coastguard Worker 
1369*6236dae4SAndroid Build Coastguard Worker   conn->transport = TRNSPRT_UDP;
1370*6236dae4SAndroid Build Coastguard Worker 
1371*6236dae4SAndroid Build Coastguard Worker   /* TFTP URLs support an extension like ";mode=<typecode>" that
1372*6236dae4SAndroid Build Coastguard Worker    * we will try to get now! */
1373*6236dae4SAndroid Build Coastguard Worker   type = strstr(data->state.up.path, ";mode=");
1374*6236dae4SAndroid Build Coastguard Worker 
1375*6236dae4SAndroid Build Coastguard Worker   if(!type)
1376*6236dae4SAndroid Build Coastguard Worker     type = strstr(conn->host.rawalloc, ";mode=");
1377*6236dae4SAndroid Build Coastguard Worker 
1378*6236dae4SAndroid Build Coastguard Worker   if(type) {
1379*6236dae4SAndroid Build Coastguard Worker     char command;
1380*6236dae4SAndroid Build Coastguard Worker     *type = 0;                   /* it was in the middle of the hostname */
1381*6236dae4SAndroid Build Coastguard Worker     command = Curl_raw_toupper(type[6]);
1382*6236dae4SAndroid Build Coastguard Worker 
1383*6236dae4SAndroid Build Coastguard Worker     switch(command) {
1384*6236dae4SAndroid Build Coastguard Worker     case 'A': /* ASCII mode */
1385*6236dae4SAndroid Build Coastguard Worker     case 'N': /* NETASCII mode */
1386*6236dae4SAndroid Build Coastguard Worker       data->state.prefer_ascii = TRUE;
1387*6236dae4SAndroid Build Coastguard Worker       break;
1388*6236dae4SAndroid Build Coastguard Worker 
1389*6236dae4SAndroid Build Coastguard Worker     case 'O': /* octet mode */
1390*6236dae4SAndroid Build Coastguard Worker     case 'I': /* binary mode */
1391*6236dae4SAndroid Build Coastguard Worker     default:
1392*6236dae4SAndroid Build Coastguard Worker       /* switch off ASCII */
1393*6236dae4SAndroid Build Coastguard Worker       data->state.prefer_ascii = FALSE;
1394*6236dae4SAndroid Build Coastguard Worker       break;
1395*6236dae4SAndroid Build Coastguard Worker     }
1396*6236dae4SAndroid Build Coastguard Worker   }
1397*6236dae4SAndroid Build Coastguard Worker 
1398*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1399*6236dae4SAndroid Build Coastguard Worker }
1400*6236dae4SAndroid Build Coastguard Worker #endif
1401