diff --git a/net/local/local.h b/net/local/local.h new file mode 100644 index 0000000000..5d8aec50ba --- /dev/null +++ b/net/local/local.h @@ -0,0 +1,242 @@ +/**************************************************************************** + * net/local/loal.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NET_LOCAL_LOCAL_H +#define __NET_LOCAL_LOCAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#ifdef CONFIG_NET_LOCAL + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* Representation of a local connection */ + +struct local_conn_s +{ + dq_entry_t node; /* Supports a doubly linked list */ + int16_t fd; /* File descriptor of underlying file */ + uint8_t crefs; /* Reference counts on this instance */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ + +/**************************************************************************** + * Name: local_initialize + * + * Description: + * Initialize the local connection structures. Called once and only from + * the UIP layer. + * + ****************************************************************************/ + +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); + +/**************************************************************************** + * 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: + * conn - A reference to local connection structure + * addr - The address of the remote host. + * + * Assumptions: + * This function is called user code. Interrupts may be enabled. + * + ****************************************************************************/ + +int local_connect(FAR struct local_conn_s *conn, + FAR const struct sockaddr *addr); + +/**************************************************************************** + * 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); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_LOCAL */ +#endif /* __NET_LOCAL_LOCAL_H */ diff --git a/net/net_initialize.c b/net/net_initialize.c index 371b309879..469270577d 100644 --- a/net/net_initialize.c +++ b/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/net/socket/net_close.c b/net/socket/net_close.c index a2ef7e91fa..d58d428294 100644 --- a/net/socket/net_close.c +++ b/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" /**************************************************************************** @@ -451,6 +452,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->crefs <= 1) + { + conn->crefs = 0; + local_free(conn); + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } +} +#endif /* CONFIG_NET_LOCAL */ + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -519,63 +559,102 @@ int psock_close(FAR struct socket *psock) break; #endif -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: { - FAR struct tcp_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... then perform the disconnection now */ + /* Release our reference to the local connection structure */ - 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) + local_close(psock); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + FAR struct tcp_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) { - /* This would normally occur only if there is a timeout - * from a lingering close. - */ + /* Yes... then perform the disconnection now */ - goto errout_with_psock; + 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--; } } - else - { - /* No.. Just decrement the reference count */ - - conn->crefs--; - } +#endif /* CONFIG_NET_TCP */ } break; #endif -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) case SOCK_DGRAM: { - 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). - */ - - if (conn->crefs <= 1) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + 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 */ - udp_free(psock->s_conn); /* Free uIP resources */ + local_close(psock); } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL else +#endif { - /* No.. Just decrement the reference count */ + FAR struct udp_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... free the connection structure */ + + conn->crefs = 0; + udp_free(psock->s_conn); + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } } +#endif /* CONFIG_NET_UDP */ } break; #endif diff --git a/net/socket/socket.c b/net/socket/socket.c index 1ce2e08906..8e00143caa 100644 --- a/net/socket/socket.c +++ b/net/socket/socket.c @@ -51,6 +51,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" /**************************************************************************** * Public Functions @@ -96,7 +97,10 @@ 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 err; /* Only PF_INET, PF_INET6 or PF_PACKET domains supported */ @@ -105,13 +109,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 +147,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 +158,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 +169,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 +201,130 @@ 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. - */ - - FAR struct tcp_conn_s *conn = tcp_alloc(domain); - if (!conn) +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif { - /* Failed to reserve a connection structure */ + /* Allocate the TCP connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + FAR struct tcp_conn_s *conn = tcp_alloc(domain); + if (!conn) + { + /* Failed to reserve a connection structure */ + + goto errout; /* With err == ENFILE or ENOMEM */ + } + + /* 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); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; } +#endif /* CONFIG_NET_TCP */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + else +#endif + { + /* Allocate the local connection structure */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + FAR struct local_conn_s *conn = local_alloc(); + if (!conn) + { + /* Failed to reserve a connection structure */ + + goto errout; /* With err == ENFILE or ENOMEM */ + } + + /* 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); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + } +#endif /* CONFIG_NET_LOCAL */ } 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. - */ - - FAR struct udp_conn_s *conn = udp_alloc(domain); - if (!conn) +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif { - /* Failed to reserve a connection structure */ + /* Allocate the UDP connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + FAR struct udp_conn_s *conn = udp_alloc(domain); + if (!conn) + { + /* Failed to reserve a connection structure */ + + goto errout; /* With err == ENFILE or ENOMEM */ + } + + /* 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); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; } +#endif /* CONFIG_NET_UDP */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + else +#endif + { + /* Allocate the local connection structure */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + FAR struct local_conn_s *conn = local_alloc(); + if (!conn) + { + /* Failed to reserve a connection structure */ + + goto errout; /* With err == ENFILE or ENOMEM */ + } + + /* 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); + conn->crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + } +#endif /* CONFIG_NET_LOCAL */ } break; #endif