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