2 * Copyright (C) 2012-2013 Czech Technical University in Prague
4 * Created on: Aug 9, 2013
9 * This document contains proprietary information belonging to Czech
10 * Technical University in Prague. Passing on and copying of this
11 * document, and communication of its contents is not permitted
12 * without prior written authorization.
17 * This file contains commands for LwIP test
31 #include "lwip/api.h" //netconn
33 #include "lwip/timers.h" //for updating timers, when NO_SYS == 1
35 #include "lwip/tcp_impl.h"
38 #define INTERFACE_INSTANCE_NUMBER 0
41 /* only for use in interactive mode (not thread) */
42 char in_buffer[BUF_SIZE];
43 uint8_t buff_index = 0;
45 /* when -p option not given, srcPort is used; when nc run repeatedly,
46 * even though netconn was removed, netconn_new() with previously used port
47 * might still cause errors like address in use, therefore in srcPort
48 * there next port NO prepared to be used */
49 uint16_t srcPort = 1025; /* initial value */
52 uint8_t tasks_running = 0, taskNameNum = 0;
53 boolean_t closeths; /* variable controling threads closing */
55 /* argument storing parameters from command line, if started as thread, they are coppied to stack of thread and cmd_do_init_nc() is acknowledged by semaphore */
57 uint16_t portNO, srcPortNO;
59 xSemaphoreHandle args_coppied;
60 boolean_t thread; /* variable controling whether this instance should run as thread */
61 boolean_t udp, listen, netLoop, test, srcPortSpec;
67 void run_nc(void *arg)
74 struct netconn *netconn, *newconn;
77 struct netbuf *remoteData = NULL, *localData = NULL;
79 boolean_t ncStop = FALSE;
80 boolean_t flush = FALSE;
81 struct nc_arg *nc_arg = (struct nc_arg *)arg;
82 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
84 /* fill options from argument */
85 uint16_t portNO = nc_arg->portNO, srcPortNO = nc_arg->srcPortNO;
86 ip_addr_t remoteIP = nc_arg->remoteIP;
87 boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
88 boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
90 uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
95 /* switch off closing of tasks/threads */
99 /*** make connection ***/
100 while (!closeths) { /* shouldn't get here twice, used only for break which leads us down to unalocating of sources */
101 /* let nc initiator go */
102 if (thread && /* just in case --> */ nc_arg->args_coppied != NULL && xSemaphoreGive(nc_arg->args_coppied) != pdTRUE) break;
103 /* fill netconn struct */
104 netconn = netconn_new(udp ? NETCONN_UDP : NETCONN_TCP);
105 if (netconn == NULL) {
106 err = ERR_NETCONN_NEW;
110 tries = 15; /* how many local ports to try */
111 /* bind filled netconn with local interface address and source port number */
112 while ( tries-- && (err = netconn_bind(netconn, &(netif->ip_addr), srcPortNO) ) == ERR_USE && !closeths) {
113 if (srcPortSpec) break; /* if port was explicitly specified (we shouldn't change user's port number just like that ;) ) */
117 if (err != ERR_OK || !tries) {
118 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
123 /* adjust recvtimeout time and tries to different values, if user shouldn't loose control over cmd processor at any time */
124 netconn_set_recvtimeout(netconn, CONNECTING_TIMEO);
125 tries = CONNECTING_TRIES;
127 if (listen) { /* -l <PORT> option */
128 if (!udp) { /* TCP - make connection */
129 /* make listening netconn */
130 netconn_listen(netconn);
131 /* accept connection to newconn */
132 while ( tries-- && (err = netconn_accept(netconn, &newconn)) == ERR_TIMEOUT && (thread || rpp_sci_read_nb(1, &input) != SUCCESS)) ;
135 err = ERR_CONN_ACCEPT;
139 netconn_delete(netconn); /* we don't need listening netconn anymore */
143 while (tries-- && !closeths) {
144 /* allow user to interrupt waiting for "udp connection" - in case this is not thread */
145 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) {
146 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
147 err = ERR_CONNECTING;
151 if ((err = netconn_recv(netconn, &remoteData)) == ERR_OK) { /* wait for data, from which we will determine our peer address and portNO */
152 remoteIP = remoteData->addr;
153 portNO = remoteData->port;
154 if (test) netbuf_delete(remoteData);
159 if (err == ERR_TIMEOUT) continue;
169 err = ERR_CONNECTING;
175 if (!listen || (listen && udp) ) { /* connect to remote node */
178 if ( ( err = netconn_connect(newconn, &remoteIP, portNO) ) != ERR_OK )
182 /* we will block for time specified on next line on netconn to receive data, if it does not come, we block for user sci input */
183 netconn_set_recvtimeout(newconn, 50);
185 if (udp && (localData = netbuf_new()) == NULL) {
190 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
194 //netconn_set_recvtimeout(newconn, 1);
195 while (!closeths && index++ < 4294967295) {
196 /* destroy all incomming data to prevent pbufs from running out */
197 /*while(remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT){
198 netbuf_delete(remoteData);
201 /* allow user to interrupt sending */
202 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break;
203 strlen = sprintf(strbuf,"%d\r\n",index);
205 if ((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK) break;
209 payload = netbuf_alloc(localData,strlen);
210 if (payload != NULL) {
211 netbuf_take(localData,strbuf,strlen);
212 netbuf_len(localData) = strlen;
213 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
225 if (netLoop) { /* -m option */
227 /* send some data to opposite node so it knows its peer (this node) ; ATENTION if opposite node was not running in time this is send, then it wont get known this node's connection info */
228 if (udp && !listen) {
229 payload = netbuf_alloc(localData,1);
230 if (payload != NULL) {
232 netbuf_take(localData,&input,1);
233 netbuf_len(localData) = 1;
234 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
243 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break; /* allow user to interrupt operation */
244 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT ) {
248 while (p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
253 netconn_write(newconn, p->payload, p->len, NETCONN_COPY); /*NETCONN_DONTBLOCK*/
256 payload = netbuf_alloc(localData,p->len);
257 if (payload != NULL) {
258 netbuf_take(localData,p->payload,p->len);
259 netbuf_len(localData) = p->len;
260 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
270 netbuf_delete(remoteData);
277 if (err == ERR_TIMEOUT) err = ERR_OK; /* timeout is not error here, this occurs on interrupt of while cycle */
281 /* only active user can control this section XXX: maybe should move to init startup condition handler */
284 /* INTERACTIVE PART */
286 /* receive remote data and print them to sci, receive sci data and write them to netconn */
288 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
289 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT) {
291 /* print remote data to SCI */
295 payload = p->payload;
296 while (index < p->len) {
297 rpp_sci_printf("%c",payload[index]);
302 netbuf_delete(remoteData);
306 break; /* receive error - e.g. newconn was closed */
308 if (err == ERR_TIMEOUT) err = ERR_OK;
312 // Backspace and Delete
313 if (input == 8 || input == 127) {
314 if (buff_index > 0) {
321 // Line feed or Carriage return
323 else if (input == 10 || input == 13) {
324 in_buffer[buff_index] = 13;
326 in_buffer[buff_index] = 10;
332 // If is any printable character
334 else if (isprint(input) || input == 9) {
336 // Store character and increment buffer index
337 in_buffer[buff_index] = input;
341 // Check if buffer is full and force flush
342 if (buff_index == BUF_SIZE - 3)
344 // All other character stops nc
353 netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
356 payload = netbuf_alloc(localData,buff_index);
357 if (payload != NULL) {
358 netbuf_take(localData,in_buffer,buff_index);
359 netbuf_len(localData) = buff_index;
360 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
376 if (thread) rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
378 if (udp && localData != NULL) netbuf_delete(localData);
379 if (remoteData != NULL) netbuf_delete(remoteData);
380 if (newconn != NULL && !udp) netconn_close(newconn);
381 netconn_delete(newconn);
384 nc_arg->err = err; /* only user controlled task is in front */
385 if (thread) vTaskDelete(NULL);
387 #else /* if !NO_SYS */
392 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
397 if (err == ERR_ABRT) {
398 rpp_sci_printk("recv abrt\n");
401 /* print remote data to SCI */
404 payload = p->payload;
405 while (index < p->len) {
406 rpp_sci_printk("%c",payload[index]);
414 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
419 /* print remote data to SCI */
422 payload = p->payload;
423 while (index < p->len) {
424 rpp_sci_printk("%c",payload[index]);
432 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
435 err_t err = udp_connect(pcb, addr, port);
436 LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
437 udp_recv(pcb, nc_udp_recv_callback, NULL);
438 nc_udp_recv_callback(arg, pcb, p, addr, port);
441 void nc_err_callback(void *arg, err_t err)
443 rpp_sci_printk("err clbck\n");
444 LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
449 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
455 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
457 struct tcp_pcb **newone = arg;
459 *newone = newpcb; /* pass accepted connection to main app loop */
463 /* Set up the various callback functions */
464 tcp_recv(newpcb, nc_recv_callback);
465 tcp_err(newpcb, nc_err_callback);
466 tcp_sent(newpcb, nc_sent_callback);
471 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
474 /* Set up the various callback functions */
475 tcp_recv(tpcb, nc_recv_callback);
476 tcp_err(tpcb, nc_err_callback);
477 tcp_sent(tpcb, nc_sent_callback);
480 rpp_sci_printk("connected\n");
484 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
486 if (err == ERR_ABRT) {
487 rpp_sci_printk("recv abrt\n");
491 if (tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY) != ERR_OK) {
492 rpp_sci_printk("error writing to newpcb - tcp_write\n");
495 if (tcp_output(tpcb) != ERR_OK) { /* when we want to send data immediately */
496 rpp_sci_printk("newpcb output err - tcp\n");
504 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
509 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
511 rpp_sci_printk("error allocating pbuf - udp_send\n");
515 if (pbuf_take(pbuf, p->payload, p->len) != ERR_OK) {
516 rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
519 if (udp_send(pcb, pbuf) != ERR_OK) {
520 rpp_sci_printk("error sending to pcb - udp_send\n");
531 * this function has two operational modes, depending on LwIP settings
532 * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
533 * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
535 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
537 if (!isPostInitialized()) {
538 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
542 uint16_t portNO, srcPortNO = 0;
544 boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
548 /* initialize arguments and thread name */
550 uint8_t name[5] = "nc";
552 struct nc_arg nc_arg; /* create space for handing args to nc_run() */
553 nc_arg.thread = FALSE;
556 boolean_t flush = FALSE;
558 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
559 struct tcp_pcb *tpcb, *tnewpcb;
561 struct pbuf *p; /* udp send */
564 /* examine parameters */
565 for (pindex = 1; param[pindex] != 0; pindex++) {
566 if (strncmp((char *)param[pindex], "-h", 3) == 0) {
570 else if (strncmp((char *)param[pindex], "-u", 3) == 0) {
574 else if (strncmp((char *)param[pindex], "-t", 3) == 0)
575 nc_arg.thread = TRUE;
576 else if (strncmp((char *)param[pindex], "-c", 3) == 0) {
581 else if (strncmp((char *)param[pindex], "-l", 3) == 0 && !srcPortSpec) {
583 srcPortNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
584 if (srcPortNO == 0) {
585 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -l option\r\n");
590 else if (strncmp((char *)param[pindex], "-p", 3) == 0 && !srcPortSpec) {
591 srcPortNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
592 if (srcPortNO == 0) {
593 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -p option\r\n");
598 else if (strncmp((char *)param[pindex], "-m", 3) == 0)
600 else if (strncmp((char *)param[pindex], "-d", 3) == 0)
602 else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t *)param[pindex])) == SUCCESS ) {
603 portNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
605 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
610 rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
617 /* TODO: additional testing of parameters mutual exclusion */
618 /* valid combinations:
619 nc <addr> <port> [-p <port>] [-u] [-t]
620 nc -l <port> [-u] [-t]
621 nc <addr> <port> -m [-p <port>] [-u] [-t]
622 nc <addr> <port> -d [-p <port>] [-u] [-t]
623 nc -l <port> -m [-u] [-t]
624 nc -l <port> -d [-u] [-t]
627 /* usage of command */
628 if (help || !param[1]) {
629 rpp_sci_printf("-u udp, -t thread, -c close tasks, -l listen, -p source port, -m ping/mirror, -d test\r\n\n");
630 rpp_sci_printf("usage:\tnc -l <port> [-u] [-m [-t] | -d [-t]]\r\n\t\tlistens on port for connection\r\n");
631 rpp_sci_printf("\tnc <address> <port> [-p <port>] [-u] [-m [-t] | -d [-t]]\r\n\t\tconnects to the address on port NO.\r\n");
632 rpp_sci_printf("\tnc -c\r\n\t\tdeletes all running threads.\r\n");
633 rpp_sci_printf("opts:\t-t run as stand alone task\r\n\t-c close all stand alone tasks\r\n");
634 rpp_sci_printf("\t-l <port> listen on given port for incomming connection\r\n\t-p <port> use as local port when connecting to remote node\r\n\t");
635 rpp_sci_printf("\t-m send all incomming data back to sender\r\n\t-d sends many testing packets containing packet number in ASCII as data\r\n");
636 rpp_sci_printf("Note: when using udp -u and listening -l options, first node data was received from is considered as peer for communication.\r\n");
640 /* determine srcPortNO from predefined value if not done yet (from argument given) */
643 srcPortNO = srcPort++;
645 #if !NO_SYS /* netconn api */
648 nc_arg.srcPortNO = srcPortNO;
649 nc_arg.portNO = portNO;
650 nc_arg.remoteIP.addr = remoteIP.addr;
652 nc_arg.listen = listen;
653 nc_arg.netLoop = netLoop;
655 nc_arg.srcPortSpec = srcPortSpec;
658 /* prepare semaphore */
659 vSemaphoreCreateBinary(nc_arg.args_coppied);
660 xSemaphoreTake(nc_arg.args_coppied, 0);
661 /* add number to task name */
662 taskNameNum = (taskNameNum%100);
663 name[2] = (taskNameNum/10) + '0';
664 name[3] = (taskNameNum%10) + '0';
665 rpp_sci_printf("STARTING THREAD: %s\r\n", name);
668 if ((err = xTaskCreate(&run_nc,(const signed char *)name, ncTaskStackSize, &nc_arg, ncTaskPriority, NULL)) == pdPASS) {
669 /* block on semaphore, till new thread copies arg to own stack */
670 xSemaphoreTake( nc_arg.args_coppied, portMAX_DELAY );
671 vSemaphoreDelete(nc_arg.args_coppied);
674 vSemaphoreDelete(nc_arg.args_coppied);
684 #else /* raw LwIP API */
690 LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
691 if (pcb == NULL) return -1;
692 err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
693 CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
694 if (err != ERR_OK) return -1;
699 LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
700 if (tpcb == NULL) return -1;
701 err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
702 CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
703 if (err != ERR_OK) return -1;
708 tpcb = tcp_listen(tpcb);
709 LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
710 /* initialize callback arg and accept callback */
711 tcp_arg(tpcb, &tnewpcb);
712 tcp_accept(tpcb, nc_accept_callback);
718 err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
719 LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
725 udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
728 err = udp_connect(pcb, &remoteIP, portNO);
729 LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
731 /* set udp recv callback */
732 udp_recv(pcb, nc_udp_recv_callback, NULL);
736 /* wait for connection to be established */
737 if (listen || !udp) {
739 if (rpp_sci_read_nb(1, &input) == SUCCESS) {
743 sys_check_timeouts();
744 vTaskDelay(10); /* just because we have no other business here */
746 if (!udp && listen && tcp_close(tpcb) != ERR_OK) rpp_sci_printk("closing listening tcp pcb err\n"); /* close listening pcb */
749 /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
751 /*************************************** 1 mirror mode *****************************************/
753 if (netLoop) { /* -m option */
755 /* send some data to opposite node so it knows its peer (this node) ; ATENTION if opposite node was not running in time this is send, then it wont get known this node's connection info */
756 /* if(udp && !listen){
757 payload = netbuf_alloc(localData,1);
760 netbuf_take(localData,&input,1);
761 netbuf_len(localData) = 1;
762 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
770 /* register callback function which sends all the recevd data back to remote host */
772 tcp_recv(tnewpcb, nc_tmirror_callback);
774 udp_recv(pcb, nc_umirror_callback, NULL);
776 while (rpp_sci_read_nb(1, &input) != SUCCESS) {
777 sys_check_timeouts();
783 /*************************************** 2 testing mode *****************************************/
785 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
789 //netconn_set_recvtimeout(newconn, 1);
790 while (index++ < 4294967295) {
791 /* allow user to interrupt sending */
792 if (rpp_sci_read_nb(1, &input) == SUCCESS) break;
793 strlen = sprintf(strbuf,"%d\r\n",index);
795 sys_check_timeouts();
796 if (tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY) != ERR_OK) {
797 rpp_sci_printf("error writing to newpcb - tcp_write testing\n");
800 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
801 rpp_sci_printf("newpcb output err - tcp testing\n");
807 p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
809 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
812 if (pbuf_take(p, strbuf, strlen) != ERR_OK) {
813 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
816 if (udp_send(pcb, p) != ERR_OK) {
817 rpp_sci_printf("error sending to pcb - udp_send testing\n");
825 /*************************************** 3 interactive mode *****************************************/
828 if (!udp && tnewpcb->state != ESTABLISHED) {
832 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
833 /* updating lwip timers here */
834 sys_check_timeouts();
838 // Backspace and Delete
839 if (input == 8 || input == 127) {
840 if (buff_index > 0) {
847 // Line feed or Carriage return
849 else if (input == 10 || input == 13) {
850 in_buffer[buff_index] = 13;
852 in_buffer[buff_index] = 10;
858 // If is any printable character
860 else if (isprint(input) || input == 9) {
862 // Store character and increment buffer index
863 in_buffer[buff_index] = input;
867 // Check if buffer is full and force flush
868 if (buff_index == BUF_SIZE - 3)
870 // All other character stops nc
878 while (!udp && !ncStop && !sent) {
879 sys_check_timeouts();
884 if (tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY) != ERR_OK) {
885 rpp_sci_printf("error writing to newpcb - tcp_write\n");
888 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
889 rpp_sci_printf("newpcb output err - tcp\n");
895 p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
897 rpp_sci_printf("error allocating pbuf - udp_send\n");
900 if (pbuf_take(p, in_buffer, buff_index) != ERR_OK) {
901 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
904 if (udp_send(pcb, p) != ERR_OK) {
905 rpp_sci_printf("error sending to pcb - udp_send\n");
918 /* close connection and clean */
920 tcp_recv(tnewpcb, NULL);
921 err = tcp_close(tnewpcb);
923 rpp_sci_printf("newpcb closing error\n");
924 /* closing failed, try again later */
925 LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
926 tcp_recv(tnewpcb, nc_recv_callback);
929 /* closing succeeded */
930 tcp_arg(tnewpcb, NULL);
931 tcp_sent(tnewpcb, NULL);
940 #endif /* if !NO_SYS */
946 cmd_des_t const cmd_des_nc = {
948 "ethnc","Start very simple netcat",
950 "### Command syntax ###\n"
952 " ethnc <IP> <PORT> [-p <PORT>] [-u] [-m [-t] | -d [-t]] [-c]\n"
953 " ethnc -l <PORT> [-u] [-m [-t] | -d [-t]] [-c]\n"
955 "### Description ###\n"
957 "Netcat is a program which allows to communicate using TCP or UDP\n"
958 "protocols. First a connection is established by either:\n"
960 "- connecting to a specified IP address and PORT (without option -l) or by\n"
961 "- listening for a new connection on a given PORT (with option -l).\n"
963 "When no -u option is specified ethnc command works with TCP\n"
964 "connections. With -u option UDP communication is used. Listening for\n"
965 "connection on UDP means waiting for reception of any UDP datagram.\n"
967 "Once the connection is established the command works in one of the\n"
970 "- interactive mode in which received data are forwarded to serial line and data received on serial line are sent to the connection when either new line is encountered or when internal buffer is full,\n"
971 "- sending of testing data (increasing ASCII formatted numbers) (option -d),\n"
972 "- looping of incoming data back to the connection's peer (option -m).\n"
974 "Note: When trying to use a same local TCP port number multiple times\n"
975 "in a row (-l or -p options) there might be several minutes delay\n"
976 "before the port is available after closing the previous connection.\n"
977 "This situation is singled with ERROR 31.\n"
981 "- -p specifies local port for outgoing connections.\n"
982 "- -u use UDP protocol instead of the default TCP.\n"
983 "- -t send and/or receive data in a background thread (works only with -d or -m options).\n"
984 "- -c stop all running background tasks\n"
988 "Listen for incoming TCP connection on local port 2000:\n"
989 " --> ethnc -l 2000\n"
991 "Connect using TCP to address 192.168.247.15 to remote port 80 using local port 1500:\n"
992 " --> ethnc 192.168.247.15 80 -p 1500\n"
994 "Send testing data to the remote node:\n"
995 " --> ethnc -d 192.168.247.2 1025\n"
997 "Loop back all data coming from remote node's UDP port 1025:\n"
998 " --> ethnc -m -u 192.168.247.2 1025\n"
1000 "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1002 " --> ethnc -l 30000 -m\n",
1003 CMD_HANDLER(cmd_do_init_nc), (void *)&cmd_list_nc
1006 /** List of commands for lwip, defined as external */
1007 cmd_des_t const *cmd_list_nc[] = {