?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * File Transfer Protocol (FTP) Client
4 * Module for Microchip TCP/IP Stack
5 * -Provides ability to remotely upload new MPFS image (web pages)
6 * to external EEPROM or external Flash memory
7 * -Reference: RFC 959
8 *
9 *********************************************************************
10 * FileName: FTP.c
11 * Dependencies: TCP, Tick, MPFS, FTPVerify() callback
12 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
13 * Compiler: Microchip C32 v1.05 or higher
14 * Microchip C30 v3.12 or higher
15 * Microchip C18 v3.30 or higher
16 * HI-TECH PICC-18 PRO 9.63PL2 or higher
17 * Company: Microchip Technology, Inc.
18 *
19 * Software License Agreement
20 *
21 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
22 * reserved.
23 *
24 * Microchip licenses to you the right to use, modify, copy, and
25 * distribute:
26 * (i) the Software when embedded on a Microchip microcontroller or
27 * digital signal controller product ("Device") which is
28 * integrated into Licensee's product; or
29 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
30 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
31 * used in conjunction with a Microchip ethernet controller for
32 * the sole purpose of interfacing with the ethernet controller.
33 *
34 * You should refer to the license agreement accompanying this
35 * Software for additional information regarding your rights and
36 * obligations.
37 *
38 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
39 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
40 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
41 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
42 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
43 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
44 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
45 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
46 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
47 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
48 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
49 *
50 *
51 * Author Date Comment
52 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 * Nilesh Rajbharti 4/23/01 Original (Rev 1.0)
54 * Nilesh Rajbharti 11/13/02 Fixed FTPServer()
55 * Howard Schlunder 07/10/06 Added hash printing to FTP client
56 * Howard Schlunder 07/20/06 Added FTP_RESP_DATA_NO_SOCKET error message
57 * Elliott Wood 07/31/07 Minor updates for compatibility
58 ********************************************************************/
59 #define __FTP_C
60  
61 #include "TCPIPConfig.h"
62  
63 #if defined(STACK_USE_FTP_SERVER)
64  
65 #include "TCPIP Stack/TCPIP.h"
66  
67  
68 #define FTP_COMMAND_PORT (21u)
69 #define FTP_DATA_PORT (20u)
70 #define FTP_TIMEOUT (180ul * TICK_SECOND)
71 #define MAX_FTP_ARGS (7u)
72 #define MAX_FTP_CMD_STRING_LEN (31u)
73  
74 typedef enum _SM_FTP
75 {
76 SM_FTP_NOT_CONNECTED,
77 SM_FTP_CONNECTED,
78 SM_FTP_USER_NAME,
79 SM_FTP_USER_PASS,
80 SM_FTP_RESPOND
81 } SM_FTP;
82  
83 typedef enum _SM_FTP_CMD
84 {
85 SM_FTP_CMD_IDLE,
86 SM_FTP_CMD_WAIT,
87 SM_FTP_CMD_RECEIVE,
88 SM_FTP_CMD_WAIT_FOR_DISCONNECT
89 } SM_FTP_CMD;
90  
91 typedef enum _FTP_COMMAND
92 {
93 FTP_CMD_USER,
94 FTP_CMD_PASS,
95 FTP_CMD_QUIT,
96 FTP_CMD_STOR,
97 FTP_CMD_PORT,
98 FTP_CMD_ABORT,
99 FTP_CMD_PWD,
100 FTP_CMD_CWD,
101 FTP_CMD_TYPE,
102 FTP_CMD_UNKNOWN,
103 FTP_CMD_NONE,
104 } FTP_COMMAND;
105  
106 // Each entry in following table must match with that of FTP_COMMAND enum.
107 static ROM char * ROM FTPCommandString[] =
108 {
109 "USER", // FTP_CMD_USER
110 "PASS", // FTP_CMD_PASS
111 "QUIT", // FTP_CMD_QUIT
112 "STOR", // FTP_CMD_STOR
113 "PORT", // FTP_CMD_PORT
114 "ABOR", // FTP_CMD_ABORT
115 "PWD ", // FTP_CMD_PWD
116 "CWD ", // FTP_CMD_CWD
117 "TYPE" // FTP_CMD_TYPE
118 };
119 #define FTP_COMMAND_TABLE_SIZE ( sizeof(FTPCommandString)/sizeof(FTPCommandString[0]) )
120  
121  
122 typedef enum _FTP_RESPONSE
123 {
124 FTP_RESP_BANNER,
125 FTP_RESP_USER_OK,
126 FTP_RESP_PASS_OK,
127 FTP_RESP_QUIT_OK,
128 FTP_RESP_STOR_OK,
129 FTP_RESP_UNKNOWN,
130 FTP_RESP_LOGIN,
131 FTP_RESP_DATA_OPEN,
132 FTP_RESP_DATA_READY,
133 FTP_RESP_DATA_CLOSE,
134 FTP_RESP_DATA_NO_SOCKET,
135 FTP_RESP_PWD,
136 FTP_RESP_OK,
137  
138 FTP_RESP_NONE // This must always be the last
139 // There is no corresponding string.
140 } FTP_RESPONSE;
141  
142 // Each entry in following table must match with FTP_RESPONE enum
143 static ROM char * ROM FTPResponseString[] =
144 {
145 "220 Ready\r\n", // FTP_RESP_BANNER
146 "331 Password required\r\n", // FTP_RESP_USER_OK
147 "230 Logged in\r\n", // FTP_RESP_PASS_OK
148 "221 Bye\r\n", // FTP_RESP_QUIT_OK
149 "500 \r\n", // FTP_RESP_STOR_OK
150 "502 Not implemented\r\n", // FTP_RESP_UNKNOWN
151 "530 Login required\r\n", // FTP_RESP_LOGIN
152 "150 Transferring data...\r\n", // FTP_RESP_DATA_OPEN
153 "125 Done\r\n", // FTP_RESP_DATA_READY
154 "226 Transfer Complete\r\n", // FTP_RESP_DATA_CLOSE
155 "425 Can't create data socket.\r\n",// FTP_RESP_DATA_NO_SOCKET
156 "257 \"/\" is current\r\n", // FTP_RESP_PWD
157 "200 Ok\r\n" // FTP_RESP_OK
158 };
159  
160  
161 static union
162 {
163 struct
164 {
165 unsigned char bUserSupplied : 1;
166 unsigned char bLoggedIn: 1;
167 } Bits;
168 BYTE Val;
169 } FTPFlags;
170  
171  
172 static TCP_SOCKET FTPSocket; // Main ftp command socket.
173 static TCP_SOCKET FTPDataSocket; // ftp data socket.
174 static WORD_VAL FTPDataPort; // ftp data port number as supplied by client
175  
176 static SM_FTP smFTP; // ftp server FSM state
177 static SM_FTP_CMD smFTPCommand; // ftp command FSM state
178  
179 static FTP_COMMAND FTPCommand;
180 static FTP_RESPONSE FTPResponse;
181  
182 static BYTE FTPUser[FTP_USER_NAME_LEN];
183 static BYTE FTPString[MAX_FTP_CMD_STRING_LEN+2];
184 static BYTE FTPStringLen;
185 static BYTE *FTP_argv[MAX_FTP_ARGS]; // Parameters for a ftp command
186 static BYTE FTP_argc; // Total number of params for a ftp command
187 static DWORD lastActivity; // Timeout keeper.
188  
189  
190 static MPFS FTPFileHandle;
191  
192 // Private helper functions.
193 static void ParseFTPString(void);
194 static FTP_COMMAND ParseFTPCommand(BYTE *cmd);
195 static void ParseFTPString(void);
196 static BOOL ExecuteFTPCommand(FTP_COMMAND cmd);
197 static BOOL PutFile(void);
198 static BOOL Quit(void);
199  
200  
201 #define FTP_PUT_ENABLED
202  
203  
204 /*********************************************************************
205 * Function: void FTPInit(void)
206 *
207 * PreCondition: TCP module is already initialized.
208 *
209 * Input: None
210 *
211 * Output: None
212 *
213 * Side Effects: None
214 *
215 * Overview: Initializes internal variables of FTP
216 *
217 * Note:
218 ********************************************************************/
219 void FTPInit(void)
220 {
221 FTPSocket = TCPOpen(0, TCP_OPEN_SERVER, FTP_COMMAND_PORT, TCP_PURPOSE_FTP_COMMAND);
222  
223 // If this trap ever gets entered, it means your TCPIPConfig.h file
224 // needs to be edited to make a TCP_PURPOSE_FTP_COMMAND socket
225 // available, as defined by the TCPSocketInitializer[] array. Make
226 // sure that a TCP_PURPOSE_FTP_DATA socket is also available to
227 // use the FTP Server.
228 if(FTPSocket == INVALID_SOCKET)
229 while(1);
230  
231 FTPDataSocket = INVALID_SOCKET;
232 smFTP = SM_FTP_NOT_CONNECTED;
233 FTPStringLen = 0;
234 FTPFlags.Val = 0;
235 FTPDataPort.Val = FTP_DATA_PORT;
236 }
237  
238  
239 /*********************************************************************
240 * Function: void FTPServer(void)
241 *
242 * PreCondition: FTPInit() must already be called.
243 *
244 * Input: None
245 *
246 * Output: Opened FTP connections are served.
247 *
248 * Side Effects: None
249 *
250 * Overview:
251 *
252 * Note: This function acts as a task (similar to one in
253 * RTOS). This function performs its task in
254 * co-operative manner. Main application must call
255 * this function repeatdly to ensure all open
256 * or new connections are served on time.
257 ********************************************************************/
258 BOOL FTPServer(void)
259 {
260 BYTE v;
261 DWORD currentTick;
262  
263 if ( !TCPIsConnected(FTPSocket) )
264 {
265 FTPStringLen = 0;
266 FTPCommand = FTP_CMD_NONE;
267 smFTP = SM_FTP_NOT_CONNECTED;
268 FTPFlags.Val = 0;
269 smFTPCommand = SM_FTP_CMD_IDLE;
270 if(FTPDataSocket != INVALID_SOCKET)
271 {
272 TCPDisconnect(FTPDataSocket);
273 FTPDataSocket = INVALID_SOCKET;
274 }
275  
276 return TRUE;
277 }
278  
279 if ( TCPIsGetReady(FTPSocket) )
280 {
281 lastActivity = TickGet();
282  
283 while( TCPGet(FTPSocket, &v ) )
284 {
285 FTPString[FTPStringLen++] = v;
286 if ( FTPStringLen == MAX_FTP_CMD_STRING_LEN )
287 FTPStringLen = 0;
288 }
289  
290  
291 if ( v == '\n' )
292 {
293 FTPString[FTPStringLen] = '\0';
294 FTPStringLen = 0;
295 ParseFTPString();
296 FTPCommand = ParseFTPCommand(FTP_argv[0]);
297 }
298 }
299 else if ( smFTP != SM_FTP_NOT_CONNECTED )
300 {
301 currentTick = TickGet();
302 currentTick = currentTick - lastActivity;
303 if ( currentTick >= FTP_TIMEOUT )
304 {
305 lastActivity = TickGet();
306 FTPCommand = FTP_CMD_QUIT;
307 smFTP = SM_FTP_CONNECTED;
308 }
309 }
310  
311 switch(smFTP)
312 {
313 case SM_FTP_NOT_CONNECTED:
314 FTPResponse = FTP_RESP_BANNER;
315 lastActivity = TickGet();
316 // No break - Continue...
317  
318 case SM_FTP_RESPOND:
319 SM_FTP_RESPOND_Label:
320 // Make sure there is enough TCP TX FIFO space to put our response
321 if(TCPIsPutReady(FTPSocket) < strlenpgm(FTPResponseString[FTPResponse]))
322 return TRUE;
323  
324 TCPPutROMString(FTPSocket, (ROM BYTE*)FTPResponseString[FTPResponse]);
325 TCPFlush(FTPSocket);
326 FTPResponse = FTP_RESP_NONE;
327 smFTP = SM_FTP_CONNECTED;
328 // No break - this will speed up little bit
329  
330 case SM_FTP_CONNECTED:
331 if ( FTPCommand != FTP_CMD_NONE )
332 {
333 if ( ExecuteFTPCommand(FTPCommand) )
334 {
335 if ( FTPResponse != FTP_RESP_NONE )
336 smFTP = SM_FTP_RESPOND;
337 else if ( FTPCommand == FTP_CMD_QUIT )
338 smFTP = SM_FTP_NOT_CONNECTED;
339  
340 FTPCommand = FTP_CMD_NONE;
341 smFTPCommand = SM_FTP_CMD_IDLE;
342 }
343 else if ( FTPResponse != FTP_RESP_NONE )
344 {
345 smFTP = SM_FTP_RESPOND;
346 goto SM_FTP_RESPOND_Label;
347 }
348 }
349 break;
350  
351  
352 }
353  
354 return TRUE;
355 }
356  
357 static BOOL ExecuteFTPCommand(FTP_COMMAND cmd)
358 {
359 switch(cmd)
360 {
361 case FTP_CMD_USER:
362 FTPFlags.Bits.bUserSupplied = TRUE;
363 FTPFlags.Bits.bLoggedIn = FALSE;
364 FTPResponse = FTP_RESP_USER_OK;
365 strncpy((char*)FTPUser, (char*)FTP_argv[1], sizeof(FTPUser));
366 break;
367  
368 case FTP_CMD_PASS:
369 if ( !FTPFlags.Bits.bUserSupplied )
370 FTPResponse = FTP_RESP_LOGIN;
371 else
372 {
373 if ( FTPVerify(FTPUser, FTP_argv[1]) )
374 {
375 FTPFlags.Bits.bLoggedIn = TRUE;
376 FTPResponse = FTP_RESP_PASS_OK;
377 }
378 else
379 FTPResponse = FTP_RESP_LOGIN;
380 }
381 break;
382  
383 case FTP_CMD_QUIT:
384 return Quit();
385  
386 case FTP_CMD_PORT:
387 FTPDataPort.v[1] = (BYTE)atoi((char*)FTP_argv[5]);
388 FTPDataPort.v[0] = (BYTE)atoi((char*)FTP_argv[6]);
389 FTPResponse = FTP_RESP_OK;
390 break;
391  
392 case FTP_CMD_STOR:
393 return PutFile();
394  
395 case FTP_CMD_PWD:
396 FTPResponse = FTP_RESP_PWD;
397 break;
398  
399 case FTP_CMD_CWD:
400 case FTP_CMD_TYPE:
401 FTPResponse = FTP_RESP_OK;
402 break;
403  
404 case FTP_CMD_ABORT:
405 FTPResponse = FTP_RESP_OK;
406 if ( FTPDataSocket != INVALID_SOCKET )
407 {
408 TCPDisconnect(FTPDataSocket);
409 FTPDataSocket = INVALID_SOCKET;
410 }
411 break;
412  
413 default:
414 FTPResponse = FTP_RESP_UNKNOWN;
415 break;
416 }
417 return TRUE;
418 }
419  
420 static BOOL Quit(void)
421 {
422 switch(smFTPCommand)
423 {
424 case SM_FTP_CMD_IDLE:
425 #if defined(FTP_PUT_ENABLED)
426 if ( smFTPCommand == SM_FTP_CMD_RECEIVE )
427 MPFSClose();
428 #endif
429  
430 if ( FTPDataSocket != INVALID_SOCKET )
431 {
432 #if defined(FTP_PUT_ENABLED)
433 MPFSClose();
434 #endif
435 TCPDisconnect(FTPDataSocket);
436 smFTPCommand = SM_FTP_CMD_WAIT;
437 }
438 else
439 goto Quit_Done;
440 break;
441  
442 case SM_FTP_CMD_WAIT:
443 if ( !TCPIsConnected(FTPDataSocket) )
444 {
445 Quit_Done:
446 FTPResponse = FTP_RESP_QUIT_OK;
447 smFTPCommand = SM_FTP_CMD_WAIT_FOR_DISCONNECT;
448 }
449 break;
450  
451 case SM_FTP_CMD_WAIT_FOR_DISCONNECT:
452 if ( TCPIsPutReady(FTPSocket) )
453 {
454 if ( TCPIsConnected(FTPSocket) )
455 TCPDisconnect(FTPSocket);
456 }
457 break;
458  
459 }
460 return FALSE;
461 }
462  
463  
464 static BOOL PutFile(void)
465 {
466 BYTE v;
467  
468  
469 switch(smFTPCommand)
470 {
471 case SM_FTP_CMD_IDLE:
472 if ( !FTPFlags.Bits.bLoggedIn )
473 {
474 FTPResponse = FTP_RESP_LOGIN;
475 return TRUE;
476 }
477 else
478 {
479 FTPResponse = FTP_RESP_DATA_OPEN;
480 FTPDataSocket = TCPOpen((PTR_BASE)&TCPGetRemoteInfo(FTPSocket)->remote, TCP_OPEN_NODE_INFO, FTPDataPort.Val, TCP_PURPOSE_FTP_DATA);
481  
482 // Make sure that a valid socket was available and returned
483 // If not, return with an error
484 if(FTPDataSocket == INVALID_SOCKET)
485 {
486 FTPResponse = FTP_RESP_DATA_NO_SOCKET;
487 return TRUE;
488 }
489  
490 smFTPCommand = SM_FTP_CMD_WAIT;
491 }
492 break;
493  
494 case SM_FTP_CMD_WAIT:
495 if ( TCPIsConnected(FTPDataSocket) )
496 {
497 #if defined(FTP_PUT_ENABLED)
498 FTPFileHandle = MPFSFormat();
499 #endif
500  
501 smFTPCommand = SM_FTP_CMD_RECEIVE;
502 }
503 break;
504  
505 case SM_FTP_CMD_RECEIVE:
506 if ( TCPIsGetReady(FTPDataSocket) )
507 {
508 // Reload timeout timer.
509 lastActivity = TickGet();
510 MPFSPutBegin(FTPFileHandle);
511 while( TCPGet(FTPDataSocket, &v) )
512 {
513 #if defined(FTP_PUT_ENABLED)
514 MPFSPut(v);
515 #endif
516 }
517 FTPFileHandle = MPFSPutEnd();
518  
519 }
520 else if ( !TCPIsConnected(FTPDataSocket) )
521 {
522 #if defined(FTP_PUT_ENABLED)
523 MPFSClose();
524 #endif
525 TCPDisconnect(FTPDataSocket);
526 FTPDataSocket = INVALID_SOCKET;
527 FTPResponse = FTP_RESP_DATA_CLOSE;
528 return TRUE;
529 }
530 }
531 return FALSE;
532 }
533  
534  
535  
536 static FTP_COMMAND ParseFTPCommand(BYTE *cmd)
537 {
538 FTP_COMMAND i;
539  
540 for ( i = 0; i < (FTP_COMMAND)FTP_COMMAND_TABLE_SIZE; i++ )
541 {
542 if ( !memcmppgm2ram((void*)cmd, (ROM void*)FTPCommandString[i], 3) )
543 return i;
544 }
545  
546 return FTP_CMD_UNKNOWN;
547 }
548  
549 static void ParseFTPString(void)
550 {
551 BYTE *p;
552 BYTE v;
553 enum { SM_FTP_PARSE_PARAM, SM_FTP_PARSE_SPACE } smParseFTP;
554  
555 smParseFTP = SM_FTP_PARSE_PARAM;
556 p = (BYTE*)&FTPString[0];
557  
558 // Skip white blanks
559 while( *p == ' ' )
560 p++;
561  
562 FTP_argv[0] = (BYTE*)p;
563 FTP_argc = 1;
564  
565 while( (v = *p) )
566 {
567 switch(smParseFTP)
568 {
569 case SM_FTP_PARSE_PARAM:
570 if ( v == ' ' || v == ',' )
571 {
572 *p = '\0';
573 smParseFTP = SM_FTP_PARSE_SPACE;
574 }
575 else if ( v == '\r' || v == '\n' )
576 *p = '\0';
577 break;
578  
579 case SM_FTP_PARSE_SPACE:
580 if ( v != ' ' )
581 {
582 FTP_argv[FTP_argc++] = (BYTE*)p;
583 smParseFTP = SM_FTP_PARSE_PARAM;
584 }
585 break;
586 }
587 p++;
588 if(FTP_argc == MAX_FTP_ARGS)
589 break;
590 }
591 }
592  
593 #endif // #if defined(STACK_USE_FTP_SERVER)
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3