summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/net/Kconfig1
-rw-r--r--nuttx/net/Makefile3
-rw-r--r--nuttx/net/README.txt1
-rw-r--r--nuttx/net/local/Kconfig19
-rw-r--r--nuttx/net/local/Make.defs48
-rw-r--r--nuttx/net/local/local.h434
-rw-r--r--nuttx/net/local/local_accept.c258
-rw-r--r--nuttx/net/local/local_bind.c113
-rw-r--r--nuttx/net/local/local_conn.c136
-rw-r--r--nuttx/net/local/local_connect.c303
-rw-r--r--nuttx/net/local/local_fifo.c407
-rw-r--r--nuttx/net/local/local_listen.c149
-rw-r--r--nuttx/net/local/local_release.c183
-rw-r--r--nuttx/net/net_initialize.c7
-rw-r--r--nuttx/net/pkt/pkt.h2
-rw-r--r--nuttx/net/pkt/pkt_conn.c3
-rw-r--r--nuttx/net/socket/Make.defs7
-rw-r--r--nuttx/net/socket/accept.c305
-rw-r--r--nuttx/net/socket/bind.c95
-rw-r--r--nuttx/net/socket/connect.c57
-rw-r--r--nuttx/net/socket/listen.c66
-rw-r--r--nuttx/net/socket/net_close.c157
-rw-r--r--nuttx/net/socket/socket.c269
-rw-r--r--nuttx/net/tcp/Make.defs2
-rw-r--r--nuttx/net/tcp/tcp.h43
-rw-r--r--nuttx/net/tcp/tcp_accept.c359
26 files changed, 3037 insertions, 390 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..670cc9550
--- /dev/null
+++ b/nuttx/net/local/Make.defs
@@ -0,0 +1,48 @@
+############################################################################
+# 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
+
+# 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..66ee6f417
--- /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 connected */
+ LOCAL_STATE_ACCEPT, /* Client waiting for a connection */
+ LOCAL_STATE_CONNECTED, /* Client (or server) connected */
+ LOCAL_STATE_DISCONNECTED /* Client 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 */
+ int16_t lc_outfd; /* File descriptor of write-only FIFO */
+ 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 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..3afe652c7
--- /dev/null
+++ b/nuttx/net/local/local_accept.c
@@ -0,0 +1,258 @@
+/****************************************************************************
+ * 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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_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/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/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 */