]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp-test-sw/commands/cmd_nc.c
Fix warnings
[pes-rpp/rpp-test-sw.git] / rpp-test-sw / commands / cmd_nc.c
1 /*
2  * Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
3  *
4  * Created on: Aug 9, 2013
5  *
6  * Authors:
7  *     - Jan Doležal
8  *
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.
13  *
14  * File : cmd_lwip.c
15  *
16  * Abstract:
17  *      This file contains commands for LwIP test
18  *
19  */
20
21 #include "cmd_nc.h"
22
23 #ifndef DOCGEN
24
25 #include <string.h>
26 #include <ctype.h>
27
28 #include "rpp/rpp.h"
29 #include "lwip/udp.h"
30 #if !NO_SYS
31 #include "lwip/api.h" //netconn
32 #else
33 #include "lwip/timers.h" //for updating timers, when NO_SYS == 1
34 #include "lwip/tcp.h"
35 #include "lwip/tcp_impl.h"
36 #endif
37
38 #define INTERFACE_INSTANCE_NUMBER 0
39
40 #define BUF_SIZE 80
41 /* only for use in interactive mode (not thread) */
42 char in_buffer[BUF_SIZE];
43 uint8_t buff_index = 0;
44
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 */
50
51 #if !NO_SYS
52 uint8_t tasks_running = 0, taskNameNum = 0;
53 boolean_t closeths; /* variable controling threads closing */
54
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 */
56 struct nc_arg {
57         uint16_t portNO, srcPortNO;
58         ip_addr_t remoteIP;
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;
62         err_t err;
63 };
64
65
66 /* nc task */
67 void run_nc(void *arg)
68 {
69         err_t err = ERR_OK;
70         uint8_t input = 0;
71         uint8_t tries;
72         uint32_t index;
73         uint8_t *payload;
74         struct netconn *netconn, *newconn;
75
76         newconn = NULL;
77         struct netbuf *remoteData = NULL, *localData = NULL;
78         struct pbuf *p;
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);
83
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 */
89 #if DEBUG
90         uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
91 #endif
92         tasks_running++;
93
94
95         /* switch off closing of tasks/threads */
96         closeths = FALSE;
97
98
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;
107                         break;
108                 }
109
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 ;) ) */
114                         srcPort++;
115                         srcPortNO = srcPort;
116                 }
117                 if (err != ERR_OK || !tries) {
118                         newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
119                         err = ERR_BINDING;
120                         break;
121                 }
122
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;
126
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)) ;
133                                 if (err != ERR_OK) {
134                                         newconn = netconn;
135                                         err = ERR_CONN_ACCEPT;
136                                         break;
137                                 }
138                                 else
139                                         netconn_delete(netconn);  /* we don't need listening netconn anymore */
140                         }
141                         else
142                         {
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;
148                                                 break;
149                                         }
150
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);
155                                                 break;
156                                         }
157                                         else
158                                         {
159                                                 if (err == ERR_TIMEOUT) continue;
160                                                 else
161                                                 {
162                                                         newconn = netconn;
163                                                         break;
164                                                 }
165                                         }
166                                 }
167                                 if (!tries) {
168                                         newconn = netconn;
169                                         err = ERR_CONNECTING;
170                                         break;
171                                 }
172                         }
173                 }
174
175                 if (!listen || (listen && udp) ) { /* connect to remote node */
176                         newconn = netconn;
177                         netconn = NULL;
178                         if ( ( err = netconn_connect(newconn, &remoteIP, portNO) ) != ERR_OK )
179                                 break;
180                 }
181
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);
184
185                 if (udp && (localData = netbuf_new()) == NULL) {
186                         err = ERR_MEM;
187                         break;
188                 }
189
190                 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
191                         index = 0;
192                         char strbuf[13];
193                         int strlen;
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);
199                                     remoteData = NULL;
200                                    }*/
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);
204                                 if (!udp) {
205                                         if ((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK) break;
206                                 }
207                                 else
208                                 {
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;
214                                         }
215                                         else
216                                         {
217                                                 err = ERR_MEM;
218                                                 break;
219                                         }
220                                 }
221                         }
222                         break;
223                 }
224
225                 if (netLoop) { /* -m option */
226                         err = ERR_OK;
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) {
231                                         input = 0;
232                                         netbuf_take(localData,&input,1);
233                                         netbuf_len(localData) = 1;
234                                         if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
235                                 }
236                                 else
237                                 {
238                                         err = ERR_MEM;
239                                         break;
240                                 }
241                         }
242                         while (!closeths) {
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 ) {
245                                         if (err == ERR_OK) {
246                                                 p = remoteData->p;
247                                                 /**/
248                                                 while (p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
249                                                         pbuf_free(p);
250                                                 /**/
251                                                 while (p != NULL) {
252                                                         if (!udp)
253                                                                 netconn_write(newconn, p->payload, p->len, NETCONN_COPY);  /*NETCONN_DONTBLOCK*/
254                                                         else
255                                                         {
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;
261                                                                 }
262                                                                 else
263                                                                 {
264                                                                         err = ERR_MEM;
265                                                                         break;
266                                                                 }
267                                                         }
268                                                         p = p->next;
269                                                 }
270                                                 netbuf_delete(remoteData);
271                                                 remoteData = NULL;
272                                         }
273                                         else
274                                                 break;
275                                 }
276                         }
277                         if (err == ERR_TIMEOUT) err = ERR_OK;  /* timeout is not error here, this occurs on interrupt of while cycle */
278                         break;
279                 }
280
281                 /* only active user can control this section XXX: maybe should move to init startup condition handler */
282                 if (thread) break;
283
284                 /* INTERACTIVE PART */
285
286                 /* receive remote data and print them to sci, receive sci data and write them to netconn */
287                 while (!ncStop) {
288                         if (rpp_sci_read_nb(1, &input) != SUCCESS) {
289                                 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT) {
290                                         if (err == ERR_OK) {
291                                                 /* print remote data to SCI */
292                                                 p = remoteData->p;
293                                                 while (p != NULL) {
294                                                         index = 0;
295                                                         payload = p->payload;
296                                                         while (index < p->len) {
297                                                                 rpp_sci_printf("%c",payload[index]);
298                                                                 index++;
299                                                         }
300                                                         p = p->next;
301                                                 }
302                                                 netbuf_delete(remoteData);
303                                                 remoteData = NULL;
304                                         }
305                                         else
306                                                 break;  /* receive error - e.g. newconn was closed */
307                                 }
308                                 if (err == ERR_TIMEOUT) err = ERR_OK;
309                                 continue;
310                         }
311
312                         // Backspace and Delete
313                         if (input == 8 || input == 127) {
314                                 if (buff_index > 0) {
315                                         buff_index--;
316                                         rpp_sci_putc('\b');
317                                         rpp_sci_putc(' ' );
318                                         rpp_sci_putc('\b');
319                                 }
320
321                                 // Line feed or Carriage return
322                         }
323                         else if (input == 10 || input == 13) {
324                                 in_buffer[buff_index] = 13;
325                                 buff_index++;
326                                 in_buffer[buff_index] = 10;
327                                 buff_index++;
328                                 flush = TRUE;
329                                 rpp_sci_putc('\r');
330                                 rpp_sci_putc('\n');
331
332                                 // If is any printable character
333                         }
334                         else if (isprint(input) || input == 9) {
335
336                                 // Store character and increment buffer index
337                                 in_buffer[buff_index] = input;
338                                 buff_index++;
339                                 rpp_sci_putc(input);
340
341                                 // Check if buffer is full and force flush
342                                 if (buff_index == BUF_SIZE - 3)
343                                         flush = TRUE;
344                                 // All other character stops nc
345                         }
346                         else {
347                                 ncStop = TRUE;
348                                 flush = TRUE;
349                         }
350
351                         if (flush) {
352                                 if (!udp)
353                                         netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
354                                 else
355                                 {
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;
361                                         }
362                                         else
363                                         {
364                                                 err = ERR_MEM;
365                                                 break;
366                                         }
367                                 }
368                                 // Reset variables
369                                 buff_index = 0;
370                                 flush = FALSE;
371                         }
372                 }
373                 break;
374         }
375 #ifdef DEBUG
376         if (thread) rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
377 #endif
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);
382         tasks_running--;
383         if (!thread)
384                 nc_arg->err = err;  /* only user controlled task is in front */
385         if (thread) vTaskDelete(NULL);
386 }
387 #else /* if !NO_SYS */
388 boolean_t connected;
389 boolean_t sent;
390 boolean_t ncStop;
391
392 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
393 {
394         uint16_t index;
395         uint8_t *payload;
396
397         if (err == ERR_ABRT) {
398                 rpp_sci_printk("recv abrt\n");
399                 return ERR_ABRT;
400         }
401         /* print remote data to SCI */
402         while (p != NULL) {
403                 index = 0;
404                 payload = p->payload;
405                 while (index < p->len) {
406                         rpp_sci_printk("%c",payload[index]);
407                         index++;
408                 }
409                 p = p->next;
410         }
411         return ERR_OK;
412 }
413
414 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
415 {
416         uint16_t index;
417         uint8_t *payload;
418
419         /* print remote data to SCI */
420         while (p != NULL) {
421                 index = 0;
422                 payload = p->payload;
423                 while (index < p->len) {
424                         rpp_sci_printk("%c",payload[index]);
425                         index++;
426                 }
427                 p = p->next;
428         }
429         //pbuf_free(p);
430 }
431
432 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
433 {
434         connected = TRUE;
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);
439 }
440
441 void nc_err_callback(void *arg, err_t err)
442 {
443         rpp_sci_printk("err clbck\n");
444         LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
445
446         ncStop = TRUE;
447 }
448
449 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
450 {
451         sent = TRUE;
452         return ERR_OK;
453 }
454
455 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
456 {
457         struct tcp_pcb **newone = arg;
458
459         *newone = newpcb; /* pass accepted connection to main app loop */
460
461         connected = TRUE;
462
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);
467
468         return ERR_OK;
469 }
470
471 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
472 {
473
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);
478
479         connected = TRUE;
480         rpp_sci_printk("connected\n");
481         return ERR_OK;
482 }
483
484 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
485 {
486         if (err == ERR_ABRT) {
487                 rpp_sci_printk("recv abrt\n");
488                 return ERR_ABRT;
489         }
490         while (p != NULL) {
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");
493                         return -1;
494                 }
495                 if (tcp_output(tpcb) != ERR_OK) { /* when we want to send data immediately */
496                         rpp_sci_printk("newpcb output err - tcp\n");
497                         return -1;
498                 }
499                 p = p->next;
500         }
501         return ERR_OK;
502 }
503
504 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
505 {
506         struct pbuf *pbuf;
507
508         while (p != NULL) {
509                 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
510                 if (pbuf == NULL) {
511                         rpp_sci_printk("error allocating pbuf - udp_send\n");
512                         //p = p->next;
513                         continue;
514                 }
515                 if (pbuf_take(pbuf, p->payload, p->len) != ERR_OK) {
516                         rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
517                         continue;
518                 }
519                 if (udp_send(pcb, pbuf) != ERR_OK) {
520                         rpp_sci_printk("error sending to pcb - udp_send\n");
521                         continue;
522                 }
523                 p = p->next;
524         }
525 }
526
527
528 #endif /* !NO_SYS */
529
530 /*
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
534  */
535 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
536 {
537         if (!isPostInitialized()) {
538                 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
539                 return FAILURE;
540         }
541         err_t err = ERR_OK;
542         uint16_t portNO, srcPortNO = 0;
543         ip_addr_t remoteIP;
544         boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
545         uint8_t pindex;
546
547         buff_index = 0;
548         /* initialize arguments and thread name */
549 #if !NO_SYS
550         char name[5] = "nc";
551         name[4] = '\0';
552         struct nc_arg nc_arg; /* create space for handing args to nc_run() */
553         nc_arg.thread = FALSE;
554 #else
555         uint8_t input = 0;
556         boolean_t flush = FALSE;
557         uint32_t index;
558         struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
559         struct tcp_pcb *tpcb, *tnewpcb;
560         struct udp_pcb *pcb;
561         struct pbuf *p; /* udp send */
562 #endif
563
564         /* examine parameters */
565         for (pindex = 1; param[pindex] != 0; pindex++) {
566                 if        (strncmp((char *)param[pindex], "-h", 3) == 0) {
567                         help = TRUE;
568                         break;
569                 }
570                 else if (strncmp((char *)param[pindex], "-u", 3) == 0) {
571                         udp = TRUE;
572 #if !NO_SYS
573                 }
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) {
577                         closeths = TRUE;
578                         return ERR_OK;
579 #endif
580                 }
581                 else if (strncmp((char *)param[pindex], "-l", 3) == 0 && !srcPortSpec) {
582                         listen = TRUE;
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");
586                                 return BAD_PORT_NO;
587                         }
588                         srcPortSpec = TRUE;
589                 }
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");
594                                 return BAD_PORT_NO;
595                         }
596                         srcPortSpec = TRUE;
597                 }
598                 else if (strncmp((char *)param[pindex], "-m", 3) == 0)
599                         netLoop = TRUE;
600                 else if (strncmp((char *)param[pindex], "-d", 3) == 0)
601                         test = TRUE;
602                 else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t *)param[pindex])) == SUCCESS ) {
603                         portNO = rpp_eth_portStrToInt((uint8_t *)param[++pindex]);
604                         if (portNO == 0) {
605                                 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
606                                 return BAD_PORT_NO;
607                         }
608                 }
609                 else {
610                         rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
611                         help = TRUE;
612                         err = BAD_OPTION;
613                         break;
614                 }
615         }
616
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]
625          */
626
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");
637                 return err;
638         }
639
640         /* determine srcPortNO from predefined value if not done yet (from argument given) */
641         if (!srcPortSpec)
642                 //udp_new_port();
643                 srcPortNO = srcPort++;
644
645 #if !NO_SYS /* netconn api */
646
647         /* prepare args */
648         nc_arg.srcPortNO = srcPortNO;
649         nc_arg.portNO = portNO;
650         nc_arg.remoteIP.addr = remoteIP.addr;
651         nc_arg.udp = udp;
652         nc_arg.listen = listen;
653         nc_arg.netLoop = netLoop;
654         nc_arg.test = test;
655         nc_arg.srcPortSpec = srcPortSpec;
656
657         if (nc_arg.thread) {
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);
666                 taskNameNum++;
667                 /* start thread */
668                 if ((err = xTaskCreate(&run_nc, 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);
672                 }
673                 else {
674                         vSemaphoreDelete(nc_arg.args_coppied);
675                         return err;
676                 }
677         }
678         else
679         {
680                 taskNameNum++;
681                 run_nc(&nc_arg);
682                 return nc_arg.err;
683         }
684 #else /* raw LwIP API */
685         ncStop = FALSE;
686         connected = FALSE;
687         sent = TRUE;
688         if (udp) {
689                 pcb = udp_new();
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;
695         }
696         else
697         {
698                 tpcb = tcp_new();
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;
704         }
705
706         if (!udp) {
707                 if (listen) {
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);
713                 }
714                 else
715                 {
716                         tnewpcb = tpcb;
717                         tpcb = NULL;
718                         err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
719                         LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
720                 }
721         }
722         else
723         {
724                 if (listen)
725                         udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
726                 else
727                 {
728                         err = udp_connect(pcb, &remoteIP, portNO);
729                         LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
730                         //connected = TRUE;
731                         /* set udp recv callback */
732                         udp_recv(pcb, nc_udp_recv_callback, NULL);
733                 }
734         }
735
736         /* wait for connection to be established */
737         if (listen || !udp) {
738                 while (!connected) {
739                         if (rpp_sci_read_nb(1, &input) == SUCCESS) {
740                                 ncStop = TRUE;
741                                 break;
742                         }
743                         sys_check_timeouts();
744                         vTaskDelay(10); /* just because we have no other business here */
745                 }
746                 if (!udp && listen && tcp_close(tpcb) != ERR_OK) rpp_sci_printk("closing listening tcp pcb err\n");  /* close listening pcb */
747         }
748
749         /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
750         do {
751                 /*************************************** 1 mirror mode *****************************************/
752
753                 if (netLoop) { /* -m option */
754                         err = ERR_OK;
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);
758                 if(payload != NULL){
759                     input = 0;
760                     netbuf_take(localData,&input,1);
761                     netbuf_len(localData) = 1;
762                     if((err = netconn_send(newconn, localData)) != ERR_OK)break;
763                 }
764                 else
765                 {
766                     err = ERR_MEM;
767                     break;
768                 }
769             }*/
770                         /* register callback function which sends all the recevd data back to remote host */
771                         if (!udp)
772                                 tcp_recv(tnewpcb, nc_tmirror_callback);
773                         else
774                                 udp_recv(pcb, nc_umirror_callback, NULL);
775
776                         while (rpp_sci_read_nb(1, &input) != SUCCESS) {
777                                 sys_check_timeouts();
778                                 vTaskDelay(10);
779                         }
780                         break;
781                 }
782
783                 /*************************************** 2 testing mode *****************************************/
784
785                 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
786                         index = 0;
787                         char strbuf[13];
788                         int strlen;
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);
794                                 if (!udp) {
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");
798                                                 break;
799                                         }
800                                         if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
801                                                 rpp_sci_printf("newpcb output err - tcp testing\n");
802                                                 break;
803                                         }
804                                 }
805                                 else
806                                 {
807                                         p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
808                                         if (p == NULL) {
809                                                 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
810                                                 continue;
811                                         }
812                                         if (pbuf_take(p, strbuf, strlen) != ERR_OK) {
813                                                 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
814                                                 continue;
815                                         }
816                                         if (udp_send(pcb, p) != ERR_OK) {
817                                                 rpp_sci_printf("error sending to pcb - udp_send testing\n");
818                                                 continue;
819                                         }
820                                 }
821                         }
822                         break;
823                 }
824
825                 /*************************************** 3 interactive mode *****************************************/
826
827                 while (!ncStop) {
828                         if (!udp && tnewpcb->state != ESTABLISHED) {
829                                 ncStop = TRUE;
830                                 break;
831                         }
832                         if (rpp_sci_read_nb(1, &input) != SUCCESS) {
833                                 /* updating lwip timers here */
834                                 sys_check_timeouts();
835                                 continue;
836                         }
837
838                         // Backspace and Delete
839                         if (input == 8 || input == 127) {
840                                 if (buff_index > 0) {
841                                         buff_index--;
842                                         rpp_sci_putc('\b');
843                                         rpp_sci_putc(' ' );
844                                         rpp_sci_putc('\b');
845                                 }
846
847                                 // Line feed or Carriage return
848                         }
849                         else if (input == 10 || input == 13) {
850                                 in_buffer[buff_index] = 13;
851                                 buff_index++;
852                                 in_buffer[buff_index] = 10;
853                                 buff_index++;
854                                 flush = TRUE;
855                                 rpp_sci_putc('\r');
856                                 rpp_sci_putc('\n');
857
858                                 // If is any printable character
859                         }
860                         else if (isprint(input) || input == 9) {
861
862                                 // Store character and increment buffer index
863                                 in_buffer[buff_index] = input;
864                                 buff_index++;
865                                 rpp_sci_putc(input);
866
867                                 // Check if buffer is full and force flush
868                                 if (buff_index == BUF_SIZE - 3)
869                                         flush = TRUE;
870                                 // All other character stops nc
871                         }
872                         else {
873                                 ncStop = TRUE;
874                                 flush = TRUE;
875                         }
876
877                         if (flush) {
878                                 while (!udp && !ncStop && !sent) {
879                                         sys_check_timeouts();
880                                         vTaskDelay(10);
881                                 }
882                                 if (ncStop) break;
883                                 if (!udp) {
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");
886                                                 continue;
887                                         }
888                                         if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
889                                                 rpp_sci_printf("newpcb output err - tcp\n");
890                                                 continue;
891                                         }
892                                 }
893                                 else
894                                 {
895                                         p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
896                                         if (p == NULL) {
897                                                 rpp_sci_printf("error allocating pbuf - udp_send\n");
898                                                 continue;
899                                         }
900                                         if (pbuf_take(p, in_buffer, buff_index) != ERR_OK) {
901                                                 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
902                                                 continue;
903                                         }
904                                         if (udp_send(pcb, p) != ERR_OK) {
905                                                 rpp_sci_printf("error sending to pcb - udp_send\n");
906                                                 continue;
907                                         }
908                                 }
909                                 // Reset variables
910                                 sent = FALSE;
911                                 buff_index = 0;
912                                 flush = FALSE;
913                         }
914                 }
915
916         } while (0);
917
918 /* close connection and clean */
919         if (!udp) {
920                 tcp_recv(tnewpcb, NULL);
921                 err = tcp_close(tnewpcb);
922                 if (err != ERR_OK) {
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);
927                 }
928                 else {
929                         /* closing succeeded */
930                         tcp_arg(tnewpcb, NULL);
931                         tcp_sent(tnewpcb, NULL);
932                 }
933         }
934         else
935         {
936                 udp_disconnect(pcb);
937                 udp_remove(pcb);
938         }
939         buff_index = 0;
940 #endif /* if !NO_SYS */
941         return ERR_OK;
942 }
943
944 #endif  /* DOCGEN */
945
946 cmd_des_t const cmd_des_nc = {
947         0,CDESM_SPACE_SEP,
948         "ethnc","Start very simple netcat",
949
950         "### Command syntax ###\n"
951         "\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"
954         "\n"
955         "### Description ###\n"
956         "\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"
959         "\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"
962         "\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"
966         "\n"
967         "Once the connection is established the command works in one of the\n"
968         "following modes:\n"
969         "\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"
973         "\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"
978         "\n"
979         "Other options:\n"
980         "\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"
985         "\n"
986         "### Examples ###\n"
987         "\n"
988         "Listen for incoming TCP connection on local port 2000:\n"
989         "     --> ethnc -l 2000\n"
990         "\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"
993         "\n"
994         "Send testing data to the remote node:\n"
995         "     --> ethnc -d 192.168.247.2 1025\n"
996         "\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"
999         "\n"
1000         "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1001         "back:\n"
1002         "     --> ethnc -l 30000 -m\n",
1003         CMD_HANDLER(cmd_do_init_nc), (void *)&cmd_list_nc
1004 };
1005
1006 /** List of commands for lwip, defined as external */
1007 cmd_des_t const *cmd_list_nc[] = {
1008         &cmd_des_nc,
1009         NULL
1010 };