/[H8]/trunk/docs/MCHPStack2.20/Source/ftp.c
ViewVC logotype

Contents of /trunk/docs/MCHPStack2.20/Source/ftp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue May 1 08:17:39 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 15913 byte(s)
Removed tcpip stack 4.02 and added tcpip stack 2.20.
1 /*********************************************************************
2 *
3 * FTP ServerModule for Microchip TCP/IP Stack
4 *
5 *********************************************************************
6 * FileName: ftp.c
7 * Dependencies: StackTsk.h
8 * tcp.h
9 * Processor: PIC18
10 * Complier: MCC18 v1.00.50 or higher
11 * HITECH PICC-18 V8.10PL1 or higher
12 * Company: Microchip Technology, Inc.
13 *
14 * Software License Agreement
15 *
16 * The software supplied herewith by Microchip Technology Incorporated
17 * (the “Company”) for its PICmicro® Microcontroller is intended and
18 * supplied to you, the Company’s customer, for use solely and
19 * exclusively on Microchip PICmicro Microcontroller products. The
20 * software is owned by the Company and/or its supplier, and is
21 * protected under applicable copyright laws. All rights are reserved.
22 * Any use in violation of the foregoing restrictions may subject the
23 * user to criminal sanctions under applicable laws, as well as to
24 * civil liability for the breach of the terms and conditions of this
25 * license.
26 *
27 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
28 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
29 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
30 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
31 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
32 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
33 *
34 * HiTech PICC18 Compiler Options excluding device selection:
35 * -FAKELOCAL -G -Zg -E -C
36 *
37 *
38 * Author Date Comment
39 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40 * Nilesh Rajbharti 4/23/01 Original (Rev 1.0)
41 * Nilesh Rajbharti 11/13/02 Fixed FTPServer()
42 ********************************************************************/
43 #define THIS_IS_FTP
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include "ftp.h"
48 #include "tcp.h"
49 #include "tick.h"
50
51 #include "mpfs.h"
52
53 #if !defined(STACK_USE_FTP_SERVER)
54 #error FTP SERVER module is not enabled.
55 #error If you do not want FTP module, remove this file from your
56 #error project to reduce your code size.
57 #error If you do want FTP module, make sure that STACK_USE_FTP_SERVER
58 #error is defined in StackTsk.h file.
59 #endif
60
61
62 #define FTP_COMMAND_PORT (21)
63 #define FTP_DATA_PORT (20)
64 #define FTP_TIMEOUT (TICK)((TICK)180 * TICK_SECOND)
65 #define MAX_FTP_ARGS (7)
66 #define MAX_FTP_CMD_STRING_LEN (31)
67
68 typedef enum _SM_FTP
69 {
70 SM_FTP_NOT_CONNECTED,
71 SM_FTP_CONNECTED,
72 SM_FTP_USER_NAME,
73 SM_FTP_USER_PASS,
74 SM_FTP_RESPOND
75 } SM_FTP;
76
77 typedef enum _SM_FTP_CMD
78 {
79 SM_FTP_CMD_IDLE,
80 SM_FTP_CMD_WAIT,
81 SM_FTP_CMD_RECEIVE,
82 SM_FTP_CMD_WAIT_FOR_DISCONNECT
83 } SM_FTP_CMD;
84
85 typedef enum _FTP_COMMAND
86 {
87 FTP_CMD_USER,
88 FTP_CMD_PASS,
89 FTP_CMD_QUIT,
90 FTP_CMD_STOR,
91 FTP_CMD_PORT,
92 FTP_CMD_ABORT,
93 FTP_CMD_UNKNOWN,
94 FTP_CMD_NONE,
95 } FTP_COMMAND;
96
97 /*
98 * Each entry in following table must match with that of FTP_COMMAND enum.
99 */
100 ROM char *FTPCommandString[] =
101 {
102 { "USER" }, // FTP_CMD_USER
103 { "PASS" }, // FTP_CMD_PASS
104 { "QUIT" }, // FTP_CMD_QUIT
105 { "STOR" }, // FTP_CMD_STOR
106 { "PORT" }, // FTP_CMD_PORT
107 { "ABOR" } // FTP_CMD_ABORT
108 };
109 #define FTP_COMMAND_TABLE_SIZE ( sizeof(FTPCommandString)/sizeof(FTPCommandString[0]) )
110
111
112 typedef enum _FTP_RESPONSE
113 {
114 FTP_RESP_BANNER,
115 FTP_RESP_USER_OK,
116 FTP_RESP_PASS_OK,
117 FTP_RESP_QUIT_OK,
118 FTP_RESP_STOR_OK,
119 FTP_RESP_UNKNOWN,
120 FTP_RESP_LOGIN,
121 FTP_RESP_DATA_OPEN,
122 FTP_RESP_DATA_READY,
123 FTP_RESP_DATA_CLOSE,
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 /*
131 * Each entry in following table must match with FTP_RESPONE enum
132 */
133 ROM char *FTPResponseString[] =
134 {
135 "220 Ready\r\n", // FTP_RESP_BANNER
136 "331 Password required\r\n", // FTP_RESP_USER_OK
137 "230 Logged in\r\n", // FTP_RESP_PASS_OK
138 "221 Bye\r\n", // FTP_RESP_QUIT_OK
139 "500 \r\n", // FTP_RESP_STOR_OK
140 "502 Not implemented\r\n", // FTP_RESP_UNKNOWN
141 "530 Login required\r\n", // FTP_RESP_LOGIN
142 "150 Transferring data...\r\n", // FTP_RESP_DATA_OPEN
143 "125 Done.\r\n", // FTP_RESP_DATA_READY
144 "226 Transfer Complete\r\n", // FTP_RESP_DATA_CLOSE
145 "200 ok\r\n" // FTP_RESP_OK
146 };
147
148
149 static union
150 {
151 struct
152 {
153 unsigned int bUserSupplied : 1;
154 unsigned int bLoggedIn: 1;
155 } Bits;
156 BYTE Val;
157 } FTPFlags;
158
159
160 static TCP_SOCKET FTPSocket; // Main ftp command socket.
161 static TCP_SOCKET FTPDataSocket; // ftp data socket.
162 static WORD_VAL FTPDataPort; // ftp data port number as supplied by client
163
164 static SM_FTP smFTP; // ftp server FSM state
165 static SM_FTP_CMD smFTPCommand; // ftp command FSM state
166
167 static FTP_COMMAND FTPCommand;
168 static FTP_RESPONSE FTPResponse;
169
170 static char FTPUser[FTP_USER_NAME_LEN];
171 static char FTPString[MAX_FTP_CMD_STRING_LEN+2];
172 static BYTE FTPStringLen;
173 static char *FTP_argv[MAX_FTP_ARGS]; // Parameters for a ftp command
174 static BYTE FTP_argc; // Total number of params for a ftp command
175 static TICK lastActivity; // Timeout keeper.
176
177
178 static MPFS FTPFileHandle;
179
180 /*
181 * Private helper functions.
182 */
183 static void ParseFTPString(void);
184 static FTP_COMMAND ParseFTPCommand(char *cmd);
185 static void ParseFTPString(void);
186 static BOOL ExecuteFTPCommand(FTP_COMMAND cmd);
187 static BOOL PutFile(void);
188 static BOOL Quit(void);
189
190 /*
191 * Uncomment following line if ftp transactions are to be displayed on
192 * RS-232 - for debug purpose only.
193 */
194 //#define FTP_SERVER_DEBUG_MODE
195 #define FTP_PUT_ENABLED
196
197 #if defined(FTP_SERVER_DEBUG_MODE)
198 static USARTPut(BYTE c)
199 {
200 while( !TXSTA_TRMT);
201 TXREG = c;
202 }
203 #else
204
205 #define USARTPut(a)
206
207 #endif
208
209
210 /*********************************************************************
211 * Function: void FTPInit(void)
212 *
213 * PreCondition: TCP module is already initialized.
214 *
215 * Input: None
216 *
217 * Output: None
218 *
219 * Side Effects: None
220 *
221 * Overview: Initializes internal variables of FTP
222 *
223 * Note:
224 ********************************************************************/
225 void FTPInit(void)
226 {
227 FTPSocket = TCPListen(FTP_COMMAND_PORT);
228 smFTP = SM_FTP_NOT_CONNECTED;
229 FTPStringLen = 0;
230 FTPFlags.Val = 0;
231 FTPDataPort.Val = FTP_DATA_PORT;
232 }
233
234
235 /*********************************************************************
236 * Function: void FTPServer(void)
237 *
238 * PreCondition: FTPInit() must already be called.
239 *
240 * Input: None
241 *
242 * Output: Opened FTP connections are served.
243 *
244 * Side Effects: None
245 *
246 * Overview:
247 *
248 * Note: This function acts as a task (similar to one in
249 * RTOS). This function performs its task in
250 * co-operative manner. Main application must call
251 * this function repeatdly to ensure all open
252 * or new connections are served on time.
253 ********************************************************************/
254 BOOL FTPServer(void)
255 {
256 BYTE v;
257 TICK currentTick;
258
259 if ( !TCPIsConnected(FTPSocket) )
260 {
261 FTPStringLen = 0;
262 FTPCommand = FTP_CMD_NONE;
263 smFTP = SM_FTP_NOT_CONNECTED;
264 FTPFlags.Val = 0;
265 smFTPCommand = SM_FTP_CMD_IDLE;
266 return TRUE;
267 }
268
269 if ( TCPIsGetReady(FTPSocket) )
270 {
271 lastActivity = TickGet();
272
273 while( TCPGet(FTPSocket, &v ) )
274 {
275 USARTPut(v);
276 FTPString[FTPStringLen++] = v;
277 if ( FTPStringLen == MAX_FTP_CMD_STRING_LEN )
278 FTPStringLen = 0;
279 }
280 TCPDiscard(FTPSocket);
281
282
283 if ( v == '\n' )
284 {
285 FTPString[FTPStringLen] = '\0';
286 FTPStringLen = 0;
287 ParseFTPString();
288 FTPCommand = ParseFTPCommand(FTP_argv[0]);
289 }
290 }
291 else if ( smFTP != SM_FTP_NOT_CONNECTED )
292 {
293 currentTick = TickGet();
294 currentTick = TickGetDiff(currentTick, lastActivity);
295 if ( currentTick >= FTP_TIMEOUT )
296 {
297 lastActivity = TickGet();
298 FTPCommand = FTP_CMD_QUIT;
299 smFTP = SM_FTP_CONNECTED;
300 }
301 }
302
303 switch(smFTP)
304 {
305 case SM_FTP_NOT_CONNECTED:
306 FTPResponse = FTP_RESP_BANNER;
307 lastActivity = TickGet();
308 /* No break - Continue... */
309
310 case SM_FTP_RESPOND:
311 SM_FTP_RESPOND_Label:
312 while( !TCPIsPutReady(FTPSocket) );
313 if ( TCPIsPutReady(FTPSocket) )
314 {
315 ROM char* pMsg;
316
317 pMsg = FTPResponseString[FTPResponse];
318
319 while( (v = *pMsg++) )
320 {
321 USARTPut(v);
322 TCPPut(FTPSocket, v);
323 }
324 TCPFlush(FTPSocket);
325 FTPResponse = FTP_RESP_NONE;
326 smFTP = SM_FTP_CONNECTED;
327 }
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(FTPUser, 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(FTP_argv[5]);
388 FTPDataPort.v[0] = (BYTE)atoi(FTP_argv[6]);
389 FTPResponse = FTP_RESP_OK;
390 break;
391
392 case FTP_CMD_STOR:
393 return PutFile();
394
395 case FTP_CMD_ABORT:
396 FTPResponse = FTP_RESP_OK;
397 if ( FTPDataSocket != INVALID_SOCKET )
398 TCPDisconnect(FTPDataSocket);
399 break;
400
401 default:
402 FTPResponse = FTP_RESP_UNKNOWN;
403 break;
404 }
405 return TRUE;
406 }
407
408 static BOOL Quit(void)
409 {
410 switch(smFTPCommand)
411 {
412 case SM_FTP_CMD_IDLE:
413 #if defined(FTP_PUT_ENABLED)
414 if ( smFTPCommand == SM_FTP_CMD_RECEIVE )
415 MPFSClose();
416 #endif
417
418 if ( FTPDataSocket != INVALID_SOCKET )
419 {
420 #if defined(FTP_PUT_ENABLED)
421 MPFSClose();
422 #endif
423 TCPDisconnect(FTPDataSocket);
424 smFTPCommand = SM_FTP_CMD_WAIT;
425 }
426 else
427 goto Quit_Done;
428 break;
429
430 case SM_FTP_CMD_WAIT:
431 if ( !TCPIsConnected(FTPDataSocket) )
432 {
433 Quit_Done:
434 FTPResponse = FTP_RESP_QUIT_OK;
435 smFTPCommand = SM_FTP_CMD_WAIT_FOR_DISCONNECT;
436 }
437 break;
438
439 case SM_FTP_CMD_WAIT_FOR_DISCONNECT:
440 if ( TCPIsPutReady(FTPSocket) )
441 {
442 if ( TCPIsConnected(FTPSocket) )
443 TCPDisconnect(FTPSocket);
444 }
445 break;
446
447 }
448 return FALSE;
449 }
450
451
452 static BOOL PutFile(void)
453 {
454 BYTE v;
455
456
457 switch(smFTPCommand)
458 {
459 case SM_FTP_CMD_IDLE:
460 if ( !FTPFlags.Bits.bLoggedIn )
461 {
462 FTPResponse = FTP_RESP_LOGIN;
463 return TRUE;
464 }
465 else
466 {
467 FTPResponse = FTP_RESP_DATA_OPEN;
468 FTPDataSocket = TCPConnect(&REMOTE_HOST(FTPSocket), FTPDataPort.Val);
469 smFTPCommand = SM_FTP_CMD_WAIT;
470 }
471 break;
472
473 case SM_FTP_CMD_WAIT:
474 if ( TCPIsConnected(FTPDataSocket) )
475 {
476 #if defined(FTP_PUT_ENABLED)
477 if ( !MPFSIsInUse() )
478 #endif
479 {
480 #if defined(FTP_PUT_ENABLED)
481 FTPFileHandle = MPFSFormat();
482 #endif
483
484 smFTPCommand = SM_FTP_CMD_RECEIVE;
485 }
486 }
487 break;
488
489 case SM_FTP_CMD_RECEIVE:
490 if ( TCPIsGetReady(FTPDataSocket) )
491 {
492 /*
493 * Reload timeout timer.
494 */
495 lastActivity = TickGet();
496 MPFSPutBegin(FTPFileHandle);
497 while( TCPGet(FTPDataSocket, &v) )
498 {
499 USARTPut(v);
500
501 #if defined(FTP_PUT_ENABLED)
502 MPFSPut(v);
503 #endif
504 }
505 FTPFileHandle = MPFSPutEnd();
506 TCPDiscard(FTPDataSocket);
507 }
508 else if ( !TCPIsConnected(FTPDataSocket) )
509 {
510 #if defined(FTP_PUT_ENABLED)
511 MPFSPutEnd();
512 MPFSClose();
513 #endif
514 TCPDisconnect(FTPDataSocket);
515 FTPDataSocket = INVALID_SOCKET;
516 FTPResponse = FTP_RESP_DATA_CLOSE;
517 return TRUE;
518 }
519 }
520 return FALSE;
521 }
522
523
524
525 static FTP_COMMAND ParseFTPCommand(char *cmd)
526 {
527 FTP_COMMAND i;
528
529 for ( i = 0; i < (FTP_COMMAND)FTP_COMMAND_TABLE_SIZE; i++ )
530 {
531 if ( !memcmppgm2ram((void*)cmd, (ROM void*)FTPCommandString[i], 4) )
532 return i;
533 }
534
535 return FTP_CMD_UNKNOWN;
536 }
537
538 static void ParseFTPString(void)
539 {
540 BYTE *p;
541 BYTE v;
542 enum { SM_FTP_PARSE_PARAM, SM_FTP_PARSE_SPACE } smParseFTP;
543
544 smParseFTP = SM_FTP_PARSE_PARAM;
545 p = (BYTE*)&FTPString[0];
546
547 /*
548 * Skip white blanks
549 */
550 while( *p == ' ' )
551 p++;
552
553 FTP_argv[0] = (char*)p;
554 FTP_argc = 1;
555
556 while( (v = *p) )
557 {
558 switch(smParseFTP)
559 {
560 case SM_FTP_PARSE_PARAM:
561 if ( v == ' ' || v == ',' )
562 {
563 *p = '\0';
564 smParseFTP = SM_FTP_PARSE_SPACE;
565 }
566 else if ( v == '\r' || v == '\n' )
567 *p = '\0';
568 break;
569
570 case SM_FTP_PARSE_SPACE:
571 if ( v != ' ' )
572 {
573 FTP_argv[FTP_argc++] = (char*)p;
574 smParseFTP = SM_FTP_PARSE_PARAM;
575 }
576 break;
577 }
578 p++;
579 }
580 }
581

  ViewVC Help
Powered by ViewVC 1.1.20