diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 06ab771080..8553e1e92b 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -105,8 +105,11 @@ struct sock_intf_s CODE int (*si_setup)(FAR struct socket *psock, int protocol); CODE int (*si_bind)(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); + CODE int (*si_listen)(FAR struct socket *psock, int backlog); CODE int (*si_connect)(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); + CODE int (*si_accept)(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); CODE ssize_t (*si_send)(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); CODE ssize_t (*si_sendto)(FAR struct socket *psock, FAR const void *buf, diff --git a/net/local/local.h b/net/local/local.h index 2233b2c8df..983e17950a 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -309,26 +309,31 @@ int local_release(FAR struct local_conn_s *conn); * Name: local_listen * * Description: - * Listen for a new connection of a SOCK_STREAM Unix domain socket. + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of local + * Unix sockets, psock_listen() calls this function. The psock_listen() + * call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. * - * This function is called as part of the implementation of listen(); - * - * Input Parameters: - * server - A reference to the server-side local connection structure - * backlog - Maximum number of pending connections. + * Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. * * Returned Value: - * Zero (OK) on success; a negated errno value on failure. - * - * Assumptions: - * The network is NOT locked + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. * ****************************************************************************/ -int local_listen(FAR struct local_conn_s *server, int backlog); +int local_listen(FAR struct socket *psock, int backlog); /**************************************************************************** - * Name: psock_local_accept + * Name: local_accept * * Description: * This function implements accept() for Unix domain sockets. See the @@ -350,8 +355,8 @@ int local_listen(FAR struct local_conn_s *server, int backlog); * ****************************************************************************/ -int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, - FAR socklen_t *addrlen, FAR void **newconn); +int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); /**************************************************************************** * Name: psock_local_send diff --git a/net/local/local_accept.c b/net/local/local_accept.c index 2ead57d103..e1aa8132b4 100644 --- a/net/local/local_accept.c +++ b/net/local/local_accept.c @@ -88,7 +88,7 @@ static int local_waitlisten(FAR struct local_conn_s *server) ****************************************************************************/ /**************************************************************************** - * Name: psock_local_accept + * Name: local_accept * * Description: * This function implements accept() for Unix domain sockets. See the @@ -110,8 +110,8 @@ static int local_waitlisten(FAR struct local_conn_s *server) * ****************************************************************************/ -int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, - FAR socklen_t *addrlen, FAR void **newconn) +int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn) { FAR struct local_conn_s *server; @@ -122,6 +122,18 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, /* Some sanity checks */ DEBUGASSERT(psock && psock->s_conn); + + /* Is the socket a stream? */ + + if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM) + { + return -EOPNOTSUPP; + } + + /* Verify that a valid memory block has been provided to receive the + * address + */ + server = (FAR struct local_conn_s *)psock->s_conn; if (server->lc_proto != SOCK_STREAM || @@ -213,7 +225,7 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, /* Return the address family */ - if (addr) + if (addr != NULL) { ret = local_getaddr(client, addr, addrlen); } diff --git a/net/local/local_listen.c b/net/local/local_listen.c index a1020570e7..996bb049fe 100644 --- a/net/local/local_listen.c +++ b/net/local/local_listen.c @@ -66,29 +66,46 @@ dq_queue_t g_local_listeners; * Name: local_listen * * Description: - * Listen for a new connection of a SOCK_STREAM Unix domain socket. + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of local + * Unix sockets, psock_listen() calls this function. The psock_listen() + * call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. * - * This function is called as part of the implementation of listen(); - * - * Input Parameters: - * server - A reference to the server-side local connection structure - * backlog - Maximum number of pending connections. + * Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. * * Returned Value: - * Zero (OK) on success; a negated errno value on failure. - * - * Assumptions: - * The network is NOT locked + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. * ****************************************************************************/ -int local_listen(FAR struct local_conn_s *server, int backlog) +int local_listen(FAR struct socket *psock, int backlog) { + FAR struct local_conn_s *server; + + /* Verify that the sockfd corresponds to a connected SOCK_STREAM in this + * address family. + */ + + if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM) + { + nerr("ERROR: Unsupported socket family=%d or socket type=%d\n", + psocl->s_domain, psock->s_type); + return -EOPNOTSUPP; + } + + server = (FAR struct local_conn_s *)psock->s_conn; /* Some sanity checks */ - DEBUGASSERT(server); - if (server->lc_proto != SOCK_STREAM || server->lc_state == LOCAL_STATE_UNBOUND || server->lc_type != LOCAL_TYPE_PATHNAME) diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c index 73113cccc2..68f93e7df0 100644 --- a/net/local/local_sockif.c +++ b/net/local/local_sockif.c @@ -59,9 +59,11 @@ static int local_setup(FAR struct socket *psock, int protocol); static int local_bind(FAR struct socket *psock, - FAR const struct sockaddr *addr, socklen_t addrlen); + FAR const struct sockaddr *addr, socklen_t addrlen); static int local_connect(FAR struct socket *psock, - FAR const struct sockaddr *addr, socklen_t addrlen); + FAR const struct sockaddr *addr, socklen_t addrlen); +static int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); static ssize_t local_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); static ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf, @@ -76,7 +78,9 @@ const struct sock_intf_s g_local_sockif = { local_setup, /* si_setup */ local_bind, /* si_bind */ + local_listen, /* si_listen */ local_connect, /* si_connect */ + local_accept, /* si_accept */ local_send, /* si_send */ local_sendto, /* si_sendto */ local_recvfrom /* si_recvfrom */ @@ -445,7 +449,7 @@ ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf, ****************************************************************************/ /**************************************************************************** - * Name: + * Name: * * Description: * diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 72e7751f8b..c110b578f6 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -58,8 +58,11 @@ static int pkt_setup(FAR struct socket *psock, int protocol); static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +static int pkt_listen(FAR struct socket *psock, int backlog); static int pkt_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); static ssize_t pkt_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf, @@ -74,7 +77,9 @@ const struct sock_intf_s g_pkt_sockif = { pkt_setup, /* si_setup */ pkt_bind, /* si_bind */ + pkt_listen, /* si_listen */ pkt_connect, /* si_connect */ + pkt_accept, /* si_accept */ pkt_send, /* si_send */ pkt_sendto, /* si_sendto */ pkt_recvfrom /* si_recvfrom */ @@ -195,6 +200,52 @@ static int pkt_connect(FAR struct socket *psock, return -EAFNOSUPPORT; } +/**************************************************************************** + * Name: pkt_accept + * + * Description: + * The pkt_accept function is used with connection-based socket types + * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an pkt_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, pkt_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, pkt_accept returns + * EAGAIN. + * + * Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a desrciption of the approriate error value. + * + ****************************************************************************/ + +static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) +{ + return -EAFNOSUPPORT; +} + /**************************************************************************** * Name: pkt_bind * @@ -271,6 +322,36 @@ static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, } } +/**************************************************************************** + * Name: pkt_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of raw + * packet sockets, psock_listen() calls this function. The psock_listen() + * call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. + * + * Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +int pkt_listen(FAR struct socket *psock, int backlog) +{ + return -EOPNOTSUPP; +} + /**************************************************************************** * Name: pkt_send * @@ -349,7 +430,7 @@ static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf, ****************************************************************************/ /**************************************************************************** - * Name: + * Name: * * Description: * diff --git a/net/socket/accept.c b/net/socket/accept.c index b295542c28..093b16e438 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -115,8 +115,7 @@ * ENFILE * The system maximum for file descriptors has been reached. * EFAULT - * The addr parameter is not in a writable part of the user address - * space. + * The addr parameter is not in a writable part of the user address space. * ENOBUFS or ENOMEM * Not enough free memory. * EPROTO @@ -134,25 +133,18 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, int ret; #endif - DEBUGASSERT(psock != NULL); + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && newsock != NULL); /* Treat as a cancellation point */ (void)enter_cancellation_point(); - /* Is the socket a stream? */ + /* May sure that the socket has been opened with socket() */ - if (psock->s_type != SOCK_STREAM) + if (psock == NULL || psock->s_conn == NULL) { -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { -#warning "Missing logic" - } -#endif - - errcode = EOPNOTSUPP; - goto errout; + nerr("ERROR: Socket invalid or not opened\n"); + return -EINVAL; } /* Is the socket listening for a connection? */ @@ -163,128 +155,16 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, goto errout; } - /* Verify that a valid memory block has been provided to receive the - * address - */ + /* Let the address family's accept() method handle the operation */ - if (addr) + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_accept != NULL); + ret = psock->s_sockif->si_accept(psock, addr, addrlen, newsock); + if (ret < 0) { - /* If an address is provided, then the length must also be provided. */ - - DEBUGASSERT(addrlen); - - /* A valid length depends on the address domain */ - - switch (psock->s_domain) - { -#ifdef CONFIG_NET_IPv4 - case PF_INET: - { - if (*addrlen < sizeof(struct sockaddr_in)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 - case PF_INET6: - { - if (*addrlen < sizeof(struct sockaddr_in6)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif /* CONFIG_NET_IPv6 */ - -#ifdef CONFIG_NET_LOCAL_STREAM - case PF_LOCAL: - { - if (*addrlen < sizeof(sa_family_t)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif /* CONFIG_NET_IPv6 */ - - default: - DEBUGPANIC(); - errcode = EINVAL; - goto errout; - } - } - - /* Initialize the socket structure. */ - - newsock->s_domain = psock->s_domain; - newsock->s_type = SOCK_STREAM; - newsock->s_sockif = psock->s_sockif; - - /* Perform the correct accept operation for this address domain */ - -#ifdef CONFIG_NET_LOCAL_STREAM -#ifdef CONFIG_NET_TCP - if (psock->s_domain == PF_LOCAL) -#endif - { - /* Perform the local accept operation (with the network unlocked) */ - - ret = psock_local_accept(psock, addr, addrlen, &newsock->s_conn); - if (ret < 0) - { - errcode = -ret; - goto errout; - } - } -#endif /* CONFIG_NET_LOCAL_STREAM */ - -#ifdef CONFIG_NET_TCP -#ifdef CONFIG_NET_LOCAL_STREAM - else -#endif - { -#ifdef NET_TCP_HAVE_STACK - /* Perform the local accept operation (with the network locked) */ - - net_lock(); - ret = psock_tcp_accept(psock, addr, addrlen, &newsock->s_conn); - if (ret < 0) - { - net_unlock(); - errcode = -ret; - goto errout; - } - - /* Begin monitoring for TCP connection events on the newly connected - * socket - */ - - ret = net_startmonitor(newsock); - if (ret < 0) - { - /* net_startmonitor() can only fail on certain race conditions - * where the connection was lost just before this function was - * called. Undo everything we have done and return a failure. - */ - - net_unlock(); - errcode = -ret; - goto errout_after_accept; - } - - net_unlock(); -#else - errcode = EOPNOTSUPP; + nerr("ERROR: si_accept failed: %d\n", ret); + errcode = -ret; goto errout; -#endif /* NET_TCP_HAVE_STACK */ } -#endif /* CONFIG_NET_TCP */ /* Mark the new socket as connected. */ @@ -294,11 +174,6 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, leave_cancellation_point(); return OK; -#ifdef NET_TCP_HAVE_STACK -errout_after_accept: - psock_close(newsock); -#endif - errout: set_errno(errcode); leave_cancellation_point(); diff --git a/net/socket/bind.c b/net/socket/bind.c index cf4c025f46..8d7270aee1 100644 --- a/net/socket/bind.c +++ b/net/socket/bind.c @@ -95,7 +95,6 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, #ifdef CONFIG_NET_PKT FAR const struct sockaddr_ll *lladdr = (const struct sockaddr_ll *)addr; #endif - socklen_t minlen; int errcode; int ret = OK; diff --git a/net/socket/inet_sockif.c b/net/socket/inet_sockif.c index 4574f2a1e4..470315c229 100644 --- a/net/socket/inet_sockif.c +++ b/net/socket/inet_sockif.c @@ -61,6 +61,9 @@ static int inet_setup(FAR struct socket *psock, int protocol); static int inet_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +static int inet_listen(FAR struct socket *psock, int backlog); +static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, @@ -75,7 +78,9 @@ const struct sock_intf_s g_inet_sockif = { inet_setup, /* si_setup */ inet_bind, /* si_bind */ + inet_listen, /* si_listen */ inet_connect, /* si_connect */ + inet_accept, /* si_accept */ inet_send, /* si_send */ inet_sendto, /* si_sendto */ inet_recvfrom /* si_recvfrom */ @@ -435,6 +440,255 @@ static int inet_bind(FAR struct socket *psock, return ret; } +/**************************************************************************** + * Name: inet_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of AFINET + * and AFINET6 sockets, psock_listen() calls this function. The + * psock_listen() call applies only to sockets of type SOCK_STREAM or + * SOCK_SEQPACKET. + * + * Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +int inet_listen(FAR struct socket *psock, int backlog) +{ +#if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) + FAR struct tcp_conn_s *conn; + int ret; +#endif + + /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ + + if (psock->s_type != SOCK_STREAM) + { +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { +#warning "Missing logic" + } +#endif + + nerr("ERROR: Unsupported socket type: %d\n", + psock->s_type); + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK + conn = (FAR struct tcp_conn_s *)psock->s_conn; + + if (conn->lport <= 0) + { + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NET_TCPBACKLOG + /* Set up the backlog for this connection */ + + ret = tcp_backlogcreate(conn, backlog); + if (ret < 0) + { + nerr("ERROR: tcp_backlogcreate failed: %d\n", ret); + return ret; + } +#endif + + /* Start listening to the bound port. This enables callbacks when + * accept() is called and enables poll()/select() logic. + */ + + ret = tcp_listen(conn); + if (ret < 0) + { + nerr("ERROR: tcp_listen failed: %d\n", ret); + } + + return ret; +#else + nwarn("WARNING: Stream socket support not available\n"); + return -EOPNOTSUPP; +#endif /* NET_TCP_HAVE_STACK */ +#else + nwarn("WARNING: Stream socket support not enabled\n"); + return -EOPNOTSUPP; +#endif /* CONFIG_NET_TCP */ +} + +/**************************************************************************** + * Name: inet_accept + * + * Description: + * The inet_accept function is used with connection-based socket types + * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an inet_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, inet_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, inet_accept returns + * EAGAIN. + * + * Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a desrciption of the approriate error value. + * + ****************************************************************************/ + +static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) +{ +#if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) + int ret; +#endif + + /* Is the socket a stream? */ + + if (psock->s_type != SOCK_STREAM) + { +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { +#warning "Missing logic" + } +#endif + + nerr("ERROR: Inappropreat socket type: %d\n", psock->s_type); + return -EOPNOTSUPP; + } + + /* Verify that a valid memory block has been provided to receive the + * address + */ + + if (addr != NULL) + { + /* If an address is provided, then the length must also be provided. */ + + DEBUGASSERT(addrlen > 0); + + /* A valid length depends on the address domain */ + + switch (psock->s_domain) + { +#ifdef CONFIG_NET_IPv4 + case PF_INET: + { + if (*addrlen < sizeof(struct sockaddr_in)) + { + return -EBADF; + } + } + break; +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 + case PF_INET6: + { + if (*addrlen < sizeof(struct sockaddr_in6)) + { + return -EBADF; + } + } + break; +#endif /* CONFIG_NET_IPv6 */ + + default: + DEBUGPANIC(); + return -EINVAL; + } + } + + /* Initialize the socket structure. */ + + newsock->s_domain = psock->s_domain; + newsock->s_type = SOCK_STREAM; + newsock->s_sockif = psock->s_sockif; + + /* Perform the correct accept operation for this address domain */ + +#ifdef CONFIG_NET_TCP +#ifdef NET_TCP_HAVE_STACK + /* Perform the local accept operation (with the network locked) */ + + net_lock(); + ret = psock_tcp_accept(psock, addr, addrlen, &newsock->s_conn); + if (ret < 0) + { + nerr("ERROR: psock_tcp_accept failed: %d\n", ret); + goto errout_with_lock; + } + + /* Begin monitoring for TCP connection events on the newly connected + * socket + */ + + ret = net_startmonitor(newsock); + if (ret < 0) + { + /* net_startmonitor() can only fail on certain race conditions where + * the connection was lost just before this function was called. Undo + * everything we have done and return a failure. + */ + + goto errout_after_accept; + } + + net_unlock(); + return OK; + +errout_after_accept: + psock_close(newsock); + +errout_with_lock: + net_unlock(); + return ret; + +#else + nwarn("WARNING: SOCK_STREAM not supported in this configuration\n"); + return -EOPNOTSUPP; +#endif /* NET_TCP_HAVE_STACK */ +#else + nwarn("WARNING: TCP/IP not supported in this configuration\n"); + return -EOPNOTSUPP; +#endif /* CONFIG_NET_TCP */ +} + /**************************************************************************** * Name: inet_send * diff --git a/net/socket/listen.c b/net/socket/listen.c index 26a9501807..fd4a410c94 100644 --- a/net/socket/listen.c +++ b/net/socket/listen.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/listen.c * - * Copyright (C) 2007-2009, 201-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 201-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -38,17 +38,15 @@ ****************************************************************************/ #include -#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 #include -#include #include +#include #include -#include "tcp/tcp.h" -#include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" + +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 /**************************************************************************** * Public Functions @@ -86,83 +84,29 @@ int psock_listen(FAR struct socket *psock, int backlog) { int errcode; + int ret; DEBUGASSERT(psock != NULL); /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ - if (psock->s_type != SOCK_STREAM || !psock->s_conn) + if (psock == NULL || psock->s_conn == NULL) { -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { -#warning "Missing logic" - } -#endif - - errcode = EOPNOTSUPP; + nerr("ERROR: Invalid or unconnected socket\n"); + errcode = EINVAL; goto errout; } -#ifdef CONFIG_NET_LOCAL -#ifdef CONFIG_NET_TCP - if (psock->s_domain == PF_LOCAL) -#endif + /* Let the address family's listen() method handle the operation */ + + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_listen != NULL); + ret = psock->s_sockif->si_listen(psock, backlog); + if (ret < 0) { - FAR struct local_conn_s *conn = - (FAR struct local_conn_s *)psock->s_conn; - - errcode = local_listen(conn, backlog); - if (errcode < 0) - { - errcode = -errcode; - goto errout; - } - } -#endif /* CONFIG_NET_LOCAL */ - -#ifdef CONFIG_NET_TCP -#ifdef CONFIG_NET_LOCAL - else -#endif - { -#ifdef NET_TCP_HAVE_STACK - FAR struct tcp_conn_s *conn = - (FAR struct tcp_conn_s *)psock->s_conn; - - if (conn->lport <= 0) - { - errcode = EOPNOTSUPP; - goto errout; - } - - /* Set up the backlog for this connection */ - -#ifdef CONFIG_NET_TCPBACKLOG - errcode = tcp_backlogcreate(conn, backlog); - if (errcode < 0) - { - errcode = -errcode; - goto errout; - } -#endif - - /* Start listening to the bound port. This enables callbacks when - * accept() is called and enables poll()/select() logic. - */ - - errcode = tcp_listen(conn); - if (errcode < 0) - { - errcode = -errcode; - goto errout; - } -#else - errcode = EOPNOTSUPP; + nerr("ERROR: si_listen failed: %d\n", ret); + errcode = -ret; goto errout; -#endif /* NET_TCP_HAVE_STACK */ } -#endif /* CONFIG_NET_TCP */ psock->s_flags |= _SF_LISTENING; return OK;