浏览代码

move net/apps to lwip folder

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1484 bbd45198-f89e-11dd-88c7-29a3b14d5316
mbbill@gmail.com 14 年之前
父节点
当前提交
70bafa328a

+ 1 - 1
components/net/SConscript

@@ -1,4 +1,4 @@
-# for libc component
+# for network related component
 import os
 Import('RTT_ROOT')
 

+ 7 - 1
components/net/lwip-1.4.0/SConscript

@@ -81,6 +81,12 @@ if GetDepend(['RT_LWIP_PPP']):
     src += ppp_src
     path += [RTT_ROOT + '/components/net/lwip-1.4.0/src/netif/ppp']
 
-group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP', 'RT_LWIP_VER140'], CPPPATH = path)
+# For testing apps
+if GetDepend(['RT_USING_NETUTILS']):
+    src += Glob('./apps/*.c')
+
+# group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP'], CPPPATH = path)
+# Switch to this branch after lwip1.4 is stable enough.
+group = DefineGroup('LwIP', src, depend = ['NOT_USED'], CPPPATH = path)
 
 Return('group')

+ 7 - 7
components/net/apps/SConscript → components/net/lwip-1.4.0/apps/SConscript

@@ -1,7 +1,7 @@
-Import('RTT_ROOT')
-from building import *
-
-src   = Glob('*.c')
-group = DefineGroup('netutils', src, depend = ['RT_USING_NETUTILS'])
-
-Return('group')
+Import('RTT_ROOT')
+from building import *
+
+src   = Glob('*.c')
+group = DefineGroup('netutils', src, depend = ['RT_USING_NETUTILS'])
+
+Return('group')

+ 216 - 216
components/net/apps/chargen.c → components/net/lwip-1.4.0/apps/chargen.c

@@ -1,216 +1,216 @@
-#include <rtthread.h>
-
-#include "lwip/sockets.h"
-#define MAX_SERV                 32         /* Maximum number of chargen services. Don't need too many */
-#define CHARGEN_THREAD_NAME      "chargen"
-#if RT_THREAD_PRIORITY_MAX == 32
-#define CHARGEN_PRIORITY         20        /* Really low priority */
-#else
-#define CHARGEN_PRIORITY         200       /* Really low priority */
-#endif
-#define CHARGEN_THREAD_STACKSIZE 1024
-struct charcb
-{
-    struct charcb *next;
-    int socket;
-    struct sockaddr_in cliaddr;
-    socklen_t clilen;
-    char nextchar;
-};
-
-static struct charcb *charcb_list = 0;
-static int do_read(struct charcb *p_charcb);
-static void close_chargen(struct charcb *p_charcb);
-
-/**************************************************************
- * void chargen_thread(void *arg)
- *
- * chargen task. This server will wait for connections on well
- * known TCP port number: 19. For every connection, the server will
- * write as much data as possible to the tcp port.
- **************************************************************/
-static void chargen_thread(void *arg)
-{
-    int listenfd;
-    struct sockaddr_in chargen_saddr;
-    fd_set readset;
-    fd_set writeset;
-    int i, maxfdp1;
-    struct charcb *p_charcb;
-
-    /* First acquire our socket for listening for connections */
-    listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-
-    LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
-    memset(&chargen_saddr, 0, sizeof(chargen_saddr));
-    chargen_saddr.sin_family = AF_INET;
-    chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
-    chargen_saddr.sin_port = htons(19);     // Chargen server port
-
-    if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
-        LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
-
-    /* Put socket into listening mode */
-    if (lwip_listen(listenfd, MAX_SERV) == -1)
-        LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
-
-    /* Wait forever for network input: This could be connections or data */
-    for (;;)
-    {
-        maxfdp1 = listenfd+1;
-
-        /* Determine what sockets need to be in readset */
-        FD_ZERO(&readset);
-        FD_ZERO(&writeset);
-        FD_SET(listenfd, &readset);
-        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
-        {
-            if (maxfdp1 < p_charcb->socket + 1)
-                maxfdp1 = p_charcb->socket + 1;
-            FD_SET(p_charcb->socket, &readset);
-            FD_SET(p_charcb->socket, &writeset);
-        }
-
-        /* Wait for data or a new connection */
-        i = lwip_select(maxfdp1, &readset, &writeset, 0, 0);
-
-        if (i == 0) continue;
-
-        /* At least one descriptor is ready */
-        if (FD_ISSET(listenfd, &readset))
-        {
-            /* We have a new connection request!!! */
-            /* Lets create a new control block */
-            p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
-            if (p_charcb)
-            {
-                p_charcb->socket = lwip_accept(listenfd,
-                                        (struct sockaddr *) &p_charcb->cliaddr,
-                                        &p_charcb->clilen);
-                if (p_charcb->socket < 0)
-                    rt_free(p_charcb);
-                else
-                {
-                    /* Keep this tecb in our list */
-                    p_charcb->next = charcb_list;
-                    charcb_list = p_charcb;
-                    p_charcb->nextchar = 0x21;
-                }
-            }
-			else
-			{
-                /* No memory to accept connection. Just accept and then close */
-                int sock;
-                struct sockaddr cliaddr;
-                socklen_t clilen;
-
-                sock = lwip_accept(listenfd, &cliaddr, &clilen);
-                if (sock >= 0)
-                    lwip_close(sock);
-            }
-        }
-        /* Go through list of connected clients and process data */
-        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
-        {
-            if (FD_ISSET(p_charcb->socket, &readset))
-            {
-                /* This socket is ready for reading. This could be because someone typed
-                 * some characters or it could be because the socket is now closed. Try reading
-                 * some data to see. */
-                if (do_read(p_charcb) < 0)
-                    break;
-            }
-            if (FD_ISSET(p_charcb->socket, &writeset))
-            {
-                char line[80];
-                char setchar = p_charcb->nextchar;
-
-                for( i = 0; i < 59; i++)
-                {
-                    line[i] = setchar;
-                    if (++setchar == 0x7f)
-                        setchar = 0x21;
-                }
-                line[i] = 0;
-                strcat(line, "\n\r");
-                if (lwip_write(p_charcb->socket, line, strlen(line)) < 0)
-                {
-                    close_chargen(p_charcb);
-                    break;
-                }
-                if (++p_charcb->nextchar == 0x7f)
-                    p_charcb->nextchar = 0x21;
-            }
-        }
-    }
-}
-
-/**************************************************************
- * void close_chargen(struct charcb *p_charcb)
- *
- * Close the socket and remove this charcb from the list.
- **************************************************************/
-static void close_chargen(struct charcb *p_charcb)
-{
-    struct charcb *p_search_charcb;
-
-    /* Either an error or tcp connection closed on other
-     * end. Close here */
-    lwip_close(p_charcb->socket);
-
-    /* Free charcb */
-    if (charcb_list == p_charcb)
-        charcb_list = p_charcb->next;
-    else
-        for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
-        {
-            if (p_search_charcb->next == p_charcb)
-            {
-                p_search_charcb->next = p_charcb->next;
-                break;
-            }
-        }
-
-    rt_free(p_charcb);
-}
-
-/**************************************************************
- * void do_read(struct charcb *p_charcb)
- *
- * Socket definitely is ready for reading. Read a buffer from the socket and
- * discard the data.  If no data is read, then the socket is closed and the
- * charcb is removed from the list and freed.
- **************************************************************/
-static int do_read(struct charcb *p_charcb)
-{
-    char buffer[80];
-    int readcount;
-
-    /* Read some data */
-    readcount = lwip_read(p_charcb->socket, &buffer, 80);
-    if (readcount <= 0)
-    {
-        close_chargen(p_charcb);
-        return -1;
-    }
-    return 0;
-}
-
-void chargen_init(void)
-{
-	rt_thread_t chargen;
-
-	chargen = rt_thread_create(CHARGEN_THREAD_NAME,
-		chargen_thread, RT_NULL,
-		CHARGEN_THREAD_STACKSIZE,
-		CHARGEN_PRIORITY, 5);
-	if (chargen != RT_NULL) rt_thread_startup(chargen);
-}
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-void chargen()
-{
-	chargen_init();
-}
-FINSH_FUNCTION_EXPORT(chargen, start chargen server);
-#endif
+#include <rtthread.h>
+
+#include "lwip/sockets.h"
+#define MAX_SERV                 32         /* Maximum number of chargen services. Don't need too many */
+#define CHARGEN_THREAD_NAME      "chargen"
+#if RT_THREAD_PRIORITY_MAX == 32
+#define CHARGEN_PRIORITY         20        /* Really low priority */
+#else
+#define CHARGEN_PRIORITY         200       /* Really low priority */
+#endif
+#define CHARGEN_THREAD_STACKSIZE 1024
+struct charcb
+{
+    struct charcb *next;
+    int socket;
+    struct sockaddr_in cliaddr;
+    socklen_t clilen;
+    char nextchar;
+};
+
+static struct charcb *charcb_list = 0;
+static int do_read(struct charcb *p_charcb);
+static void close_chargen(struct charcb *p_charcb);
+
+/**************************************************************
+ * void chargen_thread(void *arg)
+ *
+ * chargen task. This server will wait for connections on well
+ * known TCP port number: 19. For every connection, the server will
+ * write as much data as possible to the tcp port.
+ **************************************************************/
+static void chargen_thread(void *arg)
+{
+    int listenfd;
+    struct sockaddr_in chargen_saddr;
+    fd_set readset;
+    fd_set writeset;
+    int i, maxfdp1;
+    struct charcb *p_charcb;
+
+    /* First acquire our socket for listening for connections */
+    listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+    LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
+    memset(&chargen_saddr, 0, sizeof(chargen_saddr));
+    chargen_saddr.sin_family = AF_INET;
+    chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    chargen_saddr.sin_port = htons(19);     // Chargen server port
+
+    if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
+        LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
+
+    /* Put socket into listening mode */
+    if (lwip_listen(listenfd, MAX_SERV) == -1)
+        LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
+
+    /* Wait forever for network input: This could be connections or data */
+    for (;;)
+    {
+        maxfdp1 = listenfd+1;
+
+        /* Determine what sockets need to be in readset */
+        FD_ZERO(&readset);
+        FD_ZERO(&writeset);
+        FD_SET(listenfd, &readset);
+        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
+        {
+            if (maxfdp1 < p_charcb->socket + 1)
+                maxfdp1 = p_charcb->socket + 1;
+            FD_SET(p_charcb->socket, &readset);
+            FD_SET(p_charcb->socket, &writeset);
+        }
+
+        /* Wait for data or a new connection */
+        i = lwip_select(maxfdp1, &readset, &writeset, 0, 0);
+
+        if (i == 0) continue;
+
+        /* At least one descriptor is ready */
+        if (FD_ISSET(listenfd, &readset))
+        {
+            /* We have a new connection request!!! */
+            /* Lets create a new control block */
+            p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
+            if (p_charcb)
+            {
+                p_charcb->socket = lwip_accept(listenfd,
+                                        (struct sockaddr *) &p_charcb->cliaddr,
+                                        &p_charcb->clilen);
+                if (p_charcb->socket < 0)
+                    rt_free(p_charcb);
+                else
+                {
+                    /* Keep this tecb in our list */
+                    p_charcb->next = charcb_list;
+                    charcb_list = p_charcb;
+                    p_charcb->nextchar = 0x21;
+                }
+            }
+			else
+			{
+                /* No memory to accept connection. Just accept and then close */
+                int sock;
+                struct sockaddr cliaddr;
+                socklen_t clilen;
+
+                sock = lwip_accept(listenfd, &cliaddr, &clilen);
+                if (sock >= 0)
+                    lwip_close(sock);
+            }
+        }
+        /* Go through list of connected clients and process data */
+        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
+        {
+            if (FD_ISSET(p_charcb->socket, &readset))
+            {
+                /* This socket is ready for reading. This could be because someone typed
+                 * some characters or it could be because the socket is now closed. Try reading
+                 * some data to see. */
+                if (do_read(p_charcb) < 0)
+                    break;
+            }
+            if (FD_ISSET(p_charcb->socket, &writeset))
+            {
+                char line[80];
+                char setchar = p_charcb->nextchar;
+
+                for( i = 0; i < 59; i++)
+                {
+                    line[i] = setchar;
+                    if (++setchar == 0x7f)
+                        setchar = 0x21;
+                }
+                line[i] = 0;
+                strcat(line, "\n\r");
+                if (lwip_write(p_charcb->socket, line, strlen(line)) < 0)
+                {
+                    close_chargen(p_charcb);
+                    break;
+                }
+                if (++p_charcb->nextchar == 0x7f)
+                    p_charcb->nextchar = 0x21;
+            }
+        }
+    }
+}
+
+/**************************************************************
+ * void close_chargen(struct charcb *p_charcb)
+ *
+ * Close the socket and remove this charcb from the list.
+ **************************************************************/
+static void close_chargen(struct charcb *p_charcb)
+{
+    struct charcb *p_search_charcb;
+
+    /* Either an error or tcp connection closed on other
+     * end. Close here */
+    lwip_close(p_charcb->socket);
+
+    /* Free charcb */
+    if (charcb_list == p_charcb)
+        charcb_list = p_charcb->next;
+    else
+        for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
+        {
+            if (p_search_charcb->next == p_charcb)
+            {
+                p_search_charcb->next = p_charcb->next;
+                break;
+            }
+        }
+
+    rt_free(p_charcb);
+}
+
+/**************************************************************
+ * void do_read(struct charcb *p_charcb)
+ *
+ * Socket definitely is ready for reading. Read a buffer from the socket and
+ * discard the data.  If no data is read, then the socket is closed and the
+ * charcb is removed from the list and freed.
+ **************************************************************/
+static int do_read(struct charcb *p_charcb)
+{
+    char buffer[80];
+    int readcount;
+
+    /* Read some data */
+    readcount = lwip_read(p_charcb->socket, &buffer, 80);
+    if (readcount <= 0)
+    {
+        close_chargen(p_charcb);
+        return -1;
+    }
+    return 0;
+}
+
+void chargen_init(void)
+{
+	rt_thread_t chargen;
+
+	chargen = rt_thread_create(CHARGEN_THREAD_NAME,
+		chargen_thread, RT_NULL,
+		CHARGEN_THREAD_STACKSIZE,
+		CHARGEN_PRIORITY, 5);
+	if (chargen != RT_NULL) rt_thread_startup(chargen);
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+void chargen()
+{
+	chargen_init();
+}
+FINSH_FUNCTION_EXPORT(chargen, start chargen server);
+#endif

+ 0 - 0
components/net/apps/ftpd.c → components/net/lwip-1.4.0/apps/ftpd.c


+ 370 - 370
components/net/apps/netio.c → components/net/lwip-1.4.0/apps/netio.c

@@ -1,370 +1,370 @@
-/**
- * @file
- * MetIO Server
- *
- */
-
-/*
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- */
-#include "lwip/opt.h"
-
-#if LWIP_TCP
-#include "lwip/tcp.h"
-
-/*
- * This implements a netio server.
- *  The client sends a command word (4 bytes) then a data length word (4 bytes).
- *  If the command is "receive", the server is to consume "data length" bytes into
- *   a circular buffer until the first byte is non-zero, then it is to consume
- *   another command/data pair.
- *  If the command is "send", the server is to send "data length" bytes from a circular
- *   buffer with the first byte being zero, until "some time" (6 seconds in the
- *   current netio126.zip download) has passed and then send one final buffer with
- *   the first byte being non-zero. Then it is to consume another command/data pair.
- */
-
-/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
-
-/* implementation options */
-#define NETIO_BUF_SIZE              (4 * 1024)
-#define NETIO_USE_STATIC_BUF        0
-
-/* NetIO server state definition */
-#define NETIO_STATE_WAIT_FOR_CMD    0
-#define NETIO_STATE_RECV_DATA       1
-#define NETIO_STATE_SEND_DATA       2
-#define NETIO_STATE_SEND_DATA_LAST  3
-#define NETIO_STATE_DONE            4
-
-struct netio_state {
-  u32_t  state;
-  u32_t  cmd;
-  u32_t  data_len;
-  u32_t  cntr;
-  u8_t * buf_ptr;
-  u32_t  buf_pos;
-  u32_t  first_byte;
-  u32_t  time_stamp;
-};
-
-/* NetIO command protocol definition */
-#define NETIO_CMD_QUIT              0
-#define NETIO_CMD_C2S               1
-#define NETIO_CMD_S2C               2
-#define NETIO_CMD_RES               3
-
-static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
-
-static void
-netio_close(void *arg, struct tcp_pcb *pcb)
-{
-  err_t err;
-
-  struct netio_state *ns = arg;
-  ns->state = NETIO_STATE_DONE;
-  tcp_recv(pcb, NULL);
-  err = tcp_close(pcb);
-
-  if (err != ERR_OK) {
-    /* closing failed, try again later */
-    tcp_recv(pcb, netio_recv);
-  } else {
-    /* closing succeeded */
-#if NETIO_USE_STATIC_BUF != 1
-    if(ns->buf_ptr != NULL){
-      mem_free(ns->buf_ptr);
-    }
-#endif
-    tcp_arg(pcb, NULL);
-    tcp_poll(pcb, NULL, 0);
-    tcp_sent(pcb, NULL);
-    if (arg != NULL) {
-      mem_free(arg);
-    }
-  }
-}
-
-static err_t
-netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
-{
-  struct netio_state *ns = arg;
-  u8_t * data_ptr;
-  u32_t data_cntr;
-  struct pbuf *q = p;
-  u16_t len;
-
-  if (p != NULL) {
-    tcp_recved(pcb, p->tot_len);
-  }
-
-  if (err == ERR_OK && q != NULL) {
-
-    while (q != NULL) {
-      data_cntr = q->len;
-      data_ptr = q->payload;
-      while (data_cntr--) {
-        if (ns->state == NETIO_STATE_DONE){
-          netio_close(ns, pcb);
-          break;
-        } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
-          if (ns->cntr < 4) {
-            /* build up the CMD field */
-            ns->cmd <<= 8;
-            ns->cmd |= *data_ptr++;
-            ns->cntr++;
-          } else if (ns->cntr < 8) {
-            /* build up the DATA field */
-            ns->data_len <<= 8;
-            ns->data_len |= *data_ptr++;
-            ns->cntr++;
-
-            if (ns->cntr == 8) {
-              /* now we have full command and data words */
-              ns->cntr = 0;
-              ns->buf_pos = 0;
-              ns->buf_ptr[0] = 0;
-              if (ns->cmd == NETIO_CMD_C2S) {
-                ns->state = NETIO_STATE_RECV_DATA;
-              } else if (ns->cmd == NETIO_CMD_S2C) {
-                ns->state = NETIO_STATE_SEND_DATA;
-                /* start timer */
-                ns->time_stamp = rt_tick_get();
-                /* send first round of data */
-
-                len = tcp_sndbuf(pcb);
-                len = LWIP_MIN(len, ns->data_len - ns->cntr);
-                len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
-
-                do {
-                  err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
-                  if (err == ERR_MEM) {
-                    len /= 2;
-                  }
-                } while ((err == ERR_MEM) && (len > 1));
-
-                ns->buf_pos += len;
-                ns->cntr    += len;
-
-              } else {
-                /* unrecognized command, punt */
-                ns->cntr = 0;
-                ns->buf_pos = 0;
-                ns->buf_ptr[0] = 0;
-                netio_close(ns, pcb);
-                break;
-              }
-            }
-          } else {
-            /* in trouble... shouldn't be in this state! */
-          }
-
-        } else if (ns->state == NETIO_STATE_RECV_DATA) {
-
-          if(ns->cntr == 0){
-            /* save the first byte of this new round of data
-             * this will not match ns->buf_ptr[0] in the case that
-             *   NETIO_BUF_SIZE is less than ns->data_len.
-             */
-            ns->first_byte = *data_ptr;
-          }
-
-          ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
-          ns->cntr++;
-
-          if (ns->buf_pos == NETIO_BUF_SIZE) {
-            /* circularize the buffer */
-            ns->buf_pos = 0;
-          }
-
-          if(ns->cntr == ns->data_len){
-            ns->cntr = 0;
-            if (ns->first_byte != 0) {
-              /* if this last round did not start with 0,
-               *  go look for another command */
-              ns->state = NETIO_STATE_WAIT_FOR_CMD;
-              ns->data_len = 0;
-              ns->cmd = 0;
-              /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
-            } else {
-              /* stay here and wait on more data */
-            }
-          }
-
-        } else if (ns->state == NETIO_STATE_SEND_DATA
-            || ns->state == NETIO_STATE_SEND_DATA_LAST) {
-          /* I don't think this should happen... */
-        } else {
-          /* done / quit */
-          netio_close(ns, pcb);
-          break;
-        } /* end of ns->state condition */
-      } /* end of while data still in this pbuf */
-
-      q = q->next;
-    }
-
-    pbuf_free(p);
-
-  } else {
-
-    /* error or closed by other side */
-    if (p != NULL) {
-      pbuf_free(p);
-    }
-
-    /* close the connection */
-    netio_close(ns, pcb);
-
-  }
-  return ERR_OK;
-
-}
-
-static err_t
-netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
-{
-  struct netio_state *ns = arg;
-  err_t err = ERR_OK;
-
-  if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
-    /* done with this round of sending */
-    ns->buf_pos = 0;
-    ns->cntr = 0;
-
-    /* check if timer expired */
-    if (rt_tick_get() - ns->time_stamp > 600) {
-      ns->buf_ptr[0] = 1;
-      ns->state = NETIO_STATE_SEND_DATA_LAST;
-    } else {
-      ns->buf_ptr[0] = 0;
-    }
-  }
-
-  if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
-    len = tcp_sndbuf(pcb);
-    len = LWIP_MIN(len, ns->data_len - ns->cntr);
-    len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
-
-    if(ns->cntr < ns->data_len){
-      do {
-        err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
-        if (err == ERR_MEM) {
-          len /= 2;
-        }
-      } while ((err == ERR_MEM) && (len > 1));
-
-      ns->buf_pos += len;
-      if(ns->buf_pos >= NETIO_BUF_SIZE){
-        ns->buf_pos = 0;
-      }
-
-      ns->cntr += len;
-    }
-  }
-
-  if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
-    /* we have buffered up all our data to send this last round, go look for a command */
-   ns->state = NETIO_STATE_WAIT_FOR_CMD;
-   ns->cntr  = 0;
-   /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
-  }
-
-  return ERR_OK;
-}
-
-static err_t
-netio_poll(void *arg, struct tcp_pcb *pcb)
-{
-  struct netio_state * ns = arg;
-  if(ns->state == NETIO_STATE_SEND_DATA){
-
-  } else if(ns->state == NETIO_STATE_DONE){
-    netio_close(ns, pcb);
-  }
-
-  return ERR_OK;
-
-}
-
-#if NETIO_USE_STATIC_BUF == 1
-static u8_t netio_buf[NETIO_BUF_SIZE];
-#endif
-
-static err_t
-netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
-{
-  struct netio_state * ns;
-
-  LWIP_UNUSED_ARG(err);
-
-  ns = mem_malloc(sizeof(struct netio_state));
-
-  if(ns == NULL){
-    return ERR_MEM;
-  }
-
-  ns->state = NETIO_STATE_WAIT_FOR_CMD;
-  ns->data_len = 0;
-  ns->cmd = 0;
-  ns->cntr = 0;
-  ns->buf_pos = 0;
-#if NETIO_USE_STATIC_BUF == 1
-  ns->buf_ptr = netio_buf;
-#else
-  ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
-
-  if(ns->buf_ptr == NULL){
-    mem_free(ns);
-    return ERR_MEM;
-  }
-#endif
-
-  ns->buf_ptr[0] = 0;
-
-  tcp_arg(pcb, ns);
-  tcp_sent(pcb, netio_sent);
-  tcp_recv(pcb, netio_recv);
-  tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
-  return ERR_OK;
-}
-
-void netio_init(void)
-{
-  struct tcp_pcb *pcb;
-
-  pcb = tcp_new();
-  tcp_bind(pcb, IP_ADDR_ANY, 18767);
-  pcb = tcp_listen(pcb);
-  tcp_accept(pcb, netio_accept);
-}
-
-#endif /* LWIP_TCP */
-
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-FINSH_FUNCTION_EXPORT(netio_init, netio server);
-#endif
+/**
+ * @file
+ * MetIO Server
+ *
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ */
+#include "lwip/opt.h"
+
+#if LWIP_TCP
+#include "lwip/tcp.h"
+
+/*
+ * This implements a netio server.
+ *  The client sends a command word (4 bytes) then a data length word (4 bytes).
+ *  If the command is "receive", the server is to consume "data length" bytes into
+ *   a circular buffer until the first byte is non-zero, then it is to consume
+ *   another command/data pair.
+ *  If the command is "send", the server is to send "data length" bytes from a circular
+ *   buffer with the first byte being zero, until "some time" (6 seconds in the
+ *   current netio126.zip download) has passed and then send one final buffer with
+ *   the first byte being non-zero. Then it is to consume another command/data pair.
+ */
+
+/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
+
+/* implementation options */
+#define NETIO_BUF_SIZE              (4 * 1024)
+#define NETIO_USE_STATIC_BUF        0
+
+/* NetIO server state definition */
+#define NETIO_STATE_WAIT_FOR_CMD    0
+#define NETIO_STATE_RECV_DATA       1
+#define NETIO_STATE_SEND_DATA       2
+#define NETIO_STATE_SEND_DATA_LAST  3
+#define NETIO_STATE_DONE            4
+
+struct netio_state {
+  u32_t  state;
+  u32_t  cmd;
+  u32_t  data_len;
+  u32_t  cntr;
+  u8_t * buf_ptr;
+  u32_t  buf_pos;
+  u32_t  first_byte;
+  u32_t  time_stamp;
+};
+
+/* NetIO command protocol definition */
+#define NETIO_CMD_QUIT              0
+#define NETIO_CMD_C2S               1
+#define NETIO_CMD_S2C               2
+#define NETIO_CMD_RES               3
+
+static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
+
+static void
+netio_close(void *arg, struct tcp_pcb *pcb)
+{
+  err_t err;
+
+  struct netio_state *ns = arg;
+  ns->state = NETIO_STATE_DONE;
+  tcp_recv(pcb, NULL);
+  err = tcp_close(pcb);
+
+  if (err != ERR_OK) {
+    /* closing failed, try again later */
+    tcp_recv(pcb, netio_recv);
+  } else {
+    /* closing succeeded */
+#if NETIO_USE_STATIC_BUF != 1
+    if(ns->buf_ptr != NULL){
+      mem_free(ns->buf_ptr);
+    }
+#endif
+    tcp_arg(pcb, NULL);
+    tcp_poll(pcb, NULL, 0);
+    tcp_sent(pcb, NULL);
+    if (arg != NULL) {
+      mem_free(arg);
+    }
+  }
+}
+
+static err_t
+netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+  struct netio_state *ns = arg;
+  u8_t * data_ptr;
+  u32_t data_cntr;
+  struct pbuf *q = p;
+  u16_t len;
+
+  if (p != NULL) {
+    tcp_recved(pcb, p->tot_len);
+  }
+
+  if (err == ERR_OK && q != NULL) {
+
+    while (q != NULL) {
+      data_cntr = q->len;
+      data_ptr = q->payload;
+      while (data_cntr--) {
+        if (ns->state == NETIO_STATE_DONE){
+          netio_close(ns, pcb);
+          break;
+        } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
+          if (ns->cntr < 4) {
+            /* build up the CMD field */
+            ns->cmd <<= 8;
+            ns->cmd |= *data_ptr++;
+            ns->cntr++;
+          } else if (ns->cntr < 8) {
+            /* build up the DATA field */
+            ns->data_len <<= 8;
+            ns->data_len |= *data_ptr++;
+            ns->cntr++;
+
+            if (ns->cntr == 8) {
+              /* now we have full command and data words */
+              ns->cntr = 0;
+              ns->buf_pos = 0;
+              ns->buf_ptr[0] = 0;
+              if (ns->cmd == NETIO_CMD_C2S) {
+                ns->state = NETIO_STATE_RECV_DATA;
+              } else if (ns->cmd == NETIO_CMD_S2C) {
+                ns->state = NETIO_STATE_SEND_DATA;
+                /* start timer */
+                ns->time_stamp = rt_tick_get();
+                /* send first round of data */
+
+                len = tcp_sndbuf(pcb);
+                len = LWIP_MIN(len, ns->data_len - ns->cntr);
+                len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
+
+                do {
+                  err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
+                  if (err == ERR_MEM) {
+                    len /= 2;
+                  }
+                } while ((err == ERR_MEM) && (len > 1));
+
+                ns->buf_pos += len;
+                ns->cntr    += len;
+
+              } else {
+                /* unrecognized command, punt */
+                ns->cntr = 0;
+                ns->buf_pos = 0;
+                ns->buf_ptr[0] = 0;
+                netio_close(ns, pcb);
+                break;
+              }
+            }
+          } else {
+            /* in trouble... shouldn't be in this state! */
+          }
+
+        } else if (ns->state == NETIO_STATE_RECV_DATA) {
+
+          if(ns->cntr == 0){
+            /* save the first byte of this new round of data
+             * this will not match ns->buf_ptr[0] in the case that
+             *   NETIO_BUF_SIZE is less than ns->data_len.
+             */
+            ns->first_byte = *data_ptr;
+          }
+
+          ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
+          ns->cntr++;
+
+          if (ns->buf_pos == NETIO_BUF_SIZE) {
+            /* circularize the buffer */
+            ns->buf_pos = 0;
+          }
+
+          if(ns->cntr == ns->data_len){
+            ns->cntr = 0;
+            if (ns->first_byte != 0) {
+              /* if this last round did not start with 0,
+               *  go look for another command */
+              ns->state = NETIO_STATE_WAIT_FOR_CMD;
+              ns->data_len = 0;
+              ns->cmd = 0;
+              /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
+            } else {
+              /* stay here and wait on more data */
+            }
+          }
+
+        } else if (ns->state == NETIO_STATE_SEND_DATA
+            || ns->state == NETIO_STATE_SEND_DATA_LAST) {
+          /* I don't think this should happen... */
+        } else {
+          /* done / quit */
+          netio_close(ns, pcb);
+          break;
+        } /* end of ns->state condition */
+      } /* end of while data still in this pbuf */
+
+      q = q->next;
+    }
+
+    pbuf_free(p);
+
+  } else {
+
+    /* error or closed by other side */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+
+    /* close the connection */
+    netio_close(ns, pcb);
+
+  }
+  return ERR_OK;
+
+}
+
+static err_t
+netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+  struct netio_state *ns = arg;
+  err_t err = ERR_OK;
+
+  if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
+    /* done with this round of sending */
+    ns->buf_pos = 0;
+    ns->cntr = 0;
+
+    /* check if timer expired */
+    if (rt_tick_get() - ns->time_stamp > 600) {
+      ns->buf_ptr[0] = 1;
+      ns->state = NETIO_STATE_SEND_DATA_LAST;
+    } else {
+      ns->buf_ptr[0] = 0;
+    }
+  }
+
+  if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
+    len = tcp_sndbuf(pcb);
+    len = LWIP_MIN(len, ns->data_len - ns->cntr);
+    len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
+
+    if(ns->cntr < ns->data_len){
+      do {
+        err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
+        if (err == ERR_MEM) {
+          len /= 2;
+        }
+      } while ((err == ERR_MEM) && (len > 1));
+
+      ns->buf_pos += len;
+      if(ns->buf_pos >= NETIO_BUF_SIZE){
+        ns->buf_pos = 0;
+      }
+
+      ns->cntr += len;
+    }
+  }
+
+  if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
+    /* we have buffered up all our data to send this last round, go look for a command */
+   ns->state = NETIO_STATE_WAIT_FOR_CMD;
+   ns->cntr  = 0;
+   /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
+  }
+
+  return ERR_OK;
+}
+
+static err_t
+netio_poll(void *arg, struct tcp_pcb *pcb)
+{
+  struct netio_state * ns = arg;
+  if(ns->state == NETIO_STATE_SEND_DATA){
+
+  } else if(ns->state == NETIO_STATE_DONE){
+    netio_close(ns, pcb);
+  }
+
+  return ERR_OK;
+
+}
+
+#if NETIO_USE_STATIC_BUF == 1
+static u8_t netio_buf[NETIO_BUF_SIZE];
+#endif
+
+static err_t
+netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+  struct netio_state * ns;
+
+  LWIP_UNUSED_ARG(err);
+
+  ns = mem_malloc(sizeof(struct netio_state));
+
+  if(ns == NULL){
+    return ERR_MEM;
+  }
+
+  ns->state = NETIO_STATE_WAIT_FOR_CMD;
+  ns->data_len = 0;
+  ns->cmd = 0;
+  ns->cntr = 0;
+  ns->buf_pos = 0;
+#if NETIO_USE_STATIC_BUF == 1
+  ns->buf_ptr = netio_buf;
+#else
+  ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
+
+  if(ns->buf_ptr == NULL){
+    mem_free(ns);
+    return ERR_MEM;
+  }
+#endif
+
+  ns->buf_ptr[0] = 0;
+
+  tcp_arg(pcb, ns);
+  tcp_sent(pcb, netio_sent);
+  tcp_recv(pcb, netio_recv);
+  tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
+  return ERR_OK;
+}
+
+void netio_init(void)
+{
+  struct tcp_pcb *pcb;
+
+  pcb = tcp_new();
+  tcp_bind(pcb, IP_ADDR_ANY, 18767);
+  pcb = tcp_listen(pcb);
+  tcp_accept(pcb, netio_accept);
+}
+
+#endif /* LWIP_TCP */
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(netio_init, netio server);
+#endif

+ 175 - 175
components/net/apps/ping.c → components/net/lwip-1.4.0/apps/ping.c

@@ -1,175 +1,175 @@
-/*
- * netutils: ping implementation
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/mem.h"
-#include "lwip/icmp.h"
-#include "lwip/netif.h"
-#include "lwip/sys.h"
-#include "lwip/sockets.h"
-#include "lwip/inet.h"
-#include "lwip/inet_chksum.h"
-#include "lwip/ip.h"
-
-/**
- * PING_DEBUG: Enable debugging for PING.
- */
-#ifndef PING_DEBUG
-#define PING_DEBUG     LWIP_DBG_ON
-#endif
-
-/** ping receive timeout - in milliseconds */
-#define PING_RCV_TIMEO 1000
-/** ping delay - in milliseconds */
-#define PING_DELAY     100
-
-/** ping identifier - must fit on a u16_t */
-#ifndef PING_ID
-#define PING_ID        0xAFAF
-#endif
-
-/** ping additional data size to include in the packet */
-#ifndef PING_DATA_SIZE
-#define PING_DATA_SIZE 32
-#endif
-
-/* ping variables */
-static u16_t ping_seq_num;
-struct _ip_addr
-{
-	rt_uint8_t addr0, addr1, addr2, addr3;
-};
-
-/** Prepare a echo ICMP request */
-static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
-{
-	size_t i;
-	size_t data_len = len - sizeof(struct icmp_echo_hdr);
-
-	ICMPH_TYPE_SET(iecho, ICMP_ECHO);
-	ICMPH_CODE_SET(iecho, 0);
-	iecho->chksum = 0;
-	iecho->id     = PING_ID;
-	iecho->seqno  = htons(++ping_seq_num);
-
-	/* fill the additional data buffer with some data */
-	for(i = 0; i < data_len; i++)
-	{
-		((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
-	}
-
-	iecho->chksum = inet_chksum(iecho, len);
-}
-
-/* Ping using the socket ip */
-static err_t ping_send(int s, struct ip_addr *addr)
-{
-	int err;
-	struct icmp_echo_hdr *iecho;
-	struct sockaddr_in to;
-	size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
-	LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
-
-	iecho = rt_malloc(ping_size);
-	if (iecho == RT_NULL)
-	{
-		return ERR_MEM;
-	}
-
-	ping_prepare_echo(iecho, (u16_t)ping_size);
-
-	to.sin_len = sizeof(to);
-	to.sin_family = AF_INET;
-	to.sin_addr.s_addr = addr->addr;
-
-	err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
-	rt_free(iecho);
-
-	return (err ? ERR_OK : ERR_VAL);
-}
-
-static void ping_recv(int s)
-{
-	char buf[64];
-	int fromlen, len;
-	struct sockaddr_in from;
-	struct ip_hdr *iphdr;
-	struct icmp_echo_hdr *iecho;
-	struct _ip_addr *addr;
-
-	while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
-	{
-		if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
-		{
-			addr = (struct _ip_addr *)&(from.sin_addr);
-			rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
-
-			iphdr = (struct ip_hdr *)buf;
-			iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
-			if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
-			{
-				return;
-			}
-			else
-			{
-				rt_kprintf("ping: drop\n");
-			}
-		}
-	}
-
-	if (len <= 0)
-	{
-		rt_kprintf("ping: timeout\n");
-	}
-}
-
-rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size)
-{
-	int s;
-	int timeout = PING_RCV_TIMEO;
-	struct ip_addr ping_target;
-	rt_uint32_t send_time;
-	struct _ip_addr
-	{
-		rt_uint8_t addr0, addr1, addr2, addr3;
-	} *addr;
-
-    send_time = 0;
-
-	if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR;
-	addr = (struct _ip_addr*)&ping_target;
-
-	if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
-	{
-	    rt_kprintf("create socket failled\n");
-		return -RT_ERROR;
-	}
-
-	lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
-
-	while (1)
-	{
-		if (ping_send(s, &ping_target) == ERR_OK)
-		{
-			rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
-			ping_recv(s);
-		}
-		else
-		{
-			rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
-		}
-
-		send_time ++;
-		if (send_time >= time) break; /* send ping times reached, stop */
-
-		rt_thread_delay(PING_DELAY); /* take a delay */
-	}
-
-	return RT_EOK;
-}
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-FINSH_FUNCTION_EXPORT(ping, ping network host);
-#endif
+/*
+ * netutils: ping implementation
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/mem.h"
+#include "lwip/icmp.h"
+#include "lwip/netif.h"
+#include "lwip/sys.h"
+#include "lwip/sockets.h"
+#include "lwip/inet.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+
+/**
+ * PING_DEBUG: Enable debugging for PING.
+ */
+#ifndef PING_DEBUG
+#define PING_DEBUG     LWIP_DBG_ON
+#endif
+
+/** ping receive timeout - in milliseconds */
+#define PING_RCV_TIMEO 1000
+/** ping delay - in milliseconds */
+#define PING_DELAY     100
+
+/** ping identifier - must fit on a u16_t */
+#ifndef PING_ID
+#define PING_ID        0xAFAF
+#endif
+
+/** ping additional data size to include in the packet */
+#ifndef PING_DATA_SIZE
+#define PING_DATA_SIZE 32
+#endif
+
+/* ping variables */
+static u16_t ping_seq_num;
+struct _ip_addr
+{
+	rt_uint8_t addr0, addr1, addr2, addr3;
+};
+
+/** Prepare a echo ICMP request */
+static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
+{
+	size_t i;
+	size_t data_len = len - sizeof(struct icmp_echo_hdr);
+
+	ICMPH_TYPE_SET(iecho, ICMP_ECHO);
+	ICMPH_CODE_SET(iecho, 0);
+	iecho->chksum = 0;
+	iecho->id     = PING_ID;
+	iecho->seqno  = htons(++ping_seq_num);
+
+	/* fill the additional data buffer with some data */
+	for(i = 0; i < data_len; i++)
+	{
+		((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
+	}
+
+	iecho->chksum = inet_chksum(iecho, len);
+}
+
+/* Ping using the socket ip */
+static err_t ping_send(int s, struct ip_addr *addr)
+{
+	int err;
+	struct icmp_echo_hdr *iecho;
+	struct sockaddr_in to;
+	size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
+	LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
+
+	iecho = rt_malloc(ping_size);
+	if (iecho == RT_NULL)
+	{
+		return ERR_MEM;
+	}
+
+	ping_prepare_echo(iecho, (u16_t)ping_size);
+
+	to.sin_len = sizeof(to);
+	to.sin_family = AF_INET;
+	to.sin_addr.s_addr = addr->addr;
+
+	err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
+	rt_free(iecho);
+
+	return (err ? ERR_OK : ERR_VAL);
+}
+
+static void ping_recv(int s)
+{
+	char buf[64];
+	int fromlen, len;
+	struct sockaddr_in from;
+	struct ip_hdr *iphdr;
+	struct icmp_echo_hdr *iecho;
+	struct _ip_addr *addr;
+
+	while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
+	{
+		if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
+		{
+			addr = (struct _ip_addr *)&(from.sin_addr);
+			rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+
+			iphdr = (struct ip_hdr *)buf;
+			iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
+			if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
+			{
+				return;
+			}
+			else
+			{
+				rt_kprintf("ping: drop\n");
+			}
+		}
+	}
+
+	if (len <= 0)
+	{
+		rt_kprintf("ping: timeout\n");
+	}
+}
+
+rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size)
+{
+	int s;
+	int timeout = PING_RCV_TIMEO;
+	struct ip_addr ping_target;
+	rt_uint32_t send_time;
+	struct _ip_addr
+	{
+		rt_uint8_t addr0, addr1, addr2, addr3;
+	} *addr;
+
+    send_time = 0;
+
+	if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR;
+	addr = (struct _ip_addr*)&ping_target;
+
+	if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
+	{
+	    rt_kprintf("create socket failled\n");
+		return -RT_ERROR;
+	}
+
+	lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+	while (1)
+	{
+		if (ping_send(s, &ping_target) == ERR_OK)
+		{
+			rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+			ping_recv(s);
+		}
+		else
+		{
+			rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+		}
+
+		send_time ++;
+		if (send_time >= time) break; /* send ping times reached, stop */
+
+		rt_thread_delay(PING_DELAY); /* take a delay */
+	}
+
+	return RT_EOK;
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(ping, ping network host);
+#endif

+ 213 - 213
components/net/apps/sntp.c → components/net/lwip-1.4.0/apps/sntp.c

@@ -1,213 +1,213 @@
-/**
- * @file
- * SNTP client module
- *
- */
-
-/*
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- */
-
-#include "lwip/sys.h"
-#include "lwip/sockets.h"
-
-#include <string.h>
-#include <time.h>
-
-/** This is an example of a "SNTP" client (with socket API).
- *
- * For a list of some public NTP servers, see this link :
- * http://support.ntp.org/bin/view/Servers/NTPPoolServers
- *
- */
-
-/**
- * SNTP_DEBUG: Enable debugging for SNTP.
- */
-#ifndef SNTP_DEBUG
-#define SNTP_DEBUG                  LWIP_DBG_ON
-#endif
-
-/** SNTP server port */
-#ifndef SNTP_PORT
-#define SNTP_PORT                   123
-#endif
-
-/** SNTP server address as IPv4 address in "u32_t" format */
-#ifndef SNTP_SERVER_ADDRESS
-#define SNTP_SERVER_ADDRESS         inet_addr("213.161.194.93") /* pool.ntp.org */
-#endif
-
-/** SNTP receive timeout - in milliseconds */
-#ifndef SNTP_RECV_TIMEOUT
-#define SNTP_RECV_TIMEOUT           3000
-#endif
-
-/** SNTP update delay - in milliseconds */
-#ifndef SNTP_UPDATE_DELAY
-#define SNTP_UPDATE_DELAY           60000
-#endif
-
-/** SNTP macro to change system time and/or the update the RTC clock */
-#ifndef SNTP_SYSTEM_TIME
-#define SNTP_SYSTEM_TIME(t)
-#endif
-
-/* SNTP protocol defines */
-#define SNTP_MAX_DATA_LEN           48
-#define SNTP_RCV_TIME_OFS           32
-#define SNTP_LI_NO_WARNING          0x00
-#define SNTP_VERSION               (4/* NTP Version 4*/<<3)
-#define SNTP_MODE_CLIENT            0x03
-#define SNTP_MODE_SERVER            0x04
-#define SNTP_MODE_BROADCAST         0x05
-#define SNTP_MODE_MASK              0x07
-
-/* number of seconds between 1900 and 1970 */
-#define DIFF_SEC_1900_1970         (2208988800)
-
-/**
- * SNTP processing
- */
-static void sntp_process( time_t t)
-{
-	/* change system time and/or the update the RTC clock */
-	SNTP_SYSTEM_TIME(t);
-
-	/* display local time from GMT time */
-	LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t)));
-}
-
-/**
- * SNTP request
- */
-static void sntp_request()
-{
-	int                sock;
-	struct sockaddr_in local;
-	struct sockaddr_in to;
-	int                tolen;
-	int                size;
-	int                timeout;
-	u8_t               sntp_request [SNTP_MAX_DATA_LEN];
-	u8_t               sntp_response[SNTP_MAX_DATA_LEN];
-	u32_t              sntp_server_address;
-	u32_t              timestamp;
-	time_t             t;
-
-	/* initialize SNTP server address */
-	sntp_server_address = SNTP_SERVER_ADDRESS;
-
-	/* if we got a valid SNTP server address... */
-	if (sntp_server_address!=0)
-	{
-		/* create new socket */
-		sock = socket( AF_INET, SOCK_DGRAM, 0);
-		if (sock>=0)
-		{
-			/* prepare local address */
-			memset(&local, 0, sizeof(local));
-			local.sin_family      = AF_INET;
-			local.sin_port        = htons(INADDR_ANY);
-			local.sin_addr.s_addr = htonl(INADDR_ANY);
-
-			/* bind to local address */
-			if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
-			{
-				/* set recv timeout */
-				timeout = SNTP_RECV_TIMEOUT;
-				setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
-
-				/* prepare SNTP request */
-				memset( sntp_request, 0, sizeof(sntp_request));
-				sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
-
-				/* prepare SNTP server address */
-				memset(&to, 0, sizeof(to));
-				to.sin_family      = AF_INET;
-				to.sin_port        = htons(SNTP_PORT);
-				to.sin_addr.s_addr = sntp_server_address;
-
-				/* send SNTP request to server */
-				if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
-				{
-					/* receive SNTP server response */
-					tolen = sizeof(to);
-					size  = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);
-
-					/* if the response size is good */
-					if (size == SNTP_MAX_DATA_LEN)
-					{
-						/* if this is a SNTP response... */
-						if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
-						{
-							/* extract GMT time from response */
-							SMEMCPY( &timestamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
-							t = (ntohl(timestamp) - DIFF_SEC_1900_1970);
-
-							/* do time processing */
-							sntp_process(t);
-
-						}
-						else
-						{
-							LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
-						}
-					}
-					else
-					{
-						LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
-					}
-				}
-				else
-				{
-					LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
-				}
-			}
-			/* close the socket */
-			closesocket(sock);
-		}
-	}
-}
-
-/**
- * SNTP thread
- */
-static void
-sntp_thread(void *arg)
-{
-	LWIP_UNUSED_ARG(arg);
-	while(1)
-	{
-		sntp_request();
-		sys_msleep(SNTP_UPDATE_DELAY);
-	}
-}
-
-void sntp_init(void)
-{
-	sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
-}
+/**
+ * @file
+ * SNTP client module
+ *
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ */
+
+#include "lwip/sys.h"
+#include "lwip/sockets.h"
+
+#include <string.h>
+#include <time.h>
+
+/** This is an example of a "SNTP" client (with socket API).
+ *
+ * For a list of some public NTP servers, see this link :
+ * http://support.ntp.org/bin/view/Servers/NTPPoolServers
+ *
+ */
+
+/**
+ * SNTP_DEBUG: Enable debugging for SNTP.
+ */
+#ifndef SNTP_DEBUG
+#define SNTP_DEBUG                  LWIP_DBG_ON
+#endif
+
+/** SNTP server port */
+#ifndef SNTP_PORT
+#define SNTP_PORT                   123
+#endif
+
+/** SNTP server address as IPv4 address in "u32_t" format */
+#ifndef SNTP_SERVER_ADDRESS
+#define SNTP_SERVER_ADDRESS         inet_addr("213.161.194.93") /* pool.ntp.org */
+#endif
+
+/** SNTP receive timeout - in milliseconds */
+#ifndef SNTP_RECV_TIMEOUT
+#define SNTP_RECV_TIMEOUT           3000
+#endif
+
+/** SNTP update delay - in milliseconds */
+#ifndef SNTP_UPDATE_DELAY
+#define SNTP_UPDATE_DELAY           60000
+#endif
+
+/** SNTP macro to change system time and/or the update the RTC clock */
+#ifndef SNTP_SYSTEM_TIME
+#define SNTP_SYSTEM_TIME(t)
+#endif
+
+/* SNTP protocol defines */
+#define SNTP_MAX_DATA_LEN           48
+#define SNTP_RCV_TIME_OFS           32
+#define SNTP_LI_NO_WARNING          0x00
+#define SNTP_VERSION               (4/* NTP Version 4*/<<3)
+#define SNTP_MODE_CLIENT            0x03
+#define SNTP_MODE_SERVER            0x04
+#define SNTP_MODE_BROADCAST         0x05
+#define SNTP_MODE_MASK              0x07
+
+/* number of seconds between 1900 and 1970 */
+#define DIFF_SEC_1900_1970         (2208988800)
+
+/**
+ * SNTP processing
+ */
+static void sntp_process( time_t t)
+{
+	/* change system time and/or the update the RTC clock */
+	SNTP_SYSTEM_TIME(t);
+
+	/* display local time from GMT time */
+	LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t)));
+}
+
+/**
+ * SNTP request
+ */
+static void sntp_request()
+{
+	int                sock;
+	struct sockaddr_in local;
+	struct sockaddr_in to;
+	int                tolen;
+	int                size;
+	int                timeout;
+	u8_t               sntp_request [SNTP_MAX_DATA_LEN];
+	u8_t               sntp_response[SNTP_MAX_DATA_LEN];
+	u32_t              sntp_server_address;
+	u32_t              timestamp;
+	time_t             t;
+
+	/* initialize SNTP server address */
+	sntp_server_address = SNTP_SERVER_ADDRESS;
+
+	/* if we got a valid SNTP server address... */
+	if (sntp_server_address!=0)
+	{
+		/* create new socket */
+		sock = socket( AF_INET, SOCK_DGRAM, 0);
+		if (sock>=0)
+		{
+			/* prepare local address */
+			memset(&local, 0, sizeof(local));
+			local.sin_family      = AF_INET;
+			local.sin_port        = htons(INADDR_ANY);
+			local.sin_addr.s_addr = htonl(INADDR_ANY);
+
+			/* bind to local address */
+			if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
+			{
+				/* set recv timeout */
+				timeout = SNTP_RECV_TIMEOUT;
+				setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
+
+				/* prepare SNTP request */
+				memset( sntp_request, 0, sizeof(sntp_request));
+				sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
+
+				/* prepare SNTP server address */
+				memset(&to, 0, sizeof(to));
+				to.sin_family      = AF_INET;
+				to.sin_port        = htons(SNTP_PORT);
+				to.sin_addr.s_addr = sntp_server_address;
+
+				/* send SNTP request to server */
+				if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
+				{
+					/* receive SNTP server response */
+					tolen = sizeof(to);
+					size  = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);
+
+					/* if the response size is good */
+					if (size == SNTP_MAX_DATA_LEN)
+					{
+						/* if this is a SNTP response... */
+						if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
+						{
+							/* extract GMT time from response */
+							SMEMCPY( &timestamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
+							t = (ntohl(timestamp) - DIFF_SEC_1900_1970);
+
+							/* do time processing */
+							sntp_process(t);
+
+						}
+						else
+						{
+							LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
+						}
+					}
+					else
+					{
+						LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
+					}
+				}
+				else
+				{
+					LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
+				}
+			}
+			/* close the socket */
+			closesocket(sock);
+		}
+	}
+}
+
+/**
+ * SNTP thread
+ */
+static void
+sntp_thread(void *arg)
+{
+	LWIP_UNUSED_ARG(arg);
+	while(1)
+	{
+		sntp_request();
+		sys_msleep(SNTP_UPDATE_DELAY);
+	}
+}
+
+void sntp_init(void)
+{
+	sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
+}

+ 68 - 68
components/net/apps/tcpecho.c → components/net/lwip-1.4.0/apps/tcpecho.c

@@ -1,68 +1,68 @@
-#include <lwip/api.h>
-
-#define TCP_ECHO_PORT   7
-
-void tcpecho_entry(void *parameter)
-{
-	struct netconn *conn, *newconn;
-	err_t err;
-
-	/* Create a new connection identifier. */
-	conn = netconn_new(NETCONN_TCP);
-
-	/* Bind connection to well known port number 7. */
-	netconn_bind(conn, NULL, TCP_ECHO_PORT);
-
-	/* Tell connection to go into listening mode. */
-	netconn_listen(conn);
-
-	while(1)
-	{
-		/* Grab new connection. */
-		err = netconn_accept(conn, &newconn);
-		/* Process the new connection. */
-		if(err == ERR_OK)
-		{
-			struct netbuf *buf;
-			void *data;
-			u16_t len;
-
-			while(netconn_recv(newconn, &buf) == ERR_OK)
-			{
-				do
-				{
-					netbuf_data(buf, &data, &len);
-					err = netconn_write(newconn, data, len, NETCONN_COPY);
-					if(err != ERR_OK){}
-				}
-				while(netbuf_next(buf) >= 0);
-				netbuf_delete(buf);
-			}
-			/* Close connection and discard connection identifier. */
-			netconn_delete(newconn);
-		}
-	}
-}
-
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-static rt_thread_t echo_tid = RT_NULL;
-void tcpecho(rt_uint32_t startup)
-{
-    if (startup && echo_tid == RT_NULL)
-    {
-        echo_tid = rt_thread_create("echo",
-			tcpecho_entry, RT_NULL,
-            512, 30, 5);
-        if (echo_tid != RT_NULL)
-            rt_thread_startup(echo_tid);
-    }
-    else
-    {
-        if (echo_tid != RT_NULL)
-            rt_thread_delete(echo_tid); /* delete thread */
-        echo_tid = RT_NULL;
-    }
-}
-FINSH_FUNCTION_EXPORT(tcpecho, startup or stop TCP echo server);
-#endif
+#include <lwip/api.h>
+
+#define TCP_ECHO_PORT   7
+
+void tcpecho_entry(void *parameter)
+{
+	struct netconn *conn, *newconn;
+	err_t err;
+
+	/* Create a new connection identifier. */
+	conn = netconn_new(NETCONN_TCP);
+
+	/* Bind connection to well known port number 7. */
+	netconn_bind(conn, NULL, TCP_ECHO_PORT);
+
+	/* Tell connection to go into listening mode. */
+	netconn_listen(conn);
+
+	while(1)
+	{
+		/* Grab new connection. */
+		err = netconn_accept(conn, &newconn);
+		/* Process the new connection. */
+		if(err == ERR_OK)
+		{
+			struct netbuf *buf;
+			void *data;
+			u16_t len;
+
+			while(netconn_recv(newconn, &buf) == ERR_OK)
+			{
+				do
+				{
+					netbuf_data(buf, &data, &len);
+					err = netconn_write(newconn, data, len, NETCONN_COPY);
+					if(err != ERR_OK){}
+				}
+				while(netbuf_next(buf) >= 0);
+				netbuf_delete(buf);
+			}
+			/* Close connection and discard connection identifier. */
+			netconn_delete(newconn);
+		}
+	}
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+static rt_thread_t echo_tid = RT_NULL;
+void tcpecho(rt_uint32_t startup)
+{
+    if (startup && echo_tid == RT_NULL)
+    {
+        echo_tid = rt_thread_create("echo",
+			tcpecho_entry, RT_NULL,
+            512, 30, 5);
+        if (echo_tid != RT_NULL)
+            rt_thread_startup(echo_tid);
+    }
+    else
+    {
+        if (echo_tid != RT_NULL)
+            rt_thread_delete(echo_tid); /* delete thread */
+        echo_tid = RT_NULL;
+    }
+}
+FINSH_FUNCTION_EXPORT(tcpecho, startup or stop TCP echo server);
+#endif

+ 206 - 206
components/net/apps/tftp.c → components/net/lwip-1.4.0/apps/tftp.c

@@ -1,206 +1,206 @@
-#include <rtthread.h>
-#include <dfs_posix.h>
-#include <lwip/sockets.h>
-
-#include <finsh.h>
-
-#define TFTP_PORT	69
-/* opcode */
-#define TFTP_RRQ			1 	/* read request */
-#define TFTP_WRQ			2	/* write request */
-#define TFTP_DATA			3	/* data */
-#define TFTP_ACK			4	/* ACK */
-#define TFTP_ERROR			5	/* error */
-
-rt_uint8_t tftp_buffer[512 + 4];
-/* tftp client */
-void tftp_get(const char* host, const char* dir, const char* filename)
-{
-	int fd, sock_fd, sock_opt;
-	struct sockaddr_in tftp_addr, from_addr;
-	rt_uint32_t length;
-	socklen_t fromlen;
-
-	/* make local file name */
-	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
-		"%s/%s", dir, filename);
-
-	/* open local file for write */
-	fd = open((char*)tftp_buffer, O_RDWR | O_CREAT, 0);
-	if (fd < 0)
-	{
-		rt_kprintf("can't open local filename\n");
-		return;
-	}
-
-	/* connect to tftp server */
-    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
-    tftp_addr.sin_family = AF_INET;
-    tftp_addr.sin_port = htons(TFTP_PORT);
-    
-    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
-    if (sock_fd < 0)
-	{
-	    close(fd);
-	    rt_kprintf("can't create a socket\n");
-	    return ;
-	}
-	
-	/* set socket option */
-	sock_opt = 5000; /* 5 seconds */
-	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
-
-	/* make tftp request */
-	tftp_buffer[0] = 0;			/* opcode */
-	tftp_buffer[1] = TFTP_RRQ; 	/* RRQ */
-	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
-	tftp_buffer[length] = 0; length ++;
-	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
-	tftp_buffer[length] = 0; length ++;
-
-	fromlen = sizeof(struct sockaddr_in);
-	
-	/* send request */	
-	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
-		(struct sockaddr *)&tftp_addr, fromlen);
-	
-	do
-	{
-		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
-			(struct sockaddr *)&from_addr, &fromlen);
-		
-		if (length > 0)
-		{
-			write(fd, (char*)&tftp_buffer[4], length - 4);
-			rt_kprintf("#");
-
-			/* make ACK */			
-			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */
-			/* send ACK */
-			lwip_sendto(sock_fd, tftp_buffer, 4, 0, 
-				(struct sockaddr *)&from_addr, fromlen);
-		}
-	} while (length == 516);
-
-	if (length == 0) rt_kprintf("timeout\n");
-	else rt_kprintf("done\n");
-
-	close(fd);
-	lwip_close(sock_fd);
-}
-FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server);
-
-void tftp_put(const char* host, const char* dir, const char* filename)
-{
-	int fd, sock_fd, sock_opt;
-	struct sockaddr_in tftp_addr, from_addr;
-	rt_uint32_t length, block_number = 0;
-	socklen_t fromlen;
-
-	/* make local file name */
-	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
-		"%s/%s", dir, filename);
-
-	/* open local file for write */
-	fd = open((char*)tftp_buffer, O_RDONLY, 0);
-	if (fd < 0)
-	{
-		rt_kprintf("can't open local filename\n");
-		return;
-	}
-
-	/* connect to tftp server */
-    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
-    tftp_addr.sin_family = AF_INET;
-    tftp_addr.sin_port = htons(TFTP_PORT);
-
-    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
-    if (sock_fd < 0)
-	{
-	    close(fd);
-	    rt_kprintf("can't create a socket\n");
-	    return ;
-	}
-
-	/* set socket option */
-	sock_opt = 5000; /* 5 seconds */
-	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
-
-	/* make tftp request */
-	tftp_buffer[0] = 0;			/* opcode */
-	tftp_buffer[1] = TFTP_WRQ; 	/* WRQ */
-	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
-	tftp_buffer[length] = 0; length ++;
-	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
-	tftp_buffer[length] = 0; length ++;
-
-	fromlen = sizeof(struct sockaddr_in);
-	
-	/* send request */	
-	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
-		(struct sockaddr *)&tftp_addr, fromlen);
-
-	/* wait ACK 0 */	
-	length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
-		(struct sockaddr *)&from_addr, &fromlen);
-	if (!(tftp_buffer[0] == 0 &&
-		tftp_buffer[1] == TFTP_ACK &&
-		tftp_buffer[2] == 0 &&
-		tftp_buffer[3] == 0))
-	{
-		rt_kprintf("tftp server error\n");
-		close(fd);
-		return;
-	}
-
-	block_number = 1;
-	
-	while (1)
-	{
-		length = read(fd, (char*)&tftp_buffer[4], 512);
-		if (length > 0)
-		{
-			/* make opcode and block number */
-			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA;
-			tftp_buffer[2] = (block_number >> 8) & 0xff;
-			tftp_buffer[3] = block_number & 0xff;
-
-			lwip_sendto(sock_fd, tftp_buffer, length + 4, 0, 
-				(struct sockaddr *)&from_addr, fromlen);
-		}
-		else
-		{
-			rt_kprintf("done\n");
-			break; /* no data yet */
-		}
-
-		/* receive ack */
-		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
-			(struct sockaddr *)&from_addr, &fromlen);
-		if (length > 0)
-		{
-			if ((tftp_buffer[0] == 0 &&
-				tftp_buffer[1] == TFTP_ACK &&
-				tftp_buffer[2] == (block_number >> 8) & 0xff) &&
-				tftp_buffer[3] == (block_number & 0xff))
-			{
-				block_number ++;
-				rt_kprintf("#");
-			}
-			else 
-			{
-				rt_kprintf("server respondes with an error\n");
-				break;
-			}
-		}
-		else if (length == 0)
-		{
-			rt_kprintf("server timeout\n");
-			break;
-		}
-	}
-
-	close(fd);
-	lwip_close(sock_fd);
-}
-FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <lwip/sockets.h>
+
+#include <finsh.h>
+
+#define TFTP_PORT	69
+/* opcode */
+#define TFTP_RRQ			1 	/* read request */
+#define TFTP_WRQ			2	/* write request */
+#define TFTP_DATA			3	/* data */
+#define TFTP_ACK			4	/* ACK */
+#define TFTP_ERROR			5	/* error */
+
+rt_uint8_t tftp_buffer[512 + 4];
+/* tftp client */
+void tftp_get(const char* host, const char* dir, const char* filename)
+{
+	int fd, sock_fd, sock_opt;
+	struct sockaddr_in tftp_addr, from_addr;
+	rt_uint32_t length;
+	socklen_t fromlen;
+
+	/* make local file name */
+	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
+		"%s/%s", dir, filename);
+
+	/* open local file for write */
+	fd = open((char*)tftp_buffer, O_RDWR | O_CREAT, 0);
+	if (fd < 0)
+	{
+		rt_kprintf("can't open local filename\n");
+		return;
+	}
+
+	/* connect to tftp server */
+    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
+    tftp_addr.sin_family = AF_INET;
+    tftp_addr.sin_port = htons(TFTP_PORT);
+    
+    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+    if (sock_fd < 0)
+	{
+	    close(fd);
+	    rt_kprintf("can't create a socket\n");
+	    return ;
+	}
+	
+	/* set socket option */
+	sock_opt = 5000; /* 5 seconds */
+	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
+
+	/* make tftp request */
+	tftp_buffer[0] = 0;			/* opcode */
+	tftp_buffer[1] = TFTP_RRQ; 	/* RRQ */
+	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
+	tftp_buffer[length] = 0; length ++;
+	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
+	tftp_buffer[length] = 0; length ++;
+
+	fromlen = sizeof(struct sockaddr_in);
+	
+	/* send request */	
+	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
+		(struct sockaddr *)&tftp_addr, fromlen);
+	
+	do
+	{
+		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+			(struct sockaddr *)&from_addr, &fromlen);
+		
+		if (length > 0)
+		{
+			write(fd, (char*)&tftp_buffer[4], length - 4);
+			rt_kprintf("#");
+
+			/* make ACK */			
+			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */
+			/* send ACK */
+			lwip_sendto(sock_fd, tftp_buffer, 4, 0, 
+				(struct sockaddr *)&from_addr, fromlen);
+		}
+	} while (length == 516);
+
+	if (length == 0) rt_kprintf("timeout\n");
+	else rt_kprintf("done\n");
+
+	close(fd);
+	lwip_close(sock_fd);
+}
+FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server);
+
+void tftp_put(const char* host, const char* dir, const char* filename)
+{
+	int fd, sock_fd, sock_opt;
+	struct sockaddr_in tftp_addr, from_addr;
+	rt_uint32_t length, block_number = 0;
+	socklen_t fromlen;
+
+	/* make local file name */
+	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
+		"%s/%s", dir, filename);
+
+	/* open local file for write */
+	fd = open((char*)tftp_buffer, O_RDONLY, 0);
+	if (fd < 0)
+	{
+		rt_kprintf("can't open local filename\n");
+		return;
+	}
+
+	/* connect to tftp server */
+    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
+    tftp_addr.sin_family = AF_INET;
+    tftp_addr.sin_port = htons(TFTP_PORT);
+
+    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+    if (sock_fd < 0)
+	{
+	    close(fd);
+	    rt_kprintf("can't create a socket\n");
+	    return ;
+	}
+
+	/* set socket option */
+	sock_opt = 5000; /* 5 seconds */
+	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
+
+	/* make tftp request */
+	tftp_buffer[0] = 0;			/* opcode */
+	tftp_buffer[1] = TFTP_WRQ; 	/* WRQ */
+	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
+	tftp_buffer[length] = 0; length ++;
+	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
+	tftp_buffer[length] = 0; length ++;
+
+	fromlen = sizeof(struct sockaddr_in);
+	
+	/* send request */	
+	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
+		(struct sockaddr *)&tftp_addr, fromlen);
+
+	/* wait ACK 0 */	
+	length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+		(struct sockaddr *)&from_addr, &fromlen);
+	if (!(tftp_buffer[0] == 0 &&
+		tftp_buffer[1] == TFTP_ACK &&
+		tftp_buffer[2] == 0 &&
+		tftp_buffer[3] == 0))
+	{
+		rt_kprintf("tftp server error\n");
+		close(fd);
+		return;
+	}
+
+	block_number = 1;
+	
+	while (1)
+	{
+		length = read(fd, (char*)&tftp_buffer[4], 512);
+		if (length > 0)
+		{
+			/* make opcode and block number */
+			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA;
+			tftp_buffer[2] = (block_number >> 8) & 0xff;
+			tftp_buffer[3] = block_number & 0xff;
+
+			lwip_sendto(sock_fd, tftp_buffer, length + 4, 0, 
+				(struct sockaddr *)&from_addr, fromlen);
+		}
+		else
+		{
+			rt_kprintf("done\n");
+			break; /* no data yet */
+		}
+
+		/* receive ack */
+		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+			(struct sockaddr *)&from_addr, &fromlen);
+		if (length > 0)
+		{
+			if ((tftp_buffer[0] == 0 &&
+				tftp_buffer[1] == TFTP_ACK &&
+				tftp_buffer[2] == (block_number >> 8) & 0xff) &&
+				tftp_buffer[3] == (block_number & 0xff))
+			{
+				block_number ++;
+				rt_kprintf("#");
+			}
+			else 
+			{
+				rt_kprintf("server respondes with an error\n");
+				break;
+			}
+		}
+		else if (length == 0)
+		{
+			rt_kprintf("server timeout\n");
+			break;
+		}
+	}
+
+	close(fd);
+	lwip_close(sock_fd);
+}
+FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);

+ 56 - 56
components/net/apps/udpecho.c → components/net/lwip-1.4.0/apps/udpecho.c

@@ -1,56 +1,56 @@
-#include <lwip/api.h>
-
-#define UDP_ECHO_PORT   7
-
-void udpecho_entry(void *parameter)
-{
-	struct netconn *conn;
-	struct netbuf *buf;
-	struct ip_addr *addr;
-	unsigned short port;
-
-	conn = netconn_new(NETCONN_UDP);
-	netconn_bind(conn, IP_ADDR_ANY, 7);
-
-	while(1)
-	{
-        /* received data to buffer */
-		netconn_recv(conn, &buf);
-
-		addr = netbuf_fromaddr(buf);
-		port = netbuf_fromport(buf);
-
-        /* send the data to buffer */
-		netconn_connect(conn, addr, port);
-
-		/* reset address, and send to client */
-		buf->addr = *IP_ADDR_ANY;
-		netconn_send(conn, buf);
-
-        /* release buffer */
-		netbuf_delete(buf);
-	}
-}
-
-#ifdef RT_USING_FINSH
-#include <finsh.h>
-static rt_thread_t echo_tid = RT_NULL;
-void udpecho(rt_uint32_t startup)
-{
-	if (startup && echo_tid == RT_NULL)
-	{
-		echo_tid = rt_thread_create("uecho",
-									udpecho_entry, RT_NULL,
-									512, 30, 5);
-		if (echo_tid != RT_NULL)
-			rt_thread_startup(echo_tid);
-	}
-	else
-	{
-		if (echo_tid != RT_NULL)
-			rt_thread_delete(echo_tid); /* delete thread */
-		echo_tid = RT_NULL;
-	}
-}
-FINSH_FUNCTION_EXPORT(udpecho, startup or stop UDP echo server);
-#endif
+#include <lwip/api.h>
+
+#define UDP_ECHO_PORT   7
+
+void udpecho_entry(void *parameter)
+{
+	struct netconn *conn;
+	struct netbuf *buf;
+	struct ip_addr *addr;
+	unsigned short port;
+
+	conn = netconn_new(NETCONN_UDP);
+	netconn_bind(conn, IP_ADDR_ANY, 7);
+
+	while(1)
+	{
+        /* received data to buffer */
+		netconn_recv(conn, &buf);
+
+		addr = netbuf_fromaddr(buf);
+		port = netbuf_fromport(buf);
+
+        /* send the data to buffer */
+		netconn_connect(conn, addr, port);
+
+		/* reset address, and send to client */
+		buf->addr = *IP_ADDR_ANY;
+		netconn_send(conn, buf);
+
+        /* release buffer */
+		netbuf_delete(buf);
+	}
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+static rt_thread_t echo_tid = RT_NULL;
+void udpecho(rt_uint32_t startup)
+{
+	if (startup && echo_tid == RT_NULL)
+	{
+		echo_tid = rt_thread_create("uecho",
+									udpecho_entry, RT_NULL,
+									512, 30, 5);
+		if (echo_tid != RT_NULL)
+			rt_thread_startup(echo_tid);
+	}
+	else
+	{
+		if (echo_tid != RT_NULL)
+			rt_thread_delete(echo_tid); /* delete thread */
+		echo_tid = RT_NULL;
+	}
+}
+FINSH_FUNCTION_EXPORT(udpecho, startup or stop UDP echo server);
+#endif

+ 5 - 1
components/net/lwip/SConscript

@@ -80,6 +80,10 @@ if GetDepend(['RT_LWIP_PPP']):
     src += ppp_src
     path += [RTT_ROOT + '/components/net/lwip/src/netif/ppp']
 
-group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP', 'RT_LWIP_VER130'], CPPPATH = path)
+# For testing apps
+if GetDepend(['RT_USING_NETUTILS']):
+    src += Glob('./apps/*.c')
+
+group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP'], CPPPATH = path)
 
 Return('group')

+ 216 - 0
components/net/lwip/apps/chargen.c

@@ -0,0 +1,216 @@
+#include <rtthread.h>
+
+#include "lwip/sockets.h"
+#define MAX_SERV                 32         /* Maximum number of chargen services. Don't need too many */
+#define CHARGEN_THREAD_NAME      "chargen"
+#if RT_THREAD_PRIORITY_MAX == 32
+#define CHARGEN_PRIORITY         20        /* Really low priority */
+#else
+#define CHARGEN_PRIORITY         200       /* Really low priority */
+#endif
+#define CHARGEN_THREAD_STACKSIZE 1024
+struct charcb
+{
+    struct charcb *next;
+    int socket;
+    struct sockaddr_in cliaddr;
+    socklen_t clilen;
+    char nextchar;
+};
+
+static struct charcb *charcb_list = 0;
+static int do_read(struct charcb *p_charcb);
+static void close_chargen(struct charcb *p_charcb);
+
+/**************************************************************
+ * void chargen_thread(void *arg)
+ *
+ * chargen task. This server will wait for connections on well
+ * known TCP port number: 19. For every connection, the server will
+ * write as much data as possible to the tcp port.
+ **************************************************************/
+static void chargen_thread(void *arg)
+{
+    int listenfd;
+    struct sockaddr_in chargen_saddr;
+    fd_set readset;
+    fd_set writeset;
+    int i, maxfdp1;
+    struct charcb *p_charcb;
+
+    /* First acquire our socket for listening for connections */
+    listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+    LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
+    memset(&chargen_saddr, 0, sizeof(chargen_saddr));
+    chargen_saddr.sin_family = AF_INET;
+    chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    chargen_saddr.sin_port = htons(19);     // Chargen server port
+
+    if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
+        LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
+
+    /* Put socket into listening mode */
+    if (lwip_listen(listenfd, MAX_SERV) == -1)
+        LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
+
+    /* Wait forever for network input: This could be connections or data */
+    for (;;)
+    {
+        maxfdp1 = listenfd+1;
+
+        /* Determine what sockets need to be in readset */
+        FD_ZERO(&readset);
+        FD_ZERO(&writeset);
+        FD_SET(listenfd, &readset);
+        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
+        {
+            if (maxfdp1 < p_charcb->socket + 1)
+                maxfdp1 = p_charcb->socket + 1;
+            FD_SET(p_charcb->socket, &readset);
+            FD_SET(p_charcb->socket, &writeset);
+        }
+
+        /* Wait for data or a new connection */
+        i = lwip_select(maxfdp1, &readset, &writeset, 0, 0);
+
+        if (i == 0) continue;
+
+        /* At least one descriptor is ready */
+        if (FD_ISSET(listenfd, &readset))
+        {
+            /* We have a new connection request!!! */
+            /* Lets create a new control block */
+            p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
+            if (p_charcb)
+            {
+                p_charcb->socket = lwip_accept(listenfd,
+                                        (struct sockaddr *) &p_charcb->cliaddr,
+                                        &p_charcb->clilen);
+                if (p_charcb->socket < 0)
+                    rt_free(p_charcb);
+                else
+                {
+                    /* Keep this tecb in our list */
+                    p_charcb->next = charcb_list;
+                    charcb_list = p_charcb;
+                    p_charcb->nextchar = 0x21;
+                }
+            }
+			else
+			{
+                /* No memory to accept connection. Just accept and then close */
+                int sock;
+                struct sockaddr cliaddr;
+                socklen_t clilen;
+
+                sock = lwip_accept(listenfd, &cliaddr, &clilen);
+                if (sock >= 0)
+                    lwip_close(sock);
+            }
+        }
+        /* Go through list of connected clients and process data */
+        for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
+        {
+            if (FD_ISSET(p_charcb->socket, &readset))
+            {
+                /* This socket is ready for reading. This could be because someone typed
+                 * some characters or it could be because the socket is now closed. Try reading
+                 * some data to see. */
+                if (do_read(p_charcb) < 0)
+                    break;
+            }
+            if (FD_ISSET(p_charcb->socket, &writeset))
+            {
+                char line[80];
+                char setchar = p_charcb->nextchar;
+
+                for( i = 0; i < 59; i++)
+                {
+                    line[i] = setchar;
+                    if (++setchar == 0x7f)
+                        setchar = 0x21;
+                }
+                line[i] = 0;
+                strcat(line, "\n\r");
+                if (lwip_write(p_charcb->socket, line, strlen(line)) < 0)
+                {
+                    close_chargen(p_charcb);
+                    break;
+                }
+                if (++p_charcb->nextchar == 0x7f)
+                    p_charcb->nextchar = 0x21;
+            }
+        }
+    }
+}
+
+/**************************************************************
+ * void close_chargen(struct charcb *p_charcb)
+ *
+ * Close the socket and remove this charcb from the list.
+ **************************************************************/
+static void close_chargen(struct charcb *p_charcb)
+{
+    struct charcb *p_search_charcb;
+
+    /* Either an error or tcp connection closed on other
+     * end. Close here */
+    lwip_close(p_charcb->socket);
+
+    /* Free charcb */
+    if (charcb_list == p_charcb)
+        charcb_list = p_charcb->next;
+    else
+        for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
+        {
+            if (p_search_charcb->next == p_charcb)
+            {
+                p_search_charcb->next = p_charcb->next;
+                break;
+            }
+        }
+
+    rt_free(p_charcb);
+}
+
+/**************************************************************
+ * void do_read(struct charcb *p_charcb)
+ *
+ * Socket definitely is ready for reading. Read a buffer from the socket and
+ * discard the data.  If no data is read, then the socket is closed and the
+ * charcb is removed from the list and freed.
+ **************************************************************/
+static int do_read(struct charcb *p_charcb)
+{
+    char buffer[80];
+    int readcount;
+
+    /* Read some data */
+    readcount = lwip_read(p_charcb->socket, &buffer, 80);
+    if (readcount <= 0)
+    {
+        close_chargen(p_charcb);
+        return -1;
+    }
+    return 0;
+}
+
+void chargen_init(void)
+{
+	rt_thread_t chargen;
+
+	chargen = rt_thread_create(CHARGEN_THREAD_NAME,
+		chargen_thread, RT_NULL,
+		CHARGEN_THREAD_STACKSIZE,
+		CHARGEN_PRIORITY, 5);
+	if (chargen != RT_NULL) rt_thread_startup(chargen);
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+void chargen()
+{
+	chargen_init();
+}
+FINSH_FUNCTION_EXPORT(chargen, start chargen server);
+#endif

+ 791 - 0
components/net/lwip/apps/ftpd.c

@@ -0,0 +1,791 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <lwip/sockets.h>
+#include <time.h>
+
+#define FTP_PORT			21
+#define FTP_SRV_ROOT		"/"
+#define FTP_MAX_CONNECTION	2
+#define FTP_USER			"rtt"
+#define FTP_PASSWORD		"demo"
+#define FTP_WELCOME_MSG		"220-= welcome on RT-Thread FTP server =-\r\n220 \r\n"
+#define FTP_BUFFER_SIZE		1024
+
+struct ftp_session
+{
+	rt_bool_t is_anonymous;
+
+	int sockfd;
+	struct sockaddr_in remote;
+
+	/* pasv data */
+	char pasv_active;
+	int  pasv_sockfd;
+
+	unsigned short pasv_port;
+	size_t offset;
+
+	/* current directory */
+	char currentdir[256];
+
+	struct ftp_session* next;
+};
+static struct ftp_session* session_list = NULL;
+
+int ftp_process_request(struct ftp_session* session, char * buf);
+int ftp_get_filesize(char *filename);
+
+struct ftp_session* ftp_new_session()
+{
+	struct ftp_session* session;
+
+	session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session));
+
+	session->next = session_list;
+	session_list = session;
+
+	return session;
+}
+
+void ftp_close_session(struct ftp_session* session)
+{
+	struct ftp_session* list;
+
+	if (session_list == session)
+	{
+		session_list = session_list->next;
+		session->next = NULL;
+	}
+	else
+	{
+		list = session_list;
+		while (list->next != session) list = list->next;
+
+		list->next = session->next;
+		session->next = NULL;
+	}
+
+	rt_free(session);
+}
+
+int ftp_get_filesize(char * filename)
+{
+	int pos;
+	int end;
+	int fd;
+
+	fd = open(filename, O_RDONLY, 0);
+	if (fd < 0) return -1;
+
+	pos = lseek(fd, 0, SEEK_CUR);
+	end = lseek(fd, 0, SEEK_END);
+	lseek (fd, pos, SEEK_SET);
+	close(fd);
+
+	return end;
+}
+
+rt_bool_t is_absolute_path(char* path)
+{
+#ifdef _WIN32
+	if (path[0] == '\\' ||
+		(path[1] == ':' && path[2] == '\\'))
+		return RT_TRUE;
+#else
+	if (path[0] == '/') return RT_TRUE;
+#endif
+
+	return RT_FALSE;
+}
+
+int build_full_path(struct ftp_session* session, char* path, char* new_path, size_t size)
+{
+	if (is_absolute_path(path) == RT_TRUE)
+		strcpy(new_path, path);
+	else
+	{
+		rt_sprintf(new_path, "%s/%s", session->currentdir, path);
+	}
+
+	return 0;
+}
+
+void ftpd_thread_entry(void* parameter)
+{
+	int numbytes;
+	int sockfd, maxfdp1;
+	struct sockaddr_in local;
+	fd_set readfds, tmpfds;
+	struct ftp_session* session;
+	rt_uint32_t addr_len = sizeof(struct sockaddr);
+	char * buffer = (char *) rt_malloc(FTP_BUFFER_SIZE);
+
+	local.sin_port=htons(FTP_PORT);
+	local.sin_family=PF_INET;
+	local.sin_addr.s_addr=INADDR_ANY;
+
+	FD_ZERO(&readfds);
+	FD_ZERO(&tmpfds);
+
+	sockfd=socket(AF_INET, SOCK_STREAM, 0);
+	if(sockfd < 0)
+	{
+		rt_kprintf("create socket failed\n");
+		return ;
+	}
+
+	bind(sockfd, (struct sockaddr *)&local, addr_len);
+	listen(sockfd, FTP_MAX_CONNECTION);
+
+	FD_SET(sockfd, &readfds);
+	for(;;)
+	{
+	    /* get maximum fd */
+	    maxfdp1 = sockfd + 1;
+        session = session_list;
+	    while (session != RT_NULL)
+	    {
+	        if (maxfdp1 < session->sockfd + 1)
+                maxfdp1 = session->sockfd + 1;
+
+            FD_SET(session->sockfd, &readfds);
+            session = session->next;
+	    }
+
+		tmpfds=readfds;
+		if (select(maxfdp1, &tmpfds, 0, 0, 0) == 0) continue;
+
+		if(FD_ISSET(sockfd, &tmpfds))
+		{
+			int com_socket;
+			struct sockaddr_in remote;
+
+			com_socket = accept(sockfd, (struct sockaddr*)&remote, &addr_len);
+			if(com_socket == -1)
+			{
+				rt_kprintf("Error on accept()\nContinuing...\n");
+				continue;
+			}
+			else
+			{
+				rt_kprintf("Got connection from %s\n", inet_ntoa(remote.sin_addr));
+				send(com_socket, FTP_WELCOME_MSG, strlen(FTP_WELCOME_MSG), 0);
+				FD_SET(com_socket, &readfds);
+
+				/* new session */
+				session = ftp_new_session();
+				if (session != NULL)
+				{
+					strcpy(session->currentdir, FTP_SRV_ROOT);
+					session->sockfd = com_socket;
+					session->remote = remote;
+				}
+			}
+		}
+
+		{
+			struct ftp_session* next;
+
+			session = session_list;
+			while (session != NULL)
+			{
+				next = session->next;
+				if (FD_ISSET(session->sockfd, &tmpfds))
+				{
+					numbytes=recv(session->sockfd, buffer, FTP_BUFFER_SIZE, 0);
+					if(numbytes==0 || numbytes==-1)
+					{
+						rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr));
+						FD_CLR(session->sockfd, &readfds);
+						closesocket(session->sockfd);
+						ftp_close_session(session);
+					}
+					else
+					{
+						buffer[numbytes]=0;
+						if(ftp_process_request(session, buffer)==-1)
+						{
+							rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr));
+							closesocket(session->sockfd);
+							ftp_close_session(session);
+						}
+					}
+				}
+
+				session = next;
+			}
+		}
+	}
+
+	// rt_free(buffer);
+}
+
+int do_list(char* directory, int sockfd)
+{
+	DIR* dirp;
+	struct dirent* entry;
+	char line_buffer[256], line_length;
+#ifdef _WIN32
+	struct _stat s;
+#else
+	struct stat s;
+#endif
+
+	dirp = opendir(directory);
+	if (dirp == NULL)
+	{
+		line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
+		send(sockfd, line_buffer, line_length, 0);
+		return -1;
+	}
+
+	while (1)
+	{
+		entry = readdir(dirp);
+		if (entry == NULL) break;
+
+		rt_sprintf(line_buffer, "%s/%s", directory, entry->d_name);
+#ifdef _WIN32
+		if (_stat(line_buffer, &s) ==0)
+#else
+		if (stat(line_buffer, &s) == 0)
+#endif
+		{
+			if (s.st_mode & S_IFDIR)
+				line_length = rt_sprintf(line_buffer, "drw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", 0, entry->d_name);
+			else
+				line_length = rt_sprintf(line_buffer, "-rw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", s.st_size, entry->d_name);
+
+			send(sockfd, line_buffer, line_length, 0);
+		}
+		else
+		{
+			rt_kprintf("Get directory entry error\n");
+			break;
+		}
+	}
+
+	closedir(dirp);
+	return 0;
+}
+
+int do_simple_list(char* directory, int sockfd)
+{
+	DIR* dirp;
+	struct dirent* entry;
+	char line_buffer[256], line_length;
+
+	dirp = opendir(directory);
+	if (dirp == NULL)
+	{
+		line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
+		send(sockfd, line_buffer, line_length, 0);
+		return -1;
+	}
+
+	while (1)
+	{
+		entry = readdir(dirp);
+		if (entry == NULL) break;
+
+		line_length = rt_sprintf(line_buffer, "%s\r\n", entry->d_name);
+		send(sockfd, line_buffer, line_length, 0);
+	}
+
+	closedir(dirp);
+	return 0;
+}
+
+int str_begin_with(char* src, char* match)
+{
+	while (*match)
+	{
+		/* check source */
+		if (*src == 0) return -1;
+
+		if (*match != *src) return -1;
+		match ++; src ++;
+	}
+
+	return 0;
+}
+
+int ftp_process_request(struct ftp_session* session, char *buf)
+{
+	int  fd;
+	struct timeval tv;
+	fd_set readfds;
+	char filename[256];
+	int  numbytes;
+	char *sbuf;
+	char *parameter_ptr, *ptr;
+	rt_uint32_t addr_len = sizeof(struct sockaddr_in);
+	struct sockaddr_in local, pasvremote;
+
+	sbuf =(char *)rt_malloc(FTP_BUFFER_SIZE);
+
+	tv.tv_sec=3, tv.tv_usec=0;
+	local.sin_family=PF_INET;
+	local.sin_addr.s_addr=INADDR_ANY;
+
+	/* remove \r\n */
+	ptr = buf;
+	while (*ptr)
+	{
+		if (*ptr == '\r' || *ptr == '\n') *ptr = 0;
+		ptr ++;
+	}
+
+	/* get request parameter */
+	parameter_ptr = strchr(buf, ' '); if (parameter_ptr != NULL) parameter_ptr ++;
+
+	// debug:
+	rt_kprintf("%s requested: \"%s\"\n", inet_ntoa(session->remote.sin_addr), buf);
+
+	//
+	//-----------------------
+	if(str_begin_with(buf, "USER")==0)
+	{
+		rt_kprintf("%s sent login \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
+		// login correct
+		if(strcmp(parameter_ptr, "anonymous") == 0)
+		{
+			session->is_anonymous = RT_TRUE;
+			rt_sprintf(sbuf, "331 Anonymous login OK send e-mail address for password.\r\n", parameter_ptr);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else if (strcmp(parameter_ptr, FTP_USER) == 0)
+		{
+			session->is_anonymous = RT_FALSE;		
+			rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else
+		{
+			// incorrect login
+			rt_sprintf(sbuf, "530 Login incorrect. Bye.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);
+			return -1;
+		}
+		return 0;
+	}
+	else if(str_begin_with(buf, "PASS")==0)
+	{
+		rt_kprintf("%s sent password \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
+		if (strcmp(parameter_ptr, FTP_PASSWORD)==0 ||
+			session->is_anonymous == RT_TRUE)
+		{
+			// password correct
+			rt_sprintf(sbuf, "230 User logged in\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);			
+			return 0;
+		}
+
+		// incorrect password
+		rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		rt_free(sbuf);		
+		return -1;
+	}
+	else if(str_begin_with(buf, "LIST")==0  )
+	{
+		memset(sbuf,0,FTP_BUFFER_SIZE);
+		rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		do_list(session->currentdir, session->pasv_sockfd);
+		closesocket(session->pasv_sockfd);
+		session->pasv_active = 0;
+		rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "NLST")==0 )
+	{
+		memset(sbuf, 0, FTP_BUFFER_SIZE);
+		rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		do_simple_list(session->currentdir, session->pasv_sockfd);
+		closesocket(session->pasv_sockfd);
+		session->pasv_active = 0;
+		rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "PWD")==0 || str_begin_with(buf, "XPWD")==0)
+	{
+		rt_sprintf(sbuf, "257 \"%s\" is current directory.\r\n", session->currentdir);
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "TYPE")==0)
+	{
+		// Ignore it
+		if(strcmp(parameter_ptr, "I")==0)
+		{
+			rt_sprintf(sbuf, "200 Type set to binary.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else
+		{
+			rt_sprintf(sbuf, "200 Type set to ascii.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+	}
+	else if(str_begin_with(buf, "PASV")==0)
+	{
+		int dig1, dig2;
+		int sockfd;
+		char optval='1';
+
+		session->pasv_port = 10000;
+		session->pasv_active = 1;
+		local.sin_port=htons(session->pasv_port);
+		local.sin_addr.s_addr=INADDR_ANY;
+
+		dig1 = (int)(session->pasv_port/256);
+		dig2 = session->pasv_port % 256;
+
+		FD_ZERO(&readfds);
+		if((sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
+		{
+			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			goto err1;
+		}
+		if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
+		{
+			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			goto err1;
+		}
+		if(bind(sockfd, (struct sockaddr *)&local, addr_len)==-1)
+		{
+			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			goto err1;
+		}
+		if(listen(sockfd, 1)==-1)
+		{
+			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			goto err1;
+		}
+		rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
+		rt_sprintf(sbuf, "227 Entering passive mode (%d,%d,%d,%d,%d,%d)\r\n", 127, 0, 0, 1, dig1, dig2);
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		FD_SET(sockfd, &readfds);
+		select(0, &readfds, 0, 0, &tv);
+		if(FD_ISSET(sockfd, &readfds))
+		{
+			if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1)
+			{
+				rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+				send(session->sockfd, sbuf, strlen(sbuf), 0);
+				goto err1;
+			}
+			else
+			{
+				rt_kprintf("Got Data(PASV) connection from %s\n", inet_ntoa(pasvremote.sin_addr));
+				session->pasv_active = 1;
+				closesocket(sockfd);
+			}
+		}
+		else
+		{
+err1:
+			closesocket(session->pasv_sockfd);
+			session->pasv_active = 0;
+			rt_free(sbuf);
+			return 0;
+		}
+	}
+	else if (str_begin_with(buf, "RETR")==0)
+	{
+		int file_size;
+
+		strcpy(filename, buf + 5);
+
+		build_full_path(session, parameter_ptr, filename, 256);
+		file_size = ftp_get_filesize(filename);
+		if (file_size == -1)
+		{
+			rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			session->offset=0;
+			rt_free(sbuf);			
+			return 0;
+		}
+
+		fd = open(filename, O_RDONLY, 0);
+		if (fd < 0)
+		{
+			rt_free(sbuf);
+			return 0;
+		}
+
+		if(session->offset>0 && session->offset < file_size)
+		{
+			lseek(fd, session->offset, SEEK_SET);
+			rt_sprintf(sbuf, "150 Opening binary mode data connection for partial \"%s\" (%d/%d bytes).\r\n",
+				filename, file_size - session->offset, file_size);
+		}
+		else
+		{
+			rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\" (%d bytes).\r\n", filename, file_size);
+		}
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		while((numbytes = read(fd, sbuf, FTP_BUFFER_SIZE))>0)
+		{
+			send(session->pasv_sockfd, sbuf, numbytes, 0);
+		}
+		rt_sprintf(sbuf, "226 Finished.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		close(fd);
+		closesocket(session->pasv_sockfd);
+	}
+	else if (str_begin_with(buf, "STOR")==0)
+	{
+		if(session->is_anonymous == RT_TRUE)
+		{
+			rt_sprintf(sbuf, "550 Permission denied.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);
+			return 0;
+		}
+
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
+		if(fd < 0)
+		{
+			rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);
+			return 0;
+		}
+		rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\".\r\n", filename);
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		FD_ZERO(&readfds);
+		FD_SET(session->pasv_sockfd, &readfds);
+		rt_kprintf("Waiting %d seconds for data...\n", tv.tv_sec);
+		while(select(session->pasv_sockfd+1, &readfds, 0, 0, &tv)>0 )
+		{
+			if((numbytes=recv(session->pasv_sockfd, sbuf, FTP_BUFFER_SIZE, 0))>0)
+			{
+				write(fd, sbuf, numbytes);
+			}
+			else if(numbytes==0)
+			{
+				close(fd);
+				closesocket(session->pasv_sockfd);
+				rt_sprintf(sbuf, "226 Finished.\r\n");
+				send(session->sockfd, sbuf, strlen(sbuf), 0);
+				break;
+			}
+			else if(numbytes==-1)
+			{
+				close(fd);
+				closesocket(session->pasv_sockfd);
+				rt_free(sbuf);
+				return -1;
+			}
+		}
+		closesocket(session->pasv_sockfd);
+	}
+	else if(str_begin_with(buf, "SIZE")==0)
+	{
+		int file_size;
+
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		file_size = ftp_get_filesize(filename);
+		if( file_size == -1)
+		{
+			rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else
+		{
+			rt_sprintf(sbuf, "213 %d\r\n", file_size);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+	}
+	else if(str_begin_with(buf, "MDTM")==0)
+	{
+		rt_sprintf(sbuf, "550 \"/\" : not a regular file\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "SYST")==0)
+	{
+		rt_sprintf(sbuf, "215 %s\r\n", "RT-Thread RTOS");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "CWD")==0)
+	{
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		strcpy(session->currentdir, filename);
+		rt_kprintf("Changed to directory %s", filename);
+	}
+	else if(str_begin_with(buf, "CDUP")==0)
+	{
+		rt_sprintf(filename, "%s/%s", session->currentdir, "..");
+
+		rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		strcpy(session->currentdir, filename);
+		rt_kprintf("Changed to directory %s", filename);
+	}
+	else if(str_begin_with(buf, "PORT")==0)
+	{
+		int i;
+		int portcom[6];
+		char tmpip[100];
+
+		i=0;
+		portcom[i++]=atoi(strtok(parameter_ptr, ".,;()"));
+		for(;i<6;i++)
+			portcom[i]=atoi(strtok(0, ".,;()"));
+		rt_sprintf(tmpip, "%d.%d.%d.%d", portcom[0], portcom[1], portcom[2], portcom[3]);
+
+		FD_ZERO(&readfds);
+		if((session->pasv_sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
+		{
+			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			closesocket(session->pasv_sockfd);
+			session->pasv_active = 0;
+			rt_free(sbuf);	
+			return 0;
+		}
+		pasvremote.sin_addr.s_addr=inet_addr(tmpip);
+		pasvremote.sin_port=htons(portcom[4] * 256 + portcom[5]);
+		pasvremote.sin_family=PF_INET;
+		if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
+		{
+			// is it only local address?try using gloal ip addr
+			pasvremote.sin_addr=session->remote.sin_addr;
+			if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
+			{
+				rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
+				send(session->sockfd, sbuf, strlen(sbuf), 0);
+				closesocket(session->pasv_sockfd);
+				rt_free(sbuf);				
+				return 0;
+			}
+		}
+		session->pasv_active=1;
+		session->pasv_port = portcom[4] * 256 + portcom[5];
+		rt_kprintf("Connected to Data(PORT) %s @ %d\n", tmpip, portcom[4] * 256 + portcom[5]);
+		rt_sprintf(sbuf, "200 Port Command Successful.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "REST")==0)
+	{
+		if(atoi(parameter_ptr)>=0)
+		{
+			session->offset=atoi(parameter_ptr);
+			rt_sprintf(sbuf, "350 Send RETR or STOR to start transfert.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+	}
+	else if(str_begin_with(buf, "MKD")==0)
+	{
+		if (session->is_anonymous == RT_TRUE)
+		{
+			rt_sprintf(sbuf, "550 Permission denied.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);			
+			return 0;
+		}
+
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		if(mkdir(filename, 0) == -1)
+		{
+			rt_sprintf(sbuf, "550 File \"%s\" exists.\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else
+		{
+			rt_sprintf(sbuf, "257 directory \"%s\" successfully created.\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+	}
+	else if(str_begin_with(buf, "DELE")==0)
+	{
+		if (session->is_anonymous == RT_TRUE)
+		{
+			rt_sprintf(sbuf, "550 Permission denied.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);
+			return 0;
+		}
+
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		if(unlink(filename)==0)
+			rt_sprintf(sbuf, "250 Successfully deleted file \"%s\".\r\n", filename);
+		else
+		{
+			rt_sprintf(sbuf, "550 Not such file or directory: %s.\r\n", filename);
+		}
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	else if(str_begin_with(buf, "RMD")==0)
+	{
+		if (session->is_anonymous == RT_TRUE)
+		{
+			rt_sprintf(sbuf, "550 Permission denied.\r\n");
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+			rt_free(sbuf);			
+			return 0;
+		}
+		build_full_path(session, parameter_ptr, filename, 256);
+
+		if(unlink(filename) == -1)
+		{
+			rt_sprintf(sbuf, "550 Directory \"%s\" doesn't exist.\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+		else
+		{
+			rt_sprintf(sbuf, "257 directory \"%s\" successfully deleted.\r\n", filename);
+			send(session->sockfd, sbuf, strlen(sbuf), 0);
+		}
+	}
+	
+	else if(str_begin_with(buf, "QUIT")==0)
+	{
+		rt_sprintf(sbuf, "221 Bye!\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+		rt_free(sbuf);		
+		return -1;
+	}
+	else
+	{
+		rt_sprintf(sbuf, "502 Not Implemented.\r\n");
+		send(session->sockfd, sbuf, strlen(sbuf), 0);
+	}
+	rt_free(sbuf);	
+	return 0;
+}
+
+void ftpd_start()
+{
+	rt_thread_t tid;
+
+	tid = rt_thread_create("ftpd",
+		ftpd_thread_entry, RT_NULL,
+		4096, 30, 5);
+	if (tid != RT_NULL) rt_thread_startup(tid);
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server)
+#endif

+ 370 - 0
components/net/lwip/apps/netio.c

@@ -0,0 +1,370 @@
+/**
+ * @file
+ * MetIO Server
+ *
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ */
+#include "lwip/opt.h"
+
+#if LWIP_TCP
+#include "lwip/tcp.h"
+
+/*
+ * This implements a netio server.
+ *  The client sends a command word (4 bytes) then a data length word (4 bytes).
+ *  If the command is "receive", the server is to consume "data length" bytes into
+ *   a circular buffer until the first byte is non-zero, then it is to consume
+ *   another command/data pair.
+ *  If the command is "send", the server is to send "data length" bytes from a circular
+ *   buffer with the first byte being zero, until "some time" (6 seconds in the
+ *   current netio126.zip download) has passed and then send one final buffer with
+ *   the first byte being non-zero. Then it is to consume another command/data pair.
+ */
+
+/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
+
+/* implementation options */
+#define NETIO_BUF_SIZE              (4 * 1024)
+#define NETIO_USE_STATIC_BUF        0
+
+/* NetIO server state definition */
+#define NETIO_STATE_WAIT_FOR_CMD    0
+#define NETIO_STATE_RECV_DATA       1
+#define NETIO_STATE_SEND_DATA       2
+#define NETIO_STATE_SEND_DATA_LAST  3
+#define NETIO_STATE_DONE            4
+
+struct netio_state {
+  u32_t  state;
+  u32_t  cmd;
+  u32_t  data_len;
+  u32_t  cntr;
+  u8_t * buf_ptr;
+  u32_t  buf_pos;
+  u32_t  first_byte;
+  u32_t  time_stamp;
+};
+
+/* NetIO command protocol definition */
+#define NETIO_CMD_QUIT              0
+#define NETIO_CMD_C2S               1
+#define NETIO_CMD_S2C               2
+#define NETIO_CMD_RES               3
+
+static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
+
+static void
+netio_close(void *arg, struct tcp_pcb *pcb)
+{
+  err_t err;
+
+  struct netio_state *ns = arg;
+  ns->state = NETIO_STATE_DONE;
+  tcp_recv(pcb, NULL);
+  err = tcp_close(pcb);
+
+  if (err != ERR_OK) {
+    /* closing failed, try again later */
+    tcp_recv(pcb, netio_recv);
+  } else {
+    /* closing succeeded */
+#if NETIO_USE_STATIC_BUF != 1
+    if(ns->buf_ptr != NULL){
+      mem_free(ns->buf_ptr);
+    }
+#endif
+    tcp_arg(pcb, NULL);
+    tcp_poll(pcb, NULL, 0);
+    tcp_sent(pcb, NULL);
+    if (arg != NULL) {
+      mem_free(arg);
+    }
+  }
+}
+
+static err_t
+netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+  struct netio_state *ns = arg;
+  u8_t * data_ptr;
+  u32_t data_cntr;
+  struct pbuf *q = p;
+  u16_t len;
+
+  if (p != NULL) {
+    tcp_recved(pcb, p->tot_len);
+  }
+
+  if (err == ERR_OK && q != NULL) {
+
+    while (q != NULL) {
+      data_cntr = q->len;
+      data_ptr = q->payload;
+      while (data_cntr--) {
+        if (ns->state == NETIO_STATE_DONE){
+          netio_close(ns, pcb);
+          break;
+        } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
+          if (ns->cntr < 4) {
+            /* build up the CMD field */
+            ns->cmd <<= 8;
+            ns->cmd |= *data_ptr++;
+            ns->cntr++;
+          } else if (ns->cntr < 8) {
+            /* build up the DATA field */
+            ns->data_len <<= 8;
+            ns->data_len |= *data_ptr++;
+            ns->cntr++;
+
+            if (ns->cntr == 8) {
+              /* now we have full command and data words */
+              ns->cntr = 0;
+              ns->buf_pos = 0;
+              ns->buf_ptr[0] = 0;
+              if (ns->cmd == NETIO_CMD_C2S) {
+                ns->state = NETIO_STATE_RECV_DATA;
+              } else if (ns->cmd == NETIO_CMD_S2C) {
+                ns->state = NETIO_STATE_SEND_DATA;
+                /* start timer */
+                ns->time_stamp = rt_tick_get();
+                /* send first round of data */
+
+                len = tcp_sndbuf(pcb);
+                len = LWIP_MIN(len, ns->data_len - ns->cntr);
+                len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
+
+                do {
+                  err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
+                  if (err == ERR_MEM) {
+                    len /= 2;
+                  }
+                } while ((err == ERR_MEM) && (len > 1));
+
+                ns->buf_pos += len;
+                ns->cntr    += len;
+
+              } else {
+                /* unrecognized command, punt */
+                ns->cntr = 0;
+                ns->buf_pos = 0;
+                ns->buf_ptr[0] = 0;
+                netio_close(ns, pcb);
+                break;
+              }
+            }
+          } else {
+            /* in trouble... shouldn't be in this state! */
+          }
+
+        } else if (ns->state == NETIO_STATE_RECV_DATA) {
+
+          if(ns->cntr == 0){
+            /* save the first byte of this new round of data
+             * this will not match ns->buf_ptr[0] in the case that
+             *   NETIO_BUF_SIZE is less than ns->data_len.
+             */
+            ns->first_byte = *data_ptr;
+          }
+
+          ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
+          ns->cntr++;
+
+          if (ns->buf_pos == NETIO_BUF_SIZE) {
+            /* circularize the buffer */
+            ns->buf_pos = 0;
+          }
+
+          if(ns->cntr == ns->data_len){
+            ns->cntr = 0;
+            if (ns->first_byte != 0) {
+              /* if this last round did not start with 0,
+               *  go look for another command */
+              ns->state = NETIO_STATE_WAIT_FOR_CMD;
+              ns->data_len = 0;
+              ns->cmd = 0;
+              /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
+            } else {
+              /* stay here and wait on more data */
+            }
+          }
+
+        } else if (ns->state == NETIO_STATE_SEND_DATA
+            || ns->state == NETIO_STATE_SEND_DATA_LAST) {
+          /* I don't think this should happen... */
+        } else {
+          /* done / quit */
+          netio_close(ns, pcb);
+          break;
+        } /* end of ns->state condition */
+      } /* end of while data still in this pbuf */
+
+      q = q->next;
+    }
+
+    pbuf_free(p);
+
+  } else {
+
+    /* error or closed by other side */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+
+    /* close the connection */
+    netio_close(ns, pcb);
+
+  }
+  return ERR_OK;
+
+}
+
+static err_t
+netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+  struct netio_state *ns = arg;
+  err_t err = ERR_OK;
+
+  if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
+    /* done with this round of sending */
+    ns->buf_pos = 0;
+    ns->cntr = 0;
+
+    /* check if timer expired */
+    if (rt_tick_get() - ns->time_stamp > 600) {
+      ns->buf_ptr[0] = 1;
+      ns->state = NETIO_STATE_SEND_DATA_LAST;
+    } else {
+      ns->buf_ptr[0] = 0;
+    }
+  }
+
+  if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
+    len = tcp_sndbuf(pcb);
+    len = LWIP_MIN(len, ns->data_len - ns->cntr);
+    len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
+
+    if(ns->cntr < ns->data_len){
+      do {
+        err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
+        if (err == ERR_MEM) {
+          len /= 2;
+        }
+      } while ((err == ERR_MEM) && (len > 1));
+
+      ns->buf_pos += len;
+      if(ns->buf_pos >= NETIO_BUF_SIZE){
+        ns->buf_pos = 0;
+      }
+
+      ns->cntr += len;
+    }
+  }
+
+  if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
+    /* we have buffered up all our data to send this last round, go look for a command */
+   ns->state = NETIO_STATE_WAIT_FOR_CMD;
+   ns->cntr  = 0;
+   /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
+  }
+
+  return ERR_OK;
+}
+
+static err_t
+netio_poll(void *arg, struct tcp_pcb *pcb)
+{
+  struct netio_state * ns = arg;
+  if(ns->state == NETIO_STATE_SEND_DATA){
+
+  } else if(ns->state == NETIO_STATE_DONE){
+    netio_close(ns, pcb);
+  }
+
+  return ERR_OK;
+
+}
+
+#if NETIO_USE_STATIC_BUF == 1
+static u8_t netio_buf[NETIO_BUF_SIZE];
+#endif
+
+static err_t
+netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
+{
+  struct netio_state * ns;
+
+  LWIP_UNUSED_ARG(err);
+
+  ns = mem_malloc(sizeof(struct netio_state));
+
+  if(ns == NULL){
+    return ERR_MEM;
+  }
+
+  ns->state = NETIO_STATE_WAIT_FOR_CMD;
+  ns->data_len = 0;
+  ns->cmd = 0;
+  ns->cntr = 0;
+  ns->buf_pos = 0;
+#if NETIO_USE_STATIC_BUF == 1
+  ns->buf_ptr = netio_buf;
+#else
+  ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
+
+  if(ns->buf_ptr == NULL){
+    mem_free(ns);
+    return ERR_MEM;
+  }
+#endif
+
+  ns->buf_ptr[0] = 0;
+
+  tcp_arg(pcb, ns);
+  tcp_sent(pcb, netio_sent);
+  tcp_recv(pcb, netio_recv);
+  tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
+  return ERR_OK;
+}
+
+void netio_init(void)
+{
+  struct tcp_pcb *pcb;
+
+  pcb = tcp_new();
+  tcp_bind(pcb, IP_ADDR_ANY, 18767);
+  pcb = tcp_listen(pcb);
+  tcp_accept(pcb, netio_accept);
+}
+
+#endif /* LWIP_TCP */
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(netio_init, netio server);
+#endif

+ 175 - 0
components/net/lwip/apps/ping.c

@@ -0,0 +1,175 @@
+/*
+ * netutils: ping implementation
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/mem.h"
+#include "lwip/icmp.h"
+#include "lwip/netif.h"
+#include "lwip/sys.h"
+#include "lwip/sockets.h"
+#include "lwip/inet.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+
+/**
+ * PING_DEBUG: Enable debugging for PING.
+ */
+#ifndef PING_DEBUG
+#define PING_DEBUG     LWIP_DBG_ON
+#endif
+
+/** ping receive timeout - in milliseconds */
+#define PING_RCV_TIMEO 1000
+/** ping delay - in milliseconds */
+#define PING_DELAY     100
+
+/** ping identifier - must fit on a u16_t */
+#ifndef PING_ID
+#define PING_ID        0xAFAF
+#endif
+
+/** ping additional data size to include in the packet */
+#ifndef PING_DATA_SIZE
+#define PING_DATA_SIZE 32
+#endif
+
+/* ping variables */
+static u16_t ping_seq_num;
+struct _ip_addr
+{
+	rt_uint8_t addr0, addr1, addr2, addr3;
+};
+
+/** Prepare a echo ICMP request */
+static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
+{
+	size_t i;
+	size_t data_len = len - sizeof(struct icmp_echo_hdr);
+
+	ICMPH_TYPE_SET(iecho, ICMP_ECHO);
+	ICMPH_CODE_SET(iecho, 0);
+	iecho->chksum = 0;
+	iecho->id     = PING_ID;
+	iecho->seqno  = htons(++ping_seq_num);
+
+	/* fill the additional data buffer with some data */
+	for(i = 0; i < data_len; i++)
+	{
+		((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
+	}
+
+	iecho->chksum = inet_chksum(iecho, len);
+}
+
+/* Ping using the socket ip */
+static err_t ping_send(int s, struct ip_addr *addr)
+{
+	int err;
+	struct icmp_echo_hdr *iecho;
+	struct sockaddr_in to;
+	size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
+	LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
+
+	iecho = rt_malloc(ping_size);
+	if (iecho == RT_NULL)
+	{
+		return ERR_MEM;
+	}
+
+	ping_prepare_echo(iecho, (u16_t)ping_size);
+
+	to.sin_len = sizeof(to);
+	to.sin_family = AF_INET;
+	to.sin_addr.s_addr = addr->addr;
+
+	err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
+	rt_free(iecho);
+
+	return (err ? ERR_OK : ERR_VAL);
+}
+
+static void ping_recv(int s)
+{
+	char buf[64];
+	int fromlen, len;
+	struct sockaddr_in from;
+	struct ip_hdr *iphdr;
+	struct icmp_echo_hdr *iecho;
+	struct _ip_addr *addr;
+
+	while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
+	{
+		if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
+		{
+			addr = (struct _ip_addr *)&(from.sin_addr);
+			rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+
+			iphdr = (struct ip_hdr *)buf;
+			iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
+			if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
+			{
+				return;
+			}
+			else
+			{
+				rt_kprintf("ping: drop\n");
+			}
+		}
+	}
+
+	if (len <= 0)
+	{
+		rt_kprintf("ping: timeout\n");
+	}
+}
+
+rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size)
+{
+	int s;
+	int timeout = PING_RCV_TIMEO;
+	struct ip_addr ping_target;
+	rt_uint32_t send_time;
+	struct _ip_addr
+	{
+		rt_uint8_t addr0, addr1, addr2, addr3;
+	} *addr;
+
+    send_time = 0;
+
+	if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR;
+	addr = (struct _ip_addr*)&ping_target;
+
+	if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
+	{
+	    rt_kprintf("create socket failled\n");
+		return -RT_ERROR;
+	}
+
+	lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+
+	while (1)
+	{
+		if (ping_send(s, &ping_target) == ERR_OK)
+		{
+			rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+			ping_recv(s);
+		}
+		else
+		{
+			rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+		}
+
+		send_time ++;
+		if (send_time >= time) break; /* send ping times reached, stop */
+
+		rt_thread_delay(PING_DELAY); /* take a delay */
+	}
+
+	return RT_EOK;
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(ping, ping network host);
+#endif

+ 213 - 0
components/net/lwip/apps/sntp.c

@@ -0,0 +1,213 @@
+/**
+ * @file
+ * SNTP client module
+ *
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ */
+
+#include "lwip/sys.h"
+#include "lwip/sockets.h"
+
+#include <string.h>
+#include <time.h>
+
+/** This is an example of a "SNTP" client (with socket API).
+ *
+ * For a list of some public NTP servers, see this link :
+ * http://support.ntp.org/bin/view/Servers/NTPPoolServers
+ *
+ */
+
+/**
+ * SNTP_DEBUG: Enable debugging for SNTP.
+ */
+#ifndef SNTP_DEBUG
+#define SNTP_DEBUG                  LWIP_DBG_ON
+#endif
+
+/** SNTP server port */
+#ifndef SNTP_PORT
+#define SNTP_PORT                   123
+#endif
+
+/** SNTP server address as IPv4 address in "u32_t" format */
+#ifndef SNTP_SERVER_ADDRESS
+#define SNTP_SERVER_ADDRESS         inet_addr("213.161.194.93") /* pool.ntp.org */
+#endif
+
+/** SNTP receive timeout - in milliseconds */
+#ifndef SNTP_RECV_TIMEOUT
+#define SNTP_RECV_TIMEOUT           3000
+#endif
+
+/** SNTP update delay - in milliseconds */
+#ifndef SNTP_UPDATE_DELAY
+#define SNTP_UPDATE_DELAY           60000
+#endif
+
+/** SNTP macro to change system time and/or the update the RTC clock */
+#ifndef SNTP_SYSTEM_TIME
+#define SNTP_SYSTEM_TIME(t)
+#endif
+
+/* SNTP protocol defines */
+#define SNTP_MAX_DATA_LEN           48
+#define SNTP_RCV_TIME_OFS           32
+#define SNTP_LI_NO_WARNING          0x00
+#define SNTP_VERSION               (4/* NTP Version 4*/<<3)
+#define SNTP_MODE_CLIENT            0x03
+#define SNTP_MODE_SERVER            0x04
+#define SNTP_MODE_BROADCAST         0x05
+#define SNTP_MODE_MASK              0x07
+
+/* number of seconds between 1900 and 1970 */
+#define DIFF_SEC_1900_1970         (2208988800)
+
+/**
+ * SNTP processing
+ */
+static void sntp_process( time_t t)
+{
+	/* change system time and/or the update the RTC clock */
+	SNTP_SYSTEM_TIME(t);
+
+	/* display local time from GMT time */
+	LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t)));
+}
+
+/**
+ * SNTP request
+ */
+static void sntp_request()
+{
+	int                sock;
+	struct sockaddr_in local;
+	struct sockaddr_in to;
+	int                tolen;
+	int                size;
+	int                timeout;
+	u8_t               sntp_request [SNTP_MAX_DATA_LEN];
+	u8_t               sntp_response[SNTP_MAX_DATA_LEN];
+	u32_t              sntp_server_address;
+	u32_t              timestamp;
+	time_t             t;
+
+	/* initialize SNTP server address */
+	sntp_server_address = SNTP_SERVER_ADDRESS;
+
+	/* if we got a valid SNTP server address... */
+	if (sntp_server_address!=0)
+	{
+		/* create new socket */
+		sock = socket( AF_INET, SOCK_DGRAM, 0);
+		if (sock>=0)
+		{
+			/* prepare local address */
+			memset(&local, 0, sizeof(local));
+			local.sin_family      = AF_INET;
+			local.sin_port        = htons(INADDR_ANY);
+			local.sin_addr.s_addr = htonl(INADDR_ANY);
+
+			/* bind to local address */
+			if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
+			{
+				/* set recv timeout */
+				timeout = SNTP_RECV_TIMEOUT;
+				setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
+
+				/* prepare SNTP request */
+				memset( sntp_request, 0, sizeof(sntp_request));
+				sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
+
+				/* prepare SNTP server address */
+				memset(&to, 0, sizeof(to));
+				to.sin_family      = AF_INET;
+				to.sin_port        = htons(SNTP_PORT);
+				to.sin_addr.s_addr = sntp_server_address;
+
+				/* send SNTP request to server */
+				if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
+				{
+					/* receive SNTP server response */
+					tolen = sizeof(to);
+					size  = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);
+
+					/* if the response size is good */
+					if (size == SNTP_MAX_DATA_LEN)
+					{
+						/* if this is a SNTP response... */
+						if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
+						{
+							/* extract GMT time from response */
+							SMEMCPY( &timestamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
+							t = (ntohl(timestamp) - DIFF_SEC_1900_1970);
+
+							/* do time processing */
+							sntp_process(t);
+
+						}
+						else
+						{
+							LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
+						}
+					}
+					else
+					{
+						LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
+					}
+				}
+				else
+				{
+					LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
+				}
+			}
+			/* close the socket */
+			closesocket(sock);
+		}
+	}
+}
+
+/**
+ * SNTP thread
+ */
+static void
+sntp_thread(void *arg)
+{
+	LWIP_UNUSED_ARG(arg);
+	while(1)
+	{
+		sntp_request();
+		sys_msleep(SNTP_UPDATE_DELAY);
+	}
+}
+
+void sntp_init(void)
+{
+	sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
+}

+ 68 - 0
components/net/lwip/apps/tcpecho.c

@@ -0,0 +1,68 @@
+#include <lwip/api.h>
+
+#define TCP_ECHO_PORT   7
+
+void tcpecho_entry(void *parameter)
+{
+	struct netconn *conn, *newconn;
+	err_t err;
+
+	/* Create a new connection identifier. */
+	conn = netconn_new(NETCONN_TCP);
+
+	/* Bind connection to well known port number 7. */
+	netconn_bind(conn, NULL, TCP_ECHO_PORT);
+
+	/* Tell connection to go into listening mode. */
+	netconn_listen(conn);
+
+	while(1)
+	{
+		/* Grab new connection. */
+		newconn = netconn_accept(conn);
+		/* Process the new connection. */
+		if(newconn != NULL)
+		{
+			struct netbuf *buf;
+			void *data;
+			u16_t len;
+
+			while((buf = netconn_recv(newconn)) != NULL)
+			{
+				do
+				{
+					netbuf_data(buf, &data, &len);
+					err = netconn_write(newconn, data, len, NETCONN_COPY);
+					if(err != ERR_OK){}
+				}
+				while(netbuf_next(buf) >= 0);
+				netbuf_delete(buf);
+			}
+			/* Close connection and discard connection identifier. */
+			netconn_delete(newconn);
+		}
+	}
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+static rt_thread_t echo_tid = RT_NULL;
+void tcpecho(rt_uint32_t startup)
+{
+    if (startup && echo_tid == RT_NULL)
+    {
+        echo_tid = rt_thread_create("echo",
+			tcpecho_entry, RT_NULL,
+            512, 30, 5);
+        if (echo_tid != RT_NULL)
+            rt_thread_startup(echo_tid);
+    }
+    else
+    {
+        if (echo_tid != RT_NULL)
+            rt_thread_delete(echo_tid); /* delete thread */
+        echo_tid = RT_NULL;
+    }
+}
+FINSH_FUNCTION_EXPORT(tcpecho, startup or stop TCP echo server);
+#endif

+ 206 - 0
components/net/lwip/apps/tftp.c

@@ -0,0 +1,206 @@
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <lwip/sockets.h>
+
+#include <finsh.h>
+
+#define TFTP_PORT	69
+/* opcode */
+#define TFTP_RRQ			1 	/* read request */
+#define TFTP_WRQ			2	/* write request */
+#define TFTP_DATA			3	/* data */
+#define TFTP_ACK			4	/* ACK */
+#define TFTP_ERROR			5	/* error */
+
+rt_uint8_t tftp_buffer[512 + 4];
+/* tftp client */
+void tftp_get(const char* host, const char* dir, const char* filename)
+{
+	int fd, sock_fd, sock_opt;
+	struct sockaddr_in tftp_addr, from_addr;
+	rt_uint32_t length;
+	socklen_t fromlen;
+
+	/* make local file name */
+	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
+		"%s/%s", dir, filename);
+
+	/* open local file for write */
+	fd = open((char*)tftp_buffer, O_RDWR | O_CREAT, 0);
+	if (fd < 0)
+	{
+		rt_kprintf("can't open local filename\n");
+		return;
+	}
+
+	/* connect to tftp server */
+    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
+    tftp_addr.sin_family = AF_INET;
+    tftp_addr.sin_port = htons(TFTP_PORT);
+    
+    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+    if (sock_fd < 0)
+	{
+	    close(fd);
+	    rt_kprintf("can't create a socket\n");
+	    return ;
+	}
+	
+	/* set socket option */
+	sock_opt = 5000; /* 5 seconds */
+	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
+
+	/* make tftp request */
+	tftp_buffer[0] = 0;			/* opcode */
+	tftp_buffer[1] = TFTP_RRQ; 	/* RRQ */
+	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
+	tftp_buffer[length] = 0; length ++;
+	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
+	tftp_buffer[length] = 0; length ++;
+
+	fromlen = sizeof(struct sockaddr_in);
+	
+	/* send request */	
+	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
+		(struct sockaddr *)&tftp_addr, fromlen);
+	
+	do
+	{
+		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+			(struct sockaddr *)&from_addr, &fromlen);
+		
+		if (length > 0)
+		{
+			write(fd, (char*)&tftp_buffer[4], length - 4);
+			rt_kprintf("#");
+
+			/* make ACK */			
+			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */
+			/* send ACK */
+			lwip_sendto(sock_fd, tftp_buffer, 4, 0, 
+				(struct sockaddr *)&from_addr, fromlen);
+		}
+	} while (length == 516);
+
+	if (length == 0) rt_kprintf("timeout\n");
+	else rt_kprintf("done\n");
+
+	close(fd);
+	lwip_close(sock_fd);
+}
+FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server);
+
+void tftp_put(const char* host, const char* dir, const char* filename)
+{
+	int fd, sock_fd, sock_opt;
+	struct sockaddr_in tftp_addr, from_addr;
+	rt_uint32_t length, block_number = 0;
+	socklen_t fromlen;
+
+	/* make local file name */
+	rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
+		"%s/%s", dir, filename);
+
+	/* open local file for write */
+	fd = open((char*)tftp_buffer, O_RDONLY, 0);
+	if (fd < 0)
+	{
+		rt_kprintf("can't open local filename\n");
+		return;
+	}
+
+	/* connect to tftp server */
+    inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
+    tftp_addr.sin_family = AF_INET;
+    tftp_addr.sin_port = htons(TFTP_PORT);
+
+    sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+    if (sock_fd < 0)
+	{
+	    close(fd);
+	    rt_kprintf("can't create a socket\n");
+	    return ;
+	}
+
+	/* set socket option */
+	sock_opt = 5000; /* 5 seconds */
+	lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
+
+	/* make tftp request */
+	tftp_buffer[0] = 0;			/* opcode */
+	tftp_buffer[1] = TFTP_WRQ; 	/* WRQ */
+	length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
+	tftp_buffer[length] = 0; length ++;
+	length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
+	tftp_buffer[length] = 0; length ++;
+
+	fromlen = sizeof(struct sockaddr_in);
+	
+	/* send request */	
+	lwip_sendto(sock_fd, tftp_buffer, length, 0, 
+		(struct sockaddr *)&tftp_addr, fromlen);
+
+	/* wait ACK 0 */	
+	length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+		(struct sockaddr *)&from_addr, &fromlen);
+	if (!(tftp_buffer[0] == 0 &&
+		tftp_buffer[1] == TFTP_ACK &&
+		tftp_buffer[2] == 0 &&
+		tftp_buffer[3] == 0))
+	{
+		rt_kprintf("tftp server error\n");
+		close(fd);
+		return;
+	}
+
+	block_number = 1;
+	
+	while (1)
+	{
+		length = read(fd, (char*)&tftp_buffer[4], 512);
+		if (length > 0)
+		{
+			/* make opcode and block number */
+			tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA;
+			tftp_buffer[2] = (block_number >> 8) & 0xff;
+			tftp_buffer[3] = block_number & 0xff;
+
+			lwip_sendto(sock_fd, tftp_buffer, length + 4, 0, 
+				(struct sockaddr *)&from_addr, fromlen);
+		}
+		else
+		{
+			rt_kprintf("done\n");
+			break; /* no data yet */
+		}
+
+		/* receive ack */
+		length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, 
+			(struct sockaddr *)&from_addr, &fromlen);
+		if (length > 0)
+		{
+			if ((tftp_buffer[0] == 0 &&
+				tftp_buffer[1] == TFTP_ACK &&
+				tftp_buffer[2] == (block_number >> 8) & 0xff) &&
+				tftp_buffer[3] == (block_number & 0xff))
+			{
+				block_number ++;
+				rt_kprintf("#");
+			}
+			else 
+			{
+				rt_kprintf("server respondes with an error\n");
+				break;
+			}
+		}
+		else if (length == 0)
+		{
+			rt_kprintf("server timeout\n");
+			break;
+		}
+	}
+
+	close(fd);
+	lwip_close(sock_fd);
+}
+FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);

+ 56 - 0
components/net/lwip/apps/udpecho.c

@@ -0,0 +1,56 @@
+#include <lwip/api.h>
+
+#define UDP_ECHO_PORT   7
+
+void udpecho_entry(void *parameter)
+{
+	struct netconn *conn;
+	struct netbuf *buf;
+	struct ip_addr *addr;
+	unsigned short port;
+
+	conn = netconn_new(NETCONN_UDP);
+	netconn_bind(conn, IP_ADDR_ANY, 7);
+
+	while(1)
+	{
+        /* received data to buffer */
+		buf = netconn_recv(conn);
+
+		addr = netbuf_fromaddr(buf);
+		port = netbuf_fromport(buf);
+
+        /* send the data to buffer */
+		netconn_connect(conn, addr, port);
+
+		/* reset address, and send to client */
+		buf->addr = RT_NULL;
+		netconn_send(conn, buf);
+
+        /* release buffer */
+		netbuf_delete(buf);
+	}
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+static rt_thread_t echo_tid = RT_NULL;
+void udpecho(rt_uint32_t startup)
+{
+	if (startup && echo_tid == RT_NULL)
+	{
+		echo_tid = rt_thread_create("uecho",
+									udpecho_entry, RT_NULL,
+									512, 30, 5);
+		if (echo_tid != RT_NULL)
+			rt_thread_startup(echo_tid);
+	}
+	else
+	{
+		if (echo_tid != RT_NULL)
+			rt_thread_delete(echo_tid); /* delete thread */
+		echo_tid = RT_NULL;
+	}
+}
+FINSH_FUNCTION_EXPORT(udpecho, startup or stop UDP echo server);
+#endif

+ 0 - 3
tools/building.py

@@ -276,9 +276,6 @@ def PrepareBuilding(env, root_directory, has_libcpu=False):
     if (GetDepend('RT_USING_NEWLIB') == False and GetDepend('RT_USING_NOLIBC') == False) and rtconfig.PLATFORM == 'gcc':
         AddDepend('RT_USING_MINILIBC')
 
-    if (GetDepend('RT_USING_LWIP') == True and GetDepend('RT_LWIP_VER140') == False):
-        AddDepend('RT_LWIP_VER130')
-
     # add target option
     AddOption('--target',
                       dest='target',