-/*
- * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
/** \file net.c Networking-related helper functions. */
* default of 32 if not specified.
*
* \return Pointer to \a addr if successful, NULL on error.
- * \sa RFC 4632
+ * \sa RFC 4632.
*/
char *parse_cidr(const char *cidr,
char *addr, ssize_t addrlen,
* \param host The host string to check.
* \return True if \a host passes the syntax checks.
*
- * \sa RFC 3986, 3.2.2; RFC 1123, 2.1; RFC 1034, 3.5
+ * \sa RFC 3986, 3.2.2; RFC 1123, 2.1; RFC 1034, 3.5.
*/
static bool host_string_ok(const char *host)
{
* \a host and \a port are undefined. If no port number was present in \a url,
* \a port is set to -1.
*
- * \sa RFC 3986, 3.2.2/3.2.3
+ * \sa RFC 3986, 3.2.2/3.2.3.
*/
char *parse_url(const char *url,
char *host, ssize_t hostlen,
}
if (*o == ':')
- if (para_atoi32(++o, port) < 0 ||
- *port < 0 || *port > 0xffff)
+ if (para_atoi32(++o, port) < 0 || *port < 0 || *port > 0xffff)
goto failed;
if (host_string_ok(host))
return host;
/**
* Stringify port number, resolve into service name where defined.
+ *
* \param port 2-byte port number, in host-byte-order.
* \param transport Transport protocol name (e.g. "udp", "tcp"), or NULL.
* \return Pointer to static result buffer.
*
- * \sa getservent(3), services(5), nsswitch.conf(5)
+ * \sa getservent(3), services(5), nsswitch.conf(5).
*/
const char *stringify_port(int port, const char *transport)
{
*
* \param l4type The symbolic name of the transport-layer protocol.
*
- * \sa ip(7), socket(2)
+ * \sa ip(7), socket(2).
*/
static inline int sock_type(const unsigned l4type)
{
* directly after makesock(). The 'pre_conn_opt' structure is for internal use
* only and should not be visible elsewhere.
*
- * \sa setsockopt(2), makesock()
+ * \sa setsockopt(2), \ref makesock().
*/
struct pre_conn_opt {
int sock_level; /**< Second argument to setsockopt() */
* \param val The value to set \a opt to.
* \param len Length of \a val.
*
- * \sa setsockopt(2)
+ * \sa setsockopt(2).
*/
void flowopt_add(struct flowopts *fo, int lev, int opt,
const char *name, const void *val, int len)
struct addrinfo *addr = NULL, hints;
*result = NULL;
- sprintf(port, "%u", port_number & 0xffff);
+ sprintf(port, "%d", port_number & 0xffff);
/* Set up address hint structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
* \return Positive integer (socket descriptor) on success, negative value
* otherwise.
*
- * \sa makesock(), ip(7), ipv6(7), bind(2), listen(2).
+ * \sa \ref makesock(), ip(7), ipv6(7), bind(2), listen(2).
*/
int para_listen(unsigned l4type, uint16_t port, struct flowopts *fo)
{
* \param ss Container of IPv4/6 address.
* \return Pointer to normalized address (may be static storage).
*
- * \sa RFC 3493
+ * \sa RFC 3493.
*/
static const struct sockaddr *
normalize_ip_address(const struct sockaddr_storage *ss)
*/
int generic_max_transport_msg_size(int sockfd)
{
- struct sockaddr_storage ss;
+ struct sockaddr_storage ss = {.ss_family = 0};
socklen_t sslen = sizeof(ss);
int af_type = AF_INET;
* \return A static character string identifying hostname and port of the
* chosen side in numeric host:port format.
*
- * \sa getsockname(2), getpeername(2), parse_url(), getnameinfo(3),
+ * \sa getsockname(2), getpeername(2), \ref parse_url(), getnameinfo(3),
* services(5), nsswitch.conf(5).
*/
char *remote_name(int fd)
{
- struct sockaddr_storage ss;
+ struct sockaddr_storage ss = {.ss_family = 0};
const struct sockaddr *sa;
socklen_t sslen = sizeof(ss);
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
*
* \return The return value of the underlying call to \a recv_bin_buffer().
*
- * \sa recv_bin_buffer()
+ * \sa \ref recv_bin_buffer()
*/
int recv_buffer(int fd, char *buf, size_t size)
{
return nccids;
}
-/**
- * Prepare a structure for \p AF_UNIX socket addresses.
- *
- * \param u Pointer to the struct to be prepared.
- * \param name The socket pathname.
+/*
+ * Prepare a structure for AF_UNIX socket addresses.
*
- * This just copies \a name to the sun_path component of \a u.
+ * This just copies name to the sun_path component of u, prepending a zero byte
+ * if abstract sockets are supported.
*
- * \return Positive on success, \p -E_NAME_TOO_LONG if \a name is longer
- * than \p UNIX_PATH_MAX.
+ * The first call to this function tries to bind a socket to the abstract name
+ * space. The result of this test is stored in a static variable. Subsequent
+ * calls read this variable and create abstract sockets on systems that support
+ * them.
*/
-static int init_unix_addr(struct sockaddr_un *u, const char *name,
- bool abstract)
+static int init_unix_addr(struct sockaddr_un *u, const char *name)
{
- if (strlen(name) + abstract >= UNIX_PATH_MAX)
+ static int use_abstract;
+
+ if (strlen(name) + 1 >= UNIX_PATH_MAX)
return -E_NAME_TOO_LONG;
memset(u->sun_path, 0, UNIX_PATH_MAX);
u->sun_family = PF_UNIX;
- strcpy(u->sun_path + abstract, name);
+ if (use_abstract == 0) { /* executed only once */
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ memcpy(u->sun_path, "\0x\0", 3);
+ if (bind(fd, (struct sockaddr *)u, sizeof(*u)) == 0)
+ use_abstract = 1; /* yes */
+ else
+ use_abstract = -1; /* no */
+ close(fd);
+ PARA_NOTICE_LOG("%susing abstract socket namespace\n",
+ use_abstract == 1? "" : "not ");
+ }
+ strcpy(u->sun_path + (use_abstract == 1? 1 : 0), name);
return 1;
}
* Create a socket for local communication and listen on it.
*
* \param name The socket pathname.
- * \param mode The desired permissions of the socket.
*
* This function creates a passive local socket for sequenced, reliable,
* two-way, connection-based byte streams. The socket file descriptor is set to
* nonblocking mode and listen(2) is called to prepare the socket for
* accepting incoming connection requests.
*
- * If mode is zero, an abstract socket (a non-portable Linux extension) is
- * created. In this case the socket name has no connection with filesystem
- * pathnames.
- *
* \return The file descriptor on success, negative error code on failure.
*
* \sa socket(2), \sa bind(2), \sa chmod(2), listen(2), unix(7).
*/
-int create_local_socket(const char *name, mode_t mode)
+int create_local_socket(const char *name)
{
struct sockaddr_un unix_addr;
int fd, ret;
- bool abstract = mode == 0;
- ret = init_unix_addr(&unix_addr, name, abstract);
+ ret = init_unix_addr(&unix_addr, name);
if (ret < 0)
return ret;
ret = socket(PF_UNIX, SOCK_STREAM, 0);
ret = -ERRNO_TO_PARA_ERROR(errno);
goto err;
}
- if (!abstract) {
+ if (unix_addr.sun_path[0] != 0) { /* pathname socket */
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
+ | S_IROTH | S_IWOTH;
ret = -E_CHMOD;
if (chmod(name, mode) < 0)
goto err;
* \return The file descriptor of the connected socket on success, negative on
* errors.
*
- * \sa create_local_socket(), unix(7), connect(2).
+ * \sa \ref create_local_socket(), unix(7), connect(2).
*/
int connect_local_socket(const char *name)
{
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
return -ERRNO_TO_PARA_ERROR(errno);
- /* first try (linux-only) abstract socket */
- ret = init_unix_addr(&unix_addr, name, true);
- if (ret < 0)
- goto err;
- if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) != -1)
- return fd;
- /* next try pathname socket */
- ret = init_unix_addr(&unix_addr, name, false);
+ ret = init_unix_addr(&unix_addr, name);
if (ret < 0)
goto err;
if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) != -1)
* \return On success, this call returns the number of bytes sent. On errors,
* \p -E_SENDMSG is returned.
*
- * \sa \ref recv_cred_buffer, sendmsg(2), socket(7), unix(7), okir's Black Hats
- * Manual.
+ * \sa \ref recv_cred_buffer, sendmsg(2), socket(7), unix(7).
*/
ssize_t send_cred_buffer(int sock, char *buf)
{