2 * Copyright (C) 2012-2013 Czech Technical University in Prague
4 * Created on: Aug 9, 2013
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * This file contains commands for LwIP test
39 #include "lwip/api.h" //netconn
41 #include "lwip/timers.h" //for updating timers, when NO_SYS == 1
43 #include "lwip/tcp_impl.h"
46 #define INTERFACE_INSTANCE_NUMBER 0
49 /* only for use in interactive mode (not thread) */
50 char in_buffer[BUF_SIZE];
51 uint8_t buff_index = 0;
53 /* when -p option not given, srcPort is used; when nc run repeatedly,
54 * even though netconn was removed, netconn_new() with previously used port
55 * might still cause errors like address in use, therefore in srcPort
56 * there next port NO prepared to be used */
57 uint16_t srcPort = 1025; /* initial value */
60 uint8_t tasks_running = 0, taskNameNum = 0;
61 boolean_t closeths; /* variable controling threads closing */
63 /* 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 */
65 uint16_t portNO, srcPortNO;
67 xSemaphoreHandle args_coppied;
68 boolean_t thread; /* variable controling whether this instance should run as thread */
69 boolean_t udp, listen, netLoop, test, srcPortSpec;
75 void run_nc(void *arg)
82 struct netconn *netconn, *newconn;
85 struct netbuf *remoteData = NULL, *localData = NULL;
87 boolean_t ncStop = FALSE;
88 boolean_t flush = FALSE;
89 struct nc_arg *nc_arg = (struct nc_arg*)arg;
90 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
92 /* fill options from argument */
93 uint16_t portNO = nc_arg->portNO, srcPortNO = nc_arg->srcPortNO;
94 ip_addr_t remoteIP = nc_arg->remoteIP;
95 boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
96 boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
98 uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
103 /* switch off closing of tasks/threads */
107 /*** make connection ***/
108 while (!closeths) { /* shouldn't get here twice, used only for break which leads us down to unalocating of sources */
109 /* let nc initiator go */
110 if (thread && /* just in case --> */ nc_arg->args_coppied != NULL && xSemaphoreGive(nc_arg->args_coppied) != pdTRUE) break;
111 /* fill netconn struct */
112 netconn = netconn_new(udp ? NETCONN_UDP : NETCONN_TCP);
113 if (netconn == NULL) {
114 err = ERR_NETCONN_NEW;
118 tries = 15; /* how many local ports to try */
119 /* bind filled netconn with local interface address and source port number */
120 while ( tries-- && (err = netconn_bind(netconn, &(netif->ip_addr), srcPortNO) ) == ERR_USE && !closeths) {
121 if (srcPortSpec) break; /* if port was explicitly specified (we shouldn't change user's port number just like that ;) ) */
125 if (err != ERR_OK || !tries) {
126 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
131 /* adjust recvtimeout time and tries to different values, if user shouldn't loose control over cmd processor at any time */
132 netconn_set_recvtimeout(netconn, CONNECTING_TIMEO);
133 tries = CONNECTING_TRIES;
135 if (listen) { /* -l <PORT> option */
136 if (!udp) { /* TCP - make connection */
137 /* make listening netconn */
138 netconn_listen(netconn);
139 /* accept connection to newconn */
140 while ( tries-- && (err = netconn_accept(netconn, &newconn)) == ERR_TIMEOUT && (thread || rpp_sci_read_nb(1, &input) != SUCCESS)) ;
143 err = ERR_CONN_ACCEPT;
147 netconn_delete(netconn); /* we don't need listening netconn anymore */
151 while (tries-- && !closeths) {
152 /* allow user to interrupt waiting for "udp connection" - in case this is not thread */
153 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) {
154 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
155 err = ERR_CONNECTING;
159 if ((err = netconn_recv(netconn, &remoteData)) == ERR_OK) { /* wait for data, from which we will determine our peer address and portNO */
160 remoteIP = remoteData->addr;
161 portNO = remoteData->port;
162 if (test) netbuf_delete(remoteData);
167 if (err == ERR_TIMEOUT) continue;
177 err = ERR_CONNECTING;
183 if (!listen || (listen && udp) ) { /* connect to remote node */
186 if ( ( err = netconn_connect(newconn, &remoteIP, portNO) ) != ERR_OK )
190 /* 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 */
191 netconn_set_recvtimeout(newconn, 50);
193 if (udp && (localData = netbuf_new()) == NULL) {
198 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
202 //netconn_set_recvtimeout(newconn, 1);
203 while (!closeths && index++ < 4294967295) {
204 /* destroy all incomming data to prevent pbufs from running out */
205 /*while(remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT){
206 netbuf_delete(remoteData);
209 /* allow user to interrupt sending */
210 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break;
211 strlen = sprintf(strbuf,"%d\r\n",index);
213 if ((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK) break;
217 payload = netbuf_alloc(localData,strlen);
218 if (payload != NULL) {
219 netbuf_take(localData,strbuf,strlen);
220 netbuf_len(localData) = strlen;
221 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
233 if (netLoop) { /* -m option */
235 /* 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 */
236 if (udp && !listen) {
237 payload = netbuf_alloc(localData,1);
238 if (payload != NULL) {
240 netbuf_take(localData,&input,1);
241 netbuf_len(localData) = 1;
242 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
251 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break; /* allow user to interrupt operation */
252 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT ) {
256 while (p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
261 netconn_write(newconn, p->payload, p->len, NETCONN_COPY); /*NETCONN_DONTBLOCK*/
264 payload = netbuf_alloc(localData,p->len);
265 if (payload != NULL) {
266 netbuf_take(localData,p->payload,p->len);
267 netbuf_len(localData) = p->len;
268 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
278 netbuf_delete(remoteData);
285 if (err == ERR_TIMEOUT) err = ERR_OK; /* timeout is not error here, this occurs on interrupt of while cycle */
289 /* only active user can control this section XXX: maybe should move to init startup condition handler */
292 /* INTERACTIVE PART */
294 /* receive remote data and print them to sci, receive sci data and write them to netconn */
296 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
297 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT) {
299 /* print remote data to SCI */
303 payload = p->payload;
304 while (index < p->len) {
305 rpp_sci_printf("%c",payload[index]);
310 netbuf_delete(remoteData);
314 break; /* receive error - e.g. newconn was closed */
316 if (err == ERR_TIMEOUT) err = ERR_OK;
320 // Backspace and Delete
321 if (input == 8 || input == 127) {
322 if (buff_index > 0) {
329 // Line feed or Carriage return
331 else if (input == 10 || input == 13) {
332 in_buffer[buff_index] = 13;
334 in_buffer[buff_index] = 10;
340 // If is any printable character
342 else if (isprint(input) || input == 9) {
344 // Store character and increment buffer index
345 in_buffer[buff_index] = input;
349 // Check if buffer is full and force flush
350 if (buff_index == BUF_SIZE - 3)
352 // All other character stops nc
361 netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
364 payload = netbuf_alloc(localData,buff_index);
365 if (payload != NULL) {
366 netbuf_take(localData,in_buffer,buff_index);
367 netbuf_len(localData) = buff_index;
368 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
384 if (thread) rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
386 if (udp && localData != NULL) netbuf_delete(localData);
387 if (remoteData != NULL) netbuf_delete(remoteData);
388 if (newconn != NULL && !udp) netconn_close(newconn);
389 netconn_delete(newconn);
392 nc_arg->err = err; /* only user controlled task is in front */
393 if (thread) vTaskDelete(NULL);
395 #else /* if !NO_SYS */
400 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
405 if (err == ERR_ABRT) {
406 rpp_sci_printk("recv abrt\n");
409 /* print remote data to SCI */
412 payload = p->payload;
413 while (index < p->len) {
414 rpp_sci_printk("%c",payload[index]);
422 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
427 /* print remote data to SCI */
430 payload = p->payload;
431 while (index < p->len) {
432 rpp_sci_printk("%c",payload[index]);
440 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
443 err_t err = udp_connect(pcb, addr, port);
444 LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
445 udp_recv(pcb, nc_udp_recv_callback, NULL);
446 nc_udp_recv_callback(arg, pcb, p, addr, port);
449 void nc_err_callback(void *arg, err_t err)
451 rpp_sci_printk("err clbck\n");
452 LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
457 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
463 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
465 struct tcp_pcb * *newone = arg;
467 *newone = newpcb; /* pass accepted connection to main app loop */
471 /* Set up the various callback functions */
472 tcp_recv(newpcb, nc_recv_callback);
473 tcp_err(newpcb, nc_err_callback);
474 tcp_sent(newpcb, nc_sent_callback);
479 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
482 /* Set up the various callback functions */
483 tcp_recv(tpcb, nc_recv_callback);
484 tcp_err(tpcb, nc_err_callback);
485 tcp_sent(tpcb, nc_sent_callback);
488 rpp_sci_printk("connected\n");
492 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
494 if (err == ERR_ABRT) {
495 rpp_sci_printk("recv abrt\n");
499 if (tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY) != ERR_OK) {
500 rpp_sci_printk("error writing to newpcb - tcp_write\n");
503 if (tcp_output(tpcb) != ERR_OK) { /* when we want to send data immediately */
504 rpp_sci_printk("newpcb output err - tcp\n");
512 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
517 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
519 rpp_sci_printk("error allocating pbuf - udp_send\n");
523 if (pbuf_take(pbuf, p->payload, p->len) != ERR_OK) {
524 rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
527 if (udp_send(pcb, pbuf) != ERR_OK) {
528 rpp_sci_printk("error sending to pcb - udp_send\n");
539 * this function has two operational modes, depending on LwIP settings
540 * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
541 * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
543 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
545 if (!isPostInitialized()) {
546 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
550 uint16_t portNO, srcPortNO = 0;
552 boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
556 /* initialize arguments and thread name */
558 uint8_t name[5] = "nc";
560 struct nc_arg nc_arg; /* create space for handing args to nc_run() */
561 nc_arg.thread = FALSE;
564 boolean_t flush = FALSE;
566 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
567 struct tcp_pcb *tpcb, *tnewpcb;
569 struct pbuf *p; /* udp send */
572 /* examine parameters */
573 for (pindex = 1; param[pindex] != 0; pindex++) {
574 if (strncmp((char*)param[pindex], "-h", 3) == 0) {
578 else if (strncmp((char*)param[pindex], "-u", 3) == 0) {
582 else if (strncmp((char*)param[pindex], "-t", 3) == 0)
583 nc_arg.thread = TRUE;
584 else if (strncmp((char*)param[pindex], "-c", 3) == 0) {
589 else if (strncmp((char*)param[pindex], "-l", 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 -l option\r\n");
598 else if (strncmp((char*)param[pindex], "-p", 3) == 0 && !srcPortSpec) {
599 srcPortNO = rpp_eth_portStrToInt((uint8_t*)param[++pindex]);
600 if (srcPortNO == 0) {
601 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -p option\r\n");
606 else if (strncmp((char*)param[pindex], "-m", 3) == 0)
608 else if (strncmp((char*)param[pindex], "-d", 3) == 0)
610 else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t*)param[pindex])) == SUCCESS ) {
611 portNO = rpp_eth_portStrToInt((uint8_t*)param[++pindex]);
613 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
618 rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
625 /* TODO: additional testing of parameters mutual exclusion */
626 /* valid combinations:
627 nc <addr> <port> [-p <port>] [-u] [-t]
628 nc -l <port> [-u] [-t]
629 nc <addr> <port> -m [-p <port>] [-u] [-t]
630 nc <addr> <port> -d [-p <port>] [-u] [-t]
631 nc -l <port> -m [-u] [-t]
632 nc -l <port> -d [-u] [-t]
635 /* usage of command */
636 if (help || !param[1]) {
637 rpp_sci_printf("-u udp, -t thread, -c close tasks, -l listen, -p source port, -m ping/mirror, -d test\r\n\n");
638 rpp_sci_printf("usage:\tnc -l <port> [-u] [-m [-t] | -d [-t]]\r\n\t\tlistens on port for connection\r\n");
639 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");
640 rpp_sci_printf("\tnc -c\r\n\t\tdeletes all running threads.\r\n");
641 rpp_sci_printf("opts:\t-t run as stand alone task\r\n\t-c close all stand alone tasks\r\n");
642 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");
643 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");
644 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");
648 /* determine srcPortNO from predefined value if not done yet (from argument given) */
651 srcPortNO = srcPort++;
653 #if !NO_SYS /* netconn api */
656 nc_arg.srcPortNO = srcPortNO;
657 nc_arg.portNO = portNO;
658 nc_arg.remoteIP.addr = remoteIP.addr;
660 nc_arg.listen = listen;
661 nc_arg.netLoop = netLoop;
663 nc_arg.srcPortSpec = srcPortSpec;
666 /* prepare semaphore */
667 vSemaphoreCreateBinary(nc_arg.args_coppied);
668 xSemaphoreTake(nc_arg.args_coppied, 0);
669 /* add number to task name */
670 taskNameNum = (taskNameNum%100);
671 name[2] = (taskNameNum/10) + '0';
672 name[3] = (taskNameNum%10) + '0';
673 rpp_sci_printf("STARTING THREAD: %s\r\n", name);
676 if ((err = xTaskCreate(&run_nc,(const signed char*)name, ncTaskStackSize, &nc_arg, ncTaskPriority, NULL)) == pdPASS) {
677 /* block on semaphore, till new thread copies arg to own stack */
678 xSemaphoreTake( nc_arg.args_coppied, portMAX_DELAY );
679 vSemaphoreDelete(nc_arg.args_coppied);
682 vSemaphoreDelete(nc_arg.args_coppied);
692 #else /* raw LwIP API */
698 LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
699 if (pcb == NULL) return -1;
700 err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
701 CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
702 if (err != ERR_OK) return -1;
707 LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
708 if (tpcb == NULL) return -1;
709 err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
710 CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
711 if (err != ERR_OK) return -1;
716 tpcb = tcp_listen(tpcb);
717 LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
718 /* initialize callback arg and accept callback */
719 tcp_arg(tpcb, &tnewpcb);
720 tcp_accept(tpcb, nc_accept_callback);
726 err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
727 LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
733 udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
736 err = udp_connect(pcb, &remoteIP, portNO);
737 LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
739 /* set udp recv callback */
740 udp_recv(pcb, nc_udp_recv_callback, NULL);
744 /* wait for connection to be established */
745 if (listen || !udp) {
747 if (rpp_sci_read_nb(1, &input) == SUCCESS) {
751 sys_check_timeouts();
752 vTaskDelay(10); /* just because we have no other business here */
754 if (!udp && listen && tcp_close(tpcb) != ERR_OK) rpp_sci_printk("closing listening tcp pcb err\n"); /* close listening pcb */
757 /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
759 /*************************************** 1 mirror mode *****************************************/
761 if (netLoop) { /* -m option */
763 /* 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 */
764 /* if(udp && !listen){
765 payload = netbuf_alloc(localData,1);
768 netbuf_take(localData,&input,1);
769 netbuf_len(localData) = 1;
770 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
778 /* register callback function which sends all the recevd data back to remote host */
780 tcp_recv(tnewpcb, nc_tmirror_callback);
782 udp_recv(pcb, nc_umirror_callback, NULL);
784 while (rpp_sci_read_nb(1, &input) != SUCCESS) {
785 sys_check_timeouts();
791 /*************************************** 2 testing mode *****************************************/
793 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
797 //netconn_set_recvtimeout(newconn, 1);
798 while (index++ < 4294967295) {
799 /* allow user to interrupt sending */
800 if (rpp_sci_read_nb(1, &input) == SUCCESS) break;
801 strlen = sprintf(strbuf,"%d\r\n",index);
803 sys_check_timeouts();
804 if (tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY) != ERR_OK) {
805 rpp_sci_printf("error writing to newpcb - tcp_write testing\n");
808 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
809 rpp_sci_printf("newpcb output err - tcp testing\n");
815 p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
817 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
820 if (pbuf_take(p, strbuf, strlen) != ERR_OK) {
821 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
824 if (udp_send(pcb, p) != ERR_OK) {
825 rpp_sci_printf("error sending to pcb - udp_send testing\n");
833 /*************************************** 3 interactive mode *****************************************/
836 if (!udp && tnewpcb->state != ESTABLISHED) {
840 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
841 /* updating lwip timers here */
842 sys_check_timeouts();
846 // Backspace and Delete
847 if (input == 8 || input == 127) {
848 if (buff_index > 0) {
855 // Line feed or Carriage return
857 else if (input == 10 || input == 13) {
858 in_buffer[buff_index] = 13;
860 in_buffer[buff_index] = 10;
866 // If is any printable character
868 else if (isprint(input) || input == 9) {
870 // Store character and increment buffer index
871 in_buffer[buff_index] = input;
875 // Check if buffer is full and force flush
876 if (buff_index == BUF_SIZE - 3)
878 // All other character stops nc
886 while (!udp && !ncStop && !sent) {
887 sys_check_timeouts();
892 if (tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY) != ERR_OK) {
893 rpp_sci_printf("error writing to newpcb - tcp_write\n");
896 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
897 rpp_sci_printf("newpcb output err - tcp\n");
903 p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
905 rpp_sci_printf("error allocating pbuf - udp_send\n");
908 if (pbuf_take(p, in_buffer, buff_index) != ERR_OK) {
909 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
912 if (udp_send(pcb, p) != ERR_OK) {
913 rpp_sci_printf("error sending to pcb - udp_send\n");
926 /* close connection and clean */
928 tcp_recv(tnewpcb, NULL);
929 err = tcp_close(tnewpcb);
931 rpp_sci_printf("newpcb closing error\n");
932 /* closing failed, try again later */
933 LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
934 tcp_recv(tnewpcb, nc_recv_callback);
937 /* closing succeeded */
938 tcp_arg(tnewpcb, NULL);
939 tcp_sent(tnewpcb, NULL);
948 #endif /* if !NO_SYS */
954 cmd_des_t const cmd_des_nc = {
956 "ethnc","Start very simple netcat",
958 "### Command syntax ###\n"
960 " ethnc <IP> <PORT> [-p <PORT>] [-u] [-m [-t] | -d [-t]] [-c]\n"
961 " ethnc -l <PORT> [-u] [-m [-t] | -d [-t]] [-c]\n"
963 "### Description ###\n"
965 "Netcat is a program which allows to communicate using TCP or UDP\n"
966 "protocols. First a connection is established by either:\n"
968 "- connecting to a specified IP address and PORT (without option -l) or by\n"
969 "- listening for a new connection on a given PORT (with option -l).\n"
971 "When no -u option is specified ethnc command works with TCP\n"
972 "connections. With -u option UDP communication is used. Listening for\n"
973 "connection on UDP means waiting for reception of any UDP datagram.\n"
975 "Once the connection is established the command works in one of the\n"
978 "- 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"
979 "- sending of testing data (increasing ASCII formatted numbers) (option -d),\n"
980 "- looping of incoming data back to the connection's peer (option -m).\n"
982 "Note: When trying to use a same local TCP port number multiple times\n"
983 "in a row (-l or -p options) there might be several minutes delay\n"
984 "before the port is available after closing the previous connection.\n"
985 "This situation is singled with ERROR 31.\n"
989 "- -p specifies local port for outgoing connections.\n"
990 "- -u use UDP protocol instead of the default TCP.\n"
991 "- -t send and/or receive data in a background thread (works only with -d or -m options).\n"
992 "- -c stop all running background tasks\n"
996 "Listen for incoming TCP connection on local port 2000:\n"
997 " --> ethnc -l 2000\n"
999 "Connect using TCP to address 192.168.247.15 to remote port 80 using local port 1500:\n"
1000 " --> ethnc 192.168.247.15 80 -p 1500\n"
1002 "Send testing data to the remote node:\n"
1003 " --> ethnc -d 192.168.247.2 1025\n"
1005 "Loop back all data coming from remote node's UDP port 1025:\n"
1006 " --> ethnc -m -u 192.168.247.2 1025\n"
1008 "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1010 " --> ethnc -l 30000 -m\n",
1011 CMD_HANDLER(cmd_do_init_nc), (void*)&cmd_list_nc
1014 /** List of commands for lwip, defined as external */
1015 cmd_des_t const *cmd_list_nc[] = {