/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/FTP.c
ViewVC logotype

Annotation of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/FTP.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20