From e71c09ce9777ff732cb60bd07fb43d85522f79d6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 25 Jan 2015 15:46:05 -0600 Subject: Networking: Move TCP specific logic out of net/socket/accept.c to net/tcp/tcp_accept.c; add hooks for local, Unix doamin sockets --- nuttx/net/local/local.h | 26 ++++ nuttx/net/socket/accept.c | 304 ++++++++-------------------------------------- nuttx/net/tcp/Make.defs | 2 + nuttx/net/tcp/tcp.h | 43 ++++--- 4 files changed, 106 insertions(+), 269 deletions(-) diff --git a/nuttx/net/local/local.h b/nuttx/net/local/local.h index 674739562..9324d6df6 100644 --- a/nuttx/net/local/local.h +++ b/nuttx/net/local/local.h @@ -256,6 +256,32 @@ int local_listen(FAR struct local_conn_s *server, int backlog); int local_release(FAR struct local_conn_s *conn); +/**************************************************************************** + * Function: psock_local_accept + * + * Description: + * This function implements accept() for Unix domain sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening Unix domain socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted Unix domain connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is NOT locked. + * + ****************************************************************************/ + +int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + /**************************************************************************** * Name: psock_local_send * diff --git a/nuttx/net/socket/accept.c b/nuttx/net/socket/accept.c index 1a4dbd04c..3d42160d6 100644 --- a/nuttx/net/socket/accept.c +++ b/nuttx/net/socket/accept.c @@ -43,160 +43,18 @@ #include #include -#include -#include #include #include #include -#include - -#include -#include - #include "tcp/tcp.h" +#include "local/local.h" #include "socket/socket.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct accept_s -{ - FAR struct socket *acpt_sock; /* The accepting socket */ - sem_t acpt_sem; /* Wait for interrupt event */ - FAR struct sockaddr *acpt_addr; /* Return connection address */ - FAR struct tcp_conn_s *acpt_newconn; /* The accepted connection */ - int acpt_result; /* The result of the wait */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Function: accept_tcpsender - * - * Description: - * Get the sender's address from the UDP packet - * - * Parameters: - * psock - The state structure of the accepting socket - * conn - The newly accepted TCP connection - * pstate - the recvfrom state structure - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level -* - ****************************************************************************/ - -#ifdef CONFIG_NET_TCP -static inline void accept_tcpsender(FAR struct socket *psock, - FAR struct tcp_conn_s *conn, - FAR struct sockaddr *addr) -{ - if (addr) - { -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - /* If both IPv4 and IPv6 support are enabled, then we will need to - * select which one to use when obtaining the sender's IP address. - */ - - if (psock->s_domain == PF_INET) -#endif /* CONFIG_NET_IPv6 */ - { - FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; - - inaddr->sin_family = AF_INET; - inaddr->sin_port = conn->rport; - net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - /* Otherwise, this the IPv6 address is needed */ - - else -#endif /* CONFIG_NET_IPv4 */ - { - FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; - - DEBUGASSERT(psock->s_domain == PF_INET6); - inaddr->sin6_family = AF_INET6; - inaddr->sin6_port = conn->rport; - net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); - } -#endif /* CONFIG_NET_IPv6 */ - } -} -#endif /* CONFIG_NET_TCP */ - -/**************************************************************************** - * Function: accept_interrupt - * - * Description: - * Receive interrupt level callbacks when connections occur - * - * Parameters: - * listener The conection stucture of the listener - * conn The connection stucture that was just accepted - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -static int accept_interrupt(FAR struct tcp_conn_s *listener, - FAR struct tcp_conn_s *conn) -{ - struct accept_s *pstate = (struct accept_s *)listener->accept_private; - int ret = -EINVAL; - - if (pstate) - { - /* Get the connection address */ - - accept_tcpsender(pstate->acpt_sock, conn, pstate->acpt_addr); - - /* Save the connection structure */ - - pstate->acpt_newconn = conn; - pstate->acpt_result = OK; - - /* There should be a reference of one on the new connection */ - - DEBUGASSERT(conn->crefs == 1); - - /* Wake-up the waiting caller thread */ - - sem_post(&pstate->acpt_sem); - - /* Stop any further callbacks */ - - listener->accept_private = NULL; - listener->accept = NULL; - ret = OK; - } - - return ret; -} - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -229,7 +87,7 @@ static int accept_interrupt(FAR struct tcp_conn_s *listener, * connections are present on the queue, accept returns EAGAIN. * * Parameters: - * sockfd The listening socket descriptior + * sockfd The listening socket descriptor * addr Receives the address of the connecting client * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' * @@ -275,8 +133,6 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { FAR struct socket *psock = sockfd_socket(sockfd); FAR struct socket *pnewsock; - FAR struct tcp_conn_s *conn; - struct accept_s state; net_lock_t save; int newfd; int err; @@ -327,6 +183,12 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) if (addr) { + /* If an address is provided, then the lenght must also be provided. */ + + DEBUGASSERT(addrlen); + + /* A valid length depends on the address domain */ + switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 @@ -353,6 +215,18 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) break; #endif /* CONFIG_NET_IPv6 */ +#ifdef CONFIG_NET_LOCAL + case PF_LOCAL: + { + if (*addrlen < sizeof(sa_family_t)) + { + err = EBADF; + goto errout; + } + } + break; +#endif /* CONFIG_NET_IPv6 */ + default: DEBUGPANIC(); err = EINVAL; @@ -378,132 +252,54 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) goto errout_with_socket; } - /* Check the backlog to see if there is a connection already pending for - * this listener. - */ + /* Initialize the socket structure and mark the socket as connected. */ - save = net_lock(); - conn = (struct tcp_conn_s *)psock->s_conn; - -#ifdef CONFIG_NET_TCPBACKLOG - state.acpt_newconn = tcp_backlogremove(conn); - if (state.acpt_newconn) - { - /* Yes... get the address of the connected client */ - - nvdbg("Pending conn=%p\n", state.acpt_newconn); - accept_tcpsender(psock, state.acpt_newconn, addr); - } + pnewsock->s_domain = psock->s_domain; + pnewsock->s_type = SOCK_STREAM; + pnewsock->s_flags |= _SF_CONNECTED; + pnewsock->s_flags &= ~_SF_CLOSED; - /* In general, this uIP-based implementation will not support non-blocking - * socket operations... except in a few cases: Here for TCP accept with backlog - * enabled. If this socket is configured as non-blocking then return EAGAIN - * if there is no pending connection in the backlog. - */ + /* Perform the correct accept operation for this address domain */ - else if (_SS_ISNONBLOCK(psock->s_flags)) - { - err = EAGAIN; - goto errout_with_lock; - } - else +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) #endif { - /* 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. - */ - - state.acpt_sock = psock; - state.acpt_addr = addr; - state.acpt_newconn = NULL; - state.acpt_result = OK; - sem_init(&state.acpt_sem, 0, 0); - - /* Set up the callback in the connection */ - - conn->accept_private = (void*)&state; - conn->accept = accept_interrupt; - - /* Wait for the send to complete or an error to occur: NOTES: (1) - * net_lockedwait will also terminate if a signal is received, (2) - * interrupts may be disabled! They will be re-enabled while the - * task sleeps and automatically re-enabled when the task restarts. - */ - - ret = net_lockedwait(&state.acpt_sem); + ret = psock_local_accept(psock, addr, addrlen, &pnewsock->s_conn); if (ret < 0) { - /* The value returned by net_lockedwait() the same as the value - * returned by sem_wait(): Zero (OK) is returned on success; -1 - * (ERROR) is returned on a failure with the errno value set - * appropriately. - * - * We have to preserve the errno value here because it may be - * altered by intervening operations. - */ - - err = get_errno(); + err = -ret; + goto errout_with_socket; } + } +#endif /* CONFIG_NET_LOCAL */ - /* Make sure that no further interrupts are processed */ - - conn->accept_private = NULL; - conn->accept = NULL; - - sem_destroy(&state. acpt_sem); - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); - - /* Check for a errors. Errors are signalled by negative errno values - * for the send length. - */ - - if (state.acpt_result != 0) +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + save = net_lock(); + ret = psock_tcp_accept(psock, addr, addrlen, &pnewsock->s_conn); + if (ret < 0) { - err = state.acpt_result; - goto errout_with_lock; + net_unlock(save); + err = -ret; + goto errout_with_socket; } - /* If net_lockedwait failed, then we were probably reawakened by a - * signal. In this case, logic above will have set 'err' to the - * ernno value returned by net_lockedwait(). + /* Begin monitoring for TCP connection events on the newly connected + * socket */ - if (ret < 0) - { - goto errout_with_lock; - } + net_startmonitor(pnewsock); + net_unlock(save); } +#endif /* CONFIG_NET_TCP */ - /* Initialize the socket structure and mark the socket as connected. - * (The reference count on the new connection structure was set in the - * interrupt handler). - */ - - pnewsock->s_domain = psock->s_domain; - pnewsock->s_type = SOCK_STREAM; - pnewsock->s_conn = state.acpt_newconn; - pnewsock->s_flags |= _SF_CONNECTED; - pnewsock->s_flags &= ~_SF_CLOSED; - - /* Begin monitoring for TCP connection events on the newly connected socket */ - - net_startmonitor(pnewsock); - net_unlock(save); return newfd; -errout_with_lock: - net_unlock(save); - errout_with_socket: sockfd_release(newfd); diff --git a/nuttx/net/tcp/Make.defs b/nuttx/net/tcp/Make.defs index d213960b7..41a03469e 100644 --- a/nuttx/net/tcp/Make.defs +++ b/nuttx/net/tcp/Make.defs @@ -39,6 +39,8 @@ ifeq ($(CONFIG_NET_TCP),y) # Socket layer +SOCK_CSRCS += tcp_accept.c + ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y) SOCK_CSRCS += tcp_send_buffered.c else diff --git a/nuttx/net/tcp/tcp.h b/nuttx/net/tcp/tcp.h index 1d6e78e8c..010b00989 100644 --- a/nuttx/net/tcp/tcp.h +++ b/nuttx/net/tcp/tcp.h @@ -267,9 +267,8 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -/* Defined in tcp_conn.c ****************************************************/ - -struct sockaddr; /* Forward reference */ +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ /**************************************************************************** * Name: tcp_initialize @@ -389,7 +388,6 @@ int tcp_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); -/* Defined in tcp_ipselect.c ************************************************/ /**************************************************************************** * Function: tcp_ipv4_select * @@ -414,7 +412,6 @@ void tcp_ipv4_select(FAR struct net_driver_s *dev); void tcp_ipv6_select(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_seqno.c ***************************************************/ /**************************************************************************** * Name: tcp_setsequence * @@ -481,7 +478,6 @@ void tcp_initsequence(FAR uint8_t *seqno); void tcp_nextsequence(void); -/* Defined in tcp_poll.c ****************************************************/ /**************************************************************************** * Name: tcp_poll * @@ -502,7 +498,6 @@ void tcp_nextsequence(void); void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); -/* Defined in tcp_timer.c ***************************************************/ /**************************************************************************** * Name: tcp_timer * @@ -525,7 +520,6 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, int hsec); -/* Defined in tcp_listen.c **************************************************/ /**************************************************************************** * Function: tcp_listen_initialize * @@ -593,7 +587,6 @@ bool tcp_islistener(uint16_t portno); int tcp_accept_connection(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t portno); -/* Defined in tcp_send.c ****************************************************/ /**************************************************************************** * Name: tcp_send * @@ -658,7 +651,6 @@ void tcp_reset(FAR struct net_driver_s *dev); void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint8_t ack); -/* Defined in tcp_appsend.c *************************************************/ /**************************************************************************** * Name: tcp_appsend * @@ -705,7 +697,6 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t result); -/* Defined in tcp_input.c ***************************************************/ /**************************************************************************** * Name: tcp_ipv4_input * @@ -748,7 +739,6 @@ void tcp_ipv4_input(FAR struct net_driver_s *dev); void tcp_ipv6_input(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_callback.c ************************************************/ /**************************************************************************** * Function: tcp_callback * @@ -794,7 +784,6 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer, uint16_t nbytes); #endif -/* Defined in tcp_backlog.c *************************************************/ /**************************************************************************** * Function: tcp_backlogcreate * @@ -910,7 +899,32 @@ int tcp_backlogdelete(FAR struct tcp_conn_s *conn, # define tcp_backlogdelete(c,b) (-ENOSYS) #endif -/* Defined in tcp_send_buffered.c or tcp_send_unbuffered.c ******************/ +/**************************************************************************** + * Function: tcp_accept + * + * Description: + * This function implements accept() for TCP/IP sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening TCP socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted TCP connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is locked. + * + ****************************************************************************/ + +int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + /**************************************************************************** * Function: psock_tcp_send * @@ -972,7 +986,6 @@ struct socket; ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len); -/* Defined in tcp_wrbuffer.c ************************************************/ /**************************************************************************** * Function: tcp_wrbuffer_initialize * -- cgit v1.2.3