This chapter contains a description of various issues related to installation, set up, and usage of the NetX Duo FTP services.
NetX Duo FTP is available at https://github.com/eclipse-threadx/netxduo. The package includes two source files and a PDF file that contains this document, as follows:
-
nxd_ftp_client.h Header file for NetX Duo FTP Client
-
nxd_ftp_client.c C Source file for NetX Duo FTP Client
-
nxd_ftp_server.h Header file for NetX Duo FTP Server
-
nxd_ftp_server.c C Source file for NetX Duo FTP Server
-
filex_stub.h Stub file if FileX is not present
-
nxd_ftp.pdf PDF description of FTP for NetX Duo
-
demo_netxduo_ftp.c FTP demonstration system
In order to use the NetX Duo FTP API, the entire distribution mentioned previously should be copied to the same directory where NetX Duo is installed. For example, if NetX Duo is installed in the directory "\threadx\arm7\green" then the nxd_ftp_client.h and nxd_ftp_client.c should be copied into this directory for FTP Client applications, and nxd_ftp_server.h and nxd_ftp_server.c files should be copied into this directory for FTP Server applications.
Using the NetX Duo FTP API is easy. Basically, the application code must include either nxd_ftp_client.h for FTP Client applications or nxd_ftp_server for FTP Server applications, after it includes tx_api.h, fx_api.h, and nx_api.h, in order to use ThreadX, FileX, and NetX Duo, respectively. The build project must include the FTP source code and the host application file, and of course the ThreadX and NetX Duo library files. This is all that is required to use NetX Duo FTP.
Note that since FTP utilizes NetX Duo TCP services, TCP must be enabled with the nx_tcp_enable call prior to using FTP.
Note that the NetX Duo library can be enabled for IPv6 and still support IPv4 networks. However, NetX Duo cannot support IPv6 unless it is enabled. To disable IPv6 processing in NetX Duo, the NX_DISABLE_IPV6 must be defined in the nx_user.h file, and that file must be included in the NetX Duo library build by defining NX_INCLUDE_USER_DEFINE_FILE in the nx_port.h file. By default, NX_DISABLE_IPV6 is not defined (IPv6 is enabled). This is different from the nxd_ipv6_enable service that sets up the IPv6 protocols and services on the IP task, and requires NX_DISABLE_IPV6 to be not defined.
An example of how easy it is to use NetX Duo FTP is described below. In this example, both an FTP Server and an FTP Client are created. Therefore both FTP include files nxd_ftp_client.h and nxd_ftp_server.h are brought in at line 10 and 11. Next, the FTP Server is created in “_tx_application_define_” at line 99. Note that the FTP Server and Client control blocks are defined as global variables at line 26 previously.
This demo shows how to use the duo functions available in NetX Duo FTP as well as the legacy IPv4 limited FTP services. To use the IPv6 functions, the demo defines USE_IPV6 in line 16
At line 162 the FTP Server is created with nxd_ftp_server_create if the host application defines USE_IPV6 which supports both IPv4 and IPv6. If it is not, the FTP Server is created with nx_ftp_server_create on line 166 with the IPv4 limited service. Note that the 'duo' function uses different login and logout function arguments than the IPv4 service, both of which are defined at the bottom of the file on lines 534 -568.
The FTP server must then establish its IPv6 address (global and link local) with NetX Duo, starting at line 466 in the FTP server thread entry function. The FTP server is then started on line 518 and is ready for FTP client requests.
The FTP Client is created in line 316 and goes through the same process as the FTP Server to get the FTP Client IP task IPv6 enabled, and its IPv6 addresses validated starting on lines 263-313.
Then the Client connects to the FTP Server using nxd_ftp_client_connect in line 334 if it has defined USE_IPV6, or line 340 if it is using the IPv4 limited service nx_ftp_client_connect. Over the course of the FTP Client thread function, it writes a file to the FTP server and reads it back before disconnecting.
/* This is a small demo of NetX FTP on the high-performance NetX TCP/IP stack. This demo
relies on ThreadX, NetX, and FileX to show a simple file transfer from the client
and then back to the server. */
#include "tx_api.h"
#include "fx_api.h"
#include "nx_api.h"
#include "nxd_ftp_client.h"
#include "nxd_ftp_server.h"
#define DEMO_STACK_SIZE 4096
#ifdef FEATURE_NX_IPV6
#define USE_IPV6
#endif /* FEATURE_NX_IPV6 */
/* Define the ThreadX, NetX, and FileX object control blocks... */
TX_THREAD server_thread;
TX_THREAD client_thread;
NX_PACKET_POOL server_pool;
NX_IP server_ip;
NX_PACKET_POOL client_pool;
NX_IP client_ip;
FX_MEDIA ram_disk;
/* Define the NetX FTP object control blocks. */
NX_FTP_CLIENT ftp_client;
NX_FTP_SERVER ftp_server;
/* Define the counters used in the demo application... */
ULONG error_counter = 0;
/* Define the memory area for the FileX RAM disk. */
UCHAR ram_disk_memory[32000];
UCHAR ram_disk_sector_cache[512];
#define FTP_SERVER_ADDRESS IP_ADDRESS(1,2,3,4)
#define FTP_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5)
extern UINT _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media),
VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
CHAR *volume_name, UINT number_of_fats, UINT directory_entries,
UINT hidden_sectors, ULONG total_sectors, UINT bytes_per_sector,
UINT sectors_per_cluster, UINT heads, UINT sectors_per_track);
/* Define the FileX and NetX driver entry functions. */
VOID _fx_ram_driver(FX_MEDIA *media_ptr);
/* Replace the 'ram' driver with your own Ethernet driver. */
VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
void client_thread_entry(ULONG thread_input);
void thread_server_entry(ULONG thread_input);
#ifdef USE_IPV6
/* Define NetX Duo IP address for the NetX Duo FTP Server and Client. */
NXD_ADDRESS server_ip_address;
NXD_ADDRESS client_ip_address;
endif
/* Define server login/logout functions. These are stubs for functions that would
validate a client login request. */
#ifdef USE_IPV6
UINT server_login6(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address,
UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info);
UINT server_logout6(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address,
UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info);
#else
UINT server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
ULONG client_ip_address, UINT client_port,
CHAR *name, CHAR *password, CHAR *extra_info);
UINT server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
ULONG client_ip_address, UINT client_port,
CHAR *name, CHAR *password, CHAR *extra_info);
#endif
/* Define main entry point. */
int main()
{
/* Enter the ThreadX kernel. */
tx_kernel_enter();
return(0);
}
/* Define what the initial system looks like. */
void tx_application_define(void *first_unused_memory)
{
UINT status;
UCHAR *pointer;
/* Setup the working pointer. */
pointer = (UCHAR *) first_unused_memory;
/* Create a helper thread for the server. */
tx_thread_create(&server_thread, "FTP Server thread", thread_server_entry, 0,
pointer, DEMO_STACK_SIZE,
4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Initialize NetX. */
nx_system_initialize();
/* Create the packet pool for the FTP Server. */
status = nx_packet_pool_create(&server_pool, "NetX Server Packet Pool", 256, pointer, 8192);
pointer = pointer + 8192;
/* Check for errors. */
if (status)
error_counter++;
/* Create the IP instance for the FTP Server. */
status = nx_ip_create(&server_ip, "NetX Server IP Instance", FTP_SERVER_ADDRESS, 0xFFFFFF00UL,
&server_pool, _nx_ram_network_driver, pointer, 2048, 1);
pointer = pointer + 2048;
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Enable ARP and supply ARP cache memory for server IP instance. */
nx_arp_enable(&server_ip, (void *) pointer, 1024);
pointer = pointer + 1024;
/* Enable TCP. */
nx_tcp_enable(&server_ip);
#ifdef USE_IPV6
/* Next set the NetX Duo FTP Server and Client addresses. */
server_ip_address.nxd_ip_address.v6[3] = 0x105;
server_ip_address.nxd_ip_address.v6[2] = 0x0;
server_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
server_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
server_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
client_ip_address.nxd_ip_address.v6[3] = 0x101;
client_ip_address.nxd_ip_address.v6[2] = 0x0;
client_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
client_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
client_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
/* Create the FTP server. */
status = nxd_ftp_server_create(&ftp_server, "FTP Server Instance", &server_ip,
&ram_disk, pointer, DEMO_STACK_SIZE, &server_pool,
server_login6, server_logout6);
#else
/* Create the FTP server. */
status = nx_ftp_server_create(&ftp_server, "FTP Server Instance", &server_ip,
&ram_disk, pointer, DEMO_STACK_SIZE, &server_pool,
server_login, server_logout);
#endif
pointer = pointer + DEMO_STACK_SIZE;
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Now set up the FTP Client. */
/* Create the main FTP client thread. */
status = tx_thread_create(&client_thread, "FTP Client thread ", client_thread_entry, 0,
pointer, DEMO_STACK_SIZE,
6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE ;
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Create a packet pool for the FTP client. */
status = nx_packet_pool_create(&client_pool, "NetX Client Packet Pool", 256, pointer, 8192);
pointer = pointer + 8192;
/* Create an IP instance for the FTP client. */
status = nx_ip_create(&client_ip, "NetX Client IP Instance", FTP_CLIENT_ADDRESS, 0xFFFFFF00UL,
&client_pool, _nx_ram_network_driver, pointer, 2048, 1);
pointer = pointer + 2048;
/* Enable ARP and supply ARP cache memory for the FTP Client IP. */
nx_arp_enable(&client_ip, (void *) pointer, 1024);
pointer = pointer + 1024;
/* Enable TCP for client IP instance. */
nx_tcp_enable(&client_ip);
return;
}
/* Define the FTP client thread. */
void client_thread_entry(ULONG thread_input)
{
NX_PACKET *my_packet;
UINT status;
#ifdef USE_IPV6
UINT iface_index, address_index;
#endif
/* Format the RAM disk - the memory for the RAM disk was defined above. */
status = _fx_media_format(&ram_disk,
_fx_ram_driver, /* Driver entry */
ram_disk_memory, /* RAM disk memory pointer */
ram_disk_sector_cache, /* Media buffer pointer */
sizeof(ram_disk_sector_cache), /* Media buffer size */
"MY_RAM_DISK", /* Volume Name */
1, /* Number of FATs */
32, /* Directory Entries */
0, /* Hidden sectors */
256, /* Total sectors */
128, /* Sector size */
1, /* Sectors per cluster */
1, /* Heads */
1); /* Sectors per track */
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Open the RAM disk. */
status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory,
ram_disk_sector_cache, sizeof(ram_disk_sector_cache));
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Let the IP threads and driver initialize the system. */
tx_thread_sleep(100);
#ifdef USE_IPV6
/* Here's where we make the FTP Client IPv6 enabled. */
status = nxd_ipv6_enable(&client_ip);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
status = nxd_icmp_enable(&client_ip);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Set the Client link local and global addresses. */
iface_index = 0;
/* This assumes we are using the primary network interface (index 0). */
status = nxd_ipv6_address_set(&client_ip, iface_index, NX_NULL, 10, &address_index);
/* Check for link local address set error. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Set the host global IP address. We are assuming a 64
bit prefix here but this can be any value (< 128). */
status = nxd_ipv6_address_set(&client_ip, iface_index, &client_ip_address, 64, &address_index);
/* Check for global address set error. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Let NetX Duo validate the addresses. */
tx_thread_sleep(400);
#endif /* USE_IPV6 */
/* Create an FTP client. */
status = nx_ftp_client_create(&ftp_client, "FTP Client", &client_ip, 2000, &client_pool);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
printf("Created the FTP Client\n");
#ifdef USE_IPV6
do
{
/* Now connect with the NetX Duo FTP (IPv6) server. */
status = nxd_ftp_client_connect(&ftp_client, &server_ip_address, "name", "password", 100);
} while (status != NX_SUCCESS);
#else
/* Now connect with the NetX FTP (IPv4) server. */
status = nx_ftp_client_connect(&ftp_client, FTP_SERVER_ADDRESS, "name", "password", 100);
#endif /* USE_IPV6 */
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
printf("Connected to the FTP Server\n");
/* Open a FTP file for writing. */
status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_WRITE, 100);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
printf("Opened the FTP client test.txt file\n");
/* Allocate a FTP packet. */
status = nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, 100);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Write ABCs into the packet payload! */
memcpy(my_packet -> nx_packet_prepend_ptr, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", 28);
/* Adjust the write pointer. */
my_packet -> nx_packet_length = 28;
my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + 28;
/* Write the packet to the file test.txt. */
status = nx_ftp_client_file_write(&ftp_client, my_packet, 100);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
}
else
printf("Wrote to the FTP client test.txt file\n");
/* Close the file. */
status = nx_ftp_client_file_close(&ftp_client, 100);
/* Check status. */
if (status != NX_SUCCESS)
error_counter++;
else
printf("Closed the FTP client test.txt file\n");
/* Now open the same file for reading. */
status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_READ, 100);
/* Check status. */
if (status != NX_SUCCESS)
error_counter++;
else
printf("Reopened the FTP client test.txt file\n");
/* Read the file. */
status = nx_ftp_client_file_read(&ftp_client, &my_packet, 100);
/* Check status. */
if (status != NX_SUCCESS)
error_counter++;
else
{
printf("Reread the FTP client test.txt file\n");
nx_packet_release(my_packet);
}
/* Close this file. */
status = nx_ftp_client_file_close(&ftp_client, 100);
if (status != NX_SUCCESS)
error_counter++;
/* Disconnect from the server. */
status = nx_ftp_client_disconnect(&ftp_client, 100);
/* Check status. */
if (status != NX_SUCCESS)
error_counter++;
/* Delete the FTP client. */
status = nx_ftp_client_delete(&ftp_client);
/* Check status. */
if (status != NX_SUCCESS)
error_counter++;
}
/* Define the helper FTP server thread. */
void thread_server_entry(ULONG thread_input)
{
UINT status;
#ifdef USE_IPV6
UINT iface_index, address_index;
#endif
/* Wait till the IP thread and driver have initialized the system. */
tx_thread_sleep(100);
#ifdef USE_IPV6
/* Here's where we make the FTP server IPv6 enabled. */
status = nxd_ipv6_enable(&server_ip);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
status = nxd_icmp_enable(&server_ip);
/* Check status. */
if (status != NX_SUCCESS)
{
error_counter++;
return;
}
/* Set the link local address with the host MAC address. */
iface_index = 0;
/* This assumes we are using the primary network interface (index 0). */
status = nxd_ipv6_address_set(&server_ip, iface_index, NX_NULL, 10, &address_index);
/* Check for link local address set error. */
if (status)
{
error_counter++;
return;
}
/* Set the host global IP address. We are assuming a 64
bit prefix here but this can be any value (< 128). */
status = nxd_ipv6_address_set(&server_ip, iface_index, &server_ip_address, 64, &address_index);
/* Check for global address set error. */
if (status)
{
error_counter++;
return;
}
/* Wait while NetX Duo validates the link local and global address. */
tx_thread_sleep(500);
#endif /* USE_IPV6 */
/* OK to start the FTP Server. */
status = nx_ftp_server_start(&ftp_server);
if (status != NX_SUCCESS)
error_counter++;
printf("Server started!\n");
/* FTP server ready to take requests! */
/* Let the IP threads execute. */
tx_thread_relinquish();
return;
}
#ifdef USE_IPV6
UINT server_login6(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr,
NXD_ADDRESS *client_ipduo_address, UINT client_port,
CHAR *name, CHAR *password, CHAR *extra_info)
{
printf("Logged in6!\n");
/* Always return success. */
return(NX_SUCCESS);
}
UINT server_logout6(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address,
UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)
{
printf("Logged out6!\n");
/* Always return success. */
return(NX_SUCCESS);
}
#else
UINT server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address,
UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)
{
printf("Logged in!\n");
/* Always return success. */
return(NX_SUCCESS);
}
UINT server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address,
UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)
{
printf("Logged out!\n");
/* Always return success. */
return(NX_SUCCESS);
}
#endif /* USE_IPV6 */
There are several configuration options for building NetX Duo FTP. The default values are listed, but each define can be set by the application prior to inclusion of the specified NetX Duo FTP header file. If no header file is specified, the option is available in both nxd_ftp_client.h and nxd_ftp_server.h. The following list describes each in detail:
-
NX_FTP_SERVER_PRIORITY The priority of the FTP Server thread. By default, this value is defined as 16 to specify priority 16.
-
NX_FTP_MAX_CLIENTS The maximum number of Clients the Server can handle at one time. By default, this value is 4 to support 4 Clients at once.
-
NX_FTP_SERVER_MIN_PACKET_PAYLOAD The minimum size of the Server packet pool payload in bytes, including TCP, IP and network frame headers plus HTTP data. The default value is 256 (maximum length of filename in FileX) + 12 bytes for file information, and NX_PHYSICAL_TRAILER.
-
NX_FTP_SERVER_TIMEOUT Specifies the number of ThreadX ticks that internal services will suspend for. The default value is set to 1 second (1 * NX_IP_PERIODIC_RATE).
-
NX_FTP_ACTIVITY_TIMEOUT Specifies the number of seconds a Client connection is maintained if there is no activity. The default value is set to 240.
-
NX_FTP_TIMEOUT_PERIOD Specifies the intervals in seconds when the Server checks for Client activity. The default value is set to 60.
-
NX_FTP_SERVER_RETRY_SECONDS Specifies the initial timeout in seconds before retransmitting server response. The default value is 2.
-
NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH Specifies the maximum of depth of queued transmit packets on Server socket. The default value is 20.
-
NX_FTP_SERVER_RETRY_MAX Specifies the maximum retries per packet. The default value is 10.
-
NX_FTP_SERVER_RETRY_SHIFT Specifies the number of bits to shift in setting the retry timeout. The default value is 2, e.g. every retry timeout is twice as long as the previous retry.
-
NX_FTP_NO_FILEX Defined, this option provides a stub for FileX dependencies. The FTP Client will function without any change if this option is defined. The FTP Server will need to either be modified or the user will have to create a handful of FileX services in order to function properly.
-
NX_FTP_CONTROL_TOS Type of service required for the FTP control requests. By default, this value is defined as NX_IP_NORMAL to indicate normal IP packet service.
-
NX_FTP_DATA_TOS Type of service required for the FTP data requests. By default, this value is defined as NX_IP_NORMAL to indicate normal IP packet service.
-
NX_FTP_FRAGMENT_OPTION Fragment enable for FTP requests. By default, this value is NX_DONT_FRAGMENT to disable FTP TCP fragmenting.
-
NX_FTP_CONTROL_WINDOW_SIZE TCP Control socket window size. By default, this value is 400 bytes.
-
NX_FTP_DATA_WINDOW_SIZE TCP Data socket window size. By default, this value is 2048 bytes.
-
NX_FTP_TIME_TO_LIVE Specifies the number of routers this packet can pass before it is discarded. The default value is set to 0x80.
-
NX_FTP_USERNAME_SIZE Specifies the number of bytes allowed in a Client supplied username. The default value is set to 20 .
-
NX_FTP_PASSWORD_SIZE Specifies the number of bytes allowed in a client supplied password. The default value is set to 20.