]> begriffs open source - cmsis-freertos/blob - Demo/lwIP_AVR32_UC3/NETWORK/BasicTFTP/BasicTFTP.c
Update cmsis_os2.c
[cmsis-freertos] / Demo / lwIP_AVR32_UC3 / NETWORK / BasicTFTP / BasicTFTP.c
1 /*This file has been prepared for Doxygen automatic documentation generation.*/
2 /*! \file *********************************************************************
3  *
4  * \brief Basic TFTP Server for AVR32 UC3.
5  *
6  * - Compiler:           GNU GCC for AVR32
7  * - Supported devices:  All AVR32 devices can be used.
8  * - AppNote:
9  *
10  * \author               Atmel Corporation: http://www.atmel.com \n
11  *                       Support and FAQ: http://support.atmel.no/
12  *
13  *****************************************************************************/
14
15 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright notice,
21  * this list of conditions and the following disclaimer.
22  *
23  * 2. Redistributions in binary form must reproduce the above copyright notice,
24  * this list of conditions and the following disclaimer in the documentation
25  * and/or other materials provided with the distribution.
26  *
27  * 3. The name of ATMEL may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
31  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
33  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
34  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  */
41
42
43 /*
44   Implements a simplistic TFTP server.
45   
46   In order to put data on the TFTP server (not over 2048 bytes)
47   tftp 192.168.0.2 PUT <src_filename>
48   this will copy file from your hard drive to the RAM buffer of the application
49
50   tftp 192.168.0.2 GET <dst_filename>
51   this will copy file from the RAM buffer of the application to your hard drive
52   You can then check that src_filename and dst_filename are identical    
53 */
54
55 #if (TFTP_USED == 1)
56
57 #include <string.h>
58
59
60 /* Scheduler includes. */
61 #include "FreeRTOS.h"
62 #include "task.h"
63 #include "partest.h"
64 #include "BasicTFTP.h"
65
66
67 /* Demo includes. */
68 #include "portmacro.h"
69
70 /* lwIP includes. */
71 #include "lwip/api.h"
72 #include "lwip/tcpip.h"
73 #include "lwip/memp.h"
74 #include "lwip/stats.h"
75 #include "lwip/opt.h"
76 #include "lwip/api.h"
77 #include "lwip/arch.h"
78 #include "lwip/sys.h"
79 #include "netif/loopif.h"
80 #include "lwip/sockets.h"
81
82 #define O_WRONLY 1
83 #define O_RDONLY 2
84
85
86 /* The port on which we listen. */
87 #define TFTP_PORT    ( 69 )
88
89 /* Delay on close error. */
90 #define TFTP_DELAY         ( 10 )
91
92 /* Delay on bind error. */
93 #define TFTP_ERROR_DELAY    ( 40 )
94
95 #define TFTP_LED     ( 4 )
96
97 char data_out[SEGSIZE+sizeof(struct tftphdr)];
98 char data_in[SEGSIZE+sizeof(struct tftphdr)];
99
100 //struct tftp_server *server;
101
102 /*------------------------------------------------------------*/
103 static char * errmsg[] = {
104   "Undefined error code",               // 0 nothing defined
105   "File not found",                     // 1 TFTP_ENOTFOUND 
106   "Access violation",                   // 2 TFTP_EACCESS   
107   "Disk full or allocation exceeded",   // 3 TFTP_ENOSPACE  
108   "Illegal TFTP operation",             // 4 TFTP_EBADOP    
109   "Unknown transfer ID",                // 5 TFTP_EBADID    
110   "File already exists",                // 6 TFTP_EEXISTS   
111   "No such user",                       // 7 TFTP_ENOUSER   
112 };
113
114
115 /* Send an error packet to the client */
116 static void 
117 tftpd_send_error(int s, struct tftphdr * reply, int err,
118      struct sockaddr_in *from_addr, int from_len)
119 {
120     if ( ( 0 <= err ) && ( sizeof(errmsg)/sizeof(errmsg[0]) > err) ) {
121     reply->th_opcode = htons(ERROR);
122     reply->th_code = htons(err);
123     if ( (0 > err) || (sizeof(errmsg)/sizeof(errmsg[0]) <= err) )
124         err = 0; // Do not copy a random string from hyperspace
125     strcpy(reply->th_msg, errmsg[err]);
126     sendto(s, reply, 4+strlen(reply->th_msg)+1, 0, 
127      (struct sockaddr *)from_addr, from_len);
128     }
129 }
130
131 char cRamBuffer[2048];
132 int lCurrentBlock = 0;
133 int lTotalLength = 0;
134
135
136 int tftpd_close_data_file(int fd)
137 {
138   lCurrentBlock = 0;
139   return (5);
140 }
141
142 int tftpd_open_data_file(int fd, int mode)
143 {
144   lCurrentBlock = 0; 
145   return (5);
146 }
147
148 int tftpd_read_data_file(int fd, char * buffer, int length)
149 {
150 int lReturnValue;
151
152   if ((lTotalLength -= length) >= 0) {
153     lReturnValue = length;
154   }
155   else
156   {
157     lReturnValue = lTotalLength + length;
158     lTotalLength = 0;
159   }
160   memcpy(buffer, &cRamBuffer[lCurrentBlock * SEGSIZE], lReturnValue);
161   lCurrentBlock++;
162   return (lReturnValue);
163 }
164
165 //
166 // callback to store data to the RAM buffer
167 //
168 int tftpd_write_data_file(int fd, char * buffer, int length)
169 {
170   lTotalLength += length;
171   memcpy(&cRamBuffer[lCurrentBlock * SEGSIZE], buffer, length);
172   lCurrentBlock++;
173   return (length);
174 }
175
176 //
177 // Receive a file from the client
178 //
179 static void
180 tftpd_write_file(struct tftphdr *hdr,
181                  struct sockaddr_in *from_addr, int from_len)
182 {
183
184     struct tftphdr *reply = (struct tftphdr *)data_out;
185     struct tftphdr *response = (struct tftphdr *)data_in;
186     int fd, len, ok, tries, closed, data_len, s;
187     unsigned short block;
188     struct timeval timeout;
189     fd_set fds;
190     int total_timeouts = 0;
191     struct sockaddr_in client_addr, local_addr;
192     int client_len;
193
194
195     s = socket(AF_INET, SOCK_DGRAM, 0);
196     if (s < 0) {
197         return;
198     }
199
200     memset((char *)&local_addr, 0, sizeof(local_addr));
201     local_addr.sin_family = AF_INET;
202     local_addr.sin_len = sizeof(local_addr);
203     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
204     local_addr.sin_port = htons(INADDR_ANY);
205
206     if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
207         // Problem setting up my end
208         close(s);
209         return;
210     }
211
212     if ((fd = tftpd_open_data_file((int)hdr->th_stuff, O_WRONLY)) < 0) {
213         tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
214         close(s);
215         return;
216     }
217
218     ok = pdTRUE;
219     closed = pdFALSE;
220     block = 0;
221     while (ok) {
222         // Send ACK telling client he can send data
223         reply->th_opcode = htons(ACK);
224         reply->th_block = htons(block++); // postincrement
225         for (tries = 0;  tries < TFTP_RETRIES_MAX;  tries++) {
226             sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
227         repeat_select:
228             timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
229             timeout.tv_usec = 0;
230             FD_ZERO(&fds);
231             FD_SET(s, &fds);
232            vParTestToggleLED( TFTP_LED );
233            if (lwip_select(s+1, &fds, 0, 0, &timeout) <= 0) {
234                 if (++total_timeouts > TFTP_TIMEOUT_MAX) {
235                     tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
236                     ok = pdFALSE;
237                     break;
238                 }
239                 continue; // retry the send, using up one retry.
240             }
241             vParTestToggleLED( TFTP_LED );
242             // Some data has arrived
243             data_len = sizeof(data_in);
244             client_len = sizeof(client_addr);
245             if ((data_len = recvfrom(s, data_in, data_len, 0, 
246                       (struct sockaddr *)&client_addr, &client_len)) < 0) {
247                 // What happened?  No data here!
248                 continue; // retry the send, using up one retry.
249             }
250             if (ntohs(response->th_opcode) == DATA &&
251                 ntohs(response->th_block) < block) {
252                 // Then it is repeat DATA with an old block; listen again,
253                 // but do not repeat sending the current ack, and do not
254                 // use up a retry count.  (we do re-send the ack if
255                 // subsequently we time out)
256                 goto repeat_select;
257             }
258             if (ntohs(response->th_opcode) == DATA &&
259                 ntohs(response->th_block) == block) {
260                 // Good data - write to file
261                 len = tftpd_write_data_file(fd, response->th_data, data_len-4);
262                 if (len < (data_len-4)) {
263                     // File is "full"
264                     tftpd_send_error(s,reply,TFTP_ENOSPACE,
265                                      from_addr, from_len);     
266                     ok = pdFALSE;  // Give up
267                     break; // out of the retries loop
268                 }
269                 if (data_len < (SEGSIZE+4)) {
270                     // End of file
271                     closed = pdTRUE;
272                     ok = pdFALSE;
273                     vParTestSetLED( 0 , 0 );
274
275                     if (tftpd_close_data_file(fd) == -1) {
276                         tftpd_send_error(s,reply,TFTP_EACCESS,
277                                          from_addr, from_len);
278
279                        break;  // out of the retries loop
280                     }
281                     // Exception to the loop structure: we must ACK the last
282                     // packet, the one that implied EOF:
283                     reply->th_opcode = htons(ACK);
284                     reply->th_block = htons(block++); // postincrement
285                     sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
286                     break; // out of the retries loop
287                 }
288                 // Happy!  Break out of the retries loop.
289                 break;
290             }
291         } // End of the retries loop.
292         if (TFTP_RETRIES_MAX <= tries) {
293             tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
294             ok = pdFALSE;
295         }
296     }
297     close(s);
298     if (!closed) {
299       tftpd_close_data_file(fd);
300     }
301 }
302
303
304 //
305 // Send a file to the client
306 //
307 static void
308 tftpd_read_file(struct tftphdr *hdr,
309                 struct sockaddr_in *from_addr, int from_len)
310 {
311     struct tftphdr *reply = (struct tftphdr *)data_out;
312     struct tftphdr *response = (struct tftphdr *)data_in;
313     int fd, len, tries, ok, data_len, s;
314     unsigned short block;
315     struct timeval timeout;
316     fd_set fds;
317     int total_timeouts = 0;
318     struct sockaddr_in client_addr, local_addr;
319     int client_len;
320
321     s = socket(AF_INET, SOCK_DGRAM, 0);
322     if (s < 0) {
323         return;
324     }
325     memset((char *)&local_addr, 0, sizeof(local_addr));
326     local_addr.sin_family = AF_INET;
327     local_addr.sin_len = sizeof(local_addr);
328     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
329     local_addr.sin_port = htons(INADDR_ANY);
330     if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
331         // Problem setting up my end
332         close(s);
333         return;
334     }
335     if ((fd = tftpd_open_data_file((int)hdr->th_stuff, O_RDONLY)) < 0) {
336         tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
337         close(s);
338         return;
339     }
340     block = 0;
341     ok = pdTRUE;
342     while (ok) {
343         // Read next chunk of file
344         len = tftpd_read_data_file(fd, reply->th_data, SEGSIZE);
345         reply->th_block = htons(++block); // preincrement
346         reply->th_opcode = htons(DATA);
347         for (tries = 0;  tries < TFTP_RETRIES_MAX;  tries++) {
348             if (sendto(s, reply, 4+len, 0,
349                        (struct sockaddr *)from_addr, from_len) < 0) {
350                 // Something went wrong with the network!
351                 ok = pdFALSE;
352                 break;
353             }
354         repeat_select:
355             timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
356             timeout.tv_usec = 0;
357             FD_ZERO(&fds);
358             FD_SET(s, &fds);
359             vParTestToggleLED( TFTP_LED );
360             if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
361                 if (++total_timeouts > TFTP_TIMEOUT_MAX) {
362                     tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
363                     ok = pdFALSE;
364                     break;
365                 }
366                 continue; // retry the send, using up one retry.
367             }
368             vParTestToggleLED( TFTP_LED );
369             data_len = sizeof(data_in);
370             client_len = sizeof(client_addr);
371             if ((data_len = recvfrom(s, data_in, data_len, 0, 
372                                      (struct sockaddr *)&client_addr,
373                                      &client_len)) < 0) {
374                 // What happened?  Maybe someone lied to us...
375                 continue; // retry the send, using up one retry.
376             }
377             if ((ntohs(response->th_opcode) == ACK) &&
378                 (ntohs(response->th_block) < block)) {
379                 // Then it is a repeat ACK for an old block; listen again,
380                 // but do not repeat sending the current block, and do not
381                 // use up a retry count.  (we do re-send the data if
382                 // subsequently we time out)
383                 goto repeat_select;
384             }
385             if ((ntohs(response->th_opcode) == ACK) &&
386                 (ntohs(response->th_block) == block)) {
387                 // Happy!  Break out of the retries loop.
388                 break;
389             }
390         } // End of the retries loop.
391         if (TFTP_RETRIES_MAX <= tries) {
392             tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
393             ok = pdFALSE;
394         }
395         if (len < SEGSIZE) {
396             break; // That's end of file then.
397         }
398     }
399     close(s);
400     tftpd_close_data_file(fd);
401 }
402
403
404
405 portTASK_FUNCTION( vBasicTFTPServer, pvParameters )
406 {
407     int lSocket;
408     int lDataLen, lRecvLen, lFromLen;
409     struct sockaddr_in sLocalAddr, sFromAddr;
410     char cData[SEGSIZE+sizeof(struct tftphdr)];
411     struct tftphdr *sHdr = (struct tftphdr *)cData;
412
413     // Set up port
414     // Network order in info; host order in server:
415
416     for (;;) {
417         // Create socket
418         lSocket = socket(AF_INET, SOCK_DGRAM, 0);
419         if (lSocket < 0) {
420             return;
421         }
422         memset((char *)&sLocalAddr, 0, sizeof(sLocalAddr));
423         sLocalAddr.sin_family = AF_INET;
424         sLocalAddr.sin_len = sizeof(sLocalAddr);
425         sLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
426         sLocalAddr.sin_port = TFTP_PORT;
427
428         if (bind(lSocket, (struct sockaddr *)&sLocalAddr, sizeof(sLocalAddr)) < 0) {
429             // Problem setting up my end
430             close(lSocket);
431             return;
432         }
433
434
435         lRecvLen = sizeof(cData);
436         lFromLen = sizeof(sFromAddr);
437         lDataLen = recvfrom(lSocket, sHdr, lRecvLen, 0,
438                             (struct sockaddr *)&sFromAddr, &lFromLen);
439         vParTestSetLED( TFTP_LED , pdTRUE );
440         close(lSocket); // so that other servers can bind to the TFTP socket
441
442         if ( lDataLen < 0) {
443
444         } else {
445             switch (ntohs(sHdr->th_opcode)) {
446             case WRQ:
447                 tftpd_write_file(sHdr, &sFromAddr, lFromLen);
448                 vParTestSetLED( TFTP_LED , pdFALSE );
449                 break;
450             case RRQ:
451                 tftpd_read_file(sHdr, &sFromAddr, lFromLen);
452                 vParTestSetLED( TFTP_LED , pdFALSE );
453                 break;
454             case ACK:
455             case DATA:
456             case ERROR:
457                 vParTestSetLED( TFTP_LED , pdFALSE );
458                 // Ignore
459                 break;
460             default:
461                 for(;;)
462                 {
463                   vParTestToggleLED( TFTP_LED );
464                   vTaskDelay(200);                    
465                 }
466              }
467         }
468     }
469 }
470 #endif