diff options
32 files changed, 3392 insertions, 417 deletions
diff --git a/nuttx/net/Kconfig b/nuttx/net/Kconfig index 2c2eabef6..272743d2b 100644 --- a/nuttx/net/Kconfig +++ b/nuttx/net/Kconfig @@ -202,6 +202,7 @@ endmenu # Internet Protocol Selection source "net/socket/Kconfig" source "net/pkt/Kconfig" +source "net/local/Kconfig" source "net/tcp/Kconfig" source "net/udp/Kconfig" source "net/icmp/Kconfig" diff --git a/nuttx/net/Makefile b/nuttx/net/Makefile index 7a9cf03d5..ce3faf0f3 100644 --- a/nuttx/net/Makefile +++ b/nuttx/net/Makefile @@ -63,9 +63,10 @@ include icmp/Make.defs include icmpv6/Make.defs include neighbor/Make.defs include igmp/Make.defs +include pkt/Make.defs +include local/Make.defs include tcp/Make.defs include udp/Make.defs -include pkt/Make.defs include devif/Make.defs include route/Make.defs include utils/Make.defs diff --git a/nuttx/net/README.txt b/nuttx/net/README.txt index bbbccc0db..db0a59452 100644 --- a/nuttx/net/README.txt +++ b/nuttx/net/README.txt @@ -13,6 +13,7 @@ Directory Structure +- icmp - Internet Control Message Protocol (IPv4) +- icmpv6 - Internet Control Message Protocol (IPv6) +- iob - I/O buffering logic + +- local - Unix domain (local) sockets +- neighbor - Neighbor Discovery Protocol (IPv6) +- netdev - Socket network device interface +- pkt - "Raw" packet socket support diff --git a/nuttx/net/local/Kconfig b/nuttx/net/local/Kconfig new file mode 100644 index 000000000..2f720c348 --- /dev/null +++ b/nuttx/net/local/Kconfig @@ -0,0 +1,19 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +menu "Unix Domain Socket Support" + depends on NET && EXPERIMENTAL + +config NET_LOCAL + bool "Unix domain (local) sockets" + default n + ---help--- + Enable or disable Unix domain (aka Local) sockets. + +if NET_LOCAL + +endif # NET_LOCAL + +endmenu # Unix Domain Sockets diff --git a/nuttx/net/local/Make.defs b/nuttx/net/local/Make.defs new file mode 100644 index 000000000..35dc643cc --- /dev/null +++ b/nuttx/net/local/Make.defs @@ -0,0 +1,49 @@ +############################################################################ +# net/local/Make.defs +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# 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. +# +############################################################################ + +# UDP source files + +ifeq ($(CONFIG_NET_LOCAL),y) + +NET_CSRCS += local_conn.c local_connect.c local_release.c local_bind.c +NET_CSRCS += local_listen.c local_accept.c local_fifo.c local_recvfrom.c +NET_CSRCS += local_send.c local_sendto.c + +# Include UDP build support + +DEPPATH += --dep-path local +VPATH += :local + +endif # CONFIG_NET_LOCAL diff --git a/nuttx/net/local/local.h b/nuttx/net/local/local.h new file mode 100644 index 000000000..8b7fb994c --- /dev/null +++ b/nuttx/net/local/local.h @@ -0,0 +1,434 @@ +/**************************************************************************** + * net/local/loal.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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. + * + ****************************************************************************/ + +#ifndef __NET_LOCAL_LOCAL_H +#define __NET_LOCAL_LOCAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/un.h> +#include <semaphore.h> +#include <queue.h> +#include <stdint.h> + +#ifdef CONFIG_NET_LOCAL + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ +/* Local, Unix domain socket types */ + +enum local_type_e +{ + LOCAL_TYPE_UNTYPED = 0, /* Type is not determined until the socket is bound */ + LOCAL_TYPE_UNNAMED, /* A Unix socket that is not bound to any name */ + LOCAL_TYPE_PATHNAME, /* lc_path holds a null terminated string */ + LOCAL_TYPE_ABSTRACT /* lc_path is length zero */ +}; + +/* The state of a Unix socket */ + +enum local_state_s +{ + /* Common states */ + + LOCAL_STATE_UNBOUND = 0, /* Created by socket, but not bound */ + LOCAL_STATE_BOUND, /* Bound to an path */ + + /* SOCK_STREAM only */ + + LOCAL_STATE_LISTENING, /* Server listening for connections */ + LOCAL_STATE_CLOSED, /* Server closed, no longer connecting */ + LOCAL_STATE_ACCEPT, /* Client waiting for a connection */ + LOCAL_STATE_CONNECTED, /* Peer connected */ + LOCAL_STATE_DISCONNECTED /* Peer disconnected */ +}; + +/* Representation of a local connection */ + +struct local_conn_s +{ + /* lc_node supports a doubly linked list: Listening SOCK_STREAM servers + * will be linked into a list of listeners; SOCK_STREAM clients will be + * linked to the lc_waiters and lc_conn lists. + */ + + dq_entry_t lc_node; /* Supports a doubly linked list */ + + /* Fields common to SOCK_STREAM and SOCK_DGRAM */ + + uint8_t lc_crefs; /* Reference counts on this instance */ + uint8_t lc_family; /* SOCK_STREAM or SOCK_DGRAM */ + uint8_t lc_type; /* See enum local_type_e */ + uint8_t lc_state; /* See enum local_state_e */ + int16_t lc_infd; /* File descriptor of read-only FIFO (peers) */ + int16_t lc_outfd; /* File descriptor of write-only FIFO (peers) */ + char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */ + + /* SOCK_STREAM fields common to both client and server */ + + sem_t lc_waitsem; /* Use to wait for a connection to be accepted */ + + /* Union of fields unique to SOCK_STREAM client and servers */ + + union + { + /* Fields unique to the SOCK_STREAM server side */ + + struct + { + uint8_t lc_pending; /* Number of pending connections */ + uint8_t lc_backlog; /* Maximum number of pending connections */ + dq_queue_t lc_waiters; /* List of connections waiting to be accepted */ + dq_queue_t lc_conns; /* List of connections */ + } server; + + /* Fields unique to the connecting client side */ + + struct + { + FAR struct local_conn_s *lc_server; /* Server connection */ + volatile int lc_result; /* Result of the connection operation */ + } client; + } u; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/* A list of all SOCK_STREAM listener connections */ + +EXTERN dq_queue_t g_local_listeners; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ + +/**************************************************************************** + * Name: local_initialize + * + * Description: + * Initialize the local, Unix domain connection structures. Called once + * and only from the common network initialization logic. + * + ****************************************************************************/ + +void local_initialize(void); + +/**************************************************************************** + * Name: local_alloc + * + * Description: + * Allocate a new, uninitialized local connection structure. This is + * normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct local_conn_s *local_alloc(void); + +/**************************************************************************** + * Name: local_free + * + * Description: + * Free a local connection structure that is no longer in use. This should + * be done by the implementation of close(). + * + ****************************************************************************/ + +void local_free(FAR struct local_conn_s *conn); + +/**************************************************************************** + * Name: local_bind + * + * Description: + * This function implements the low-level parts of the standard local + * bind()operation. + * + ****************************************************************************/ + +int local_bind(FAR struct local_conn_s *conn, + FAR const struct sockaddr *addr, socklen_t addrlen); + +/**************************************************************************** + * Name: local_connect + * + * Description: + * This function sets up a new local connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * local_bind() call, after the local_connect() function has been + * called. + * + * This function is called as part of the implementation of sendto + * and recvfrom. + * + * Input Parameters: + * client - A reference to the client-side local connection structure + * addr - The address of the remote host. + * + ****************************************************************************/ + +int local_connect(FAR struct local_conn_s *client, + FAR const struct sockaddr *addr); + +/**************************************************************************** + * Name: local_release + * + * Description: + * If the local, Unix domain socket is in the connected state, then + * disconnect it. Release the local connection structure in any event + * + * Input Parameters: + * conn - A reference to local connection structure + * + ****************************************************************************/ + +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. + * + * 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. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * The network is NOT locked + * + ****************************************************************************/ + +int local_listen(FAR struct local_conn_s *server, int backlog); + +/**************************************************************************** + * Function: psock_local_accept + * + * Description: + * This function implements accept() for Unix domain sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening Unix domain socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted Unix domain connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is NOT locked. + * + ****************************************************************************/ + +int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + +/**************************************************************************** + * Name: psock_local_send + * + * Description: + * Send a local packet as a stream. + * + * Parameters: + * psock An instance of the internal socket structure. + * buf Data to send + * len Length of data to send + * flags Send flags + * + * Return: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see send() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags); + +/**************************************************************************** + * Function: psock_sendto + * + * Description: + * Send a local packet as a datagram. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see sendto() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen); + +/**************************************************************************** + * Function: psock_recvfrom + * + * Description: + * recvfrom() receives messages from a local socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on errors, -1 is returned, and errno + * is set appropriately (see receivefrom for the complete list). + * + ****************************************************************************/ + +ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen); + +/**************************************************************************** + * Name: local_create_fifos + * + * Description: + * Create the FIFO pair needed for a connection. + * + ****************************************************************************/ + +int local_create_fifos(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_destroy_fifos + * + * Description: + * Destroy the FIFO pair used for a connection. + * + ****************************************************************************/ + +int local_destroy_fifos(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_client_rx + * + * Description: + * Only the client-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_client_rx(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_client_tx + * + * Description: + * Only the client-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_client_tx(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_server_rx + * + * Description: + * Only the server-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_server_rx(FAR struct local_conn_s *server); + +/**************************************************************************** + * Name: local_open_server_tx + * + * Description: + * Only the server-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_server_tx(FAR struct local_conn_s *server); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_LOCAL */ +#endif /* __NET_LOCAL_LOCAL_H */ diff --git a/nuttx/net/local/local_accept.c b/nuttx/net/local/local_accept.c new file mode 100644 index 000000000..e3ce2f577 --- /dev/null +++ b/nuttx/net/local/local_accept.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * net/local/local_accept.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "socket/socket.h" +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_local_accept + * + * Description: + * This function implements accept() for Unix domain sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening Unix domain socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted Unix domain connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is NOT locked. + * + ****************************************************************************/ + +int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn) + +{ + FAR struct local_conn_s *server; + FAR struct local_conn_s *client; + FAR struct local_conn_s *conn; + int ret; + + /* Some sanity checks */ + + DEBUGASSERT(psock && psock->s_conn); + server = (FAR struct local_conn_s *)psock->s_conn; + + if (server->lc_family != SOCK_STREAM || + server->lc_state != LOCAL_STATE_LISTENING || + server->lc_type != LOCAL_TYPE_PATHNAME) + { + return -EOPNOTSUPP; + } + + /* Loop as necessary if we have to wait for a connection */ + + for (;;) + { + /* Are there pending connections. Remove the client from the + * head of the waiting list. + */ + + client = (FAR struct local_conn_s *) + dq_remfirst(&server->u.server.lc_waiters); + + if (client) + { + /* Decrement the number of pending clients */ + + DEBUGASSERT(server->u.server.lc_pending > 0); + server->u.server.lc_pending--; + + /* Create a new connection structure for the server side of the + * connection. + */ + + conn = local_alloc(); + if (!conn) + { + ndbg("ERROR: Failed to allocate new connection structure\n"); + ret = -ENOMEM; + } + else + { + /* Initialize the new connection structure */ + + conn->lc_crefs = 1; + conn->lc_family = SOCK_STREAM; + conn->lc_type = LOCAL_TYPE_PATHNAME; + conn->lc_state = LOCAL_STATE_CONNECTED; + + strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX-1); + conn->lc_path[UNIX_PATH_MAX-1] = '\0'; + + /* Open the server-side write-only FIFO. This should not + * block. + */ + + ret = local_open_server_tx(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + conn->lc_path, ret); + } + } + + /* Do we have a connection? Is the write-side FIFO opened? */ + + if (ret == OK) + { + DEBUGASSERT(conn->lc_outfd >= 0); + + /* Open the server-side read-only FIFO. This should not + * block because the client side has already opening it + * for writing. + */ + + ret = local_open_server_rx(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to open read-only FIFOs for %s: %d\n", + conn->lc_path, ret); + } + } + + /* Do we have a connection? Are the FIFOs opened? */ + + if (ret == OK) + { + DEBUGASSERT(conn->lc_infd >= 0); + + /* Add the waiting connection to list of clients */ + + dq_addlast(&client->lc_node, &server->u.server.lc_conns); + + /* Return the address family */ + + if (addr) + { + FAR struct sockaddr_un *unaddr; + int totlen; + int pathlen; + + /* If an address is provided, then the length must also be + * provided. + */ + + DEBUGASSERT(addrlen); + + /* Get the length of the path (minus the NUL terminator) + * and the length of the whole client address. + */ + + pathlen = strnlen(client->lc_path, UNIX_PATH_MAX-1); + totlen = sizeof(sa_family_t) + pathlen + 1; + + /* If the length of the whole client address is larger + * than the buffer provided by the caller, then truncate + * the address to fit. + */ + + if (totlen > *addrlen) + { + pathlen -= (totlen - *addrlen); + totlen = *addrlen; + } + + /* Copy the Unix domain address */ + + unaddr = (FAR struct sockaddr_un *)addr; + unaddr->sun_family = AF_LOCAL; + memcpy(unaddr->sun_path, client->lc_path, pathlen); + unaddr->sun_path[pathlen] = '\0'; + + /* Return the Unix domain address size */ + + *addrlen = totlen; + } + + /* Return the client connection structure */ + + *newconn = (FAR void *)conn; + } + + /* Signal the client with the result of the connection */ + + client->u.client.lc_result = ret; + sem_post(&client->lc_waitsem); + return ret; + } + + /* No.. then there should be no pending connections */ + + DEBUGASSERT(server->u.server.lc_pending == 0); + + /* Was the socket opened non-blocking? */ + + if (_SS_ISNONBLOCK(psock->s_flags)) + { + /* Yes.. return EAGAIN */ + + return -EAGAIN; + } + + /* Otherwise, listen for a connection and try again. */ + + ret = local_listen(server, server->u.server.lc_backlog); + if (ret < 0) + { + return ret; + } + } +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_bind.c b/nuttx/net/local/local_bind.c new file mode 100644 index 000000000..5a469f786 --- /dev/null +++ b/nuttx/net/local/local_bind.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * net/local/local_bind.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/socket.h> +#include <string.h> +#include <assert.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_bind + * + * Description: + * This function implements the low-level parts of the standard local + * bind()operation. + * + ****************************************************************************/ + +int local_bind(FAR struct local_conn_s *conn, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR const struct sockaddr_un *unaddr = + (FAR const struct sockaddr_un *)addr; + int namelen; + + DEBUGASSERT(conn && unaddr && unaddr->sun_family == AF_LOCAL && + addrlen >= sizeof(sa_family_t)); + + /* Save the address family */ + + conn->lc_family = unaddr->sun_family; + + /* No determine the type of the Unix domain socket by comparing the size + * of the address description. + */ + + if (addrlen == sizeof(sa_family_t)) + { + /* No sun_path... This is an un-named Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_UNNAMED; + } + else + { + namelen = strnlen(unaddr->sun_path, UNIX_PATH_MAX-1); + if (namelen <= 0) + { + /* Zero-length sun_path... This is an abstract Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_ABSTRACT; + conn->lc_path[0] = '\0'; + } + else + { + /* This is an normal, pathname Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_PATHNAME; + + /* Copy the path into the connection structure */ + + (void)strncpy(conn->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1); + conn->lc_path[UNIX_PATH_MAX-1] = '\0'; + } + } + + conn->lc_state = LOCAL_STATE_BOUND; + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_conn.c b/nuttx/net/local/local_conn.c new file mode 100644 index 000000000..171313b29 --- /dev/null +++ b/nuttx/net/local/local_conn.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * net/local/local_conn.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <semaphore.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_initialize + * + * Description: + * Initialize the local, Unix domain connection structures. Called once + * and only from the common network initialization logic. + * + ****************************************************************************/ + + void local_initialize(void) +{ + dq_init(&g_local_listeners); +} + +/**************************************************************************** + * Name: local_alloc() + * + * Description: + * Allocate a new, uninitialized Unix domain socket connection structure. + * This is normally something done by the implementation of the socket() + * API + * + ****************************************************************************/ + +FAR struct local_conn_s *local_alloc(void) +{ + FAR struct local_conn_s *conn = + (FAR struct local_conn_s *)kmm_zalloc(sizeof(struct local_conn_s)); + + if (conn) + { + /* Initialize non-zero elements the new connection structure */ + + conn->lc_infd = -1; + conn->lc_outfd = -1; + sem_init(&conn->lc_waitsem, 0, 0); + } + + return conn; +} + +/**************************************************************************** + * Name: local_free() + * + * Description: + * Free a packet Unix domain connection structure that is no longer in use. + * This should be done by the implementation of close(). + * + ****************************************************************************/ + +void local_free(FAR struct local_conn_s *conn) +{ + DEBUGASSERT(conn != NULL); + + /* Make sure that the read-only FIFO is closed */ + + if (conn->lc_infd >= 0) + { + close(conn->lc_infd); + } + + /* Make sure that the write-only FIFO is closed */ + + if (conn->lc_outfd >= 0) + { + close(conn->lc_outfd); + } + + /* Destroy all FIFOs associted with the connection */ + + local_destroy_fifos(conn); + sem_destroy(&conn->lc_waitsem); + + /* And free the connection structure */ + + kmm_free(conn); +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_connect.c b/nuttx/net/local/local_connect.c new file mode 100644 index 000000000..fdc0bd74e --- /dev/null +++ b/nuttx/net/local/local_connect.c @@ -0,0 +1,303 @@ +/**************************************************************************** + * net/local/local_connnect.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "utils/utils.h" +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _local_semtake() and _local_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static inline void _local_semtake(sem_t *sem) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + ASSERT(*get_errno_ptr() == EINTR); + } +} + +#define _local_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: local_stream_connect + * + * Description: + * Find a local connection structure that is the appropriate "server" + * connection to be used with the provided "client" connection. + * + * Returned Values: + * Zero (OK) returned on success; A negated errno value is returned on a + * failure. Possible failures include: + * + * Assumptions: + * The network is locked on entry, unlocked on return. This logic is + * an integral part of the lock_connect() implementation and was + * separated out only to improve readability. + * + ****************************************************************************/ + +int inline local_stream_connect(FAR struct local_conn_s *client, + FAR struct local_conn_s *server, + net_lock_t state) +{ + int ret; + + /* Has server backlog been reached? + * NOTE: The backlog will be zero if listen() has never been called by the + * server. + */ + + if (server->lc_state != LOCAL_STATE_LISTENING || + server->u.server.lc_pending >= server->u.server.lc_backlog) + { + net_unlock(state); + ndbg("ERROR: Server is not listening: lc_state=%d\n", + server->lc_state); + ndbg(" OR: The backlog limit was reached: %d or %d\n", + server->u.server.lc_pending, server->u.server.lc_backlog); + return -ECONNREFUSED; + } + + /* Increment the number of pending server connection s*/ + + server->u.server.lc_pending++; + DEBUGASSERT(server->u.server.lc_pending != 0); + + /* Create the FIFOs needed for the connection */ + + ret = local_create_fifos(client); + if (ret < 0) + { + ndbg("ERROR: Failed to create FIFOs for %s: %d\n", + client->lc_path, ret); + return ret; + } + + /* Open the client-side write-only FIFO. This should not block and should + * prevent the server-side from blocking as well. + */ + + ret = local_open_client_tx(client); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + client->lc_path, ret); + goto errout_with_fifos; + } + + DEBUGASSERT(client->lc_outfd >= 0); + + /* Add ourself to the list of waiting connections and notify the server. */ + + dq_addlast(&client->lc_node, &server->u.server.lc_waiters); + client->lc_state = LOCAL_STATE_ACCEPT; + _local_semgive(&server->lc_waitsem); + net_unlock(state); + + /* Wait for the server to accept the connections */ + + client->u.client.lc_result = -EBUSY; + do + { + _local_semtake(&client->lc_waitsem); + ret = client->u.client.lc_result; + } + while (ret == -EBUSY); + + /* Did we successfully connect? */ + + if (ret < 0) + { + ndbg("ERROR: Failed to connect: %d\n", ret); + goto errout_with_outfd; + } + + /* Yes.. open the read-only FIFO */ + + ret = local_open_client_tx(client); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + client->lc_path, ret); + goto errout_with_outfd; + } + + DEBUGASSERT(client->lc_infd >= 0); + client->lc_state = LOCAL_STATE_CONNECTED; + return OK; + +errout_with_outfd: + (void)close(client->lc_outfd); + +errout_with_fifos: + (void)local_destroy_fifos(client); + client->lc_state = LOCAL_STATE_BOUND; + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_connect + * + * Description: + * Find a local connection structure that is the appropriate "server" + * connection to be used with the provided "client" connection. + * + * Returned Values: + * Zero (OK) returned on success; A negated errno value is returned on a + * failure. Possible failures include: + * + * EISCONN - The specified socket is connection-mode and is already + * connected. + * EADDRNOTAVAIL - The specified address is not available from the + * local machine. + * ECONNREFUSED - The target address was not listening for connections or + * refused the connection request because the connection backlog has + * been exceeded. + * + ****************************************************************************/ + +int local_connect(FAR struct local_conn_s *client, + FAR const struct sockaddr *addr) +{ + FAR struct local_conn_s *conn; + net_lock_t state; + + DEBUGASSERT(client); + + if (client->lc_state == LOCAL_STATE_ACCEPT || + client->lc_state == LOCAL_STATE_CONNECTED) + { + return -EISCONN; + } + + /* Find the matching server connection */ + + state = net_lock(); + for(conn = (FAR struct local_conn_s *)g_local_listeners.head; + conn; + conn = (FAR struct local_conn_s *)dq_next(&conn->lc_node)) + { + /* Skip over connections that that have not yet been bound, + * are or a different address family, or are of a different type. + */ + + if (conn->lc_state == LOCAL_STATE_UNBOUND || + conn->lc_state == LOCAL_STATE_CLOSED || + conn->lc_family != client->lc_family || + conn->lc_type != client->lc_type) + { + continue; + } + + /* Handle according to the connection type */ + + switch (client->lc_type) + { + case LOCAL_TYPE_UNNAMED: /* A Unix socket that is not bound to any name */ + case LOCAL_TYPE_ABSTRACT: /* lc_path is length zero */ + { +#warning Missing logic + net_unlock(state); + return OK; + } + break; + + case LOCAL_TYPE_PATHNAME: /* lc_path holds a null terminated string */ + { + if (strncmp(client->lc_path, conn->lc_path, UNIX_PATH_MAX-1) == 0) + { + /* We have to do more for the SOCK_STREAM family */ + + if (conn->lc_family == SOCK_STREAM) + { + return local_stream_connect(client, conn, state); + } + + net_unlock(state); + return OK; + } + } + break; + + default: /* Bad, memory must be corrupted */ + DEBUGPANIC(); /* PANIC if debug on, else fall through */ + + case LOCAL_TYPE_UNTYPED: /* Type is not determined until the socket is bound */ + { + net_unlock(state); + return -EINVAL; + } + } + } + + net_unlock(state); + return -EADDRNOTAVAIL; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_fifo.c b/nuttx/net/local/local_fifo.c new file mode 100644 index 000000000..15ded2932 --- /dev/null +++ b/nuttx/net/local/local_fifo.c @@ -0,0 +1,407 @@ +/**************************************************************************** + * net/local/local_fifo.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/stat.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#define LOCAL_RX_SUFFIX "RX" +#define LOCAL_TX_SUFFIX "TX" +#define LOCAL_SUFFIX_LEN 2 + +#define LOCAL_FULLPATH_LEN (UNIX_PATH_MAX + LOCAL_SUFFIX_LEN) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_rx_name + * + * Description: + * Create the name of the RX (client-to-server) FIFO name. + * + ****************************************************************************/ + +static inline void local_rx_name(FAR struct local_conn_s *conn, + FAR char *path) +{ + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_RX_SUFFIX, + conn->lc_path); + path[LOCAL_FULLPATH_LEN-1] = '\0'; +} + +/**************************************************************************** + * Name: local_tx_name + * + * Description: + * Create the name of the TX (server-to-client) FIFO name. + * + ****************************************************************************/ + +static inline void local_tx_name(FAR struct local_conn_s *conn, + FAR char *path) +{ + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_TX_SUFFIX, + conn->lc_path); + path[LOCAL_FULLPATH_LEN-1] = '\0'; +} + +/**************************************************************************** + * Name: local_fifo_exists + * + * Description: + * Check if a FIFO exists. + * + ****************************************************************************/ + +static bool local_fifo_exists(FAR const char *path) +{ + struct stat buf; + int ret; + + /* Create the client-to-server FIFO */ + + ret = stat(path, &buf); + if (ret < 0) + { + return false; + } + + /* FIFOs are character devices in NuttX. Return true if what we found + * is a FIFO. What if it is something else? In that case, we will + * return false and mkfifo() will fail. + */ + + return (bool)S_ISCHR(buf.st_mode); +} + +/**************************************************************************** + * Name: local_create_fifo + * + * Description: + * Create the one of FIFOs needed for a connection. + * + ****************************************************************************/ + +static int local_create_fifo(FAR const char *path) +{ + int ret; + + /* Create the client-to-server FIFO if it does not already exist. */ + + if (!local_fifo_exists(path)) + { + ret = mkfifo(path, 0644); + if (ret < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed to create FIFO %s: %d\n", path, errcode); + return -errcode; + } + } + + /* The FIFO (or some character driver) exists at PATH or we successfully + * created the FIFO at that location. + */ + + return OK; +} + +/**************************************************************************** + * Name: local_destroy_fifo + * + * Description: + * Destroy one of the FIFOs used in a connection. + * + ****************************************************************************/ + +static int local_destroy_fifo(FAR const char *path) +{ + int ret; + + /* Unlink the client-to-server FIFO if it exists. */ + + if (local_fifo_exists(path)) + { + ret = unlink(path); + if (ret < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed to unlink FIFO %s: %d\n", path, errcode); + return -errcode; + } + } + + /* The FIFO does not exist or we successfully unlinked it. */ + + return OK; +} + +/**************************************************************************** + * Name: local_rx_open + * + * Description: + * Open a FIFO for read-only access. + * + ****************************************************************************/ + +static inline int local_rx_open(FAR struct local_conn_s *conn, + FAR const char *path) +{ + conn->lc_infd = open(path, O_RDONLY); + if (conn->lc_infd < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed on open %s for reading: %d\n", + path, errcode); + + /* Map the errcode to something consistent with the return + * error codes from connect(): + * + * If errcode is ENOENT, meaning that the FIFO does exist, + * return EFAULT meaning that the socket structure address is + * outside the user's address space. + */ + + return errcode == ENOENT ? -EFAULT : -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: local_tx_open + * + * Description: + * Open a FIFO for write-only access. + * + ****************************************************************************/ + +static inline int local_tx_open(FAR struct local_conn_s *conn, + FAR const char *path) +{ + conn->lc_infd = open(path, O_WRONLY); + if (conn->lc_infd < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed on open %s for writing: %d\n", + path, errcode); + + /* Map the errcode to something consistent with the return + * error codes from connect(): + * + * If errcode is ENOENT, meaning that the FIFO does exist, + * return EFAULT meaning that the socket structure address is + * outside the user's address space. + */ + + return errcode == ENOENT ? -EFAULT : -errcode; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_create_fifos + * + * Description: + * Create the FIFO pair needed for a connection. + * + ****************************************************************************/ + +int local_create_fifos(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + int ret; + + /* Create the client-to-server FIFO if it does not already exist. */ + + local_tx_name(client, path); + ret = local_create_fifo(path); + if (ret >= 0) + { + /* Create the server-to-client FIFO if it does not already exist. */ + + local_rx_name(client, path); + ret = local_create_fifo(path); + } + + return ret; +} + +/**************************************************************************** + * Name: local_destroy_fifos + * + * Description: + * Destroy the FIFO pair used for a connection. + * + ****************************************************************************/ + +int local_destroy_fifos(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + int ret1; + int ret2; + + /* Destroy the client-to-server FIFO if it exists. */ + + local_tx_name(client, path); + ret1 = local_destroy_fifo(path); + + /* Destroy the server-to-client FIFO if it exists. */ + + local_rx_name(client, path); + ret2 = local_create_fifo(path); + + /* Return a failure if one occurred. */ + + return ret1 < 0 ? ret1 : ret2; +} + +/**************************************************************************** + * Name: local_open_client_rx + * + * Description: + * Only the client-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_client_rx(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_tx_name(client, path); + + /* Then open the file for read-only access */ + + return local_rx_open(client, path); +} + +/**************************************************************************** + * Name: local_open_client_tx + * + * Description: + * Only the client-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_client_tx(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the client-to-server path name */ + + local_rx_name(client, path); + + /* Then open the file for write-only access */ + + return local_tx_open(client, path); +} + +/**************************************************************************** + * Name: local_open_server_rx + * + * Description: + * Only the server-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_server_rx(FAR struct local_conn_s *server) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the client-to-server path name */ + + local_rx_name(server, path); + + /* Then open the file for write-only access */ + + return local_rx_open(server, path); +} + +/**************************************************************************** + * Name: local_open_server_tx + * + * Description: + * Only the server-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_server_tx(FAR struct local_conn_s *server) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_tx_name(server, path); + + /* Then open the file for read-only access */ + + return local_tx_open(server, path); +} +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_listen.c b/nuttx/net/local/local_listen.c new file mode 100644 index 000000000..545908820 --- /dev/null +++ b/nuttx/net/local/local_listen.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * net/local/local_listen.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <assert.h> +#include <queue.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* A list of all allocated packet socket connections */ + +dq_queue_t g_local_listeners; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_listen + * + * Description: + * Listen for a new connection of a SOCK_STREAM Unix domain socket. + * + * 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. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * The network is NOT locked + * + ****************************************************************************/ + +int local_listen(FAR struct local_conn_s *server, int backlog) +{ + net_lock_t state; + int ret; + + /* Some sanity checks */ + + DEBUGASSERT(server); + + if (server->lc_family != SOCK_STREAM || + server->lc_state == LOCAL_STATE_UNBOUND || + server->lc_type != LOCAL_TYPE_PATHNAME) + { + return -EOPNOTSUPP; + } + + DEBUGASSERT(server->lc_state == LOCAL_STATE_BOUND || + server->lc_state == LOCAL_STATE_LISTENING); + + /* Set the backlog value */ + + DEBUGASSERT((unsigned)backlog < 256); + server->u.server.lc_backlog = backlog; + + /* Is this the first time since being bound to an address and that + * listen() was called? If so, the state should be LOCAL_STATE_BOUND. + */ + + if (server->lc_state == LOCAL_STATE_BOUND) + { + /* The connection should not reside in any other list */ + + DEBUGASSERT(server->lc_node.flink == NULL && + server->lc_node.flink == NULL); + + /* Add the connection structure to the list of listeners */ + + state = net_lock(); + dq_addlast(&server->lc_node, &g_local_listeners); + net_unlock(state); + + /* And change the server state to listing */ + + server->lc_state = LOCAL_STATE_LISTENING; + } + + /* Loop until a connection is requested or we receive a signal */ + + while (dq_empty(&server->u.server.lc_waiters)) + { + /* No.. wait for a connection or a signal */ + + ret = sem_wait(&server->lc_waitsem); + if (ret < 0) + { + int errval = errno; + DEBUGASSERT(errval == EINTR); + return -errval; + } + } + + /* There is a client waiting for the connection */ + + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_recvfrom.c b/nuttx/net/local/local_recvfrom.c new file mode 100644 index 000000000..c31bec1f2 --- /dev/null +++ b/nuttx/net/local/local_recvfrom.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * net/local/local_recvfrom.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_recvfrom + * + * Description: + * recvfrom() receives messages from a local socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on errors, -1 is returned, and errno + * is set appropriately (see receivefrom for the complete list). + * + ****************************************************************************/ + +ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) +{ +#warning Missing logic + return -ENOSYS; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_release.c b/nuttx/net/local/local_release.c new file mode 100644 index 000000000..d69a0a3da --- /dev/null +++ b/nuttx/net/local/local_release.c @@ -0,0 +1,183 @@ +/**************************************************************************** + * net/local/local_release.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <semaphore.h> +#include <errno.h> +#include <queue.h> +#include <assert.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_release + * + * Description: + * If the local, Unix domain socket is in the connected state, then + * disconnect it. Release the local connection structure in any event + * + * Input Parameters: + * conn - A reference to local connection structure + * + ****************************************************************************/ + +int local_release(FAR struct local_conn_s *conn) +{ + net_lock_t state; + + /* There should be no references on this structure */ + + DEBUGASSERT(conn->lc_crefs == 0); + state = net_lock(); + + /* We should not bet here with states LOCAL_STATE_CLOSED or with + * LOCAL_STATE_ACCEPT. Those are internal states that should be atomic + * with respect to socket operations. + */ + + DEBUGASSERT(conn->lc_state != LOCAL_STATE_CLOSED && + conn->lc_state != LOCAL_STATE_ACCEPT); + + /* If the socket is connected (SOCK_STREAM client), then disconnect it */ + + if (conn->lc_state == LOCAL_STATE_CONNECTED || + conn->lc_state == LOCAL_STATE_DISCONNECTED) + { + FAR struct local_conn_s *server; + + DEBUGASSERT(conn->lc_family == SOCK_STREAM); + + server = conn->u.client.lc_server; + DEBUGASSERT(server && + (server->lc_state == LOCAL_STATE_LISTENING || + server->lc_state == LOCAL_STATE_CLOSED) && + !dq_empty(&server->u.server.lc_conns)); + + /* Remove ourself from the list of connections */ + + dq_rem(&conn->lc_node, &server->u.server.lc_conns); + + /* Is the list of pending connections now empty? Was the connection + * already closed? + */ + + if (dq_empty(&server->u.server.lc_waiters) && + server->lc_state == LOCAL_STATE_CLOSED) + { + /* Yes, free the server connection as well */ + + local_free(server); + } + + /* Now we can free this connection structure */ + + local_free(conn); + } + + /* Is the socket is listening socket (SOCK_STREAM server) */ + + else if (conn->lc_state == LOCAL_STATE_LISTENING) + { + FAR struct local_conn_s *client; + FAR struct local_conn_s *next; + + DEBUGASSERT(conn->lc_family == SOCK_STREAM); + + /* Are there still clients waiting for a connection to the server? */ + + for (client = (FAR struct local_conn_s *)conn->u.server.lc_waiters.head; + client; + client = (FAR struct local_conn_s *)dq_next(&client->lc_node)) + { + client->u.client.lc_result = -ENOTCONN; + sem_post(&client->lc_waitsem); + conn->lc_state = LOCAL_STATE_CLOSED; + } + + conn->u.server.lc_pending = 0; + + /* Disconnect any previous client connections */ + + for (client = (FAR struct local_conn_s *)conn->u.server.lc_conns.head; + client; + client = next) + { + next = (FAR struct local_conn_s *)dq_next(&client->lc_node); + dq_rem(&client->lc_node, &conn->u.server.lc_conns); + client->lc_state = LOCAL_STATE_DISCONNECTED; + } + + /* Remove the server from the list of listeners */ + + dq_rem(&conn->lc_node, &g_local_listeners); + + /* Can we free the connection structure now? We cannot + * if there are still pending connection requested to + * be resolved. + */ + + conn->u.server.lc_backlog = 0; + if (conn->lc_state == LOCAL_STATE_CLOSED) + { + local_free(conn); + } + } + + /* For the remaining states (LOCAL_STATE_UNBOUND and LOCAL_STATE_UNBOUND), + * we simply free the connection structure. + */ + + else + { + local_free(conn); + } + + net_unlock(state); + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_send.c b/nuttx/net/local/local_send.c new file mode 100644 index 000000000..b0cb1d22f --- /dev/null +++ b/nuttx/net/local/local_send.c @@ -0,0 +1,80 @@ +/**************************************************************************** + * net/local/local_send.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_local_send + * + * Description: + * Send a local packet as a stream. + * + * Parameters: + * psock An instance of the internal socket structure. + * buf Data to send + * len Length of data to send + * flags Send flags + * + * Return: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see send() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags) +{ +#warning Missing logic + return -ENOSYS; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_sendto.c b/nuttx/net/local/local_sendto.c new file mode 100644 index 000000000..a44333d6f --- /dev/null +++ b/nuttx/net/local/local_sendto.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * net/local/local_sendto.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_sendto + * + * Description: + * Send a local packet as a datagram. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see sendto() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen) +{ +#warning Missing logic + return -ENOSYS; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/net_initialize.c b/nuttx/net/net_initialize.c index 371b30987..469270577 100644 --- a/nuttx/net/net_initialize.c +++ b/nuttx/net/net_initialize.c @@ -53,6 +53,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "igmp/igmp.h" #include "route/route.h" #include "utils/utils.h" @@ -128,6 +129,12 @@ void net_initialize(void) pkt_initialize(); #endif +#ifdef CONFIG_NET_UDP + /* Initialize the local, "Unix domain" socket support */ + + local_initialize(); +#endif + #ifdef CONFIG_NET_TCP /* Initialize the listening port structures */ diff --git a/nuttx/net/pkt/pkt.h b/nuttx/net/pkt/pkt.h index 61fd45387..bf50889d5 100644 --- a/nuttx/net/pkt/pkt.h +++ b/nuttx/net/pkt/pkt.h @@ -100,7 +100,7 @@ extern "C" * * Description: * Initialize the packet socket connection structures. Called once and - * only from the UIP layer. + * only from the network initialization logic. * ****************************************************************************/ diff --git a/nuttx/net/pkt/pkt_conn.c b/nuttx/net/pkt/pkt_conn.c index 50a71c0c8..c47eea2d1 100644 --- a/nuttx/net/pkt/pkt_conn.c +++ b/nuttx/net/pkt/pkt_conn.c @@ -71,7 +71,7 @@ static struct pkt_conn_s g_pkt_connections[CONFIG_NET_PKT_CONNS]; static dq_queue_t g_free_pkt_connections; static sem_t g_free_sem; -/* A list of all allocated packet scoket connections */ +/* A list of all allocated packet socket connections */ static dq_queue_t g_active_pkt_connections; @@ -129,6 +129,7 @@ void pkt_initialize(void) for (i = 0; i < CONFIG_NET_PKT_CONNS; i++) { /* Mark the connection closed and move it to the free list */ + g_pkt_connections[i].ifindex = 0; dq_addlast(&g_pkt_connections[i].node, &g_free_pkt_connections); } diff --git a/nuttx/net/socket/Make.defs b/nuttx/net/socket/Make.defs index 44645261a..0859d28a8 100644 --- a/nuttx/net/socket/Make.defs +++ b/nuttx/net/socket/Make.defs @@ -43,6 +43,13 @@ SOCK_CSRCS += net_clone.c net_poll.c net_vfcntl.c ifeq ($(CONFIG_NET_TCP),y) SOCK_CSRCS += send.c listen.c accept.c net_monitor.c +else + +# Local Unix domain support + +ifeq ($(CONFIG_NET_LOCAL),y) +SOCK_CSRCS += send.c listen.c accept.c +endif endif # Socket options diff --git a/nuttx/net/socket/accept.c b/nuttx/net/socket/accept.c index 1a4dbd04c..5cddaa264 100644 --- a/nuttx/net/socket/accept.c +++ b/nuttx/net/socket/accept.c @@ -43,161 +43,19 @@ #include <sys/types.h> #include <sys/socket.h> -#include <semaphore.h> -#include <string.h> #include <errno.h> #include <assert.h> #include <debug.h> -#include <arch/irq.h> - -#include <nuttx/net/net.h> -#include <nuttx/net/ip.h> - #include "tcp/tcp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct accept_s -{ - FAR struct socket *acpt_sock; /* The accepting socket */ - sem_t acpt_sem; /* Wait for interrupt event */ - FAR struct sockaddr *acpt_addr; /* Return connection address */ - FAR struct tcp_conn_s *acpt_newconn; /* The accepted connection */ - int acpt_result; /* The result of the wait */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Function: accept_tcpsender - * - * Description: - * Get the sender's address from the UDP packet - * - * Parameters: - * psock - The state structure of the accepting socket - * conn - The newly accepted TCP connection - * pstate - the recvfrom state structure - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level -* - ****************************************************************************/ - -#ifdef CONFIG_NET_TCP -static inline void accept_tcpsender(FAR struct socket *psock, - FAR struct tcp_conn_s *conn, - FAR struct sockaddr *addr) -{ - if (addr) - { -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - /* If both IPv4 and IPv6 support are enabled, then we will need to - * select which one to use when obtaining the sender's IP address. - */ - - if (psock->s_domain == PF_INET) -#endif /* CONFIG_NET_IPv6 */ - { - FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; - - inaddr->sin_family = AF_INET; - inaddr->sin_port = conn->rport; - net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - /* Otherwise, this the IPv6 address is needed */ - - else -#endif /* CONFIG_NET_IPv4 */ - { - FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; - - DEBUGASSERT(psock->s_domain == PF_INET6); - inaddr->sin6_family = AF_INET6; - inaddr->sin6_port = conn->rport; - net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); - } -#endif /* CONFIG_NET_IPv6 */ - } -} -#endif /* CONFIG_NET_TCP */ - -/**************************************************************************** - * Function: accept_interrupt - * - * Description: - * Receive interrupt level callbacks when connections occur - * - * Parameters: - * listener The conection stucture of the listener - * conn The connection stucture that was just accepted - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -static int accept_interrupt(FAR struct tcp_conn_s *listener, - FAR struct tcp_conn_s *conn) -{ - struct accept_s *pstate = (struct accept_s *)listener->accept_private; - int ret = -EINVAL; - - if (pstate) - { - /* Get the connection address */ - - accept_tcpsender(pstate->acpt_sock, conn, pstate->acpt_addr); - - /* Save the connection structure */ - - pstate->acpt_newconn = conn; - pstate->acpt_result = OK; - - /* There should be a reference of one on the new connection */ - - DEBUGASSERT(conn->crefs == 1); - - /* Wake-up the waiting caller thread */ - - sem_post(&pstate->acpt_sem); - - /* Stop any further callbacks */ - - listener->accept_private = NULL; - listener->accept = NULL; - ret = OK; - } - - return ret; -} - -/**************************************************************************** * Public Functions ****************************************************************************/ @@ -229,7 +87,7 @@ static int accept_interrupt(FAR struct tcp_conn_s *listener, * connections are present on the queue, accept returns EAGAIN. * * Parameters: - * sockfd The listening socket descriptior + * sockfd The listening socket descriptor * addr Receives the address of the connecting client * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' * @@ -275,9 +133,6 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { FAR struct socket *psock = sockfd_socket(sockfd); FAR struct socket *pnewsock; - FAR struct tcp_conn_s *conn; - struct accept_s state; - net_lock_t save; int newfd; int err; int ret; @@ -327,6 +182,12 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) if (addr) { + /* If an address is provided, then the lenght must also be provided. */ + + DEBUGASSERT(addrlen); + + /* A valid length depends on the address domain */ + switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 @@ -353,6 +214,18 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) break; #endif /* CONFIG_NET_IPv6 */ +#ifdef CONFIG_NET_LOCAL + case PF_LOCAL: + { + if (*addrlen < sizeof(sa_family_t)) + { + err = EBADF; + goto errout; + } + } + break; +#endif /* CONFIG_NET_IPv6 */ + default: DEBUGPANIC(); err = EINVAL; @@ -378,132 +251,60 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) goto errout_with_socket; } - /* Check the backlog to see if there is a connection already pending for - * this listener. - */ + /* Initialize the socket structure and mark the socket as connected. */ - save = net_lock(); - conn = (struct tcp_conn_s *)psock->s_conn; - -#ifdef CONFIG_NET_TCPBACKLOG - state.acpt_newconn = tcp_backlogremove(conn); - if (state.acpt_newconn) - { - /* Yes... get the address of the connected client */ - - nvdbg("Pending conn=%p\n", state.acpt_newconn); - accept_tcpsender(psock, state.acpt_newconn, addr); - } + pnewsock->s_domain = psock->s_domain; + pnewsock->s_type = SOCK_STREAM; + pnewsock->s_flags |= _SF_CONNECTED; + pnewsock->s_flags &= ~_SF_CLOSED; - /* In general, this uIP-based implementation will not support non-blocking - * socket operations... except in a few cases: Here for TCP accept with backlog - * enabled. If this socket is configured as non-blocking then return EAGAIN - * if there is no pending connection in the backlog. - */ + /* Perform the correct accept operation for this address domain */ - else if (_SS_ISNONBLOCK(psock->s_flags)) - { - err = EAGAIN; - goto errout_with_lock; - } - else +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) #endif { - /* Set the socket state to accepting */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); - - /* Perform the TCP accept operation */ - - /* Initialize the state structure. This is done with interrupts - * disabled because we don't want anything to happen until we - * are ready. - */ + /* Perform the local accept operation (with the network unlocked) */ - state.acpt_sock = psock; - state.acpt_addr = addr; - state.acpt_newconn = NULL; - state.acpt_result = OK; - sem_init(&state.acpt_sem, 0, 0); - - /* Set up the callback in the connection */ - - conn->accept_private = (void*)&state; - conn->accept = accept_interrupt; - - /* Wait for the send to complete or an error to occur: NOTES: (1) - * net_lockedwait will also terminate if a signal is received, (2) - * interrupts may be disabled! They will be re-enabled while the - * task sleeps and automatically re-enabled when the task restarts. - */ - - ret = net_lockedwait(&state.acpt_sem); + ret = psock_local_accept(psock, addr, addrlen, &pnewsock->s_conn); if (ret < 0) { - /* The value returned by net_lockedwait() the same as the value - * returned by sem_wait(): Zero (OK) is returned on success; -1 - * (ERROR) is returned on a failure with the errno value set - * appropriately. - * - * We have to preserve the errno value here because it may be - * altered by intervening operations. - */ - - err = get_errno(); + err = -ret; + goto errout_with_socket; } + } +#endif /* CONFIG_NET_LOCAL */ - /* Make sure that no further interrupts are processed */ - - conn->accept_private = NULL; - conn->accept = NULL; - - sem_destroy(&state. acpt_sem); - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + net_lock_t state; - /* Check for a errors. Errors are signalled by negative errno values - * for the send length. - */ + /* Perform the local accept operation (with the network locked) */ - if (state.acpt_result != 0) + state = net_lock(); + ret = psock_tcp_accept(psock, addr, addrlen, &pnewsock->s_conn); + if (ret < 0) { - err = state.acpt_result; - goto errout_with_lock; + net_unlock(state); + err = -ret; + goto errout_with_socket; } - /* If net_lockedwait failed, then we were probably reawakened by a - * signal. In this case, logic above will have set 'err' to the - * ernno value returned by net_lockedwait(). + /* Begin monitoring for TCP connection events on the newly connected + * socket */ - if (ret < 0) - { - goto errout_with_lock; - } + net_startmonitor(pnewsock); + net_unlock(state); } +#endif /* CONFIG_NET_TCP */ - /* Initialize the socket structure and mark the socket as connected. - * (The reference count on the new connection structure was set in the - * interrupt handler). - */ - - pnewsock->s_domain = psock->s_domain; - pnewsock->s_type = SOCK_STREAM; - pnewsock->s_conn = state.acpt_newconn; - pnewsock->s_flags |= _SF_CONNECTED; - pnewsock->s_flags &= ~_SF_CLOSED; - - /* Begin monitoring for TCP connection events on the newly connected socket */ - - net_startmonitor(pnewsock); - net_unlock(save); return newfd; -errout_with_lock: - net_unlock(save); - errout_with_socket: sockfd_release(newfd); diff --git a/nuttx/net/socket/bind.c b/nuttx/net/socket/bind.c index d905e5aaf..6dc7de9ff 100644 --- a/nuttx/net/socket/bind.c +++ b/nuttx/net/socket/bind.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/bind.c * - * Copyright (C) 2007-2009, 2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/un.h> #include <errno.h> #include <string.h> #include <debug.h> @@ -58,6 +59,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" /**************************************************************************** * Private Functions @@ -116,8 +118,8 @@ static int pkt_bind(FAR struct pkt_conn_s *conn, * * Description: * 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 + * '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: @@ -175,6 +177,12 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, 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); @@ -204,18 +212,87 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, break; #endif -#ifdef CONFIG_NET_TCP + /* 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) case SOCK_STREAM: - ret = tcp_bind(psock->s_conn, addr); - psock->s_flags |= _SF_BOUND; + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + /* Is this a Unix domain socket? */ + + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Bind the Unix domain connection structure */ + + ret = local_bind(psock->s_conn, addr, addrlen); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + /* Bind the TCP/IP connection structure */ + + ret = tcp_bind(psock->s_conn, addr); + } +#endif /* CONFIG_NET_TCP */ + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } + } break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ + + /* 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) + case SOCK_DGRAM: + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + /* Is this a Unix domain socket? */ + + if (psock->s_domain == PF_LOCAL) #endif + { + /* Bind the Unix domain connection structure */ + + ret = local_bind(psock->s_conn, addr, addrlen); + } +#endif /* CONFIG_NET_LOCAL */ #ifdef CONFIG_NET_UDP - case SOCK_DGRAM: - ret = udp_bind(psock->s_conn, addr); - break; +#ifdef CONFIG_NET_LOCAL + else #endif + { + /* Bind the UDPP/IP connection structure */ + + ret = udp_bind(psock->s_conn, addr); + } +#endif /* CONFIG_NET_UDP */ + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } + } + break; +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ default: err = EBADF; diff --git a/nuttx/net/socket/connect.c b/nuttx/net/socket/connect.c index e152df888..88535210a 100644 --- a/nuttx/net/socket/connect.c +++ b/nuttx/net/socket/connect.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/connect.c * - * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2012, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -56,6 +56,7 @@ #include "devif/devif.h" #include "tcp/tcp.h" #include "udp/udp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -511,7 +512,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: { /* Verify that the socket is not already connected */ @@ -522,9 +523,30 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, goto errout; } - /* Its not ... connect it */ + /* It's not ... connect it */ + +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Connect to the local Unix domain server */ + + ret = local_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + /* Connect the TCP/IP socket */ + + ret = psock_tcp_connect(psock, addr); + } +#endif /* CONFIG_NET_TCP */ - ret = psock_tcp_connect(psock, addr); if (ret < 0) { err = -ret; @@ -532,12 +554,31 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, } } break; -#endif +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) case SOCK_DGRAM: { - ret = udp_connect(psock->s_conn, addr); +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Perform the datagram connection logic */ + + ret = local_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + ret = udp_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_UDP */ + if (ret < 0) { err = -ret; @@ -545,7 +586,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, } } break; -#endif +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ default: err = EBADF; diff --git a/nuttx/net/socket/listen.c b/nuttx/net/socket/listen.c index b9b8d1d5b..cdfc4d9d8 100644 --- a/nuttx/net/socket/listen.c +++ b/nuttx/net/socket/listen.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/listen.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include <debug.h> #include "tcp/tcp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -89,7 +90,6 @@ int listen(int sockfd, int backlog) { FAR struct socket *psock = sockfd_socket(sockfd); - struct tcp_conn_s *conn; int err; /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -111,39 +111,73 @@ int listen(int sockfd, int backlog) { err = EBADF; } + goto errout; } /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ - conn = (FAR struct tcp_conn_s *)psock->s_conn; - if (psock->s_type != SOCK_STREAM || !psock->s_conn || conn->lport <= 0) + if (psock->s_type != SOCK_STREAM || !psock->s_conn) { err = EOPNOTSUPP; goto errout; } - /* Set up the backlog for this connection */ - -#ifdef CONFIG_NET_TCPBACKLOG - err = tcp_backlogcreate(conn, backlog); - if (err < 0) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif { - err = -err; - goto errout; + FAR struct local_conn_s *conn = + (FAR struct local_conn_s *)psock->s_conn; + + err = local_listen(conn, backlog); + if (err < 0) + { + err = -err; + goto errout; + } } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + FAR struct tcp_conn_s *conn = + (FAR struct tcp_conn_s *)psock->s_conn; + + if (conn->lport <= 0) + { + err = EOPNOTSUPP; + goto errout; + } + + /* Set up the backlog for this connection */ + +#ifdef CONFIG_NET_TCPBACKLOG + err = tcp_backlogcreate(conn, backlog); + if (err < 0) + { + err = -err; + goto errout; + } #endif - /* Start listening to the bound port. This enables callbacks when accept() - * is called and enables poll()/select() logic. - */ + /* Start listening to the bound port. This enables callbacks when + * accept() is called and enables poll()/select() logic. + */ + + tcp_listen(conn); + } +#endif /* CONFIG_NET_TCP */ - tcp_listen(conn); psock->s_flags |= _SF_LISTENING; return OK; errout: - errno = err; + set_errno(err); return ERROR; } diff --git a/nuttx/net/socket/net_close.c b/nuttx/net/socket/net_close.c index a2ef7e91f..e33853fa7 100644 --- a/nuttx/net/socket/net_close.c +++ b/nuttx/net/socket/net_close.c @@ -63,6 +63,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -452,6 +453,45 @@ static inline int netclose_disconnect(FAR struct socket *psock) #endif /* CONFIG_NET_TCP */ /**************************************************************************** + * Function: local_close + * + * Description: + * Performs the close operation on a local socket instance + * + * Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_LOCAL +static void local_close(FAR struct socket *psock) +{ + FAR struct local_conn_s *conn = psock->s_conn; + + /* Is this the last reference to the connection structure (there could + * be more if the socket was dup'ed). + */ + + if (conn->lc_crefs <= 1) + { + conn->lc_crefs = 0; + local_release(conn); + } + else + { + /* No.. Just decrement the reference count */ + + conn->lc_crefs--; + } +} +#endif /* CONFIG_NET_LOCAL */ + +/**************************************************************************** * Public Functions ****************************************************************************/ @@ -493,71 +533,110 @@ int psock_close(FAR struct socket *psock) switch (psock->s_type) { -#ifdef CONFIG_NET_PKT - case SOCK_RAW: +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) + case SOCK_STREAM: { - FAR struct pkt_conn_s *conn = psock->s_conn; - - /* Is this the last reference to the connection structure (there - * could be more if the socket was dup'ed). - */ - - if (conn->crefs <= 1) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif { - /* Yes... free the connection structure */ + /* Release our reference to the local connection structure */ - conn->crefs = 0; /* No more references on the connection */ - pkt_free(psock->s_conn); /* Free uIP resources */ + local_close(psock); } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL else +#endif { - /* No.. Just decrement the reference count */ + FAR struct tcp_conn_s *conn = psock->s_conn; - conn->crefs--; + /* Is this the last reference to the connection structure + * (there could be more if the socket was dup'ed). + */ + + if (conn->crefs <= 1) + { + /* Yes... then perform the disconnection now */ + + tcp_unlisten(conn); /* No longer accepting connections */ + conn->crefs = 0; /* Discard our reference to the connection */ + + /* Break any current connections */ + + err = netclose_disconnect(psock); + if (err < 0) + { + /* This would normally occur only if there is a + * timeout from a lingering close. + */ + + goto errout_with_psock; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } } +#endif /* CONFIG_NET_TCP */ } break; #endif -#ifdef CONFIG_NET_TCP - case SOCK_STREAM: +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) + case SOCK_DGRAM: { - FAR struct tcp_conn_s *conn = psock->s_conn; +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Release our reference to the local connection structure */ - /* Is this the last reference to the connection structure (there - * could be more if the socket was dup'ed). - */ + local_close(psock); + } +#endif /* CONFIG_NET_LOCAL */ - if (conn->crefs <= 1) +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif { - /* Yes... then perform the disconnection now */ + FAR struct udp_conn_s *conn = psock->s_conn; + + /* Is this the last reference to the connection structure + * (there could be more if the socket was dup'ed). + */ - tcp_unlisten(conn); /* No longer accepting connections */ - conn->crefs = 0; /* Discard our reference to the connection */ - err = netclose_disconnect(psock); /* Break any current connections */ - if (err < 0) + if (conn->crefs <= 1) { - /* This would normally occur only if there is a timeout - * from a lingering close. - */ + /* Yes... free the connection structure */ - goto errout_with_psock; + conn->crefs = 0; + udp_free(psock->s_conn); } - } - else - { - /* No.. Just decrement the reference count */ + else + { + /* No.. Just decrement the reference count */ - conn->crefs--; + conn->crefs--; + } } +#endif /* CONFIG_NET_UDP */ } break; #endif -#ifdef CONFIG_NET_UDP - case SOCK_DGRAM: +#ifdef CONFIG_NET_PKT + case SOCK_RAW: { - FAR struct udp_conn_s *conn = psock->s_conn; + FAR struct pkt_conn_s *conn = psock->s_conn; /* Is this the last reference to the connection structure (there * could be more if the socket was dup'ed). @@ -568,7 +647,7 @@ int psock_close(FAR struct socket *psock) /* Yes... free the connection structure */ conn->crefs = 0; /* No more references on the connection */ - udp_free(psock->s_conn); /* Free uIP resources */ + pkt_free(psock->s_conn); /* Free uIP resources */ } else { diff --git a/nuttx/net/socket/recvfrom.c b/nuttx/net/socket/recvfrom.c index fe194ac86..669deb1a7 100644 --- a/nuttx/net/socket/recvfrom.c +++ b/nuttx/net/socket/recvfrom.c @@ -68,6 +68,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -1580,7 +1581,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, ****************************************************************************/ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, - int flags,FAR struct sockaddr *from, + int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { ssize_t ret; @@ -1645,30 +1646,72 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Read from the network interface driver buffer */ /* Or perform the TCP/IP or UDP recv() operation */ -#if defined(CONFIG_NET_PKT) - if (psock->s_type == SOCK_RAW) + switch (psock->s_type) { - ret = pkt_recvfrom(psock, buf, len, from); - } - else +#ifdef CONFIG_NET_PKT + case SOCK_RAW: + { + ret = pkt_recvfrom(psock, buf, len, from); + } + break; +#endif /* CONFIG_NET_PKT */ + +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) + case SOCK_STREAM: + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) #endif -#if defined(CONFIG_NET_TCP) - if (psock->s_type == SOCK_STREAM) - { - ret = tcp_recvfrom(psock, buf, len, from); - } - else + { + ret = psock_local_recvfrom(psock, buf, len, flags, + from, fromlen); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else #endif -#if defined(CONFIG_NET_UDP) - if (psock->s_type == SOCK_DGRAM) - { - ret = udp_recvfrom(psock, buf, len, from); - } - else + { + ret = tcp_recvfrom(psock, buf, len, from); + } +#endif /* CONFIG_NET_TCP */ + } + break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ + +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) + case SOCK_DGRAM: + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) #endif - { - ndbg("ERROR: Unsupported socket type: %d\n", psock->s_type); - ret = -ENOSYS; + { + ret = psock_local_recvfrom(psock, buf, len, flags, + from, fromlen); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + ret = udp_recvfrom(psock, buf, len, from); + } +#endif /* CONFIG_NET_UDP */ + } + break; +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ + + default: + { + ndbg("ERROR: Unsupported socket type: %d\n", psock->s_type); + ret = -ENOSYS; + } + break; } /* Set the socket state to idle */ diff --git a/nuttx/net/socket/send.c b/nuttx/net/socket/send.c index 1b7358481..ddcc97ea3 100644 --- a/nuttx/net/socket/send.c +++ b/nuttx/net/socket/send.c @@ -45,6 +45,7 @@ #include "tcp/tcp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -138,17 +139,31 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, case SOCK_RAW: { ret = psock_pkt_send(psock, buf, len); - break; } + break; #endif -#if defined(CONFIG_NET_TCP) case SOCK_STREAM: { - ret = psock_tcp_send(psock, buf, len); - break; - } +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif + { + ret = psock_local_send(psock, buf, len, flags); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else #endif + { + ret = psock_tcp_send(psock, buf, len); + } +#endif /* CONFIG_NET_TCP */ + } + break; default: { diff --git a/nuttx/net/socket/sendto.c b/nuttx/net/socket/sendto.c index 0134bde3c..85ce83f31 100644 --- a/nuttx/net/socket/sendto.c +++ b/nuttx/net/socket/sendto.c @@ -467,6 +467,12 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, break; #endif +#ifdef CONFIG_NET_IPv6 + case AF_LOCAL: + minlen = sizeof(sa_family_t); + break; +#endif + default: ndbg("ERROR: Unrecognized address family: %d\n", to->sa_family); err = EAFNOSUPPORT; @@ -511,9 +517,13 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, } #endif - /* Perform the UDP sendto operation */ +#ifdef CONFIG_NET_LOCAL + /* Perform the Unix domain sendto operation */ +# warning Missing logic +#endif #ifdef CONFIG_NET_UDP + /* Perform the UDP sendto operation */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); diff --git a/nuttx/net/socket/socket.c b/nuttx/net/socket/socket.c index 1ce2e0890..427dd7016 100644 --- a/nuttx/net/socket/socket.c +++ b/nuttx/net/socket/socket.c @@ -51,6 +51,153 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_tcp_alloc + * + * Description: + * Allocate and attach a TCP connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static int psock_tcp_alloc(FAR struct socket *psock) +{ + /* Allocate the TCP connection structure */ + + FAR struct tcp_conn_s *conn = tcp_alloc(psock->s_domain); + if (!conn) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Set the reference count on the connection structure. This reference + * count will be incremented only if the socket is dup'ed + */ + + DEBUGASSERT(conn->crefs == 0); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + return OK; +} +#endif /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Name: psock_udp_alloc + * + * Description: + * Allocate and attach a UDP connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP +static int psock_udp_alloc(FAR struct socket *psock) +{ + /* Allocate the UDP connection structure */ + + FAR struct udp_conn_s *conn = udp_alloc(psock->s_domain); + if (!conn) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Set the reference count on the connection structure. This reference + * count will be incremented only if the socket is dup'ed + */ + + DEBUGASSERT(conn->crefs == 0); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + return OK; +} +#endif /* CONFIG_NET_UDP */ + +/**************************************************************************** + * Name: psock_pkt_alloc + * + * Description: + * Allocate and attach a raw packet connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_PKT +static int psock_pkt_alloc(FAR struct socket *psock) +{ + /* Allocate the packet socket connection structure and save in the new + * socket instance. + */ + + FAR struct pkt_conn_s *conn = pkt_alloc(); + if (!conn) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Set the reference count on the connection structure. This reference + * count will be incremented only if the socket is dup'ed + */ + + DEBUGASSERT(conn->crefs == 0); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + return OK; +} +#endif /* CONFIG_NET_PKT */ + +/**************************************************************************** + * Name: psock_local_alloc + * + * Description: + * Allocate and attach a local, Unix domain connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_LOCAL +static int psock_local_alloc(FAR struct socket *psock) +{ + /* Allocate the local connection structure */ + + FAR struct local_conn_s *conn = local_alloc(); + if (!conn) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Set the reference count on the connection structure. This reference + * count will be incremented only if the socket is dup'ed + */ + + DEBUGASSERT(conn->lc_crefs == 0); + conn->lc_crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + return OK; +} +#endif /* CONFIG_NET_LOCAL */ /**************************************************************************** * Public Functions @@ -96,7 +243,11 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) { +#ifdef CONFIG_NET_LOCAL bool ipdomain = false; +#endif + bool dgramok = false; + int ret; int err; /* Only PF_INET, PF_INET6 or PF_PACKET domains supported */ @@ -105,13 +256,25 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) { #ifdef CONFIG_NET_IPv4 case PF_INET: +#ifdef CONFIG_NET_LOCAL ipdomain = true; +#endif + dgramok = true; break; #endif #ifdef CONFIG_NET_IPv6 case PF_INET6: +#ifdef CONFIG_NET_LOCAL ipdomain = true; +#endif + dgramok = true; + break; +#endif + +#ifdef CONFIG_NET_LOCAL + case PF_LOCAL: + dgramok = true; break; #endif @@ -131,7 +294,7 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) { #ifdef CONFIG_NET_TCP case SOCK_STREAM: - if ((protocol != 0 && protocol != IPPROTO_TCP) || !ipdomain) + if ((protocol != 0 && protocol != IPPROTO_TCP) || !dgramok) { err = EPROTONOSUPPORT; goto errout; @@ -142,7 +305,7 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) #ifdef CONFIG_NET_UDP case SOCK_DGRAM: - if ((protocol != 0 && protocol != IPPROTO_UDP) || !ipdomain) + if ((protocol != 0 && protocol != IPPROTO_UDP) || !dgramok) { err = EPROTONOSUPPORT; goto errout; @@ -153,7 +316,7 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) #ifdef CONFIG_NET_PKT case SOCK_RAW: - if (ipdomain) + if (dgramok) { err = EPROTONOSUPPORT; goto errout; @@ -185,56 +348,78 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) err = ENOMEM; /* Assume failure to allocate connection instance */ switch (type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: { - /* Allocate the TCP connection structure and save in the new - * socket instance. - */ +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif + { + /* Allocate and attach the TCP connection structure */ + + ret = psock_tcp_alloc(psock); + } +#endif /* CONFIG_NET_TCP */ - FAR struct tcp_conn_s *conn = tcp_alloc(domain); - if (!conn) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + else +#endif { - /* Failed to reserve a connection structure */ + /* Allocate and attach the local connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + ret = psock_local_alloc(psock); } +#endif /* CONFIG_NET_LOCAL */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ + /* Check for failures to allocate the connection structure. */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + if (ret < 0) + { + /* Failed to reserve a connection structure */ + + err = -ret; + goto errout; + } } break; #endif -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) case SOCK_DGRAM: { - /* Allocate the UDP connection structure and save in the new - * socket instance. - */ +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif + { + /* Allocate and attach the UDP connection structure */ + + ret = psock_udp_alloc(psock); + } +#endif /* CONFIG_NET_UDP */ - FAR struct udp_conn_s *conn = udp_alloc(domain); - if (!conn) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + else +#endif { - /* Failed to reserve a connection structure */ + /* Allocate and attach the local connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + ret = psock_local_alloc(psock); } +#endif /* CONFIG_NET_LOCAL */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ + /* Check for failures to allocate the connection structure. */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + if (ret < 0) + { + /* Failed to reserve a connection structure */ + + err = -ret; + goto errout; + } } break; #endif @@ -242,26 +427,14 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) #ifdef CONFIG_NET_PKT case SOCK_RAW: { - /* Allocate the packet socket connection structure and save - * in the new socket instance. - */ - - FAR struct pkt_conn_s *conn = pkt_alloc(); - if (!conn) + ret = psock_pkt_alloc(FAR struct socket *psock) + if (ret < 0) { /* Failed to reserve a connection structure */ + err = -ret; goto errout; } - - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ - - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; } break; #endif diff --git a/nuttx/net/tcp/Make.defs b/nuttx/net/tcp/Make.defs index d213960b7..41a03469e 100644 --- a/nuttx/net/tcp/Make.defs +++ b/nuttx/net/tcp/Make.defs @@ -39,6 +39,8 @@ ifeq ($(CONFIG_NET_TCP),y) # Socket layer +SOCK_CSRCS += tcp_accept.c + ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y) SOCK_CSRCS += tcp_send_buffered.c else diff --git a/nuttx/net/tcp/tcp.h b/nuttx/net/tcp/tcp.h index 1d6e78e8c..010b00989 100644 --- a/nuttx/net/tcp/tcp.h +++ b/nuttx/net/tcp/tcp.h @@ -267,9 +267,8 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -/* Defined in tcp_conn.c ****************************************************/ - -struct sockaddr; /* Forward reference */ +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ /**************************************************************************** * Name: tcp_initialize @@ -389,7 +388,6 @@ int tcp_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); -/* Defined in tcp_ipselect.c ************************************************/ /**************************************************************************** * Function: tcp_ipv4_select * @@ -414,7 +412,6 @@ void tcp_ipv4_select(FAR struct net_driver_s *dev); void tcp_ipv6_select(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_seqno.c ***************************************************/ /**************************************************************************** * Name: tcp_setsequence * @@ -481,7 +478,6 @@ void tcp_initsequence(FAR uint8_t *seqno); void tcp_nextsequence(void); -/* Defined in tcp_poll.c ****************************************************/ /**************************************************************************** * Name: tcp_poll * @@ -502,7 +498,6 @@ void tcp_nextsequence(void); void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); -/* Defined in tcp_timer.c ***************************************************/ /**************************************************************************** * Name: tcp_timer * @@ -525,7 +520,6 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, int hsec); -/* Defined in tcp_listen.c **************************************************/ /**************************************************************************** * Function: tcp_listen_initialize * @@ -593,7 +587,6 @@ bool tcp_islistener(uint16_t portno); int tcp_accept_connection(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t portno); -/* Defined in tcp_send.c ****************************************************/ /**************************************************************************** * Name: tcp_send * @@ -658,7 +651,6 @@ void tcp_reset(FAR struct net_driver_s *dev); void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint8_t ack); -/* Defined in tcp_appsend.c *************************************************/ /**************************************************************************** * Name: tcp_appsend * @@ -705,7 +697,6 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t result); -/* Defined in tcp_input.c ***************************************************/ /**************************************************************************** * Name: tcp_ipv4_input * @@ -748,7 +739,6 @@ void tcp_ipv4_input(FAR struct net_driver_s *dev); void tcp_ipv6_input(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_callback.c ************************************************/ /**************************************************************************** * Function: tcp_callback * @@ -794,7 +784,6 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer, uint16_t nbytes); #endif -/* Defined in tcp_backlog.c *************************************************/ /**************************************************************************** * Function: tcp_backlogcreate * @@ -910,7 +899,32 @@ int tcp_backlogdelete(FAR struct tcp_conn_s *conn, # define tcp_backlogdelete(c,b) (-ENOSYS) #endif -/* Defined in tcp_send_buffered.c or tcp_send_unbuffered.c ******************/ +/**************************************************************************** + * Function: tcp_accept + * + * Description: + * This function implements accept() for TCP/IP sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening TCP socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted TCP connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is locked. + * + ****************************************************************************/ + +int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + /**************************************************************************** * Function: psock_tcp_send * @@ -972,7 +986,6 @@ struct socket; ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len); -/* Defined in tcp_wrbuffer.c ************************************************/ /**************************************************************************** * Function: tcp_wrbuffer_initialize * diff --git a/nuttx/net/tcp/tcp_accept.c b/nuttx/net/tcp/tcp_accept.c new file mode 100644 index 000000000..86e4e8bc0 --- /dev/null +++ b/nuttx/net/tcp/tcp_accept.c @@ -0,0 +1,359 @@ +/**************************************************************************** + * net/tcp/tcp_accept.c + * + * Copyright (C) 2007-2012, 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * 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 <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET_TCP) + +#include <sys/types.h> +#include <sys/socket.h> + +#include <semaphore.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "socket/socket.h" +#include "tcp/tcp.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct accept_s +{ + FAR struct socket *acpt_sock; /* The accepting socket */ + sem_t acpt_sem; /* Wait for interrupt event */ + FAR struct sockaddr *acpt_addr; /* Return connection address */ + FAR socklen_t *acpt_addrlen; /* Return length of address */ + FAR struct tcp_conn_s *acpt_newconn; /* The accepted connection */ + int acpt_result; /* The result of the wait */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: accept_tcpsender + * + * Description: + * Get the sender's address from the UDP packet + * + * Parameters: + * psock - The state structure of the accepting socket + * conn - The newly accepted TCP connection + * pstate - the recvfrom state structure + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level +* + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static inline void accept_tcpsender(FAR struct socket *psock, + FAR struct tcp_conn_s *conn, + FAR struct sockaddr *addr, + socklen_t *addrlen) +{ + if (addr) + { + /* If an address is provided, then the length must also be provided. */ + + DEBUGASSERT(addrlen); + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when obtaining the sender's IP address. + */ + + if (psock->s_domain == PF_INET) +#endif /* CONFIG_NET_IPv6 */ + { + FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; + + inaddr->sin_family = AF_INET; + inaddr->sin_port = conn->rport; + net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); + + *addrlen = sizeof(struct sockaddr_in); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + /* Otherwise, this the IPv6 address is needed */ + + else +#endif /* CONFIG_NET_IPv4 */ + { + FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; + + DEBUGASSERT(psock->s_domain == PF_INET6); + inaddr->sin6_family = AF_INET6; + inaddr->sin6_port = conn->rport; + net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); + + *addrlen = sizeof(struct sockaddr_in6); + } +#endif /* CONFIG_NET_IPv6 */ + } +} +#endif /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Function: accept_interrupt + * + * Description: + * Receive interrupt level callbacks when connections occur + * + * Parameters: + * listener The connection structure of the listener + * conn The connection structure that was just accepted + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static int accept_interrupt(FAR struct tcp_conn_s *listener, + FAR struct tcp_conn_s *conn) +{ + struct accept_s *pstate = (struct accept_s *)listener->accept_private; + int ret = -EINVAL; + + if (pstate) + { + /* Get the connection address */ + + accept_tcpsender(pstate->acpt_sock, conn, pstate->acpt_addr, + pstate->acpt_addrlen); + + /* Save the connection structure */ + + pstate->acpt_newconn = conn; + pstate->acpt_result = OK; + + /* There should be a reference of one on the new connection */ + + DEBUGASSERT(conn->crefs == 1); + + /* Wake-up the waiting caller thread */ + + sem_post(&pstate->acpt_sem); + + /* Stop any further callbacks */ + + listener->accept_private = NULL; + listener->accept = NULL; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: tcp_accept + * + * Description: + * This function implements accept() for TCP/IP sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening TCP socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted TCP connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is locked. + * + ****************************************************************************/ + +int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn) +{ + FAR struct tcp_conn_s *conn; + struct accept_s state; + int err; + int ret; + + DEBUGASSERT(psock && newconn); + + /* Check the backlog to see if there is a connection already pending for + * this listener. + */ + + conn = (FAR struct tcp_conn_s *)psock->s_conn; + +#ifdef CONFIG_NET_TCPBACKLOG + state.acpt_newconn = tcp_backlogremove(conn); + if (state.acpt_newconn) + { + /* Yes... get the address of the connected client */ + + nvdbg("Pending conn=%p\n", state.acpt_newconn); + accept_tcpsender(psock, state.acpt_newconn, addr, addrlen); + } + + /* In general, this uIP-based implementation will not support non-blocking + * socket operations... except in a few cases: Here for TCP accept with backlog + * enabled. If this socket is configured as non-blocking then return EAGAIN + * if there is no pending connection in the backlog. + */ + + else if (_SS_ISNONBLOCK(psock->s_flags)) + { + err = EAGAIN; + goto errout; + } + else +#endif + { + /* Set the socket state to accepting */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); + + /* Perform the TCP accept operation */ + + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + state.acpt_sock = psock; + state.acpt_addr = addr; + state.acpt_addrlen = addrlen; + state.acpt_newconn = NULL; + state.acpt_result = OK; + sem_init(&state.acpt_sem, 0, 0); + + /* Set up the callback in the connection */ + + conn->accept_private = (void*)&state; + conn->accept = accept_interrupt; + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * net_lockedwait will also terminate if a signal is received, (2) + * interrupts may be disabled! They will be re-enabled while the + * task sleeps and automatically re-enabled when the task restarts. + */ + + ret = net_lockedwait(&state.acpt_sem); + if (ret < 0) + { + /* The value returned by net_lockedwait() the same as the value + * returned by sem_wait(): Zero (OK) is returned on success; -1 + * (ERROR) is returned on a failure with the errno value set + * appropriately. + * + * We have to preserve the errno value here because it may be + * altered by intervening operations. + */ + + err = get_errno(); + } + + /* Make sure that no further interrupts are processed */ + + conn->accept_private = NULL; + conn->accept = NULL; + + sem_destroy(&state. acpt_sem); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Check for a errors. Errors are signalled by negative errno values + * for the send length. + */ + + if (state.acpt_result != 0) + { + err = state.acpt_result; + goto errout; + } + + /* If net_lockedwait failed, then we were probably reawakened by a + * signal. In this case, logic above will have set 'err' to the + * ernno value returned by net_lockedwait(). + */ + + if (ret < 0) + { + goto errout; + } + } + + *newconn = (FAR void *)state.acpt_newconn; + return OK; + +errout: + set_errno(err); + return ERROR; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && CONFIG_NET_TCP */ |