diff --git a/components/net/SConscript b/components/net/SConscript index 2e3bfdd60313d33e777a34387e8cefa36ddf9a32..1a2485b8aa618c20800d2f55d00860acfa119ea2 100644 --- a/components/net/SConscript +++ b/components/net/SConscript @@ -1,4 +1,4 @@ -# for libc component +# for network related component import os Import('RTT_ROOT') diff --git a/components/net/lwip-1.4.0/SConscript b/components/net/lwip-1.4.0/SConscript index bf6aefbef1ced558faa06a9c22c60a0b6b23f8e2..a09177c290517f119d11e8da3dc86b2fdcdc2eb9 100644 --- a/components/net/lwip-1.4.0/SConscript +++ b/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') diff --git a/components/net/apps/SConscript b/components/net/lwip-1.4.0/apps/SConscript similarity index 95% rename from components/net/apps/SConscript rename to components/net/lwip-1.4.0/apps/SConscript index a0822b53fad2662317f3838d83b06d7afb8112ae..d5eb18deb8201fe08b76f538eca11ac52fb4a746 100644 --- a/components/net/apps/SConscript +++ b/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') diff --git a/components/net/apps/chargen.c b/components/net/lwip-1.4.0/apps/chargen.c similarity index 97% rename from components/net/apps/chargen.c rename to components/net/lwip-1.4.0/apps/chargen.c index 7d8240a31edf033cb524c5a6527ea9653ba6b18c..096401ae7508fbc605a2d8788e211a334bf6245d 100644 --- a/components/net/apps/chargen.c +++ b/components/net/lwip-1.4.0/apps/chargen.c @@ -1,216 +1,216 @@ -#include - -#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 -void chargen() -{ - chargen_init(); -} -FINSH_FUNCTION_EXPORT(chargen, start chargen server); -#endif +#include + +#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 +void chargen() +{ + chargen_init(); +} +FINSH_FUNCTION_EXPORT(chargen, start chargen server); +#endif diff --git a/components/net/apps/ftpd.c b/components/net/lwip-1.4.0/apps/ftpd.c similarity index 100% rename from components/net/apps/ftpd.c rename to components/net/lwip-1.4.0/apps/ftpd.c diff --git a/components/net/apps/netio.c b/components/net/lwip-1.4.0/apps/netio.c similarity index 96% rename from components/net/apps/netio.c rename to components/net/lwip-1.4.0/apps/netio.c index c603acc9476a830c2df0480adea8e4e0871a2211..48d016bf7bb82ccb08a4445ea3c386e2bcefe1d8 100644 --- a/components/net/apps/netio.c +++ b/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_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_FUNCTION_EXPORT(netio_init, netio server); +#endif diff --git a/components/net/apps/ping.c b/components/net/lwip-1.4.0/apps/ping.c similarity index 95% rename from components/net/apps/ping.c rename to components/net/lwip-1.4.0/apps/ping.c index 1f0b82205ce5cc96a1fad78f91917f538ffd06ef..d3c3dd399b4bd370662bf2baf5d5a504a0d8c8e7 100644 --- a/components/net/apps/ping.c +++ b/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_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_FUNCTION_EXPORT(ping, ping network host); +#endif diff --git a/components/net/apps/sntp.c b/components/net/lwip-1.4.0/apps/sntp.c similarity index 96% rename from components/net/apps/sntp.c rename to components/net/lwip-1.4.0/apps/sntp.c index a9a3f7ddc81eca20e0f93aaa45841201dfa47f01..a2fe2cf967ba4b16b4061a6a4b2b9fa3a1b10cad 100644 --- a/components/net/apps/sntp.c +++ b/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 -#include - -/** 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( ×tamp, (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 +#include + +/** 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( ×tamp, (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); +} diff --git a/components/net/apps/tcpecho.c b/components/net/lwip-1.4.0/apps/tcpecho.c similarity index 95% rename from components/net/apps/tcpecho.c rename to components/net/lwip-1.4.0/apps/tcpecho.c index ac5c8cf27333ee55320fab5dc8b0621d48b86e33..04ca9ebf3fb274f5e3df4ae681b4a36bf1657da3 100644 --- a/components/net/apps/tcpecho.c +++ b/components/net/lwip-1.4.0/apps/tcpecho.c @@ -1,68 +1,68 @@ -#include - -#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 -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 + +#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 +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 diff --git a/components/net/apps/tftp.c b/components/net/lwip-1.4.0/apps/tftp.c similarity index 96% rename from components/net/apps/tftp.c rename to components/net/lwip-1.4.0/apps/tftp.c index 262c0673ce77729c95cdb2fbce3a92b8b85bc630..df5d24162fbcfba2bebb4fa2a266a2e2bf6cf58b 100644 --- a/components/net/apps/tftp.c +++ b/components/net/lwip-1.4.0/apps/tftp.c @@ -1,206 +1,206 @@ -#include -#include -#include - -#include - -#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 +#include +#include + +#include + +#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); diff --git a/components/net/apps/udpecho.c b/components/net/lwip-1.4.0/apps/udpecho.c similarity index 95% rename from components/net/apps/udpecho.c rename to components/net/lwip-1.4.0/apps/udpecho.c index 4bffcb18ad3d79033c63744a0a06b58269978c2b..7ea481366e8ee1589a60f3f9005e6382f61f9733 100644 --- a/components/net/apps/udpecho.c +++ b/components/net/lwip-1.4.0/apps/udpecho.c @@ -1,56 +1,56 @@ -#include - -#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 -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 + +#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 +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 diff --git a/components/net/lwip/SConscript b/components/net/lwip/SConscript index 78b87eb5485783d8ea34a32a2dd8b0eed8f9e197..adc16de628d47f7a7a33f5254150b8a151c62b99 100644 --- a/components/net/lwip/SConscript +++ b/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') diff --git a/components/net/lwip/apps/chargen.c b/components/net/lwip/apps/chargen.c new file mode 100644 index 0000000000000000000000000000000000000000..096401ae7508fbc605a2d8788e211a334bf6245d --- /dev/null +++ b/components/net/lwip/apps/chargen.c @@ -0,0 +1,216 @@ +#include + +#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 +void chargen() +{ + chargen_init(); +} +FINSH_FUNCTION_EXPORT(chargen, start chargen server); +#endif diff --git a/components/net/lwip/apps/ftpd.c b/components/net/lwip/apps/ftpd.c new file mode 100644 index 0000000000000000000000000000000000000000..af48237e4223f9cb9b909670bf1979818976248d --- /dev/null +++ b/components/net/lwip/apps/ftpd.c @@ -0,0 +1,791 @@ +#include +#include + +#include +#include +#include +#include + +#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_FUNCTION_EXPORT(ftpd_start, start ftp server) +#endif diff --git a/components/net/lwip/apps/netio.c b/components/net/lwip/apps/netio.c new file mode 100644 index 0000000000000000000000000000000000000000..48d016bf7bb82ccb08a4445ea3c386e2bcefe1d8 --- /dev/null +++ b/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_FUNCTION_EXPORT(netio_init, netio server); +#endif diff --git a/components/net/lwip/apps/ping.c b/components/net/lwip/apps/ping.c new file mode 100644 index 0000000000000000000000000000000000000000..d3c3dd399b4bd370662bf2baf5d5a504a0d8c8e7 --- /dev/null +++ b/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_FUNCTION_EXPORT(ping, ping network host); +#endif diff --git a/components/net/lwip/apps/sntp.c b/components/net/lwip/apps/sntp.c new file mode 100644 index 0000000000000000000000000000000000000000..a2fe2cf967ba4b16b4061a6a4b2b9fa3a1b10cad --- /dev/null +++ b/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 +#include + +/** 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( ×tamp, (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); +} diff --git a/components/net/lwip/apps/tcpecho.c b/components/net/lwip/apps/tcpecho.c new file mode 100644 index 0000000000000000000000000000000000000000..3d5ec27de718e07f9ec539d311e2d273f62d0541 --- /dev/null +++ b/components/net/lwip/apps/tcpecho.c @@ -0,0 +1,68 @@ +#include + +#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 +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 diff --git a/components/net/lwip/apps/tftp.c b/components/net/lwip/apps/tftp.c new file mode 100644 index 0000000000000000000000000000000000000000..df5d24162fbcfba2bebb4fa2a266a2e2bf6cf58b --- /dev/null +++ b/components/net/lwip/apps/tftp.c @@ -0,0 +1,206 @@ +#include +#include +#include + +#include + +#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); diff --git a/components/net/lwip/apps/udpecho.c b/components/net/lwip/apps/udpecho.c new file mode 100644 index 0000000000000000000000000000000000000000..c9e07d099d927ca2680ada40ec5947cdc9284c68 --- /dev/null +++ b/components/net/lwip/apps/udpecho.c @@ -0,0 +1,56 @@ +#include + +#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 +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 diff --git a/tools/building.py b/tools/building.py index 1856b23db9e6c62e6f107bf69ea5ef2be1bda4a6..86089ccbe516ce2668234cfd4d334471f3d803f5 100644 --- a/tools/building.py +++ b/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',