diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-09-09 17:20:56 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-09-09 17:20:56 +0000 |
commit | 7a65f932826220c741ffbf5698b48692a787d915 (patch) | |
tree | 825e048f8fc18b7e69cb155ad96b7254566a3ffe | |
parent | d12e00bdd6ffbb39ab5d45d5d5a484d293108021 (diff) | |
download | nuttx-7a65f932826220c741ffbf5698b48692a787d915.tar.gz nuttx-7a65f932826220c741ffbf5698b48692a787d915.tar.bz2 nuttx-7a65f932826220c741ffbf5698b48692a787d915.zip |
Implement TCP send; remove uIP proto-sockets
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@339 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/examples/uip/main.c | 1 | ||||
-rw-r--r-- | nuttx/include/net/uip/httpd.h | 49 | ||||
-rw-r--r-- | nuttx/include/net/uip/psock.h | 257 | ||||
-rw-r--r-- | nuttx/include/nuttx/net.h | 2 | ||||
-rw-r--r-- | nuttx/include/sys/socket.h | 20 | ||||
-rw-r--r-- | nuttx/net/bind.c | 1 | ||||
-rw-r--r-- | nuttx/net/connect.c | 20 | ||||
-rw-r--r-- | nuttx/net/net-internal.h | 20 | ||||
-rw-r--r-- | nuttx/net/recv.c | 2 | ||||
-rw-r--r-- | nuttx/net/recvfrom.c | 286 | ||||
-rw-r--r-- | nuttx/net/send.c | 200 | ||||
-rw-r--r-- | nuttx/net/sendto.c | 10 | ||||
-rw-r--r-- | nuttx/net/uip/Make.defs | 2 | ||||
-rw-r--r-- | nuttx/net/uip/psock.c | 385 | ||||
-rw-r--r-- | nuttx/net/uip/uip-tcpconn.c | 109 | ||||
-rw-r--r-- | nuttx/netutils/smtp/smtp.c | 212 | ||||
-rw-r--r-- | nuttx/netutils/webserver/httpd-cgi.c | 83 | ||||
-rw-r--r-- | nuttx/netutils/webserver/httpd-cgi.h | 3 | ||||
-rw-r--r-- | nuttx/netutils/webserver/httpd-fs.c | 1 | ||||
-rw-r--r-- | nuttx/netutils/webserver/httpd.c | 271 | ||||
-rw-r--r-- | nuttx/netutils/webserver/httpd.h | 74 |
21 files changed, 878 insertions, 1130 deletions
diff --git a/nuttx/examples/uip/main.c b/nuttx/examples/uip/main.c index 9771f4a9e..773d430ea 100644 --- a/nuttx/examples/uip/main.c +++ b/nuttx/examples/uip/main.c @@ -89,6 +89,7 @@ int user_start(int argc, char *argv[]) #if defined(CONFIG_EXAMPLE_UIP_WEBSERVER) httpd_init(); + httpd_listen(); #elif defined(CONFIG_EXAMPLE_UIP_TELNETD) telnetd_init(); #elif defined(CONFIG_EXAMPLE_UIP_DHCPC) diff --git a/nuttx/include/net/uip/httpd.h b/nuttx/include/net/uip/httpd.h index 1c9420448..ff99ddb36 100644 --- a/nuttx/include/net/uip/httpd.h +++ b/nuttx/include/net/uip/httpd.h @@ -28,51 +28,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __HTTPD_H__ -#define __HTTPD_H__ +#ifndef _NET_UIP_HTTPD_H +#define _NET_UIP_HTTPD_H #include <sys/types.h> -#include <net/uip/psock.h> -#define HTTPD_FS_STATISTICS 1 +extern void httpd_init(void); +extern void httpd_listen(void); -struct httpd_fs_file -{ - char *data; - int len; -}; - -struct httpd_state -{ - unsigned char timer; - struct psock sin, sout; - char inputbuf[50]; - char filename[20]; - char state; - struct httpd_fs_file file; - int len; - char *scriptptr; - int scriptlen; - - unsigned short count; -}; - -#ifdef HTTPD_FS_STATISTICS -#if HTTPD_FS_STATISTICS == 1 -extern uint16 httpd_fs_count(char *name); -#endif /* HTTPD_FS_STATISTICS */ -#endif /* HTTPD_FS_STATISTICS */ - -void httpd_init(void); -void httpd_log(char *msg); -void httpd_log_file(uint16 *requester, char *file); - -/* file must be allocated by caller and will be filled in - * by the function. - */ - -int httpd_fs_open(const char *name, struct httpd_fs_file *file); -void httpd_fs_init(void); - - -#endif /* __HTTPD_H__ */ +#endif /* _NET_UIP_HTTPD_H */ diff --git a/nuttx/include/net/uip/psock.h b/nuttx/include/net/uip/psock.h deleted file mode 100644 index 3ecc7abdc..000000000 --- a/nuttx/include/net/uip/psock.h +++ /dev/null @@ -1,257 +0,0 @@ -/**************************************************************************** - * psock.h - * Protosocket library header file - * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> - * - * This logic was leveraged from uIP which also has a BSD-style license: - * - * Author: Adam Dunkels <adam@sics.se> - * Copyright (c) 2004, Swedish Institute of Computer Science. - * All rights reserved. - * - * 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. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. - ****************************************************************************/ - -#ifndef __NET_UIP_PSOCK_H -#define __NET_UIP_PSOCK_H - -/* psock Protosockets library - * - * The protosocket library provides an interface to the uIP stack that is - * similar to the traditional BSD socket interface. Unlike programs - * written for the ordinary uIP event-driven interface, programs - * written with the protosocket library are executed in a sequential - * fashion and does not have to be implemented as explicit state - * machines. - * - * Protosockets only work with TCP connections. - * - * The protosocket library uses \ref pt protothreads to provide - * sequential control flow. This makes the protosockets lightweight in - * terms of memory, but also means that protosockets inherits the - * functional limitations of protothreads. Each protosocket lives only - * within a single function. Automatic variables (stack variables) are - * not retained across a protosocket library function call. - * - * \note Because the protosocket library uses protothreads, local - * variables will not always be saved across a call to a protosocket - * library function. It is therefore advised that local variables are - * used with extreme care. - * - * The protosocket library provides functions for sending data without - * having to deal with retransmissions and acknowledgements, as well - * as functions for reading data without having to deal with data - * being split across more than one TCP segment. - * - * Because each protosocket runs as a protothread, the protosocket has to be - * started with a call to PSOCK_BEGIN() at the start of the function - * in which the protosocket is used. Similarly, the protosocket protothread can - * be terminated by a call to PSOCK_EXIT(). - * - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> -#ifdef CONFIG_NET - -#include <sys/types.h> -#include <net/uip/uipopt.h> - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/* The structure that holds the state of a buffer. - * - * This structure holds the state of a uIP buffer. The structure has - * no user-visible elements, but is used through the functions - * provided by the library. - * - */ - -struct psock_buf -{ - uint8 *ptr; - unsigned short left; -}; - -/* The representation of a protosocket. - * - * The protosocket structrure is an opaque structure with no user-visible - * elements. - */ - -struct psock -{ - const uint8 *sendptr; /* Pointer to the next data to be sent. */ - uint8 *readptr; /* Pointer to the next data to be read. */ - uint8 *bufptr; /* Pointer to the buffer used for buffering incoming data. */ - uint16 sendlen; /* The number of bytes left to be sent. */ - uint16 readlen; /* The number of bytes left to be read. */ - struct psock_buf buf; /* The structure holding the state of the input buffer. */ - unsigned int bufsize; /* The size of the input buffer. */ - unsigned char state; /* The state of the protosocket. */ -}; - -/**************************************************************************** - * Public FunctionPrototypes - ****************************************************************************/ - -/* Initialize a protosocket. - * - * Initializes a protosocket and must be called before the - * protosocket is used. The initialization also specifies the input buffer - * for the protosocket. - * - * psock (struct psock *) A pointer to the protosocket to be - * initialized - * - * buffer (char *) A pointer to the input buffer for the - * protosocket. - * - * buffersize (unsigned int) The size of the input buffer. - */ - -extern void psock_init(struct psock *psock, char *buffer, unsigned int buffersize); - -/* Send data. - * - * This macro sends data over a protosocket. The protosocket protothread blocks - * until all data has been sent and is known to have been received by - * the remote end of the TCP connection. - * - * psock (struct psock *) A pointer to the protosocket over which - * data is to be sent. - * - * data (char *) A pointer to the data that is to be sent. - * - * datalen (unsigned int) The length of the data that is to be - * sent. - */ - -extern void psock_send(struct psock *psock, const char *buf, unsigned int len); - -/*Send a null-terminated string. - * - * psock Pointer to the protosocket. - * str The string to be sent. - * - * This function sends a null-terminated string over the - * protosocket. - */ - -#define PSOCK_SEND_STR(psock, str) psock_send(psock, str, strlen(str)) - -/* Generate data with a function and send it - * - * psock Pointer to the protosocket. - * generator Pointer to the generator function - * arg Argument to the generator function - * - * This function generates data and sends it over the - * protosocket. This can be used to dynamically generate - * data for a transmission, instead of generating the data - * in a buffer beforehand. This function reduces the need for - * buffer memory. The generator function is implemented by - * the application, and a pointer to the function is given - * as an argument with the call to PSOCK_GENERATOR_SEND(). - * - * The generator function should place the generated data - * directly in the uip_appdata buffer, and return the - * length of the generated data. The generator function is - * called by the protosocket layer when the data first is - * sent, and once for every retransmission that is needed. - */ - -extern void psock_generator_send(struct psock *psock, unsigned short (*f)(void *), void *arg); - -/* Close a protosocket. - * - * This macro closes a protosocket and can only be called from within the - * protothread in which the protosocket lives. - * - * psock (struct psock *) A pointer to the protosocket that is to - * be closed. - */ - -#define PSOCK_CLOSE(psock) uip_close() - -/* Read data until the buffer is full. - * - * This macro will block waiting for data and read the data into the - * input buffer specified with the call to PSOCK_INIT(). Data is read - * until the buffer is full.. - * - * psock (struct psock *) A pointer to the protosocket from which - * data should be read. - */ - -extern void psock_readbuf(struct psock *psock); - -/* Read data up to a specified character. - * - * This macro will block waiting for data and read the data into the - * input buffer specified with the call to PSOCK_INIT(). Data is only - * read until the specifieed character appears in the data stream. - * - * psock (struct psock *) A pointer to the protosocket from which - * data should be read. - * - * c (char) The character at which to stop reading. - */ - -extern void psock_readto(struct psock *psock, unsigned char c); - -/* The length of the data that was previously read. - * - * Returns the length of the data that was previously read - * using PSOCK_READTO() or PSOCK_READ(). - * - * psock (struct psock *) A pointer to the protosocket holding the data. - */ - -extern uint16 psock_datalen(struct psock *psock); - -/* Check if there is new data has arrived on a protosocket without blocking - * - * psock (struct psock *) A pointer to the protosocket. - */ - -extern boolean psock_checknewdata(struct psock *s); - -/* Block until new data has arrived on a protosocket. - * - * psock (struct psock *) A pointer to the protosocket. - */ - -extern void psock_waitnewdata(struct psock *s); - -#endif /* CONFIG_NET */ -#endif /* __NET_UIP_PSOCK_H */ diff --git a/nuttx/include/nuttx/net.h b/nuttx/include/nuttx/net.h index 2f700a985..5247fe3fd 100644 --- a/nuttx/include/nuttx/net.h +++ b/nuttx/include/nuttx/net.h @@ -46,7 +46,6 @@ #include <semaphore.h> #include <net/uip/uip.h> -#include <net/uip/psock.h> /**************************************************************************** * Definitions @@ -87,6 +86,7 @@ struct socket { int s_crefs; /* Reference count on the socket */ uint8 s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */ + uint8 s_flags; /* See _SF_* definitions */ #ifdef CONFIG_NET_SOCKOPTS sockopt_t s_options; /* Selected socket options */ #ifndef CONFIG_DISABLE_CLOCK diff --git a/nuttx/include/sys/socket.h b/nuttx/include/sys/socket.h index 52c20e272..865b1f69e 100644 --- a/nuttx/include/sys/socket.h +++ b/nuttx/include/sys/socket.h @@ -177,21 +177,21 @@ extern "C" { #endif EXTERN int socket(int domain, int type, int protocol); -EXTERN int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); -EXTERN int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +EXTERN int bind(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen); +EXTERN int connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen); -EXTERN ssize_t send(int sockfd, const void *buf, size_t len, int flags); -EXTERN ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *to, socklen_t tolen); +EXTERN ssize_t send(int sockfd, FAR const void *buf, size_t len, int flags); +EXTERN ssize_t sendto(int sockfd, FAR const void *buf, size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen); -EXTERN ssize_t recv(int sockfd, void *buf, size_t len, int flags); -EXTERN ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen); +EXTERN ssize_t recv(int sockfd, FAR void *buf, size_t len, int flags); +EXTERN ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, + FAR struct sockaddr *from, FAR socklen_t *fromlen); EXTERN int setsockopt(int sockfd, int level, int option, - const void *value, socklen_t value_len); + FAR const void *value, socklen_t value_len); EXTERN int getsockopt(int sockfd, int level, int option, - void *value, socklen_t *value_len); + FAR void *value, FAR socklen_t *value_len); #undef EXTERN #if defined(__cplusplus) diff --git a/nuttx/net/bind.c b/nuttx/net/bind.c index edc9776d4..f1d5dbbd9 100644 --- a/nuttx/net/bind.c +++ b/nuttx/net/bind.c @@ -119,6 +119,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { case SOCK_STREAM: ret = uip_tcpbind(psock->s_conn, inaddr); + psock->s_flags |= _SF_BOUND; break; #ifdef CONFIG_NET_UDP diff --git a/nuttx/net/connect.c b/nuttx/net/connect.c index aaa267227..5bc978fe9 100644 --- a/nuttx/net/connect.c +++ b/nuttx/net/connect.c @@ -90,7 +90,7 @@ * sa_family field. * EAGAIN * No more free local ports or insufficient entries in the routing - * cache. For PF_INET. + * cache. * EALREADY * The socket is non-blocking and a previous connection attempt has * not yet been completed. @@ -155,12 +155,28 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { case SOCK_STREAM: { - int ret = uip_tcpconnect(psock->s_conn, inaddr); + int ret; + + /* Verify that the socket is not already connected */ + + if (_SS_ISCONNECTED(psock->s_flags)) + { + err = -EISCONN; + goto errout; + } + + /* Perform the uIP connection operation */ + + ret = uip_tcpconnect(psock->s_conn, inaddr); if (ret < 0) { err = -ret; goto errout; } + + /* Mark the connection bound and connected */ + + psock->s_flags |= (_SF_BOUND|_SF_CONNECTED); } break; diff --git a/nuttx/net/net-internal.h b/nuttx/net/net-internal.h index b62099a16..f517f863d 100644 --- a/nuttx/net/net-internal.h +++ b/nuttx/net/net-internal.h @@ -52,6 +52,26 @@ * Definitions ****************************************************************************/ +/* Definitions of 8-bit socket flags */ + + /* Bits 0:2 : Socket state */ +#define _SF_IDLE 0x00 /* There is no socket activity */ +#define _SF_LISTEN 0x01 /* Socket is listening */ +#define _SF_RECV 0x02 /* Waiting for recv action to complete */ +#define _SF_SEND 0x03 /* Waiting for send action to complete */ +#define _SF_MASK 0x03 /* Mask to isolate the above actions */ + /* Bits 3:5 : unused */ +#define _SF_BOUND 0x40 /* Bit 6: SOCK_STREAM is bound to an address */ +#define _SF_CONNECTED 0x80 /* Bit 7: SOCK_STREAM is connected */ + +/* Macro to manage the socket state and flags */ + +#define _SS_SETSTATE(s,f) (((s) & ~_SF_MASK) | (f)) +#define _SS_GETSTATE(s) ((s) & _SF_MASK) +#define _SS_ISBUSY(s) (_SS_GETSTATE(s) != _SF_IDLE) +#define _SS_ISCONNECTED(s) (((s) & _SF_CONNECTED) != 0) +#define _SS_ISBOUND(s) (((s) & _SF_CONNECTED) != 0) + /* This macro converts a socket option value into a bit setting */ #define _SO_BIT(o) (1 << (o)) diff --git a/nuttx/net/recv.c b/nuttx/net/recv.c index e03fbd495..135b6f319 100644 --- a/nuttx/net/recv.c +++ b/nuttx/net/recv.c @@ -69,7 +69,7 @@ * ****************************************************************************/ -ssize_t recv(int sockfd, void *buf, size_t len, int flags) +ssize_t recv(int sockfd, FAR void *buf, size_t len, int flags) { return recvfrom(sockfd, buf, len, flags, NULL, 0); } diff --git a/nuttx/net/recvfrom.c b/nuttx/net/recvfrom.c index 318f0d1bf..a8bc59505 100644 --- a/nuttx/net/recvfrom.c +++ b/nuttx/net/recvfrom.c @@ -77,6 +77,7 @@ struct recvfrom_s void recvfrom_interrupt(void *private) { struct recvfrom_s *pstate = (struct recvfrom_s *)private; + struct uip_udp_conn *udp_conn; size_t recvlen; /* 'private' might be null in some race conditions (?) */ @@ -88,9 +89,9 @@ void recvfrom_interrupt(void *private) if (uip_newdata()) { /* Get the length of the data to return */ - if (uip_len > pstate-> rf_buflen) + if (uip_len > pstate->rf_buflen) { - recvlen = pstate-> rf_buflen; + recvlen = pstate->rf_buflen; } else { @@ -103,15 +104,16 @@ void recvfrom_interrupt(void *private) /* Don't allow any further call backs. */ - uip_conn->private = NULL; - uip_conn->callback = NULL; + udp_conn = (struct uip_udp_conn *)pstate->rf_sock->s_conn; + udp_conn->private = NULL; + udp_conn->callback = NULL; /* Wake up the waiting thread, returning the number of bytes * actually read. */ pstate->rf_buflen = recvlen; - sem_post(&pstate-> rf_sem); + sem_post(&pstate->rf_sem); } /* No data has been received -- this is some other event... probably a @@ -131,15 +133,16 @@ void recvfrom_interrupt(void *private) { /* Don't allow any further call backs. */ - uip_conn->private = NULL; - uip_conn->callback = NULL; + udp_conn = (struct uip_udp_conn *)pstate->rf_sock->s_conn; + udp_conn->private = NULL; + udp_conn->callback = NULL; /* Wake up the waiting thread, returning the error -EAGAIN * that signals the timeout event */ pstate->rf_buflen = -EAGAIN; - sem_post(&pstate-> rf_sem); + sem_post(&pstate->rf_sem); } } } @@ -148,6 +151,157 @@ void recvfrom_interrupt(void *private) } /**************************************************************************** + * Function: udp_recvfrom + * + * Description: + * Perform the recvfrom operation for a UDP SOCK_DGRAM + * + * Parameters: + * psock Pointer to the socket structure for the SOCK_DRAM socket + * buf Buffer to receive data + * len Length of buffer + * infrom INET ddress of source + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -errno is returned (see recvfrom for list of errnos). + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_IPv6 +static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR const struct sockaddr_in6 *infrom ) +#else +static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR const struct sockaddr_in *infrom ) +#endif +{ + struct uip_udp_conn *udp_conn; + struct recvfrom_s state; + irqstate_t save; + int err; + int ret; + + /* Perform the UDP recvfrom() operation */ + + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + save = irqsave(); + memset(&state, 0, sizeof(struct recvfrom_s)); + (void)sem_init(&state. rf_sem, 0, 0); /* Doesn't really fail */ + state.rf_sock = psock; + state.rf_buflen = len; + state.rf_buffer = buf; + +#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) + /* Set up the start time for the timeout */ + + state.rf_starttime = g_system_timer; +#endif + + /* Setup the UDP socket */ + + err = uip_udpconnect(psock->s_conn, NULL); + if (err < 0) + { + irqrestore(save); + return err; + } + + /* Set up the callback in the connection */ + + udp_conn = (struct uip_udp_conn *)psock->s_conn; + udp_conn->private = (void*)&state; + udp_conn->callback = recvfrom_interrupt; + + /* Wait for either the receive to complete or for an error/timeout to occur. + * NOTES: (1) sem_wait will also terminate if a signal is received, (2) + * interrupts are disabled! They will be re-enabled while the task sleeps + * and automatically re-enabled when the task restarts. + */ + + ret = sem_wait(&state. rf_sem); + + /* Make sure that no further interrupts are processed */ + + udp_conn->private = NULL; + udp_conn->callback = NULL; + sem_destroy(&state. rf_sem); + irqrestore(save); + + /* Check for a error/timeout detected by the interrupt handler. Errors are + * signaled by negative errno values for the rcv length + */ + + if (state.rf_buflen < 0) + { + /* Return EGAIN on a timeout */ + + return state.rf_buflen; + } + + /* If sem_wait failed, then we were probably reawakened by a signal. In + * this case, sem_wait will have set errno appropriately. + */ + + if (ret < 0) + { + return -*get_errno_ptr(); + } + +#warning "Needs to return server address" + return state.rf_buflen; +} +#endif /* CONFIG_NET_UDP */ + +/**************************************************************************** + * Function: tcp_recvfrom + * + * Description: + * Perform the recvfrom operation for a TCP/IP SOCK_STREAM + * + * Parameters: + * psock Pointer to the socket structure for the SOCK_DRAM socket + * buf Buffer to receive data + * len Length of buffer + * infrom INET ddress of source + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -errno is returned (see recvfrom for list of errnos). + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR const struct sockaddr_in6 *infrom ) +#else +static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + FAR const struct sockaddr_in *infrom ) +#endif +{ + /* Verify that the SOCK_STREAM has been connected */ + + if (_SS_ISCONNECTED(psock->s_flags)) + { + /* The SOCK_STREAM must be connect in order to recive */ + + return -ENOTCONN; + } + +#warning "TCP/IP recv not implemented" + return -ENOSYS; +} + +/**************************************************************************** * Global Functions ****************************************************************************/ @@ -203,8 +357,8 @@ void recvfrom_interrupt(void *private) * ****************************************************************************/ -ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, - socklen_t *fromlen) +ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) { FAR struct socket *psock; #ifdef CONFIG_NET_IPv6 @@ -212,13 +366,16 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * #else FAR const struct sockaddr_in *infrom = (const struct sockaddr_in *)from; #endif -#ifdef CONFIG_NET_UDP - struct uip_udp_conn *udp_conn; - struct recvfrom_s state; - irqstate_t save; -#endif + ssize_t ret; int err; - int ret; + + /* Verify that non-NULL pointers were passed */ + + if (!buf || !from || !fromlen) + { + err = EINVAL; + goto errout; + } /* Get the underlying socket structure */ /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -230,95 +387,52 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * goto errout; } - /* Perform the TCP/IP recv() operation */ + /* Verify that a valid address has been provided */ - if (psock->s_type == SOCK_STREAM) - { -#warning "TCP/IP recv not implemented" - err = ENOSYS; +#ifdef CONFIG_NET_IPv6 + if (from->sa_family != AF_INET6 || *fromlen < sizeof(struct sockaddr_in6)) +#else + if (from->sa_family != AF_INET || *fromlen < sizeof(struct sockaddr_in)) +#endif + { + err = EBADF; goto errout; - } + } - /* Perform the UDP recvfrom() operation */ + /* Set the socket state to receiving */ -#ifdef CONFIG_NET_UDP - /* Initialize the state structure. This is done with interrupts - * disabled because we don't want anything to happen until we - * are ready. - */ + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); - save = irqsave(); - memset(&state, 0, sizeof(struct recvfrom_s)); - (void)sem_init(&state. rf_sem, 0, 0); /* Doesn't really fail */ - state. rf_buflen = len; - state. rf_buffer = buf; + /* Perform the TCP/IP or UDP recv() operation */ -#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) - /* Set up the start time for the timeout */ - - state.rf_starttime = g_system_timer; +#ifdef CONFIG_NET_UDP + if (psock->s_type == SOCK_STREAM) #endif - - /* Setup the UDP socket */ - - ret = uip_udpconnect(psock->s_conn, NULL); - if (ret < 0) { - irqrestore(save); - err = -ret; - goto errout; + ret = tcp_recvfrom(psock, buf, len, infrom); } - - /* Set up the callback in the connection */ - - udp_conn = (struct uip_udp_conn *)psock->s_conn; - udp_conn->private = (void*)&state; - udp_conn->callback = recvfrom_interrupt; - - /* Wait for either the read to complete: NOTES: (1) sem_wait will also - * terminate if a signal is received, (2) interrupts are disabled! They - * will be re-enabled while the task sleeps and automatically re-enabled - * when the task restarts. - */ - - ret = sem_wait(&state. rf_sem); - - /* Make sure that no further interrupts are processed */ - - uip_conn->private = NULL; - uip_conn->callback = NULL; - sem_destroy(&state. rf_sem); - irqrestore(save); - - /* Check for a timeout. Errors are signaled by negative errno values - * for the rcv length - */ - -#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) - if (state.rf_buflen < 0) +#ifdef CONFIG_NET_UDP + else { - /* Return EGAIN on a timeout */ - - err = -state.rf_buflen; - goto errout; + ret = udp_recvfrom(psock, buf, len, infrom); } #endif - /* If sem_wait failed, then we were probably reawakened by a signal. In - * this case, sem_wait will have set errno appropriately. - */ + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Handle returned errors */ if (ret < 0) { - return ERROR; + err = -ret; + goto errout; } -#warning "Needs to return server address" - return state.rf_buflen; + /* Success return */ -#else - err = ENOSYS; -#endif + return ret; errout: *get_errno_ptr() = err; diff --git a/nuttx/net/send.c b/nuttx/net/send.c index cc2b154a2..037455faf 100644 --- a/nuttx/net/send.c +++ b/nuttx/net/send.c @@ -42,12 +42,125 @@ #include <sys/types.h> #include <sys/socket.h> +#include <string.h> #include <errno.h> +#include <arch/irq.h> #include "net-internal.h" /**************************************************************************** - * Global Functions + * Definitions + ****************************************************************************/ + +#define STATE_POLLWAIT 1 +#define STATE_DATA_SENT 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure holds the state of the send operation until it can be + * operated upon from the interrupt level. + */ + +struct send_s +{ + FAR struct socket *snd_sock; /* Points to the parent socket structure */ + sem_t snd_sem; /* Used to wake up the waiting thread */ + FAR const uint8 *snd_buffer; /* Points to the buffer of data to send */ + size_t snd_buflen; /* Number of bytes in the buffer to send */ + ssize_t snd_sent; /* The number of bytes sent */ + uint8 snd_state; /* The state of the send operation. */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: send_Interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the uIP layer. + * + * Parameters: + * private An instance of struct send_s cast to void* + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static void send_interrupt(void *private) +{ + struct send_s *pstate = (struct send_s *)private; + struct uip_conn *conn; + + /* If the data has not been sent OR if it needs to be retransmitted, + * then send it now. + */ + + if (pstate->snd_state != STATE_DATA_SENT || uip_rexmit()) + { + if (pstate->snd_buflen > uip_mss()) + { + uip_send(pstate->snd_buffer, uip_mss()); + } + else + { + uip_send(pstate->snd_buffer, pstate->snd_buflen); + } + + pstate->snd_state = STATE_DATA_SENT; + } + + /* Check if all data has been sent and acknowledged */ + + else if (pstate->snd_state == STATE_DATA_SENT && uip_acked()) + { + /* Yes.. the data has been sent AND acknowledge */ + + if (pstate->snd_buflen > uip_mss()) + { + /* Not all data has been sent */ + + pstate->snd_sent += uip_mss(); + pstate->snd_buflen -= uip_mss(); + pstate->snd_buffer += uip_mss(); + + /* Send again on the next poll */ + + pstate->snd_state = STATE_POLLWAIT; + } + else + { + /* All data has been sent */ + + pstate->snd_sent += pstate->snd_buflen; + pstate->snd_buffer += pstate->snd_buflen; + pstate->snd_buflen = 0; + + /* Don't allow any further call backs. */ + + conn = (struct uip_conn *)pstate->snd_sock->s_conn; + conn->private = NULL; + conn->callback = NULL; + + /* Wake up the waiting thread, returning the number of bytes + * actually sent. + */ + + sem_post(&pstate->snd_sem); + } + } +} + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -57,8 +170,8 @@ * The send() call may be used only when the socket is in a connected state * (so that the intended recipient is known). The only difference between * send() and write() is the presence of flags. With zero flags parameter, - * send() is equivalent to write(). Also, send(s,buf,len,flags) is - * equivalent to sendto(s,buf,len,flags,NULL,0). + * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is + * equivalent to sendto(sockfd,buf,len,flags,NULL,0). * * Parameters: * sockfd Socket descriptor of socket @@ -117,7 +230,11 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) { FAR struct socket *psock = sockfd_socket(sockfd); + struct uip_conn *conn; + struct send_s state; + irqstate_t save; int err; + int ret; /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -129,21 +246,86 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) /* If this is a connected socket, then return ENOTCONN */ - if (psock->s_type != SOCK_STREAM) + if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { err = ENOTCONN; goto errout; } + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + /* Perform the TCP send operation */ -#warning "send() not implemented" - err = ENOSYS; + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + save = irqsave(); + memset(&state, 0, sizeof(struct send_s)); + (void)sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */ + state.snd_sock = psock; + state.snd_buflen = len; + state.snd_buffer = buf; + state.snd_state = STATE_POLLWAIT; + + if (len > 0) + { + /* Set up the callback in the connection */ + + conn = (struct uip_conn *)psock->s_conn; + conn->private = (void*)&state; + conn->callback = send_interrupt; + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * sem_wait will also terminate if a signal is received, (2) interrupts + * are disabled! They will be re-enabled while the task sleeps and + * automatically re-enabled when the task restarts. + */ + + ret = sem_wait(&state. snd_sem); + + /* Make sure that no further interrupts are processed */ + + conn->private = NULL; + conn->callback = NULL; + } + + sem_destroy(&state. snd_sem); + irqrestore(save); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Check for a errors. Errors are signaled by negative errno values + * for the send length + */ + + if (state.snd_sent < 0) + { + err = state.snd_sent; + goto errout; + } + + /* If sem_wait failed, then we were probably reawakened by a signal. In + * this case, sem_wait will have set errno appropriately. + */ + + if (ret < 0) + { + err = -ret; + goto errout; + } + + /* Return the number of bytes actually sent */ + + return state.snd_sent; errout: - *get_errno_ptr() = ENOSYS; - return ERROR; - *get_errno_ptr() = ENOSYS; + *get_errno_ptr() = err; return ERROR; } diff --git a/nuttx/net/sendto.c b/nuttx/net/sendto.c index eef1a31b4..bba9c5b47 100644 --- a/nuttx/net/sendto.c +++ b/nuttx/net/sendto.c @@ -97,7 +97,7 @@ void sendto_interrupt(void *private) * * Description: * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) - * socket, the parameters to and tolen are ignored (and the error EISCONN + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN * may be returned when they are not NULL and 0), and the error ENOTCONN is * returned when the socket was not actually connected. * @@ -214,6 +214,10 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, /* Perform the UDP sendto operation */ #ifdef CONFIG_NET_UDP + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. @@ -244,6 +248,10 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, sem_wait(&state.st_sem); sem_destroy(&state.st_sem); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); return len; #else err = ENOSYS; diff --git a/nuttx/net/uip/Make.defs b/nuttx/net/uip/Make.defs index 96691792d..4ad51f9bc 100644 --- a/nuttx/net/uip/Make.defs +++ b/nuttx/net/uip/Make.defs @@ -34,6 +34,6 @@ ############################################################################ UIP_ASRCS = -UIP_CSRCS = psock.c uip-arp.c uip.c uip-fw.c uip-neighbor.c uip-split.c \ +UIP_CSRCS = uip-arp.c uip.c uip-fw.c uip-neighbor.c uip-split.c \ uip-tcpconn.c uip-udpconn.c uip-wait.c diff --git a/nuttx/net/uip/psock.c b/nuttx/net/uip/psock.c deleted file mode 100644 index 55676c3c2..000000000 --- a/nuttx/net/uip/psock.c +++ /dev/null @@ -1,385 +0,0 @@ -/**************************************************************************** - * net/uip/psock.c - * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> - * - * Based on uIP which also has a BSD style license: - * - * Copyright (c) 2004, Swedish Institute of Computer Science. - * All rights reserved. - * - * 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. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <stdio.h> -#include <string.h> -#include <pthread.h> -#include <debug.h> - -#include <net/uip/uip.h> -#include <net/uip/uipopt.h> -#include <net/uip/psock.h> - -#define STATE_NONE 0 -#define STATE_ACKED 1 -#define STATE_READ 2 -#define STATE_BLOCKED_NEWDATA 3 -#define STATE_BLOCKED_CLOSE 4 -#define STATE_BLOCKED_SEND 5 -#define STATE_DATA_SENT 6 - -/* - * Return value of the buffering functions that indicates that a - * buffer was not filled by incoming data. - * - */ -#define BUF_NOT_FULL 0 -#define BUF_NOT_FOUND 0 - -/* - * Return value of the buffering functions that indicates that a - * buffer was completely filled by incoming data. - * - */ -#define BUF_FULL 1 - -/* - * Return value of the buffering functions that indicates that an - * end-marker byte was found. - * - */ -#define BUF_FOUND 2 - -static void buf_setup(struct psock_buf *buf, uint8 *bufptr, uint16 bufsize) -{ - buf->ptr = bufptr; - buf->left = bufsize; -} - -static uint8 buf_bufdata(struct psock_buf *buf, uint16 len, uint8 **dataptr, uint16 *datalen) -{ - if (*datalen < buf->left) - { - memcpy(buf->ptr, *dataptr, *datalen); - buf->ptr += *datalen; - buf->left -= *datalen; - *dataptr += *datalen; - *datalen = 0; - return BUF_NOT_FULL; - } - else if (*datalen == buf->left) - { - memcpy(buf->ptr, *dataptr, *datalen); - buf->ptr += *datalen; - buf->left = 0; - *dataptr += *datalen; - *datalen = 0; - return BUF_FULL; - } - else - { - memcpy(buf->ptr, *dataptr, buf->left); - buf->ptr += buf->left; - *datalen -= buf->left; - *dataptr += buf->left; - buf->left = 0; - return BUF_FULL; - } -} - -static uint8 buf_bufto(struct psock_buf *buf, uint8 endmarker, uint8 **dataptr, uint16 *datalen) -{ - uint8 c; - while(buf->left > 0 && *datalen > 0) - { - c = *buf->ptr = **dataptr; - ++*dataptr; - ++buf->ptr; - --*datalen; - --buf->left; - - if (c == endmarker) - { - return BUF_FOUND; - } - } - - if (*datalen == 0) - { - return BUF_NOT_FOUND; - } - - while(*datalen > 0) - { - c = **dataptr; - --*datalen; - ++*dataptr; - - if (c == endmarker) - { - return BUF_FOUND | BUF_FULL; - } - } - - return BUF_FULL; -} - -static boolean send_data(register struct psock *s) -{ - /* Inidicate that we are blocked waiting for the send to complete */ - - s->state = STATE_BLOCKED_SEND; - - /* Loop until we successfully send the data */ - - for (;;) - { - /* If the data has not been sent OR if it needs to be retransmitted, - * then send it now. - */ - - if (s->state != STATE_DATA_SENT || uip_rexmit()) - { - if (s->sendlen > uip_mss()) - { - uip_send(s->sendptr, uip_mss()); - } - else - { - uip_send(s->sendptr, s->sendlen); - } - - s->state = STATE_DATA_SENT; - } - - /* Check if all data has been sent and acknowledged */ - - if (s->state == STATE_DATA_SENT && uip_acked()) - { - /* Yes.. the data has been sent AND acknowledge */ - - if (s->sendlen > uip_mss()) - { - s->sendlen -= uip_mss(); - s->sendptr += uip_mss(); - } - else - { - s->sendptr += s->sendlen; - s->sendlen = 0; - } - - s->state = STATE_ACKED; - return TRUE; - } - - /* No.. then wait on the retransmit or acked events */ - - (void)uip_event_wait(UIP_ACKDATA|UIP_REXMIT); - } - - return FALSE; /* We never get here */ -} - -void psock_send(struct psock *s, const char *buf, unsigned int len) -{ - /* If there is no data to send, we exit immediately. */ - - if (len > 0) - { - /* Save the length of and a pointer to the data that is to be sent. */ - - s->sendptr = (const uint8*)buf; - s->sendlen = len; - s->state = STATE_NONE; - - /* Loop here until all data is sent. The s->sendlen variable is updated - * by the data_sent() function. - */ - - while(s->sendlen > 0) { - - /* Wait until the data has been sent and acknowledged */ - - send_data(s); - } - - /* Done */ - - s->state = STATE_NONE; - } -} - -void psock_generator_send(register struct psock *s, unsigned short (*generate)(void *), void *arg) -{ - /* Ensure that there is a generator function to call. */ - - if (generate != NULL) - { - /* Call the generator function to generate the data in the uip_appdata - * buffer. - */ - - s->sendlen = generate(arg); - s->sendptr = uip_appdata; - s->state = STATE_NONE; - - do - { - /* Call the generator function again if we are called to perform a - * retransmission. - */ - - if (uip_rexmit()) - { - generate(arg); - } - - /* Wait until all data is sent and acknowledged. */ - - send_data(s); - } - while(s->sendlen > 0); - - /* Done */ - - s->state = STATE_NONE; - } -} - -uint16 psock_datalen(struct psock *psock) -{ - return psock->bufsize - psock->buf.left; -} - -boolean psock_checknewdata(struct psock *s) -{ - if (s->readlen > 0) - { - /* There is data in the uip_appdata buffer that has not yet been read - * with the PSOCK_READ functions. - */ - return TRUE; - } - else if (s->state == STATE_READ) - { - /* All data in uip_appdata buffer already consumed. */ - - s->state = STATE_BLOCKED_NEWDATA; - return FALSE; - } - else if (uip_newdata()) - { - /* There is new data that has not been consumed. */ - - return TRUE; - } - else - { - /* There is no new data. */ - - return FALSE; - } -} - -void psock_waitnewdata(struct psock *s) -{ - while (!psock_checknewdata(s)) - { - uip_event_wait(UIP_NEWDATA); - } -} - -void psock_readto(register struct psock *psock, unsigned char c) -{ -restart: - buf_setup(&psock->buf, psock->bufptr, psock->bufsize); - - /* XXX: Should add buf_checkmarker() before do{} loop, if - incoming data has been handled while waiting for a write. */ - - do - { - if (psock->readlen == 0) - { - psock_waitnewdata(psock); - psock->state = STATE_READ; - psock->readptr = (uint8 *)uip_appdata; - psock->readlen = uip_datalen(); - } - } - while((buf_bufto(&psock->buf, c, &psock->readptr, &psock->readlen) & BUF_FOUND) == 0); - - if (psock_datalen(psock) == 0) - { - psock->state = STATE_NONE; - goto restart; - } -} - -void psock_readbuf(register struct psock *psock) -{ -restart: - buf_setup(&psock->buf, psock->bufptr, psock->bufsize); - - /* XXX: Should add buf_checkmarker() before do{} loop, if - incoming data has been handled while waiting for a write. */ - - do - { - if (psock->readlen == 0) - { - psock_waitnewdata(psock); - dbg("Waited for newdata\n"); - psock->state = STATE_READ; - psock->readptr = (uint8 *)uip_appdata; - psock->readlen = uip_datalen(); - } - } - while(buf_bufdata(&psock->buf, psock->bufsize, &psock->readptr, &psock->readlen) != BUF_FULL); - - if (psock_datalen(psock) == 0) - { - psock->state = STATE_NONE; - goto restart; - } -} - -void psock_init(register struct psock *psock, char *buffer, unsigned int buffersize) -{ - psock->state = STATE_NONE; - psock->readlen = 0; - psock->bufptr = (uint8*)buffer; - psock->bufsize = buffersize; - buf_setup(&psock->buf, (uint8*)buffer, buffersize); -} - diff --git a/nuttx/net/uip/uip-tcpconn.c b/nuttx/net/uip/uip-tcpconn.c index 9d1380f6b..8f14dc24b 100644 --- a/nuttx/net/uip/uip-tcpconn.c +++ b/nuttx/net/uip/uip-tcpconn.c @@ -123,6 +123,69 @@ static struct uip_conn *uip_find_conn(uint16 portno) } /**************************************************************************** + * Name: uip_selectport() + * + * Description: + * If the portnumber is zero; select an unused port for the connection. + * If the portnumber is non-zero, verify that no other connection has + * been created with this port number. + * + * Input Parameters: + * portno -- the selected port number in host order. Zero means no port + * selected. + * + * Return: + * 0 on success, -ERRNO on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +static int uip_selectport(uint16 portno) +{ + if (portno == 0) + { + /* No local port assigned. Loop until we find a valid listen port number + * that is not being used by any other connection. + */ + + do + { + /* Guess that the next available port number will be the one after + * the last port number assigned. + */ + portno = ++g_last_tcp_port; + + /* Make sure that the port number is within range */ + + if (g_last_tcp_port >= 32000) + { + g_last_tcp_port = 4096; + } + } + while (uip_find_conn(g_last_tcp_port)); + } + else + { + /* A port number has been supplied. Verify that no other TCP/IP + * connection is using this local port. + */ + + if (uip_find_conn(portno)) + { + /* It is in use... return EADDRINUSE */ + + return -EADDRINUSE; + } + } + + /* Return the selecte or verified port number */ + + return portno; +} + +/**************************************************************************** * Public Functions ****************************************************************************/ @@ -422,6 +485,20 @@ int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in6 *addr) int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in *addr) #endif { + irqstate_t flags; + int port; + + /* Verify or select a local port */ + + flags = irqsave(); + port = uip_selectport(ntohs(conn->lport)); + irqrestore(flags); + + if (port < 0) + { + return port; + } + #warning "Need to implement bind logic" return -ENOSYS; } @@ -453,7 +530,7 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr) #endif { irqstate_t flags; - uint16 port; + int port; /* The connection is expected to be in the UIP_ALLOCATED state.. i.e., * allocated via up_tcpalloc(), but not yet put into the active connections @@ -469,29 +546,13 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr) * one now. */ - port = ntohs(conn->lport); - if (port == 0) - { - /* No local port assigned. Loop until we find a valid listen port number\ - * that is not being used by any other connection. - */ - - do - { - /* Guess that the next available port number will be the one after - * the last port number assigned. - */ -#warning "This need protection from other threads and from interrupts" - port = ++g_last_tcp_port; - - /* Make sure that the port number is within range */ + flags = irqsave(); + port = uip_selectport(ntohs(conn->lport)); + irqrestore(flags); - if (g_last_tcp_port >= 32000) - { - g_last_tcp_port = 4096; - } - } - while (uip_find_conn(g_last_tcp_port)); + if (port < 0) + { + return port; } /* Initialize and return the connection structure, bind it to the port number */ @@ -511,7 +572,7 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr) conn->rto = UIP_RTO; conn->sa = 0; conn->sv = 16; /* Initial value of the RTT variance. */ - conn->lport = htons(port); + conn->lport = htons((uint16)port); /* The sockaddr port is 16 bits and already in network order */ diff --git a/nuttx/netutils/smtp/smtp.c b/nuttx/netutils/smtp/smtp.c index 5d7a61aa6..be224590a 100644 --- a/nuttx/netutils/smtp/smtp.c +++ b/nuttx/netutils/smtp/smtp.c @@ -47,13 +47,14 @@ ****************************************************************************/ #include <sys/types.h> -#include <string.h> +#include <stdio.h> #include <stdlib.h> +#include <unistd.h> +#include <string.h> #include <semaphore.h> #include <sys/socket.h> #include <net/uip/uip.h> -#include <net/uip/psock.h> #include <net/uip/smtp.h> #include "smtp-strings.h" @@ -77,7 +78,6 @@ struct smtp_state uint8 state; boolean connected; sem_t sem; - struct psock psock; uip_ipaddr_t smtpserver; char *localhostname; char *to; @@ -89,146 +89,155 @@ struct smtp_state int sentlen; int textlen; int sendptr; - int result; char buffer[SMTP_INPUT_BUFFER_SIZE]; }; -static volatile struct smtp_state *gpsmtp = 0; - -static void smtp_send_message(struct smtp_state *psmtp) +static inline int smtp_send_message(int sockfd, struct smtp_state *psmtp) { - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (strncmp(psmtp->buffer, smtp_220, 3) != 0) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 2; - return; + return ERROR; } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_helo); - PSOCK_SEND_STR(&psmtp->psock, psmtp->localhostname); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_helo, psmtp->localhostname); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (psmtp->buffer[0] != ISO_2) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 3; - return; + return ERROR; } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_mail_from); - PSOCK_SEND_STR(&psmtp->psock, psmtp->from); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_mail_from, psmtp->from); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (psmtp->buffer[0] != ISO_2) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 3; - return; + return ERROR; } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_rcpt_to); - PSOCK_SEND_STR(&psmtp->psock, psmtp->to); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_rcpt_to, psmtp->to); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (psmtp->buffer[0] != ISO_2) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 5; - return; + return ERROR; } if (psmtp->cc != 0) { - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_rcpt_to); - PSOCK_SEND_STR(&psmtp->psock, psmtp->cc); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_rcpt_to, psmtp->cc); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (psmtp->buffer[0] != ISO_2) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 6; - return; + return ERROR; } } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_data); + if (send(sockfd, smtp_data, strlen(smtp_data), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } if (psmtp->buffer[0] != ISO_3) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 7; - return; + return ERROR; } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_to); - PSOCK_SEND_STR(&psmtp->psock, psmtp->to); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_to, psmtp->to); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } if (psmtp->cc != 0) { - PSOCK_SEND_STR(&psmtp->psock, (char *)psmtp->cc); - PSOCK_SEND_STR(&psmtp->psock, psmtp->cc); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_to, psmtp->cc); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_from); - PSOCK_SEND_STR(&psmtp->psock, psmtp->from); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); - - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_subject); - PSOCK_SEND_STR(&psmtp->psock, psmtp->subject); - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl); - - psock_send(&psmtp->psock, psmtp->msg, psmtp->msglen); - - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnlperiodcrnl); + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_from, psmtp->from); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } - psock_readto(&psmtp->psock, ISO_nl); - if (psmtp->buffer[0] != ISO_2) + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_subject, psmtp->subject); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) { - PSOCK_CLOSE(&psmtp->psock); - psmtp->result = 8; - return; + return ERROR; } - PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_quit); - psmtp->result = 0; -} + if (send(sockfd, psmtp->msg, psmtp->msglen, 0) < 0) + { + return ERROR; + } -/* This function is called by the UIP interrupt handling logic whenevent an - * event of interest occurs. - */ + if (send(sockfd, smtp_crnlperiodcrnl, strlen(smtp_crnlperiodcrnl), 0) < 0) + { + return ERROR; + } -void uip_interrupt_event(void) -{ -#warning OBSOLETE -- needs to be redesigned - if (gpsmtp) + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) { - if (uip_closed()) - { - gpsmtp->connected = FALSE; - return; - } + return ERROR; + } - if (uip_aborted() || uip_timedout()) - { - gpsmtp->connected = FALSE; - } + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } - sem_post((sem_t*)&gpsmtp->sem); + if (send(sockfd, smtp_quit, strlen(smtp_quit), 0) < 0) + { + return ERROR; } + return OK; } /* Specificy an SMTP server and hostname. @@ -264,6 +273,7 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char struct smtp_state *psmtp = (struct smtp_state *)handle; struct sockaddr_in server; int sockfd; + int ret; /* Setup */ @@ -274,7 +284,6 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char psmtp->subject = subject; psmtp->msg = msg; psmtp->msglen = msglen; - psmtp->result = OK; /* Create a socket */ @@ -284,12 +293,6 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char return ERROR; } - /* Make this instance globally visible (we will get interrupts as - * soon as we connect - */ - - gpsmtp = psmtp; - /* Connect to server. First we have to set some fields in the * 'server' structure. The system will assign me an arbitrary * local port that is not in use. @@ -301,27 +304,16 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char if (connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { + close(sockfd); return ERROR; - } - - /* Initialize the psock structure inside the smtp state structure */ - - psock_init(&psmtp->psock, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE); - - /* And wait for the the socket to be connected */ - - sem_wait(&psmtp->sem); - gpsmtp = 0; + } - /* Was an error reported by interrupt handler? */ + /* Send the message */ - if (psmtp->result == OK ) - { - /* No... Send the message */ - smtp_send_message(psmtp); - } + ret = smtp_send_message(sockfd, psmtp); - return psmtp->result; + close(sockfd); + return ret; } void *smtp_open(void) diff --git a/nuttx/netutils/webserver/httpd-cgi.c b/nuttx/netutils/webserver/httpd-cgi.c index 2b68040a2..9870961e6 100644 --- a/nuttx/netutils/webserver/httpd-cgi.c +++ b/nuttx/netutils/webserver/httpd-cgi.c @@ -30,15 +30,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> + #include <net/uip/uip.h> -#include <net/uip/psock.h> #include <net/uip/httpd.h> #include "httpd-cgi.h" -#include <stdio.h> -#include <string.h> - #define CONFIG_HTTPDCGI_FILESTATS 1 #undef CONFIG_HTTPDCGI_DCPSTATS #define CONFIG_HTTPDCGI_NETSTATS 1 @@ -101,7 +101,7 @@ static const char *states[] = }; #endif -static void nullfunction(struct httpd_state *s, char *ptr) +static void nullfunction(struct httpd_state *pstate, char *ptr) { } @@ -120,66 +120,57 @@ httpd_cgifunction httpd_cgi(char *name) } #ifdef CONFIG_HTTPDCGI_FILESTATS -static unsigned short generate_file_stats(void *arg) +static void file_stats(struct httpd_state *pstate, char *ptr) { - char *f = (char *)arg; - return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, "%5u", httpd_fs_count(f)); -} - -static void file_stats(struct httpd_state *s, char *ptr) -{ - psock_generator_send(&s->sout, generate_file_stats, strchr(ptr, ' ') + 1); + char buffer[16]; + char *pcount = strchr(ptr, ' ') + 1; + snprintf(buffer, 16, "%5u", httpd_fs_count(pcount)); + (void)send(pstate->sockout, buffer, strlen(buffer), 0); } #endif #if CONFIG_HTTPDCGI_TCPSTATS -static unsigned short generate_tcp_stats(void *arg) +static void tcp_stats(struct httpd_state *pstate, char *ptr) { struct uip_conn *conn; - struct httpd_state *s = (struct httpd_state *)arg; - - conn = &uip_conns[s->count]; - return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, - "<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n", - htons(conn->lport), - htons(conn->ripaddr[0]) >> 8, - htons(conn->ripaddr[0]) & 0xff, - htons(conn->ripaddr[1]) >> 8, - htons(conn->ripaddr[1]) & 0xff, - htons(conn->rport), - states[conn->tcpstateflags & UIP_TS_MASK], - conn->nrtx, - conn->timer, - (uip_outstanding(conn))? '*':' ', - (uip_stopped(conn))? '!':' '); -} + struct httpd_state *pstate = (struct httpd_state *)arg; + char buffer[256]; -static void tcp_stats(struct httpd_state *s, char *ptr) -{ - for(s->count = 0; s->count < UIP_CONNS; ++s->count) + for(pstate->count = 0; pstate->count < UIP_CONNS; ++pstate->count) { - if((uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) + conn = &uip_conns[pstate->count]; + if((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { - psock_generator_send(&s->sout, generate_tcp_stats, s); + snprintf(buffer, 25t, + "<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n", + htons(conn->lport), + htons(conn->ripaddr[0]) >> 8, + htons(conn->ripaddr[0]) & 0xff, + htons(conn->ripaddr[1]) >> 8, + htons(conn->ripaddr[1]) & 0xff, + htons(conn->rport), + states[conn->tcpstateflags & UIP_TS_MASK], + conn->nrtx, + conn->timer, + (uip_outstanding(conn))? '*':' ', + (uip_stopped(conn))? '!':' '); + + (void)send(pstate->sockout, buffer, strlen(buffer), 0); } } } #endif #ifdef CONFIG_HTTPDCGI_NETSTATS -static unsigned short generate_net_stats(void *arg) -{ - struct httpd_state *s = (struct httpd_state *)arg; - return snprintf((char*)uip_appdata, UIP_APPDATA_SIZE, - "%5u\n", ((uip_stats_t *)&uip_stat)[s->count]); -} - -static void net_stats(struct httpd_state *s, char *ptr) +static void net_stats(struct httpd_state *pstate, char *ptr) { #if UIP_STATISTICS - for(s->count = 0; s->count < sizeof(uip_stat) / sizeof(uip_stats_t); ++s->count) + char buffer[16]; + + for(pstate->count = 0; pstate->count < sizeof(uip_stat) / sizeof(uip_stats_t); ++pstate->count) { - psock_generator_send(&s->sout, generate_net_stats, s); + snprintf(buffer, 16, "%5u\n", ((uip_stats_t *)&uip_stat)[pstate->count]); + send(pstate->sockout, buffer, strlen(buffer), 0); } #endif /* UIP_STATISTICS */ } diff --git a/nuttx/netutils/webserver/httpd-cgi.h b/nuttx/netutils/webserver/httpd-cgi.h index bd22feb85..7243b19f2 100644 --- a/nuttx/netutils/webserver/httpd-cgi.h +++ b/nuttx/netutils/webserver/httpd-cgi.h @@ -33,9 +33,10 @@ #ifndef __HTTPD_CGI_H__ #define __HTTPD_CGI_H__ -#include <net/uip/psock.h> #include <net/uip/httpd.h> +#include "httpd.h" + typedef void (* httpd_cgifunction)(struct httpd_state *, char *); httpd_cgifunction httpd_cgi(char *name); diff --git a/nuttx/netutils/webserver/httpd-fs.c b/nuttx/netutils/webserver/httpd-fs.c index 3b446ac43..d3fe35171 100644 --- a/nuttx/netutils/webserver/httpd-fs.c +++ b/nuttx/netutils/webserver/httpd-fs.c @@ -45,6 +45,7 @@ #include <net/uip/httpd.h> +#include "httpd.h" #include "httpd-fsdata.h" #ifndef NULL diff --git a/nuttx/netutils/webserver/httpd.c b/nuttx/netutils/webserver/httpd.c index 6cf50962f..4f18a72df 100644 --- a/nuttx/netutils/webserver/httpd.c +++ b/nuttx/netutils/webserver/httpd.c @@ -35,9 +35,12 @@ */ #include <stdlib.h> +#include <sys/socket.h> + #include <net/uip/uip.h> #include <net/uip/httpd.h> +#include "httpd.h" #include "httpd-cgi.h" #include "http-strings.h" @@ -54,244 +57,208 @@ #define ISO_slash 0x2f #define ISO_colon 0x3a -static unsigned short generate_part_of_file(void *state) -{ - struct httpd_state *s = (struct httpd_state *)state; - - if (s->file.len > uip_mss()) { - s->len = uip_mss(); - } else { - s->len = s->file.len; - } - memcpy(uip_appdata, s->file.data, s->len); - - return s->len; -} +#define SEND_STR(psock, str) psock_send(psock, str, strlen(str)) -static void send_file(struct httpd_state *s) +static inline int send_file(struct httpd_state *pstate) { - do { - psock_generator_send(&s->sout, generate_part_of_file, s); - s->file.len -= s->len; - s->file.data += s->len; - } while(s->file.len > 0); -#warning REVISIT must not return until file sent + return send(pstate->sockout, pstate->file.data, pstate->file.len, 0); } -static void send_part_of_file(struct httpd_state *s) +static inline int send_part_of_file(struct httpd_state *pstate) { - psock_send(&s->sout, s->file.data, s->len); -#warning REVISIT must not return until file sent + return send(pstate->sockout, pstate->file.data, pstate->len, 0); } -static void next_scriptstate(struct httpd_state *s) +static void next_scriptstate(struct httpd_state *pstate) { char *p; - p = strchr(s->scriptptr, ISO_nl) + 1; - s->scriptlen -= (unsigned short)(p - s->scriptptr); - s->scriptptr = p; + p = strchr(pstate->scriptptr, ISO_nl) + 1; + pstate->scriptlen -= (unsigned short)(p - pstate->scriptptr); + pstate->scriptptr = p; } -static void handle_script(struct httpd_state *s) +static void handle_script(struct httpd_state *pstate) { char *ptr; - - while(s->file.len > 0) { + + while(pstate->file.len > 0) { /* Check if we should start executing a script. */ - if (*s->file.data == ISO_percent && - *(s->file.data + 1) == ISO_bang) { - s->scriptptr = s->file.data + 3; - s->scriptlen = s->file.len - 3; - if (*(s->scriptptr - 1) == ISO_colon) { - httpd_fs_open(s->scriptptr + 1, &s->file); - send_file(s); + if (*pstate->file.data == ISO_percent && + *(pstate->file.data + 1) == ISO_bang) { + pstate->scriptptr = pstate->file.data + 3; + pstate->scriptlen = pstate->file.len - 3; + if (*(pstate->scriptptr - 1) == ISO_colon) { + httpd_fs_open(pstate->scriptptr + 1, &pstate->file); + send_file(pstate); } else { - httpd_cgi(s->scriptptr)(s, s->scriptptr); + httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr); } - next_scriptstate(s); + next_scriptstate(pstate); /* The script is over, so we reset the pointers and continue sending the rest of the file. */ - s->file.data = s->scriptptr; - s->file.len = s->scriptlen; + pstate->file.data = pstate->scriptptr; + pstate->file.len = pstate->scriptlen; } else { /* See if we find the start of script marker in the block of HTML to be sent. */ - if (s->file.len > uip_mss()) { - s->len = uip_mss(); + if (pstate->file.len > uip_mss()) { + pstate->len = uip_mss(); } else { - s->len = s->file.len; + pstate->len = pstate->file.len; } - if (*s->file.data == ISO_percent) { - ptr = strchr(s->file.data + 1, ISO_percent); + if (*pstate->file.data == ISO_percent) { + ptr = strchr(pstate->file.data + 1, ISO_percent); } else { - ptr = strchr(s->file.data, ISO_percent); + ptr = strchr(pstate->file.data, ISO_percent); } if (ptr != NULL && - ptr != s->file.data) { - s->len = (int)(ptr - s->file.data); - if (s->len >= uip_mss()) { - s->len = uip_mss(); + ptr != pstate->file.data) { + pstate->len = (int)(ptr - pstate->file.data); + if (pstate->len >= uip_mss()) { + pstate->len = uip_mss(); } } - send_part_of_file(s); - s->file.data += s->len; - s->file.len -= s->len; + send_part_of_file(pstate); + pstate->file.data += pstate->len; + pstate->file.len -= pstate->len; } } -#warning REVISIT must not return until sent } -static void send_headers(struct httpd_state *s, const char *statushdr) +static int send_headers(struct httpd_state *pstate, const char *statushdr) { char *ptr; + int ret; - PSOCK_SEND_STR(&s->sout, statushdr); - - ptr = strrchr(s->filename, ISO_period); - if (ptr == NULL) { - PSOCK_SEND_STR(&s->sout, http_content_type_binary); - } else if (strncmp(http_html, ptr, 5) == 0 || - strncmp(http_shtml, ptr, 6) == 0) { - PSOCK_SEND_STR(&s->sout, http_content_type_html); - } else if (strncmp(http_css, ptr, 4) == 0) { - PSOCK_SEND_STR(&s->sout, http_content_type_css); - } else if (strncmp(http_png, ptr, 4) == 0) { - PSOCK_SEND_STR(&s->sout, http_content_type_png); - } else if (strncmp(http_gif, ptr, 4) == 0) { - PSOCK_SEND_STR(&s->sout, http_content_type_gif); - } else if (strncmp(http_jpg, ptr, 4) == 0) { - PSOCK_SEND_STR(&s->sout, http_content_type_jpg); - } else { - PSOCK_SEND_STR(&s->sout, http_content_type_plain); - } -#warning REVISIT must not return until sent + ret = send(pstate->sockout, statushdr, strlen(statushdr), 0); + + ptr = strrchr(pstate->filename, ISO_period); + if (ptr == NULL) + { + ret = send(pstate->sockout, http_content_type_binary, strlen(http_content_type_binary), 0); + } + else if (strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0) + { + ret = send(pstate->sockout, http_content_type_html, strlen(http_content_type_html), 0); + } + else if (strncmp(http_css, ptr, 4) == 0) + { + ret = send(pstate->sockout, http_content_type_css, strlen(http_content_type_css), 0); + } + else if (strncmp(http_png, ptr, 4) == 0) + { + ret = send(pstate->sockout, http_content_type_png, strlen(http_content_type_png), 0); + } + else if (strncmp(http_gif, ptr, 4) == 0) + { + ret = send(pstate->sockout, http_content_type_gif, strlen(http_content_type_gif), 0); + } + else if (strncmp(http_jpg, ptr, 4) == 0) + { + ret = send(pstate->sockout, http_content_type_jpg, strlen(http_content_type_jpg), 0); + } + else + { + ret = send(pstate->sockout, http_content_type_plain, strlen(http_content_type_plain), 0); + } + return ret; } -static void handle_output(struct httpd_state *s) +static void handle_output(struct httpd_state *pstate) { char *ptr; - if (!httpd_fs_open(s->filename, &s->file)) + if (!httpd_fs_open(pstate->filename, &pstate->file)) { - httpd_fs_open(http_404_html, &s->file); - strcpy(s->filename, http_404_html); - send_headers(s, http_header_404); - send_file(s); + httpd_fs_open(http_404_html, &pstate->file); + strcpy(pstate->filename, http_404_html); + send_headers(pstate, http_header_404); + send_file(pstate); } else { - send_headers(s, http_header_200); - ptr = strchr(s->filename, ISO_period); + send_headers(pstate, http_header_200); + ptr = strchr(pstate->filename, ISO_period); if (ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) { - handle_script(s); + handle_script(pstate); } else { - send_file(s); + send_file(pstate); } } - PSOCK_CLOSE(&s->sout); } -static void handle_input(struct httpd_state *s) +static int handle_input(struct httpd_state *pstate) { - psock_readto(&s->sin, ISO_space); + ssize_t recvlen; + + if (recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0) < 0) + { + return ERROR; + } - if (strncmp(s->inputbuf, http_get, 4) != 0) + if (strncmp(pstate->inputbuf, http_get, 4) != 0) { - PSOCK_CLOSE(&s->sin); - return; + return ERROR; } - psock_readto(&s->sin, ISO_space); + recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0); + if (recvlen < 0) + { + return ERROR; + } - if (s->inputbuf[0] != ISO_slash) + if (pstate->inputbuf[0] != ISO_slash) { - PSOCK_CLOSE(&s->sin); - return; + return ERROR; } - if (s->inputbuf[1] == ISO_space) + if (pstate->inputbuf[1] == ISO_space) { - strncpy(s->filename, http_index_html, sizeof(s->filename)); + strncpy(pstate->filename, http_index_html, sizeof(pstate->filename)); } else { - s->inputbuf[psock_datalen(&s->sin) - 1] = 0; - strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); + pstate->inputbuf[recvlen - 1] = 0; + strncpy(pstate->filename, &pstate->inputbuf[0], sizeof(pstate->filename)); } - s->state = STATE_OUTPUT; + pstate->state = STATE_OUTPUT; while(1) { - psock_readto(&s->sin, ISO_nl); + recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0); + if (recvlen < 0) + { + return ERROR; + } - if (strncmp(s->inputbuf, http_referer, 8) == 0) + if (strncmp(pstate->inputbuf, http_referer, 8) == 0) { - s->inputbuf[psock_datalen(&s->sin) - 2] = 0; + pstate->inputbuf[recvlen - 2] = 0; } } + + return OK; } -static void handle_connection(struct httpd_state *s) +static void handle_connection(struct httpd_state *pstate) { - handle_input(s); - if (s->state == STATE_OUTPUT) { - handle_output(s); + handle_input(pstate); + if (pstate->state == STATE_OUTPUT) { + handle_output(pstate); } } -/* This function is called by the UIP interrupt handling logic whenevent an - * event of interest occurs. - */ - -void uip_interrupt_event(void) +void httpd_listen(void) { -#warning OBSOLETE -- needs to be redesigned - /* Get the private application specific data */ - struct httpd_state *s = (struct httpd_state *)(uip_conn->private); - - /* Has application specific data been allocate yet? */ - - if (!s) - { - /* No.. allocate it now */ - s = (struct httpd_state *)malloc(sizeof(struct httpd_state)); - if (!s) - { - return; - } - - /* And assign the private instance to the connection */ - uip_conn->private = s; - } - - if (uip_closed() || uip_aborted() || uip_timedout()) { - } else if (uip_connected()) { - psock_init(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); - psock_init(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); - s->state = STATE_WAITING; - s->timer = 0; - handle_connection(s); - } else if (s != NULL) { - if (uip_poll()) { - ++s->timer; - if (s->timer >= 20) { - uip_abort(); - } - } else { - s->timer = 0; - } - handle_connection(s); - } else { - uip_abort(); - } +#warning "this is all very broken at the moment" } /* Initialize the web server diff --git a/nuttx/netutils/webserver/httpd.h b/nuttx/netutils/webserver/httpd.h new file mode 100644 index 000000000..b256c1dd1 --- /dev/null +++ b/nuttx/netutils/webserver/httpd.h @@ -0,0 +1,74 @@ +/* httpd.h + * + * Copyright (c) 2001-2005, Adam Dunkels. + * All rights reserved. + * + * 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. + */ + +#ifndef _NETUTILS_WEBSERVER_HTTPD_H +#define _NETUTILS_WEBSERVER_HTTPD_H + +#include <sys/types.h> + +#define HTTPD_FS_STATISTICS 1 +#define HTTPD_INBUFFER_SIZE 50 + +struct httpd_fs_file +{ + char *data; + int len; +}; + +struct httpd_state +{ + unsigned char timer; + int sockin; + int sockout; + char inputbuf[HTTPD_INBUFFER_SIZE]; + char filename[20]; + char state; + struct httpd_fs_file file; + int len; + char *scriptptr; + int scriptlen; + + unsigned short count; +}; + +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 +extern uint16 httpd_fs_count(char *name); +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ + +/* file must be allocated by caller and will be filled in + * by the function. + */ + +int httpd_fs_open(const char *name, struct httpd_fs_file *file); +void httpd_fs_init(void); + +#endif /* _NETUTILS_WEBSERVER_HTTPD_H */ |