1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Duo Component */
16 /** */
17 /** File Transfer Protocol */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_FTP_SOURCE_CODE
23
24
25 /* Force error checking to be disabled in this module */
26
27 #ifndef NX_DISABLE_ERROR_CHECKING
28 #define NX_DISABLE_ERROR_CHECKING
29 #endif
30
31 /* If FileX is not used in this application, define this option and define the FileX services
32 declared in filex_stub.h elsewhere.
33 #define NX_FTP_NO_FILEX
34 */
35
36 /* Include necessary system files. */
37
38 #include "nx_api.h"
39 #include "nx_ip.h"
40 #include "nxd_ftp_server.h"
41 #include "stdio.h"
42 #include "string.h"
43
44
45 /* Bring in externs for caller checking code. */
46
47 NX_CALLER_CHECKING_EXTERNS
48
49
50 /* Define FTP Error codes. */
51
52 #define NX_FTP_CODE_RESTART_MARKER "110" /* Restart marker reply.
53 In this case, the text is exact and not left to the
54 particular implementation; it must read:
55 MARK yyyy = mmmm
56 Where yyyy is User-process data stream marker, and mmmm
57 server's equivalent marker (note the spaces between markers
58 and "="). */
59 #define NX_FTP_CODE_READY_NNN "120" /* Service ready in nnn minutes. */
60 #define NX_FTP_CODE_START_XFER "125" /* Data connection already open; transfer starting. */
61 #define NX_FTP_CODE_OPENING "150" /* File status okay; about to open data connection. */
62 #define NX_FTP_CODE_CMD_OK "200" /* Command okay. */
63 #define NX_FTP_CODE_CONNECTION_OK "220" /* Connection okay. */
64 #define NX_FTP_CODE_CLOSE "221" /* Service closing control connection. */
65 #define NX_FTP_CODE_LOGOFF "226" /* Closing data connection. */
66 #define NX_FTP_CODE_LOGIN "230" /* User logged in, proceed. */
67 #define NX_FTP_CODE_COMPLETED "250" /* Requested file action okay, completed. */
68 #define NX_FTP_CODE_MADE_DIR "257" /* PATHNAME created. */
69 #define NX_FTP_CODE_USER_OK "331" /* User name okay, need password. */
70 #define NX_FTP_CODE_NEED_ACCT "332" /* Need account for login. */
71 #define NX_FTP_CODE_FILE_PEND "350" /* Requested file action pending further information. */
72 #define NX_FTP_CODE_CMD_FAIL "501" /* Syntax error in parameters or arguments. */
73 #define NX_FTP_CODE_NOT_IMPLEMENTED "502" /* Command not implemented. */
74 #define NX_FTP_CODE_UNAUTHORIZED "530" /* Not logged in. */
75 #define NX_FTP_CODE_NO_ACCT "532" /* Need account for storing files. */
76 #define NX_FTP_CODE_BAD_TYPE "504" /* Invalid TYPE. */
77 #define NX_FTP_CODE_BAD_FILE "550" /* Requested action not taken. File unavailable (e.g., file not found, no access). */
78 #define NX_FTP_CODE_BAD_PAGE_TYPE "551" /* Requested action aborted: page type unknown. */
79 #define NX_FTP_CODE_NO_SPACE "552" /* Requested file action aborted, no space. */
80 #define NX_FTP_CODE_BAD_NAME "553" /* Requested action not taken, File name not allowed. */
81
82 static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number, UCHAR pad);
83
84 /**************************************************************************/
85 /* */
86 /* FUNCTION RELEASE */
87 /* */
88 /* _nxe_ftp_server_create PORTABLE C */
89 /* 6.1 */
90 /* AUTHOR */
91 /* */
92 /* Yuxin Zhou, Microsoft Corporation */
93 /* */
94 /* DESCRIPTION */
95 /* */
96 /* This function checks for errors in the FTP server create call. */
97 /* */
98 /* */
99 /* INPUT */
100 /* */
101 /* ftp_server_ptr Pointer to FTP server */
102 /* ftp_server_name Name of FTP server */
103 /* ip_ptr Pointer to IP instance */
104 /* media_ptr Pointer to media structure */
105 /* stack_ptr Server thread's stack pointer */
106 /* stack_size Server thread's stack size */
107 /* pool_ptr Pointer to packet pool */
108 /* ftp_login Pointer to user's login */
109 /* function */
110 /* ftp_logout Pointer to user's logout */
111 /* function */
112 /* */
113 /* OUTPUT */
114 /* */
115 /* status Completion status */
116 /* */
117 /* CALLS */
118 /* */
119 /* _nx_ftp_server_create Actual server create call */
120 /* */
121 /* CALLED BY */
122 /* */
123 /* Application Code */
124 /* */
125 /* RELEASE HISTORY */
126 /* */
127 /* DATE NAME DESCRIPTION */
128 /* */
129 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
130 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
131 /* resulting in version 6.1 */
132 /* */
133 /**************************************************************************/
_nxe_ftp_server_create(NX_FTP_SERVER * ftp_server_ptr,CHAR * ftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr,UINT (* ftp_login)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,ULONG client_ip_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info),UINT (* ftp_logout)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,ULONG client_ip_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info))134 UINT _nxe_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
135 UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info),
136 UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info))
137 {
138
139 #ifndef NX_DISABLE_IPV4
140 UINT status;
141
142
143 /* Check for invalid input pointers. */
144 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
145 (ftp_server_ptr == NX_NULL) || (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) ||
146 (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL))
147 return(NX_PTR_ERROR);
148
149 /* Call actual server create function. */
150 status = _nx_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout);
151
152 /* Return completion status. */
153 return(status);
154 #else
155 NX_PARAMETER_NOT_USED(ftp_server_ptr);
156 NX_PARAMETER_NOT_USED(ftp_server_name);
157 NX_PARAMETER_NOT_USED(ip_ptr);
158 NX_PARAMETER_NOT_USED(media_ptr);
159 NX_PARAMETER_NOT_USED(stack_ptr);
160 NX_PARAMETER_NOT_USED(stack_size);
161 NX_PARAMETER_NOT_USED(pool_ptr);
162 NX_PARAMETER_NOT_USED(ftp_login);
163 NX_PARAMETER_NOT_USED(ftp_logout);
164
165 return(NX_NOT_SUPPORTED);
166 #endif /* NX_DISABLE_IPV4 */
167 }
168
169
170 /**************************************************************************/
171 /* */
172 /* FUNCTION RELEASE */
173 /* */
174 /* _nx_ftp_server_create PORTABLE C */
175 /* 6.1 */
176 /* AUTHOR */
177 /* */
178 /* Yuxin Zhou, Microsoft Corporation */
179 /* */
180 /* DESCRIPTION */
181 /* */
182 /* This function creates an FTP server on the specified IP. */
183 /* */
184 /* INPUT */
185 /* */
186 /* ftp_server_ptr Pointer to FTP server */
187 /* ftp_server_name Name of FTP server */
188 /* ip_ptr Pointer to IP instance */
189 /* media_ptr Pointer to media structure */
190 /* stack_ptr Server thread's stack pointer */
191 /* stack_size Server thread's stack size */
192 /* pool_ptr Pointer to packet pool */
193 /* ftp_login Pointer to user's login */
194 /* function */
195 /* ftp_logout Pointer to user's logout */
196 /* function */
197 /* */
198 /* OUTPUT */
199 /* */
200 /* status Completion status */
201 /* */
202 /* CALLS */
203 /* */
204 /* _nx_ftp_server_create_internal Actual server create call */
205 /* */
206 /* CALLED BY */
207 /* */
208 /* Application Code */
209 /* */
210 /* RELEASE HISTORY */
211 /* */
212 /* DATE NAME DESCRIPTION */
213 /* */
214 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
215 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
216 /* resulting in version 6.1 */
217 /* */
218 /**************************************************************************/
_nx_ftp_server_create(NX_FTP_SERVER * ftp_server_ptr,CHAR * ftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr,UINT (* ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,ULONG client_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info),UINT (* ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,ULONG client_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info))219 UINT _nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
220 UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info),
221 UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info))
222 {
223
224 #ifndef NX_DISABLE_IPV4
225 UINT status;
226
227
228 /* Call actual server create function but set the ftp login and logout arguments to NULL. */
229 status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, NX_NULL, NX_NULL);
230
231 /* Set the FTP server to accept login functions having IPv4 address arguments. */
232 ftp_server_ptr -> nx_ftp_login_ipv4 = ftp_login_ipv4;
233 ftp_server_ptr -> nx_ftp_logout_ipv4 = ftp_logout_ipv4;
234
235 /* Return status. */
236 return status;
237 #else
238 NX_PARAMETER_NOT_USED(ftp_server_ptr);
239 NX_PARAMETER_NOT_USED(ftp_server_name);
240 NX_PARAMETER_NOT_USED(ip_ptr);
241 NX_PARAMETER_NOT_USED(media_ptr);
242 NX_PARAMETER_NOT_USED(stack_ptr);
243 NX_PARAMETER_NOT_USED(stack_size);
244 NX_PARAMETER_NOT_USED(pool_ptr);
245 NX_PARAMETER_NOT_USED(ftp_login_ipv4);
246 NX_PARAMETER_NOT_USED(ftp_logout_ipv4);
247
248 return(NX_NOT_SUPPORTED);
249 #endif /* NX_DISABLE_IPV4 */
250 }
251
252
253 /**************************************************************************/
254 /* */
255 /* FUNCTION RELEASE */
256 /* */
257 /* _nxde_ftp_server_create PORTABLE C */
258 /* 6.1 */
259 /* AUTHOR */
260 /* */
261 /* Yuxin Zhou, Microsoft Corporation */
262 /* */
263 /* DESCRIPTION */
264 /* */
265 /* This function checks for errors in the FTP duo (IPv4 and IPv6) */
266 /* server create call. */
267 /* */
268 /* */
269 /* INPUT */
270 /* */
271 /* ftp_server_ptr Pointer to FTP server */
272 /* ftp_server_name Name of FTP server */
273 /* ip_ptr Pointer to IP instance */
274 /* media_ptr Pointer to media structure */
275 /* stack_ptr Server thread's stack pointer */
276 /* stack_size Server thread's stack size */
277 /* pool_ptr Pointer to packet pool */
278 /* ftp_login Pointer to user's login */
279 /* function */
280 /* ftp_logout Pointer to user's logout */
281 /* function */
282 /* */
283 /* OUTPUT */
284 /* */
285 /* status Completion status */
286 /* */
287 /* CALLS */
288 /* */
289 /* _nxd_ftp_server_create Actual server create call */
290 /* */
291 /* CALLED BY */
292 /* */
293 /* Application Code */
294 /* */
295 /* RELEASE HISTORY */
296 /* */
297 /* DATE NAME DESCRIPTION */
298 /* */
299 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
300 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
301 /* resulting in version 6.1 */
302 /* */
303 /**************************************************************************/
_nxde_ftp_server_create(NX_FTP_SERVER * ftp_server_ptr,CHAR * ftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr,UINT (* ftp_login)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_ipduo_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info),UINT (* ftp_logout)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_ipduo_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info))304 UINT _nxde_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
305 UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info),
306 UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info))
307 {
308
309 UINT status;
310
311
312 /* Check for invalid input pointers. */
313 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
314 (ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id == NXD_FTP_SERVER_ID) ||
315 (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) ||
316 (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL))
317 return(NX_PTR_ERROR);
318
319 /* Call actual server create function. */
320 status = _nxd_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout);
321
322 /* Return completion status. */
323 return(status);
324 }
325
326
327 /**************************************************************************/
328 /* */
329 /* FUNCTION RELEASE */
330 /* */
331 /* _nxd_ftp_server_create PORTABLE C */
332 /* 6.1 */
333 /* AUTHOR */
334 /* */
335 /* Yuxin Zhou, Microsoft Corporation */
336 /* */
337 /* DESCRIPTION */
338 /* */
339 /* This function creates a "duo" FTP server on the specified IP for */
340 /* IPv4 or IPv6 networks. */
341 /* */
342 /* INPUT */
343 /* */
344 /* ftp_server_ptr Pointer to FTP server */
345 /* ftp_server_name Name of FTP server */
346 /* ip_ptr Pointer to IP instance */
347 /* media_ptr Pointer to media structure */
348 /* stack_ptr Server thread's stack pointer */
349 /* stack_size Server thread's stack size */
350 /* pool_ptr Pointer to packet pool */
351 /* ftp_login Pointer to user's login */
352 /* function */
353 /* ftp_logout Pointer to user's logout */
354 /* function */
355 /* */
356 /* OUTPUT */
357 /* */
358 /* status Completion status */
359 /* */
360 /* CALLS */
361 /* */
362 /* _nx_ftp_server_create_internal Actual server create call */
363 /* */
364 /* CALLED BY */
365 /* */
366 /* Application Code */
367 /* */
368 /* RELEASE HISTORY */
369 /* */
370 /* DATE NAME DESCRIPTION */
371 /* */
372 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
373 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
374 /* resulting in version 6.1 */
375 /* */
376 /**************************************************************************/
_nxd_ftp_server_create(NX_FTP_SERVER * ftp_server_ptr,CHAR * ftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr,UINT (* ftp_login)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_ipduo_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info),UINT (* ftp_logout)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_ipduo_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info))377 UINT _nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
378 UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info),
379 UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info))
380 {
381
382
383 UINT status;
384
385
386 /* Call actual server create function. */
387 status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout);
388
389 /* Return status. */
390 return status;
391 }
392
393
394 /**************************************************************************/
395 /* */
396 /* FUNCTION RELEASE */
397 /* */
398 /* _nx_ftp_server_create_internal PORTABLE C */
399 /* 6.1 */
400 /* AUTHOR */
401 /* */
402 /* Yuxin Zhou, Microsoft Corporation */
403 /* */
404 /* DESCRIPTION */
405 /* */
406 /* This function creates a FTP server on the specified IP. */
407 /* */
408 /* INPUT */
409 /* */
410 /* ftp_server_ptr Pointer to FTP server */
411 /* ftp_server_name Name of FTP server */
412 /* ip_ptr Pointer to IP instance */
413 /* media_ptr Pointer to media structure */
414 /* stack_ptr Server thread's stack pointer */
415 /* stack_size Server thread's stack size */
416 /* pool_ptr Pointer to packet pool */
417 /* ftp_login Pointer to user's login */
418 /* function */
419 /* ftp_logout Pointer to user's logout */
420 /* function */
421 /* */
422 /* OUTPUT */
423 /* */
424 /* status Completion status */
425 /* NX_FTP_INSUFFICIENT_PACKET_PAYLOAD Packet payload too small */
426 /* */
427 /* CALLS */
428 /* */
429 /* nx_tcp_socket_create Create control sockets */
430 /* nx_tcp_socket_delete Delete control sockets */
431 /* nx_tcp_socket_receive_notify Register receive notify */
432 /* callback */
433 /* tx_event_flags_create Create event flags */
434 /* tx_event_flags_delete Delete event flags */
435 /* tx_thread_create Create FTP server thread */
436 /* tx_thread_delete Delete FTP server thread */
437 /* tx_timer_create Create FTP server timer */
438 /* tx_timer_delete Delete FTP server timer */
439 /* */
440 /* CALLED BY */
441 /* */
442 /* Application Code */
443 /* */
444 /* RELEASE HISTORY */
445 /* */
446 /* DATE NAME DESCRIPTION */
447 /* */
448 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
449 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
450 /* resulting in version 6.1 */
451 /* */
452 /**************************************************************************/
_nx_ftp_server_create_internal(NX_FTP_SERVER * ftp_server_ptr,CHAR * ftp_server_name,NX_IP * ip_ptr,FX_MEDIA * media_ptr,VOID * stack_ptr,ULONG stack_size,NX_PACKET_POOL * pool_ptr,UINT (* ftp_login)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info),UINT (* ftp_logout)(struct NX_FTP_SERVER_STRUCT * ftp_server_ptr,NXD_ADDRESS * client_address,UINT client_port,CHAR * name,CHAR * password,CHAR * extra_info))453 UINT _nx_ftp_server_create_internal(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr,
454 UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info),
455 UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info))
456 {
457
458 UINT i;
459 UINT status;
460
461
462 /* Clear the FTP server structure. */
463 memset((void *) ftp_server_ptr, 0, sizeof(NX_FTP_SERVER));
464
465 /* Check the supplied packet pool for minimum required payload length (NX_FTP_SERVER_MIN_PACKET_PAYLOAD). This configurable
466 option is explained in more detail in the header file. */
467 if (pool_ptr -> nx_packet_pool_payload_size < NX_FTP_SERVER_MIN_PACKET_PAYLOAD)
468 {
469
470 return NX_FTP_INSUFFICIENT_PACKET_PAYLOAD;
471 }
472
473 /* Save the packet pool pointer. */
474 ftp_server_ptr -> nx_ftp_server_packet_pool_ptr = pool_ptr;
475
476 /* Create the FTP Server thread. */
477 status = tx_thread_create(&(ftp_server_ptr -> nx_ftp_server_thread), "FTP Server Thread", _nx_ftp_server_thread_entry,
478 (ULONG) ftp_server_ptr, stack_ptr, stack_size, NX_FTP_SERVER_PRIORITY, NX_FTP_SERVER_PRIORITY,
479 NX_FTP_SERVER_TIME_SLICE, TX_DONT_START);
480
481 /* Determine if an error occurred creating the thread. */
482 if (status)
483 {
484
485 /* Error creating the server thread. */
486 return(status);
487 }
488
489 /* Create the ThreadX event flags. These will be used to driver the FTP server thread. */
490 status = tx_event_flags_create(&(ftp_server_ptr -> nx_ftp_server_event_flags),
491 "FTP Server Thread Events");
492
493 /* Determine if an error occurred creating the event flags. */
494 if (status)
495 {
496
497
498 /* Delete the server thread. */
499 tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread));
500
501 /* Error creating the server event flags. */
502 return(status);
503 }
504
505 /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if
506 a client connection has gone silent and needs to be terminated. */
507 status = tx_timer_create(&(ftp_server_ptr -> nx_ftp_server_timer), "FTP Server Timer", _nx_ftp_server_timeout,
508 (ULONG) ftp_server_ptr, (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD),
509 (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD), TX_NO_ACTIVATE);
510
511 /* Determine if an error occurred creating the timer. */
512 if (status)
513 {
514
515 /* Delete the server thread. */
516 tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread));
517
518 /* Delete the server event flags. */
519 tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags));
520
521 /* Error creating the server timer. */
522 return(status);
523 }
524
525 /* Loop to create all the FTP client control sockets. */
526 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
527 {
528
529 /* Create an FTP client control socket. */
530 status += nx_tcp_socket_create(ip_ptr, &(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket),
531 "FTP Server Control Socket", NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION,
532 NX_FTP_TIME_TO_LIVE, NX_FTP_CONTROL_WINDOW_SIZE, NX_NULL, _nx_ftp_server_control_disconnect);
533
534 /* If no error is present, register the receive notify function. */
535 if (status == NX_SUCCESS)
536 {
537
538 /* Register the receive function. */
539 nx_tcp_socket_receive_notify(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket),
540 _nx_ftp_server_command_present);
541 }
542
543 /* Make sure each socket points to the FTP server. */
544 ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
545 }
546
547 /* Determine if an error has occurred. */
548 if (status)
549 {
550
551 /* Loop to delete any created sockets. */
552 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
553 {
554
555 /* Delete the FTP socket. */
556 nx_tcp_socket_delete(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket));
557 }
558
559 /* Delete the server thread. */
560 tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread));
561
562 /* Delete the event flag group. */
563 tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags));
564
565 /* Delete the timer. */
566 tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer));
567
568 /* Return an error. */
569 return(status);
570 }
571
572 /* Initialize the data port. */
573 ftp_server_ptr -> nx_ftp_server_data_port = NX_SEARCH_PORT_START;
574
575 /* Save the Server name. */
576 ftp_server_ptr -> nx_ftp_server_name = ftp_server_name;
577
578 /* Save the IP pointer address. */
579 ftp_server_ptr -> nx_ftp_server_ip_ptr = ip_ptr;
580
581 /* Set the FTP media pointer address. */
582 ftp_server_ptr -> nx_ftp_server_media_ptr = media_ptr;
583
584 /* Save the user-supplied login and logout functions. */
585 ftp_server_ptr -> nx_ftp_login = ftp_login;
586 ftp_server_ptr -> nx_ftp_logout = ftp_logout;
587
588 /* Set the server ID to indicate the FTP server thread is ready. */
589 ftp_server_ptr -> nx_ftp_server_id = NXD_FTP_SERVER_ID;
590
591 /* Return successful completion. */
592 return(NX_SUCCESS);
593 }
594
595
596 /**************************************************************************/
597 /* */
598 /* FUNCTION RELEASE */
599 /* */
600 /* _nxe_ftp_server_delete PORTABLE C */
601 /* 6.1 */
602 /* AUTHOR */
603 /* */
604 /* Yuxin Zhou, Microsoft Corporation */
605 /* */
606 /* DESCRIPTION */
607 /* */
608 /* This function checks for errors in the FTP server delete call. */
609 /* */
610 /* */
611 /* INPUT */
612 /* */
613 /* ftp_server_ptr Pointer to FTP server */
614 /* */
615 /* OUTPUT */
616 /* */
617 /* status Completion status */
618 /* */
619 /* CALLS */
620 /* */
621 /* _nx_ftp_server_delete Actual server delete call */
622 /* */
623 /* CALLED BY */
624 /* */
625 /* Application Code */
626 /* */
627 /* RELEASE HISTORY */
628 /* */
629 /* DATE NAME DESCRIPTION */
630 /* */
631 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
632 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
633 /* resulting in version 6.1 */
634 /* */
635 /**************************************************************************/
_nxe_ftp_server_delete(NX_FTP_SERVER * ftp_server_ptr)636 UINT _nxe_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr)
637 {
638
639 UINT status;
640
641
642 /* Check for invalid input pointers. */
643 if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID))
644 return(NX_PTR_ERROR);
645
646 /* Check for appropriate caller. */
647 NX_THREADS_ONLY_CALLER_CHECKING
648
649 /* Call actual server delete function. */
650 status = _nx_ftp_server_delete(ftp_server_ptr);
651
652 /* Return completion status. */
653 return(status);
654 }
655
656
657 /**************************************************************************/
658 /* */
659 /* FUNCTION RELEASE */
660 /* */
661 /* _nx_ftp_server_delete PORTABLE C */
662 /* 6.1.9 */
663 /* AUTHOR */
664 /* */
665 /* Yuxin Zhou, Microsoft Corporation */
666 /* */
667 /* DESCRIPTION */
668 /* */
669 /* This function deletes a previously created FTP server on the */
670 /* specified IP. */
671 /* */
672 /* */
673 /* INPUT */
674 /* */
675 /* ftp_server_ptr Pointer to FTP server */
676 /* */
677 /* OUTPUT */
678 /* */
679 /* status Completion status */
680 /* */
681 /* CALLS */
682 /* */
683 /* fx_file_close Close file */
684 /* nx_tcp_server_socket_unaccept Unaccept server socket */
685 /* nx_tcp_server_socket_unlisten Unlisten on server */
686 /* nx_tcp_socket_delete Delete socket */
687 /* nx_tcp_socket_disconnect Disconnect socket */
688 /* tx_event_flags_delete Delete event flags */
689 /* tx_thread_delete Delete thread */
690 /* tx_thread_suspend Suspend thread */
691 /* tx_thread_terminate Terminate thread */
692 /* tx_timer_deactivate Deactivate timer */
693 /* tx_timer_delete Delete timer */
694 /* _nx_ftp_server_data_socket_cleanup Clean up data socket */
695 /* */
696 /* CALLED BY */
697 /* */
698 /* Application Code */
699 /* */
700 /* RELEASE HISTORY */
701 /* */
702 /* DATE NAME DESCRIPTION */
703 /* */
704 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
705 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
706 /* resulting in version 6.1 */
707 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
708 /* fixed the issue of clearing */
709 /* data socket, */
710 /* resulting in version 6.1.9 */
711 /* */
712 /**************************************************************************/
_nx_ftp_server_delete(NX_FTP_SERVER * ftp_server_ptr)713 UINT _nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr)
714 {
715
716 UINT i;
717 NX_FTP_CLIENT_REQUEST *client_request_ptr;
718
719
720 /* Clear the server ID to indicate the FTP server is no longer ready. */
721 ftp_server_ptr -> nx_ftp_server_id = 0;
722
723 /* Suspend the FTP server thread. */
724 tx_thread_suspend(&(ftp_server_ptr -> nx_ftp_server_thread));
725
726 /* Terminate server thread. */
727 tx_thread_terminate(&(ftp_server_ptr -> nx_ftp_server_thread));
728
729 /* Delete server thread. */
730 tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread));
731
732 /* Delete the event flag group. */
733 tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags));
734
735 /* Deactivate and delete timer. */
736 tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer));
737 tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer));
738
739 /* Walk through the server structure to close any remaining open files. */
740 for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++)
741 {
742
743 /* Set the client request. */
744 client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
745
746 /* If created, cleanup the data socket. */
747 if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
748 {
749
750 /* Clean up the data socket. */
751 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_request_ptr);
752 }
753
754 /* Reset the transfer mode as stream mode. */
755 client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
756
757 /* Reset the block bytes. */
758 client_request_ptr -> nx_ftp_client_request_block_bytes = 0;
759
760 /* Disconnect the control and data ports. */
761 nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT);
762
763 /* Unaccept the control socket. */
764 nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket));
765
766 /* Delete both the control and data sockets. */
767 nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_control_socket));
768 }
769
770 /* Unlisten on the FTP control port. */
771 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT);
772
773 /* Return successful completion. */
774 return(NX_SUCCESS);
775 }
776
777 /**************************************************************************/
778 /* */
779 /* FUNCTION RELEASE */
780 /* */
781 /* _nxe_ftp_server_start PORTABLE C */
782 /* 6.1 */
783 /* AUTHOR */
784 /* */
785 /* Yuxin Zhou, Microsoft Corporation */
786 /* */
787 /* DESCRIPTION */
788 /* */
789 /* This function checks for errors in the FTP server start call. */
790 /* */
791 /* */
792 /* INPUT */
793 /* */
794 /* ftp_server_ptr Pointer to FTP server */
795 /* */
796 /* OUTPUT */
797 /* */
798 /* status Completion status */
799 /* */
800 /* CALLS */
801 /* */
802 /* _nx_ftp_server_start Actual server start call */
803 /* */
804 /* CALLED BY */
805 /* */
806 /* Application Code */
807 /* */
808 /* RELEASE HISTORY */
809 /* */
810 /* DATE NAME DESCRIPTION */
811 /* */
812 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
813 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
814 /* resulting in version 6.1 */
815 /* */
816 /**************************************************************************/
_nxe_ftp_server_start(NX_FTP_SERVER * ftp_server_ptr)817 UINT _nxe_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr)
818 {
819
820 UINT status;
821
822
823 /* Check for invalid input pointers. */
824 if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID))
825 return(NX_PTR_ERROR);
826
827 /* Call actual server start function. */
828 status = _nx_ftp_server_start(ftp_server_ptr);
829
830 /* Return completion status. */
831 return(status);
832 }
833
834
835 /**************************************************************************/
836 /* */
837 /* FUNCTION RELEASE */
838 /* */
839 /* _nx_ftp_server_start PORTABLE C */
840 /* 6.1 */
841 /* AUTHOR */
842 /* */
843 /* Yuxin Zhou, Microsoft Corporation */
844 /* */
845 /* DESCRIPTION */
846 /* */
847 /* This function starts a previously created FTP server on the */
848 /* specified IP. */
849 /* */
850 /* */
851 /* INPUT */
852 /* */
853 /* ftp_server_ptr Pointer to FTP server */
854 /* */
855 /* OUTPUT */
856 /* */
857 /* status Completion status */
858 /* */
859 /* CALLS */
860 /* */
861 /* nx_tcp_server_socket_listen Listen of FTP clients */
862 /* tx_thread_resume Resume the FTP server thread */
863 /* tx_timer_activate Activate FTP server timer */
864 /* */
865 /* CALLED BY */
866 /* */
867 /* Application Code */
868 /* */
869 /* RELEASE HISTORY */
870 /* */
871 /* DATE NAME DESCRIPTION */
872 /* */
873 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
874 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
875 /* resulting in version 6.1 */
876 /* */
877 /**************************************************************************/
_nx_ftp_server_start(NX_FTP_SERVER * ftp_server_ptr)878 UINT _nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr)
879 {
880
881 UINT status;
882 ULONG events;
883
884
885 /* Start listening on the FTP control socket. */
886 status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT,
887 &(ftp_server_ptr -> nx_ftp_server_client_list[0].nx_ftp_client_request_control_socket),
888 NX_FTP_MAX_CLIENTS, _nx_ftp_server_connection_present);
889
890 /* Determine if an error is present. */
891 if (status)
892 {
893
894 /* Error, return to caller. */
895 return(status);
896 }
897
898 /* Activate FTP server timer. */
899 tx_timer_activate(&(ftp_server_ptr -> nx_ftp_server_timer));
900
901 /* Clear stop event. */
902 tx_event_flags_get(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR_CLEAR, &events, TX_NO_WAIT);
903
904 /* Start the FTP server thread. */
905 tx_thread_resume(&(ftp_server_ptr -> nx_ftp_server_thread));
906
907 /* Return successful completion. */
908 return(NX_SUCCESS);
909 }
910
911
912 /**************************************************************************/
913 /* */
914 /* FUNCTION RELEASE */
915 /* */
916 /* _nxe_ftp_server_stop PORTABLE C */
917 /* 6.1 */
918 /* AUTHOR */
919 /* */
920 /* Yuxin Zhou, Microsoft Corporation */
921 /* */
922 /* DESCRIPTION */
923 /* */
924 /* This function checks for errors in the FTP server stop call. */
925 /* */
926 /* */
927 /* INPUT */
928 /* */
929 /* ftp_server_ptr Pointer to FTP server */
930 /* */
931 /* OUTPUT */
932 /* */
933 /* status Completion status */
934 /* */
935 /* CALLS */
936 /* */
937 /* _nx_ftp_server_stop Actual server start call */
938 /* */
939 /* CALLED BY */
940 /* */
941 /* Application Code */
942 /* */
943 /* RELEASE HISTORY */
944 /* */
945 /* DATE NAME DESCRIPTION */
946 /* */
947 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
948 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
949 /* resulting in version 6.1 */
950 /* */
951 /**************************************************************************/
_nxe_ftp_server_stop(NX_FTP_SERVER * ftp_server_ptr)952 UINT _nxe_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr)
953 {
954
955 UINT status;
956
957
958 /* Check for invalid input pointers. */
959 if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID))
960 return(NX_PTR_ERROR);
961
962 /* Check for appropriate caller. */
963 NX_THREADS_ONLY_CALLER_CHECKING
964
965 /* Call actual server delete function. */
966 status = _nx_ftp_server_stop(ftp_server_ptr);
967
968 /* Return completion status. */
969 return(status);
970 }
971
972
973 /**************************************************************************/
974 /* */
975 /* FUNCTION RELEASE */
976 /* */
977 /* _nx_ftp_server_stop PORTABLE C */
978 /* 6.3.0 */
979 /* AUTHOR */
980 /* */
981 /* Yuxin Zhou, Microsoft Corporation */
982 /* */
983 /* DESCRIPTION */
984 /* */
985 /* This function stops a previously started FTP server on the */
986 /* specified IP. */
987 /* */
988 /* */
989 /* INPUT */
990 /* */
991 /* ftp_server_ptr Pointer to FTP server */
992 /* */
993 /* OUTPUT */
994 /* */
995 /* status Completion status */
996 /* */
997 /* CALLS */
998 /* */
999 /* tx_thread_suspend Suspend the FTP server thread */
1000 /* tx_timer_deactivate Deactivate FTP server timer */
1001 /* */
1002 /* CALLED BY */
1003 /* */
1004 /* Application Code */
1005 /* */
1006 /* RELEASE HISTORY */
1007 /* */
1008 /* DATE NAME DESCRIPTION */
1009 /* */
1010 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1011 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1012 /* resulting in version 6.1 */
1013 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
1014 /* removed deletion of control */
1015 /* socket, */
1016 /* resulting in version 6.3.0 */
1017 /* */
1018 /**************************************************************************/
_nx_ftp_server_stop(NX_FTP_SERVER * ftp_server_ptr)1019 UINT _nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr)
1020 {
1021
1022 UINT i;
1023 NX_FTP_CLIENT_REQUEST *client_request_ptr;
1024
1025 /* Deactivate FTP server timer. */
1026 tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer));
1027
1028 /* Suspend the FTP server thread. */
1029 tx_event_flags_set(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR);
1030
1031 /* Walk through the server structure to close any remaining open files. */
1032 for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++)
1033 {
1034
1035 /* Set the client request. */
1036 client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
1037
1038 /* If created, cleanup the data socket. */
1039 if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
1040 {
1041
1042 /* Disconnect data socket. */
1043 nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT);
1044
1045 /* Unbind/unaccept the data socket. */
1046 if (client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE)
1047 {
1048 nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_data_socket));
1049 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port);
1050 }
1051 else
1052 {
1053 nx_tcp_client_socket_unbind(&(client_request_ptr -> nx_ftp_client_request_data_socket));
1054 }
1055
1056 /* Delete data socket. */
1057 nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_data_socket));
1058
1059 /* Close file. */
1060 fx_file_close(&(client_request_ptr -> nx_ftp_client_request_file));
1061 }
1062
1063 /* Clear the passive transfer enabled flag. */
1064 client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE;
1065
1066 /* Reset the transfer mode as stream mode. */
1067 client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
1068
1069 /* Reset the block bytes. */
1070 client_request_ptr -> nx_ftp_client_request_block_bytes = 0;
1071
1072 /* Disconnect the control and data ports. */
1073 nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT);
1074
1075 /* Unaccept the control socket. */
1076 nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket));
1077 }
1078
1079 /* Unlisten on the FTP control port. */
1080 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT);
1081
1082 /* Return successful completion. */
1083 return(NX_SUCCESS);
1084 }
1085
1086
1087 /**************************************************************************/
1088 /* */
1089 /* FUNCTION RELEASE */
1090 /* */
1091 /* _nx_ftp_server_response PORTABLE C */
1092 /* 6.1 */
1093 /* AUTHOR */
1094 /* */
1095 /* Yuxin Zhou, Microsoft Corporation */
1096 /* */
1097 /* DESCRIPTION */
1098 /* */
1099 /* This function builds an FTP Server response. */
1100 /* */
1101 /* */
1102 /* INPUT */
1103 /* */
1104 /* socket FTP socket */
1105 /* packet_ptr Response packet pointer */
1106 /* reply_code Reply code string */
1107 /* message Optional message */
1108 /* */
1109 /* OUTPUT */
1110 /* */
1111 /* None */
1112 /* */
1113 /* CALLS */
1114 /* */
1115 /* nx_packet_release Packet release */
1116 /* nx_tcp_socket_send Send TCP packet */
1117 /* */
1118 /* CALLED BY */
1119 /* */
1120 /* NetX FTP Routines */
1121 /* */
1122 /* RELEASE HISTORY */
1123 /* */
1124 /* DATE NAME DESCRIPTION */
1125 /* */
1126 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1127 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1128 /* resulting in version 6.1 */
1129 /* */
1130 /**************************************************************************/
_nx_ftp_server_response(NX_TCP_SOCKET * socket,NX_PACKET * packet_ptr,CHAR * reply_code,CHAR * message)1131 VOID _nx_ftp_server_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message)
1132 {
1133
1134 UCHAR *buffer_ptr;
1135 UINT status;
1136
1137
1138 /* Set the packet prepend pointer. */
1139 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
1140 packet_ptr -> nx_packet_length = 0;
1141
1142 /* Now setup pointer to the buffer area. */
1143 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1144
1145 /* Copy reply code to the packet. */
1146 while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER)))
1147 {
1148
1149 /* copy the next character */
1150 *buffer_ptr++ = (UCHAR) *reply_code++;
1151
1152 /* Update the packet length. */
1153 packet_ptr -> nx_packet_length++;
1154 }
1155
1156 /* Add a separating space */
1157 *buffer_ptr++ = (UCHAR) ' ';
1158 packet_ptr -> nx_packet_length++;
1159
1160 /* Copy message to the packet */
1161 while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER)))
1162 {
1163
1164 /* copy the next character */
1165 *buffer_ptr++ = (UCHAR) *message++;
1166
1167 /* Update the packet length. */
1168 packet_ptr -> nx_packet_length++;
1169 }
1170
1171 /* Add a trailing space, CR, LF. */
1172 *buffer_ptr++ = ' ';
1173 *buffer_ptr++ = 13;
1174 *buffer_ptr = 10;
1175
1176 /* Adjust the packet length. */
1177 packet_ptr -> nx_packet_length += 3;
1178
1179 /* Setup the packet append pointer. */
1180 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
1181
1182 /* Send the failed message back. */
1183 status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT);
1184
1185 /* Determine if the send was unsuccessful. */
1186 if (status)
1187 {
1188
1189 /* Release the packet. */
1190 nx_packet_release(packet_ptr);
1191 }
1192 }
1193
1194
1195 /**************************************************************************/
1196 /* */
1197 /* FUNCTION RELEASE */
1198 /* */
1199 /* _nx_ftp_server_directory_response PORTABLE C */
1200 /* 6.1 */
1201 /* AUTHOR */
1202 /* */
1203 /* Yuxin Zhou, Microsoft Corporation */
1204 /* */
1205 /* DESCRIPTION */
1206 /* */
1207 /* This function builds an FTP Server directory response. */
1208 /* */
1209 /* */
1210 /* INPUT */
1211 /* */
1212 /* socket FTP socket */
1213 /* packet_ptr Response packet pointer */
1214 /* reply_code Reply code string */
1215 /* message Optional message */
1216 /* directory Directory path */
1217 /* */
1218 /* OUTPUT */
1219 /* */
1220 /* None */
1221 /* */
1222 /* CALLS */
1223 /* */
1224 /* nx_packet_release Packet release */
1225 /* nx_tcp_socket_send Send TCP packet */
1226 /* */
1227 /* CALLED BY */
1228 /* */
1229 /* NetX FTP Routines */
1230 /* */
1231 /* RELEASE HISTORY */
1232 /* */
1233 /* DATE NAME DESCRIPTION */
1234 /* */
1235 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1236 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1237 /* resulting in version 6.1 */
1238 /* */
1239 /**************************************************************************/
_nx_ftp_server_directory_response(NX_TCP_SOCKET * socket,NX_PACKET * packet_ptr,CHAR * reply_code,CHAR * message,CHAR * directory)1240 VOID _nx_ftp_server_directory_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message, CHAR *directory)
1241 {
1242
1243 UCHAR *buffer_ptr;
1244 UINT status;
1245
1246
1247 /* Set the packet prepend pointer. */
1248 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
1249 packet_ptr -> nx_packet_length = 0;
1250
1251 /* Now setup pointer to the buffer area. */
1252 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1253
1254 /* Copy reply code to the packet. */
1255 while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER)))
1256 {
1257
1258 /* copy the next character. */
1259 *buffer_ptr++ = (UCHAR) *reply_code++;
1260
1261 /* Update the packet length. */
1262 packet_ptr -> nx_packet_length++;
1263 }
1264
1265 /* Add a separating space and the leading ". */
1266 *buffer_ptr++ = (UCHAR) ' ';
1267 packet_ptr -> nx_packet_length++;
1268
1269 *buffer_ptr++ = (UCHAR) '"';
1270 packet_ptr -> nx_packet_length++;
1271
1272 /* Is there a valid directory. */
1273 if ((directory != NULL) && (*directory))
1274 {
1275
1276 /* If the directory doesn't start with a / then make sure it does. */
1277 if ((*directory != '/') && (*directory != '\\'))
1278 {
1279
1280 /* Add / to message. */
1281 *buffer_ptr++ = (UCHAR) '/';
1282 packet_ptr -> nx_packet_length++;
1283 }
1284
1285 /* Copy directory to the packet. */
1286 while ((*directory) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER)))
1287 {
1288
1289 /* Copy the next character , doubling any " characters. */
1290 if (*directory == '"')
1291 {
1292
1293 /* Double the character. */
1294 *buffer_ptr++ = (UCHAR) *directory;
1295 packet_ptr -> nx_packet_length++;
1296 }
1297
1298 /* Copy the directory character, converting backslashes to slashes. */
1299 if (*directory == '\\')
1300 {
1301
1302 /* Convert to slash for consistency. */
1303 *buffer_ptr++ = (UCHAR) '/';
1304 directory++;
1305 }
1306 else
1307 {
1308
1309 /* Copy regular directory character. */
1310 *buffer_ptr++ = (UCHAR) *directory++;
1311 }
1312
1313 /* Update the packet length. */
1314 packet_ptr -> nx_packet_length++;
1315 }
1316 }
1317 else
1318 {
1319
1320 /* No valid directory, simply assume root. */
1321 *buffer_ptr++ = (UCHAR) '/';
1322 packet_ptr -> nx_packet_length++;
1323 }
1324
1325 /* Add the trailing " and a separating space. */
1326 *buffer_ptr++ = (UCHAR) '"';
1327 packet_ptr -> nx_packet_length++;
1328
1329 *buffer_ptr++ = (UCHAR) ' ';
1330 packet_ptr -> nx_packet_length++;
1331
1332 /* Copy message to the packet. */
1333 while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER)))
1334 {
1335
1336 /* Copy the next character. */
1337 *buffer_ptr++ = (UCHAR) *message++;
1338
1339 /* Update the packet length. */
1340 packet_ptr -> nx_packet_length++;
1341 }
1342
1343 /* Add a trailing space, CR, LF. */
1344 *buffer_ptr++ = (UCHAR) ' ';
1345 *buffer_ptr++ = (UCHAR) 13;
1346 *buffer_ptr = (UCHAR) 10;
1347
1348 /* Adjust the packet length. */
1349 packet_ptr -> nx_packet_length += 3;
1350
1351 /* Setup the packet append pointer. */
1352 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
1353
1354 /* Send the failed message back. */
1355 status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT);
1356
1357 /* Determine if the send was unsuccessful. */
1358 if (status)
1359 {
1360
1361 /* Release the packet. */
1362 nx_packet_release(packet_ptr);
1363 }
1364 }
1365
1366 /**************************************************************************/
1367 /* */
1368 /* FUNCTION RELEASE */
1369 /* */
1370 /* _nx_ftp_server_thread_entry PORTABLE C */
1371 /* 6.1 */
1372 /* AUTHOR */
1373 /* */
1374 /* Yuxin Zhou, Microsoft Corporation */
1375 /* */
1376 /* DESCRIPTION */
1377 /* */
1378 /* This function is the entry of the FTP server. All basic */
1379 /* processing is initiated by this function. */
1380 /* */
1381 /* */
1382 /* INPUT */
1383 /* */
1384 /* ftp_server_address Pointer to FTP server */
1385 /* */
1386 /* OUTPUT */
1387 /* */
1388 /* None */
1389 /* */
1390 /* CALLS */
1391 /* */
1392 /* _nx_ftp_server_command_process Process client FTP command */
1393 /* _nx_ftp_server_connect_process Process connection requests */
1394 /* _nx_ftp_server_control_disconnect_processing */
1395 /* Process control disconnect */
1396 /* _nx_ftp_server_data_disconnect_process Process data disconnection */
1397 /* requests */
1398 /* _nx_ftp_server_data_process Process client write data */
1399 /* _nx_ftp_server_timeout_processing Process activity timeout */
1400 /* tx_event_flags_get Get FTP event(s) */
1401 /* */
1402 /* CALLED BY */
1403 /* */
1404 /* ThreadX */
1405 /* */
1406 /* RELEASE HISTORY */
1407 /* */
1408 /* DATE NAME DESCRIPTION */
1409 /* */
1410 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1411 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1412 /* resulting in version 6.1 */
1413 /* */
1414 /**************************************************************************/
_nx_ftp_server_thread_entry(ULONG ftp_server_address)1415 VOID _nx_ftp_server_thread_entry(ULONG ftp_server_address)
1416 {
1417
1418 NX_FTP_SERVER *server_ptr;
1419 UINT status;
1420 ULONG events;
1421
1422
1423 /* Setup the server pointer. */
1424 server_ptr = (NX_FTP_SERVER *) ftp_server_address;
1425
1426 /* Loop to process FTP Server requests. */
1427 while(1)
1428 {
1429
1430 /* Wait for an FTP client activity. */
1431 status = tx_event_flags_get(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_ANY_EVENT,
1432 TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
1433
1434 /* Check the return status. */
1435 if (status)
1436 {
1437
1438 /* If an error occurs, simply continue the loop. */
1439 continue;
1440 }
1441
1442 /* Check whether service is started. */
1443 if (events & NX_FTP_STOP_EVENT)
1444 {
1445
1446 /* Suspend thread here. */
1447 tx_thread_suspend(&server_ptr -> nx_ftp_server_thread);
1448 continue;
1449 }
1450
1451 /* Otherwise, an event is present. Process according to the event. */
1452
1453 /* Check for a client connection event. */
1454 if (events & NX_FTP_SERVER_CONNECT)
1455 {
1456
1457 /* Call the connect processing. */
1458 _nx_ftp_server_connect_process(server_ptr);
1459 }
1460
1461 /* Check for an FTP client write data event. */
1462 if (events & NX_FTP_SERVER_DATA)
1463 {
1464
1465 /* Call processing to handle client file write data. */
1466 _nx_ftp_server_data_process(server_ptr);
1467 }
1468
1469 /* Check for a FTP client command event. */
1470 if (events & NX_FTP_SERVER_COMMAND)
1471 {
1472
1473 /* Call the command processing. */
1474 _nx_ftp_server_command_process(server_ptr);
1475 }
1476
1477 /* Check for a client disconnect event. */
1478 if (events & NX_FTP_SERVER_DATA_DISCONNECT)
1479 {
1480
1481 /* Call the data disconnect processing. */
1482 _nx_ftp_server_data_disconnect_process(server_ptr);
1483 }
1484
1485 /* Check for a control disconnect event. */
1486 if (events & NX_FTP_SERVER_CONTROL_DISCONNECT)
1487 {
1488
1489 /* Call the control disconnect processing. */
1490 _nx_ftp_server_control_disconnect_processing(server_ptr);
1491 }
1492
1493
1494 /* Check for a client activity timeout event. */
1495 if (events & NX_FTP_SERVER_ACTIVITY_TIMEOUT)
1496 {
1497
1498 /* Call the activity timeout processing. */
1499 _nx_ftp_server_timeout_processing(server_ptr);
1500 }
1501 }
1502 }
1503
1504
1505 /**************************************************************************/
1506 /* */
1507 /* FUNCTION RELEASE */
1508 /* */
1509 /* _nx_ftp_server_command_process PORTABLE C */
1510 /* 6.3.0 */
1511 /* AUTHOR */
1512 /* */
1513 /* Yuxin Zhou, Microsoft Corporation */
1514 /* */
1515 /* DESCRIPTION */
1516 /* */
1517 /* This function handles all FTP client commands received on all */
1518 /* client connections. */
1519 /* */
1520 /* */
1521 /* INPUT */
1522 /* */
1523 /* ftp_server_ptr Pointer to FTP server */
1524 /* */
1525 /* OUTPUT */
1526 /* */
1527 /* None */
1528 /* */
1529 /* CALLS */
1530 /* */
1531 /* _nx_ftp_server_parse_command Parse FTP client command */
1532 /* _nx_ftp_server_response Send FTP response */
1533 /* _nx_ftp_server_directory_response Send FTP response for dir */
1534 /* _nx_ftp_server_number_to_ascii Converts number to ascii text */
1535 /* fx_file_attributes_read Read file attributes */
1536 /* fx_file_close Close file */
1537 /* fx_file_delete Delete file */
1538 /* fx_file_open Open file */
1539 /* fx_file_read Read from file */
1540 /* fx_file_rename Rename file */
1541 /* fx_file_truncate Truncate file */
1542 /* fx_directory_attributes_read Read directory attributes */
1543 /* fx_directory_create Create directory */
1544 /* fx_directory_delete Delete directory */
1545 /* fx_directory_first_entry_find Find first directory entry */
1546 /* fx_directory_local_path_restore Restore directory path */
1547 /* fx_directory_local_path_set Set directory path */
1548 /* fx_directory_next_entry_find Find next directory entry */
1549 /* fx_media_flush Flush cached media sectors */
1550 /* nx_ftp_packet_allocate Allocate a packet */
1551 /* nx_packet_release Release a packet */
1552 /* nx_tcp_client_socket_bind Bind client socket */
1553 /* nx_tcp_client_socket_connect Connect client socket */
1554 /* nxd_tcp_client_socket_connect Connect client socket in IPv6 */
1555 /* nx_tcp_client_socket_unbind Unbind client socket */
1556 /* nx_tcp_server_socket_relisten Relisten on server socket */
1557 /* nx_tcp_server_socket_unaccept Unaccept server connection */
1558 /* nx_tcp_socket_create Create data socket */
1559 /* nx_tcp_socket_delete Delete data socket */
1560 /* nx_tcp_socket_disconnect Disconnect socket */
1561 /* nx_tcp_socket_receive Receive from command socket */
1562 /* nx_tcp_socket_send Send packet */
1563 /* nx_tcp_socket_receive_notify Register notification routine */
1564 /* nx_tcp_socket_transmit_configure Configure data transer socket */
1565 /* _nx_utility_uint_to_string Convert number to string */
1566 /* _nx_ftp_server_data_socket_cleanup Clean up data socket */
1567 /* */
1568 /* CALLED BY */
1569 /* */
1570 /* _nx_ftp_server_thread_entry FTP server thread */
1571 /* */
1572 /* RELEASE HISTORY */
1573 /* */
1574 /* DATE NAME DESCRIPTION */
1575 /* */
1576 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1577 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
1578 /* packet length verification, */
1579 /* verified memcpy use cases, */
1580 /* resulting in version 6.1 */
1581 /* 12-31-2020 Yuxin Zhou Modified comment(s), improved */
1582 /* packet length verification, */
1583 /* resulting in version 6.1.3 */
1584 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
1585 /* corrected the pad character,*/
1586 /* resulting in version 6.1.8 */
1587 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
1588 /* fixed the issue of clearing */
1589 /* data socket and processing */
1590 /* disconnection event, */
1591 /* improved the PASV response, */
1592 /* fixed the bug of processing */
1593 /* STOR in passive mode, */
1594 /* reset the packet prepend */
1595 /* pointer for alignment, */
1596 /* resulting in version 6.1.9 */
1597 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
1598 /* fixed duplicate packet */
1599 /* release issue, avoided */
1600 /* duplicate creation for data */
1601 /* socket, fixed data length */
1602 /* underflow, */
1603 /* resulting in version 6.3.0 */
1604 /* */
1605 /**************************************************************************/
_nx_ftp_server_command_process(NX_FTP_SERVER * ftp_server_ptr)1606 VOID _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr)
1607 {
1608
1609
1610 #ifdef FEATURE_NX_IPV6
1611 NXD_ADDRESS ipduo_address;
1612 UINT port_size;
1613 CHAR temp_buffer[10];
1614 #endif
1615 #ifndef NX_DISABLE_IPV4
1616 ULONG connect_ip4_address = 0;
1617 UINT commas;
1618 ULONG ip_address;
1619 UINT temp;
1620 #endif /* NX_DISABLE_IPV4 */
1621 UINT i, j;
1622 INT k;
1623 UINT port;
1624 ULONG length;
1625 ULONG remaining_length;
1626 UINT status;
1627 UINT ftp_command;
1628 UINT single_file;
1629 UCHAR *buffer_ptr;
1630 NX_PACKET *packet_ptr;
1631 FX_LOCAL_PATH temp_path;
1632 NX_FTP_CLIENT_REQUEST *client_req_ptr;
1633 UINT attributes;
1634 ULONG size;
1635 UINT year, month, day;
1636 UINT hour, minute, second;
1637 CHAR filename[FX_MAX_LONG_NAME_LEN];
1638 const char *months[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
1639 UINT no_more_ftp_entries = NX_FALSE;
1640 ULONG block_size;
1641
1642 year = 1900;
1643 month = 1;
1644 day = 1;
1645 hour = 1;
1646 minute = 1;
1647 second = 1;
1648 attributes = 1;
1649 size = 1;
1650
1651 /* Now look for a socket that has receive data. */
1652 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
1653 {
1654
1655 /* Setup pointer to client request structure. */
1656 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
1657
1658 #ifndef NX_DISABLE_IPV4
1659 if(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
1660 {
1661 connect_ip4_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4;
1662 }
1663 #endif /* NX_DISABLE_IPV4 */
1664
1665 /* Now see if this socket has data. */
1666 if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_receive_queue_count)
1667 {
1668
1669 /* Reset the client request activity timeout. */
1670 client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT;
1671
1672 for (;;)
1673 {
1674
1675 /* Attempt to read a packet from this socket. */
1676 status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_control_socket), &packet_ptr, NX_NO_WAIT);
1677
1678 /* Check for not data present. */
1679 if (status != NX_SUCCESS)
1680 {
1681
1682 /* Break the loop and look at the next socket. */
1683 break;
1684 }
1685
1686 #ifndef NX_DISABLE_PACKET_CHAIN
1687 if (packet_ptr -> nx_packet_next)
1688 {
1689
1690 /* Release the packet. */
1691 nx_packet_release(packet_ptr);
1692
1693 /* And continue looking at other client requests. */
1694 continue;
1695 }
1696 #endif /* NX_DISABLE_PACKET_CHAIN */
1697
1698 /* Now, parse the command in the packet. Note that the parse command adjusts the packet pointer
1699 such that it is positioned at the next token in the buffer. */
1700 ftp_command = _nx_ftp_server_parse_command(packet_ptr);
1701
1702 /* Check to make sure the client request is authenticated. */
1703 if ((client_req_ptr -> nx_ftp_client_request_authenticated == NX_FALSE) &&
1704 (ftp_command != NX_FTP_USER) && (ftp_command != NX_FTP_PASS))
1705 {
1706
1707 /* Unauthorized request. */
1708
1709 /* Increment the access error count. */
1710 ftp_server_ptr -> nx_ftp_server_authentication_errors++;
1711
1712 /* Now send an error response to the client. */
1713 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1714 NX_FTP_CODE_UNAUTHORIZED, "Not logged in");
1715
1716 /* And continue looking at other client requests. */
1717 continue;
1718 }
1719
1720 /* Check to make sure the client has write access if requesting a write. */
1721 else if ((client_req_ptr -> nx_ftp_client_request_read_only == NX_TRUE) &&
1722 ((ftp_command == NX_FTP_STOR) || (ftp_command == NX_FTP_RNFR) || (ftp_command == NX_FTP_RNTO) ||
1723 (ftp_command == NX_FTP_DELE) || (ftp_command == NX_FTP_RMD ) || (ftp_command == NX_FTP_MKD )))
1724 {
1725
1726 /* Unauthorized request. */
1727
1728 /* Increment the access error count. */
1729 ftp_server_ptr -> nx_ftp_server_authentication_errors++;
1730
1731 /* Now send an error response to the client. */
1732 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1733 NX_FTP_CODE_NO_ACCT, "Need account for storing files");
1734
1735 /* And continue looking at other client requests. */
1736 continue;
1737 }
1738
1739 /* Switch on the command received. */
1740 switch(ftp_command)
1741 {
1742
1743 case NX_FTP_USER:
1744 {
1745
1746 /* Setup pointer to packet buffer area. */
1747 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1748
1749 /* First, save the username in the request structure. */
1750 for (j = 0; j < (NX_FTP_USERNAME_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++)
1751 {
1752
1753 /* Copy a character. */
1754 client_req_ptr -> nx_ftp_client_request_username[j] = (CHAR) buffer_ptr[j];
1755
1756 /* Determine if a CR/LF is present. */
1757 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
1758 break;
1759 }
1760
1761 /* Ensure the username is NULL terminated. */
1762 client_req_ptr -> nx_ftp_client_request_username[j] = NX_NULL;
1763
1764 /* Now send an intermediate response to the username. */
1765 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1766 NX_FTP_CODE_USER_OK, "Enter password");
1767 break;
1768 }
1769
1770 case NX_FTP_PASS:
1771 {
1772
1773 /* Setup pointer to packet buffer area. */
1774 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1775
1776 /* First, save the password in the request structure. */
1777 for (j = 0; j < (NX_FTP_PASSWORD_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++)
1778 {
1779
1780 /* Copy a character. */
1781 client_req_ptr -> nx_ftp_client_request_password[j] = (CHAR) buffer_ptr[j];
1782
1783 /* Determine if a CR/LF is present. */
1784 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
1785 break;
1786 }
1787
1788 /* Ensure the password is NULL terminated. */
1789 client_req_ptr -> nx_ftp_client_request_password[j] = NX_NULL;
1790
1791 /* Initially assume client will have read-write access. */
1792 client_req_ptr -> nx_ftp_client_request_read_only = NX_FALSE;
1793
1794 /* Initialize the login status as unsuccessful. */
1795 status = NX_FTP_INVALID_LOGIN;
1796
1797 /* Does this FTP server have an login handler? */
1798 if (ftp_server_ptr -> nx_ftp_login)
1799 {
1800
1801 /* Now call the user's login callback routine to see if the username,password is valid. */
1802 status = (ftp_server_ptr -> nx_ftp_login)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
1803 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
1804 client_req_ptr -> nx_ftp_client_request_username,
1805 client_req_ptr -> nx_ftp_client_request_password,
1806 &client_req_ptr -> nx_ftp_client_request_read_only);
1807 }
1808 #ifndef NX_DISABLE_IPV4
1809 else
1810 {
1811
1812 /* No duo handler. Check if this is an IPv4 connection. */
1813 if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4)
1814 {
1815
1816 /* This is an IPv4 connection. */
1817
1818 /* Does this server have an IPv4 login function? */
1819 if (ftp_server_ptr -> nx_ftp_login_ipv4)
1820 {
1821
1822 /* Yes; Now call the user's login callback routine to see if the username,password is valid. */
1823 status = (ftp_server_ptr -> nx_ftp_login_ipv4)
1824 (ftp_server_ptr,
1825 (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4),
1826 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
1827 client_req_ptr -> nx_ftp_client_request_username,
1828 client_req_ptr -> nx_ftp_client_request_password,
1829 &client_req_ptr -> nx_ftp_client_request_read_only);
1830 }
1831 }
1832 }
1833 #endif /* NX_DISABLE_IPV4 */
1834
1835 /* Set the login as TRUE. */
1836 client_req_ptr -> nx_ftp_client_request_login = NX_TRUE;
1837
1838 if (status == NX_SUCCESS)
1839 {
1840
1841 /* Successful connection. */
1842
1843 /* Mark as authenticated. */
1844 client_req_ptr -> nx_ftp_client_request_authenticated = NX_TRUE;
1845
1846 /* Default transfer type is ASCII image. */
1847 client_req_ptr -> nx_ftp_client_request_transfer_type = 'A';
1848
1849 /* Now build a successful response to the client. */
1850 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1851 NX_FTP_CODE_LOGIN, "Logged in");
1852 }
1853 else
1854 {
1855
1856 /* Unsuccessful login. */
1857
1858 /* Increment the number of login errors. */
1859 ftp_server_ptr -> nx_ftp_server_login_errors++;
1860
1861 /* Now send an error response to the client. */
1862 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1863 NX_FTP_CODE_UNAUTHORIZED, "Login Fail");
1864 }
1865
1866 break;
1867 }
1868
1869 case NX_FTP_QUIT:
1870 {
1871
1872 /* Increment the number of disconnection requests. */
1873 ftp_server_ptr -> nx_ftp_server_disconnection_requests++;
1874
1875 /* Check if this client login. */
1876 if (client_req_ptr -> nx_ftp_client_request_login)
1877 {
1878
1879 /* Call the logout function. */
1880
1881 #ifndef NX_DISABLE_IPV4
1882 /* Does this server have an IPv4 login function? */
1883 if (ftp_server_ptr -> nx_ftp_logout_ipv4)
1884 {
1885
1886 /* Call the logout which takes IPv4 address input. */
1887 (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr,
1888 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4,
1889 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
1890 client_req_ptr -> nx_ftp_client_request_username,
1891 client_req_ptr -> nx_ftp_client_request_password, NX_NULL);
1892 }
1893 #endif /* NX_DISABLE_IPV4 */
1894 if (ftp_server_ptr -> nx_ftp_logout)
1895 {
1896
1897 /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */
1898 (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
1899 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
1900 client_req_ptr -> nx_ftp_client_request_username,
1901 client_req_ptr -> nx_ftp_client_request_password, NX_NULL);
1902 }
1903
1904 /* Set the login as FALSE. */
1905 client_req_ptr -> nx_ftp_client_request_login = NX_FALSE;
1906 }
1907
1908 /* Clear authentication. */
1909 client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE;
1910
1911 /* Now send a successful response to the client. */
1912 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1913 NX_FTP_CODE_CLOSE, "Logging Off");
1914
1915 /* If create, cleanup the associated data socket. */
1916 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
1917 {
1918
1919 /* Clean up the client socket. */
1920 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
1921 }
1922
1923 /* Now disconnect the command socket. */
1924 nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT);
1925
1926 /* Unaccept the server socket. */
1927 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket));
1928
1929 /* Relisten on this socket. This will probably fail, but it is needed just in case all available
1930 clients were in use at the time of the last relisten. */
1931 nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT,
1932 &(client_req_ptr -> nx_ftp_client_request_control_socket));
1933
1934 /* Check to see if a packet is queued up. */
1935 if (client_req_ptr -> nx_ftp_client_request_packet)
1936 {
1937
1938 /* Yes, release it! */
1939 nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet);
1940 client_req_ptr -> nx_ftp_client_request_packet = NX_NULL;
1941 }
1942
1943 /* Disable the client request activity timeout. */
1944 client_req_ptr -> nx_ftp_client_request_activity_timeout = 0;
1945 break;
1946 }
1947
1948 case NX_FTP_RETR:
1949 {
1950
1951 /* Check that the transfer type is a Binary Image. */
1952 if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')
1953 {
1954
1955 /* Now send a successful response to the client. */
1956 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1957 NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed");
1958
1959 /* We are done processing. */
1960 break;
1961 }
1962
1963 /* Check packet length. */
1964 if (packet_ptr -> nx_packet_length == 0)
1965 {
1966
1967 /* Empty message. */
1968
1969 /* Now send an error response to the client. */
1970 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
1971 NX_FTP_CODE_BAD_FILE, "File Open Fail");
1972 break;
1973 }
1974
1975 /* Change to the default directory of this connection. */
1976 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
1977
1978 /* Setup pointer to packet buffer area. */
1979 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1980
1981 /* Find the end of the message. */
1982 j = 0;
1983 while (j < packet_ptr -> nx_packet_length - 1)
1984 {
1985
1986 /* Determine if a CR/LF is present. */
1987 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
1988 break;
1989
1990 /* Move to next character. */
1991 j++;
1992 }
1993
1994 /* Ensure the name is NULL terminated. */
1995 buffer_ptr[j] = NX_NULL;
1996
1997 /* Attempt to open the file. */
1998 status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr,
1999 &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr,
2000 FX_OPEN_FOR_READ);
2001
2002 /* Determine if the file open was successful. */
2003 if (status == FX_SUCCESS)
2004 {
2005
2006 /* Check if passive transfer enabled. */
2007 if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE)
2008 {
2009
2010 /* Now wait for the data connection to connect. */
2011 status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT);
2012
2013 /* Check for connect error. */
2014 if (status)
2015 {
2016
2017 /* Yes, a connect error is present. Tear everything down. */
2018 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2019 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port);
2020 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2021 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
2022 }
2023 }
2024 else if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
2025 {
2026
2027 /* Socket already created. Error. */
2028 status = NX_NOT_CLOSED;
2029 }
2030 else
2031 {
2032
2033 /* Create an FTP client data socket. */
2034 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr,
2035 &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
2036 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE,
2037 NX_NULL, NX_NULL);
2038
2039 /* If no error is present, register the receive notify function. */
2040 if (status == NX_SUCCESS)
2041 {
2042
2043 /* Make sure each socket points to the corresponding FTP server. */
2044 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
2045
2046 /* Bind the socket to the FTP server data port. */
2047 status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2048 NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT);
2049
2050 /* Determine if the socket was bound. */
2051 if (status)
2052 {
2053
2054 /* FTP server data port is busy, use any data port. */
2055 nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT);
2056 }
2057
2058 /* Now attempt to connect the data port to the client's data port. */
2059 status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2060 &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
2061 client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT);
2062
2063 /* Check for connect error. */
2064 if (status)
2065 {
2066
2067 /* Yes, a connect error is present. Tear everything down. */
2068 nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2069 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2070 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
2071 }
2072 else
2073 {
2074
2075 /* Setup the data port with a specific packet transmit retry logic. */
2076 nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2077 NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH,
2078 NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE,
2079 NX_FTP_SERVER_RETRY_MAX,
2080 NX_FTP_SERVER_RETRY_SHIFT);
2081 }
2082 }
2083 }
2084 }
2085
2086 /* Now check and see if the open for read has any errors. */
2087 if (status == NX_SUCCESS)
2088 {
2089
2090 /* The open for read command is successful! */
2091
2092 /* Set the open for read type in the client request structure. */
2093 client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_READ;
2094
2095 /* Set the total bytes field to files size. */
2096 client_req_ptr -> nx_ftp_client_request_total_bytes = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size;
2097
2098 /* Now send a successful response to the client. */
2099 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2100 NX_FTP_CODE_START_XFER, "File Opened");
2101
2102 /* Determine if the block mode is enabled. */
2103 if ((client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) &&
2104 (client_req_ptr -> nx_ftp_client_request_total_bytes))
2105 {
2106
2107 /* Send start block header for file size. */
2108 status = _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr,
2109 client_req_ptr -> nx_ftp_client_request_total_bytes);
2110 }
2111
2112 /* Now read the file and send the contents to the client. */
2113 while (status == NX_SUCCESS)
2114 {
2115
2116 /* Allocate a new packet. */
2117 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
2118
2119 /* Calculate the maximum read size. */
2120 length = ((ULONG) (packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - NX_PHYSICAL_TRAILER;
2121
2122 /* Determine if the length is greater than the connected MSS. */
2123 if (length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss)
2124 {
2125
2126 /* Yes, reduce the length to match the MSS. */
2127 length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss;
2128 }
2129
2130 /* Read a buffer's worth of the file. */
2131 status = fx_file_read(&(client_req_ptr -> nx_ftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr, length, &length);
2132
2133 /* Determine if the file read was successful. */
2134 if (status == FX_SUCCESS)
2135 {
2136
2137 /* Now send the packet on the data socket. */
2138
2139 /* Set the packet length. */
2140 packet_ptr -> nx_packet_length = length;
2141
2142 /* Setup the packet append pointer. */
2143 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
2144
2145 /* Send the file data to the client. */
2146 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2147 packet_ptr, NX_FTP_SERVER_TIMEOUT);
2148
2149 /* Determine if the send was unsuccessful. */
2150 if (status)
2151 {
2152 /* Release the packet. */
2153 nx_packet_release(packet_ptr);
2154 }
2155 else
2156 {
2157
2158 /* Update the remaining bytes in the file. */
2159 client_req_ptr -> nx_ftp_client_request_total_bytes = client_req_ptr -> nx_ftp_client_request_total_bytes - length;
2160
2161 /* Increment the number of bytes sent. */
2162 ftp_server_ptr -> nx_ftp_server_total_bytes_sent += length;
2163 }
2164 }
2165 else
2166 {
2167
2168 /* Release packet. */
2169 nx_packet_release(packet_ptr);
2170 }
2171 }
2172
2173 /* Determine if the block mode is enabled. */
2174 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
2175 {
2176
2177 /* Send end block header for file size. */
2178 _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0);
2179 }
2180
2181 /* Clean up the data socket. */
2182 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
2183
2184 /* Clear the open type in the client request structure. */
2185 client_req_ptr -> nx_ftp_client_request_open_type = 0;
2186
2187 /* Allocate a new packet. */
2188 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
2189
2190 /* Now determine if the read was a success. */
2191 if ((status == FX_END_OF_FILE) && (client_req_ptr -> nx_ftp_client_request_total_bytes == 0))
2192 {
2193
2194 /* The read command was successful! */
2195 /* Now send a successful response to the client. */
2196 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2197 NX_FTP_CODE_COMPLETED, "File Sent");
2198 }
2199 else
2200 {
2201
2202 /* Read command failed. */
2203 /* Now send an error response to the client. */
2204 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2205 NX_FTP_CODE_BAD_FILE, "Read Fail");
2206 }
2207 }
2208 else
2209 {
2210
2211 /* Unsuccessful open for read or read command. */
2212
2213 /* Now send an error response to the client. */
2214 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2215 NX_FTP_CODE_BAD_FILE, "File Open Fail");
2216 }
2217
2218 break;
2219 }
2220
2221 case NX_FTP_STOR:
2222 {
2223
2224 /* Check that the transfer type is a Binary Image. */
2225 if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')
2226 {
2227
2228 /* Now send a successful response to the client. */
2229 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2230 NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed");
2231
2232 /* And we are done processing. */
2233 break;
2234 }
2235
2236 /* Check packet length. */
2237 if (packet_ptr -> nx_packet_length == 0)
2238 {
2239
2240 /* Empty message. */
2241
2242 /* Now send an error response to the client. */
2243 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2244 NX_FTP_CODE_BAD_FILE, "File Open Failed");
2245 break;
2246 }
2247
2248 /* Change to the default directory of this connection. */
2249 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2250
2251 /* Setup pointer to packet buffer area. */
2252 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2253
2254 /* Find the end of the message. */
2255 j = 0;
2256 while (j < packet_ptr -> nx_packet_length - 1)
2257 {
2258
2259 /* Determine if a CR/LF is present. */
2260 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2261 break;
2262
2263 /* Move to next character. */
2264 j++;
2265 }
2266
2267 /* Ensure the name is NULL terminated. */
2268 buffer_ptr[j] = NX_NULL;
2269
2270 /* Attempt to open the file. */
2271 status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE);
2272
2273
2274 /* Determine if there was an error. */
2275 if (status != FX_SUCCESS)
2276 {
2277
2278 /* Create a new file. */
2279 status = fx_file_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr);
2280
2281 if (status == FX_SUCCESS)
2282 {
2283
2284 /* Open the new file. */
2285 status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE);
2286 }
2287 }
2288
2289 /* Truncate the file to a size of 0. */
2290 status += fx_file_truncate(&(client_req_ptr -> nx_ftp_client_request_file), 0);
2291
2292 /* Determine if the file create/open was successful. */
2293 if (status == FX_SUCCESS)
2294 {
2295
2296 /* Check if passive transfer enabled. */
2297 if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_FALSE)
2298 {
2299 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
2300 {
2301
2302 /* Socket already created. Error. */
2303 status = NX_NOT_CLOSED;
2304 }
2305 else
2306 {
2307
2308 /* Create an FTP client data socket. */
2309 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
2310 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, _nx_ftp_server_data_disconnect);
2311
2312 /* If no error is present, register the receive notify function. */
2313 if (status == NX_SUCCESS)
2314 {
2315
2316 /* Make sure each socket points to the corresponding FTP server. */
2317 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
2318
2319 /* Register the receive function. */
2320 nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2321 _nx_ftp_server_data_present);
2322
2323 /* Bind the socket to the FTP server data port. */
2324 status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT);
2325
2326 /* Determine if the socket was bound. */
2327 if (status)
2328 {
2329
2330 /* FTP server data port is busy, use any data port. */
2331 nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT);
2332 }
2333 /* Now attempt to connect the data port to the client's data port. */
2334 status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2335 &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
2336 client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT);
2337
2338
2339 /* Check for connect error. */
2340 if (status)
2341 {
2342 /* Yes, a connect error is present. Tear everything down. */
2343 nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2344 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2345 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
2346
2347 #ifdef NX_FTP_FAULT_TOLERANT
2348
2349 /* Flush the media. */
2350 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
2351 #endif
2352 }
2353 else
2354 {
2355 /* Setup the data port with a specific packet transmit retry logic. */
2356 nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2357 NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH,
2358 NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE,
2359 NX_FTP_SERVER_RETRY_MAX,
2360 NX_FTP_SERVER_RETRY_SHIFT);
2361 }
2362 }
2363 }
2364 }
2365 }
2366
2367 /* Now check and see if the open for write has any errors. */
2368 if (status == NX_SUCCESS)
2369 {
2370
2371 /* The open for writing command is successful! */
2372
2373 /* Set the open for write type in the client request structure. */
2374 client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_WRITE;
2375
2376 /* Set the total bytes field to zero. */
2377 client_req_ptr -> nx_ftp_client_request_total_bytes = 0;
2378
2379 /* Now send a successful response to the client. */
2380 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2381 NX_FTP_CODE_START_XFER, "File Open for Write");
2382 }
2383 else
2384 {
2385 /* Unsuccessful open for writing command. */
2386
2387 /* Now send an error response to the client. */
2388 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2389 NX_FTP_CODE_BAD_FILE, "File Open Failed");
2390 }
2391
2392 break;
2393 }
2394
2395 case NX_FTP_RNFR:
2396 {
2397
2398 /* Check packet length. */
2399 if (packet_ptr -> nx_packet_length == 0)
2400 {
2401
2402 /* Empty message. */
2403
2404 /* Now send an error response to the client. */
2405 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2406 NX_FTP_CODE_BAD_FILE, "Rename File not found");
2407 break;
2408 }
2409
2410 /* Change to the default directory of this connection. */
2411 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2412
2413 /* Setup pointer to packet buffer area. */
2414 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2415
2416 /* Find the end of the message. */
2417 j = 0;
2418 while (j < packet_ptr -> nx_packet_length - 1)
2419 {
2420
2421 /* Determine if a CR/LF is present. */
2422 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2423 break;
2424
2425 /* Move to next character. */
2426 j++;
2427 }
2428
2429 /* If specified path ends with slash or backslash, strip it. */
2430 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
2431 {
2432 j--;
2433 }
2434
2435 /* Ensure the name is NULL terminated. */
2436 buffer_ptr[j] = NX_NULL;
2437
2438 /* Read the file attributes to see if it is actually there. */
2439 status = fx_file_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j);
2440
2441 /* If not a file, read the directory attributes. */
2442 if (status == FX_NOT_A_FILE)
2443 status = fx_directory_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j);
2444
2445 /* Determine if it was successful. */
2446 if (status == NX_SUCCESS)
2447 {
2448
2449 /* Successful start to the file rename. */
2450
2451 /* Save the packet in the client request structure. */
2452 client_req_ptr -> nx_ftp_client_request_packet = packet_ptr;
2453
2454 /* Allocate a new packet. */
2455 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
2456
2457 /* Now send a successful response to the client. */
2458 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2459 NX_FTP_CODE_FILE_PEND, "Rename File From");
2460 }
2461 else
2462 {
2463
2464 /* Unsuccessful first half of file rename. */
2465
2466 /* Now send an error response to the client. */
2467 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2468 NX_FTP_CODE_BAD_FILE, "Rename File not found");
2469 }
2470 break;
2471 }
2472
2473 case NX_FTP_RNTO:
2474 {
2475
2476 /* Check packet length. */
2477 if (packet_ptr -> nx_packet_length == 0)
2478 {
2479
2480 /* Empty message. */
2481
2482 /* Now send an error response to the client. */
2483 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2484 NX_FTP_CODE_BAD_FILE, "Rename failed");
2485 break;
2486 }
2487
2488 /* Change to the default directory of this connection. */
2489 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2490
2491 /* Setup pointer to packet buffer area. */
2492 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2493
2494 /* Find the end of the message. */
2495 j = 0;
2496 while (j < packet_ptr -> nx_packet_length - 1)
2497 {
2498
2499 /* Determine if a CR/LF is present. */
2500 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2501 break;
2502
2503 /* Move to next character. */
2504 j++;
2505 }
2506
2507 /* If specified path ends with slash or backslash, strip it. */
2508 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
2509 {
2510 j--;
2511 }
2512
2513 /* Ensure the name is NULL terminated. */
2514 buffer_ptr[j] = NX_NULL;
2515
2516 /* Rename the file. */
2517 status = fx_file_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr);
2518
2519 /* If not a file, rename the directory. */
2520 if (status == FX_NOT_A_FILE)
2521 status = fx_directory_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr);
2522
2523 #ifdef NX_FTP_FAULT_TOLERANT
2524
2525 /* Flush the media. */
2526 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
2527 #endif
2528
2529 /* Release the packet in the client request structure. */
2530 nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet);
2531 client_req_ptr -> nx_ftp_client_request_packet = NX_NULL;
2532
2533 /* Determine if it was successful. */
2534 if (status == NX_SUCCESS)
2535 {
2536
2537 /* Successful file rename. */
2538
2539 /* Now send a successful response to the client. */
2540 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2541 NX_FTP_CODE_COMPLETED, "File Renamed");
2542 }
2543 else
2544 {
2545
2546 /* Unsuccessful file rename. */
2547
2548 /* Now send an error response to the client. */
2549 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2550 NX_FTP_CODE_BAD_FILE, "Rename failed");
2551 }
2552 break;
2553 }
2554
2555 case NX_FTP_DELE:
2556 {
2557
2558 /* Check packet length. */
2559 if (packet_ptr -> nx_packet_length == 0)
2560 {
2561
2562 /* Empty message. */
2563
2564 /* Now send an error response to the client. */
2565 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2566 NX_FTP_CODE_BAD_FILE, "Delete Failed");
2567 break;
2568 }
2569
2570 /* Change to the default directory of this connection. */
2571 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2572
2573 /* Setup pointer to packet buffer area. */
2574 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2575
2576 /* Find the end of the message. */
2577 j = 0;
2578 while (j < packet_ptr -> nx_packet_length - 1)
2579 {
2580
2581 /* Determine if a CR/LF is present. */
2582 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2583 break;
2584
2585 /* Move to next character. */
2586 j++;
2587 }
2588
2589 /* Ensure the name is NULL terminated. */
2590 buffer_ptr[j] = NX_NULL;
2591
2592 /* Remove the specified file. */
2593 status = fx_file_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr);
2594
2595 #ifdef NX_FTP_FAULT_TOLERANT
2596
2597 /* Flush the media. */
2598 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
2599 #endif
2600
2601 /* Determine if it was successful. */
2602 if (status == NX_SUCCESS)
2603 {
2604
2605 /* Successful delete file. */
2606
2607 /* Now send a successful response to the client. */
2608 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2609 NX_FTP_CODE_COMPLETED, "File Deleted");
2610 }
2611 else
2612 {
2613
2614 /* Unsuccessful file delete. */
2615
2616 /* Now send an error response to the client. */
2617 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2618 NX_FTP_CODE_BAD_FILE, "Delete Failed");
2619 }
2620 break;
2621 }
2622
2623 case NX_FTP_RMD:
2624 {
2625
2626 /* Check packet length. */
2627 if (packet_ptr -> nx_packet_length == 0)
2628 {
2629
2630 /* Empty message. */
2631
2632 /* Now send an error response to the client. */
2633 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2634 NX_FTP_CODE_BAD_FILE, "Delete Directory Fail");
2635 break;
2636 }
2637
2638 /* Change to the default directory of this connection. */
2639 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2640
2641 /* Setup pointer to packet buffer area. */
2642 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2643
2644 /* Find the end of the message. */
2645 j = 0;
2646 while (j < packet_ptr -> nx_packet_length - 1)
2647 {
2648
2649 /* Determine if a CR/LF is present. */
2650 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2651 break;
2652
2653 /* Move to next character. */
2654 j++;
2655 }
2656
2657 /* If specified path ends with slash or backslash, strip it. */
2658 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
2659 {
2660 j--;
2661 }
2662
2663 /* Ensure the name is NULL terminated. */
2664 buffer_ptr[j] = NX_NULL;
2665
2666 /* Remove the specified directory. */
2667 status = fx_directory_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr);
2668
2669 #ifdef NX_FTP_FAULT_TOLERANT
2670
2671 /* Flush the media. */
2672 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
2673 #endif
2674
2675 /* Determine if it was successful. */
2676 if (status == NX_SUCCESS)
2677 {
2678
2679 /* Successful delete directory. */
2680
2681 /* Now send a successful response to the client. */
2682 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2683 NX_FTP_CODE_COMPLETED, "Directory Deleted");
2684 }
2685 else
2686 {
2687
2688 /* Unsuccessful directory delete. */
2689
2690 /* Now send an error response to the client. */
2691 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2692 NX_FTP_CODE_BAD_FILE, "Delete Directory Fail");
2693 }
2694 break;
2695 }
2696
2697 case NX_FTP_MKD:
2698 {
2699
2700 /* Check packet length. */
2701 if (packet_ptr -> nx_packet_length == 0)
2702 {
2703
2704 /* Empty message. */
2705
2706 /* Now send an error response to the client. */
2707 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2708 NX_FTP_CODE_BAD_FILE, "Directory Create failed");
2709 break;
2710 }
2711
2712 /* Change to the default directory of this connection. */
2713 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2714
2715 /* Setup pointer to packet buffer area. */
2716 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2717
2718 /* Find the end of the message. */
2719 j = 0;
2720 while (j < packet_ptr -> nx_packet_length - 1)
2721 {
2722
2723 /* Determine if a CR/LF is present. */
2724 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2725 break;
2726
2727 /* Move to next character. */
2728 j++;
2729 }
2730
2731 /* If specified path ends with slash or backslash, strip it. */
2732 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
2733 {
2734 j--;
2735 }
2736
2737 /* Ensure the name is NULL terminated. */
2738 buffer_ptr[j] = NX_NULL;
2739
2740 /* Create the specified directory. */
2741 status = fx_directory_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr);
2742
2743 #ifdef NX_FTP_FAULT_TOLERANT
2744
2745 /* Flush the media. */
2746 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
2747 #endif
2748
2749 /* Determine if it was successful. */
2750 if (status == NX_SUCCESS)
2751 {
2752
2753 FX_LOCAL_PATH temporary_path;
2754
2755
2756 /* Successful create directory. */
2757
2758 /* Change the path to the new directory, using a temporary directory structure */
2759 status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temporary_path, (CHAR *) buffer_ptr);
2760
2761 /* Determine if it was successful. */
2762 if (status == NX_SUCCESS)
2763 {
2764
2765 CHAR *local_dir;
2766
2767
2768 /* Successful change directory. */
2769
2770 /* Get the actual path */
2771 fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir);
2772
2773 /* Now send a successful response to the client. */
2774 _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2775 NX_FTP_CODE_CMD_OK, "Directory Created", local_dir);
2776 }
2777 else
2778 {
2779 /* Unsuccessful directory change. */
2780
2781 /* Now send an error response to the client. */
2782 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2783 NX_FTP_CODE_BAD_FILE, "Set New Directory Fail");
2784 }
2785
2786 /* Restore the default directory of this connection. */
2787 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2788 }
2789 else
2790 {
2791
2792 /* Unsuccessful directory create. */
2793
2794 /* Now send an error response to the client. */
2795 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2796 NX_FTP_CODE_BAD_FILE, "Directory Create failed");
2797 }
2798 break;
2799 }
2800
2801 case NX_FTP_NLST:
2802 {
2803
2804 /* Assume ASCII and relax restriction. */
2805 if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') &&
2806 (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I'))
2807 {
2808
2809 /* Now send a successful response to the client. */
2810 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2811 NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed");
2812
2813 /* And we are done processing. */
2814 break;
2815 }
2816
2817 /* Check packet length. */
2818 if (packet_ptr -> nx_packet_length == 0)
2819 {
2820
2821 /* Empty message. */
2822
2823 /* Now send an error response to the client. */
2824 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2825 NX_FTP_CODE_BAD_FILE, "List bad Directory");
2826 break;
2827 }
2828
2829 /* Change to the default directory of this connection. */
2830 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
2831
2832 /* Setup pointer to packet buffer area. */
2833 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
2834
2835 /* Find the end of the message. */
2836 j = 0;
2837 while (j < packet_ptr -> nx_packet_length - 1)
2838 {
2839
2840 /* Determine if a CR/LF is present. */
2841 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
2842 break;
2843
2844 /* Move to next character. */
2845 j++;
2846 }
2847
2848 /* If specified path ends with slash or backslash, strip it. */
2849 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
2850 {
2851 j--;
2852 }
2853
2854 /* Determine if there is a directory path. */
2855 if (j)
2856 {
2857
2858 /* Ensure the name is NULL terminated. */
2859 buffer_ptr[j] = NX_NULL;
2860
2861 /* Set the path to the supplied directory. */
2862 status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr);
2863 }
2864 else
2865 {
2866
2867 /* Just set the buffer pointer to NULL since there isn't a string. */
2868 buffer_ptr = NX_NULL;
2869
2870 /* Default status to success. */
2871 status = FX_SUCCESS;
2872 }
2873
2874
2875 /* Determine if the path setup was successful. */
2876 if (status == FX_SUCCESS)
2877 {
2878
2879 /* Check if passive transfer enabled. */
2880 if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE)
2881 {
2882
2883 /* Now wait for the data connection to connect. */
2884 status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT);
2885
2886 /* Check for connect error. */
2887 if (status)
2888 {
2889
2890 /* Yes, a connect error is present. Tear everything down. */
2891 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2892 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port);
2893 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2894 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
2895 }
2896 }
2897 else if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
2898 {
2899
2900 /* Socket already created. Error. */
2901 status = NX_NOT_CLOSED;
2902 }
2903 else
2904 {
2905
2906 /* Create an FTP client data socket. */
2907 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
2908 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL);
2909
2910 /* If no error is present, register the receive notify function. */
2911 if (status == NX_SUCCESS)
2912 {
2913
2914 /* Make sure each socket points to the corresponding FTP server. */
2915 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
2916
2917 /* Bind the socket to the FTP server data port. */
2918 status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT);
2919
2920 /* Determine if the socket was bound. */
2921 if (status)
2922 {
2923
2924 /* FTP server data port is busy, use any data port. */
2925 nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT);
2926 }
2927 /* Now attempt to connect the data port to the client's data port. */
2928 status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2929 &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
2930 client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT);
2931
2932
2933 /* Check for connect error. */
2934 if (status)
2935 {
2936
2937 /* Yes, a connect error is present. Tear everything down. */
2938 nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2939 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
2940 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
2941 }
2942 else
2943 {
2944
2945 /* Setup the data port with a specific packet transmit retry logic. */
2946 nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket),
2947 NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH,
2948 NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE,
2949 NX_FTP_SERVER_RETRY_MAX,
2950 NX_FTP_SERVER_RETRY_SHIFT);
2951 }
2952 }
2953 }
2954 }
2955
2956 /* Now check and see if the directory listing command has any errors. */
2957 if (status == NX_SUCCESS)
2958 {
2959
2960 /* The directory listing is successful! */
2961
2962 /* Now send a successful response to the client. */
2963 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
2964 NX_FTP_CODE_START_XFER, "Sending List");
2965
2966 /* Determine if the block mode is enabled. */
2967 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
2968 {
2969
2970 /* Get the directory listing size. */
2971 _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size);
2972
2973 /* Send start block header for file size. */
2974 if (block_size)
2975 _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size);
2976 }
2977
2978 /* Allocate a new packet. */
2979 status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
2980
2981 /* Calculate the remaining length. */
2982 remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER);
2983
2984 /* Determine if the advertised MSS is even less. */
2985 if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss)
2986 {
2987
2988 /* Reduce the remaining length to the MSS value. */
2989 remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss;
2990 }
2991
2992 /* Now generate the full directory listing and send the contents to the client. */
2993 j = 0;
2994 while (status == NX_SUCCESS)
2995 {
2996
2997 /* Pickup the next directory entry. */
2998 if (j == 0)
2999 {
3000
3001
3002 /* First directory entry. */
3003 status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
3004 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
3005
3006 }
3007 else
3008 {
3009
3010 /* Not the first entry - pickup the next! */
3011 status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
3012 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
3013
3014 }
3015
3016 /* Increment the entry count. */
3017 j++;
3018
3019 /* Determine if successful. */
3020 if (status == NX_SUCCESS)
3021 {
3022
3023 /* Setup pointer to buffer. */
3024 buffer_ptr = packet_ptr -> nx_packet_append_ptr;
3025
3026 /* Calculate the size of the name. */
3027 length = 0;
3028 do
3029 {
3030 if (filename[length])
3031 length++;
3032 else
3033 break;
3034 } while (length < FX_MAX_LONG_NAME_LEN);
3035
3036 /* Make sure there is enough space for the file name. */
3037 if ((length + 2) > remaining_length)
3038 {
3039
3040 /* Send the current buffer out. */
3041
3042 /* Send the directory data to the client. */
3043 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3044 packet_ptr, NX_FTP_SERVER_TIMEOUT);
3045
3046 /* Determine if the send was unsuccessful. */
3047 if (status)
3048 {
3049
3050 /* Release the packet. */
3051 nx_packet_release(packet_ptr);
3052 }
3053
3054 /* Allocate a new packet. */
3055 status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
3056
3057 /* Determine if the packet allocate was successful. */
3058 if (status)
3059 {
3060
3061 /* Get out of the loop! */
3062 break;
3063 }
3064
3065 /* Calculate the remaining length. */
3066 remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER);
3067
3068 /* Determine if the advertised MSS is even less. */
3069 if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss)
3070 {
3071
3072 /* Reduce the remaining length to the MSS value. */
3073 remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss;
3074 }
3075
3076 /* Setup pointer to buffer. */
3077 buffer_ptr = packet_ptr -> nx_packet_append_ptr;
3078 }
3079
3080 /* Put the file name and cr/lf in the buffer*/
3081 memcpy(buffer_ptr, filename, length); /* Use case of memcpy is verified. */
3082 buffer_ptr[length++] = '\r';
3083 buffer_ptr[length++] = '\n';
3084
3085 /* Set the packet length. */
3086 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length;
3087
3088 /* Setup the packet append pointer. */
3089 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length;
3090
3091 /* Adjust the remaining length. */
3092 if (remaining_length > length)
3093 {
3094 remaining_length = remaining_length - length;
3095 }
3096 else
3097 {
3098 remaining_length = 0;
3099 }
3100 }
3101 }
3102
3103 /* Now determine if the directory listing was a success. */
3104 if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length))
3105 {
3106
3107 no_more_ftp_entries = NX_TRUE;
3108
3109 /* Send the directory data to the client. */
3110 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3111 packet_ptr, NX_FTP_SERVER_TIMEOUT);
3112
3113 /* Determine if the send was unsuccessful. */
3114 if (status)
3115 {
3116
3117 /* Release the packet. */
3118 nx_packet_release(packet_ptr);
3119 }
3120 }
3121 else if (packet_ptr)
3122 {
3123
3124 /* Release packet just in case! */
3125 nx_packet_release(packet_ptr);
3126 }
3127
3128 /* Determine if the block mode is enabled. */
3129 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
3130 {
3131
3132 /* Send end block header for file size. */
3133 _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0);
3134 }
3135
3136 /* Clean up the data socket. */
3137 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
3138
3139 /* Allocate a new packet. */
3140 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
3141
3142 /* Now determine if the directory listing was a success (e..g runs until no more entries found). */
3143 if (no_more_ftp_entries)
3144 {
3145
3146 /* The directory listing was successful! */
3147
3148 /* Now send a successful response to the client. */
3149 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3150 NX_FTP_CODE_COMPLETED, "List End");
3151 }
3152 else
3153 {
3154
3155 /* Directory listing command failed. */
3156
3157 /* Now send an error response to the client. */
3158 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3159 NX_FTP_CODE_BAD_FILE, "List fail");
3160 }
3161 }
3162 else
3163 {
3164 /* Unsuccessful directory listing command. */
3165
3166 /* Now send an error response to the client. */
3167 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3168 NX_FTP_CODE_BAD_FILE, "List bad Directory");
3169 }
3170 break;
3171 }
3172
3173 case NX_FTP_LIST:
3174 {
3175
3176 /* Assume ASCII and relax restriction. */
3177 if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') &&
3178 (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I'))
3179 {
3180
3181 /* Now send a successful response to the client. */
3182 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3183 NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed");
3184
3185 /* And we are done processing. */
3186 break;
3187 }
3188
3189 /* Check packet length. */
3190 if (packet_ptr -> nx_packet_length == 0)
3191 {
3192
3193 /* Empty message. */
3194
3195 /* Now send an error response to the client. */
3196 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3197 NX_FTP_CODE_BAD_FILE, "Bad Directory");
3198 break;
3199 }
3200
3201 /* Change to the default directory of this connection. */
3202 status = fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
3203
3204 /* Setup pointer to packet buffer area. */
3205 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
3206
3207 /* Find the end of the message. */
3208 j = 0;
3209 k = -1;
3210 while (j < packet_ptr -> nx_packet_length - 1)
3211 {
3212
3213 /* Determine if a slash or backslash is present. */
3214 if ((buffer_ptr[j] == '/') || (buffer_ptr[j] == '\\'))
3215 k = (INT)j;
3216
3217 /* Determine if a CR/LF is present. */
3218 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
3219 break;
3220
3221 /* Move to next character. */
3222 j++;
3223 }
3224
3225 /* If specified path ends with slash or backslash, strip it. */
3226 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
3227 {
3228 j--;
3229 }
3230
3231 /* Default the single file specified flag to false. */
3232 single_file = NX_FALSE;
3233
3234 /* Determine if there is a directory path. */
3235 if (j)
3236 {
3237
3238 /* Ensure the name is NULL terminated. */
3239 buffer_ptr[j] = NX_NULL;
3240
3241 /* Set the path to the supplied directory. */
3242 status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr);
3243
3244 /* Determine if the path setup was unsuccessful. */
3245 if (status)
3246 {
3247
3248 /* Pickup the information for the single file. */
3249 status = fx_directory_information_get(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr,
3250 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
3251
3252 /* Determine if a file is specified as the LIST parameter. */
3253 if ((status == FX_SUCCESS) && ((attributes & FX_DIRECTORY) == 0))
3254 {
3255
3256 /* Yes, a file name was supplied. Set the single file flag for the processing below. */
3257 single_file = NX_TRUE;
3258
3259 /* Advance to first character of the filename. */
3260 k++;
3261
3262 /* Copy the file name from the last slash into the filename buffer. */
3263 j = 0;
3264 while ((buffer_ptr[(UINT)k + j]) && (j < FX_MAX_LONG_NAME_LEN-1))
3265 {
3266
3267 /* Copy a character of the filename. */
3268 filename[j] = (CHAR)(buffer_ptr[(UINT)k + j]);
3269
3270 /* Move to next character. */
3271 j++;
3272 }
3273
3274 /* Null terminate the string. */
3275 filename[j] = NX_NULL;
3276 }
3277 }
3278 }
3279 else
3280 {
3281
3282 /* Just set the buffer pointer to NULL since there isn't a string. */
3283 buffer_ptr = NX_NULL;
3284 }
3285
3286 /* Determine if the path setup was successful. */
3287 if (status == FX_SUCCESS)
3288 {
3289
3290 CHAR *local_dir;
3291
3292
3293 /* Get the actual path */
3294 fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir);
3295
3296 /* Check if passive transfer enabled. */
3297 if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE)
3298 {
3299
3300 /* Now wait for the data connection to connect. */
3301 status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT);
3302
3303 /* Check for connect error. */
3304 if (status)
3305 {
3306
3307 /* Yes, a connect error is present. Tear everything down. */
3308 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3309 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port);
3310 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3311 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
3312 }
3313 }
3314 else if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
3315 {
3316
3317 /* Socket already created. Error. */
3318 status = NX_NOT_CLOSED;
3319 }
3320 else
3321 {
3322
3323 /* Create an FTP client data socket. */
3324 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
3325 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL);
3326
3327 /* If no error is present, register the receive notify function. */
3328 if (status == NX_SUCCESS)
3329 {
3330
3331 /* Make sure each socket points to the corresponding FTP server. */
3332 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
3333
3334 /* Bind the socket to the FTP server data port. */
3335 status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT);
3336
3337 /* Determine if the socket was bound. */
3338 if (status)
3339 {
3340
3341 /* FTP server data port is busy, use any data port. */
3342 nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT);
3343 }
3344
3345 /* Now attempt to connect the data port to the client's data port. */
3346 status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3347 &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
3348 client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT);
3349
3350
3351 /* Check for connect error. */
3352 if (status)
3353 {
3354
3355 /* Yes, a connect error is present. Tear everything down. */
3356 nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3357 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3358 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
3359 }
3360 else
3361 {
3362
3363 /* Setup the data port with a specific packet transmit retry logic. */
3364 nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3365 NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH,
3366 NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE,
3367 NX_FTP_SERVER_RETRY_MAX,
3368 NX_FTP_SERVER_RETRY_SHIFT);
3369 }
3370 }
3371 }
3372 }
3373
3374 /* Now check and see if the directory listing command has any errors. */
3375 if (status == NX_SUCCESS)
3376 {
3377
3378 /* The directory listing is successful! */
3379
3380 /* Now send a successful response to the client. */
3381 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3382 NX_FTP_CODE_START_XFER, "Sending List");
3383
3384 /* Determine if the block mode is enabled. */
3385 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
3386 {
3387
3388 /* Get the directory listing size. */
3389 _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size);
3390
3391 /* Send start block header for file size. */
3392 if (block_size)
3393 _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size);
3394 }
3395
3396 /* Allocate a new packet. */
3397 status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
3398
3399 /* Calculate the remaining length. */
3400 remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER);
3401
3402 /* Determine if the advertised MSS is even less. */
3403 if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss)
3404 {
3405
3406 /* Reduce the remaining length to the MSS value. */
3407 remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss;
3408 }
3409
3410 /* Now generate the full directory listing and send the contents to the client. */
3411 j = 0;
3412 while (status == NX_SUCCESS)
3413 {
3414
3415 /* Determine if a single file was specified. */
3416 if (single_file == NX_FALSE)
3417 {
3418
3419 /* Typical case - not a single file. */
3420
3421 /* Pickup the next directory entry. */
3422 if (j == 0)
3423 {
3424
3425 /* First directory entry. */
3426 status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
3427 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
3428
3429 }
3430 else
3431 {
3432
3433 /* Not the first entry - pickup the next! */
3434 status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
3435 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
3436
3437 }
3438 }
3439 else
3440 {
3441
3442 /* The parameter to the LIST command is a single file. Simply return the information
3443 already gathered above for this one file instead of traversing the entire list. */
3444
3445 /* Is this the first pass through the loop? */
3446 if (j)
3447 {
3448
3449 /* End the loop, since the single file has already been sent. */
3450 status = FX_NO_MORE_ENTRIES;
3451 }
3452 }
3453
3454 /* Increment the entry count. */
3455 j++;
3456
3457 /* Determine if successful. */
3458 if (status == NX_SUCCESS)
3459 {
3460
3461 /* Check if the month is valid before convert it. */
3462 if ((month < 1) || (month > 12))
3463 continue;
3464
3465 /* Setup pointer to buffer. */
3466 buffer_ptr = packet_ptr -> nx_packet_append_ptr;
3467
3468 /* Calculate the size of the name. */
3469 length = 0;
3470 do
3471 {
3472 if (filename[length])
3473 length++;
3474 else
3475 break;
3476 } while (length < FX_MAX_LONG_NAME_LEN);
3477
3478 /* Make sure there is enough space for the data plus the file info.
3479 File Info is 10 chars for permissions, 15 chars for owner and group,
3480 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */
3481 if ((length + 52) > remaining_length)
3482 {
3483
3484 /* Send the current buffer out. */
3485
3486 /* Send the directory data to the client. */
3487 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT);
3488
3489 /* Determine if the send was unsuccessful. */
3490 if (status)
3491 {
3492
3493 /* Release the packet. */
3494 nx_packet_release(packet_ptr);
3495 }
3496
3497 /* Allocate a new packet. */
3498 status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
3499
3500 /* Determine if the packet allocate was successfull. */
3501 if (status)
3502 {
3503
3504 /* Get out of the loop! */
3505 break;
3506 }
3507
3508 /* Calculate the remaining length. */
3509 remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER);
3510
3511 /* Determine if the advertised MSS is even less. */
3512 if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss)
3513 {
3514
3515 /* Reduce the remaining length to the MSS value. */
3516 remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss;
3517 }
3518
3519 /* Setup pointer to buffer. */
3520 buffer_ptr = packet_ptr -> nx_packet_append_ptr;
3521 }
3522
3523 /* Put the file information followed by the file name */
3524 buffer_ptr[0] = ((attributes & FX_DIRECTORY) ? 'd' : '-');
3525 if (attributes & FX_READ_ONLY)
3526 {
3527 memcpy(&buffer_ptr[1], "r--r--r--", 9); /* Use case of memcpy is verified. */
3528 }
3529 else
3530 {
3531 memcpy(&buffer_ptr[1], "rw-rw-rw-", 9); /* Use case of memcpy is verified. */
3532 }
3533 memcpy(&buffer_ptr[10], " 1 owner group ", 16); /* Use case of memcpy is verified. */
3534 _nx_ftp_server_number_to_ascii(&buffer_ptr[26], 10, size, ' ');
3535 buffer_ptr[36] = ' ';
3536 buffer_ptr[37] = (UCHAR)months[month - 1][0];
3537 buffer_ptr[38] = (UCHAR)months[month - 1][1];
3538 buffer_ptr[39] = (UCHAR)months[month - 1][2];
3539 buffer_ptr[40] = ' ';
3540 _nx_ftp_server_number_to_ascii(&buffer_ptr[41], 2, day, '0');
3541 buffer_ptr[43] = ' ';
3542 _nx_ftp_server_number_to_ascii(&buffer_ptr[44], 2, hour, '0');
3543 buffer_ptr[46] = ':';
3544 _nx_ftp_server_number_to_ascii(&buffer_ptr[47], 2, minute, '0');
3545 buffer_ptr[49] = ' ';
3546 memcpy(&buffer_ptr[50], filename, length); /* Use case of memcpy is verified. */
3547 length += 50;
3548 buffer_ptr[length++] = '\r';
3549 buffer_ptr[length++] = '\n';
3550
3551
3552 /* Set the packet length. */
3553 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length;
3554
3555 /* Setup the packet append pointer. */
3556 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length;
3557
3558 /* Adjust the remaining length. */
3559 if (remaining_length > length)
3560 {
3561 remaining_length = remaining_length - length;
3562 }
3563 else
3564 {
3565 remaining_length = 0;
3566 }
3567 }
3568 }
3569
3570 /* Now determine if the directory listing was a success. */
3571 if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length))
3572 {
3573
3574 /* Send the directory data to the client. */
3575 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3576 packet_ptr, NX_FTP_SERVER_TIMEOUT);
3577
3578 /* Determine if the send was unsuccessful. */
3579 if (status)
3580 {
3581
3582 /* Release the packet. */
3583 nx_packet_release(packet_ptr);
3584 }
3585 else
3586 {
3587
3588 /* Reset the status for the response processing below. */
3589 status = FX_NO_MORE_ENTRIES;
3590 }
3591 }
3592 else if (packet_ptr)
3593 {
3594
3595 /* Release packet just in case! */
3596 nx_packet_release(packet_ptr);
3597 }
3598
3599 /* Determine if the block mode is enabled. */
3600 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
3601 {
3602
3603 /* Send end block header for file size. */
3604 _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0);
3605 }
3606
3607 /* Clean up the data socket. */
3608 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
3609
3610 /* Allocate a new packet. */
3611 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
3612
3613 /* Now determine if the directory listing was a success. */
3614 if (status == FX_NO_MORE_ENTRIES)
3615 {
3616
3617 /* The directory listing was successful! */
3618
3619 /* Now send a successful response to the client. */
3620 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3621 NX_FTP_CODE_COMPLETED, "List End");
3622 }
3623 else
3624 {
3625
3626 /* Directory listing command failed. */
3627
3628 /* Now send an error response to the client. */
3629 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3630 NX_FTP_CODE_BAD_FILE, "List fail");
3631 }
3632 }
3633 else
3634 {
3635 /* Unsuccessful directory listing command. */
3636
3637 /* Now send an error response to the client. */
3638 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3639 NX_FTP_CODE_BAD_FILE, "Bad Directory");
3640 }
3641 break;
3642 }
3643
3644 #ifndef NX_DISABLE_IPV4
3645 case NX_FTP_PORT:
3646 {
3647
3648
3649 /* Check that only IPv4 packets can use the PORT command. */
3650 if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
3651 {
3652 /* Illegal PORT command. */
3653
3654 /* Now send an error response to the client. */
3655 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3656 NX_FTP_CODE_NOT_IMPLEMENTED, "PORT illegal in IPv6");
3657
3658 /* Bail out! */
3659 break;
3660 }
3661 /* Setup pointer to packet buffer area. */
3662 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
3663
3664 /* First, pickup the IP address. */
3665 commas = 0;
3666 ip_address = 0;
3667 j = 0;
3668 temp = 0;
3669 status = NX_SUCCESS;
3670 while (j < packet_ptr -> nx_packet_length)
3671 {
3672
3673 /* Is a numeric character present? */
3674 if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9'))
3675 {
3676
3677 /* Yes, numeric character is present. Update the IP address. */
3678 temp = (temp*10) + (ULONG) (buffer_ptr[j] - '0');
3679 }
3680
3681 /* Determine if a CR/LF is present. */
3682 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
3683 {
3684 status = NX_FTP_INVALID_COMMAND;
3685 break;
3686 }
3687
3688 /* Determine if a comma is present. */
3689 if (buffer_ptr[j] == ',')
3690 {
3691
3692 /* Increment the comma count. */
3693 commas++;
3694
3695 /* Setup next byte of IP address. */
3696 ip_address = (ip_address << 8) & 0xFFFFFFFF;
3697 ip_address = ip_address | (temp & 0xFF);
3698 temp = 0;
3699
3700 /* Have we finished with the IP address? */
3701 if (commas == 4)
3702 {
3703
3704 /* Finished with IP address. */
3705 j++;
3706 break;
3707 }
3708
3709 }
3710
3711 /* Move to next character. */
3712 j++;
3713 }
3714
3715 /* Now pickup the port number. */
3716 port = 0;
3717 temp = 0;
3718 while (j < packet_ptr -> nx_packet_length)
3719 {
3720
3721 /* Is a numeric character present? */
3722 if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9'))
3723 {
3724
3725 /* Yes, numeric character is present. Update the IP port. */
3726 temp = (temp*10) + (UINT) (buffer_ptr[j] - '0');
3727 }
3728
3729 /* Determine if a CR/LF is present. */
3730 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
3731 {
3732 /* Good condition on the port number! */
3733 break;
3734 }
3735
3736 /* Determine if a comma is present. */
3737 if (buffer_ptr[j] == ',')
3738 {
3739
3740 /* Increment the comma count. */
3741 commas++;
3742
3743 /* Move port number up. */
3744 port = (port << 8) & 0xFFFFFFFF;
3745 port = port | (temp & 0xFF);
3746 temp = 0;
3747
3748 /* Have we finished with the IP address? */
3749 if (commas >= 6)
3750 {
3751
3752 /* Error, get out of the loop. */
3753 status = NX_FTP_INVALID_ADDRESS;
3754 break;
3755 }
3756 }
3757
3758 /* Move to next character. */
3759 j++;
3760 }
3761
3762 /* Move port number up. */
3763 port = (port << 8) & 0xFFFFFFFF;
3764 port = port | (temp & 0xFF);
3765 temp = 0;
3766
3767 /* Determine if an error occurred. */
3768 if ((buffer_ptr[j] != 13) || (commas != 5) || (ip_address == 0) || (port == 0) ||
3769 (ip_address != connect_ip4_address))
3770 {
3771
3772 /* Set the error status. */
3773 status = NX_FTP_INVALID_COMMAND;
3774 }
3775
3776 /* Save the data port. */
3777 client_req_ptr -> nx_ftp_client_request_data_port = port;
3778
3779 /* Determine if the port command was successful. */
3780 if (status == NX_SUCCESS)
3781 {
3782
3783 /* Yes, the port command is successful! */
3784
3785 /* Now send a successful response to the client. */
3786 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3787 NX_FTP_CODE_CMD_OK, "Port set");
3788 }
3789 else
3790 {
3791
3792 /* Unsuccessful port command. */
3793
3794 /* Now send an error response to the client. */
3795 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3796 NX_FTP_CODE_CMD_FAIL, "Port Fail");
3797 }
3798
3799 break;
3800 }
3801
3802 case NX_FTP_PASV:
3803 {
3804
3805 /* If create, cleanup the data socket. */
3806 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
3807 {
3808
3809 /* Clean up the data socket. */
3810 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
3811 }
3812
3813 /* Try to find the data port. */
3814 status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr,
3815 ftp_server_ptr -> nx_ftp_server_data_port++, &port);
3816
3817 /* Determine if the PASV command was successful. */
3818 if (status != NX_SUCCESS)
3819 {
3820
3821 /* Unsuccessful port find. */
3822
3823 /* Now send an error response to the client. */
3824 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3825 NX_FTP_CODE_CMD_FAIL, "PASV Fail");
3826
3827 /* And we are done processing. */
3828 break;
3829 }
3830
3831 /* Create an FTP client data socket. */
3832 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
3833 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, _nx_ftp_server_data_disconnect);
3834
3835 /* Determine if the listen is successful. */
3836 if (status != NX_SUCCESS)
3837 {
3838
3839 /* Unsuccessful data socket create. */
3840
3841 /* Now send an error response to the client. */
3842 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3843 NX_FTP_CODE_CMD_FAIL, "PASV Fail");
3844
3845 /* And we are done processing. */
3846 break;
3847 }
3848
3849 /* Register the receive function. */
3850 nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket), _nx_ftp_server_data_present);
3851
3852 /* Setup the data port with a specific packet transmit retry logic. */
3853 nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket),
3854 NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH,
3855 NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE,
3856 NX_FTP_SERVER_RETRY_MAX,
3857 NX_FTP_SERVER_RETRY_SHIFT);
3858
3859 /* Make sure each socket points to the corresponding FTP server. */
3860 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
3861
3862 /* Start listening on the data port. */
3863 status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0);
3864
3865 /* Determine if the listen is successful. */
3866 if (status != NX_SUCCESS)
3867 {
3868
3869 /* Unsuccessful data socket listen. */
3870
3871 /* Now send an error response to the client. */
3872 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3873 NX_FTP_CODE_CMD_FAIL, "PASV Fail");
3874
3875 /* Delete data socket. */
3876 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3877
3878 /* And we are done processing. */
3879 break;
3880 }
3881
3882 /* Wait for the data connection to connect. */
3883 nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT);
3884
3885 /* Pickup the IPv4 address of this IP instance. */
3886 ip_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address;
3887
3888 /* Reset the packet prepend pointer for alignment. */
3889 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
3890
3891 /* Setup pointer to packet buffer area. */
3892 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
3893
3894 /* Now build PASV response. "227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)." */
3895
3896 /* Verify packet payload. The max size of this message is 54. */
3897 if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 54)
3898 {
3899
3900 /* Delete data socket. */
3901 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port);
3902 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3903
3904 /* Release the packet. */
3905 nx_packet_release(packet_ptr);
3906 break;
3907 }
3908
3909 /* Build the string. "227 Entering Passive Mode " */
3910 memcpy(buffer_ptr, "227 Entering Passive Mode ", 26); /* Use case of memcpy is verified. */
3911
3912 /* Build the IP address and port. */
3913 j = 26;
3914 buffer_ptr[j++] = '(';
3915 j += _nx_utility_uint_to_string((ip_address >> 24), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3916 buffer_ptr[j++] = ',';
3917 j += _nx_utility_uint_to_string(((ip_address >> 16) & 0xFF), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3918 buffer_ptr[j++] = ',';
3919 j += _nx_utility_uint_to_string(((ip_address >> 8) & 0xFF), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3920 buffer_ptr[j++] = ',';
3921 j += _nx_utility_uint_to_string((ip_address & 0xFF), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3922 buffer_ptr[j++] = ',';
3923 j += _nx_utility_uint_to_string((port >> 8), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3924 buffer_ptr[j++] = ',';
3925 j += _nx_utility_uint_to_string((port & 0XFF), 10, (CHAR *)(buffer_ptr + j), 54 - j);
3926 buffer_ptr[j++] = ')';
3927 buffer_ptr[j++] = '.';
3928
3929 /* Set the CR/LF. */
3930 buffer_ptr[j++] = 13;
3931 buffer_ptr[j++] = 10;
3932
3933 /* Set the packet length. */
3934 packet_ptr -> nx_packet_length = j;
3935
3936 /* Setup the packet append pointer. */
3937 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
3938
3939 /* Send the PASV response message. */
3940 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT);
3941
3942 /* Determine if the send was unsuccessful. */
3943 if (status != NX_SUCCESS)
3944 {
3945
3946 /* Delete data socket. */
3947 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port);
3948 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
3949
3950 /* Release the packet. */
3951 nx_packet_release(packet_ptr);
3952 }
3953
3954 /* Yes, passive transfer enabled. */
3955 client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE;
3956
3957 break;
3958 }
3959 #endif /* NX_DISABLE_IPV4 */
3960
3961 #ifdef FEATURE_NX_IPV6
3962 case NX_FTP_EPRT:
3963 {
3964
3965
3966 /* Check that only IPv6 packets can use the EPRT command. */
3967 if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4)
3968 {
3969 /* Illegal EPRT command. */
3970
3971 /* Now send an error response to the client. */
3972 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3973 NX_FTP_CODE_NOT_IMPLEMENTED, "EPRT illegal in IPv4");
3974
3975 /* Bail out! */
3976 break;
3977 }
3978
3979 /* Setup pointer to packet buffer area. */
3980 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
3981
3982 /* First, pickup the IPv6 address. */
3983 status = _nx_ftp_utility_parse_IPv6_address((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &ipduo_address);
3984
3985 if (status != NX_SUCCESS)
3986 {
3987 /* Now send an error response to the client. */
3988 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
3989 NX_FTP_CODE_CMD_FAIL, "Bad IPv6 address");
3990
3991 return;
3992 }
3993
3994 /* Now pickup the port number. */
3995 status = _nx_ftp_utility_parse_port_number((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &port);
3996
3997 /* Save the data port. */
3998 client_req_ptr -> nx_ftp_client_request_data_port = port;
3999
4000 /* Determine if the EPRT command was successful. */
4001 if (status == NX_SUCCESS)
4002 {
4003
4004 /* Yes, the EPRT command is successful! */
4005
4006 /* Now send a successful response to the client. */
4007 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4008 NX_FTP_CODE_CMD_OK, "EPRT command set");
4009 }
4010 else
4011 {
4012
4013 /* Unsuccessful EPRT command. */
4014
4015 /* Now send an error response to the client. */
4016 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4017 NX_FTP_CODE_CMD_FAIL, "EPRT command failed");
4018 }
4019
4020 break;
4021
4022 }
4023
4024 case NX_FTP_EPSV:
4025 {
4026
4027 /* If create, cleanup the data socket. */
4028 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
4029 {
4030
4031 /* Clean up the client socket. */
4032 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
4033 }
4034
4035 /* Try to find the data port. */
4036 status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr,
4037 ftp_server_ptr -> nx_ftp_server_data_port++, &port);
4038
4039 /* Determine if the EPSV command was successful. */
4040 if (status != NX_SUCCESS)
4041 {
4042
4043 /* Unsuccessful port find. */
4044
4045 /* Now send an error response to the client. */
4046 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4047 NX_FTP_CODE_CMD_FAIL, "EPSV Fail");
4048
4049 /* And we are done processing. */
4050 break;
4051 }
4052
4053 /* Create an FTP client data socket. */
4054 status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket",
4055 NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, _nx_ftp_server_data_disconnect);
4056
4057 /* Determine if the listen is successful. */
4058 if (status != NX_SUCCESS)
4059 {
4060
4061 /* Unsuccessful data socket create. */
4062
4063 /* Now send an error response to the client. */
4064 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4065 NX_FTP_CODE_CMD_FAIL, "EPSV Fail");
4066
4067 /* And we are done processing. */
4068 break;
4069 }
4070
4071 /* Make sure each socket points to the corresponding FTP server. */
4072 client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr;
4073
4074 /* Start listening on the data port. */
4075 status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0);
4076
4077 /* Determine if the listen is successful. */
4078 if (status != NX_SUCCESS)
4079 {
4080
4081 /* Unsuccessful data socket listen. */
4082
4083 /* Now send an error response to the client. */
4084 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4085 NX_FTP_CODE_CMD_FAIL, "EPSV Fail");
4086
4087 /* Delete data socket. */
4088 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
4089
4090 /* And we are done processing. */
4091 break;
4092 }
4093
4094 /* Wait for the data connection to connect. */
4095 nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT);
4096
4097 /* Reset the packet prepend pointer for alignment. */
4098 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
4099
4100 /* Setup pointer to packet buffer area. */
4101 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
4102
4103 /* Now build EPSV response. "229 Entering Extended Passive Mode (|||6446|)." */
4104
4105 /* Get port size. */
4106 port_size = _nx_ftp_server_utility_fill_port_number(temp_buffer, port);
4107
4108 /* Verify packet payload. */
4109 if ((ULONG)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (43 + port_size))
4110 {
4111
4112 /* Delete data socket. */
4113 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port);
4114 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
4115
4116 /* Release the packet. */
4117 nx_packet_release(packet_ptr);
4118 break;
4119 }
4120
4121 /* Build the string. "229 Entering Extended Passive Mode " */
4122 memcpy(buffer_ptr, "229 Entering Extended Passive Mode ", 35); /* Use case of memcpy is verified. */
4123
4124 /* Build the IPv6 address and port. */
4125 buffer_ptr[35] = '(';
4126 buffer_ptr[36] = '|';
4127 buffer_ptr[37] = '|';
4128 buffer_ptr[38] = '|';
4129
4130 memcpy(&buffer_ptr[39], temp_buffer, port_size); /* Use case of memcpy is verified. */
4131
4132 buffer_ptr[39 + port_size] = '|';
4133 buffer_ptr[40 + port_size] = ')';
4134
4135 /* Set the CR/LF. */
4136 buffer_ptr[41 + port_size] = 13;
4137 buffer_ptr[42 + port_size] = 10;
4138
4139 /* Set the packet length. */
4140 packet_ptr -> nx_packet_length = 43 + port_size;
4141
4142 /* Setup the packet append pointer. */
4143 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
4144
4145 /* Send the EPSV response message. */
4146 status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT);
4147
4148 /* Determine if the send was unsuccessful. */
4149 if (status != NX_SUCCESS)
4150 {
4151
4152 /* Delete data socket. */
4153 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port);
4154 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
4155
4156 /* Release the packet. */
4157 nx_packet_release(packet_ptr);
4158 }
4159
4160 /* Yes, passive transfer enabled. */
4161 client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE;
4162
4163 break;
4164 }
4165 #endif /* FEATURE_NX_IPV6 */
4166
4167 case NX_FTP_CDUP:
4168 case NX_FTP_CWD:
4169 {
4170
4171 /* Change to the default directory of this connection. */
4172 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr,
4173 &(client_req_ptr -> nx_ftp_client_local_path));
4174
4175 /* Setup pointer to packet buffer area. */
4176 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
4177
4178 /* If CDUP command, create the "up one directory" pathname string. */
4179 if (ftp_command == NX_FTP_CDUP)
4180 {
4181
4182 /* Move the pointer to make sure there is enough memory to store the data. */
4183 buffer_ptr -= 3;
4184 buffer_ptr[0] = '.';
4185 buffer_ptr[1] = '.';
4186 buffer_ptr[2] = NX_NULL;
4187 }
4188
4189 /* Otherwise CWD command, parse the pathname string. */
4190 else
4191 {
4192
4193 /* Check packet length. */
4194 if (packet_ptr -> nx_packet_length == 0)
4195 {
4196
4197 /* Empty message. */
4198
4199 /* Now send an error response to the client. */
4200 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4201 NX_FTP_CODE_BAD_FILE, "Change Dir Fail");
4202 break;
4203 }
4204
4205 /* Find the end of the message. */
4206 j = 0;
4207 while (j < packet_ptr -> nx_packet_length - 1)
4208 {
4209
4210 /* Determine if a CR/LF is present. */
4211 if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
4212 break;
4213
4214 /* Move to next character. */
4215 j++;
4216 }
4217
4218 /* If specified path ends with slash or backslash, strip it. */
4219 if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\')))
4220 {
4221 j--;
4222 }
4223
4224 /* Ensure the name is NULL terminated. */
4225 buffer_ptr[j] = NX_NULL;
4226 }
4227
4228 /* Set the local path to the path specified. */
4229 status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr,
4230 &(client_req_ptr -> nx_ftp_client_local_path), (CHAR *) buffer_ptr);
4231
4232 /* Determine if it was successful. */
4233 if (status == NX_SUCCESS)
4234 {
4235
4236 CHAR *local_dir;
4237
4238
4239 /* Successful change directory. */
4240
4241 /* Get the actual path */
4242 fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir);
4243
4244 /* Now send a successful response to the client. */
4245 _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4246 NX_FTP_CODE_COMPLETED, "set successfully", local_dir);
4247 }
4248 else
4249 {
4250
4251 /* Unsuccessful directory change. */
4252
4253 /* Now send an error response to the client. */
4254 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4255 NX_FTP_CODE_BAD_FILE, "Change Dir Fail");
4256 }
4257 break;
4258 }
4259
4260 case NX_FTP_PWD:
4261 {
4262
4263 /* Change to the default directory of this connection. */
4264 fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path));
4265
4266 {
4267
4268 CHAR *local_dir;
4269
4270 /* Pickup the current directory. */
4271 fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir);
4272
4273 /* Now send a successful response to the client. */
4274 _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4275 NX_FTP_CODE_MADE_DIR, "is current Directory", local_dir);
4276 }
4277
4278 break;
4279 }
4280
4281 case NX_FTP_TYPE:
4282 {
4283
4284 /* Setup pointer to packet buffer area. */
4285 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
4286
4287 /* Determine if a binary transfer is specified. */
4288 if (buffer_ptr[0] == 'I')
4289 {
4290
4291 /* Yes, a binary image is specified and supported. */
4292 client_req_ptr -> nx_ftp_client_request_transfer_type = 'I';
4293
4294 /* Now send a successful response to the client. */
4295 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4296 NX_FTP_CODE_CMD_OK, "Type Binary");
4297 }
4298
4299 /* Not Binary - check if ASCII type is specified */
4300 else if (buffer_ptr[0] == 'A')
4301 {
4302
4303 /* Yes, a ASCII image is specified and supported. */
4304 client_req_ptr -> nx_ftp_client_request_transfer_type = 'A';
4305
4306 /* Now send a successful response to the client. */
4307 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4308 NX_FTP_CODE_CMD_OK, "Type ASCII");
4309 }
4310 else
4311 {
4312
4313 /* Otherwise, a non-binary type is requested. */
4314
4315 /* Now send an error response to the client. */
4316 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4317 NX_FTP_CODE_BAD_TYPE, "Type Non ASCII or Binary");
4318 }
4319 break;
4320 }
4321
4322 case NX_FTP_MODE:
4323 {
4324
4325 /* Setup pointer to packet buffer area. */
4326 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
4327
4328 /* Determine if stream mode is specified. */
4329 if (buffer_ptr[0] == 'S')
4330 {
4331
4332 /* Yes, stream mode is specified and supported. */
4333 client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
4334
4335 /* Now send a successful response to the client. */
4336 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4337 NX_FTP_CODE_CMD_OK, "Mode Stream");
4338 }
4339
4340 /* Not stream - check if block mode is specified */
4341 else if (buffer_ptr[0] == 'B')
4342 {
4343
4344 /* Yes, stream mode is specified and supported. */
4345 client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_BLOCK;
4346
4347 /* Now send a successful response to the client. */
4348 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4349 NX_FTP_CODE_CMD_OK, "Mode Block");
4350 }
4351 else
4352 {
4353
4354 /* Now send an error response to the client. */
4355 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4356 NX_FTP_CODE_BAD_TYPE, "Mode Non Stream or Block");
4357 }
4358 break;
4359 }
4360
4361 case NX_FTP_NOOP:
4362
4363 /* Now send a successful response to the client. */
4364 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4365 NX_FTP_CODE_CMD_OK, "NOOP Success");
4366 break;
4367
4368 default:
4369
4370 /* Unimplemented Command. */
4371
4372 /* Increment the number of unknown commands. */
4373 ftp_server_ptr -> nx_ftp_server_unknown_commands++;
4374
4375 /* Now send an error response to the client. */
4376 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4377 NX_FTP_CODE_NOT_IMPLEMENTED, "Not Implemented");
4378 break;
4379 }
4380 }
4381 }
4382 }
4383 }
4384
4385
4386 /**************************************************************************/
4387 /* */
4388 /* FUNCTION RELEASE */
4389 /* */
4390 /* _nx_ftp_server_connect_process PORTABLE C */
4391 /* 6.1 */
4392 /* AUTHOR */
4393 /* */
4394 /* Yuxin Zhou, Microsoft Corporation */
4395 /* */
4396 /* DESCRIPTION */
4397 /* */
4398 /* This function handles all FTP client connections received. */
4399 /* */
4400 /* */
4401 /* INPUT */
4402 /* */
4403 /* ftp_server_ptr Pointer to FTP server */
4404 /* */
4405 /* OUTPUT */
4406 /* */
4407 /* None */
4408 /* */
4409 /* CALLS */
4410 /* */
4411 /* _nx_ftp_server_response Build and send response */
4412 /* fx_directory_local_path_set Set local path */
4413 /* nx_tcp_server_socket_accept Accept connection on socket */
4414 /* nx_tcp_server_socket_relisten Relisten for connection */
4415 /* nx_tcp_server_socket_unaccept Unaccept connection */
4416 /* nx_ftp_packet_allocate Allocate a packet */
4417 /* */
4418 /* CALLED BY */
4419 /* */
4420 /* _nx_ftp_server_thread_entry FTP server thread */
4421 /* */
4422 /* RELEASE HISTORY */
4423 /* */
4424 /* DATE NAME DESCRIPTION */
4425 /* */
4426 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4427 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4428 /* resulting in version 6.1 */
4429 /* */
4430 /**************************************************************************/
_nx_ftp_server_connect_process(NX_FTP_SERVER * ftp_server_ptr)4431 VOID _nx_ftp_server_connect_process(NX_FTP_SERVER *ftp_server_ptr)
4432 {
4433
4434 UINT i;
4435 UINT status;
4436 NX_PACKET *packet_ptr;
4437 NX_FTP_CLIENT_REQUEST *client_req_ptr;
4438
4439
4440 /* One of the control ports is in the process of connection. */
4441
4442 /* Search the connections to see which one. */
4443 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
4444 {
4445
4446 /* Setup pointer to client request structure. */
4447 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
4448
4449 /* Now see if this socket was the one that is in being connected. */
4450 if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_CLOSED) &&
4451 (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_ESTABLISHED) &&
4452 (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port))
4453 {
4454
4455 /* Yes, we have found the socket being connected. */
4456
4457 /* Increment the number of connection requests. */
4458 ftp_server_ptr -> nx_ftp_server_connection_requests++;
4459
4460 /* Attempt to accept on this socket. */
4461 status = nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT);
4462
4463 /* Determine if it is successful. */
4464 if (status)
4465 {
4466
4467 /* Not successful, simply unaccept on this socket. */
4468 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket));
4469 }
4470 else
4471 {
4472
4473 /* Set the request type. */
4474 if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
4475 {
4476
4477 client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V6;
4478 }
4479 else
4480 {
4481 client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V4;
4482 }
4483
4484 /* Reset the client request activity timeout. */
4485 client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT;
4486
4487 /* Send a connection ACK back to the client, indicating a successful connection
4488 has been established. */
4489
4490 /* Allocate a packet for sending the connection ACK. */
4491 status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT);
4492
4493 /* Determine if the packet allocation was successful. */
4494 if (status == NX_SUCCESS)
4495 {
4496
4497 /* Now send "220" ACK message to indicate connection is ready. */
4498 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4499 NX_FTP_CODE_CONNECTION_OK, "Connection Ready");
4500
4501 /* Set the local path to the root directory. */
4502 fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path), "\\");
4503 }
4504 else
4505 {
4506
4507 /* Increment allocation error count. */
4508 ftp_server_ptr -> nx_ftp_server_allocation_errors++;
4509 }
4510 }
4511 }
4512 }
4513
4514 /* Now look for a socket that is closed to relisten on. */
4515 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
4516 {
4517
4518 /* Setup pointer to client request structure. */
4519 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
4520
4521 /* Now see if this socket is closed. */
4522 if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state == NX_TCP_CLOSED)
4523 {
4524
4525 /* Relisten on this socket. */
4526 status = nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT,
4527 &(client_req_ptr -> nx_ftp_client_request_control_socket));
4528 /* Check for bad status. */
4529 if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING))
4530 {
4531
4532 /* Increment the error count and keep trying. */
4533 ftp_server_ptr -> nx_ftp_server_relisten_errors++;
4534 continue;
4535 }
4536
4537 /* Break out of loop. */
4538 break;
4539 }
4540 }
4541 }
4542
4543
4544 /**************************************************************************/
4545 /* */
4546 /* FUNCTION RELEASE */
4547 /* */
4548 /* _nx_ftp_server_command_present PORTABLE C */
4549 /* 6.1 */
4550 /* AUTHOR */
4551 /* */
4552 /* Yuxin Zhou, Microsoft Corporation */
4553 /* */
4554 /* DESCRIPTION */
4555 /* */
4556 /* This function handles all FTP client commands received on */
4557 /* the control socket. */
4558 /* */
4559 /* */
4560 /* INPUT */
4561 /* */
4562 /* control_socket_ptr Socket event occurred */
4563 /* */
4564 /* OUTPUT */
4565 /* */
4566 /* None */
4567 /* */
4568 /* CALLS */
4569 /* */
4570 /* tx_event_flags_set Set events for server thread */
4571 /* */
4572 /* CALLED BY */
4573 /* */
4574 /* NetX NetX receive packet callback */
4575 /* */
4576 /* RELEASE HISTORY */
4577 /* */
4578 /* DATE NAME DESCRIPTION */
4579 /* */
4580 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4581 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4582 /* resulting in version 6.1 */
4583 /* */
4584 /**************************************************************************/
_nx_ftp_server_command_present(NX_TCP_SOCKET * control_socket_ptr)4585 VOID _nx_ftp_server_command_present(NX_TCP_SOCKET *control_socket_ptr)
4586 {
4587
4588 NX_FTP_SERVER *server_ptr;
4589
4590
4591 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
4592 server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr;
4593
4594 /* Set the command event flag. */
4595 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_COMMAND, TX_OR);
4596 }
4597
4598
4599 /**************************************************************************/
4600 /* */
4601 /* FUNCTION RELEASE */
4602 /* */
4603 /* _nx_ftp_server_connection_present PORTABLE C */
4604 /* 6.1 */
4605 /* AUTHOR */
4606 /* */
4607 /* Yuxin Zhou, Microsoft Corporation */
4608 /* */
4609 /* DESCRIPTION */
4610 /* */
4611 /* This function handles all FTP client connections received on */
4612 /* the control socket. */
4613 /* */
4614 /* */
4615 /* INPUT */
4616 /* */
4617 /* control_socket_ptr Socket event occurred */
4618 /* port Port the connection occurred */
4619 /* */
4620 /* OUTPUT */
4621 /* */
4622 /* None */
4623 /* */
4624 /* CALLS */
4625 /* */
4626 /* tx_event_flags_set Set events for server thread */
4627 /* */
4628 /* CALLED BY */
4629 /* */
4630 /* NetX NetX connect callback */
4631 /* */
4632 /* RELEASE HISTORY */
4633 /* */
4634 /* DATE NAME DESCRIPTION */
4635 /* */
4636 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4637 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4638 /* resulting in version 6.1 */
4639 /* */
4640 /**************************************************************************/
_nx_ftp_server_connection_present(NX_TCP_SOCKET * control_socket_ptr,UINT port)4641 VOID _nx_ftp_server_connection_present(NX_TCP_SOCKET *control_socket_ptr, UINT port)
4642 {
4643
4644 NX_FTP_SERVER *server_ptr;
4645
4646
4647 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
4648 server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr;
4649
4650 /* Set the connect event flag. */
4651 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONNECT, TX_OR);
4652
4653 NX_PARAMETER_NOT_USED(port);
4654 }
4655
4656
4657 /**************************************************************************/
4658 /* */
4659 /* FUNCTION RELEASE */
4660 /* */
4661 /* _nx_ftp_server_data_disconnect PORTABLE C */
4662 /* 6.1 */
4663 /* AUTHOR */
4664 /* */
4665 /* Yuxin Zhou, Microsoft Corporation */
4666 /* */
4667 /* DESCRIPTION */
4668 /* */
4669 /* This function handles all FTP client disconnections received on */
4670 /* the data socket. */
4671 /* */
4672 /* */
4673 /* INPUT */
4674 /* */
4675 /* data_socket_ptr Socket event occurred */
4676 /* */
4677 /* OUTPUT */
4678 /* */
4679 /* None */
4680 /* */
4681 /* CALLS */
4682 /* */
4683 /* tx_event_flags_set Set events for server thread */
4684 /* */
4685 /* CALLED BY */
4686 /* */
4687 /* NetX NetX connect callback */
4688 /* */
4689 /* RELEASE HISTORY */
4690 /* */
4691 /* DATE NAME DESCRIPTION */
4692 /* */
4693 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4694 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4695 /* resulting in version 6.1 */
4696 /* */
4697 /**************************************************************************/
_nx_ftp_server_data_disconnect(NX_TCP_SOCKET * data_socket_ptr)4698 VOID _nx_ftp_server_data_disconnect(NX_TCP_SOCKET *data_socket_ptr)
4699 {
4700
4701 NX_FTP_SERVER *server_ptr;
4702
4703
4704 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
4705 server_ptr = (NX_FTP_SERVER *) data_socket_ptr -> nx_tcp_socket_reserved_ptr;
4706
4707 /* Set the disconnect event flag. */
4708 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA_DISCONNECT, TX_OR);
4709 }
4710
4711
4712 /**************************************************************************/
4713 /* */
4714 /* FUNCTION RELEASE */
4715 /* */
4716 /* _nx_ftp_server_data_disconnect_process PORTABLE C */
4717 /* 6.1.9 */
4718 /* AUTHOR */
4719 /* */
4720 /* Yuxin Zhou, Microsoft Corporation */
4721 /* */
4722 /* DESCRIPTION */
4723 /* */
4724 /* This function processes all FTP client disconnections received on */
4725 /* the data socket. */
4726 /* */
4727 /* */
4728 /* INPUT */
4729 /* */
4730 /* ftp_server_ptr Pointer to FTP server */
4731 /* */
4732 /* OUTPUT */
4733 /* */
4734 /* None */
4735 /* */
4736 /* CALLS */
4737 /* */
4738 /* fx_file_close Close file */
4739 /* nx_ftp_packet_allocate Allocate a packet */
4740 /* _nx_ftp_server_data_socket_cleanup Clean up data socket */
4741 /* */
4742 /* CALLED BY */
4743 /* */
4744 /* _nx_ftp_server_thread_entry FTP server thread */
4745 /* */
4746 /* RELEASE HISTORY */
4747 /* */
4748 /* DATE NAME DESCRIPTION */
4749 /* */
4750 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4751 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4752 /* resulting in version 6.1 */
4753 /* 10-15-2021 Yuxin Zhou Modified comment(s), fixed */
4754 /* the issue of processing */
4755 /* disconnection event, */
4756 /* resulting in version 6.1.9 */
4757 /* */
4758 /**************************************************************************/
_nx_ftp_server_data_disconnect_process(NX_FTP_SERVER * ftp_server_ptr)4759 VOID _nx_ftp_server_data_disconnect_process(NX_FTP_SERVER *ftp_server_ptr)
4760 {
4761
4762 UINT i;
4763 UINT block_status;
4764 ULONG length;
4765 NX_PACKET *packet_ptr;
4766 NX_FTP_CLIENT_REQUEST *client_req_ptr;
4767
4768
4769 /* Now look for a socket that has receive data. */
4770 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
4771 {
4772
4773 /* Setup pointer to client request structure. */
4774 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
4775
4776 /* Initialize block status as NX_TRUE. */
4777 block_status = NX_TRUE;
4778
4779 /* Now see if this socket has entered a disconnect state. */
4780 while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED)
4781 {
4782
4783 /* Yes, a disconnect is present, which signals an end of file of a client FTP write request. */
4784
4785 /* Cleanup this data socket. */
4786 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
4787
4788 /* Determine if the block mode is enabled. */
4789 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
4790 {
4791
4792 /* Check if receive all block bytes. */
4793 if (client_req_ptr -> nx_ftp_client_request_total_bytes != client_req_ptr -> nx_ftp_client_request_block_bytes)
4794 block_status = NX_FALSE;
4795
4796 /* Reset the transfer mode as stream mode. */
4797 client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
4798
4799 /* Reset the block bytes. */
4800 client_req_ptr -> nx_ftp_client_request_block_bytes = 0;
4801 }
4802
4803 /* Reset the client request activity timeout. */
4804 client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT;
4805
4806 /* Check if file is open. */
4807 if (client_req_ptr -> nx_ftp_client_request_open_type == NX_FTP_OPEN_FOR_WRITE)
4808 {
4809
4810 /* Pickup the file length. */
4811 length = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size;
4812
4813 /* Allocate a packet for sending the file write response. */
4814 _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER);
4815
4816 /* Now determine if the operation was successful. */
4817 if ((length == client_req_ptr -> nx_ftp_client_request_total_bytes) && (block_status == NX_TRUE))
4818 {
4819
4820 /* Successful client file write. */
4821
4822 /* Now send "250" message to indicate successful file write. */
4823 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4824 NX_FTP_CODE_COMPLETED, "File Written");
4825 }
4826 else
4827 {
4828
4829 /* Unsuccessful client file write. */
4830
4831 /* Now send "550" message to indicate unsuccessful file write. */
4832 _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr,
4833 NX_FTP_CODE_BAD_FILE, "File Write Failed");
4834 }
4835
4836 /* Clear the open type. */
4837 client_req_ptr -> nx_ftp_client_request_open_type = 0;
4838 }
4839 }
4840 }
4841 }
4842
4843 /**************************************************************************/
4844 /* */
4845 /* FUNCTION RELEASE */
4846 /* */
4847 /* _nx_ftp_server_data_present PORTABLE C */
4848 /* 6.1 */
4849 /* AUTHOR */
4850 /* */
4851 /* Yuxin Zhou, Microsoft Corporation */
4852 /* */
4853 /* DESCRIPTION */
4854 /* */
4855 /* This function notifies the FTP server thread of data received */
4856 /* from a client on a data socket. */
4857 /* */
4858 /* */
4859 /* INPUT */
4860 /* */
4861 /* data_socket_ptr Socket event occurred */
4862 /* */
4863 /* OUTPUT */
4864 /* */
4865 /* None */
4866 /* */
4867 /* CALLS */
4868 /* */
4869 /* tx_event_flags_set Set events for server thread */
4870 /* */
4871 /* CALLED BY */
4872 /* */
4873 /* NetX NetX connect callback */
4874 /* */
4875 /* RELEASE HISTORY */
4876 /* */
4877 /* DATE NAME DESCRIPTION */
4878 /* */
4879 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4880 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4881 /* resulting in version 6.1 */
4882 /* */
4883 /**************************************************************************/
_nx_ftp_server_data_present(NX_TCP_SOCKET * data_socket_ptr)4884 VOID _nx_ftp_server_data_present(NX_TCP_SOCKET *data_socket_ptr)
4885 {
4886
4887 NX_FTP_SERVER *server_ptr;
4888
4889
4890 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
4891 server_ptr = (NX_FTP_SERVER *)data_socket_ptr -> nx_tcp_socket_reserved_ptr;
4892
4893 /* Set the data event flag. */
4894 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA, TX_OR);
4895 }
4896
4897
4898 /**************************************************************************/
4899 /* */
4900 /* FUNCTION RELEASE */
4901 /* */
4902 /* _nx_ftp_server_data_process PORTABLE C */
4903 /* 6.1 */
4904 /* AUTHOR */
4905 /* */
4906 /* Yuxin Zhou, Microsoft Corporation */
4907 /* */
4908 /* DESCRIPTION */
4909 /* */
4910 /* This function processes all FTP client data packets received on */
4911 /* the data socket. */
4912 /* */
4913 /* */
4914 /* INPUT */
4915 /* */
4916 /* ftp_server_ptr Pointer to FTP server */
4917 /* */
4918 /* OUTPUT */
4919 /* */
4920 /* None */
4921 /* */
4922 /* CALLS */
4923 /* */
4924 /* fx_file_write Write client data to file */
4925 /* nx_packet_release Release packet */
4926 /* nx_tcp_socket_receive Receive from data socket */
4927 /* _nx_ftp_server_block_header_retrieve Retrieve the block header */
4928 /* */
4929 /* CALLED BY */
4930 /* */
4931 /* _nx_ftp_server_thread_entry FTP server thread */
4932 /* */
4933 /* RELEASE HISTORY */
4934 /* */
4935 /* DATE NAME DESCRIPTION */
4936 /* */
4937 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4938 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4939 /* resulting in version 6.1 */
4940 /* */
4941 /**************************************************************************/
_nx_ftp_server_data_process(NX_FTP_SERVER * ftp_server_ptr)4942 VOID _nx_ftp_server_data_process(NX_FTP_SERVER *ftp_server_ptr)
4943 {
4944
4945 UINT i;
4946 UINT status;
4947 ULONG length;
4948 NX_PACKET *packet_ptr;
4949 NX_PACKET *next_packet_ptr;
4950 NX_FTP_CLIENT_REQUEST *client_req_ptr;
4951
4952
4953 /* Now look for a socket that has receive data. */
4954 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
4955 {
4956
4957 /* Setup pointer to client request structure. */
4958 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
4959
4960 /* Now see if this socket has data. If so, process all of it now! */
4961 while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_receive_queue_count)
4962 {
4963
4964 /* Reset the client request activity timeout. */
4965 client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT;
4966
4967 /* Attempt to read a packet from this socket. */
4968 status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_data_socket), &packet_ptr, NX_NO_WAIT);
4969
4970 /* Check for not data present. */
4971 if (status != NX_SUCCESS)
4972 {
4973
4974 /* Just continue the loop and look at the next socket. */
4975 continue;
4976 }
4977
4978 /* Check for open type. */
4979 if (client_req_ptr -> nx_ftp_client_request_open_type != NX_FTP_OPEN_FOR_WRITE)
4980 {
4981
4982 /* Just release the packet. */
4983 nx_packet_release(packet_ptr);
4984
4985 /* Continue the loop. */
4986 continue;
4987 }
4988
4989 /* Determine if the block mode is enabled. */
4990 if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)
4991 {
4992
4993 /* Retrieve the block header. */
4994 status = _nx_ftp_server_block_header_retrieve(client_req_ptr, packet_ptr);
4995
4996 /* Determine if an error occurred. */
4997 if (status)
4998 {
4999
5000 /* Continue the loop. */
5001 continue;
5002 }
5003 }
5004
5005 /* Update the total bytes for this file. This will be checked on close to see if
5006 any error occurred. */
5007 client_req_ptr -> nx_ftp_client_request_total_bytes += packet_ptr -> nx_packet_length;
5008
5009 /* Write the packet to the file. */
5010 length = packet_ptr -> nx_packet_length;
5011 next_packet_ptr = packet_ptr;
5012 do
5013 {
5014
5015 /* Write to the already opened file. */
5016 status = fx_file_write(&(client_req_ptr -> nx_ftp_client_request_file), next_packet_ptr -> nx_packet_prepend_ptr,
5017 (ULONG)((next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)));
5018
5019 /* If unsuccessful file write, ok to receive the rest of the socket
5020 packets from the receive queue. */
5021
5022 if (status == FX_SUCCESS)
5023 {
5024
5025 /* Increment the number of bytes received. */
5026 ftp_server_ptr -> nx_ftp_server_total_bytes_received +=
5027 (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr);
5028 }
5029
5030 /* If not successful, keep retrieving packets from the socket receive queue so we can free
5031 up the packets. */
5032
5033 /* Update the remaining length to write. */
5034 length = length - (ULONG) (next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr);
5035
5036 #ifdef NX_DISABLE_PACKET_CHAIN
5037 next_packet_ptr = NX_NULL;
5038 #else
5039 /* Pickup next packet pointer. */
5040 next_packet_ptr = next_packet_ptr -> nx_packet_next;
5041 #endif /* NX_DISABLE_PACKET_CHAIN */
5042
5043 } while ((next_packet_ptr) && (length));
5044
5045 /* Release the packet and continue the loop. */
5046 nx_packet_release(packet_ptr);
5047 }
5048 }
5049 }
5050
5051
5052 /**************************************************************************/
5053 /* */
5054 /* FUNCTION RELEASE */
5055 /* */
5056 /* _nx_ftp_server_parse_command PORTABLE C */
5057 /* 6.1.3 */
5058 /* AUTHOR */
5059 /* */
5060 /* Yuxin Zhou, Microsoft Corporation */
5061 /* */
5062 /* DESCRIPTION */
5063 /* */
5064 /* This function determines which FTP request is present, returns */
5065 /* a code for it, and adjusts the packet pointer to the next token. */
5066 /* */
5067 /* */
5068 /* INPUT */
5069 /* */
5070 /* packet_ptr Pointer to FTP packet */
5071 /* */
5072 /* OUTPUT */
5073 /* */
5074 /* FTP command code */
5075 /* */
5076 /* CALLS */
5077 /* */
5078 /* None */
5079 /* */
5080 /* CALLED BY */
5081 /* */
5082 /* _nx_ftp_server_command_process FTP command process */
5083 /* */
5084 /* RELEASE HISTORY */
5085 /* */
5086 /* DATE NAME DESCRIPTION */
5087 /* */
5088 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5089 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5090 /* resulting in version 6.1 */
5091 /* 12-31-2020 Yuxin Zhou Modified comment(s), improved */
5092 /* packet length verification, */
5093 /* resulting in version 6.1.3 */
5094 /* */
5095 /**************************************************************************/
_nx_ftp_server_parse_command(NX_PACKET * packet_ptr)5096 UINT _nx_ftp_server_parse_command(NX_PACKET *packet_ptr)
5097 {
5098
5099 UINT i;
5100 char *buffer_ptr;
5101
5102
5103 /* Check packet length. */
5104 if (packet_ptr -> nx_packet_length == 0)
5105 {
5106
5107 /* Empty message, just return INVALID. */
5108 return(NX_FTP_INVALID);
5109 }
5110
5111 /* Setup pointer to command buffer area. */
5112 buffer_ptr = (char *) packet_ptr -> nx_packet_prepend_ptr;
5113
5114 /* Search the packet to find the end of the token, converting the token to Uppercase. */
5115 i = 0;
5116 while ((buffer_ptr[i] != ' ') && (buffer_ptr[i] != (char) 13) && (i < packet_ptr -> nx_packet_length - 1))
5117 {
5118
5119 /* Determine if the character is lowercase. */
5120 if ((buffer_ptr[i] >= 'a') && (buffer_ptr[i] <= 'z'))
5121 {
5122
5123 /* Convert to uppercase. */
5124 buffer_ptr[i] = (char) (((UCHAR) buffer_ptr[i]) - ((UCHAR) 0x20));
5125 }
5126
5127 /* Move to next character. */
5128 i++;
5129 }
5130
5131 /* Set the NULL termination for the command. */
5132 buffer_ptr[i] = NX_NULL;
5133
5134 /* Move the packet pointer to the next token. */
5135 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + (i + 1);
5136
5137 /* Decrease the length of the packet. */
5138 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (i + 1);
5139
5140 /* Is it the "USER" command? */
5141 if (strcmp(buffer_ptr, "USER") == 0)
5142 {
5143 return(NX_FTP_USER);
5144 }
5145
5146 /* Is the the "PASS" command? */
5147 if (strcmp(buffer_ptr, "PASS") == 0)
5148 {
5149 return(NX_FTP_PASS);
5150 }
5151
5152 /* Is it the "QUIT" command? */
5153 if (strcmp(buffer_ptr, "QUIT") == 0)
5154 {
5155 return(NX_FTP_QUIT);
5156 }
5157
5158 /* Is it the "RETR" command? */
5159 if (strcmp(buffer_ptr, "RETR") == 0)
5160 {
5161 return(NX_FTP_RETR);
5162 }
5163
5164 /* Is it the "STOR" command? */
5165 if (strcmp(buffer_ptr, "STOR") == 0)
5166 {
5167 return(NX_FTP_STOR);
5168 }
5169
5170 /* Is it the "RNFR" command? */
5171 if (strcmp(buffer_ptr, "RNFR") == 0)
5172 {
5173 return(NX_FTP_RNFR);
5174 }
5175
5176 /* Is it the "RNTO" command? */
5177 if (strcmp(buffer_ptr, "RNTO") == 0)
5178 {
5179 return(NX_FTP_RNTO);
5180 }
5181
5182 /* Is it the "DELE" command? */
5183 if (strcmp(buffer_ptr, "DELE") == 0)
5184 {
5185 return(NX_FTP_DELE);
5186 }
5187
5188 /* Is it the "RMD" or "XRMD" command? */
5189 if ((strcmp(buffer_ptr, "RMD") == 0) || (strcmp(buffer_ptr, "XRMD") == 0))
5190 {
5191 return(NX_FTP_RMD);
5192 }
5193
5194 /* Is it the "MKD" or "XMKD" command? */
5195 if ((strcmp(buffer_ptr, "MKD") == 0) || (strcmp(buffer_ptr, "XMKD")== 0))
5196 {
5197 return(NX_FTP_MKD);
5198 }
5199
5200 /* Is it the "CDUP" command? */
5201 if (strcmp(buffer_ptr, "CDUP") == 0)
5202 {
5203 return(NX_FTP_CDUP);
5204 }
5205
5206 /* Is it the "CWD" command? */
5207 if (strcmp(buffer_ptr, "CWD") == 0)
5208 {
5209 return(NX_FTP_CWD);
5210 }
5211
5212 /* Is it the "PWD" command? */
5213 if (strcmp(buffer_ptr, "PWD") == 0)
5214 {
5215 return(NX_FTP_PWD);
5216 }
5217
5218 /* Is it the "NLST" command? */
5219 if (strcmp(buffer_ptr, "NLST") == 0)
5220 {
5221 return(NX_FTP_NLST);
5222 }
5223
5224 /* Is it the "LIST" command? */
5225 if (strcmp(buffer_ptr, "LIST") == 0)
5226 {
5227 return(NX_FTP_LIST);
5228 }
5229
5230 /* Is it the "PORT" command? */
5231 if (strcmp(buffer_ptr, "PORT") == 0)
5232 {
5233 return(NX_FTP_PORT);
5234 }
5235
5236 /* Is it the "EPRT" command? */
5237 if (strcmp(buffer_ptr, "EPRT") == 0)
5238 {
5239 return(NX_FTP_EPRT);
5240 }
5241
5242 /* Is it the "TYPE" command? */
5243 if (strcmp(buffer_ptr, "TYPE") == 0)
5244 {
5245 return(NX_FTP_TYPE);
5246 }
5247
5248 /* Is it the "NOOP" command? */
5249 if (strcmp(buffer_ptr, "NOOP") == 0)
5250 {
5251 return(NX_FTP_NOOP);
5252 }
5253
5254 /* Is it the "PASV" command? */
5255 if (strcmp(buffer_ptr, "PASV") == 0)
5256 {
5257 return(NX_FTP_PASV);
5258 }
5259
5260 /* Is it the "EPSV" command? */
5261 if (strcmp(buffer_ptr, "EPSV") == 0)
5262 {
5263 return(NX_FTP_EPSV);
5264 }
5265
5266 /* Is it the "MODE" command? */
5267 if (strcmp(buffer_ptr, "MODE") == 0)
5268 {
5269 return(NX_FTP_MODE);
5270 }
5271
5272 /* Otherwise, just return INVALID. */
5273 return(NX_FTP_INVALID);
5274 }
5275
5276
5277 /**************************************************************************/
5278 /* */
5279 /* FUNCTION RELEASE */
5280 /* */
5281 /* _nx_ftp_server_timeout PORTABLE C */
5282 /* 6.1 */
5283 /* AUTHOR */
5284 /* */
5285 /* Yuxin Zhou, Microsoft Corporation */
5286 /* */
5287 /* DESCRIPTION */
5288 /* */
5289 /* This function is the periodic timer for this FTP server. Its duty */
5290 /* is to inform the FTP server that it is time to check for activity */
5291 /* timeouts. */
5292 /* */
5293 /* */
5294 /* INPUT */
5295 /* */
5296 /* ftp_server_address FTP server's address */
5297 /* */
5298 /* OUTPUT */
5299 /* */
5300 /* None */
5301 /* */
5302 /* CALLS */
5303 /* */
5304 /* tx_event_flags_set Set events for server thread */
5305 /* */
5306 /* CALLED BY */
5307 /* */
5308 /* ThreadX ThreadX timer callback */
5309 /* */
5310 /* RELEASE HISTORY */
5311 /* */
5312 /* DATE NAME DESCRIPTION */
5313 /* */
5314 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5315 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5316 /* resulting in version 6.1 */
5317 /* */
5318 /**************************************************************************/
_nx_ftp_server_timeout(ULONG ftp_server_address)5319 VOID _nx_ftp_server_timeout(ULONG ftp_server_address)
5320 {
5321
5322 NX_FTP_SERVER *server_ptr;
5323
5324
5325 /* Pickup server pointer. */
5326 server_ptr = (NX_FTP_SERVER *) ftp_server_address;
5327
5328 /* Set the data event flag. */
5329 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_ACTIVITY_TIMEOUT, TX_OR);
5330 }
5331
5332
5333 /**************************************************************************/
5334 /* */
5335 /* FUNCTION RELEASE */
5336 /* */
5337 /* _nx_ftp_server_timeout_processing PORTABLE C */
5338 /* 6.3.0 */
5339 /* AUTHOR */
5340 /* */
5341 /* Yuxin Zhou, Microsoft Corporation */
5342 /* */
5343 /* DESCRIPTION */
5344 /* */
5345 /* This function reviews all the active FTP client connections and */
5346 /* looks for an activity timeout. If a connection has not had any */
5347 /* activity within NX_FTP_ACTIVITY_TIMEOUT seconds, the connection is */
5348 /* deleted and its resources are made available to a new connection. */
5349 /* */
5350 /* */
5351 /* INPUT */
5352 /* */
5353 /* ftp_server_ptr Pointer to FTP server */
5354 /* */
5355 /* OUTPUT */
5356 /* */
5357 /* None */
5358 /* */
5359 /* CALLS */
5360 /* */
5361 /* fx_file_close Close file */
5362 /* nx_packet_release Release saved packet */
5363 /* nx_tcp_server_socket_relisten Relisten for another connect */
5364 /* nx_tcp_server_socket_unaccept Unaccept server connection */
5365 /* nx_tcp_socket_disconnect Disconnect socket */
5366 /* _nx_ftp_server_data_socket_cleanup Clean up data socket */
5367 /* */
5368 /* CALLED BY */
5369 /* */
5370 /* _nx_ftp_server_thread_entry FTP server thread */
5371 /* */
5372 /* RELEASE HISTORY */
5373 /* */
5374 /* DATE NAME DESCRIPTION */
5375 /* */
5376 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5377 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5378 /* resulting in version 6.1 */
5379 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
5380 /* fixed the issue of clearing */
5381 /* data socket, */
5382 /* resulting in version 6.1.9 */
5383 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
5384 /* fixed duplicate packet */
5385 /* release issue, */
5386 /* resulting in version 6.3.0 */
5387 /* */
5388 /**************************************************************************/
_nx_ftp_server_timeout_processing(NX_FTP_SERVER * ftp_server_ptr)5389 VOID _nx_ftp_server_timeout_processing(NX_FTP_SERVER *ftp_server_ptr)
5390 {
5391
5392 UINT i;
5393 NX_FTP_CLIENT_REQUEST *client_req_ptr;
5394
5395
5396 /* Examine all the client request structures. */
5397 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
5398 {
5399
5400 /* Setup pointer to client request structure. */
5401 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
5402
5403 /* Now see if this socket has an activity timeout active. */
5404 if (client_req_ptr -> nx_ftp_client_request_activity_timeout)
5405 {
5406
5407 /* Decrement the activity timeout for this client request. */
5408 if (client_req_ptr -> nx_ftp_client_request_activity_timeout > NX_FTP_TIMEOUT_PERIOD)
5409 client_req_ptr -> nx_ftp_client_request_activity_timeout = client_req_ptr -> nx_ftp_client_request_activity_timeout - NX_FTP_TIMEOUT_PERIOD;
5410 else
5411 client_req_ptr -> nx_ftp_client_request_activity_timeout = 0;
5412
5413 /* Determine if this entry has exceeded the activity timeout. */
5414 if (client_req_ptr -> nx_ftp_client_request_activity_timeout == 0)
5415 {
5416
5417 /* Yes, activity timeout has been exceeded. Tear down and cleanup the
5418 entire client request structure. */
5419
5420 /* Increment the activity timeout counter. */
5421 ftp_server_ptr -> nx_ftp_server_activity_timeouts++;
5422
5423 /* If create, cleanup the data socket. */
5424 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
5425 {
5426
5427 /* Clean up the client socket. */
5428 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
5429 }
5430
5431 /* Reset the transfer mode as stream mode. */
5432 client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
5433
5434 /* Reset the block bytes. */
5435 client_req_ptr -> nx_ftp_client_request_block_bytes = 0;
5436
5437 /* Now disconnect the command socket. */
5438 nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT);
5439
5440 /* Unaccept the server socket. */
5441 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket));
5442
5443 /* Check to see if a packet is queued up. */
5444 if (client_req_ptr -> nx_ftp_client_request_packet)
5445 {
5446
5447 /* Yes, release it! */
5448 nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet);
5449 client_req_ptr -> nx_ftp_client_request_packet = NX_NULL;
5450 }
5451
5452 /* Relisten on this socket. This will probably fail, but it is needed just in case all available
5453 clients were in use at the time of the last relisten. */
5454 nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT,
5455 &(client_req_ptr -> nx_ftp_client_request_control_socket));
5456 }
5457 }
5458 }
5459 }
5460
5461
5462 /**************************************************************************/
5463 /* */
5464 /* FUNCTION RELEASE */
5465 /* */
5466 /* _nx_ftp_server_control_disconnect PORTABLE C */
5467 /* 6.1 */
5468 /* AUTHOR */
5469 /* */
5470 /* Yuxin Zhou, Microsoft Corporation */
5471 /* */
5472 /* DESCRIPTION */
5473 /* */
5474 /* This function notifies the FTP server thread of client disconnects */
5475 /* of the control socket. */
5476 /* */
5477 /* */
5478 /* INPUT */
5479 /* */
5480 /* control_socket_ptr Control socket event occurred */
5481 /* */
5482 /* OUTPUT */
5483 /* */
5484 /* None */
5485 /* */
5486 /* CALLS */
5487 /* */
5488 /* tx_event_flags_set Set events for server thread */
5489 /* */
5490 /* CALLED BY */
5491 /* */
5492 /* NetX NetX connect callback */
5493 /* */
5494 /* RELEASE HISTORY */
5495 /* */
5496 /* DATE NAME DESCRIPTION */
5497 /* */
5498 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5499 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5500 /* resulting in version 6.1 */
5501 /* */
5502 /**************************************************************************/
_nx_ftp_server_control_disconnect(NX_TCP_SOCKET * control_socket_ptr)5503 VOID _nx_ftp_server_control_disconnect(NX_TCP_SOCKET *control_socket_ptr)
5504 {
5505
5506 NX_FTP_SERVER *server_ptr;
5507
5508
5509 /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */
5510 server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr;
5511
5512 /* Set the data event flag. */
5513 tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONTROL_DISCONNECT, TX_OR);
5514 }
5515
5516
5517 /**************************************************************************/
5518 /* */
5519 /* FUNCTION RELEASE */
5520 /* */
5521 /* _nx_ftp_server_control_disconnect_processing PORTABLE C */
5522 /* 6.3.0 */
5523 /* AUTHOR */
5524 /* */
5525 /* Yuxin Zhou, Microsoft Corporation */
5526 /* */
5527 /* DESCRIPTION */
5528 /* */
5529 /* This function reviews all the active FTP client connections and */
5530 /* looks for a client initiated disconnect activity that was done */
5531 /* without a QUIT command. */
5532 /* */
5533 /* */
5534 /* INPUT */
5535 /* */
5536 /* ftp_server_ptr Pointer to FTP server */
5537 /* */
5538 /* OUTPUT */
5539 /* */
5540 /* None */
5541 /* */
5542 /* CALLS */
5543 /* */
5544 /* fx_file_close Close file */
5545 /* nx_packet_release Release saved packet */
5546 /* nx_tcp_server_socket_relisten Relisten for another connect */
5547 /* nx_tcp_server_socket_unaccept Unaccept server connection */
5548 /* nx_tcp_socket_disconnect Disconnect socket */
5549 /* _nx_ftp_server_data_socket_cleanup Clean up data socket */
5550 /* */
5551 /* CALLED BY */
5552 /* */
5553 /* _nx_ftp_server_thread_entry FTP server thread */
5554 /* */
5555 /* RELEASE HISTORY */
5556 /* */
5557 /* DATE NAME DESCRIPTION */
5558 /* */
5559 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5560 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5561 /* resulting in version 6.1 */
5562 /* 10-15-2021 Yuxin Zhou Modified comment(s), */
5563 /* fixed the issue of clearing */
5564 /* data socket, */
5565 /* resulting in version 6.1.9 */
5566 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
5567 /* fixed duplicate packet */
5568 /* release issue, */
5569 /* resulting in version 6.3.0 */
5570 /* */
5571 /**************************************************************************/
_nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER * ftp_server_ptr)5572 VOID _nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER *ftp_server_ptr)
5573 {
5574
5575 UINT i;
5576 NX_FTP_CLIENT_REQUEST *client_req_ptr;
5577
5578
5579 /* Examine all the client request structures. */
5580 for (i = 0; i < NX_FTP_MAX_CLIENTS; i++)
5581 {
5582
5583 /* Setup pointer to client request structure. */
5584 client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]);
5585
5586 /* Determine if this socket is in a disconnect state. This should only happen
5587 if the client issues a disconnect without issuing a QUIT command. */
5588 if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) ||
5589 ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_SYN_SENT) &&
5590 (client_req_ptr -> nx_ftp_client_request_activity_timeout > 0)))
5591 {
5592
5593 /* Yes, this socket needs to be torn down. */
5594
5595 /* Increment the number of disconnection requests. */
5596 ftp_server_ptr -> nx_ftp_server_disconnection_requests++;
5597
5598 /* Clear authentication. */
5599 client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE;
5600
5601 /* Disable the client request activity timeout. */
5602 client_req_ptr -> nx_ftp_client_request_activity_timeout = 0;
5603
5604 /* If create, cleanup the associated data socket. */
5605 if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id)
5606 {
5607
5608 /* Clean up the client socket. */
5609 _nx_ftp_server_data_socket_cleanup(ftp_server_ptr, client_req_ptr);
5610 }
5611
5612 /* Reset the transfer mode as stream mode. */
5613 client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM;
5614
5615 /* Reset the block bytes. */
5616 client_req_ptr -> nx_ftp_client_request_block_bytes = 0;
5617
5618 /* Check if this client login. */
5619 if (client_req_ptr -> nx_ftp_client_request_login)
5620 {
5621
5622 /* Call the logout function. */
5623
5624 #ifndef NX_DISABLE_IPV4
5625 /* Does this server have an IPv4 login function? */
5626 if (ftp_server_ptr -> nx_ftp_logout_ipv4)
5627 {
5628
5629 /* Call the logout which takes IPv4 address input. */
5630 (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr,
5631 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4,
5632 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
5633 client_req_ptr -> nx_ftp_client_request_username,
5634 client_req_ptr -> nx_ftp_client_request_password, NX_NULL);
5635 }
5636 #endif /* NX_DISABLE_IPV4 */
5637 if (ftp_server_ptr -> nx_ftp_logout)
5638 {
5639
5640 /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */
5641 (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip),
5642 client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port,
5643 client_req_ptr -> nx_ftp_client_request_username,
5644 client_req_ptr -> nx_ftp_client_request_password, NX_NULL);
5645 }
5646
5647 /* Set the login as FALSE. */
5648 client_req_ptr -> nx_ftp_client_request_login = NX_FALSE;
5649 }
5650
5651 /* Now disconnect the command socket. */
5652 nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT);
5653
5654 /* Unaccept the server socket. */
5655 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket));
5656
5657 /* Check to see if a packet is queued up. */
5658 if (client_req_ptr -> nx_ftp_client_request_packet)
5659 {
5660
5661 /* Yes, release it! */
5662 nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet);
5663 client_req_ptr -> nx_ftp_client_request_packet = NX_NULL;
5664 }
5665
5666 /* Relisten on this socket. This will probably fail, but it is needed just in case all available
5667 clients were in use at the time of the last relisten. */
5668 nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT,
5669 &(client_req_ptr -> nx_ftp_client_request_control_socket));
5670 }
5671 }
5672 }
5673
5674 /**************************************************************************/
5675 /* */
5676 /* FUNCTION RELEASE */
5677 /* */
5678 /* _nx_ftp_packet_allocate PORTABLE C */
5679 /* 6.1 */
5680 /* AUTHOR */
5681 /* */
5682 /* Yuxin Zhou, Microsoft Corporation */
5683 /* */
5684 /* DESCRIPTION */
5685 /* */
5686 /* This function uses knowledge of the client request connection type */
5687 /* to allocate the proper TCP packet type. */
5688 /* */
5689 /* */
5690 /* INPUT */
5691 /* */
5692 /* pool_ptr Pointer to packet pool */
5693 /* client_request_ptr Pointer to Client request */
5694 /* packet_ptr Pointer to allocated packet */
5695 /* packet_type Packet type, usually TCP */
5696 /* wait_option Wait option on packet alloc */
5697 /* */
5698 /* OUTPUT */
5699 /* */
5700 /* status Packet allocation status */
5701 /* */
5702 /* CALLS */
5703 /* */
5704 /* nx_packet_allocate NetX packet allocate service */
5705 /* */
5706 /* CALLED BY */
5707 /* */
5708 /* _nx_ftp_server_command_process Client command handler */
5709 /* _nx_ftp_server_control_disconnect_processing */
5710 /* Client disconnect handler */
5711 /* _nx_ftp_server_connect_process Client Connect request handler*/
5712 /* */
5713 /* RELEASE HISTORY */
5714 /* */
5715 /* DATE NAME DESCRIPTION */
5716 /* */
5717 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5718 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5719 /* resulting in version 6.1 */
5720 /* */
5721 /**************************************************************************/
5722
_nx_ftp_packet_allocate(NX_PACKET_POOL * pool_ptr,NX_FTP_CLIENT_REQUEST * client_request_ptr,NX_PACKET ** packet_ptr,UINT packet_type,UINT wait_option)5723 UINT _nx_ftp_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET **packet_ptr, UINT packet_type, UINT wait_option)
5724 {
5725
5726 UINT status;
5727
5728
5729 /* Determine type of packet to allocate based on client connection. */
5730
5731 if (client_request_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V6)
5732 {
5733
5734 /* This is an IPV6 connection. */
5735 status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv6_TCP_PACKET, wait_option);
5736 }
5737 else
5738 {
5739
5740 /* This is an IPv4 connection. */
5741 status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv4_TCP_PACKET, wait_option);
5742 }
5743
5744
5745 NX_PARAMETER_NOT_USED(packet_type);
5746
5747 /* Return completion status. */
5748 return status;
5749 }
5750
5751
5752 #ifdef FEATURE_NX_IPV6
5753 /**************************************************************************/
5754 /* */
5755 /* FUNCTION RELEASE */
5756 /* */
5757 /* _nx_ftp_utility_parse_IPv6_address PORTABLE C */
5758 /* 6.1.3 */
5759 /* AUTHOR */
5760 /* */
5761 /* Yuxin Zhou, Microsoft Corporation */
5762 /* */
5763 /* DESCRIPTION */
5764 /* */
5765 /* This function parses a string containing a properly formatted IPv6 */
5766 /* string and while it does not assume it is part of the EPRT command */
5767 /* it does not expect to find any non IPv6 characters in the string */
5768 /* after checking for a leading 'EPRT |2|' and before an entire IPv6 */
5769 /* address is parsed. If there is a leading 'EPRT ' in the string, it */
5770 /* does check that it has the required '|2|' preamble to the IPv6 */
5771 /* address. */
5772 /* */
5773 /* */
5774 /* INPUT */
5775 /* */
5776 /* buffer_ptr Pointer to the string to parse*/
5777 /* buffer_length Size of the IPv6 string */
5778 /* ipduo_address Pointer to the IPv6 address */
5779 /* parsed from the buffer */
5780 /* */
5781 /* OUTPUT */
5782 /* */
5783 /* NX_SUCCESS Proper IPv6 address parsed */
5784 /* NX_FTP_ERROR IPv6 address is bad */
5785 /* */
5786 /* CALLS */
5787 /* */
5788 /* None */
5789 /* */
5790 /* CALLED BY */
5791 /* */
5792 /* _nx_ftp_server_command_process Parse a received FTP command */
5793 /* packet service */
5794 /* */
5795 /* RELEASE HISTORY */
5796 /* */
5797 /* DATE NAME DESCRIPTION */
5798 /* */
5799 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
5800 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
5801 /* resulting in version 6.1 */
5802 /* 12-31-2020 Yuxin Zhou Modified comment(s), improved */
5803 /* colons count verification, */
5804 /* resulting in version 6.1.3 */
5805 /* */
5806 /**************************************************************************/
_nx_ftp_utility_parse_IPv6_address(CHAR * buffer_ptr,UINT buffer_length,NXD_ADDRESS * ipduo_address)5807 UINT _nx_ftp_utility_parse_IPv6_address(CHAR *buffer_ptr, UINT buffer_length, NXD_ADDRESS *ipduo_address)
5808 {
5809
5810 UINT j, k, i, m, colons, digit;
5811 UINT number_consecutive_zeros_to_add, remaining_colons, actual_colons_left;
5812 ULONG temp;
5813
5814
5815 /* Initialize variables. */
5816 temp = 0;
5817 colons = 0;
5818 remaining_colons = 0;
5819 actual_colons_left = 0;
5820 j = 0;
5821 k = 0;
5822 i = 0;
5823
5824 number_consecutive_zeros_to_add = 0;
5825
5826 /* Check if the buffer includes the leading EPRT command. */
5827 if ( (buffer_ptr[0] == 'E' || buffer_ptr[0] == 'e') &&
5828 (buffer_ptr[1] == 'P' || buffer_ptr[1] == 'p') &&
5829 (buffer_ptr[2] == 'R' || buffer_ptr[2] == 'p') &&
5830 (buffer_ptr[3] == 'T' || buffer_ptr[3] == 't') &&
5831 (buffer_ptr[4] == ' '))
5832 {
5833
5834 /* If this is an EPRT command it must be followed by a single
5835 space and the |2| preamble. */
5836 if ((buffer_ptr[5] != '|') || (buffer_ptr[6] != '2') || (buffer_ptr[7] != '|'))
5837 {
5838
5839 /* It does not. Return error status. */
5840 return NX_FTP_INVALID_COMMAND;
5841 }
5842
5843 /* Set the start of where to resume parsing. */
5844 j = 8;
5845 }
5846 else
5847 {
5848 /* If the EPRT command has been removed already, check for the |2| preamble. */
5849 if ((buffer_ptr[0] == '|') && (buffer_ptr[1] == '2') && (buffer_ptr[2] == '|'))
5850 {
5851
5852 /* Set the start of where to resume parsing. */
5853 j = 3;
5854 }
5855 }
5856
5857 /* Parse the buffer till the end is reached (or a complete
5858 IPv6 address is parsed. */
5859 while (j < buffer_length)
5860 {
5861
5862 /* Is a numeric or hex character present? */
5863 if (((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) ||
5864 ((buffer_ptr[j] >= 'A') && (buffer_ptr[j] <= 'F')) ||
5865 ((buffer_ptr[j] >= 'a') && (buffer_ptr[j] <= 'f')))
5866 {
5867
5868 /* Yes, is a numeric character is present? Update the IP address. */
5869 if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9')
5870 {
5871 temp = (temp*16) + (ULONG) (buffer_ptr[j] - '0');
5872 }
5873 else
5874 {
5875 /* Is a hex character present? */
5876 switch (buffer_ptr[j] )
5877 {
5878 case 'A':
5879 case 'a':
5880 digit = 10;
5881 break;
5882
5883 case 'B':
5884 case 'b':
5885 digit = 11;
5886 break;
5887
5888 case 'C':
5889 case 'c':
5890 digit = 12;
5891 break;
5892
5893 case 'D':
5894 case 'd':
5895 digit = 13;
5896 break;
5897
5898 case 'E':
5899 case 'e':
5900 digit = 14;
5901 break;
5902
5903 case 'F':
5904 case 'f':
5905 digit = 15;
5906 break;
5907
5908 default:
5909 digit = 0;
5910 }
5911
5912 /* Update the ULONG. */
5913 temp = (temp*16 + digit);
5914 }
5915
5916 /* Increase the size of the digit by one. */
5917 i++;
5918
5919 /* Check if the size of this digit is out of range. */
5920 if (i > 4)
5921 {
5922
5923 /* Yes, return an error status. */
5924 return NX_FTP_INVALID_ADDRESS;
5925 }
5926 }
5927
5928 /* Determine if a CR/LF is present. */
5929 else if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0))
5930 {
5931
5932 /* Whether this is a prematurely terminated IPv6 string, abort any further parsing. */
5933 break;
5934 }
5935
5936 /* Determine if a colon is present. */
5937 else if (buffer_ptr[j] == ':')
5938 {
5939
5940 /* Check if colons is valid. */
5941 if (colons >= 7)
5942 {
5943 return NX_FTP_INVALID_ADDRESS;
5944 }
5945
5946 /* Increment the colon count. */
5947 colons++;
5948
5949 /* Are we in the middle of a ULONG? */
5950 if (colons % 2 == 1)
5951 {
5952
5953 /* Yes, add this temp to the lower half. */
5954 ipduo_address -> nxd_ip_address.v6[k] = temp;
5955 }
5956 else
5957 {
5958
5959 /* No, shift the existing 16 bits left first. */
5960 ipduo_address -> nxd_ip_address.v6[k] <<= 16;
5961
5962 /* Mask out the lower 16 bits. */
5963 ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000;
5964
5965 /* Add the number we just parsed. */
5966 ipduo_address -> nxd_ip_address.v6[k] += temp;
5967
5968 /* Move to the next ULONG in the nxd_ip_address array. */
5969 k++;
5970 }
5971
5972 /* Reset our counters and temporary ULONG. */
5973 i = 0;
5974 temp = 0;
5975
5976 /* Check if we have encountered a double colon. */
5977 if (buffer_ptr[j + 1] == ':')
5978 {
5979
5980 /* Yes; Check if we already encountered a double colon. */
5981 if (remaining_colons)
5982 {
5983
5984 /* Yes we have. This is an improperly formatted IPv6 address. */
5985 return NX_FTP_INVALID_ADDRESS;
5986 }
5987
5988 /* Move the index to the second colon. */
5989 j++;
5990
5991 /* Compute how many more colons should there be. */
5992 remaining_colons = 7 - colons;
5993
5994 /* Start looking for the rest of the colons after the double. */
5995 m = j + 1;
5996
5997 /* Count colons in the rest of the string. */
5998 while (m < buffer_length)
5999 {
6000
6001 /* Do we have another colon? */
6002 if (buffer_ptr [m] == ':')
6003 {
6004
6005 /* Yes, update the count. */
6006 actual_colons_left++;
6007 }
6008 m++;
6009 }
6010
6011 /* Check if colons is valid. */
6012 if (actual_colons_left >= remaining_colons)
6013 {
6014 return NX_FTP_INVALID_ADDRESS;
6015 }
6016
6017 /* Compute the number of zeros to insert into the NXD_ADDRESS IPv6 ULONG array. */
6018 number_consecutive_zeros_to_add = remaining_colons - actual_colons_left;
6019
6020 /* Add the zeroes until its time to start parsing rest of the IPv6 address string. */
6021 while (number_consecutive_zeros_to_add)
6022 {
6023
6024 /* Determine where to add the 16 bits depending
6025 on odd or even number colon we're on. */
6026
6027 /* Are we in the middle of the current v6 ULONG?*/
6028 if (colons % 2 == 1)
6029 {
6030
6031 /* Yes, shift the bits in v6[k] left, and insert a zero at the least significant end. */
6032 ipduo_address -> nxd_ip_address.v6[k] <<= 16;
6033 ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000;
6034 k++;
6035 }
6036 else
6037 {
6038
6039 /* No, starting the next ULONG in v6 so just set to zero. */
6040 ipduo_address -> nxd_ip_address.v6[k] = 0;
6041 }
6042
6043 /* Keep track of how many colons would have been in the IPv6 string
6044 without the double colon. */
6045 colons++;
6046
6047 number_consecutive_zeros_to_add--;
6048 }
6049 }
6050
6051 }
6052 /* Have we hit the end of the IPv6 address? */
6053 else if (buffer_ptr[j] == '|' && k <= 3)
6054 {
6055
6056 /* Yes, shift the existing 16 bits left first. */
6057 ipduo_address -> nxd_ip_address.v6[k] <<= 16;
6058
6059 /* Mask out the lower 16 bits. */
6060 ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000;
6061
6062 /* Add the number we just parsed. */
6063 ipduo_address -> nxd_ip_address.v6[k] += temp;
6064
6065 /* Clear the temporary ULONG so we know we applied it to our IPv6 address array. */
6066 temp = 0;
6067
6068 /* This is the end of the IP address. Bail out...*/
6069 break;
6070 }
6071 else /* No hex, not a seperator or part of the EPRT command. */
6072 {
6073 /* Unknown character in the IPv6 string. */
6074 return NX_FTP_INVALID_ADDRESS;
6075 }
6076
6077 j++;
6078 }
6079
6080 /* Did we parse the full IP address? */
6081 if (colons != 7 )
6082 {
6083
6084 /* No, it is either too long or too short. */
6085 return NX_FTP_INVALID_ADDRESS;
6086 }
6087
6088 /* Is there a parsed number to apply to the last ULONG e.g. no terminating '|'
6089 in the buffer? */
6090 if (temp)
6091 {
6092 /* Yes, shift the existing 16 bits left first. */
6093 ipduo_address -> nxd_ip_address.v6[3] <<= 16;
6094
6095 /* Mask out the lower 16 bits. */
6096 ipduo_address -> nxd_ip_address.v6[3] = ipduo_address -> nxd_ip_address.v6[3] & 0xFFFF0000;
6097
6098 /* Add the number we just parsed. */
6099 ipduo_address -> nxd_ip_address.v6[3] += temp;
6100 }
6101
6102 return NX_SUCCESS;
6103 }
6104
6105
6106 /**************************************************************************/
6107 /* */
6108 /* FUNCTION RELEASE */
6109 /* */
6110 /* _nx_ftp_utility_parse_port_number PORTABLE C */
6111 /* 6.1 */
6112 /* AUTHOR */
6113 /* */
6114 /* Yuxin Zhou, Microsoft Corporation */
6115 /* */
6116 /* DESCRIPTION */
6117 /* */
6118 /* This function parses a port number from the input buffer. It assumes*/
6119 /* the buffer holds an EPRT command string and therefore looks for the */
6120 /* last '|' separator in the string. If it does not find one, it */
6121 /* returns an error. If it encounters anything after this separator, */
6122 /* other than a digit or CRLF before reaching the end of the buffer it */
6123 /* returns an error. */
6124 /* */
6125 /* */
6126 /* INPUT */
6127 /* */
6128 /* buffer_ptr Pointer to the string to parse*/
6129 /* buffer_length Size of the string */
6130 /* portnumber Pointer to the port number */
6131 /* parsed from the buffer */
6132 /* */
6133 /* OUTPUT */
6134 /* */
6135 /* NX_SUCCESS Proper port number parsed */
6136 /* NX_FTP_ERROR Port number is bad */
6137 /* */
6138 /* CALLS */
6139 /* */
6140 /* None */
6141 /* */
6142 /* CALLED BY */
6143 /* */
6144 /* _nx_ftp_server_command_process Parse a received FTP command */
6145 /* packet service */
6146 /* */
6147 /* RELEASE HISTORY */
6148 /* */
6149 /* DATE NAME DESCRIPTION */
6150 /* */
6151 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6152 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6153 /* resulting in version 6.1 */
6154 /* */
6155 /**************************************************************************/
6156
_nx_ftp_utility_parse_port_number(CHAR * buffer_ptr,UINT buffer_length,UINT * portnumber)6157 UINT _nx_ftp_utility_parse_port_number(CHAR *buffer_ptr, UINT buffer_length, UINT *portnumber)
6158 {
6159
6160 UINT j;
6161 UINT digits = 0;
6162
6163
6164 j = (buffer_length - 1);
6165 *portnumber = 0;
6166
6167 /* Find the terminating CRLF. */
6168 while (j >= 1)
6169 {
6170 if (buffer_ptr[j - 1] == 13 && buffer_ptr[j] == 10)
6171 {
6172 /* Subtract for the extra LF character. */
6173 j--;
6174
6175 /* We're ready to move on to the port number extraction. */
6176 break;
6177 }
6178 j--;
6179 }
6180
6181 /* Find the port number. There may be separators between the port number
6182 and the CRLF. */
6183 while (j >= 1)
6184 {
6185 /* Skip everything except for digits. */
6186 if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9')
6187 {
6188 break;
6189 }
6190
6191 /* But we should not encounter a colon! */
6192 if (buffer_ptr[j] == ':')
6193 {
6194
6195 /* Return an error status. */
6196 return NX_FTP_INVALID_NUMBER;
6197 }
6198
6199 j--;
6200 }
6201
6202 while ((INT)j >= 0)
6203 {
6204
6205 /* Is this a space separator '|'? */
6206 if (buffer_ptr[j] == '|')
6207 {
6208 /* Yes, so the port number must be adjacent. */
6209 j++;
6210
6211 /* Now go back up the buffer. */
6212 while(j < buffer_length - 2)
6213 {
6214
6215 /* Check if we have backed up into the IPv6 address? */
6216 if ((buffer_ptr[j] == ':'))
6217 {
6218 /* Yes, apparently this string is missing the separator and port number. */
6219 return NX_FTP_INVALID_NUMBER;
6220 }
6221
6222 /* Is a numeric character present? */
6223 if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9'))
6224 {
6225
6226 /* Yes, numeric character is present. Update the port number. */
6227 *portnumber = (*portnumber * 10) + (ULONG) (buffer_ptr[j] - '0');
6228 digits++;
6229
6230 /* Check for overflow. */
6231 if (digits > 5)
6232 {
6233 return NX_FTP_INVALID_NUMBER;
6234 }
6235 /* Determine if a CR/LF or | separator is present. This marks
6236 the end of the port number. */
6237 if ((buffer_ptr[j+1] == '|') || (buffer_ptr[j+1] == 13) || (buffer_ptr[j+2] == 10))
6238 {
6239 return NX_SUCCESS;
6240 }
6241
6242
6243 }
6244 else
6245 {
6246
6247 /* This is a non numeric character, and not a CRLF either. */
6248 return NX_FTP_INVALID_NUMBER;
6249 }
6250 j++;
6251 }
6252
6253 /* If we got here we did not parse a properly formatted port number. */
6254 return NX_FTP_INVALID_NUMBER;
6255 }
6256
6257 j--;
6258 }
6259
6260 /* If we got here we did not parse a properly formatted port number. */
6261 return NX_FTP_INVALID_NUMBER;
6262 }
6263
6264
6265 /**************************************************************************/
6266 /* */
6267 /* FUNCTION RELEASE */
6268 /* */
6269 /* _nx_ftp_server_utility_fill_port_number PORTABLE C */
6270 /* 6.1 */
6271 /* AUTHOR */
6272 /* */
6273 /* Yuxin Zhou, Microsoft Corporation */
6274 /* */
6275 /* DESCRIPTION */
6276 /* */
6277 /* This function converts a number to ascii text e.g. and fill the */
6278 /* text port into the buffer. */
6279 /* */
6280 /* INPUT */
6281 /* */
6282 /* number Port number to convert to ASCII */
6283 /* numstring Pointer to ascii portnumber string */
6284 /* */
6285 /* OUTPUT */
6286 /* */
6287 /* size Size of port number */
6288 /* */
6289 /* CALLS */
6290 /* */
6291 /* None */
6292 /* */
6293 /* CALLED BY */
6294 /* */
6295 /* _nx_ftp_server_command_process Processes FTP commands */
6296 /* */
6297 /* */
6298 /* RELEASE HISTORY */
6299 /* */
6300 /* DATE NAME DESCRIPTION */
6301 /* */
6302 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6303 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6304 /* resulting in version 6.1 */
6305 /* */
6306 /**************************************************************************/
_nx_ftp_server_utility_fill_port_number(CHAR * buffer_ptr,UINT port_number)6307 UINT _nx_ftp_server_utility_fill_port_number(CHAR *buffer_ptr, UINT port_number)
6308 {
6309
6310 UINT j;
6311 UINT digit;
6312 UINT size;
6313
6314
6315 /* Initialize counters. */
6316 size = 0;
6317
6318 /* Loop to convert the number to ASCII. */
6319 while (size < 10)
6320 {
6321
6322 /* Shift the current digits over one. */
6323 for (j = size; j != 0; j--)
6324 {
6325
6326 /* Move each digit over one place. */
6327 buffer_ptr[j] = buffer_ptr[j-1];
6328 }
6329
6330 /* Compute the next decimal digit. */
6331 digit = (port_number % 10);
6332
6333 /* Update the input number. */
6334 port_number = (port_number / 10);
6335
6336 /* Store the new digit in ASCII form. */
6337 buffer_ptr[0] = (CHAR) (digit + 0x30);
6338
6339 /* Increment the size. */
6340 size++;
6341
6342 /* Determine if the number is now zero. */
6343 if (port_number == 0)
6344 break;
6345 }
6346
6347 /* Determine if there is an overflow error. */
6348 if (port_number)
6349 {
6350
6351 /* Error, return bad values to user. */
6352 return(0);
6353 }
6354
6355 /* Return size to caller. */
6356 return(size);
6357 }
6358 #endif /* FEATURE_NX_IPV6 */
6359
6360
6361 /**************************************************************************/
6362 /* */
6363 /* FUNCTION RELEASE */
6364 /* */
6365 /* _nx_ftp_server_block_size_get PORTABLE C */
6366 /* 6.1 */
6367 /* AUTHOR */
6368 /* */
6369 /* Yuxin Zhou, Microsoft Corporation */
6370 /* */
6371 /* DESCRIPTION */
6372 /* */
6373 /* This function gets the block size for LIST and NLST in block mode. */
6374 /* */
6375 /* INPUT */
6376 /* */
6377 /* client_request_ptr Pointer to FTP client */
6378 /* block_size The size of block data */
6379 /* */
6380 /* OUTPUT */
6381 /* */
6382 /* status Completion status */
6383 /* */
6384 /* CALLS */
6385 /* */
6386 /* fx_directory_first_full_entry_find Find first directory entry */
6387 /* fx_directory_next_full_entry_find Find next directory entry */
6388 /* _nx_utility_string_length_check Check string length */
6389 /* */
6390 /* CALLED BY */
6391 /* */
6392 /* _nx_ftp_server_command_process Process command */
6393 /* */
6394 /* RELEASE HISTORY */
6395 /* */
6396 /* DATE NAME DESCRIPTION */
6397 /* */
6398 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6399 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6400 /* resulting in version 6.1 */
6401 /* */
6402 /**************************************************************************/
_nx_ftp_server_block_size_get(NX_FTP_SERVER * ftp_server_ptr,UINT ftp_command,CHAR * filename,ULONG * block_size)6403 VOID _nx_ftp_server_block_size_get(NX_FTP_SERVER *ftp_server_ptr, UINT ftp_command, CHAR *filename, ULONG *block_size)
6404 {
6405
6406 UINT j = 0;
6407 UINT attributes;
6408 ULONG size;
6409 UINT year, month, day;
6410 UINT hour, minute, second;
6411 UINT length;
6412 UINT status;
6413
6414
6415 /* Block size for LIST and NLST. */
6416 *block_size = 0;
6417
6418 /* Now get the full directory listing. */
6419 do
6420 {
6421 if (j == 0)
6422 {
6423
6424 /* First directory entry. */
6425 status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
6426 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
6427 j++;
6428 }
6429 else
6430 {
6431
6432 /* Not the first entry - pickup the next! */
6433 status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename,
6434 &attributes, &size, &year, &month, &day, &hour, &minute, &second);
6435 }
6436
6437 /* Determine if successful. */
6438 if (status == NX_SUCCESS)
6439 {
6440
6441 /* Calculate the size of the name. */
6442 if (_nx_utility_string_length_check(filename, &length, FX_MAX_LONG_NAME_LEN - 1))
6443 {
6444 return;
6445 }
6446
6447 /* Check the command. */
6448 if (ftp_command == NX_FTP_NLST)
6449 {
6450
6451 /* NLST. Add extra "cr/lf" (2 bytes). */
6452 (*block_size) += (length + 2);
6453 }
6454 else
6455 {
6456
6457 /* Check if the month is valid. */
6458 if ((month < 1) || (month > 12))
6459 continue;
6460
6461 /* LIST. Add extra file info (52 bytes).
6462 File Info is 10 chars for permissions, 15 chars for owner and group,
6463 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */
6464 (*block_size) += (length + 52);
6465 }
6466 }
6467 } while (status == NX_SUCCESS);
6468 }
6469
6470
6471 /**************************************************************************/
6472 /* */
6473 /* FUNCTION RELEASE */
6474 /* */
6475 /* _nx_ftp_server_block_header_send PORTABLE C */
6476 /* 6.1 */
6477 /* AUTHOR */
6478 /* */
6479 /* Yuxin Zhou, Microsoft Corporation */
6480 /* */
6481 /* DESCRIPTION */
6482 /* */
6483 /* This function sends the block header for block mode. */
6484 /* */
6485 /* INPUT */
6486 /* */
6487 /* client_request_ptr Pointer to FTP client */
6488 /* block_size The size of block data */
6489 /* */
6490 /* OUTPUT */
6491 /* */
6492 /* status Completion status */
6493 /* */
6494 /* CALLS */
6495 /* */
6496 /* nx_packet_release Release packet */
6497 /* nx_tcp_socket_send Send data packet to server */
6498 /* */
6499 /* CALLED BY */
6500 /* */
6501 /* _nx_ftp_server_command_process Process command */
6502 /* */
6503 /* RELEASE HISTORY */
6504 /* */
6505 /* DATE NAME DESCRIPTION */
6506 /* */
6507 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6508 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6509 /* resulting in version 6.1 */
6510 /* */
6511 /**************************************************************************/
_nx_ftp_server_block_header_send(NX_PACKET_POOL * pool_ptr,NX_FTP_CLIENT_REQUEST * client_request_ptr,ULONG block_size)6512 UINT _nx_ftp_server_block_header_send(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, ULONG block_size)
6513 {
6514
6515 UINT status;
6516 NX_PACKET *packet_ptr;
6517 UCHAR *buffer_ptr;
6518
6519
6520 /* Use block mode to transfer data. RFC959, Section3.4.2, Page21-22. */
6521
6522 /* Allocate the packet. */
6523 status = _nx_ftp_packet_allocate(pool_ptr, client_request_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT);
6524
6525 /* Determine if the send was unsuccessful. */
6526 if (status)
6527 {
6528
6529 /* Return error. */
6530 return(status);
6531 }
6532
6533 /* We have a packet, setup pointer to the buffer area. */
6534 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
6535
6536 /* Set the block header. */
6537 if (block_size)
6538 {
6539
6540 /* Descriptor. */
6541 buffer_ptr[0] = 0;
6542
6543 /* Byte count. */
6544 buffer_ptr[1] = (UCHAR)(block_size >> 8);
6545 buffer_ptr[2] = (UCHAR)(block_size);
6546 }
6547 else
6548 {
6549
6550 /* Descriptor. */
6551 buffer_ptr[0] = 64;
6552
6553 /* Byte count. */
6554 buffer_ptr[1] = 0;
6555 buffer_ptr[2] = 0;
6556 }
6557
6558 /* Setup the length of the packet. */
6559 packet_ptr -> nx_packet_length = 3;
6560
6561 /* Setup the packet append pointer. */
6562 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length;
6563
6564 /* Write packet payload to the file. */
6565 status = nx_tcp_socket_send(&(client_request_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT);
6566
6567 /* Determine if the send was unsuccessful. */
6568 if (status)
6569 {
6570
6571 /* Release the packet. */
6572 nx_packet_release(packet_ptr);
6573 }
6574
6575 /* Return success to caller. */
6576 return(status);
6577 }
6578
6579
6580 /**************************************************************************/
6581 /* */
6582 /* FUNCTION RELEASE */
6583 /* */
6584 /* _nx_ftp_server_block_header_retrieve PORTABLE C */
6585 /* 6.1 */
6586 /* AUTHOR */
6587 /* */
6588 /* Yuxin Zhou, Microsoft Corporation */
6589 /* */
6590 /* DESCRIPTION */
6591 /* */
6592 /* This function retrieves the block header for block mode. */
6593 /* */
6594 /* INPUT */
6595 /* */
6596 /* client_request_ptr Pointer to FTP client */
6597 /* packet_ptr Pointer to packet to write */
6598 /* */
6599 /* OUTPUT */
6600 /* */
6601 /* status Completion status */
6602 /* */
6603 /* CALLS */
6604 /* */
6605 /* nx_packet_release Release packet */
6606 /* */
6607 /* CALLED BY */
6608 /* */
6609 /* _nx_ftp_server_data_process Process client write data */
6610 /* */
6611 /* RELEASE HISTORY */
6612 /* */
6613 /* DATE NAME DESCRIPTION */
6614 /* */
6615 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6616 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6617 /* resulting in version 6.1 */
6618 /* */
6619 /**************************************************************************/
_nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST * ftp_client_ptr,NX_PACKET * packet_ptr)6620 UINT _nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST *ftp_client_ptr, NX_PACKET *packet_ptr)
6621 {
6622
6623 ULONG remaining_bytes;
6624 ULONG delta;
6625 UCHAR *buffer_ptr;
6626 #ifndef NX_DISABLE_PACKET_CHAIN
6627 NX_PACKET *before_last_packet;
6628 NX_PACKET *last_packet;
6629 #endif /* NX_DISABLE_PACKET_CHAIN */
6630
6631
6632 /* Check if it is the first packet. */
6633 if (ftp_client_ptr -> nx_ftp_client_request_block_bytes == 0)
6634 {
6635
6636 /* Check the packet length. */
6637 if ((packet_ptr -> nx_packet_length < 3) ||
6638 (packet_ptr -> nx_packet_prepend_ptr + 3 > packet_ptr -> nx_packet_append_ptr))
6639 {
6640
6641 /* Release the packet. */
6642 nx_packet_release(packet_ptr);
6643 return(NX_FTP_SERVER_INVALID_SIZE);
6644 }
6645
6646 /* We have a packet, setup pointer to the buffer area. */
6647 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
6648
6649 /* Process block header. */
6650 ftp_client_ptr -> nx_ftp_client_request_block_bytes = (ULONG)((buffer_ptr[1] << 8) | buffer_ptr[2]);
6651
6652 /* Skip the block header. */
6653 packet_ptr -> nx_packet_prepend_ptr += 3;
6654 packet_ptr -> nx_packet_length -= 3;
6655 }
6656
6657 /* Check if have remaining data. */
6658 remaining_bytes = ftp_client_ptr -> nx_ftp_client_request_block_bytes - ftp_client_ptr -> nx_ftp_client_request_total_bytes;
6659 if (remaining_bytes == 0)
6660 {
6661
6662 /* Release the packet. */
6663 nx_packet_release(packet_ptr);
6664 return(NX_FTP_SERVER_END_OF_BLOCK);
6665 }
6666
6667 /* Check the data of current packet. */
6668 if (remaining_bytes < packet_ptr -> nx_packet_length)
6669 {
6670
6671 /* Remove the extra data, such as: end block header. */
6672
6673 /* Calculate the difference in the length. */
6674 delta = packet_ptr -> nx_packet_length - remaining_bytes;
6675
6676 /* Adjust the packet length. */
6677 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta;
6678
6679 /* Adjust the append pointer. */
6680
6681 #ifndef NX_DISABLE_PACKET_CHAIN
6682 /* Loop to process adjustment that spans multiple packets. */
6683 while (delta)
6684 {
6685
6686 /* Determine if the packet is chained (or still chained after the adjustment). */
6687 if (packet_ptr -> nx_packet_last == NX_NULL)
6688 {
6689
6690 /* No, packet is not chained, simply adjust the append pointer in the packet. */
6691 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
6692
6693 /* Break out of the loop, since the adjustment is complete. */
6694 break;
6695 }
6696
6697 /* Pickup the pointer to the last packet. */
6698 last_packet = packet_ptr -> nx_packet_last;
6699
6700 /* Determine if the amount to adjust is less than the payload in the last packet. */
6701 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
6702 if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta)
6703 {
6704
6705 /* Yes, simply adjust the append pointer of the last packet in the chain. */
6706 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
6707 last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta;
6708
6709 /* Get out of the loop, since the adjustment is complete. */
6710 break;
6711 }
6712 else
6713 {
6714
6715 /* Adjust the delta by the amount in the last packet. */
6716 delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr));
6717
6718 /* Find the packet before the last packet. */
6719 before_last_packet = packet_ptr;
6720 while (before_last_packet -> nx_packet_next != last_packet)
6721 {
6722
6723 /* Move to the next packet in the chain. */
6724 before_last_packet = before_last_packet -> nx_packet_next;
6725 }
6726
6727 /* At this point, we need to release the last packet and adjust the other packet
6728 pointers. */
6729
6730 /* Ensure the next packet pointer is NULL in what is now the last packet. */
6731 before_last_packet -> nx_packet_next = NX_NULL;
6732
6733 /* Determine if the packet is still chained. */
6734 if (packet_ptr != before_last_packet)
6735 {
6736
6737 /* Yes, the packet is still chained, setup the last packet pointer. */
6738 packet_ptr -> nx_packet_last = before_last_packet;
6739 }
6740 else
6741 {
6742
6743 /* The packet is no longer chained, set the last packet pointer to NULL. */
6744 packet_ptr -> nx_packet_last = NX_NULL;
6745 }
6746
6747 /* Release the last packet. */
6748 _nx_packet_release(last_packet);
6749 }
6750 }
6751 #else
6752
6753 /* Simply adjust the append pointer in the packet. */
6754 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
6755 #endif /* NX_DISABLE_PACKET_CHAIN */
6756 }
6757
6758 /* Return success to caller. */
6759 return(NX_SUCCESS);
6760 }
6761
6762
6763 /**************************************************************************/
6764 /* */
6765 /* FUNCTION RELEASE */
6766 /* */
6767 /* _nx_ftp_server_number_to_ascii PORTABLE C */
6768 /* 6.1.8 */
6769 /* AUTHOR */
6770 /* */
6771 /* Yuxin Zhou, Microsoft Corporation */
6772 /* */
6773 /* DESCRIPTION */
6774 /* */
6775 /* This function converts a number to ascii text. Fill space at the */
6776 /* beginning if possible. */
6777 /* */
6778 /* INPUT */
6779 /* */
6780 /* buffer_ptr Pointer to output string buffer */
6781 /* buffer_size Size of output buffer */
6782 /* number Number to convert to ASCII */
6783 /* */
6784 /* OUTPUT */
6785 /* */
6786 /* None */
6787 /* */
6788 /* CALLS */
6789 /* */
6790 /* None */
6791 /* */
6792 /* CALLED BY */
6793 /* */
6794 /* _nx_ftp_server_command_process */
6795 /* Process command */
6796 /* */
6797 /* RELEASE HISTORY */
6798 /* */
6799 /* DATE NAME DESCRIPTION */
6800 /* */
6801 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
6802 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
6803 /* resulting in version 6.1 */
6804 /* 06-02-2021 Yuxin Zhou Modified comment(s), and */
6805 /* corrected the size check, */
6806 /* resulting in version 6.1.7 */
6807 /* 08-02-2021 Yuxin Zhou Modified comment(s), */
6808 /* corrected the pad character,*/
6809 /* resulting in version 6.1.8 */
6810 /* */
6811 /**************************************************************************/
_nx_ftp_server_number_to_ascii(UCHAR * buffer_ptr,UINT buffer_size,UINT number,UCHAR pad)6812 static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number, UCHAR pad)
6813 {
6814 UINT digit;
6815 UINT size;
6816
6817 /* Initialize counters. */
6818 size = 1;
6819
6820 /* Initialize buffer with pad character. */
6821 memset(buffer_ptr, pad, buffer_size);
6822
6823 /* Loop to convert the number to ASCII. */
6824 while (size <= buffer_size)
6825 {
6826
6827 /* Compute the next decimal digit. */
6828 digit = (number % 10);
6829
6830 /* Update the input number. */
6831 number = (number / 10);
6832
6833 /* Store the new digit in ASCII form. */
6834 buffer_ptr[buffer_size - size] = (UCHAR)(digit + '0');
6835
6836 /* Increment the size. */
6837 size++;
6838
6839 /* Determine if the number is now zero. */
6840 if (number == 0)
6841 break;
6842 }
6843 }
6844
6845
6846 /**************************************************************************/
6847 /* */
6848 /* FUNCTION RELEASE */
6849 /* */
6850 /* _nx_ftp_server_data_socket_cleanup PORTABLE C */
6851 /* 6.1.9 */
6852 /* AUTHOR */
6853 /* */
6854 /* Yuxin Zhou, Microsoft Corporation */
6855 /* */
6856 /* DESCRIPTION */
6857 /* */
6858 /* This function cleans up the data socket. */
6859 /* */
6860 /* INPUT */
6861 /* */
6862 /* ftp_server_ptr Pointer to FTP server */
6863 /* client_req_ptr Pointer to client request */
6864 /* */
6865 /* OUTPUT */
6866 /* */
6867 /* None */
6868 /* */
6869 /* CALLS */
6870 /* */
6871 /* fx_file_close Close file */
6872 /* nx_tcp_socket_disconnect Disconnect a socket */
6873 /* nx_tcp_client_socket_unbind Release the data socket port */
6874 /* nx_tcp_server_socket_unaccept Unaccept server connection */
6875 /* nx_tcp_server_socket_unlisten Unlisten on server socket */
6876 /* nx_tcp_socket_delete Delete socket */
6877 /* */
6878 /* CALLED BY */
6879 /* */
6880 /* _nx_ftp_server_command_process Process command */
6881 /* _nx_ftp_server_data_disconnect_process */
6882 /* Disconnect data socket */
6883 /* */
6884 /* RELEASE HISTORY */
6885 /* */
6886 /* DATE NAME DESCRIPTION */
6887 /* */
6888 /* 10-15-2021 Yuxin Zhou Initial Version 6.1.9 */
6889 /* */
6890 /**************************************************************************/
_nx_ftp_server_data_socket_cleanup(NX_FTP_SERVER * ftp_server_ptr,NX_FTP_CLIENT_REQUEST * client_req_ptr)6891 VOID _nx_ftp_server_data_socket_cleanup(NX_FTP_SERVER *ftp_server_ptr, NX_FTP_CLIENT_REQUEST *client_req_ptr)
6892 {
6893
6894 /* First, cleanup this data socket. */
6895 nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT);
6896
6897 /* Unbind/unaccept the data socket. */
6898 if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE)
6899 {
6900 nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket));
6901 nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port);
6902 }
6903 else
6904 {
6905 nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket));
6906 }
6907
6908 /* And finally delete the data socket. */
6909 nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket));
6910
6911 fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file));
6912
6913 #ifdef NX_FTP_FAULT_TOLERANT
6914
6915 /* Flush the media. */
6916 fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr);
6917 #endif
6918
6919 /* Clear the passive transfer enabled flag. */
6920 client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE;
6921 }