diff options
Diffstat (limited to 'nuttx/net')
-rw-r--r-- | nuttx/net/accept.c | 217 | ||||
-rw-r--r-- | nuttx/net/listen.c | 48 | ||||
-rw-r--r-- | nuttx/net/net-internal.h | 8 | ||||
-rw-r--r-- | nuttx/net/uip/Make.defs | 2 | ||||
-rw-r--r-- | nuttx/net/uip/uip-internal.h | 12 | ||||
-rw-r--r-- | nuttx/net/uip/uip-listen.c | 206 | ||||
-rw-r--r-- | nuttx/net/uip/uip-tcpconn.c | 72 | ||||
-rw-r--r-- | nuttx/net/uip/uip.c | 64 |
8 files changed, 546 insertions, 83 deletions
diff --git a/nuttx/net/accept.c b/nuttx/net/accept.c index c54b49d37..66c05e989 100644 --- a/nuttx/net/accept.c +++ b/nuttx/net/accept.c @@ -42,12 +42,72 @@ #include <sys/types.h> #include <sys/socket.h> +#include <semaphore.h> +#include <string.h> #include <errno.h> +#include <arch/irq.h> #include "net-internal.h" /**************************************************************************** - * Global Functions + * Private Types + ****************************************************************************/ + +struct accept_s +{ + sem_t acpt_sem; /* Wait for interrupt event */ +#ifdef CONFIG_NET_IPv6 + FAR const struct sockaddr_in6 *acpt_addr; /* Return connection adress */ +#else + FAR const struct sockaddr_in *acpt_addr; /* Return connection adress */ +#endif + FAR struct uip_conn *acpt_listenconn; /* The listener connection */ + FAR struct uip_conn *acpt_newconn; /* The accepted connection */ + int acpt_result; /* The result of the wait */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: accept_interrupt + * + * Description: + * Receive interrupt level callbacks when connections occur + * + ****************************************************************************/ + +static int accept_interrupt(void *private, struct uip_conn *conn) +{ + struct accept_s *pstate = (struct accept_s *)private; + int ret = -EINVAL; + if (pstate) + { + /* Get the connection address */ +#warning "need to return the address of the connection" + + /* Save the connection structure */ + + pstate->acpt_newconn = conn; + pstate->acpt_result = OK; + sem_post(&pstate->acpt_sem); + + /* Stop any further callbacks */ + + pstate->acpt_listenconn->accept_private = NULL; + pstate->acpt_listenconn->accept = NULL; + ret = OK; + } + return ret; +} + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -122,7 +182,160 @@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - *get_errno_ptr() = ENOSYS; + FAR struct socket *psock = sockfd_socket(sockfd); + FAR struct socket *pnewsock; + FAR struct uip_conn *conn; + struct accept_s state; +#ifdef CONFIG_NET_IPv6 + FAR const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6 *)addr; +#else + FAR const struct sockaddr_in *inaddr = (const struct sockaddr_in *)addr; +#endif + irqstate_t save; + int newfd; + int err; + int ret; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (!psock || psock->s_crefs <= 0) + { + /* It is not a valid socket description. Distinguish between the cases + * where sockfd is a just valid and when it is a valid file descriptor used + * in the wrong context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) + { + err = ENOTSOCK; + } + else +#endif + { + err = EBADF; + } + goto errout; + } + + /* We have a socket descriptor, but it is a stream? */ + + if (psock->s_type != SOCK_STREAM) + { + err = EOPNOTSUPP; + goto errout; + } + + /* Is the socket listening for a connection? */ + + if (!_SS_ISLISTENING(psock->s_flags)) + { + err = EINVAL; + goto errout; + } + + /* Verify that a valid memory block has been provided to receive the address address */ + +#ifdef CONFIG_NET_IPv6 + if (addr->sa_family != AF_INET6 || *addrlen < sizeof(struct sockaddr_in6)) +#else + if (addr->sa_family != AF_INET || *addrlen < sizeof(struct sockaddr_in)) +#endif + { + err = EBADF; + goto errout; + } + + /* Allocate a socket descriptor for the new connection now (so that it cannot fail later) */ + + newfd = sockfd_allocate(); + if (newfd < 0) + { + err = ENFILE; + goto errout; + } + + pnewsock = sockfd_socket(newfd); + if (newfd) + { + err = ENFILE; + goto errout_with_socket; + } + + /* Set the socket state to accepting */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); + + /* Perform the TCP accept 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(); + state.acpt_addr = inaddr; + state.acpt_listenconn = psock->s_conn; + state.acpt_newconn = NULL; + state.acpt_result = OK; + + /* Set up the callback in the connection */ + + conn = (struct uip_conn *)psock->s_conn; + conn->accept_private = (void*)&state; + conn->accept = accept_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. acpt_sem); + + /* Make sure that no further interrupts are processed */ + + conn->accept_private = NULL; + conn->accept = NULL; + + sem_destroy(&state. acpt_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.acpt_result != 0) + { + err = state.acpt_result; + goto errout_with_socket; + } + + /* 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_with_socket; + } + + /* Initialize the socket structure */ + + pnewsock->s_type = SOCK_STREAM; + pnewsock->s_conn = state.acpt_newconn; + return newfd; + +errout_with_socket: + sockfd_release(newfd); + +errout: + *get_errno_ptr() = err; return ERROR; } diff --git a/nuttx/net/listen.c b/nuttx/net/listen.c index 30dcb778b..08f9d851a 100644 --- a/nuttx/net/listen.c +++ b/nuttx/net/listen.c @@ -56,7 +56,7 @@ * Description: * To accept connections, a socket is first created with socket(), a * willingness to accept incoming connections and a queue limit for incoming - * connections are specified with listen, and then the connections are + * connections are specified with listen(), and then the connections are * accepted with accept(). The listen() call applies only to sockets of * type SOCK_STREAM or SOCK_SEQPACKET. * @@ -87,7 +87,51 @@ int listen(int sockfd, int backlog) { - *get_errno_ptr() = ENOSYS; + FAR struct socket *psock = sockfd_socket(sockfd); + struct uip_conn *conn; + int err; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (!psock || psock->s_crefs <= 0) + { + /* It is not a valid socket description. Distinguish between the cases + * where sockfd is a just valid and when it is a valid file descriptor used + * in the wrong context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) + { + err = ENOTSOCK; + } + else +#endif + { + err = EBADF; + } + goto errout; + } + + /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ + + conn = (struct uip_conn *)psock->s_conn; + if (psock->s_type != SOCK_STREAM || !psock->s_conn || conn->lport <= 0) + { + err = EOPNOTSUPP; + goto errout; + } + + /* Start listening to the bound port. This enables callbacks when accept() + * is called; and someday should enable post() or select() logic. + */ + + uip_listen(conn->lport); + psock->s_flags |= _SF_LISTENING; + return OK; + +errout: + *get_errno_ptr() = err; return ERROR; } diff --git a/nuttx/net/net-internal.h b/nuttx/net/net-internal.h index eca4ec5cc..af587d970 100644 --- a/nuttx/net/net-internal.h +++ b/nuttx/net/net-internal.h @@ -56,11 +56,12 @@ /* Bits 0:2 : Socket state */ #define _SF_IDLE 0x00 /* There is no socket activity */ -#define _SF_LISTEN 0x01 /* Socket is listening */ +#define _SF_ACCEPT 0x01 /* Socket is waiting to accept a connection */ #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 */ + /* Bits 3:4 : unused */ +#define _SF_LISTENING 0x20 /* Bit 5: SOCK_STREAM is listening */ #define _SF_BOUND 0x40 /* Bit 6: SOCK_STREAM is bound to an address */ #define _SF_CONNECTED 0x80 /* Bit 7: SOCK_STREAM is connected */ @@ -69,8 +70,9 @@ #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_ISLISTENING(s) (((s) & _SF_LISTENING) != 0) #define _SS_ISBOUND(s) (((s) & _SF_CONNECTED) != 0) +#define _SS_ISCONNECTED(s) (((s) & _SF_CONNECTED) != 0) /* This macro converts a socket option value into a bit setting */ diff --git a/nuttx/net/uip/Make.defs b/nuttx/net/uip/Make.defs index fd20143ff..61f89cc7b 100644 --- a/nuttx/net/uip/Make.defs +++ b/nuttx/net/uip/Make.defs @@ -35,5 +35,5 @@ UIP_ASRCS = UIP_CSRCS = uip-arp.c uip.c uip-send.c uip-fw.c uip-neighbor.c uip-split.c \ - uip-tcpconn.c uip-udpconn.c + uip-tcpconn.c uip-udpconn.c uip-listen.c diff --git a/nuttx/net/uip/uip-internal.h b/nuttx/net/uip/uip-internal.h index f8613c63a..6c76f39cf 100644 --- a/nuttx/net/uip/uip-internal.h +++ b/nuttx/net/uip/uip-internal.h @@ -44,6 +44,9 @@ ****************************************************************************/ #include <sys/types.h> +#include <errno.h> +#include <arch/irq.h> +#include <net/uip/uip.h> /**************************************************************************** * Public Macro Definitions @@ -75,7 +78,8 @@ extern "C" { EXTERN void uip_tcpinit(void); EXTERN struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf); -EXTERN struct uip_conn *uip_tcplistener(struct uip_tcpip_hdr *buf); +EXTERN struct uip_conn *uip_tcplistener(uint16 portno); +EXTERN struct uip_conn *uip_tcpaccept(struct uip_tcpip_hdr *buf); EXTERN void uip_tcpnextsequence(void); /* Defined in uip_udpconn.c *************************************************/ @@ -83,6 +87,12 @@ EXTERN void uip_tcpnextsequence(void); EXTERN void uip_udpinit(void); EXTERN struct uip_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf); +/* Defined in uip_listen.c **************************************************/ + +EXTERN void uip_listeninit(void); +EXTERN boolean uip_islistener(uint16 port); +EXTERN int uip_accept(struct uip_conn *conn, uint16 portno); + #undef EXTERN #ifdef __cplusplus } diff --git a/nuttx/net/uip/uip-listen.c b/nuttx/net/uip/uip-listen.c new file mode 100644 index 000000000..edbb9d469 --- /dev/null +++ b/nuttx/net/uip/uip-listen.c @@ -0,0 +1,206 @@ +/**************************************************************************** + * net/uip/uip-listen.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * A direct leverage of logic from uIP which also has b BSD style license + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2001-2003, 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <net/uip/uipopt.h> + +#include "uip-internal.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The uip_listenports list all currently listening ports. */ + +static uint16 uip_listenports[UIP_LISTENPORTS]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: uip_listeninit + * + * Description: + * Setup the listening data structures + * + * Assumptions: + * Called early in the inialization phase while the system is still + * single-threaded. + * + ****************************************************************************/ + +void uip_listeninit(void) +{ + int ndx; + for (ndx = 0; ndx < UIP_LISTENPORTS; ndx++) + { + uip_listenports[ndx] = 0; + } +} + +/**************************************************************************** + * Function: uip_unlisten + * + * Description: + * Stop listening on a port + * + * Assumptions: + * Called from normal user code. + * + ****************************************************************************/ + +int uip_unlisten(uint16 port) +{ + irqstate_t flags; + int ndx; + int ret = -EINVAL; + + flags = irqsave(); + for (ndx = 0; ndx < UIP_LISTENPORTS; ndx++) + { + if (uip_listenports[ndx] == port) + { + uip_listenports[ndx] = 0; + ret = OK; + break; + } + } + irqrestore(flags); + return ret; +} + +/**************************************************************************** + * Function: uip_listen + * + * Description: + * Start listening on a port + * + * Assumptions: + * Called from normal user code. + * + ****************************************************************************/ + +int uip_listen(uint16 port) +{ + irqstate_t flags; + int ndx; + int ret = -ENOBUFS; + + flags = irqsave(); + for (ndx = 0; ndx < UIP_LISTENPORTS; ndx++) + { + if (uip_listenports[ndx] == 0) + { + uip_listenports[ndx] = port; + ret = OK; + break; + } + } + irqrestore(flags); + return ret; +} + +/**************************************************************************** + * Function: uip_islistener + * + * Description: + * Return TRUE is there is a listener for the specified port + * + * Assumptions: + * Called at interrupt level + * + ****************************************************************************/ + +boolean uip_islistener(uint16 portno) +{ + int ndx; + for (ndx = 0; ndx < UIP_LISTENPORTS; ndx++) + { + if (uip_listenports[ndx] == portno) + { + return TRUE; + } + } + return FALSE; +} + +/**************************************************************************** + * Function: uip_accept + * + * Description: + * Accept the new connection for the specified listening port. + * + * Assumptions: + * Called at interrupt level + * + ****************************************************************************/ + +int uip_accept(struct uip_conn *conn, uint16 portno) +{ + struct uip_conn *listener; + int ret = ERROR; + + /* The interrupt logic has already allocated and initialized a TCP + * connection -- now check if is an application in place to accept the + * connection. + */ + + listener = uip_tcplistener(portno); + if (listener && listener->accept) + { + /* Yes.. accept the connection */ + + ret = listener->accept(listener->accept_private, conn); + } + return ret; +} + +#endif /* CONFIG_NET */ diff --git a/nuttx/net/uip/uip-tcpconn.c b/nuttx/net/uip/uip-tcpconn.c index f604c26c7..b8bcdb3ce 100644 --- a/nuttx/net/uip/uip-tcpconn.c +++ b/nuttx/net/uip/uip-tcpconn.c @@ -91,38 +91,6 @@ static uint8 g_tcp_sequence[4]; ****************************************************************************/ /**************************************************************************** - * Name: uip_find_conn() - * - * Description: - * Given a port number, find the socket bound to the port number. - * Primary use: to determine if a port number is available. - * - ****************************************************************************/ - -static struct uip_conn *uip_find_conn(uint16 portno) -{ - struct uip_conn *conn; - int i; - - /* Check if this port number is already in use, and if so try to find - * another one. - */ - - for (i = 0; i < UIP_CONNS; i++) - { - conn = &g_tcp_connections[i]; - if (conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(g_last_tcp_port)) - { - /* The portnumber is in use */ - - return conn; - } - } - - return NULL; -} - -/**************************************************************************** * Name: uip_selectport() * * Description: @@ -164,7 +132,7 @@ static int uip_selectport(uint16 portno) g_last_tcp_port = 4096; } } - while (uip_find_conn(g_last_tcp_port)); + while (uip_tcplistener(g_last_tcp_port)); } else { @@ -172,7 +140,7 @@ static int uip_selectport(uint16 portno) * connection is using this local port. */ - if (uip_find_conn(portno)) + if (uip_tcplistener(portno)) { /* It is in use... return EADDRINUSE */ @@ -373,7 +341,39 @@ struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf) } /**************************************************************************** - * Name: uip_tcpactive() + * Name: uip_tcplistener() + * + * Description: + * Given a local port number, find the TCP connection that listens on this + * this port. + * + * Primary uses: (1) to determine if a port number is available, (2) to + * To idenfity the socket that will accept new connections on a local port. + * + ****************************************************************************/ + +struct uip_conn *uip_tcplistener(uint16 portno) +{ + struct uip_conn *conn; + int i; + + /* Check if this port number is in use by any active UIP TCP connection */ + + for (i = 0; i < UIP_CONNS; i++) + { + conn = &g_tcp_connections[i]; + if (conn->tcpstateflags != UIP_CLOSED && conn->lport == htons(g_last_tcp_port)) + { + /* The portnumber is in use, return the connection */ + + return conn; + } + } + return NULL; +} + +/**************************************************************************** + * Name: uip_tcpaccept() * * Description: * Called when uip_interupt matches the incoming packet with a connection @@ -385,7 +385,7 @@ struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf) * ****************************************************************************/ -struct uip_conn *uip_tcplistener(struct uip_tcpip_hdr *buf) +struct uip_conn *uip_tcpaccept(struct uip_tcpip_hdr *buf) { struct uip_conn *conn = uip_tcpalloc(); if (conn) diff --git a/nuttx/net/uip/uip.c b/nuttx/net/uip/uip.c index 49536fa41..3cfb37b2a 100644 --- a/nuttx/net/uip/uip.c +++ b/nuttx/net/uip/uip.c @@ -156,10 +156,6 @@ uint8 uip_flags; struct uip_conn *uip_conn; -/* The uip_listenports list all currently listening ports. */ - -uint16 uip_listenports[UIP_LISTENPORTS]; - #ifdef CONFIG_NET_UDP struct uip_udp_conn *uip_udp_conn; #endif /* CONFIG_NET_UDP */ @@ -361,10 +357,9 @@ uint16 uip_udpchksum(struct uip_driver_s *dev) void uip_init(void) { - for (c = 0; c < UIP_LISTENPORTS; ++c) - { - uip_listenports[c] = 0; - } + /* Initialize the listening port structures */ + + uip_listeninit(); /* Initialize the TCP/IP connection structures */ @@ -379,30 +374,6 @@ void uip_init(void) /* IPv4 initialization. */ } -void uip_unlisten(uint16 port) -{ - for (c = 0; c < UIP_LISTENPORTS; ++c) - { - if (uip_listenports[c] == port) - { - uip_listenports[c] = 0; - return; - } - } -} - -void uip_listen(uint16 port) -{ - for (c = 0; c < UIP_LISTENPORTS; ++c) - { - if (uip_listenports[c] == 0) - { - uip_listenports[c] = port; - return; - } - } -} - /* IP fragment reassembly: not well-tested. */ #if UIP_REASSEMBLY && !defined(CONFIG_NET_IPv6) @@ -1195,9 +1166,8 @@ void uip_interrupt(struct uip_driver_s *dev, uint8 flag) tmp16 = BUF->destport; /* Next, check listening connections. */ - for (c = 0; c < UIP_LISTENPORTS; ++c) + if (uip_islistener(tmp16)) { - if (tmp16 == uip_listenports[c]) goto found_listen; } @@ -1267,14 +1237,32 @@ void uip_interrupt(struct uip_driver_s *dev, uint8 flag) found_listen: - /* First allocate a new connection structure */ + /* First allocate a new connection structure and see if there is any + * user application to accept it. + */ - uip_connr = uip_tcplistener(BUF); + uip_connr = uip_tcpaccept(BUF); + if (uip_connr) + { + /* The connection structure was successfully allocated. Now see + * there is an application waiting to accept the connection (or at + * least queue it it for acceptance). + */ + if (uip_accept(uip_connr, tmp16) != OK) + { + /* No, then we have to give the connection back */ + + uip_tcpfree(uip_connr); + uip_connr = NULL; + } + } + if (!uip_connr) { - /* All connections are used already, we drop packet and hope that + /* Either (1) all available connections are in use, or (2) there is no + * application in place to accept the connection. We drop packet and hope that * the remote end will retransmit the packet at a time when we - * have more spare connections. + * have more spare connections or someone waiting to accept the connection. */ UIP_STAT(++uip_stat.tcp.syndrop); |