summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-01-26 13:30:27 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-01-26 13:30:27 -0600
commit6840f3fdad01a702edec589d940b24092f19848c (patch)
tree53e7a1cf710c2e9a825c99da5f14cb7fb3c231e1
parentb3a86b681e90f212a78ab8ed0991c5f991fd030e (diff)
downloadnuttx-6840f3fdad01a702edec589d940b24092f19848c.tar.gz
nuttx-6840f3fdad01a702edec589d940b24092f19848c.tar.bz2
nuttx-6840f3fdad01a702edec589d940b24092f19848c.zip
Networking: Add FIFO management logic needed to support Unix domain sockets
-rw-r--r--nuttx/net/local/Make.defs2
-rw-r--r--nuttx/net/local/local.h67
-rw-r--r--nuttx/net/local/local_accept.c134
-rw-r--r--nuttx/net/local/local_conn.c19
-rw-r--r--nuttx/net/local/local_connect.c60
-rw-r--r--nuttx/net/local/local_fifo.c407
-rw-r--r--nuttx/net/local/local_release.c2
7 files changed, 642 insertions, 49 deletions
diff --git a/nuttx/net/local/Make.defs b/nuttx/net/local/Make.defs
index c72c48a39..670cc9550 100644
--- a/nuttx/net/local/Make.defs
+++ b/nuttx/net/local/Make.defs
@@ -38,7 +38,7 @@
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
+NET_CSRCS += local_listen.c local_accept.c local_fifo.c
# Include UDP build support
diff --git a/nuttx/net/local/local.h b/nuttx/net/local/local.h
index a9ae7dbaa..66ee6f417 100644
--- a/nuttx/net/local/local.h
+++ b/nuttx/net/local/local.h
@@ -74,14 +74,14 @@ enum local_state_s
/* Common states */
LOCAL_STATE_UNBOUND = 0, /* Created by socket, but not bound */
- LOCAL_STATE_BOUND, /* Bound to an pipe */
+ 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 connected */
+ LOCAL_STATE_CONNECTED, /* Client (or server) connected */
LOCAL_STATE_DISCONNECTED /* Client disconnected */
};
@@ -102,7 +102,8 @@ struct local_conn_s
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_fd; /* File descriptor of underlying pipe */
+ 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 */
@@ -364,6 +365,66 @@ 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
}
diff --git a/nuttx/net/local/local_accept.c b/nuttx/net/local/local_accept.c
index b7dc623a0..3afe652c7 100644
--- a/nuttx/net/local/local_accept.c
+++ b/nuttx/net/local/local_accept.c
@@ -44,6 +44,7 @@
#include <errno.h>
#include <assert.h>
#include <queue.h>
+#include <debug.h>
#include <nuttx/net/net.h>
@@ -83,6 +84,7 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
{
FAR struct local_conn_s *server;
FAR struct local_conn_s *client;
+ FAR struct local_conn_s *conn;
int ret;
/* Some sanity checks */
@@ -110,68 +112,124 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
if (client)
{
- /* Add the waiting connection to list of clients */
-
- dq_addlast(&client->lc_node, &server->u.server.lc_conns);
-
/* Decrement the number of pending clients */
DEBUGASSERT(server->u.server.lc_pending > 0);
server->u.server.lc_pending--;
- /* And signal the client that the connection was successful */
-
- client->u.client.lc_result = OK;
- sem_post(&client->lc_waitsem);
-
- /* Return the address family */
+ /* Create a new connection structure for the server side of the
+ * connection.
+ */
- if (addr)
+ conn = local_alloc();
+ if (!conn)
+ {
+ ndbg("ERROR: Failed to allocate new connection structure\n");
+ ret = -ENOMEM;
+ }
+ else
{
- FAR struct sockaddr_un *unaddr;
- int totlen;
- int pathlen;
+ /* Initialize the new connection structure */
- /* If an address is provided, then the length must also be
- * provided.
- */
+ conn->lc_crefs = 1;
+ conn->lc_family = SOCK_STREAM;
+ conn->lc_type = LOCAL_TYPE_PATHNAME;
+ conn->lc_state = LOCAL_STATE_CONNECTED;
- DEBUGASSERT(addrlen);
+ strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX-1);
+ conn->lc_path[UNIX_PATH_MAX-1] = '\0';
- /* Get the length of the path (minus the NUL terminator)
- * and the length of the whole client address.
+ /* Open the server-side write-only FIFO. This should not
+ * block.
*/
- pathlen = strnlen(client->lc_path, UNIX_PATH_MAX-1);
- totlen = sizeof(sa_family_t) + pathlen + 1;
+ 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);
- /* If the length of the whole client address is larger
- * than the buffer provided by the caller, then truncate
- * the address to fit.
+ /* Open the server-side read-only FIFO. This should not
+ * block because the client side has already opening it
+ * for writing.
*/
- if (totlen > *addrlen)
+ ret = local_open_server_rx(conn);
+ if (ret < 0)
{
- pathlen -= (totlen - *addrlen);
- totlen = *addrlen;
+ ndbg("ERROR: Failed to open read-only FIFOs for %s: %d\n",
+ conn->lc_path, ret);
}
+ }
+
+ if (ret == OK)
+ {
+ DEBUGASSERT(conn->lc_infd >= 0);
- /* Copy the Unix domain address */
+ /* Add the waiting connection to list of clients */
- unaddr = (FAR struct sockaddr_un *)addr;
- unaddr->sun_family = AF_LOCAL;
- memcpy(unaddr->sun_path, client->lc_path, pathlen);
- unaddr->sun_path[pathlen] = '\0';
+ dq_addlast(&client->lc_node, &server->u.server.lc_conns);
- /* Return the Unix domain address size */
+ /* Return the address family */
- *addrlen = totlen;
+ 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;
}
- /* Return the client connection structure */
+ /* Signal the client with the result of the connection */
- *newconn = (FAR void *)client;
- return OK;
+ client->u.client.lc_result = ret;
+ sem_post(&client->lc_waitsem);
+ return ret;
}
/* No.. then there should be no pending connections */
diff --git a/nuttx/net/local/local_conn.c b/nuttx/net/local/local_conn.c
index e19a0c12c..171313b29 100644
--- a/nuttx/net/local/local_conn.c
+++ b/nuttx/net/local/local_conn.c
@@ -88,7 +88,8 @@ FAR struct local_conn_s *local_alloc(void)
{
/* Initialize non-zero elements the new connection structure */
- conn->lc_fd = -1;
+ conn->lc_infd = -1;
+ conn->lc_outfd = -1;
sem_init(&conn->lc_waitsem, 0, 0);
}
@@ -108,13 +109,23 @@ void local_free(FAR struct local_conn_s *conn)
{
DEBUGASSERT(conn != NULL);
- /* Make sure that the pipe is closed */
+ /* Make sure that the read-only FIFO is closed */
- if (conn->lc_fd >= 0)
+ if (conn->lc_infd >= 0)
{
- close(conn->lc_fd);
+ 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 */
diff --git a/nuttx/net/local/local_connect.c b/nuttx/net/local/local_connect.c
index c1e4b9fda..fdc0bd74e 100644
--- a/nuttx/net/local/local_connect.c
+++ b/nuttx/net/local/local_connect.c
@@ -41,6 +41,7 @@
#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL)
#include <string.h>
+#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <queue.h>
@@ -112,12 +113,42 @@ int inline local_stream_connect(FAR struct local_conn_s *client,
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);
@@ -135,9 +166,34 @@ int inline local_stream_connect(FAR struct local_conn_s *client,
}
while (ret == -EBUSY);
- /* Was the connection successful? */
+ /* 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);
- client->lc_state = (ret < 0 ? LOCAL_STATE_BOUND : LOCAL_STATE_CONNECTED);
+errout_with_fifos:
+ (void)local_destroy_fifos(client);
+ client->lc_state = LOCAL_STATE_BOUND;
return ret;
}
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_release.c b/nuttx/net/local/local_release.c
index c2d6092ce..d69a0a3da 100644
--- a/nuttx/net/local/local_release.c
+++ b/nuttx/net/local/local_release.c
@@ -133,7 +133,7 @@ int local_release(FAR struct local_conn_s *conn)
client;
client = (FAR struct local_conn_s *)dq_next(&client->lc_node))
{
- client->u.client.lc_result = -ENETUNREACH;
+ client->u.client.lc_result = -ENOTCONN;
sem_post(&client->lc_waitsem);
conn->lc_state = LOCAL_STATE_CLOSED;
}