From ffc02f30b02f135f1c8410b9b8c3a463557afa70 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 25 Jan 2015 08:33:39 -0600 Subject: [PATCH] Networking: Add logic for binding Unix domain sockets --- net/local/local.h | 11 ++++- net/local/local_conn.c | 68 ++++++++++++++++++++++++++++- net/socket/bind.c | 97 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 163 insertions(+), 13 deletions(-) diff --git a/net/local/local.h b/net/local/local.h index e44a1739e73..864f09a9095 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -56,12 +56,21 @@ /**************************************************************************** * Public Type Definitions ****************************************************************************/ +/* Local, Unix domain socket types */ + +enum local_type_e +{ + LOCAL_TYPE_UNNAMED = 0, /* 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 */ +}; /* Representation of a local connection */ struct local_conn_s { uint8_t lc_crefs; /* Reference counts on this instance */ + uint8_t lc_type; /* See enum local_type_e */ int16_t lc_fd; /* File descriptor of underlying pipe */ char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */ }; @@ -129,7 +138,7 @@ void local_free(FAR struct local_conn_s *conn); ****************************************************************************/ int local_bind(FAR struct local_conn_s *conn, - FAR const struct sockaddr *addr); + FAR const struct sockaddr *addr, socklen_t addrlen); /**************************************************************************** * Name: local_connect diff --git a/net/local/local_conn.c b/net/local/local_conn.c index 506b56b405b..74fc61afee3 100644 --- a/net/local/local_conn.c +++ b/net/local/local_conn.c @@ -40,10 +40,12 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) -#include +#include #include #include +#include + #include "local/local.h" /**************************************************************************** @@ -81,7 +83,17 @@ FAR struct local_conn_s *local_alloc(void) { - return (FAR struct local_conn_s *)malloc(sizeof(struct local_conn_s)); + FAR struct local_conn_s *conn = + (FAR struct local_conn_s *)kmm_zalloc(sizeof(struct local_conn_s)); + + if (conn) + { + /* Make sure that the pipe is marked closed */ + + conn->lc_fd = -1; + } + + return conn; } /**************************************************************************** @@ -99,4 +111,56 @@ void local_free(FAR struct local_conn_s *conn) free(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) +{ + 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)); + + 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'; + } + } + + return OK; +} + + #endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/net/socket/bind.c b/net/socket/bind.c index d905e5aaf27..6dc7de9ff10 100644 --- a/net/socket/bind.c +++ b/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 * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -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; - break; + { +#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;