Mercurial > ecos
annotate packages/net/common/current/src/tftp_client.c @ 957:db3e0a2fda2f
2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_loopback_interface): Close the
socket when things go wrong otherwise we leak sockets.
* src/tftp_server.c (tftpd_server): Added support for IPv6 as well
as IPv4. Extended the multithreading support so that it works
correctly when there are multiple servers on multiple ports.
* doc/tcpip.sgml: Documentation for the changes made to the tftp
server.
2003-04-10 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_all_network_interfaces): Wait upto 4
seconds for a router solicit message to be received. Once we have
received the message we know we have a valid IPv6 address.
* src/tftp_client.c: Added support for IPv6. This requires two new
functions, tftp_client_{get|put} which are protocol version
independent.
* tests/tftp_client_test.c (tftp_test): Added tests which use IPv6
addresses.
2003-04-07 Andrew Lunn <andrew.lunn@ascom.ch>
* src/getaddrinfo.c (getaddrinfo): Correctly deal with node when
its not NULL. Its OK for the address to not parse for an address
family when AF_UNSPEC is passed in hints. Also get the socktype
correct when wildcarding for services that use UDP.
* tests/addr_test.c: Added more test cases which test IP addresses
in number format as node.
2003-04-05 Andrew Lunn <andrew.lunn@ascom.ch>
* cdl/net.cdl: Added addr_tests to the HW tests.
* tests/addr_test.c (net_test): void function not int.
* tests/ping_test.c (net_test): Added IPv6 ping test. This pings
the router which answers our router solicit message.
* src/ipv6_routing_thread.c (cyg_rs): Print out the router
advertisement message. Cleaned up the debug messages so they can
be disabled.
* src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New
function to return the address of the router.
* include/network.h: Added prototype for above and
ipv6_start_routing_thread which did not have a prototype.
* src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before
sending the first solicit request rather than 10.
* src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq
before using it. If the request fails finish the IPv4 code rather
than returning,.
2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch>
* tests/ping_lo_test.c: Added IPv6 ping test.
* src/getproto.c: Added the protocol ipv6-icmp.
| author | asl |
|---|---|
| date | Wed, 23 Apr 2003 08:52:08 +0000 |
| parents | a440f07b6d29 |
| children | 16d247bb9c70 |
| rev | line source |
|---|---|
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
1 //========================================================================== |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
2 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
3 // lib/tftp_client.c |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
4 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
5 // TFTP client support |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
6 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
7 //========================================================================== |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
8 //####ECOSGPLCOPYRIGHTBEGIN#### |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
9 // ------------------------------------------- |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
10 // This file is part of eCos, the Embedded Configurable Operating System. |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
| 957 | 12 // Copyright (C) 2003 Andrew.Lunn@ascom.ch |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
13 // |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
14 // eCos is free software; you can redistribute it and/or modify it under |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
15 // the terms of the GNU General Public License as published by the Free |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
16 // Software Foundation; either version 2 or (at your option) any later version. |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
17 // |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
21 // for more details. |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
22 // |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
23 // You should have received a copy of the GNU General Public License along |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
24 // with eCos; if not, write to the Free Software Foundation, Inc., |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
26 // |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
27 // As a special exception, if other files instantiate templates or use macros |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
28 // or inline functions from this file, or you compile this file and link it |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
29 // with other works to produce a work based on this file, this file does not |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
30 // by itself cause the resulting work to be covered by the GNU General Public |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
31 // License. However the source code for this file must still be made available |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
32 // in accordance with section (3) of the GNU General Public License. |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
33 // |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
34 // This exception does not invalidate any other reasons why a work based on |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
35 // this file might be covered by the GNU General Public License. |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
36 // |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
38 // at http://sources.redhat.com/ecos/ecos-license/ |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
39 // ------------------------------------------- |
|
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
40 //####ECOSGPLCOPYRIGHTEND#### |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
41 //========================================================================== |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
42 //#####DESCRIPTIONBEGIN#### |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
43 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
44 // Author(s): gthomas |
| 957 | 45 // Contributors: gthomas, andrew.lunn@ascom.ch |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
46 // Date: 2000-04-06 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
47 // Purpose: |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
48 // Description: |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
49 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
50 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
51 //####DESCRIPTIONEND#### |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
52 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
53 //========================================================================== |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
54 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
55 // TFTP client support |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
56 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
57 #include <network.h> |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
58 #include <arpa/tftp.h> |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
59 #include <tftp_support.h> |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
60 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
61 #define min(x,y) (x<y ? x : y) |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
62 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
63 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
64 // Read a file from a host into a local buffer. Returns the |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
65 // number of bytes actually read, or (-1) if an error occurs. |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
66 // On error, *err will hold the reason. |
| 957 | 67 // This version uses the server name. This can be a name for DNS lookup |
| 68 // or a dotty or colony number format for IPv4 or IPv6. | |
| 69 int tftp_client_get(char *filename, | |
| 70 char *server, | |
| 71 int port, | |
| 72 char *buf, | |
| 73 int len, | |
| 74 int mode, | |
| 75 int *err) { | |
| 76 | |
| 77 int result = 0; | |
| 78 int s=-1; | |
| 79 int actual_len, data_len, recv_len, from_len; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
80 static int get_port = 7700; |
| 957 | 81 struct addrinfo * addrinfo; |
| 82 struct addrinfo * res; | |
| 83 struct addrinfo hints; | |
| 84 int error; | |
| 85 | |
| 86 struct sockaddr local_addr, from_addr; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
87 char data[SEGSIZE+sizeof(struct tftphdr)]; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
88 struct tftphdr *hdr = (struct tftphdr *)data; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
89 char *cp, *fp; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
90 struct timeval timeout; |
| 270 | 91 unsigned short last_good_block = 0; |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
92 fd_set fds; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
93 int total_timeouts = 0; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
94 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
95 *err = 0; // Just in case |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
96 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
97 // Create initial request |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
98 hdr->th_opcode = htons(RRQ); // Read file |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
99 cp = (char *)&hdr->th_stuff; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
100 fp = filename; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
101 while (*fp) *cp++ = *fp++; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
102 *cp++ = '\0'; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
103 if (mode == TFTP_NETASCII) { |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
104 fp = "NETASCII"; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
105 } else if (mode == TFTP_OCTET) { |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
106 fp = "OCTET"; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
107 } else { |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
108 *err = TFTP_INVALID; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
109 return -1; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
110 } |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
111 while (*fp) *cp++ = *fp++; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
112 *cp++ = '\0'; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
113 |
| 957 | 114 memset(&hints,0,sizeof(hints)); |
| 115 hints.ai_family = PF_UNSPEC; | |
| 116 error = getaddrinfo(server, "tftp", &hints, &res); | |
| 117 if (error) { | |
| 118 *err = TFTP_NETERR; | |
| 119 return -1; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
120 } |
| 957 | 121 |
| 122 addrinfo = res; | |
| 123 while (addrinfo) { | |
| 124 s = socket(addrinfo->ai_family, addrinfo->ai_socktype, | |
| 125 addrinfo->ai_protocol); | |
| 126 if (s >= 0) { | |
| 127 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); | |
| 128 switch(addrinfo->ai_addr->sa_family) { | |
| 129 case AF_INET: { | |
| 130 struct sockaddr_in * saddr = | |
| 131 (struct sockaddr_in *) addrinfo->ai_addr; | |
| 132 struct sockaddr_in * laddr = | |
| 133 (struct sockaddr_in *) &local_addr; | |
| 134 if (port) { | |
| 135 saddr->sin_port = htons(port); | |
| 136 } | |
| 137 laddr->sin_port = htons(get_port++); | |
| 138 laddr->sin_addr.s_addr = INADDR_ANY; | |
| 139 break; | |
| 140 } | |
| 141 #ifdef CYGPKG_NET_INET6 | |
| 142 case AF_INET6: { | |
| 143 struct sockaddr_in6 * saddr = | |
| 144 (struct sockaddr_in6 *) addrinfo->ai_addr; | |
| 145 struct sockaddr_in6 * laddr = | |
| 146 (struct sockaddr_in6 *) &local_addr; | |
| 147 if (port) { | |
| 148 saddr->sin6_port = htons(port); | |
| 149 } | |
| 150 laddr->sin6_port = htons(get_port++); | |
| 151 laddr->sin6_addr = in6addr_any; | |
| 152 break; | |
| 153 } | |
| 154 #endif | |
| 155 default: | |
| 156 *err = TFTP_NETERR; | |
| 157 goto out; | |
| 158 } | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
159 |
| 957 | 160 if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) { |
| 161 *err = TFTP_NETERR; | |
| 162 goto out; | |
| 163 } | |
| 164 | |
| 165 // Send request | |
| 166 if (sendto(s, data, (int)(cp-data), 0, | |
| 167 addrinfo->ai_addr, | |
| 168 addrinfo->ai_addrlen) < 0) { | |
| 169 // Problem sending request | |
| 170 *err = TFTP_NETERR; | |
| 171 goto nextaddr; | |
| 172 } | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
173 |
| 957 | 174 // Read data |
| 175 fp = buf; | |
| 176 while (true) { | |
| 177 timeout.tv_sec = TFTP_TIMEOUT_PERIOD; | |
| 178 timeout.tv_usec = 0; | |
| 179 FD_ZERO(&fds); | |
| 180 FD_SET(s, &fds); | |
| 181 if (select(s+1, &fds, 0, 0, &timeout) <= 0) { | |
| 182 if ((++total_timeouts > TFTP_TIMEOUT_MAX) | |
| 183 || (last_good_block == 0)) { | |
| 184 // Timeout - no data received | |
| 185 *err = TFTP_TIMEOUT; | |
| 186 goto out; | |
| 187 } | |
| 188 // Try resending last ACK | |
| 189 hdr->th_opcode = htons(ACK); | |
| 190 hdr->th_block = htons(last_good_block); | |
| 191 if (sendto(s, data, 4 /* FIXME */, 0, | |
| 192 &from_addr, from_len) < 0) { | |
| 193 // Problem sending request | |
| 194 *err = TFTP_NETERR; | |
| 195 goto out; | |
| 196 } | |
| 197 } else { | |
| 198 recv_len = sizeof(data); | |
| 199 from_len = sizeof(from_addr); | |
| 200 if ((data_len = recvfrom(s, &data, recv_len, 0, | |
| 201 &from_addr, &from_len)) < 0) { | |
| 202 // What happened? | |
| 203 *err = TFTP_NETERR; | |
| 204 goto out; | |
| 205 } | |
| 206 if (ntohs(hdr->th_opcode) == DATA) { | |
| 207 actual_len = 0; | |
| 208 if (ntohs(hdr->th_block) == (last_good_block+1)) { | |
| 209 // Consume this data | |
| 210 cp = hdr->th_data; | |
| 211 data_len -= 4; /* Sizeof TFTP header */ | |
| 212 actual_len = data_len; | |
| 213 result += actual_len; | |
| 214 while (data_len-- > 0) { | |
| 215 if (len-- > 0) { | |
| 216 *fp++ = *cp++; | |
| 217 } else { | |
| 218 // Buffer overflow | |
| 219 *err = TFTP_TOOLARGE; | |
| 220 goto out; | |
| 221 } | |
| 222 } | |
| 223 last_good_block++; | |
| 224 } | |
| 225 // Send out the ACK | |
| 226 hdr->th_opcode = htons(ACK); | |
| 227 hdr->th_block = htons(last_good_block); | |
| 228 if (sendto(s, data, 4 /* FIXME */, 0, | |
| 229 &from_addr, from_len) < 0) { | |
| 230 // Problem sending request | |
| 231 *err = TFTP_NETERR; | |
| 232 goto out; | |
| 233 } | |
| 234 if ((actual_len >= 0) && (actual_len < SEGSIZE)) { | |
| 235 // End of data | |
| 236 close(s); | |
| 237 freeaddrinfo(res); | |
| 238 return result; | |
| 239 } | |
| 240 } else | |
| 241 if (ntohs(hdr->th_opcode) == ERROR) { | |
| 242 *err = ntohs(hdr->th_code); | |
| 243 goto out; | |
| 244 } else { | |
| 245 // What kind of packet is this? | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
246 *err = TFTP_PROTOCOL; |
| 957 | 247 goto out; |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 } | |
| 252 // If we got here, it means there was a problem connecting to the | |
| 253 // server. Try the next address returned by getaddrinfo | |
| 254 nextaddr: | |
| 255 if (-1 != s) { | |
| 256 close(s); | |
| 257 } | |
| 258 addrinfo=addrinfo->ai_next; | |
| 259 } | |
| 260 // We ran into problems. Cleanup | |
| 261 out: | |
| 262 if (-1 != s) { | |
| 263 close (s); | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
264 } |
| 957 | 265 freeaddrinfo(res); |
| 266 return -1; | |
| 267 } | |
| 268 // | |
| 269 // Read a file from a host into a local buffer. Returns the | |
| 270 // number of bytes actually read, or (-1) if an error occurs. | |
| 271 // On error, *err will hold the reason. | |
| 272 // | |
| 273 // Depreciated. Use tftp_client_get instead. | |
| 274 int | |
| 275 tftp_get(char *filename, | |
| 276 struct sockaddr_in *server, | |
| 277 char *buf, | |
| 278 int len, | |
| 279 int mode, | |
| 280 int *err) | |
| 281 { | |
| 282 char server_name[20]; | |
| 283 char *ret; | |
| 284 int port; | |
| 285 | |
| 286 ret = inet_ntop(AF_INET, (void *)&server->sin_addr, | |
| 287 server_name, sizeof(server_name)); | |
| 288 if (NULL == ret) { | |
| 289 *err = TFTP_NETERR; | |
| 290 return -1; | |
| 291 } | |
| 292 port = server->sin_port; | |
| 293 | |
| 294 return tftp_client_get(filename, server_name, port, buf, len, mode, err); | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
295 } |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
296 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
297 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
298 // Send data to a file on a server via TFTP. |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
299 // |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
300 int |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
301 tftp_put(char *filename, |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
302 struct sockaddr_in *server, |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
303 char *buf, |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
304 int len, |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
305 int mode, |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
306 int *err) |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
307 { |
| 957 | 308 char server_name[20]; |
| 309 char *ret; | |
| 310 int port; | |
| 311 | |
| 312 ret = inet_ntop(AF_INET, (void *)&server->sin_addr, | |
| 313 server_name, sizeof(server_name)); | |
| 314 if (NULL == ret) { | |
| 315 *err = TFTP_NETERR; | |
| 316 return -1; | |
| 317 } | |
| 318 port = server->sin_port; | |
| 319 | |
| 320 return tftp_client_put(filename, server_name, port, buf, len, mode, err); | |
| 321 } | |
| 322 | |
| 323 // | |
| 324 // Put a file to a host from a local buffer. Returns the | |
| 325 // number of bytes actually writen, or (-1) if an error occurs. | |
| 326 // On error, *err will hold the reason. | |
| 327 // This version uses the server name. This can be a name for DNS lookup | |
| 328 // or a dotty or colony number format for IPv4 or IPv6. | |
| 329 int tftp_client_put(char *filename, | |
| 330 char *server, | |
| 331 int port, | |
| 332 char *buf, | |
| 333 int len, | |
| 334 int mode, | |
| 335 int *err) { | |
| 336 | |
| 337 int result = 0; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
338 int s, actual_len, data_len, recv_len, from_len; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
339 static int put_port = 7800; |
| 957 | 340 struct sockaddr local_addr, from_addr; |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
341 char data[SEGSIZE+sizeof(struct tftphdr)]; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
342 struct tftphdr *hdr = (struct tftphdr *)data; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
343 char *cp, *fp, *sfp; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
344 struct timeval timeout; |
| 270 | 345 unsigned short last_good_block = 0; |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
346 fd_set fds; |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
347 int total_timeouts = 0; |
| 957 | 348 struct addrinfo hints; |
| 349 struct addrinfo * addrinfo; | |
| 350 struct addrinfo * res; | |
| 351 int error; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
352 |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
353 *err = 0; // Just in case |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
354 |
| 957 | 355 memset(&hints,0,sizeof(hints)); |
| 356 hints.ai_family = PF_UNSPEC; | |
| 357 error = getaddrinfo(server, "tftp", &hints, &res); | |
| 358 if (error) { | |
| 359 *err = TFTP_NETERR; | |
| 360 return -1; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
361 } |
| 957 | 362 |
| 363 addrinfo = res; | |
| 364 while (addrinfo) { | |
| 365 s = socket(addrinfo->ai_family, addrinfo->ai_socktype, | |
| 366 addrinfo->ai_protocol); | |
| 367 if (s >= 0) { | |
| 368 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); | |
| 369 switch(addrinfo->ai_addr->sa_family) { | |
| 370 case AF_INET: { | |
| 371 struct sockaddr_in * saddr = | |
| 372 (struct sockaddr_in *) addrinfo->ai_addr; | |
| 373 struct sockaddr_in * laddr = | |
| 374 (struct sockaddr_in *) &local_addr; | |
| 375 if (port) { | |
| 376 saddr->sin_port = htons(port); | |
| 377 } | |
| 378 laddr->sin_port = htons(put_port++); | |
| 379 laddr->sin_addr.s_addr = INADDR_ANY; | |
| 380 break; | |
| 381 } | |
| 382 #ifdef CYGPKG_NET_INET6 | |
| 383 case AF_INET6: { | |
| 384 struct sockaddr_in6 * saddr = | |
| 385 (struct sockaddr_in6 *) addrinfo->ai_addr; | |
| 386 struct sockaddr_in6 * laddr = | |
| 387 (struct sockaddr_in6 *) &local_addr; | |
| 388 if (port) { | |
| 389 saddr->sin6_port = htons(port); | |
| 390 } | |
| 391 laddr->sin6_port = htons(put_port++); | |
| 392 laddr->sin6_addr = in6addr_any; | |
| 393 break; | |
| 394 } | |
| 395 #endif | |
| 396 default: | |
| 397 *err = TFTP_NETERR; | |
| 398 goto out; | |
| 399 } | |
| 400 if (bind(s, | |
| 401 (struct sockaddr *)&local_addr, | |
| 402 addrinfo->ai_addrlen) < 0) { | |
| 403 // Problem setting up my end | |
| 404 *err = TFTP_NETERR; | |
| 405 goto out; | |
| 406 } | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
407 |
| 957 | 408 while (1) { |
| 409 // Create initial request | |
| 410 hdr->th_opcode = htons(WRQ); // Create/write file | |
| 411 cp = (char *)&hdr->th_stuff; | |
| 412 fp = filename; | |
| 413 while (*fp) *cp++ = *fp++; | |
| 414 *cp++ = '\0'; | |
| 415 if (mode == TFTP_NETASCII) { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
416 fp = "NETASCII"; |
| 957 | 417 } else if (mode == TFTP_OCTET) { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
418 fp = "OCTET"; |
| 957 | 419 } else { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
420 *err = TFTP_INVALID; |
| 957 | 421 goto out; |
| 422 } | |
| 423 while (*fp) *cp++ = *fp++; | |
| 424 *cp++ = '\0'; | |
| 425 // Send request | |
| 426 if (sendto(s, data, (int)(cp-data), 0, | |
| 427 addrinfo->ai_addr, | |
| 428 addrinfo->ai_addrlen) < 0) { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
429 // Problem sending request |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
430 *err = TFTP_NETERR; |
| 957 | 431 goto nextaddr; |
| 432 } | |
| 433 // Wait for ACK | |
| 434 timeout.tv_sec = TFTP_TIMEOUT_PERIOD; | |
| 435 timeout.tv_usec = 0; | |
| 436 FD_ZERO(&fds); | |
| 437 FD_SET(s, &fds); | |
| 438 if (select(s+1, &fds, 0, 0, &timeout) <= 0) { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
439 if (++total_timeouts > TFTP_TIMEOUT_MAX) { |
| 957 | 440 // Timeout - no ACK received |
| 441 *err = TFTP_TIMEOUT; | |
| 442 goto nextaddr; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
443 } |
| 957 | 444 } else { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
445 recv_len = sizeof(data); |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
446 from_len = sizeof(from_addr); |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
447 if ((data_len = recvfrom(s, &data, recv_len, 0, |
| 957 | 448 &from_addr, &from_len)) < 0) { |
| 449 // What happened? | |
| 450 *err = TFTP_NETERR; | |
| 451 goto out; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
452 } |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
453 if (ntohs(hdr->th_opcode) == ACK) { |
| 957 | 454 // Write request accepted - start sending data |
| 455 break; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
456 } else |
| 957 | 457 if (ntohs(hdr->th_opcode) == ERROR) { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
458 *err = ntohs(hdr->th_code); |
| 957 | 459 goto out; |
| 460 } else { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
461 // What kind of packet is this? |
| 957 | 462 goto out; |
| 463 } | |
| 464 } | |
| 465 } | |
| 466 | |
| 467 // Send data | |
| 468 sfp = buf; | |
| 469 last_good_block = 1; | |
| 470 while (result < len) { | |
| 471 // Build packet of data to send | |
| 472 data_len = min(SEGSIZE, len-result); | |
| 473 hdr->th_opcode = htons(DATA); | |
| 474 hdr->th_block = htons(last_good_block); | |
| 475 cp = hdr->th_data; | |
| 476 fp = sfp; | |
| 477 actual_len = data_len + 4; | |
| 478 // FIXME - what about "netascii" data? | |
| 479 while (data_len-- > 0) *cp++ = *fp++; | |
| 480 // Send data packet | |
| 481 if (sendto(s, data, actual_len, 0, | |
| 482 &from_addr, from_len) < 0) { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
483 // Problem sending request |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
484 *err = TFTP_NETERR; |
| 957 | 485 goto out; |
| 486 } | |
| 487 // Wait for ACK | |
| 488 timeout.tv_sec = TFTP_TIMEOUT_PERIOD; | |
| 489 timeout.tv_usec = 0; | |
| 490 FD_ZERO(&fds); | |
| 491 FD_SET(s, &fds); | |
| 492 if (select(s+1, &fds, 0, 0, &timeout) <= 0) { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
493 if (++total_timeouts > TFTP_TIMEOUT_MAX) { |
| 957 | 494 // Timeout - no data received |
| 495 *err = TFTP_TIMEOUT; | |
| 496 goto out; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
497 } |
| 957 | 498 } else { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
499 recv_len = sizeof(data); |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
500 from_len = sizeof(from_addr); |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
501 if ((data_len = recvfrom(s, &data, recv_len, 0, |
| 957 | 502 &from_addr, &from_len)) < 0) { |
| 503 // What happened? | |
| 504 *err = TFTP_NETERR; | |
| 505 goto out; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
506 } |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
507 if (ntohs(hdr->th_opcode) == ACK) { |
| 957 | 508 if (ntohs(hdr->th_block) == last_good_block) { |
| 509 // Advance pointers, etc | |
| 510 sfp = fp; | |
| 511 result += (actual_len - 4); | |
| 512 last_good_block++; | |
| 513 } else { | |
| 514 diag_printf("Send block #%d, got ACK for #%d\n", | |
| 515 last_good_block, ntohs(hdr->th_block)); | |
| 516 } | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
517 } else |
| 957 | 518 if (ntohs(hdr->th_opcode) == ERROR) { |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
519 *err = ntohs(hdr->th_code); |
| 957 | 520 goto out; |
| 521 } else { | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
522 // What kind of packet is this? |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
523 *err = TFTP_PROTOCOL; |
| 957 | 524 goto out; |
| 525 } | |
| 526 } | |
| 527 } | |
| 528 close (s); | |
| 529 return result; | |
| 530 } | |
| 531 | |
| 532 // If we got here, it means there was a problem connecting to the | |
| 533 // server. Try the next address returned by getaddrinfo | |
| 534 nextaddr: | |
| 535 if (-1 != s) { | |
| 536 close(s); | |
| 537 } | |
| 538 addrinfo=addrinfo->ai_next; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
539 } |
| 957 | 540 // We ran into problems. Cleanup |
| 541 out: | |
| 542 if (-1 != s) { | |
| 543 close (s); | |
| 544 } | |
| 545 freeaddrinfo(res); | |
| 546 return -1; | |
|
208
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
547 } |
|
e0c0827131d1
Merge from eCos master repository on 2002-05-20-20:11:54-BST
jlarmour
parents:
diff
changeset
|
548 |
|
490
7c34839e7e97
* src/bootp_support.c: Fix licence which should always have been
jlarmour
parents:
270
diff
changeset
|
549 // EOF tftp_client.c |
| 957 | 550 |
| 551 |
