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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 16791 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
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