free(client);
}
/* Accept connections on the local socket. */
- if (!FD_ISSET(ct->fd, &s->rfds))
- return;
- ret = para_accept(ct->fd, &unix_addr, sizeof(unix_addr));
- if (ret < 0) {
+ ret = para_accept(ct->fd, &s->rfds, &unix_addr, sizeof(unix_addr), &fd);
+ if (ret < 0)
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
+ if (ret <= 0)
return;
- }
- fd = ret;
ret = mark_fd_nonblocking(fd);
if (ret < 0) {
PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
last_status_dump = *now;
}
- if (!FD_ISSET(ct->fd, &s->rfds))
- return;
- ret = handle_connect(ct->fd);
+ ret = handle_connect(ct->fd, &s->rfds);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
audiod_status_dump();
extern int audiod_status;
void __noreturn clean_exit(int status, const char *msg);
-int handle_connect(int accept_fd);
+int handle_connect(int accept_fd, fd_set *rfds);
void audiod_status_dump(void);
char *get_time_string(int slot_num);
struct btr_node *audiod_get_btr_root(void);
}
/**
- * handle arriving connections on the local socket
+ * Handle arriving connections on the local socket.
*
- * \param accept_fd the fd to call accept() on
+ * \param accept_fd The fd to accept connections on.
*
- * This is called whenever para_audiod's main task detects an incoming
- * connection by the readability of \a accept_fd. This function reads the
- * command sent by the peer, checks the connecting user's permissions by using
- * unix socket credentials (if supported by the OS) and calls the corresponding
- * command handler if permissions are OK.
+ * This is called in each iteration of the select loop. If there is an incoming
+ * connection on \a accept_fd, this function reads the command sent by the peer,
+ * checks the connecting user's permissions by using unix socket credentials
+ * (if supported by the OS) and calls the corresponding command handler if
+ * permissions are OK.
*
- * \return positive on success, negative on errors
+ * \return Positive on success, negative on errors, zero if there was no
+ * connection to accept.
*
* \sa para_accept(), recv_cred_buffer()
* */
-int handle_connect(int accept_fd)
+int handle_connect(int accept_fd, fd_set *rfds)
{
- int i, argc, ret, clifd = -1;
+ int i, argc, ret, clifd;
char buf[MAXLINE], **argv = NULL;
struct sockaddr_un unix_addr;
uid_t uid;
- ret = para_accept(accept_fd, &unix_addr, sizeof(struct sockaddr_un));
- if (ret < 0)
- goto out;
- clifd = ret;
+ ret = para_accept(accept_fd, rfds, &unix_addr, sizeof(struct sockaddr_un), &clifd);
+ if (ret <= 0)
+ return ret;
ret = recv_cred_buffer(clifd, buf, sizeof(buf) - 1);
if (ret < 0)
goto out;
struct sender_client *sc;
int tx_ccid;
- if (dss->listen_fd < 0 || !FD_ISSET(dss->listen_fd, rfds))
- return;
- sc = accept_sender_client(dss);
+ sc = accept_sender_client(dss, rfds);
if (!sc)
return;
break;
}
}
- if (!FD_ISSET(hss->listen_fd, rfds))
- return;
- sc = accept_sender_client(hss);
+ sc = accept_sender_client(hss, rfds);
if (!sc)
return;
phsd = para_malloc(sizeof(*phsd));
* Wrapper around the accept system call.
*
* \param fd The listening socket.
+ * \param rfds An optional fd_set pointer.
* \param addr Structure which is filled in with the address of the peer socket.
* \param size Should contain the size of the structure pointed to by \a addr.
+ * \param new_fd Result pointer.
*
- * Accept incoming connections on \a addr. Retry if interrupted.
+ * Accept incoming connections on \a addr, retry if interrupted. If \a rfds is
+ * not \p NULL, return 0 if \a fd is not set in \a rfds without calling accept().
*
- * \return The new file descriptor on success, negative on errors.
+ * \return Negative on errors, zero if no connections are present to be accepted,
+ * one otherwise.
*
* \sa accept(2).
*/
-int para_accept(int fd, void *addr, socklen_t size)
+int para_accept(int fd, fd_set *rfds, void *addr, socklen_t size, int *new_fd)
{
- int new_fd;
+ int ret;
+ if (rfds && !FD_ISSET(fd, rfds))
+ return 0;
do
- new_fd = accept(fd, (struct sockaddr *) addr, &size);
- while (new_fd < 0 && errno == EINTR);
- return new_fd < 0? -ERRNO_TO_PARA_ERROR(errno) : new_fd;
+ ret = accept(fd, (struct sockaddr *) addr, &size);
+ while (ret < 0 && errno == EINTR);
+
+ if (ret >= 0) {
+ *new_fd = ret;
+ return 1;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return 0;
+ return -ERRNO_TO_PARA_ERROR(errno);
}
/**
int recv_bin_buffer(int fd, char *buf, size_t size);
int recv_buffer(int fd, char *buf, size_t size);
-int para_accept(int, void *addr, socklen_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, struct sockaddr_un *unix_addr,
mode_t mode);
int create_remote_socket(const char *name);
int generic_com_on(struct sender_status *ss, unsigned protocol);
void generic_com_off(struct sender_status *ss);
char *generic_sender_help(void);
-struct sender_client *accept_sender_client(struct sender_status *ss);
+struct sender_client *accept_sender_client(struct sender_status *ss, fd_set *rfds);
int send_queued_chunks(int fd, struct chunk_queue *cq,
size_t max_bytes_per_write);
int parse_fec_url(const char *arg, struct sender_command_data *scd);
* \sa \ref para_accept(), \ref mark_fd_nonblocking(), \ref acl_check_access(),
* \ref cq_new(), \ref add_close_on_fork_list().
*/
-struct sender_client *accept_sender_client(struct sender_status *ss)
+struct sender_client *accept_sender_client(struct sender_status *ss, fd_set *rfds)
{
struct sender_client *sc;
- int fd, ret = para_accept(ss->listen_fd, NULL, 0);
- if (ret < 0) {
+ int fd, ret;
+
+ if (ss->listen_fd < 0)
+ return NULL;
+ ret = para_accept(ss->listen_fd, rfds, NULL, 0, &fd);
+ if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+ if (ret <= 0)
return NULL;
- }
- fd = ret;
ret = -E_MAX_CLIENTS;
if (ss->max_clients > 0 && ss->num_clients >= ss->max_clients)
goto err_out;
pid_t child_pid;
uint32_t *chunk_table;
- if (!FD_ISSET(sct->listen_fd, &s->rfds))
- return;
- ret = para_accept(sct->listen_fd, NULL, 0);
- if (ret < 0)
+ ret = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd);
+ if (ret <= 0)
goto out;
- new_fd = ret;
peer_name = remote_name(new_fd);
PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
mmd->num_connects++;