1 //==========================================================================
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Andrew.Lunn@ascom.ch
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas, andrew.lunn@ascom.ch
51 //####DESCRIPTIONEND####
53 //==========================================================================
55 // TFTP client support
58 #include <arpa/tftp.h>
59 #include <tftp_support.h>
63 #define min(x,y) (x<y ? x : y)
66 // Read a file from a host into a local buffer. Returns the
67 // number of bytes actually read, or (-1) if an error occurs.
68 // On error, *err will hold the reason.
69 // This version uses the server name. This can be a name for DNS lookup
70 // or a dotty or colony number format for IPv4 or IPv6.
71 static int tftp_client_get_inner(char *data,
72 const char * const filename,
73 const char * const server,
79 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
87 int actual_len, data_len;
88 socklen_t from_len, recv_len;
89 static int get_port = 7700;
90 struct addrinfo * addrinfo;
91 struct addrinfo * res;
92 struct addrinfo hints;
95 struct sockaddr local_addr, from_addr;
96 struct tftphdr *hdr = (struct tftphdr *)data;
99 struct timeval timeout;
100 unsigned short last_good_block = 0;
102 int total_timeouts = 0;
104 *err = 0; // Just in case
106 // Create initial request
107 hdr->th_opcode = htons(RRQ); // Read file
108 cp = (char *)&hdr->th_stuff;
110 while (*fp) *cp++ = *fp++;
112 if (mode == TFTP_NETASCII) {
114 } else if (mode == TFTP_OCTET) {
120 while (*fp) *cp++ = *fp++;
122 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
128 cp+=sprintf(cp, "%d", CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET_SIZE);
133 memset(&hints,0,sizeof(hints));
134 hints.ai_family = PF_UNSPEC;
135 error = getaddrinfo(server, "tftp", &hints, &res);
143 s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
144 addrinfo->ai_protocol);
146 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
147 switch(addrinfo->ai_addr->sa_family) {
149 struct sockaddr_in * saddr =
150 (struct sockaddr_in *) addrinfo->ai_addr;
151 struct sockaddr_in * laddr =
152 (struct sockaddr_in *) &local_addr;
154 saddr->sin_port = htons(port);
156 laddr->sin_port = htons(get_port++);
157 laddr->sin_addr.s_addr = INADDR_ANY;
160 #ifdef CYGPKG_NET_INET6
162 struct sockaddr_in6 * saddr =
163 (struct sockaddr_in6 *) addrinfo->ai_addr;
164 struct sockaddr_in6 * laddr =
165 (struct sockaddr_in6 *) &local_addr;
167 saddr->sin6_port = htons(port);
169 laddr->sin6_port = htons(get_port++);
170 laddr->sin6_addr = in6addr_any;
179 if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
185 if (sendto(s, data, (int)(cp-data), 0,
187 addrinfo->ai_addrlen) < 0) {
188 // Problem sending request
196 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
200 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
202 if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) {
203 // Timeout - no data received. Probably no server.
207 if (total_timeouts > TFTP_TIMEOUT_MAX) {
208 // Timeout - have received data. Network problem?
213 if (last_good_block == 0 ) {
215 if (sendto(s, data, (int)(cp-data), 0,
217 addrinfo->ai_addrlen) < 0) {
218 // Problem sending request
223 // Try resending last ACK
224 hdr->th_opcode = htons(ACK);
225 hdr->th_block = htons(last_good_block);
226 if (sendto(s, data, 4 /* FIXME */, 0,
227 &from_addr, from_len) < 0) {
228 // Problem sending request
234 recv_len = blksize+sizeof(struct tftphdr);
235 from_len = sizeof(from_addr);
236 if ((data_len = recvfrom(s, data, recv_len, 0,
237 &from_addr, &from_len)) < 0) {
242 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
243 if (ntohs(hdr->th_opcode) == OACK) {
244 // We can have only *one* option, the one we sent..
245 if (strncmp(data+2, "blksize", data_len)==0) {
246 blksize=atol(data+2+strlen("blksize")+1);
248 // option ignored, use default.
251 hdr->th_opcode = htons(ACK);
252 hdr->th_block = htons(last_good_block);
253 if (sendto(s, data, 4 /* FIXME */, 0,
254 &from_addr, from_len) < 0) {
255 // Problem sending request
261 if (ntohs(hdr->th_opcode) == DATA) {
263 if (ntohs(hdr->th_block) == (last_good_block+1)) {
266 data_len -= 4; /* Sizeof TFTP header */
267 actual_len = data_len;
268 result += actual_len;
272 *err = TFTP_TOOLARGE;
275 memcpy(bp, cp, data_len);
280 // To prevent an out-of-sequence packet from
281 // terminating transmission prematurely, set
282 // actual_len to a full size packet.
283 actual_len = blksize;
286 hdr->th_opcode = htons(ACK);
287 hdr->th_block = htons(last_good_block);
288 if (sendto(s, data, 4 /* FIXME */, 0,
289 &from_addr, from_len) < 0) {
290 // Problem sending request
294 // A short packet marks the end of the file.
295 /* 4 = Sizeof TFTP header */
296 if ((actual_len >= 0) && (actual_len < blksize)) {
303 if (ntohs(hdr->th_opcode) == ERROR) {
304 *err = ntohs(hdr->th_code);
307 // What kind of packet is this?
308 *err = TFTP_PROTOCOL;
314 // If we got here, it means there was a problem connecting to the
315 // server. Try the next address returned by getaddrinfo
320 addrinfo=addrinfo->ai_next;
322 // We ran into problems. Cleanup
332 int tftp_client_get(const char * const filename,
333 const char * const server,
340 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
341 char *data = malloc(CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET_SIZE+
342 sizeof(struct tftphdr));
348 char data[SEGSIZE+sizeof(struct tftphdr)];
350 result=tftp_client_get_inner(data, filename, server,
351 port, buf, len, mode, err
352 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
358 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
359 // try without negotiating packet size. The serves that do
360 // not support options negotiation may or may not ignore the
361 // options. If they return an error in the case of options
362 // this code path will try without packet size negotiation.
363 result=tftp_client_get_inner(data, filename, server,
364 port, buf, len, mode, err,
369 #ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
377 // Read a file from a host into a local buffer. Returns the
378 // number of bytes actually read, or (-1) if an error occurs.
379 // On error, *err will hold the reason.
381 // Depreciated. Use tftp_client_get instead.
383 tftp_get(const char * const filename,
384 const struct sockaddr_in * const server,
390 char server_name[20];
394 ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
395 server_name, sizeof(server_name));
400 port = server->sin_port;
402 return tftp_client_get(filename, server_name, port, buf, len, mode, err);
406 // Send data to a file on a server via TFTP.
409 tftp_put(const char * const filename,
410 const struct sockaddr_in * const server,
416 char server_name[20];
420 ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
421 server_name, sizeof(server_name));
426 port = server->sin_port;
428 return tftp_client_put(filename, server_name, port, buf, len, mode, err);
432 // Put a file to a host from a local buffer. Returns the
433 // number of bytes actually writen, or (-1) if an error occurs.
434 // On error, *err will hold the reason.
435 // This version uses the server name. This can be a name for DNS lookup
436 // or a dotty or colony number format for IPv4 or IPv6.
437 int tftp_client_put(const char * const filename,
438 const char * const server,
446 int s = -1, actual_len, data_len;
447 socklen_t recv_len, from_len;
448 static int put_port = 7800;
449 struct sockaddr local_addr, from_addr;
450 char data[SEGSIZE+sizeof(struct tftphdr)];
451 struct tftphdr *hdr = (struct tftphdr *)data;
452 const char *fp, *sfp;
454 struct timeval timeout;
455 unsigned short last_good_block = 0;
457 int total_timeouts = 0;
458 struct addrinfo hints;
459 struct addrinfo * addrinfo;
460 struct addrinfo * res;
463 *err = 0; // Just in case
465 memset(&hints,0,sizeof(hints));
466 hints.ai_family = PF_UNSPEC;
467 error = getaddrinfo(server, "tftp", &hints, &res);
475 s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
476 addrinfo->ai_protocol);
478 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
479 switch(addrinfo->ai_addr->sa_family) {
481 struct sockaddr_in * saddr =
482 (struct sockaddr_in *) addrinfo->ai_addr;
483 struct sockaddr_in * laddr =
484 (struct sockaddr_in *) &local_addr;
486 saddr->sin_port = htons(port);
488 laddr->sin_port = htons(put_port++);
489 laddr->sin_addr.s_addr = INADDR_ANY;
492 #ifdef CYGPKG_NET_INET6
494 struct sockaddr_in6 * saddr =
495 (struct sockaddr_in6 *) addrinfo->ai_addr;
496 struct sockaddr_in6 * laddr =
497 (struct sockaddr_in6 *) &local_addr;
499 saddr->sin6_port = htons(port);
501 laddr->sin6_port = htons(put_port++);
502 laddr->sin6_addr = in6addr_any;
511 (struct sockaddr *)&local_addr,
512 addrinfo->ai_addrlen) < 0) {
513 // Problem setting up my end
519 // Create initial request
520 hdr->th_opcode = htons(WRQ); // Create/write file
521 cp = (char *)&hdr->th_stuff;
523 while (*fp) *cp++ = *fp++;
525 if (mode == TFTP_NETASCII) {
527 } else if (mode == TFTP_OCTET) {
533 while (*fp) *cp++ = *fp++;
536 if (sendto(s, data, (int)(cp-data), 0,
538 addrinfo->ai_addrlen) < 0) {
539 // Problem sending request
544 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
548 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
549 if (++total_timeouts > TFTP_RETRIES_MAX) {
550 // Timeout - no ACK received
555 recv_len = sizeof(data);
556 from_len = sizeof(from_addr);
557 if ((data_len = recvfrom(s, &data, recv_len, 0,
558 &from_addr, &from_len)) < 0) {
563 if (ntohs(hdr->th_opcode) == ACK) {
564 // Write request accepted - start sending data
567 if (ntohs(hdr->th_opcode) == ERROR) {
568 *err = ntohs(hdr->th_code);
571 // What kind of packet is this?
580 while (result < len) {
581 // Build packet of data to send
582 data_len = min(SEGSIZE, len-result);
583 hdr->th_opcode = htons(DATA);
584 hdr->th_block = htons(last_good_block);
587 actual_len = data_len + 4;
588 // FIXME - what about "netascii" data?
589 while (data_len-- > 0) *cp++ = *fp++;
591 if (sendto(s, data, actual_len, 0,
592 &from_addr, from_len) < 0) {
593 // Problem sending request
598 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
602 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
603 if (++total_timeouts > TFTP_TIMEOUT_MAX) {
604 // Timeout - no data received
609 recv_len = sizeof(data);
610 from_len = sizeof(from_addr);
611 if ((data_len = recvfrom(s, &data, recv_len, 0,
612 &from_addr, &from_len)) < 0) {
617 if (ntohs(hdr->th_opcode) == ACK) {
618 if (ntohs(hdr->th_block) == last_good_block) {
619 // Advance pointers, etc
621 result += (actual_len - 4);
624 diag_printf("Send block #%d, got ACK for #%d\n",
625 last_good_block, ntohs(hdr->th_block));
628 if (ntohs(hdr->th_opcode) == ERROR) {
629 *err = ntohs(hdr->th_code);
632 // What kind of packet is this?
633 *err = TFTP_PROTOCOL;
642 // If we got here, it means there was a problem connecting to the
643 // server. Try the next address returned by getaddrinfo
648 addrinfo=addrinfo->ai_next;
650 // We ran into problems. Cleanup