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 }