char *socket_name = conf.afs_socket_arg;
unlink(socket_name);
- ret = create_local_socket(socket_name, 0);
+ ret = create_local_socket(socket_name);
if (ret < 0) {
- ret = create_local_socket(socket_name,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IROTH);
- if (ret < 0) {
- PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret),
- socket_name);
- exit(EXIT_FAILURE);
- }
+ PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret), socket_name);
+ exit(EXIT_FAILURE);
}
socket_fd = ret;
PARA_INFO_LOG("listening on socket %s (fd %d)\n", socket_name,
*/
static struct status_task *stat_task = &status_task_struct;
-/*
- * The task for handling audiod commands.
- *
- * We need two listening sockets for backward compability: on Linux systems
- * fd[0] is an abstract socket (more precisely, a socket bound to an address in
- * the abstract namespace), and fd[1] is the usual pathname socket. On other
- * systems, fd[0] is negative, and only the pathname socket is used.
- *
- * For 0.5.x we accept connections on both sockets to make sure that old
- * para_audioc versions can still connect. New versions use only the abstract
- * socket. Hence after v0.6.0 we can go back to a single socket, either an
- * abstract one (Linux) or a pathname socket (all other systems).
- */
struct command_task {
- /** The local listening sockets. */
- int fd[2];
+ /** The local listening socket. */
+ int fd;
/** the associated task structure */
struct task *task;
};
}
/* does not unlink socket on errors */
-static void init_local_sockets(struct command_task *ct)
+static void init_local_socket(struct command_task *ct)
{
if (conf.socket_given)
socket_name = para_strdup(conf.socket_arg);
PARA_NOTICE_LOG("local socket: %s\n", socket_name);
if (conf.force_given)
unlink(socket_name);
- ct->fd[0] = create_local_socket(socket_name, 0);
- ct->fd[1] = create_local_socket(socket_name,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
- if (ct->fd[0] >= 0 || ct->fd[1] >= 0)
+ ct->fd = create_local_socket(socket_name);
+ if (ct->fd >= 0)
return;
- PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1]));
+ PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd));
exit(EXIT_FAILURE);
}
static void command_pre_select(struct sched *s, void *context)
{
struct command_task *ct = context;
- int i;
-
- for (i = 0; i < 2; i++)
- if (ct->fd[i] >= 0)
- para_fd_set(ct->fd[i], &s->rfds, &s->max_fileno);
+ para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
}
static int command_post_select(struct sched *s, void *context)
{
- int ret, i;
+ int ret;
struct command_task *ct = context;
static struct timeval last_status_dump;
struct timeval tmp, delay;
ret = task_get_notification(ct->task);
if (ret < 0)
return ret;
- for (i = 0; i < 2; i++) {
- if (ct->fd[i] < 0)
- continue;
- ret = handle_connect(ct->fd[i], &s->rfds);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- if (ret == -E_AUDIOD_TERM) {
- task_notify_all(s, -ret);
- return ret;
- }
- } else if (ret > 0)
- force = true;
- }
+ ret = handle_connect(ct->fd, &s->rfds);
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ if (ret == -E_AUDIOD_TERM) {
+ task_notify_all(s, -ret);
+ return ret;
+ }
+ } else if (ret > 0)
+ force = true;
if (force == true)
goto dump;
static void init_command_task(struct command_task *ct)
{
- init_local_sockets(ct); /* doesn't return on errors */
+ init_local_socket(ct); /* doesn't return on errors */
ct->task = task_register(&(struct task_info) {
.name = "command",
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;
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)
int recv_buffer(int fd, char *buf, size_t size);
int para_accept(int fd, fd_set *rfds, void *addr, socklen_t size, int *new_fd);
-int create_local_socket(const char *name, mode_t mode);
+int create_local_socket(const char *name);
int connect_local_socket(const char *name);
int recv_cred_buffer(int, char *, size_t);
ssize_t send_cred_buffer(int, char*);