1 /* This test checks for the Telnet Server to negotiate with a Telnet Client for three common
2    Telnet options.  It offers to ECHO, Suppress Go Ahead and asks the peer not to ECHO (Don't Echo).
3    The Telnet Client is programmed to acknowledge the ECHO and SGA, and Won't Echo.
4 
5    Required configuration settings:
6 
7    NX_TELNET_SERVER_OPTION_DISABLE not defined
8    NX_TELNET_SERVER_USER_CREATE_PACKET_POOL  defined
9 */
10 
11 #include  "tx_api.h"
12 #include  "nx_api.h"
13 
14 
15 extern void    test_control_return(UINT);
16 
17 #if defined(NX_TELNET_SERVER_USER_CREATE_PACKET_POOL) && !defined(NX_DISABLE_IPV4)
18 
19 #include  "nxd_telnet_client.h"
20 #include  "nxd_telnet_server.h"
21 
22 
23 #define     DEMO_STACK_SIZE         4096
24 
25 
26 /* Define the ThreadX and NetX object control blocks...  */
27 
28 static TX_THREAD               server_thread;
29 static TX_THREAD               client_thread;
30 static NX_PACKET_POOL          pool_server;
31 static NX_PACKET_POOL          pool_client;
32 static NX_IP                   ip_server;
33 static NX_IP                   ip_client;
34 
35 
36 /* Define TELNET server object.  */
37 
38 static NX_TELNET_SERVER        my_server;
39 static NX_TELNET_CLIENT        my_client;
40 
41 #define         SERVER_ADDRESS          IP_ADDRESS(1,2,3,4)
42 #define         CLIENT_ADDRESS          IP_ADDRESS(1,2,3,5)
43 
44 
45 
46 /* Define the counters and flags used in the demo application...  */
47 
48 static ULONG                   error_counter;
49 static UINT                    server_option_negotiation;
50 
51 /* Define timeout in ticks for connecting and sending/receiving data. */
52 
53 #define                        TELNET_TIMEOUT  200
54 
55 
56 void    thread_server_entry(ULONG thread_input);
57 void    thread_client_entry(ULONG thread_input);
58 
59 extern void    _nx_ram_network_driver_512(struct NX_IP_DRIVER_STRUCT *driver_req);
60 
61 static UCHAR                   send_buff[256];
62 
63 /* Define the application's TELNET Server callback routines.  */
64 
65 void    telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection);
66 void    telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr);
67 void    telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection);
68 
69 
70 
71 /* Define what the initial system looks like.  */
72 #ifdef CTEST
test_application_define(void * first_unused_memory)73 VOID test_application_define(void *first_unused_memory)
74 #else
75 void    netx_telnet_server_options_negotiate_test_application_define(void *first_unused_memory)
76 #endif
77 {
78 
79 UINT    status;
80 CHAR    *pointer;
81 
82     error_counter = 0;
83 
84     /* Setup the working pointer.  */
85     pointer =  (CHAR *) first_unused_memory;
86 
87     /* Create the server thread.  */
88     status = tx_thread_create(&server_thread, "Telnet Server thread", thread_server_entry, 0,
89             pointer, DEMO_STACK_SIZE,
90             12, 12, TX_NO_TIME_SLICE, TX_AUTO_START);
91     pointer =  pointer + DEMO_STACK_SIZE;
92 
93 
94     if (status)
95     {
96         printf("Error creating Server thread 0x%x\n", status);
97     }
98 
99     /* Initialize the NetX system.  */
100     nx_system_initialize();
101 
102     /* Create the server packet pool.  */
103     nx_packet_pool_create(&pool_server, "Server NetX Packet Pool", 600, pointer, 8192);
104     pointer = pointer + 8192;
105 
106     /* Create the Server IP instance.  */
107     nx_ip_create(&ip_server, "Server NetX IP Instance", SERVER_ADDRESS,
108                         0xFFFFFF00UL, &pool_server, _nx_ram_network_driver_512,
109                         pointer, 4096, 1);
110 
111     pointer =  pointer + 4096;
112 
113 
114     /* Enable ARP and supply ARP cache memory for the server.  */
115     nx_arp_enable(&ip_server, (void *) pointer, 1024);
116     pointer = pointer + 1024;
117 
118     /* Enable TCP processing for both IP instances.  */
119     nx_tcp_enable(&ip_server);
120     nx_icmp_enable(&ip_server);
121 
122 
123     /* Create the NetX Duo TELNET Server.  */
124     status =  nx_telnet_server_create(&my_server, "Telnet Server", &ip_server,
125                     pointer, 2048, telnet_new_connection, telnet_receive_data,
126                     telnet_connection_end);
127 
128     /* Check for errors.  */
129     if (status)
130         error_counter++;
131 
132 
133     pointer = pointer + 2048;
134 
135     /* Create the Client thread.  */
136     status = tx_thread_create(&client_thread, "Telnet Client thread", thread_client_entry, 0,
137             pointer, DEMO_STACK_SIZE,
138             12, 12, TX_NO_TIME_SLICE, TX_AUTO_START);
139 
140     if (status)
141     {
142         error_counter++;
143     }
144 
145     pointer =  pointer + DEMO_STACK_SIZE;
146 
147     /* Create the client packet pool.  */
148     status = nx_packet_pool_create(&pool_client, "Client NetX Packet Pool", 600, pointer, 8192);
149     if (status)
150     {
151         error_counter++;
152     }
153     pointer = pointer + 8192;
154 
155     /* Create the Client IP instance.  */
156     status = nx_ip_create(&ip_client, "Client NetX IP Instance", CLIENT_ADDRESS,
157                         0xFFFFFF00UL, &pool_client, _nx_ram_network_driver_512,
158                         pointer, 4096, 1);
159     if (status)
160     {
161         error_counter++;
162     }
163 
164     pointer =  pointer + 4096;
165 
166     /* Enable ARP and supply ARP cache memory for the client.  */
167     nx_arp_enable(&ip_client, (void *) pointer, 1024);
168     pointer = pointer + 1024;
169 
170     /* Enable TCP and ICMP processing for client IP instance.  */
171     nx_tcp_enable(&ip_client);
172     nx_icmp_enable(&ip_client);
173 
174 
175     return;
176 }
177 
thread_client_entry(ULONG thread_input)178 void    thread_client_entry(ULONG thread_input)
179 {
180 
181 UINT status;
182 NX_PACKET *my_packet, *my_packet2, *rcv_packet;
183 
184     tx_thread_sleep(100);
185 
186     /* Create a TELENT client instance.  */
187     status =  nx_telnet_client_create(&my_client, "TELNET Client", &ip_client, 6 * NX_IP_PERIODIC_RATE);
188     if (status)
189         error_counter++;
190 
191     /* Connect the TELNET client to the TELNET Server at port 23 over IPv4.  */
192     status =  nx_telnet_client_connect(&my_client, SERVER_ADDRESS, NX_TELNET_SERVER_PORT, 200);
193     if (status)
194         error_counter++;
195 
196 
197     /* This should be the welcome message. */
198     status =  nx_telnet_client_packet_receive(&my_client, &rcv_packet, TELNET_TIMEOUT);
199 
200     if (status)
201         error_counter++;
202 
203     /* To do verify this is just a hello message. */
204 
205     nx_packet_release(rcv_packet);
206 
207     /* Server should be negotiating options. */
208     status =  nx_telnet_client_packet_receive(&my_client, &rcv_packet, TELNET_TIMEOUT);
209 
210     if (status)
211         error_counter++;
212 
213     /* Parse the options. Should be will echo don't echo and will suppress go ahead */
214 
215     nx_packet_release(rcv_packet);
216 
217     /* Prepare a Do ECHO reply */
218     send_buff[0] = 0xFF;
219     send_buff[1] = 0xFD;
220     send_buff[2] = 0x01;
221 
222     /* Allocate a packet.  */
223     status =  nx_packet_allocate(&pool_client, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
224     if (status)
225         error_counter++;
226 
227     /* Build a simple 1-byte message.  */
228     nx_packet_data_append(my_packet, send_buff, sizeof(send_buff), &pool_client, NX_WAIT_FOREVER);
229 
230     /* Send the packet to the TELNET Server.  */
231     status =  nx_telnet_client_packet_send(&my_client, my_packet, TELNET_TIMEOUT);
232     if (status)
233         error_counter++;
234 
235     /* Prepare a second reply: WONT ECHO, DO SUPPRESS GO AHEAD */
236     send_buff[0] = 0xFF;
237     send_buff[1] = 0xFC;
238     send_buff[2] = 0x01;
239     send_buff[0] = 0xFF;
240     send_buff[1] = 0xFD;
241     send_buff[2] = 0x03;
242 
243     /* Allocate a packet.  */
244     status =  nx_packet_allocate(&pool_client, &my_packet2, NX_TCP_PACKET, NX_WAIT_FOREVER);
245     if (status)
246         error_counter++;
247 
248     /* Load the reply in to the packet.  */
249     nx_packet_data_append(my_packet2, send_buff, sizeof(send_buff), &pool_client, NX_WAIT_FOREVER);
250 
251     /* Send the packet to the TELNET Server.  */
252     status =  nx_telnet_client_packet_send(&my_client, my_packet2, TELNET_TIMEOUT);
253     if (status)
254         error_counter++;
255 
256     tx_thread_sleep(200);
257 
258     /* Now disconnect form the TELNET Server.  */
259     nx_telnet_client_disconnect(&my_client, 100);
260 
261     /* Delete the TELNET Client.  */
262     status =  nx_telnet_client_delete(&my_client);
263     if (status)
264         error_counter++;
265 
266 }
267 
268 /* Define the Telnet Server thread.  */
thread_server_entry(ULONG thread_input)269 void    thread_server_entry(ULONG thread_input)
270 {
271 
272 UINT        status;
273 
274 
275     tx_thread_sleep(20);
276 
277     /* Print out test information banner.  */
278     printf("NetX Test:   Telnet Server Negotiation Test............................");
279 
280     /* Check for earlier error. */
281     if(error_counter)
282     {
283         printf("ERROR!\n");
284         test_control_return(1);
285     }
286 
287     /* We have defined the NX_TELNET_CREATE_PACKET_POOL option for sending
288        Telnet options (not disabled). So set the telnet packet pool. */
289     status = nx_telnet_server_packet_pool_set(&my_server, &pool_server);
290 
291     if (status != NX_SUCCESS)
292     {
293         error_counter++;
294     }
295 
296     server_option_negotiation = NX_FALSE;
297 
298     /* Start the TELNET Server.  */
299     status =  nx_telnet_server_start(&my_server);
300 
301     /* Check for errors.  */
302     if (status != NX_SUCCESS)
303     {
304         error_counter++;
305     }
306 
307     do
308     {
309         /* Check on the result of optio negotiations while the client connection is live. */
310 
311         NX_TELNET_CLIENT_REQUEST *client_req_ptr = &(my_server.nx_telnet_server_client_list[0]);
312         if ((client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success == NX_TRUE) &&
313             (client_req_ptr -> nx_telnet_client_agree_server_will_echo_success == NX_TRUE))
314         {
315             /* negotiation successful. */
316             server_option_negotiation = NX_TRUE;
317         }
318 
319         tx_thread_sleep(100);
320     }while (my_server.nx_telnet_server_open_connections == 1);
321 
322     status =  nx_telnet_server_stop(&my_server);
323 
324     /* Check for errors.  */
325     if (status != NX_SUCCESS)
326     {
327         error_counter++;
328 
329     }
330 
331     if (error_counter || !server_option_negotiation)
332     {
333 
334         printf("ERROR!\n");
335         test_control_return(1);
336     }
337     else
338 
339     {
340 
341         printf("SUCCESS!\n");
342         test_control_return(0);
343     }
344 
345     return;
346 }
347 
348 
349 /* This routine is called by the NetX Telnet Server whenever a new Telnet client
350    connection is established.  */
telnet_new_connection(NX_TELNET_SERVER * server_ptr,UINT logical_connection)351 void  telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection)
352 {
353 
354 UINT        status;
355 NX_PACKET   *packet_ptr;
356 
357 
358     /* Allocate a packet for client greeting. */
359     status =  nx_packet_allocate(&pool_server, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT);
360 
361     if (status != NX_SUCCESS)
362     {
363         error_counter++;
364         return;
365     }
366 
367     if (pool_server.nx_packet_pool_available < 2)
368     {
369         printf("Packet pool getting low...\n");
370     }
371     /* Build a banner message and a prompt.  */
372     nx_packet_data_append(packet_ptr, "**** Welcome to NetX TELNET Server ****\r\n\r\n\r\n", 45, &pool_server, NX_NO_WAIT);
373 
374     /* Send the packet to the client.  */
375     status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
376 
377     if (status != NX_SUCCESS)
378     {
379         error_counter++;
380         nx_packet_release(packet_ptr);
381     }
382 
383     return;
384 }
385 
386 
387 /* This routine is called by the NetX Telnet Server whenever data is present on a Telnet client
388    connection.  */
telnet_receive_data(NX_TELNET_SERVER * server_ptr,UINT logical_connection,NX_PACKET * packet_ptr)389 void  telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr)
390 {
391 
392 UINT    status;
393 UCHAR   alpha;
394 
395 
396 
397     /* This demo just echoes the character back and on <cr,lf> sends a new prompt back to the
398        client.  A real system would most likely buffer the character(s) received in a buffer
399        associated with the supplied logical connection and process according to it.  */
400 
401 
402     /* Just throw away carriage returns.  */
403     if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\r') && (packet_ptr -> nx_packet_length == 1))
404     {
405         nx_packet_release(packet_ptr);
406         return;
407     }
408 
409 
410     /* Setup new line on line feed.  */
411     if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\n') || (packet_ptr -> nx_packet_prepend_ptr[1] == '\n'))
412     {
413 
414         /* Clean up the packet.  */
415         packet_ptr -> nx_packet_length =  0;
416         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
417         packet_ptr -> nx_packet_append_ptr =   packet_ptr -> nx_packet_data_start + NX_TCP_PACKET;
418 
419         /* Build the next prompt.  */
420         nx_packet_data_append(packet_ptr, "\r\nNETX> ", 8, &pool_server, NX_NO_WAIT);
421 
422         /* Send the packet to the client.  */
423         status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
424 
425         if (status)
426         {
427             nx_packet_release(packet_ptr);
428             error_counter++;
429         }
430 
431         return;
432     }
433 
434     /* Pickup first character (usually only one from client).  */
435     alpha =  packet_ptr -> nx_packet_prepend_ptr[0];
436 
437     /* Echo character.  */
438     status =  nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT);
439 
440     if (status != NX_SUCCESS)
441     {
442         error_counter++;
443         nx_packet_release(packet_ptr);
444     }
445 
446     /* Check for a disconnection.  */
447     if (alpha == 'q')
448     {
449 
450         /* Initiate server disconnection.  */
451         nx_telnet_server_disconnect(server_ptr, logical_connection);
452     }
453 }
454 
455 
456 /* This routine is called by the NetX Telnet Server whenever the client disconnects.  */
telnet_connection_end(NX_TELNET_SERVER * server_ptr,UINT logical_connection)457 void  telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection)
458 {
459 
460     /* Cleanup any application specific connection or buffer information.  */
461 }
462 
463 #else /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */
464 
465 #ifdef CTEST
test_application_define(void * first_unused_memory)466 VOID test_application_define(void *first_unused_memory)
467 #else
468 void    netx_telnet_server_options_negotiate_test_application_define(void *first_unused_memory)
469 #endif
470 {
471     printf("NetX Test:   Telnet Server Negotiation Test............................N/A\n");
472     test_control_return(3);
473 }
474 #endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */
475 
476