diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2015-01-25 16:27:25 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2015-01-25 16:27:25 -0600 |
commit | 8cac18f0f8619c9f3f0a6429904eeceb3c965302 (patch) | |
tree | 4176c46865c705fa927a6816422b108508d45476 /nuttx/net/local/local_accept.c | |
parent | e71c09ce9777ff732cb60bd07fb43d85522f79d6 (diff) | |
download | px4-nuttx-8cac18f0f8619c9f3f0a6429904eeceb3c965302.tar.gz px4-nuttx-8cac18f0f8619c9f3f0a6429904eeceb3c965302.tar.bz2 px4-nuttx-8cac18f0f8619c9f3f0a6429904eeceb3c965302.zip |
Networking: Add local Unix domain socket accept logic
Diffstat (limited to 'nuttx/net/local/local_accept.c')
-rw-r--r-- | nuttx/net/local/local_accept.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/nuttx/net/local/local_accept.c b/nuttx/net/local/local_accept.c new file mode 100644 index 000000000..e1406168a --- /dev/null +++ b/nuttx/net/local/local_accept.c @@ -0,0 +1,202 @@ +/**************************************************************************** + * 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 <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; + + /* 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; + } + + /* Are there pending connections. Remove the client from the + * head of the waiting list. + */ + +try_again: + + client = (FAR struct local_conn_s *) + dq_remfirst(&server->u.server.lc_waiters); + + 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 */ + + 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 *)client; + return OK; + } + else + { + int 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; + } + + goto try_again; + } +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ |