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){
81 struct netconn *netconn, *newconn;
83 struct netbuf *remoteData = NULL, *localData = NULL;
85 boolean_t ncStop = FALSE;
86 boolean_t flush = FALSE;
87 struct nc_arg *nc_arg = (struct nc_arg *) arg;
88 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
90 /* fill options from argument */
91 uint16_t portNO = nc_arg->portNO, srcPortNO = nc_arg->srcPortNO;
92 ip_addr_t remoteIP = nc_arg->remoteIP;
93 boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
94 boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
96 uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
101 /* switch off closing of tasks/threads */
105 /*** make connection ***/
106 while(!closeths){ /* shouldn't get here twice, used only for break which leads us down to unalocating of sources */
107 /* let nc initiator go */
108 if(thread && /* just in case --> */ nc_arg->args_coppied != NULL && xSemaphoreGive(nc_arg->args_coppied) != pdTRUE)break;
109 /* fill netconn struct */
110 netconn = netconn_new(udp?NETCONN_UDP:NETCONN_TCP);
112 err = ERR_NETCONN_NEW;
116 tries = 15; /* how many local ports to try */
117 /* bind filled netconn with local interface address and source port number */
118 while( tries-- && (err = netconn_bind(netconn, &(netif->ip_addr), srcPortNO) ) == ERR_USE && !closeths){
119 if(srcPortSpec)break; /* if port was explicitly specified (we shouldn't change user's port number just like that ;) ) */
123 if(err != ERR_OK || !tries)
125 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
130 /* adjust recvtimeout time and tries to different values, if user shouldn't loose control over cmd processor at any time */
131 netconn_set_recvtimeout(netconn, CONNECTING_TIMEO);
132 tries = CONNECTING_TRIES;
134 if(listen) /* -l <PORT> option */
136 if(!udp) /* TCP - make connection */
138 /* make listening netconn */
139 netconn_listen(netconn);
140 /* accept connection to newconn */
141 while( tries-- && (err = netconn_accept(netconn, &newconn)) == ERR_TIMEOUT && (thread || rpp_sci_read_nb(1, &input) != SUCCESS));
145 err = ERR_CONN_ACCEPT;
150 netconn_delete(netconn); /* we don't need listening netconn anymore */
155 while(tries-- && !closeths)
157 /* allow user to interrupt waiting for "udp connection" - in case this is not thread */
158 if(!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)){
159 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
160 err = ERR_CONNECTING;
164 if((err = netconn_recv(netconn, &remoteData)) == ERR_OK) /* wait for data, from which we will determine our peer address and portNO */
166 remoteIP = remoteData->addr;
167 portNO = remoteData->port;
168 if(test)netbuf_delete(remoteData);
173 if(err == ERR_TIMEOUT)continue;
183 err = ERR_CONNECTING;
189 if(!listen || (listen && udp) ) /* connect to remote node */
193 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 */
211 //netconn_set_recvtimeout(newconn, 1);
212 while(!closeths && index++ < 4294967295){
213 /* destroy all incomming data to prevent pbufs from running out */
214 /*while(remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT){
215 netbuf_delete(remoteData);
218 /* allow user to interrupt sending */
219 if(!thread && (rpp_sci_read_nb(1, &input) == SUCCESS))break;
220 strlen = sprintf(strbuf,"%d\r\n",index);
223 if((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK)break;
227 payload = netbuf_alloc(localData,strlen);
230 netbuf_take(localData,strbuf,strlen);
231 netbuf_len(localData) = strlen;
232 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
244 if(netLoop) /* -m option */
247 /* 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 */
249 payload = netbuf_alloc(localData,1);
252 netbuf_take(localData,&input,1);
253 netbuf_len(localData) = 1;
254 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
263 if(!thread && (rpp_sci_read_nb(1, &input) == SUCCESS))break; /* allow user to interrupt operation */
264 if( remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT )
269 while(p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
276 netconn_write(newconn, p->payload, p->len, NETCONN_COPY); /*NETCONN_DONTBLOCK*/
280 payload = netbuf_alloc(localData,p->len);
283 netbuf_take(localData,p->payload,p->len);
284 netbuf_len(localData) = p->len;
285 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
295 netbuf_delete(remoteData);
304 if(err == ERR_TIMEOUT)err = ERR_OK; /* timeout is not error here, this occurs on interrupt of while cycle */
308 /* only active user can control this section XXX: maybe should move to init startup condition handler */
311 /* INTERACTIVE PART */
313 /* receive remote data and print them to sci, receive sci data and write them to netconn */
316 if(rpp_sci_read_nb(1, &input) != SUCCESS) {
317 if( remoteData != NULL || (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT)
321 /* print remote data to SCI */
326 payload = p->payload;
329 rpp_sci_printf("%c",payload[index]);
334 netbuf_delete(remoteData);
339 break; /* receive error - e.g. newconn was closed */
342 if(err == ERR_TIMEOUT)err = ERR_OK;
346 // Backspace and Delete
347 if(input == 8 || input == 127) {
355 // Line feed or Carriage return
356 } else if(input == 10 || input == 13) {
357 in_buffer[buff_index] = 13;
359 in_buffer[buff_index] = 10;
365 // If is any printable character
366 } else if(isprint(input) || input == 9) {
368 // Store character and increment buffer index
369 in_buffer[buff_index] = input;
373 // Check if buffer is full and force flush
374 if(buff_index == BUF_SIZE - 3) {
377 // All other character stops nc
387 netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
391 payload = netbuf_alloc(localData,buff_index);
394 netbuf_take(localData,in_buffer,buff_index);
395 netbuf_len(localData) = buff_index;
396 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
412 if(thread)rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
414 if(udp && localData != NULL)netbuf_delete(localData);
415 if(remoteData != NULL)netbuf_delete(remoteData);
416 if(newconn != NULL && !udp)netconn_close(newconn);
417 netconn_delete(newconn);
420 nc_arg->err = err; /* only user controlled task is in front */
421 if(thread)vTaskDelete(NULL);
428 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
434 rpp_sci_printk("recv abrt\n");
437 /* print remote data to SCI */
441 payload = p->payload;
444 rpp_sci_printk("%c",payload[index]);
452 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
456 /* print remote data to SCI */
460 payload = p->payload;
463 rpp_sci_printk("%c",payload[index]);
471 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
474 err_t err = udp_connect(pcb, addr, port);
475 LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
476 udp_recv(pcb, nc_udp_recv_callback, NULL);
477 nc_udp_recv_callback(arg, pcb, p, addr, port);
480 void nc_err_callback(void *arg, err_t err)
482 rpp_sci_printk("err clbck\n");
483 LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
488 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
494 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
496 struct tcp_pcb **newone = arg;
497 *newone = newpcb; /* pass accepted connection to main app loop */
501 /* Set up the various callback functions */
502 tcp_recv(newpcb, nc_recv_callback);
503 tcp_err(newpcb, nc_err_callback);
504 tcp_sent(newpcb, nc_sent_callback);
509 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
512 /* Set up the various callback functions */
513 tcp_recv(tpcb, nc_recv_callback);
514 tcp_err(tpcb, nc_err_callback);
515 tcp_sent(tpcb, nc_sent_callback);
518 rpp_sci_printk("connected\n");
522 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
526 rpp_sci_printk("recv abrt\n");
531 if(tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY)!=ERR_OK){
532 rpp_sci_printk("error writing to newpcb - tcp_write\n");
535 if(tcp_output(tpcb)!=ERR_OK){ /* when we want to send data immediately */
536 rpp_sci_printk("newpcb output err - tcp\n");
544 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
549 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
552 rpp_sci_printk("error allocating pbuf - udp_send\n");
556 if(pbuf_take(pbuf, p->payload, p->len)!=ERR_OK)
558 rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
561 if(udp_send (pcb, pbuf)!=ERR_OK)
563 rpp_sci_printk("error sending to pcb - udp_send\n");
574 * this function has two operational modes, depending on LwIP settings
575 * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
576 * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
578 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
580 if(!isPostInitialized())
582 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
586 uint16_t portNO, srcPortNO = 0;
588 boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
592 /* initialize arguments and thread name */
594 uint8_t name[5] = "nc";
596 struct nc_arg nc_arg; /* create space for handing args to nc_run() */
597 nc_arg.thread = FALSE;
600 boolean_t flush = FALSE;
602 struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
603 struct tcp_pcb *tpcb, *tnewpcb;
605 struct pbuf *p; /* udp send */
608 /* examine parameters */
609 for(pindex = 1;param[pindex] != 0;pindex++)
611 if (strncmp((char *) param[pindex], "-h", 3) == 0) {
614 } else if (strncmp((char *) param[pindex], "-u", 3) == 0) {
617 } else if (strncmp((char *) param[pindex], "-t", 3) == 0) {
618 nc_arg.thread = TRUE;
619 } else if (strncmp((char *) param[pindex], "-c", 3) == 0) {
623 } else if (strncmp((char *) param[pindex], "-l", 3) == 0 && !srcPortSpec) {
625 srcPortNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
628 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -l option\r\n");
632 } else if (strncmp((char *) param[pindex], "-p", 3) == 0 && !srcPortSpec) {
633 srcPortNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
636 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -p option\r\n");
640 } else if (strncmp((char *) param[pindex], "-m", 3) == 0) {
642 } else if (strncmp((char *) param[pindex], "-d", 3) == 0) {
644 } else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t *) param[pindex])) == SUCCESS ) {
645 portNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
648 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
652 rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
659 /* TODO: additional testing of parameters mutual exclusion */
660 /* valid combinations:
661 nc <addr> <port> [-p <port>] [-u] [-t]
662 nc -l <port> [-u] [-t]
663 nc <addr> <port> -m [-p <port>] [-u] [-t]
664 nc <addr> <port> -d [-p <port>] [-u] [-t]
665 nc -l <port> -m [-u] [-t]
666 nc -l <port> -d [-u] [-t]
669 /* usage of command */
670 if(help || !param[1])
672 rpp_sci_printf("-u udp, -t thread, -c close tasks, -l listen, -p source port, -m ping/mirror, -d test\r\n\n");
673 rpp_sci_printf("usage:\tnc -l <port> [-u] [-m [-t] | -d [-t]]\r\n\t\tlistens on port for connection\r\n");
674 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");
675 rpp_sci_printf("\tnc -c\r\n\t\tdeletes all running threads.\r\n");
676 rpp_sci_printf("opts:\t-t run as stand alone task\r\n\t-c close all stand alone tasks\r\n");
677 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");
678 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");
679 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");
683 /* determine srcPortNO from predefined value if not done yet (from argument given) */
687 srcPortNO = srcPort++;
690 #if !NO_SYS /* netconn api */
693 nc_arg.srcPortNO = srcPortNO;
694 nc_arg.portNO = portNO;
695 nc_arg.remoteIP.addr = remoteIP.addr;
697 nc_arg.listen = listen;
698 nc_arg.netLoop = netLoop;
700 nc_arg.srcPortSpec = srcPortSpec;
703 /* prepare semaphore */
704 vSemaphoreCreateBinary(nc_arg.args_coppied);
705 xSemaphoreTake(nc_arg.args_coppied, 0);
706 /* add number to task name */
707 taskNameNum = (taskNameNum%100);
708 name[2] = (taskNameNum/10) + '0';
709 name[3] = (taskNameNum%10) + '0';
710 rpp_sci_printf("STARTING THREAD: %s\r\n", name);
713 if((err = xTaskCreate(&run_nc,(const signed char *) name, ncTaskStackSize, &nc_arg, ncTaskPriority, NULL)) == pdPASS){
714 /* block on semaphore, till new thread copies arg to own stack */
715 xSemaphoreTake( nc_arg.args_coppied, portMAX_DELAY );
716 vSemaphoreDelete(nc_arg.args_coppied);
718 vSemaphoreDelete(nc_arg.args_coppied);
728 #else /* raw LwIP API */
735 LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
736 if(pcb == NULL)return -1;
737 err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
738 CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
739 if(err != ERR_OK)return -1;
744 LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
745 if(tpcb == NULL)return -1;
746 err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
747 CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
748 if(err != ERR_OK)return -1;
755 tpcb = tcp_listen(tpcb);
756 LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
757 /* initialize callback arg and accept callback */
758 tcp_arg(tpcb, &tnewpcb);
759 tcp_accept(tpcb, nc_accept_callback);
765 err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
766 LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
773 udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
777 err = udp_connect(pcb, &remoteIP, portNO);
778 LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
780 /* set udp recv callback */
781 udp_recv(pcb, nc_udp_recv_callback, NULL);
785 /* wait for connection to be established */
790 if(rpp_sci_read_nb(1, &input) == SUCCESS)
795 sys_check_timeouts();
796 vTaskDelay(10); /* just because we have no other business here */
798 if(!udp && listen && tcp_close(tpcb) != ERR_OK)rpp_sci_printk("closing listening tcp pcb err\n"); /* close listening pcb */
801 /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
803 /*************************************** 1 mirror mode *****************************************/
805 if(netLoop) /* -m option */
808 /* 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 */
809 /* if(udp && !listen){
810 payload = netbuf_alloc(localData,1);
813 netbuf_take(localData,&input,1);
814 netbuf_len(localData) = 1;
815 if((err = netconn_send(newconn, localData)) != ERR_OK)break;
823 /* register callback function which sends all the recevd data back to remote host */
826 tcp_recv(tnewpcb, nc_tmirror_callback);
830 udp_recv(pcb, nc_umirror_callback, NULL);
833 while(rpp_sci_read_nb(1, &input) != SUCCESS)
835 sys_check_timeouts();
841 /*************************************** 2 testing mode *****************************************/
843 if(test) /* -d option; sends packets to the opposite node and doesn't receive anything */
848 //netconn_set_recvtimeout(newconn, 1);
849 while(index++ < 4294967295){
850 /* allow user to interrupt sending */
851 if(rpp_sci_read_nb(1, &input) == SUCCESS)break;
852 strlen = sprintf(strbuf,"%d\r\n",index);
855 sys_check_timeouts();
856 if(tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY)!=ERR_OK){
857 rpp_sci_printf("error writing to newpcb - tcp_write testing\n");
860 if(tcp_output(tnewpcb)!=ERR_OK){ /* when we want to send data immediately */
861 rpp_sci_printf("newpcb output err - tcp testing\n");
867 p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
870 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
873 if(pbuf_take(p, strbuf, strlen)!=ERR_OK)
875 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
878 if(udp_send (pcb, p)!=ERR_OK)
880 rpp_sci_printf("error sending to pcb - udp_send testing\n");
888 /*************************************** 3 interactive mode *****************************************/
892 if(!udp && tnewpcb->state != ESTABLISHED)
897 if(rpp_sci_read_nb(1, &input) != SUCCESS) {
898 /* updating lwip timers here */
899 sys_check_timeouts();
903 // Backspace and Delete
904 if(input == 8 || input == 127) {
912 // Line feed or Carriage return
913 } else if(input == 10 || input == 13) {
914 in_buffer[buff_index] = 13;
916 in_buffer[buff_index] = 10;
922 // If is any printable character
923 } else if(isprint(input) || input == 9) {
925 // Store character and increment buffer index
926 in_buffer[buff_index] = input;
930 // Check if buffer is full and force flush
931 if(buff_index == BUF_SIZE - 3) {
934 // All other character stops nc
942 while(!udp && !ncStop && !sent)
944 sys_check_timeouts();
950 if(tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY)!=ERR_OK){
951 rpp_sci_printf("error writing to newpcb - tcp_write\n");
954 if(tcp_output(tnewpcb)!=ERR_OK){ /* when we want to send data immediately */
955 rpp_sci_printf("newpcb output err - tcp\n");
961 p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
964 rpp_sci_printf("error allocating pbuf - udp_send\n");
967 if(pbuf_take(p, in_buffer, buff_index)!=ERR_OK)
969 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
972 if(udp_send (pcb, p)!=ERR_OK)
974 rpp_sci_printf("error sending to pcb - udp_send\n");
987 /* close connection and clean */
990 tcp_recv(tnewpcb, NULL);
991 err = tcp_close(tnewpcb);
993 rpp_sci_printf("newpcb closing error\n");
994 /* closing failed, try again later */
995 LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
996 tcp_recv(tnewpcb, nc_recv_callback);
998 /* closing succeeded */
999 tcp_arg(tnewpcb, NULL);
1000 tcp_sent(tnewpcb, NULL);
1005 udp_disconnect(pcb);
1015 cmd_des_t const cmd_des_nc={
1017 "ethnc","Start very simple netcat",
1019 "### Command syntax ###\n"
1021 " ethnc <IP> <PORT> [-p <PORT>] [-u] [-m [-t] | -d [-t]] [-c]\n"
1022 " ethnc -l <PORT> [-u] [-m [-t] | -d [-t]] [-c]\n"
1024 "### Description ###\n"
1026 "Netcat is a program which allows to communicate using TCP or UDP\n"
1027 "protocols. First a connection is established by either:\n"
1029 "- connecting to a specified IP address and PORT (without option -l) or by\n"
1030 "- listening for a new connection on a given PORT (with option -l).\n"
1032 "When no -u option is specified ethnc command works with TCP\n"
1033 "connections. With -u option UDP communication is used. Listening for\n"
1034 "connection on UDP means waiting for reception of any UDP datagram.\n"
1036 "Once the connection is established the command works in one of the\n"
1037 "following modes:\n"
1039 "- 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"
1040 "- sending of testing data (increasing ASCII formatted numbers) (option -d),\n"
1041 "- looping of incoming data back to the connection's peer (option -m).\n"
1043 "Note: When trying to use a same local TCP port number multiple times\n"
1044 "in a row (-l or -p options) there might be several minutes delay\n"
1045 "before the port is available after closing the previous connection.\n"
1046 "This situation is singled with ERROR 31.\n"
1050 "- -p specifies local port for outgoing connections.\n"
1051 "- -u use UDP protocol instead of the default TCP.\n"
1052 "- -t send and/or receive data in a background thread (works only with -d or -m options).\n"
1053 "- -c stop all running background tasks\n"
1055 "### Examples ###\n"
1057 "Listen for incoming TCP connection on local port 2000:\n"
1058 " --> ethnc -l 2000\n"
1060 "Connect using TCP to address 192.168.247.15 to remote port 80 using local port 1500:\n"
1061 " --> ethnc 192.168.247.15 80 -p 1500\n"
1063 "Send testing data to the remote node:\n"
1064 " --> ethnc -d 192.168.247.2 1025\n"
1066 "Loop back all data coming from remote node's UDP port 1025:\n"
1067 " --> ethnc -m -u 192.168.247.2 1025\n"
1069 "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1071 " --> ethnc -l 30000 -m\n",
1072 CMD_HANDLER(cmd_do_init_nc), (void *)&cmd_list_nc
1075 /** List of commands for lwip, defined as external */
1076 cmd_des_t const *cmd_list_nc[]={