* \return Positive on success, \p -E_NAME_TOO_LONG if \a name is longer
* than \p UNIX_PATH_MAX.
*/
-static int init_unix_addr(struct sockaddr_un *u, const char *name)
+static int init_unix_addr(struct sockaddr_un *u, const char *name,
+ bool abstract)
{
- if (strlen(name) >= UNIX_PATH_MAX)
+ if (strlen(name) + abstract >= 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, name);
+ strcpy(u->sun_path + abstract, name);
return 1;
}
/**
- * Prepare, create, and bind a socket for local communication.
+ * 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 local socket for sequenced, reliable,
- * two-way, connection-based byte streams.
+ * 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.
*
- * \return The file descriptor, on success, negative on errors.
+ * 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.
*
- * \sa socket(2)
- * \sa bind(2)
- * \sa chmod(2)
+ * \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)
{
struct sockaddr_un unix_addr;
int fd, ret;
+ bool abstract = mode == 0;
- ret = init_unix_addr(&unix_addr, name);
+ ret = init_unix_addr(&unix_addr, name, abstract);
if (ret < 0)
return ret;
ret = socket(PF_UNIX, SOCK_STREAM, 0);
if (ret < 0)
return -ERRNO_TO_PARA_ERROR(errno);
fd = ret;
- ret = bind(fd, (struct sockaddr *)&unix_addr, UNIX_PATH_MAX);
+ ret = mark_fd_nonblocking(fd);
+ if (ret < 0)
+ goto err;
+ ret = bind(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
if (ret < 0) {
ret = -ERRNO_TO_PARA_ERROR(errno);
goto err;
}
- ret = -E_CHMOD;
- if (chmod(name, mode) < 0)
+ if (!abstract) {
+ ret = -E_CHMOD;
+ if (chmod(name, mode) < 0)
+ goto err;
+ }
+ if (listen(fd , 5) < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
goto err;
+ }
return fd;
err:
close(fd);
int fd, ret;
PARA_DEBUG_LOG("connecting to %s\n", name);
- ret = init_unix_addr(&unix_addr, name);
- if (ret < 0)
- return ret;
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
return -ERRNO_TO_PARA_ERROR(errno);
- if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) == -1) {
- ret = -ERRNO_TO_PARA_ERROR(errno);
+ /* first try (linux-only) abstract socket */
+ ret = init_unix_addr(&unix_addr, name, true);
+ if (ret < 0)
goto err;
- }
- return fd;
+ 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);
+ if (ret < 0)
+ goto err;
+ if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) != -1)
+ return fd;
+ ret = -ERRNO_TO_PARA_ERROR(errno);
err:
close(fd);
return ret;