1 /* This is a small demo of the NetX HTTP Client Server API running on a
2    high-performance NetX TCP/IP stack.  */
3 
4 #include   "tx_api.h"
5 #include   "nx_api.h"
6 /* If not using FileX, define this option and define the file writing services
7    declared in filex_stub.h.
8 #define      NX_HTTP_NO_FILEX
9 */
10 #ifndef      NX_HTTP_NO_FILEX
11 #include    "fx_api.h"
12 #else
13 #include    "filex_stub.h"
14 #endif
15 #include   "nxd_http_client.h"
16 #include   "nxd_http_server.h"
17 
18 /* For NetX Duo applications, determine which IP version to use. For IPv6,
19    set IP_TYPE to 6; for IPv4 set to 4. Note that for IPv6, you must enable
20    USE_DUO so the application 'knows' to enabled IPv6 services on the IP task.  */
21 
22 #ifdef NX_DISABLE_IPV4
23 #define     IP_TYPE     6
24 #else
25 #define     IP_TYPE     4
26 #endif /* NX_DISABLE_IPV4 */
27 
28 
29 #define     DEMO_STACK_SIZE         4096
30 
31 
32 /* Set up FileX and file memory resources. */
33 UCHAR           ram_disk_memory[32000];
34 FX_MEDIA        ram_disk;
35 unsigned char   media_memory[512];
36 
37 
38 /* Define device drivers.  */
39 extern void _fx_ram_driver(FX_MEDIA *media_ptr);
40 
41 /* Replace the 'ram' driver with your Ethernet driver. */
42 VOID        _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
43 
44 UINT        authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type,
45                                  CHAR *resource, CHAR **name, CHAR **password, CHAR **realm);
46 
47 /* Set up the HTTP client global variables. */
48 
49 TX_THREAD       client_thread;
50 NX_PACKET_POOL  client_pool;
51 NX_HTTP_CLIENT  my_client;
52 NX_IP           client_ip;
53 #define         CLIENT_PACKET_SIZE  (NX_HTTP_SERVER_MIN_PACKET_SIZE * 2)
54 
55 
56 /* Set up the HTTP server global variables */
57 
58 NX_HTTP_SERVER  my_server;
59 NX_PACKET_POOL  server_pool;
60 TX_THREAD       server_thread;
61 NX_IP           server_ip;
62 NXD_ADDRESS     server_ip_address;
63 #define         SERVER_PACKET_SIZE  (NX_HTTP_SERVER_MIN_PACKET_SIZE * 2)
64 
65 void            thread_client_entry(ULONG thread_input);
66 void            thread_server_entry(ULONG thread_input);
67 
68 #define HTTP_SERVER_ADDRESS  IP_ADDRESS(1,2,3,4)
69 #define HTTP_CLIENT_ADDRESS  IP_ADDRESS(1,2,3,5)
70 
71 
72 /* Define the application's authentication check.  This is called by
73    the HTTP server whenever a new request is received.  */
authentication_check(NX_HTTP_SERVER * server_ptr,UINT request_type,CHAR * resource,CHAR ** name,CHAR ** password,CHAR ** realm)74 UINT  authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type,
75             CHAR *resource, CHAR **name, CHAR **password, CHAR **realm)
76 {
77     NX_PARAMETER_NOT_USED(server_ptr);
78     NX_PARAMETER_NOT_USED(request_type);
79     NX_PARAMETER_NOT_USED(resource);
80 
81     /* Just use a simple name, password, and realm for all
82        requests and resources.  */
83     *name =     "name";
84     *password = "password";
85     *realm =    "NetX Duo HTTP demo";
86 
87     /* Request basic authentication.  */
88     return(NX_HTTP_BASIC_AUTHENTICATE);
89 }
90 
91 /* Define main entry point.  */
92 
main()93 int main()
94 {
95 
96     /* Enter the ThreadX kernel.  */
97     tx_kernel_enter();
98 }
99 
100 
101 /* Define what the initial system looks like.  */
tx_application_define(void * first_unused_memory)102 void    tx_application_define(void *first_unused_memory)
103 {
104 
105 CHAR    *pointer;
106 UINT    status;
107 
108 
109     /* Setup the working pointer.  */
110     pointer =  (CHAR *) first_unused_memory;
111 
112     /* Create a helper thread for the server. */
113     tx_thread_create(&server_thread, "HTTP Server thread", thread_server_entry, 0,
114                      pointer, DEMO_STACK_SIZE,
115                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
116 
117     pointer =  pointer + DEMO_STACK_SIZE;
118 
119     /* Initialize the NetX system.  */
120     nx_system_initialize();
121 
122     /* Create the server packet pool.  */
123     status =  nx_packet_pool_create(&server_pool, "HTTP Server Packet Pool", SERVER_PACKET_SIZE,
124                                     pointer, SERVER_PACKET_SIZE*4);
125 
126     pointer = pointer + SERVER_PACKET_SIZE * 4;
127 
128     /* Check for pool creation error.  */
129     if (status)
130     {
131 
132         return;
133     }
134 
135     /* Create an IP instance.  */
136     status = nx_ip_create(&server_ip, "HTTP Server IP", HTTP_SERVER_ADDRESS,
137                           0xFFFFFF00UL, &server_pool, _nx_ram_network_driver,
138                           pointer, 4096, 1);
139 
140     pointer =  pointer + 4096;
141 
142     /* Check for IP create errors.  */
143     if (status)
144     {
145         return;
146     }
147 
148 #ifndef NX_DISABLE_IPV4
149     /* Enable ARP and supply ARP cache memory for the server IP instance.  */
150     status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
151     pointer = pointer + 1024;
152 
153     /* Check for ARP enable errors.  */
154     if (status)
155     {
156         return;
157     }
158 #endif /* NX_DISABLE_IPV4  */
159 
160      /* Enable TCP traffic.  */
161     status = nx_tcp_enable(&server_ip);
162 
163     if (status)
164     {
165         return;
166     }
167 #if (IP_TYPE==6)
168 
169     /* Set up the server's IPv6 address here. */
170     server_ip_address.nxd_ip_address.v6[3] = 0x105;
171     server_ip_address.nxd_ip_address.v6[2] = 0x0;
172     server_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
173     server_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
174     server_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
175 #else
176 
177     /* Set up the server's IPv4 address here. */
178     server_ip_address.nxd_ip_address.v4 = HTTP_SERVER_ADDRESS;
179     server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
180 
181 #endif /* (IP_TYPE==6) */
182 
183     /* Create the HTTP Server.  */
184     status = nx_http_server_create(&my_server, "My HTTP Server", &server_ip, &ram_disk,
185                           pointer, 2048, &server_pool, authentication_check, NX_NULL);
186     if (status)
187     {
188         return;
189     }
190 
191     pointer =  pointer + 2048;
192 
193     /* Create the HTTP Client thread. */
194     status = tx_thread_create(&client_thread, "HTTP Client", thread_client_entry, 0,
195                      pointer, DEMO_STACK_SIZE,
196                      6, 6, TX_NO_TIME_SLICE, TX_AUTO_START);
197 
198     pointer =  pointer + DEMO_STACK_SIZE;
199 
200     /* Check for thread create error.  */
201     if (status)
202     {
203 
204         return;
205     }
206 
207     /* Create the Client packet pool.  */
208     status =  nx_packet_pool_create(&client_pool, "HTTP Client Packet Pool", SERVER_PACKET_SIZE,
209                                     pointer, SERVER_PACKET_SIZE*4);
210 
211     pointer = pointer + SERVER_PACKET_SIZE * 4;
212 
213     /* Check for pool creation error.  */
214     if (status)
215     {
216 
217         return;
218     }
219 
220 
221     /* Create an IP instance.  */
222     status = nx_ip_create(&client_ip, "HTTP Client IP", HTTP_CLIENT_ADDRESS,
223                           0xFFFFFF00UL, &client_pool, _nx_ram_network_driver,
224                           pointer, 2048, 1);
225 
226     pointer =  pointer + 2048;
227 
228     /* Check for IP create errors.  */
229     if (status)
230     {
231         return;
232     }
233 
234 #ifndef NX_DISABLE_IPV4
235     /* Enable ARP and supply ARP cache memory for the client IP instance.  */
236     status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
237     pointer =  pointer + 2048;
238 
239     /* Check for ARP enable errors.  */
240     if (status)
241     {
242         return;
243     }
244 #endif /* NX_DISABLE_IPV4  */
245 
246      /* Enable TCP traffic.  */
247     status = nx_tcp_enable(&client_ip);
248 
249     return;
250 }
251 
252 
thread_client_entry(ULONG thread_input)253 VOID thread_client_entry(ULONG thread_input)
254 {
255 
256 UINT            status;
257 NX_PACKET       *my_packet;
258 #if (IP_TYPE == 6)
259 UINT           iface_index;
260 UINT           address_index;
261 NXD_ADDRESS    client_ip_address;
262 #endif
263 
264     NX_PARAMETER_NOT_USED(thread_input);
265 
266     /* Format the RAM disk - the memory for the RAM disk was setup in
267       tx_application_define above.  This must be set up before the client(s) start
268       sending requests. */
269     status = fx_media_format(&ram_disk,
270                              _fx_ram_driver,         /* Driver entry               */
271                              ram_disk_memory,        /* RAM disk memory pointer    */
272                              media_memory,           /* Media buffer pointer       */
273                              sizeof(media_memory),   /* Media buffer size          */
274                              "MY_RAM_DISK",          /* Volume Name                */
275                              1,                      /* Number of FATs             */
276                              32,                     /* Directory Entries          */
277                              0,                      /* Hidden sectors             */
278                              256,                    /* Total sectors              */
279                              128,                    /* Sector size                */
280                              1,                      /* Sectors per cluster        */
281                              1,                      /* Heads                      */
282                              1);                     /* Sectors per track          */
283 
284     /* Check the media format status.  */
285     if (status != FX_SUCCESS)
286     {
287 
288         /* Error, bail out.  */
289         return ;
290     }
291 
292     /* Open the RAM disk.  */
293     status =  fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, media_memory, sizeof(media_memory));
294 
295     /* Check the media open status.  */
296     if (status != FX_SUCCESS)
297     {
298 
299         /* Error, bail out.  */
300         return ;
301     }
302 
303     /* Give IP task and driver a chance to initialize the system. */
304     tx_thread_sleep(NX_IP_PERIODIC_RATE);
305 
306     /* Create an HTTP client instance.  */
307     status = nx_http_client_create(&my_client, "HTTP Client", &client_ip, &client_pool, 600);
308 
309     /* Check status.  */
310     if (status != NX_SUCCESS)
311     {
312         return;
313     }
314 
315 
316 #if (IP_TYPE == 6)
317 
318     /* Set up the client IPv6 address here. */
319     client_ip_address.nxd_ip_address.v6[3] = 0x101;
320     client_ip_address.nxd_ip_address.v6[2] = 0x0;
321     client_ip_address.nxd_ip_address.v6[1] = 0x0000f101;
322     client_ip_address.nxd_ip_address.v6[0] = 0x20010db8;
323     client_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
324 
325     /* Enable ICMPv6 services for the Client. */
326     status = nxd_icmp_enable(&client_ip);
327     if (status != NX_SUCCESS)
328     {
329         return;
330     }
331 
332     /* Enable IPv6 services for the Client. */
333     status = nxd_ipv6_enable(&client_ip);
334     if (status != NX_SUCCESS)
335     {
336         return;
337     }
338 
339 
340     /* Register the Client link local and global IPv6 address with NetX Duo. */
341 
342     /* This assumes we are using the Server primary interface. See the NetX Duo
343        User Guide for more information on address configuration. */
344 
345     /* This assumes we are using the Client primary interface. See the NetX Duo
346        User Guide for more information on address configuration. */
347 
348     iface_index = 0;
349     status = nxd_ipv6_address_set(&client_ip, iface_index, NX_NULL, 10, &address_index);
350     status += nxd_ipv6_address_set(&client_ip, iface_index, &client_ip_address, 64, &address_index);
351 
352 
353     if (status != NX_SUCCESS)
354     {
355         return;
356     }
357 
358     /* Wait for DAD to validate Client addresses. */
359     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
360 
361 #endif /* (IP_TYPE == 6) */
362 
363 
364     /* Now upload an HTML file to the HTTP IP server using the 'duo' service (supports IPv4 and IPv6). */
365     status =  nxd_http_client_put_start(&my_client, &server_ip_address, "/client_test.htm",
366                                             "name", "password", 112, 5 * NX_IP_PERIODIC_RATE);
367 
368     /* Check status.  */
369     if (status != NX_SUCCESS)
370     {
371         tx_thread_sleep(NX_IP_PERIODIC_RATE);
372     }
373 
374 
375     /* Allocate a packet.  */
376     status =  nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
377 
378     /* Check status.  */
379     if (status != NX_SUCCESS)
380     {
381         return;
382     }
383 
384     /* Build a simple 103-byte HTML page.  */
385     nx_packet_data_append(my_packet, "<HTML>\r\n", 8,
386                         &client_pool, NX_WAIT_FOREVER);
387     nx_packet_data_append(my_packet,
388                  "<HEAD><TITLE>NetX HTTP Test</TITLE></HEAD>\r\n", 44,
389                         &client_pool, NX_WAIT_FOREVER);
390     nx_packet_data_append(my_packet, "<BODY>\r\n", 8,
391                         &client_pool, NX_WAIT_FOREVER);
392     nx_packet_data_append(my_packet, "<H1>Another NetX Test Page!</H1>\r\n", 34,
393                         &client_pool, NX_WAIT_FOREVER);
394     nx_packet_data_append(my_packet, "</BODY>\r\n", 9,
395                         &client_pool, NX_WAIT_FOREVER);
396     nx_packet_data_append(my_packet, "</HTML>\r\n", 9,
397                         &client_pool, NX_WAIT_FOREVER);
398 
399     /* Complete the PUT by writing the total length.  */
400     status =  nx_http_client_put_packet(&my_client, my_packet, 50);
401 
402     /* Check status.  */
403     if (status != NX_SUCCESS)
404     {
405         return;
406     }
407 
408     /* Now GET the test file  */
409 
410 
411     /* Use the 'duo' service to send a GET request to the server (can use IPv4 or IPv6 addresses). */
412     status =  nxd_http_client_get_start(&my_client, &server_ip_address,
413                                             "/client_test.htm", NX_NULL, 0, "name", "password", 50);
414 
415     /* Check status.  */
416     if (status != NX_SUCCESS)
417     {
418         return;
419     }
420 
421     status = nx_http_client_delete(&my_client);
422 
423     return;
424 
425 }
426 
427 
428 /* Define the helper HTTP server thread.  */
thread_server_entry(ULONG thread_input)429 void    thread_server_entry(ULONG thread_input)
430 {
431 
432 UINT            status;
433 #if (IP_TYPE == 6)
434 UINT           iface_index;
435 UINT           address_index;
436 #endif
437 
438     NX_PARAMETER_NOT_USED(thread_input);
439 
440     /* Give NetX a chance to initialize the system. */
441     tx_thread_sleep(NX_IP_PERIODIC_RATE);
442 
443 #if (IP_TYPE == 6)
444 
445     /* Here's where we make the HTTP server IPv6 enabled. */
446 
447     /* Enable ICMPv6 services for the Server. */
448     status = nxd_icmp_enable(&server_ip);
449     if (status != NX_SUCCESS)
450     {
451         return;
452     }
453 
454     /* Enable IPv6 services for the Server. */
455     status = nxd_ipv6_enable(&server_ip);
456     if (status != NX_SUCCESS)
457     {
458         return;
459     }
460 
461 
462     /* Register the Server link local and global IPv6 address with NetX Duo. */
463 
464     /* This assumes we are using the Server primary interface. See the NetX Duo
465        User Guide for more information on address configuration. */
466 
467 
468 
469     iface_index = 0;
470     status = nxd_ipv6_address_set(&server_ip, iface_index, NX_NULL, 10, &address_index);
471     status += nxd_ipv6_address_set(&server_ip, iface_index, &server_ip_address, 64, &address_index);
472 
473 
474     if (status != NX_SUCCESS)
475     {
476         return;
477     }
478 
479     /* Wait for DAD to validate Server address. */
480     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
481 
482 
483 #endif  /* (IP_TYPE == 6) */
484 
485     /* OK to start the HTTP Server.   */
486     status = nx_http_server_start(&my_server);
487 
488     if (status != NX_SUCCESS)
489     {
490         return;
491     }
492 
493     /* HTTP server ready to take requests! */
494 
495     /* Let the IP thread execute.    */
496     tx_thread_sleep(NX_IP_PERIODIC_RATE);
497 
498     return;
499 }
500 
501 
502 
503