From 85b1ae4cf00355ec05e85fab51f124221b8d2194 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 13 Jul 2017 09:27:56 -0600 Subject: [PATCH] Socket interface: Added bind() and connect() interfaces. --- include/nuttx/net/net.h | 4 + net/local/local_sockif.c | 156 +++++++++- net/pkt/pkt_sockif.c | 122 +++++++- net/socket/Make.defs | 4 +- net/socket/bind.c | 233 +-------------- net/socket/connect.c | 561 +----------------------------------- net/socket/inet_connect.c | 567 +++++++++++++++++++++++++++++++++++++ net/socket/inet_recvfrom.c | 10 + net/socket/inet_sockif.c | 320 ++++++++++++++++++--- net/socket/net_clone.c | 2 - net/socket/recvfrom.c | 32 +-- net/socket/send.c | 18 +- net/socket/sendto.c | 30 +- net/socket/socket.c | 87 ------ net/socket/socket.h | 35 +++ 15 files changed, 1203 insertions(+), 978 deletions(-) create mode 100644 net/socket/inet_connect.c diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 6d343cfd5f..06ab771080 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -103,6 +103,10 @@ struct socket; /* Forward reference */ 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_connect)(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); 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_sockif.c b/net/local/local_sockif.c index 0baeab57e2..73113cccc2 100644 --- a/net/local/local_sockif.c +++ b/net/local/local_sockif.c @@ -57,7 +57,11 @@ * Private Function Prototypes ****************************************************************************/ -static ssize_t local_setup(FAR struct socket *psock, int protocol); +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); +static int local_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); 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, @@ -71,6 +75,8 @@ static ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf, const struct sock_intf_s g_local_sockif = { local_setup, /* si_setup */ + local_bind, /* si_bind */ + local_connect, /* si_connect */ local_send, /* si_send */ local_sendto, /* si_sendto */ local_recvfrom /* si_recvfrom */ @@ -171,6 +177,154 @@ static int local_setup(FAR struct socket *psock, int protocol) } } +/**************************************************************************** + * Name: local_bind + * + * Description: + * local_bind() gives the socket 'psock' the local address 'addr'. 'addr' + * is 'addrlen' bytes long. Traditionally, this is called "assigning a + * name to a socket." When a socket is created with socket(), it exists + * in a name space (address family) but has no name assigned. + * + * Parameters: + * psock Socket structure of the socket to bind + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; A negated errno value is returned on failure. See + * bind() for a list a appropriate error values. + * + ****************************************************************************/ + +static int local_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + int ret; + + /* Verify that a valid address has been provided */ + + if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t)) + { + nerr("ERROR: Invalid address length: %d < %d\n", + addrlen, sizeof(sa_family_t)); + return -EBADF; + } + + /* Perform the binding depending on the protocol type */ + + switch (psock->s_type) + { + /* Bind a local TCP/IP stream or datagram socket */ + +#if defined(ONFIG_NET_TCP) || defined(CONFIG_NET_UDP) +#ifdef CONFIG_NET_TCP + case SOCK_STREAM: +#endif +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: +#endif + { + /* Bind the Unix domain connection structure */ + + ret psock_local_bind(psock, addr, addrlen); + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } + } + break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/ + + default: + ret = -EBADF; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: local_connect + * + * Description: + * local_connect() connects the local socket referred to by the structure + * 'psock' to the address specified by 'addr'. The addrlen argument + * specifies the size of 'addr'. The format of the address in 'addr' is + * determined by the address space of the socket 'psock'. + * + * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address + * to which datagrams are sent by default, and the only address from which + * datagrams are received. If the socket is of type SOCK_STREAM or + * SOCK_SEQPACKET, this call attempts to make a connection to the socket + * that is bound to the address specified by 'addr'. + * + * Generally, connection-based protocol sockets may successfully + * local_connect() only once; connectionless protocol sockets may use + * local_connect() multiple times to change their association. + * Connectionless sockets may dissolve the association by connecting to + * an address with the sa_family member of sockaddr set to AF_UNSPEC. + * + * Parameters: + * psock Pointer to a socket structure initialized by psock_socket() + * addr Server address (form depends on type of socket) + * addrlen Length of actual 'addr' + * + * Returned Value: + * 0 on success; a negated errno value on failue. See connect() for the + * list of appropriate errno values to be returned. + * + ****************************************************************************/ + +static int local_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + /* Verify that a valid address has been provided */ + + if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t)) + { + return -EBADF; + } + + /* Perform the connection depending on the protocol type */ + + switch (psock->s_type) + { +#ifdef CONFIG_NET_TCP + case SOCK_STREAM: + { + /* Verify that the socket is not already connected */ + + if (_SS_ISCONNECTED(psock->s_flags)) + { + return -EISCONN; + } + + /* It's not... Connect to the local Unix domain server */ + + return psock_local_connect(psock, addr); + } + break; +#endif /* CONFIG_NET_TCP */ + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + { + /* Perform the datagram connection logic */ + + return psock_local_connect(psock, addr); + } + break; +#endif /* CONFIG_NET_UDP */ + + default: + return -EBADF; + } +} + /**************************************************************************** * Name: local_send * diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 9e3f0f6758..72e7751f8b 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -55,7 +55,11 @@ * Private Function Prototypes ****************************************************************************/ -static ssize_t pkt_setup(FAR struct socket *psock, int protocol); +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_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); 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, @@ -69,6 +73,8 @@ static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf, const struct sock_intf_s g_pkt_sockif = { pkt_setup, /* si_setup */ + pkt_bind, /* si_bind */ + pkt_connect, /* si_connect */ pkt_send, /* si_send */ pkt_sendto, /* si_sendto */ pkt_recvfrom /* si_recvfrom */ @@ -151,6 +157,120 @@ static int pkt_setup(FAR struct socket *psock, int protocol) } } +/**************************************************************************** + * Name: pkt_connect + * + * Description: + * pkt_connect() connects the local socket referred to by the structure + * 'psock' to the address specified by 'addr'. The addrlen argument + * specifies the size of 'addr'. The format of the address in 'addr' is + * determined by the address space of the socket 'psock'. + * + * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address + * to which datagrams are sent by default, and the only address from which + * datagrams are received. If the socket is of type SOCK_STREAM or + * SOCK_SEQPACKET, this call attempts to make a connection to the socket + * that is bound to the address specified by 'addr'. + * + * Generally, connection-based protocol sockets may successfully + * pkt_connect() only once; connectionless protocol sockets may use + * pkt_connect() multiple times to change their association. + * Connectionless sockets may dissolve the association by connecting to + * an address with the sa_family member of sockaddr set to AF_UNSPEC. + * + * Parameters: + * psock Pointer to a socket structure initialized by psock_socket() + * addr Server address (form depends on type of socket) + * addrlen Length of actual 'addr' + * + * Returned Value: + * 0 on success; a negated errno value on failue. See connect() for the + * list of appropriate errno values to be returned. + * + ****************************************************************************/ + +static int pkt_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + return -EAFNOSUPPORT; +} + +/**************************************************************************** + * Name: pkt_bind + * + * Description: + * pkt_bind() gives the socket 'psock' the local address 'addr'. 'addr' + * is 'addrlen' bytes long. Traditionally, this is called "assigning a + * name to a socket." When a socket is created with socket(), it exists + * in a name space (address family) but has no name assigned. + * + * Parameters: + * psock Socket structure of the socket to bind + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; A negated errno value is returned on failure. See + * bind() for a list a appropriate error values. + * + ****************************************************************************/ + +static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, + socklen_t addrlen) +{ +#if 0 + char hwaddr[6] = /* our MAC for debugging */ + { + 0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1 + }; +#endif + char hwaddr[6] = /* MAC from ifconfig */ + { + 0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef + }; + int ifindex; + + /* Verify that a valid address has been provided */ + + if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll) + { + nerr("ERROR: Invalid address length: %d < %d\n", + addrlen, sizeof(struct sockaddr_ll); + return -EBADF; + } + + /* Bind a raw socket to an network device. */ + + if (psock->s_type == SOCK_RAW) + { + FAR struct pkt_conn_s *conn = (FAR struct pkt_conn_s *)psock->s_conn; + + /* Look at the addr and identify network interface */ + + ifindex = addr->sll_ifindex; + +#if 0 + /* Get the MAC address of that interface */ + + memcpy(hwaddr, g_netdevices->d_mac.ether, 6); +#endif + + /* Put ifindex and mac address into connection */ + + conn->ifindex = ifindex; + memcpy(conn->lmac, hwaddr, 6); + + /* Mark the socket bound */ + + psock->s_flags |= _SF_BOUND; + return OK; + } + else + { + return -EBADF; + } +} + /**************************************************************************** * Name: pkt_send * diff --git a/net/socket/Make.defs b/net/socket/Make.defs index 105f70a636..34deabf99e 100644 --- a/net/socket/Make.defs +++ b/net/socket/Make.defs @@ -44,9 +44,9 @@ SOCK_CSRCS += net_dupsd2.c net_clone.c net_poll.c net_vfcntl.c SOCK_CSRCS += net_sockif.c ifeq ($(CONFIG_NET_IPv4),y) -SOCK_CSRCS += inet_sockif.c inet_recvfrom.c +SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c else ifeq ($(CONFIG_NET_IPv6),y) -SOCK_CSRCS += inet_sockif.c inet_recvfrom.c +SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c endif # TCP/IP support diff --git a/net/socket/bind.c b/net/socket/bind.c index a6671ec40d..cf4c025f46 100644 --- a/net/socket/bind.c +++ b/net/socket/bind.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/bind.c * - * Copyright (C) 2007-2009, 2012, 2014-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2014-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -38,85 +38,23 @@ ****************************************************************************/ #include -#ifdef CONFIG_NET #include #include -#include -#include -#include -#include #include - -#ifdef CONFIG_NET_PKT -# include -#endif +#include +#include #include -#include #include "socket/socket.h" -#include "netdev/netdev.h" -#include "tcp/tcp.h" -#include "udp/udp.h" -#include "pkt/pkt.h" -#include "local/local.h" -#include "usrsock/usrsock.h" + +#ifdef CONFIG_NET /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: pkt_bind - * - * Description: - * Bind a raw socket to an network device. - * - * Parameters: - * conn AF_PACKET connection structure - * addr Peer address information - * - * Returned Value: - * 0 on success; -1 on error with errno set appropriately - * - ****************************************************************************/ - -#ifdef CONFIG_NET_PKT -static int pkt_bind(FAR struct pkt_conn_s *conn, - FAR const struct sockaddr_ll *addr) -{ - int ifindex; -#if 0 - char hwaddr[6] = /* our MAC for debugging */ - { - 0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1 - }; -#endif - char hwaddr[6] = /* MAC from ifconfig */ - { - 0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef - }; - - /* Look at the addr and identify network interface */ - - ifindex = addr->sll_ifindex; - -#if 0 - /* Get the MAC address of that interface */ - - memcpy(hwaddr, g_netdevices->d_mac.ether, 6); -#endif - - /* Put ifindex and mac address into connection */ - - conn->ifindex = ifindex; - memcpy(conn->lmac, hwaddr, 6); - - return OK; -} -#endif /* CONFIG_NET_PKT */ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -169,165 +107,10 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, goto errout; } - /* Verify that a valid address has been provided */ + /* Let the address family's connect() method handle the operation */ - switch (addr->sa_family) - { -#ifdef CONFIG_NET_IPv4 - case AF_INET: - minlen = sizeof(struct sockaddr_in); - break; -#endif - -#ifdef CONFIG_NET_IPv6 - case AF_INET6: - minlen = sizeof(struct sockaddr_in6); - break; -#endif - -#ifdef CONFIG_NET_LOCAL - case AF_LOCAL: - minlen = sizeof(sa_family_t); - break; -#endif - -#ifdef CONFIG_NET_PKT - case AF_PACKET: - minlen = sizeof(struct sockaddr_ll); - break; -#endif - - default: - nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family); - errcode = EAFNOSUPPORT; - goto errout; - } - - if (addrlen < minlen) - { - nerr("ERROR: Invalid address length: %d < %d\n", addrlen, minlen); - errcode = EBADF; - goto errout; - } - - /* Perform the binding depending on the protocol type */ - - switch (psock->s_type) - { -#ifdef CONFIG_NET_USRSOCK - case SOCK_USRSOCK_TYPE: - { - FAR struct usrsock_conn_s *conn = psock->s_conn; - - DEBUGASSERT(conn); - - /* Perform the usrsock bind operation */ - - ret = usrsock_bind(conn, addr, addrlen); - } - break; -#endif - -#ifdef CONFIG_NET_PKT - case SOCK_RAW: - ret = pkt_bind(psock->s_conn, lladdr); - break; -#endif - - /* Bind a stream socket which may either be TCP/IP or a local, Unix - * domain socket. - */ - -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) - case SOCK_STREAM: - { -#ifdef CONFIG_NET_LOCAL_STREAM -#ifdef CONFIG_NET_TCP - /* Is this a Unix domain socket? */ - - if (psock->s_domain == PF_LOCAL) -#endif - { - /* Bind the Unix domain connection structure */ - - ret = psock_local_bind(psock, addr, addrlen); - } -#endif /* CONFIG_NET_LOCAL_STREAM */ - -#ifdef CONFIG_NET_TCP -#ifdef CONFIG_NET_LOCAL_STREAM - else -#endif - { -#ifdef NET_TCP_HAVE_STACK - /* Bind the TCP/IP connection structure */ - - ret = tcp_bind(psock->s_conn, addr); -#else - ret = -ENOSYS; -#endif - } -#endif /* CONFIG_NET_TCP */ - - /* Mark the socket bound */ - - if (ret >= 0) - { - psock->s_flags |= _SF_BOUND; - } - } - break; -#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */ - - /* Bind a datagram socket which may either be TCP/IP or a local, Unix - * domain socket. - */ - -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) - case SOCK_DGRAM: - { -#ifdef CONFIG_NET_LOCAL_DGRAM -#ifdef CONFIG_NET_UDP - /* Is this a Unix domain socket? */ - - if (psock->s_domain == PF_LOCAL) -#endif - { - /* Bind the Unix domain connection structure */ - - ret = psock_local_bind(psock, addr, addrlen); - } -#endif /* CONFIG_NET_LOCAL_DGRAM */ - -#ifdef CONFIG_NET_UDP -#ifdef CONFIG_NET_LOCAL_DGRAM - else -#endif - { -#ifdef NET_UDP_HAVE_STACK - /* Bind the UDPP/IP connection structure */ - - ret = udp_bind(psock->s_conn, addr); -#else - ret = -ENOSYS; -#endif - } -#endif /* CONFIG_NET_UDP */ - - /* Mark the socket bound */ - - if (ret >= 0) - { - psock->s_flags |= _SF_BOUND; - } - } - break; -#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */ - - default: - errcode = EBADF; - goto errout; - } + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_bind != NULL); + ret = psock->s_sockif->si_bind(psock, addr, addrlen); /* Was the bind successful */ diff --git a/net/socket/connect.c b/net/socket/connect.c index dd3ee97e09..4a8fbe52e2 100644 --- a/net/socket/connect.c +++ b/net/socket/connect.c @@ -38,7 +38,6 @@ ****************************************************************************/ #include -#ifdef CONFIG_NET #include #include @@ -48,398 +47,17 @@ #include #include -#include - -#include #include #include -#include -#include -#include -#include "devif/devif.h" -#include "tcp/tcp.h" -#include "udp/udp.h" -#include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" -/**************************************************************************** - * Private Types - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -struct tcp_connect_s -{ - FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */ - FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */ - FAR struct socket *tc_psock; /* The socket being connected */ - sem_t tc_sem; /* Semaphore signals recv completion */ - int tc_result; /* OK on success, otherwise a negated errno. */ -}; -#endif - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -static inline int psock_setup_callbacks(FAR struct socket *psock, - FAR struct tcp_connect_s *pstate); -static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, - int status); -static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, - FAR void *pvconn, FAR void *pvpriv, - uint16_t flags); -static inline int psock_tcp_connect(FAR struct socket *psock, - FAR const struct sockaddr *addr); -#endif /* NET_TCP_HAVE_STACK */ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/**************************************************************************** - * Name: psock_setup_callbacks - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -static inline int psock_setup_callbacks(FAR struct socket *psock, - FAR struct tcp_connect_s *pstate) -{ - FAR struct tcp_conn_s *conn = psock->s_conn; - int ret = -EBUSY; - - /* Initialize the TCP state structure */ - - /* This semaphore is used for signaling and, hence, should not have - * priority inheritance enabled. - */ - - (void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */ - (void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE); - - pstate->tc_conn = conn; - pstate->tc_psock = psock; - pstate->tc_result = -EAGAIN; - - /* Set up the callbacks in the connection */ - - pstate->tc_cb = tcp_callback_alloc(conn); - if (pstate->tc_cb) - { - /* Set up the connection "interrupt" handler */ - - pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT | - TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN); - pstate->tc_cb->priv = (FAR void *)pstate; - pstate->tc_cb->event = psock_connect_interrupt; - ret = OK; - } - - return ret; -} -#endif /* NET_TCP_HAVE_STACK */ - -/**************************************************************************** - * Name: psock_teardown_callbacks - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, - int status) -{ - FAR struct tcp_conn_s *conn = pstate->tc_conn; - - /* Make sure that no further interrupts are processed */ - - tcp_callback_free(conn, pstate->tc_cb); - pstate->tc_cb = NULL; - - /* If we successfully connected, we will continue to monitor the connection - * state via callbacks. - */ - - if (status < 0) - { - /* Failed to connect. Stop the connection event monitor */ - - net_stopmonitor(conn); - } -} -#endif /* NET_TCP_HAVE_STACK */ - -/**************************************************************************** - * Name: psock_connect_interrupt - * - * Description: - * This function is called from the interrupt level to perform the actual - * connection operation via by the lower, device interfacing layer. - * - * Parameters: - * dev The structure of the network driver that caused the interrupt - * pvconn The connection structure associated with the socket - * flags Set of events describing why the callback was invoked - * - * Returned Value: - * The new flags setting - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, - FAR void *pvconn, FAR void *pvpriv, - uint16_t flags) -{ - struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv; - - ninfo("flags: %04x\n", flags); - - /* 'priv' might be null in some race conditions (?) */ - - if (pstate) - { - /* The following errors should be detected here (someday) - * - * ECONNREFUSED - * No one listening on the remote address. - * ENETUNREACH - * Network is unreachable. - * ETIMEDOUT - * Timeout while attempting connection. The server may be too busy - * to accept new connections. - */ - - /* TCP_CLOSE: The remote host has closed the connection - * TCP_ABORT: The remote host has aborted the connection - */ - - if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0) - { - /* Indicate that remote host refused the connection */ - - pstate->tc_result = -ECONNREFUSED; - } - - /* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */ - - else if ((flags & TCP_TIMEDOUT) != 0) - { - /* Indicate that the connection timedout?) */ - - pstate->tc_result = -ETIMEDOUT; - } - - else if ((flags & NETDEV_DOWN) != 0) - { - /* The network device went down. Indicate that the remote host - * is unreachable. - */ - - pstate->tc_result = -ENETUNREACH; - } - - /* TCP_CONNECTED: The socket is successfully connected */ - - else if ((flags & TCP_CONNECTED) != 0) - { - FAR struct socket *psock = pstate->tc_psock; - DEBUGASSERT(psock); - - /* Mark the connection bound and connected. NOTE this is - * is done here (vs. later) in order to avoid any race condition - * in the socket state. It is known to connected here and now, - * but not necessarily at any time later. - */ - - psock->s_flags |= (_SF_BOUND | _SF_CONNECTED); - - /* Indicate that the socket is no longer connected */ - - pstate->tc_result = OK; - } - - /* Otherwise, it is not an event of importance to us at the moment */ - - else - { - /* Drop data received in this state */ - - dev->d_len = 0; - return flags & ~TCP_NEWDATA; - } - - ninfo("Resuming: %d\n", pstate->tc_result); - - /* Stop further callbacks */ - - psock_teardown_callbacks(pstate, pstate->tc_result); - -#ifdef CONFIG_NET_MULTILINK - /* When we set up the connection structure, we did not know the size - * of the initial MSS. Now that the connection is associated with a - * network device, we now know the size of link layer header and can - * determine the correct initial MSS. - */ - - DEBUGASSERT(pstate->tc_conn); - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (pstate->tc_conn->domain == PF_INET) -#endif - { - pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev); - } -#endif /* CONFIG_NET_IPv6 */ - -#ifdef CONFIG_NETDEV_MULTINIC - /* We now have to filter all outgoing transfers so that they use only - * the MSS of this device. - */ - - DEBUGASSERT(pstate->tc_conn->dev == NULL || - pstate->tc_conn->dev == dev); - pstate->tc_conn->dev = dev; - -#endif /* CONFIG_NETDEV_MULTINIC */ -#endif /* CONFIG_NET_MULTILINK */ - - /* Wake up the waiting thread */ - - sem_post(&pstate->tc_sem); - } - - return flags; -} -#endif /* NET_TCP_HAVE_STACK */ - -/**************************************************************************** - * Name: psock_tcp_connect - * - * Description: - * Perform a TCP connection - * - * Parameters: - * psock - A reference to the socket structure of the socket to be connected - * addr - The address of the remote server to connect to - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -#ifdef NET_TCP_HAVE_STACK -static inline int psock_tcp_connect(FAR struct socket *psock, - FAR const struct sockaddr *addr) -{ - struct tcp_connect_s state; - int ret = OK; - - /* Interrupts must be disabled through all of the following because - * we cannot allow the network callback to occur until we are completely - * setup. - */ - - net_lock(); - - /* Get the connection reference from the socket */ - - if (!psock->s_conn) /* Should always be non-NULL */ - { - ret = -EINVAL; - } - else - { - /* Perform the TCP connection operation */ - - ret = tcp_connect(psock->s_conn, addr); - } - - if (ret >= 0) - { - /* Set up the callbacks in the connection */ - - ret = psock_setup_callbacks(psock, &state); - if (ret >= 0) - { - /* Wait for either the connect to complete or for an error/timeout - * 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-disabled - * when the task restarts. - */ - - ret = net_lockedwait(&state.tc_sem); - - /* Uninitialize the state structure */ - - (void)sem_destroy(&state.tc_sem); - - /* If net_lockedwait failed, recover the negated error (probably -EINTR) */ - - if (ret < 0) - { - ret = -get_errno(); - } - else - { - /* If the wait succeeded, then get the new error value from - * the state structure - */ - - ret = state.tc_result; - } - - /* Make sure that no further interrupts are processed */ - - psock_teardown_callbacks(&state, ret); - } - - /* Check if the socket was successfully connected. */ - - if (ret >= 0) - { - /* Yes... Now that we are connected, we need to set up to monitor - * the state of the connection up the connection event monitor. - */ - - ret = net_startmonitor(psock); - if (ret < 0) - { - /* net_startmonitor() can only fail on certain race - * conditions where the connection was lost just before - * this function was called. That is not expected to - * happen in this context, but just in case... - */ - - net_lostconnection(psock, TCP_ABORT); - } - } - } - - net_unlock(); - return ret; -} -#endif /* NET_TCP_HAVE_STACK */ +#ifdef CONFIG_NET /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: psock_connect * @@ -512,12 +130,8 @@ static inline int psock_tcp_connect(FAR struct socket *psock, int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen) { - FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr; -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || \ - defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_USRSOCK) - int ret; -#endif int errcode; + int ret; /* Treat as a cancellation point */ @@ -525,179 +139,22 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, /* Verify that the psock corresponds to valid, allocated socket */ - if (!psock || psock->s_crefs <= 0) + if (psock == NULL || psock->s_crefs <= 0) { errcode = EBADF; goto errout; } - /* Verify that a valid address has been provided */ + /* Let the address family's connect() method handle the operation */ - switch (inaddr->sin_family) + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_connect != NULL); + ret = psock->s_sockif->si_connect(psock, addr, addrlen); + if (ret < 0) { -#ifdef CONFIG_NET_IPv4 - case AF_INET: - { - if (addrlen < sizeof(struct sockaddr_in)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif - -#ifdef CONFIG_NET_IPv6 - case AF_INET6: - { - if (addrlen < sizeof(struct sockaddr_in6)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif - -#ifdef CONFIG_NET_LOCAL - case AF_LOCAL: - { - if (addrlen < sizeof(sa_family_t)) - { - errcode = EBADF; - goto errout; - } - } - break; -#endif - - default: -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { - break; - } -#endif - - DEBUGPANIC(); - errcode = EAFNOSUPPORT; + errcode = -ret; goto errout; } - /* Perform the connection depending on the protocol type */ - - switch (psock->s_type) - { -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) - case SOCK_STREAM: - { - /* Verify that the socket is not already connected */ - - if (_SS_ISCONNECTED(psock->s_flags)) - { - errcode = EISCONN; - goto errout; - } - - /* It's not ... connect it */ - -#ifdef CONFIG_NET_LOCAL_STREAM -#ifdef CONFIG_NET_TCP - if (psock->s_domain == PF_LOCAL) -#endif - { - /* Connect to the local Unix domain server */ - - ret = psock_local_connect(psock, addr); - } -#endif /* CONFIG_NET_LOCAL_STREAM */ - -#ifdef CONFIG_NET_TCP -#ifdef CONFIG_NET_LOCAL_STREAM - else -#endif - { -#ifdef NET_TCP_HAVE_STACK - /* Connect the TCP/IP socket */ - - ret = psock_tcp_connect(psock, addr); -#else - ret = -ENOSYS; -#endif - } -#endif /* CONFIG_NET_TCP */ - - if (ret < 0) - { - errcode = -ret; - goto errout; - } - } - break; -#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */ - -#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) - case SOCK_DGRAM: - { -#ifdef CONFIG_NET_LOCAL_DGRAM -#ifdef CONFIG_NET_UDP - if (psock->s_domain == PF_LOCAL) -#endif - { - /* Perform the datagram connection logic */ - - ret = psock_local_connect(psock, addr); - } -#endif /* CONFIG_NET_LOCAL_DGRAM */ - -#ifdef CONFIG_NET_UDP -#ifdef CONFIG_NET_LOCAL_DGRAM - else -#endif - { -#ifdef NET_UDP_HAVE_STACK - ret = udp_connect(psock->s_conn, addr); - if (ret < 0 || addr == NULL) - { - psock->s_flags &= ~_SF_CONNECTED; - } - else - { - psock->s_flags |= _SF_CONNECTED; - } -#else - ret = -ENOSYS; -#endif - } -#endif /* CONFIG_NET_UDP */ - - if (ret < 0) - { - errcode = -ret; - goto errout; - } - } - break; -#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */ - -#ifdef CONFIG_NET_USRSOCK - case SOCK_USRSOCK_TYPE: - { - ret = usrsock_connect(psock, addr, addrlen); - if (ret < 0) - { - errcode = -ret; - goto errout; - } - } - break; -#endif /* CONFIG_NET_USRSOCK */ - - default: - errcode = EBADF; - goto errout; - } - leave_cancellation_point(); return OK; diff --git a/net/socket/inet_connect.c b/net/socket/inet_connect.c new file mode 100644 index 0000000000..49aa17cd75 --- /dev/null +++ b/net/socket/inet_connect.c @@ -0,0 +1,567 @@ +/**************************************************************************** + * net/socket/inet_connect.c + * + * Copyright (C) 2007-2012, 2015-2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "devif/devif.h" +#include "tcp/tcp.h" +#include "udp/udp.h" +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +#ifdef CONFIG_NET + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +struct tcp_connect_s +{ + FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */ + FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */ + FAR struct socket *tc_psock; /* The socket being connected */ + sem_t tc_sem; /* Semaphore signals recv completion */ + int tc_result; /* OK on success, otherwise a negated errno. */ +}; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +static inline int psock_setup_callbacks(FAR struct socket *psock, + FAR struct tcp_connect_s *pstate); +static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, + int status); +static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags); +static inline int psock_tcp_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr); +#endif /* NET_TCP_HAVE_STACK */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: psock_setup_callbacks + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +static inline int psock_setup_callbacks(FAR struct socket *psock, + FAR struct tcp_connect_s *pstate) +{ + FAR struct tcp_conn_s *conn = psock->s_conn; + int ret = -EBUSY; + + /* Initialize the TCP state structure */ + + /* This semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + (void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */ + (void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE); + + pstate->tc_conn = conn; + pstate->tc_psock = psock; + pstate->tc_result = -EAGAIN; + + /* Set up the callbacks in the connection */ + + pstate->tc_cb = tcp_callback_alloc(conn); + if (pstate->tc_cb) + { + /* Set up the connection "interrupt" handler */ + + pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT | + TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN); + pstate->tc_cb->priv = (FAR void *)pstate; + pstate->tc_cb->event = psock_connect_interrupt; + ret = OK; + } + + return ret; +} +#endif /* NET_TCP_HAVE_STACK */ + +/**************************************************************************** + * Name: psock_teardown_callbacks + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate, + int status) +{ + FAR struct tcp_conn_s *conn = pstate->tc_conn; + + /* Make sure that no further interrupts are processed */ + + tcp_callback_free(conn, pstate->tc_cb); + pstate->tc_cb = NULL; + + /* If we successfully connected, we will continue to monitor the connection + * state via callbacks. + */ + + if (status < 0) + { + /* Failed to connect. Stop the connection event monitor */ + + net_stopmonitor(conn); + } +} +#endif /* NET_TCP_HAVE_STACK */ + +/**************************************************************************** + * Name: psock_connect_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * connection operation via by the lower, device interfacing layer. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * pvconn The connection structure associated with the socket + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * The new flags setting + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags) +{ + struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv; + + ninfo("flags: %04x\n", flags); + + /* 'priv' might be null in some race conditions (?) */ + + if (pstate) + { + /* The following errors should be detected here (someday) + * + * ECONNREFUSED + * No one listening on the remote address. + * ENETUNREACH + * Network is unreachable. + * ETIMEDOUT + * Timeout while attempting connection. The server may be too busy + * to accept new connections. + */ + + /* TCP_CLOSE: The remote host has closed the connection + * TCP_ABORT: The remote host has aborted the connection + */ + + if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0) + { + /* Indicate that remote host refused the connection */ + + pstate->tc_result = -ECONNREFUSED; + } + + /* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */ + + else if ((flags & TCP_TIMEDOUT) != 0) + { + /* Indicate that the connection timedout?) */ + + pstate->tc_result = -ETIMEDOUT; + } + + else if ((flags & NETDEV_DOWN) != 0) + { + /* The network device went down. Indicate that the remote host + * is unreachable. + */ + + pstate->tc_result = -ENETUNREACH; + } + + /* TCP_CONNECTED: The socket is successfully connected */ + + else if ((flags & TCP_CONNECTED) != 0) + { + FAR struct socket *psock = pstate->tc_psock; + DEBUGASSERT(psock); + + /* Mark the connection bound and connected. NOTE this is + * is done here (vs. later) in order to avoid any race condition + * in the socket state. It is known to connected here and now, + * but not necessarily at any time later. + */ + + psock->s_flags |= (_SF_BOUND | _SF_CONNECTED); + + /* Indicate that the socket is no longer connected */ + + pstate->tc_result = OK; + } + + /* Otherwise, it is not an event of importance to us at the moment */ + + else + { + /* Drop data received in this state */ + + dev->d_len = 0; + return flags & ~TCP_NEWDATA; + } + + ninfo("Resuming: %d\n", pstate->tc_result); + + /* Stop further callbacks */ + + psock_teardown_callbacks(pstate, pstate->tc_result); + +#ifdef CONFIG_NET_MULTILINK + /* When we set up the connection structure, we did not know the size + * of the initial MSS. Now that the connection is associated with a + * network device, we now know the size of link layer header and can + * determine the correct initial MSS. + */ + + DEBUGASSERT(pstate->tc_conn); + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (pstate->tc_conn->domain == PF_INET) +#endif + { + pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { + pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev); + } +#endif /* CONFIG_NET_IPv6 */ + +#ifdef CONFIG_NETDEV_MULTINIC + /* We now have to filter all outgoing transfers so that they use only + * the MSS of this device. + */ + + DEBUGASSERT(pstate->tc_conn->dev == NULL || + pstate->tc_conn->dev == dev); + pstate->tc_conn->dev = dev; + +#endif /* CONFIG_NETDEV_MULTINIC */ +#endif /* CONFIG_NET_MULTILINK */ + + /* Wake up the waiting thread */ + + sem_post(&pstate->tc_sem); + } + + return flags; +} +#endif /* NET_TCP_HAVE_STACK */ + +/**************************************************************************** + * Name: psock_tcp_connect + * + * Description: + * Perform a TCP connection + * + * Parameters: + * psock - A reference to the socket structure of the socket to be connected + * addr - The address of the remote server to connect to + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef NET_TCP_HAVE_STACK +static inline int psock_tcp_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr) +{ + struct tcp_connect_s state; + int ret = OK; + + /* Interrupts must be disabled through all of the following because + * we cannot allow the network callback to occur until we are completely + * setup. + */ + + net_lock(); + + /* Get the connection reference from the socket */ + + if (!psock->s_conn) /* Should always be non-NULL */ + { + ret = -EINVAL; + } + else + { + /* Perform the TCP connection operation */ + + ret = tcp_connect(psock->s_conn, addr); + } + + if (ret >= 0) + { + /* Set up the callbacks in the connection */ + + ret = psock_setup_callbacks(psock, &state); + if (ret >= 0) + { + /* Wait for either the connect to complete or for an error/timeout + * 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-disabled + * when the task restarts. + */ + + ret = net_lockedwait(&state.tc_sem); + + /* Uninitialize the state structure */ + + (void)sem_destroy(&state.tc_sem); + + /* If net_lockedwait failed, recover the negated error (probably -EINTR) */ + + if (ret < 0) + { + ret = -get_errno(); + } + else + { + /* If the wait succeeded, then get the new error value from + * the state structure + */ + + ret = state.tc_result; + } + + /* Make sure that no further interrupts are processed */ + + psock_teardown_callbacks(&state, ret); + } + + /* Check if the socket was successfully connected. */ + + if (ret >= 0) + { + /* Yes... Now that we are connected, we need to set up to monitor + * the state of the connection up the connection event monitor. + */ + + ret = net_startmonitor(psock); + if (ret < 0) + { + /* net_startmonitor() can only fail on certain race + * conditions where the connection was lost just before + * this function was called. That is not expected to + * happen in this context, but just in case... + */ + + net_lostconnection(psock, TCP_ABORT); + } + } + } + + net_unlock(); + return ret; +} +#endif /* NET_TCP_HAVE_STACK */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inet_connect + * + * Description: + * inet_connect() connects the local socket referred to by the structure + * 'psock' to the address specified by 'addr'. The addrlen argument + * specifies the size of 'addr'. The format of the address in 'addr' is + * determined by the address space of the socket 'psock'. + * + * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address + * to which datagrams are sent by default, and the only address from which + * datagrams are received. If the socket is of type SOCK_STREAM or + * SOCK_SEQPACKET, this call attempts to make a connection to the socket + * that is bound to the address specified by 'addr'. + * + * Generally, connection-based protocol sockets may successfully + * inet_connect() only once; connectionless protocol sockets may use + * inet_connect() multiple times to change their association. + * Connectionless sockets may dissolve the association by connecting to + * an address with the sa_family member of sockaddr set to AF_UNSPEC. + * + * Parameters: + * psock Pointer to a socket structure initialized by psock_socket() + * addr Server address (form depends on type of socket) + * addrlen Length of actual 'addr' + * + * Returned Value: + * 0 on success; a negated errno value on failue. See connect() for the + * list of appropriate errno values to be returned. + * + ****************************************************************************/ + +int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr; + + /* Verify that a valid address has been provided */ + + switch (inaddr->sin_family) + { +#ifdef CONFIG_NET_IPv4 + case AF_INET: + { + if (addrlen < sizeof(struct sockaddr_in)) + { + return -EBADF; + } + } + break; +#endif + +#ifdef CONFIG_NET_IPv6 + case AF_INET6: + { + if (addrlen < sizeof(struct sockaddr_in6)) + { + return -EBADF; + } + } + break; +#endif + + default: +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + break; + } +#endif + + DEBUGPANIC(); + return -EAFNOSUPPORT; + } + + /* Perform the connection depending on the protocol type */ + + switch (psock->s_type) + { +#ifdef CONFIG_NET_TCP + case SOCK_STREAM: + { + /* Verify that the socket is not already connected */ + + if (_SS_ISCONNECTED(psock->s_flags)) + { + return -EISCONN; + } + + /* It's not ... Connect the TCP/IP socket */ + + return psock_tcp_connect(psock, addr); + } +#endif /* CONFIG_NET_TCP */ + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + { + int ret = udp_connect(psock->s_conn, addr); + if (ret < 0 || addr == NULL) + { + psock->s_flags &= ~_SF_CONNECTED; + } + else + { + psock->s_flags |= _SF_CONNECTED; + } + + return ret; + } +#endif /* CONFIG_NET_UDP */ + +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + return usrsock_connect(psock, addr, addrlen); + } +#endif /* CONFIG_NET_USRSOCK */ + + default: + return -EBADF; + } +} + +#endif /* CONFIG_NET */ diff --git a/net/socket/inet_recvfrom.c b/net/socket/inet_recvfrom.c index b38c15e82d..3e29b93e4b 100644 --- a/net/socket/inet_recvfrom.c +++ b/net/socket/inet_recvfrom.c @@ -1650,6 +1650,16 @@ ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, break; #endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */ +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + /* Perform the usrsock recvfrom operation */ + + ret = usrsock_recvfrom(psock, buf, len, from, fromlen); + } + break; +#endif + default: { nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); diff --git a/net/socket/inet_sockif.c b/net/socket/inet_sockif.c index 4866afd695..4574f2a1e4 100644 --- a/net/socket/inet_sockif.c +++ b/net/socket/inet_sockif.c @@ -49,6 +49,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" +#include "usrsock/usrsock.h" #include "socket/socket.h" #if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) @@ -57,12 +58,14 @@ * Private Function Prototypes ****************************************************************************/ -static int inet_setup(FAR struct socket *psock, int protocol); +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 ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, - size_t len, int flags); + size_t len, int flags); static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, - size_t len, int flags, FAR const struct sockaddr *to, - socklen_t tolen); + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen); /**************************************************************************** * Public Data @@ -71,6 +74,8 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, const struct sock_intf_s g_inet_sockif = { inet_setup, /* si_setup */ + inet_bind, /* si_bind */ + inet_connect, /* si_connect */ inet_send, /* si_send */ inet_sendto, /* si_sendto */ inet_recvfrom /* si_recvfrom */ @@ -152,6 +157,65 @@ static int inet_udp_alloc(FAR struct socket *psock) } #endif /* NET_UDP_HAVE_STACK */ +/**************************************************************************** + * Name: usrsock_socket_setup + * + * Description: + * Special socket setup may be required by user sockets. + * + * Parameters: + * domain (see sys/socket.h) + * type (see sys/socket.h) + * protocol (see sys/socket.h) + * psock A pointer to a user allocated socket structure to be initialized. + * + * Returned Value: + * 0 on success; a negated errno value is returned on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_USRSOCK +static int usrsock_socket_setup(int domain, int type, int protocol, + FAR struct socket *psock) +{ + switch (domain) + { + default: + return OK; + + case PF_INET: + case PF_INET6: + { +#ifndef CONFIG_NET_USRSOCK_UDP + if (type == SOCK_DGRAM) + { + return OK; + } +#endif +#ifndef CONFIG_NET_USRSOCK_TCP + if (type == SOCK_STREAM) + { + return OK; + } +#endif + psock->s_type = PF_UNSPEC; + psock->s_conn = NULL; + + /* Let the user socket logic handle the setup... + * + * A return value of zero means that the operation was + * successfully handled by usrsock. A negative value means that + * an error occurred. The special error value -ENETDOWN means + * that usrsock daemon is not running. The caller should attempt + * to open socket with kernel networking stack in this case. + */ + + return usrsock_socket(domain, type, protocol, psock); + } + } +} +#endif /* CONFIG_NET_USRSOCK */ + /**************************************************************************** * Name: inet_setup * @@ -175,6 +239,27 @@ static int inet_udp_alloc(FAR struct socket *psock) static int inet_setup(FAR struct socket *psock, int protocol) { +#ifdef CONFIG_NET_USRSOCK + /* Handle speical setup for user INET sockets */ + + ret = usrsock_socket_setup(domain, type, protocol, psock); + if (ret < 0) + { + if (ret = -ENETDOWN) + { + /* -ENETDOWN means that usrsock daemon is not running. Attempt to + * open socket with kernel networking stack. + */ + + warn("WARNING: usrsock daemon is not running\n"); + } + else + { + return ret; + } + } +#endif /* CONFIG_NET_USRSOCK */ + /* Allocate the appropriate connection structure. This reserves the * the connection structure is is unallocated at this point. It will * not actually be initialized until the socket is connected. @@ -197,6 +282,7 @@ static int inet_setup(FAR struct socket *psock, int protocol) return inet_tcp_alloc(psock); #else + warning("WARNING: SOCK_STREAM disabled\n"); return = -ENETDOWN; #endif #endif /* CONFIG_NET_TCP */ @@ -214,6 +300,7 @@ static int inet_setup(FAR struct socket *psock, int protocol) return inet_udp_alloc(psock); #else + warning("WARNING: SOCK_DGRAM disabled\n"); return -ENETDOWN; #endif #endif /* CONFIG_NET_UDP */ @@ -224,6 +311,130 @@ static int inet_setup(FAR struct socket *psock, int protocol) } } +/**************************************************************************** + * Name: inet_bind + * + * Description: + * inet_bind() gives the socket 'psock' the local address 'addr'. 'addr' + * is 'addrlen' bytes long. Traditionally, this is called "assigning a + * name to a socket." When a socket is created with socket(), it exists + * in a name space (address family) but has no name assigned. + * + * Parameters: + * psock Socket structure of the socket to bind + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; A negated errno value is returned on failure. See + * bind() for a list a appropriate error values. + * + ****************************************************************************/ + +static int inet_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + int minlen; + int ret; + + /* Verify that a valid address has been provided */ + + switch (addr->sa_family) + { +#ifdef CONFIG_NET_IPv4 + case AF_INET: + minlen = sizeof(struct sockaddr_in); + break; +#endif + +#ifdef CONFIG_NET_IPv6 + case AF_INET6: + minlen = sizeof(struct sockaddr_in6); + break; +#endif + + default: + nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family); + return -EAFNOSUPPORT; + } + + if (addrlen < minlen) + { + nerr("ERROR: Invalid address length: %d < %d\n", addrlen, minlen); + return -EBADF; + } + + /* Perform the binding depending on the protocol type */ + + switch (psock->s_type) + { +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + DEBUGASSERT(conn != NULL); + + /* Perform the usrsock bind operation */ + + ret = usrsock_bind(conn, addr, addrlen); + } + break; +#endif + +#ifdef CONFIG_NET_TCP + case SOCK_STREAM: + { +#ifdef NET_TCP_HAVE_STACK + /* Bind a TCP/IP stream socket. */ + + ret = tcp_bind(psock->s_conn, addr); + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } +#else + nwarn("WARNING: TCP/IP stack is not available in this configuration\n"); + return -ENOSYS; +#endif + } + break; +#endif /* CONFIG_NET_TCP */ + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + { +#ifdef NET_UDP_HAVE_STACK + /* Bind a UDP/IP datagram socket */ + + ret = udp_bind(psock->s_conn, addr); + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } +#else + nwarn("WARNING: UDP stack is not available in this configuration\n"); + ret = -ENOSYS; +#endif + } + break; +#endif /* CONFIG_NET_UDP */ + + default: + nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); + ret = -EBADF; + break; + } + + return ret; +} + /**************************************************************************** * Name: inet_send * @@ -303,6 +514,16 @@ static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, break; #endif /* CONFIG_NET_UDP */ + /* Special case user sockets */ + +#ifdef CONFIG_NET_USRSOCK + case SOCK_USRSOCK_TYPE: + { + ret = usrsock_sendto(psock, buf, len, NULL, 0); + } + break; +#endif /*CONFIG_NET_USRSOCK*/ + default: { /* EDESTADDRREQ. Signifies that the socket is not connection-mode @@ -347,71 +568,78 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, socklen_t minlen; ssize_t nsent; - /* Verify that a valid address has been provided */ - - switch (to->sa_family) +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) { + /* Perform the usrsock sendto operation */ + + nsent = usrsock_sendto(psock, buf, len, to, tolen); + } + else +#endif + { + /* Verify that a valid address has been provided */ + + switch (to->sa_family) + { #ifdef CONFIG_NET_IPv4 - case AF_INET: - minlen = sizeof(struct sockaddr_in); - break; + case AF_INET: + minlen = sizeof(struct sockaddr_in); + break; #endif #ifdef CONFIG_NET_IPv6 - case AF_INET6: - minlen = sizeof(struct sockaddr_in6); - break; + case AF_INET6: + minlen = sizeof(struct sockaddr_in6); + break; #endif -#ifdef CONFIG_NET_LOCAL_DGRAM - case AF_LOCAL: - minlen = sizeof(sa_family_t); - break; -#endif + default: + nerr("ERROR: Unrecognized address family: %d\n", to->sa_family); + return -EAFNOSUPPORT; + } - default: - nerr("ERROR: Unrecognized address family: %d\n", to->sa_family); - return -EAFNOSUPPORT; - } - - if (tolen < minlen) - { - nerr("ERROR: Invalid address length: %d < %d\n", tolen, minlen); - return -EBADF; - } + if (tolen < minlen) + { + nerr("ERROR: Invalid address length: %d < %d\n", tolen, minlen); + return -EBADF; + } #ifdef CONFIG_NET_UDP - /* If this is a connected socket, then return EISCONN */ + /* If this is a connected socket, then return EISCONN */ - if (psock->s_type != SOCK_DGRAM) - { - nerr("ERROR: Connected socket\n"); - return -EBADF; - } + if (psock->s_type != SOCK_DGRAM) + { + nerr("ERROR: Connected socket\n"); + return -EBADF; + } - /* Now handle the INET sendto() operation */ + /* Now handle the INET sendto() operation */ #if defined(CONFIG_NET_6LOWPAN) - /* Try 6LoWPAN UDP packet sendto() */ + /* Try 6LoWPAN UDP packet sendto() */ - nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen); + nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen); #if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK) - if (nsent < 0) - { - /* UDP/IP packet sendto */ + if (nsent < 0) + { + /* UDP/IP packet sendto */ - nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); - } + nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); + } #endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */ #elif defined(NET_UDP_HAVE_STACK) - nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); + nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); #else - nsent = -ENOSYS; + nwarn("WARNING: UDP not available in this configuiration\n") + nsent = -ENOSYS; #endif /* CONFIG_NET_6LOWPAN */ #else - nsent = -EISCONN; + nwarn("WARNING: UDP not enabled in this configuiration\n") + nsent = -EISCONN; #endif /* CONFIG_NET_UDP */ + } return nsent; } @@ -421,7 +649,7 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, ****************************************************************************/ /**************************************************************************** - * Name: + * Name: * * Description: * diff --git a/net/socket/net_clone.c b/net/socket/net_clone.c index c134116d7f..5c41702774 100644 --- a/net/socket/net_clone.c +++ b/net/socket/net_clone.c @@ -155,5 +155,3 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2) } #endif /* CONFIG_NET */ - - diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 9b576cbcb8..1144bf6d6f 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -46,7 +46,6 @@ #include #include "socket/socket.h" -#include "usrsock/usrsock.h" #ifdef CONFIG_NET @@ -147,33 +146,14 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { - /* Perform the usrsock recvfrom operation */ + /* Let logic specific to this address family handle the recvfrom() + * operation. + */ - ret = usrsock_recvfrom(psock, buf, len, from, fromlen); - } - else -#endif - { - /* Let logic specific to this address family handle the recvfrom() - * operation. - */ + DEBUGASSERT(psock->s_sockif != NULL && + psock->s_sockif->si_recvfrom != NULL); - DEBUGASSERT(psock->s_sockif != NULL && - psock->s_sockif->si_recvfrom != NULL); - - if (psock->s_sockif->si_recvfrom != NULL) - { - ret = psock->s_sockif->si_recvfrom(psock, buf, len, flags, - from, fromlen); - } - else - { - ret = -ENOSYS; - } - } + ret = psock->s_sockif->si_recvfrom(psock, buf, len, flags, from, fromlen); /* Set the socket state to idle */ diff --git a/net/socket/send.c b/net/socket/send.c index 1b8a39d47c..9af7e88cdb 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -53,7 +53,6 @@ #include "sixlowpan/sixlowpan.h" #include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -134,21 +133,10 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, (void)enter_cancellation_point(); - /* Special case user sockets */ + /* Let the address family's send() method handle the operation */ -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type SOCK_USRSOCK_TYPE) - { - ret = usrsock_sendto(psock, buf, len, NULL, 0); - } - else -#endif /*CONFIG_NET_USRSOCK*/ - { - /* Let the address family's send() method handle the operation */ - - DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL); - ret = psock->s_sockif->si_send(psock, buf, len, flags); - } + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL); + ret = psock->s_sockif->si_send(psock, buf, len, flags); leave_cancellation_point(); if (ret < 0) diff --git a/net/socket/sendto.c b/net/socket/sendto.c index 6a7dd9a51a..6ddf2a5958 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -53,7 +53,6 @@ #include "sixlowpan/sixlowpan.h" #include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions @@ -149,30 +148,19 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, #endif } -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) + /* Verify that the psock corresponds to valid, allocated socket */ + + if (!psock || psock->s_crefs <= 0) { - /* Perform the usrsock sendto operation */ - - nsent = usrsock_sendto(psock, buf, len, to, tolen); + nerr("ERROR: Invalid socket\n"); + errcode = EBADF; + goto errout; } - else -#endif - { - /* Verify that the psock corresponds to valid, allocated socket */ - if (!psock || psock->s_crefs <= 0) - { - nerr("ERROR: Invalid socket\n"); - errcode = EBADF; - goto errout; - } + /* Let the address family's send() method handle the operation */ - /* Let the address family's send() method handle the operation */ - - DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL); - nsent = psock->s_sockif->si_send(psock, buf, len, flags); - } + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL); + nsent = psock->s_sockif->si_send(psock, buf, len, flags); /* Check if the domain-specific sendto() logic failed */ diff --git a/net/socket/socket.c b/net/socket/socket.c index 8c63c8095f..7265e5cce9 100644 --- a/net/socket/socket.c +++ b/net/socket/socket.c @@ -44,87 +44,10 @@ #include #include -#include "usrsock/usrsock.h" #include "socket/socket.h" #ifdef CONFIG_NET -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usrsock_socket_setup - * - * Description: - * Special socket setup may be required by user sockets. - * - * Parameters: - * domain (see sys/socket.h) - * type (see sys/socket.h) - * protocol (see sys/socket.h) - * psock A pointer to a user allocated socket structure to be initialized. - * - * Returned Value: - * 0 on success; -1 on error with errno set appropriately - * - ****************************************************************************/ - -#ifdef CONFIG_NET_USRSOCK -static int usrsock_socket_setup(int domain, int type, int protocol, - FAR struct socket *psock) -{ - int errcode; - int ret; - - switch (domain) - { - default: - break; - - case PF_INET: - case PF_INET6: - { -#ifndef CONFIG_NET_USRSOCK_UDP - if (type == SOCK_DGRAM) - { - break; - } -#endif -#ifndef CONFIG_NET_USRSOCK_TCP - if (type == SOCK_STREAM) - { - break; - } -#endif - psock->s_type = 0; - psock->s_conn = NULL; - - ret = usrsock_socket(domain, type, protocol, psock); - if (ret >= 0) - { - /* Successfully handled and opened by usrsock daemon. */ - - return OK; - } - else if (ret == -ENETDOWN) - { - /* Net down means that usrsock daemon is not running. - * Attempt to open socket with kernel networking stack. - */ - } - else - { - return ret; - } - } - } - - return OK; -} -#else -#endif /* CONFIG_NET_USRSOCK */ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -173,16 +96,6 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) int errcode; int ret; -#ifdef CONFIG_NET_USRSOCK - ret = usrsock_socket_setup(domain, type, protocol, psock); - if (ret < 0) - { - nerr("ERROR: usrsock_socket_setup() failed: %d\n", ret); - errcode = -ret; - goto errout; - } -#endif /* CONFIG_NET_USRSOCK */ - /* Initialize the socket structure */ psock->s_domain = domain; diff --git a/net/socket/socket.h b/net/socket/socket.h index a7f43ce10e..fec553de29 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -436,6 +436,41 @@ int net_timeo(systime_t start_time, socktimeo_t timeo); ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); +/**************************************************************************** + * Name: inet_connect + * + * Description: + * inet_connect() connects the local socket referred to by the structure + * 'psock' to the address specified by 'addr'. The addrlen argument + * specifies the size of 'addr'. The format of the address in 'addr' is + * determined by the address space of the socket 'psock'. + * + * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address + * to which datagrams are sent by default, and the only address from which + * datagrams are received. If the socket is of type SOCK_STREAM or + * SOCK_SEQPACKET, this call attempts to make a connection to the socket + * that is bound to the address specified by 'addr'. + * + * Generally, connection-based protocol sockets may successfully + * inet_connect() only once; connectionless protocol sockets may use + * inet_connect() multiple times to change their association. + * Connectionless sockets may dissolve the association by connecting to + * an address with the sa_family member of sockaddr set to AF_UNSPEC. + * + * Parameters: + * psock Pointer to a socket structure initialized by psock_socket() + * addr Server address (form depends on type of socket) + * addrlen Length of actual 'addr' + * + * Returned Value: + * 0 on success; a negated errno value on failue. See connect() for the + * list of appropriate errno values to be returned. + * + ****************************************************************************/ + +int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, + socklen_t addrlen); + /**************************************************************************** * Name: inet_recvfrom *