2 * Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
4 * Created on: Aug 9, 2013
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
33 * This file contains commands for LwIP test
47 #include "lwip/api.h" //netconn
49 #include "lwip/timers.h" //for updating timers, when NO_SYS == 1
51 #include "lwip/tcp_impl.h"
54 #define INTERFACE_INSTANCE_NUMBER 0
57 /* only for use in interactive mode (not thread) */
58 char in_buffer[BUF_SIZE];
59 uint8_t buff_index = 0;
61 /* when -p option not given, srcPort is used; when nc run repeatedly,
62 * even though netconn was removed, netconn_new() with previously used port
63 * might still cause errors like address in use, therefore in srcPort
64 * there next port NO prepared to be used */
65 uint16_t srcPort = 1025; /* initial value */
68 uint8_t tasks_running = 0, taskNameNum = 0;
69 boolean_t closeths; /* variable controling threads closing */
71 /* 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 */
73 uint16_t portNO, srcPortNO;
75 xSemaphoreHandle args_coppied;
76 boolean_t thread; /* variable controling whether this instance should run as thread */
77 boolean_t udp, listen, netLoop, test, srcPortSpec;
83 void run_nc(void *arg)
90 struct netconn *netconn, *newconn;
93 struct netbuf *remoteData = NULL, *localData = NULL;
95 boolean_t ncStop = FALSE;
96 boolean_t flush = FALSE;
97 struct nc_arg *nc_arg = (struct nc_arg *)arg;
98 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
100 /* fill options from argument */
101 uint16_t portNO = nc_arg->portNO, srcPortNO = nc_arg->srcPortNO;
102 ip_addr_t remoteIP = nc_arg->remoteIP;
103 boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
104 boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
106 uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
111 /* switch off closing of tasks/threads */
115 /*** make connection ***/
116 while (!closeths) { /* shouldn't get here twice, used only for break which leads us down to unalocating of sources */
117 /* let nc initiator go */
118 if (thread && /* just in case --> */ nc_arg->args_coppied != NULL && xSemaphoreGive(nc_arg->args_coppied) != pdTRUE) break;
119 /* fill netconn struct */
120 netconn = netconn_new(udp ? NETCONN_UDP : NETCONN_TCP);
121 if (netconn == NULL) {
122 err = ERR_NETCONN_NEW;
126 tries = 15; /* how many local ports to try */
127 /* bind filled netconn with local interface address and source port number */
128 while ( tries-- && (err = netconn_bind(netconn, &(netif->ip_addr), srcPortNO) ) == ERR_USE && !closeths) {
129 if (srcPortSpec) break; /* if port was explicitly specified (we shouldn't change user's port number just like that ;) ) */
133 if (err != ERR_OK || !tries) {
134 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
139 /* adjust recvtimeout time and tries to different values, if user shouldn't loose control over cmd processor at any time */
140 netconn_set_recvtimeout(netconn, CONNECTING_TIMEO);
141 tries = CONNECTING_TRIES;
143 if (listen) { /* -l <PORT> option */
144 if (!udp) { /* TCP - make connection */
145 /* make listening netconn */
146 netconn_listen(netconn);
147 /* accept connection to newconn */
148 while ( tries-- && (err = netconn_accept(netconn, &newconn)) == ERR_TIMEOUT && (thread || rpp_sci_read_nb(1, &input) != SUCCESS)) ;
151 err = ERR_CONN_ACCEPT;
155 netconn_delete(netconn); /* we don't need listening netconn anymore */
159 while (tries-- && !closeths) {
160 /* allow user to interrupt waiting for "udp connection" - in case this is not thread */
161 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) {
162 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
163 err = ERR_CONNECTING;
167 if ((err = netconn_recv(netconn, &remoteData)) == ERR_OK) { /* wait for data, from which we will determine our peer address and portNO */
168 remoteIP = remoteData->addr;
169 portNO = remoteData->port;
170 if (test) netbuf_delete(remoteData);
175 if (err == ERR_TIMEOUT) continue;
185 err = ERR_CONNECTING;
191 if (!listen || (listen && udp) ) { /* connect to remote node */
194 if ( ( err = netconn_connect(newconn, &remoteIP, portNO) ) != ERR_OK )
198 /* 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 */
199 netconn_set_recvtimeout(newconn, 50);
201 if (udp && (localData = netbuf_new()) == NULL) {
206 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
210 //netconn_set_recvtimeout(newconn, 1);
211 while (!closeths && index++ < 4294967295) {
212 /* destroy all incomming data to prevent pbufs from running out */
213 /*while(remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT){
214 netbuf_delete(remoteData);
217 /* allow user to interrupt sending */
218 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break;
219 strlen = sprintf(strbuf,"%d\r\n",index);
221 if ((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK) break;
225 payload = netbuf_alloc(localData,strlen);
226 if (payload != NULL) {
227 netbuf_take(localData,strbuf,strlen);
228 netbuf_len(localData) = strlen;
229 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
241 if (netLoop) { /* -m option */
243 /* 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 */
244 if (udp && !listen) {
245 payload = netbuf_alloc(localData,1);
246 if (payload != NULL) {
248 netbuf_take(localData,&input,1);
249 netbuf_len(localData) = 1;
250 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
259 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break; /* allow user to interrupt operation */
260 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT ) {
264 while (p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
269 netconn_write(newconn, p->payload, p->len, NETCONN_COPY); /*NETCONN_DONTBLOCK*/
272 payload = netbuf_alloc(localData,p->len);
273 if (payload != NULL) {
274 netbuf_take(localData,p->payload,p->len);
275 netbuf_len(localData) = p->len;
276 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
286 netbuf_delete(remoteData);
293 if (err == ERR_TIMEOUT) err = ERR_OK; /* timeout is not error here, this occurs on interrupt of while cycle */
297 /* only active user can control this section XXX: maybe should move to init startup condition handler */
300 /* INTERACTIVE PART */
302 /* receive remote data and print them to sci, receive sci data and write them to netconn */
304 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
305 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT) {
307 /* print remote data to SCI */
311 payload = p->payload;
312 while (index < p->len) {
313 rpp_sci_printf("%c",payload[index]);
318 netbuf_delete(remoteData);
322 break; /* receive error - e.g. newconn was closed */
324 if (err == ERR_TIMEOUT) err = ERR_OK;
328 // Backspace and Delete
329 if (input == 8 || input == 127) {
330 if (buff_index > 0) {
337 // Line feed or Carriage return
339 else if (input == 10 || input == 13) {
340 in_buffer[buff_index] = 13;
342 in_buffer[buff_index] = 10;
348 // If is any printable character
350 else if (isprint(input) || input == 9) {
352 // Store character and increment buffer index
353 in_buffer[buff_index] = input;
357 // Check if buffer is full and force flush
358 if (buff_index == BUF_SIZE - 3)
360 // All other character stops nc
369 netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
372 payload = netbuf_alloc(localData,buff_index);
373 if (payload != NULL) {
374 netbuf_take(localData,in_buffer,buff_index);
375 netbuf_len(localData) = buff_index;
376 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
392 if (thread) rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
394 if (udp && localData != NULL) netbuf_delete(localData);
395 if (remoteData != NULL) netbuf_delete(remoteData);
396 if (newconn != NULL && !udp) netconn_close(newconn);
397 netconn_delete(newconn);
400 nc_arg->err = err; /* only user controlled task is in front */
401 if (thread) vTaskDelete(NULL);
403 #else /* if !NO_SYS */
408 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
413 if (err == ERR_ABRT) {
414 rpp_sci_printk("recv abrt\n");
417 /* print remote data to SCI */
420 payload = p->payload;
421 while (index < p->len) {
422 rpp_sci_printk("%c",payload[index]);
430 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
435 /* print remote data to SCI */
438 payload = p->payload;
439 while (index < p->len) {
440 rpp_sci_printk("%c",payload[index]);
448 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
451 err_t err = udp_connect(pcb, addr, port);
452 LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
453 udp_recv(pcb, nc_udp_recv_callback, NULL);
454 nc_udp_recv_callback(arg, pcb, p, addr, port);
457 void nc_err_callback(void *arg, err_t err)
459 rpp_sci_printk("err clbck\n");
460 LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
465 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
471 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
473 struct tcp_pcb **newone = arg;
475 *newone = newpcb; /* pass accepted connection to main app loop */
479 /* Set up the various callback functions */
480 tcp_recv(newpcb, nc_recv_callback);
481 tcp_err(newpcb, nc_err_callback);
482 tcp_sent(newpcb, nc_sent_callback);
487 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
490 /* Set up the various callback functions */
491 tcp_recv(tpcb, nc_recv_callback);
492 tcp_err(tpcb, nc_err_callback);
493 tcp_sent(tpcb, nc_sent_callback);
496 rpp_sci_printk("connected\n");
500 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
502 if (err == ERR_ABRT) {
503 rpp_sci_printk("recv abrt\n");
507 if (tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY) != ERR_OK) {
508 rpp_sci_printk("error writing to newpcb - tcp_write\n");
511 if (tcp_output(tpcb) != ERR_OK) { /* when we want to send data immediately */
512 rpp_sci_printk("newpcb output err - tcp\n");
520 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
525 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
527 rpp_sci_printk("error allocating pbuf - udp_send\n");
531 if (pbuf_take(pbuf, p->payload, p->len) != ERR_OK) {
532 rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
535 if (udp_send(pcb, pbuf) != ERR_OK) {
536 rpp_sci_printk("error sending to pcb - udp_send\n");
547 * this function has two operational modes, depending on LwIP settings
548 * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
549 * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
551 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
553 if (!isPostInitialized()) {
554 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
558 uint16_t portNO, srcPortNO = 0;
560 boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
564 /* initialize arguments and thread name */
568 struct nc_arg nc_arg; /* create space for handing args to nc_run() */
569 nc_arg.thread = FALSE;
572 boolean_t flush = FALSE;
574 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
575 struct tcp_pcb *tpcb, *tnewpcb;
577 struct pbuf *p; /* udp send */
580 /* examine parameters */
581 for (pindex = 1; param[pindex] != 0; pindex++) {
582 if (strncmp((char *)param[pindex], "-h", 3) == 0) {
586 else if (strncmp((char *)param[pindex], "-u", 3) == 0) {
590 else if (strncmp((char *)param[pindex], "-t", 3) == 0)
591 nc_arg.thread = TRUE;
592 else if (strncmp((char *)param[pindex], "-c", 3) == 0) {
597 else if (strncmp((char *)param[pindex], "-l", 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 -l option\r\n");
606 else if (strncmp((char *)param[pindex], "-p", 3) == 0 && !srcPortSpec) {
607 srcPortNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
608 if (srcPortNO == 0) {
609 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -p option\r\n");
614 else if (strncmp((char *)param[pindex], "-m", 3) == 0)
616 else if (strncmp((char *)param[pindex], "-d", 3) == 0)
618 else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t *)param[pindex])) == SUCCESS ) {
619 portNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
621 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
626 rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
633 /* TODO: additional testing of parameters mutual exclusion */
634 /* valid combinations:
635 nc <addr> <port> [-p <port>] [-u] [-t]
636 nc -l <port> [-u] [-t]
637 nc <addr> <port> -m [-p <port>] [-u] [-t]
638 nc <addr> <port> -d [-p <port>] [-u] [-t]
639 nc -l <port> -m [-u] [-t]
640 nc -l <port> -d [-u] [-t]
643 /* usage of command */
644 if (help || !param[1]) {
645 rpp_sci_printf("-u udp, -t thread, -c close tasks, -l listen, -p source port, -m ping/mirror, -d test\r\n\n");
646 rpp_sci_printf("usage:\tnc -l <port> [-u] [-m [-t] | -d [-t]]\r\n\t\tlistens on port for connection\r\n");
647 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");
648 rpp_sci_printf("\tnc -c\r\n\t\tdeletes all running threads.\r\n");
649 rpp_sci_printf("opts:\t-t run as stand alone task\r\n\t-c close all stand alone tasks\r\n");
650 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");
651 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");
652 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");
656 /* determine srcPortNO from predefined value if not done yet (from argument given) */
659 srcPortNO = srcPort++;
661 #if !NO_SYS /* netconn api */
664 nc_arg.srcPortNO = srcPortNO;
665 nc_arg.portNO = portNO;
666 nc_arg.remoteIP.addr = remoteIP.addr;
668 nc_arg.listen = listen;
669 nc_arg.netLoop = netLoop;
671 nc_arg.srcPortSpec = srcPortSpec;
674 /* prepare semaphore */
675 vSemaphoreCreateBinary(nc_arg.args_coppied);
676 xSemaphoreTake(nc_arg.args_coppied, 0);
677 /* add number to task name */
678 taskNameNum = (taskNameNum%100);
679 name[2] = (taskNameNum/10) + '0';
680 name[3] = (taskNameNum%10) + '0';
681 rpp_sci_printf("STARTING THREAD: %s\r\n", name);
684 if ((err = xTaskCreate(&run_nc, name, ncTaskStackSize, &nc_arg, ncTaskPriority, NULL)) == pdPASS) {
685 /* block on semaphore, till new thread copies arg to own stack */
686 xSemaphoreTake( nc_arg.args_coppied, portMAX_DELAY );
687 vSemaphoreDelete(nc_arg.args_coppied);
690 vSemaphoreDelete(nc_arg.args_coppied);
700 #else /* raw LwIP API */
706 LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
707 if (pcb == NULL) return -1;
708 err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
709 CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
710 if (err != ERR_OK) return -1;
715 LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
716 if (tpcb == NULL) return -1;
717 err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
718 CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
719 if (err != ERR_OK) return -1;
724 tpcb = tcp_listen(tpcb);
725 LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
726 /* initialize callback arg and accept callback */
727 tcp_arg(tpcb, &tnewpcb);
728 tcp_accept(tpcb, nc_accept_callback);
734 err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
735 LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
741 udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
744 err = udp_connect(pcb, &remoteIP, portNO);
745 LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
747 /* set udp recv callback */
748 udp_recv(pcb, nc_udp_recv_callback, NULL);
752 /* wait for connection to be established */
753 if (listen || !udp) {
755 if (rpp_sci_read_nb(1, &input) == SUCCESS) {
759 sys_check_timeouts();
760 vTaskDelay(10); /* just because we have no other business here */
762 if (!udp && listen && tcp_close(tpcb) != ERR_OK) rpp_sci_printk("closing listening tcp pcb err\n"); /* close listening pcb */
765 /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
767 /*************************************** 1 mirror mode *****************************************/
769 if (netLoop) { /* -m option */
771 /* 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 */
772 /* if(udp && !listen){
773 payload = netbuf_alloc(localData,1);
776 netbuf_take(localData,&input,1);
777 netbuf_len(localData) = 1;
778 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
786 /* register callback function which sends all the recevd data back to remote host */
788 tcp_recv(tnewpcb, nc_tmirror_callback);
790 udp_recv(pcb, nc_umirror_callback, NULL);
792 while (rpp_sci_read_nb(1, &input) != SUCCESS) {
793 sys_check_timeouts();
799 /*************************************** 2 testing mode *****************************************/
801 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
805 //netconn_set_recvtimeout(newconn, 1);
806 while (index++ < 4294967295) {
807 /* allow user to interrupt sending */
808 if (rpp_sci_read_nb(1, &input) == SUCCESS) break;
809 strlen = sprintf(strbuf,"%d\r\n",index);
811 sys_check_timeouts();
812 if (tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY) != ERR_OK) {
813 rpp_sci_printf("error writing to newpcb - tcp_write testing\n");
816 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
817 rpp_sci_printf("newpcb output err - tcp testing\n");
823 p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
825 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
828 if (pbuf_take(p, strbuf, strlen) != ERR_OK) {
829 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
832 if (udp_send(pcb, p) != ERR_OK) {
833 rpp_sci_printf("error sending to pcb - udp_send testing\n");
841 /*************************************** 3 interactive mode *****************************************/
844 if (!udp && tnewpcb->state != ESTABLISHED) {
848 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
849 /* updating lwip timers here */
850 sys_check_timeouts();
854 // Backspace and Delete
855 if (input == 8 || input == 127) {
856 if (buff_index > 0) {
863 // Line feed or Carriage return
865 else if (input == 10 || input == 13) {
866 in_buffer[buff_index] = 13;
868 in_buffer[buff_index] = 10;
874 // If is any printable character
876 else if (isprint(input) || input == 9) {
878 // Store character and increment buffer index
879 in_buffer[buff_index] = input;
883 // Check if buffer is full and force flush
884 if (buff_index == BUF_SIZE - 3)
886 // All other character stops nc
894 while (!udp && !ncStop && !sent) {
895 sys_check_timeouts();
900 if (tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY) != ERR_OK) {
901 rpp_sci_printf("error writing to newpcb - tcp_write\n");
904 if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
905 rpp_sci_printf("newpcb output err - tcp\n");
911 p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
913 rpp_sci_printf("error allocating pbuf - udp_send\n");
916 if (pbuf_take(p, in_buffer, buff_index) != ERR_OK) {
917 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
920 if (udp_send(pcb, p) != ERR_OK) {
921 rpp_sci_printf("error sending to pcb - udp_send\n");
934 /* close connection and clean */
936 tcp_recv(tnewpcb, NULL);
937 err = tcp_close(tnewpcb);
939 rpp_sci_printf("newpcb closing error\n");
940 /* closing failed, try again later */
941 LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
942 tcp_recv(tnewpcb, nc_recv_callback);
945 /* closing succeeded */
946 tcp_arg(tnewpcb, NULL);
947 tcp_sent(tnewpcb, NULL);
956 #endif /* if !NO_SYS */
962 cmd_des_t const cmd_des_nc = {
964 "ethnc","Start very simple netcat",
966 "### Command syntax ###\n"
968 " ethnc <IP> <PORT> [-p <PORT>] [-u] [-m [-t] | -d [-t]] [-c]\n"
969 " ethnc -l <PORT> [-u] [-m [-t] | -d [-t]] [-c]\n"
971 "### Description ###\n"
973 "Netcat is a program which allows to communicate using TCP or UDP\n"
974 "protocols. First a connection is established by either:\n"
976 "- connecting to a specified IP address and PORT (without option -l) or by\n"
977 "- listening for a new connection on a given PORT (with option -l).\n"
979 "When no -u option is specified ethnc command works with TCP\n"
980 "connections. With -u option UDP communication is used. Listening for\n"
981 "connection on UDP means waiting for reception of any UDP datagram.\n"
983 "Once the connection is established the command works in one of the\n"
986 "- 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"
987 "- sending of testing data (increasing ASCII formatted numbers) (option -d),\n"
988 "- looping of incoming data back to the connection's peer (option -m).\n"
990 "Note: When trying to use a same local TCP port number multiple times\n"
991 "in a row (-l or -p options) there might be several minutes delay\n"
992 "before the port is available after closing the previous connection.\n"
993 "This situation is singled with ERROR 31.\n"
997 "- -p specifies local port for outgoing connections.\n"
998 "- -u use UDP protocol instead of the default TCP.\n"
999 "- -t send and/or receive data in a background thread (works only with -d or -m options).\n"
1000 "- -c stop all running background tasks\n"
1002 "### Examples ###\n"
1004 "Listen for incoming TCP connection on local port 2000:\n"
1005 " --> ethnc -l 2000\n"
1007 "Connect using TCP to address 192.168.247.15 to remote port 80 using local port 1500:\n"
1008 " --> ethnc 192.168.247.15 80 -p 1500\n"
1010 "Send testing data to the remote node:\n"
1011 " --> ethnc -d 192.168.247.2 1025\n"
1013 "Loop back all data coming from remote node's UDP port 1025:\n"
1014 " --> ethnc -m -u 192.168.247.2 1025\n"
1016 "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1018 " --> ethnc -l 30000 -m\n",
1019 CMD_HANDLER(cmd_do_init_nc), (void *)&cmd_list_nc
1022 /** List of commands for lwip, defined as external */
1023 cmd_des_t const *cmd_list_nc[] = {