From 8dab386f87d2998fd26126600ca7faf56d5a35d1 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sun, 25 Apr 2010 20:01:06 +0200 Subject: [PATCH] Rework para_accept(). Make it take an fd_set pointer and check the fd for readability within para_accept() rather than in each caller. Also, don't return an error on EAGAIN. Fix all callers accordingly. Most of them become a bit simpler due to this change. --- afs.c | 9 +++------ audiod.c | 4 +--- audiod.h | 2 +- audiod_command.c | 28 ++++++++++++++-------------- dccp_send.c | 4 +--- http_send.c | 4 +--- net.c | 27 ++++++++++++++++++++------- net.h | 2 +- send.h | 2 +- send_common.c | 13 ++++++++----- server.c | 7 ++----- 11 files changed, 53 insertions(+), 49 deletions(-) diff --git a/afs.c b/afs.c index d738c3d9..62868060 100644 --- a/afs.c +++ b/afs.c @@ -930,14 +930,11 @@ static void command_post_select(struct sched *s, struct task *t) 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)); diff --git a/audiod.c b/audiod.c index 380e53e0..f0d450a6 100644 --- a/audiod.c +++ b/audiod.c @@ -1023,9 +1023,7 @@ static void command_post_select(struct sched *s, struct task *t) 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(); diff --git a/audiod.h b/audiod.h index f0cb6cae..44b430c8 100644 --- a/audiod.h +++ b/audiod.h @@ -70,7 +70,7 @@ extern struct audiod_args_info conf; 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); diff --git a/audiod_command.c b/audiod_command.c index 8024ec56..f9349a1d 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -421,31 +421,31 @@ static int check_perms(uid_t uid) } /** - * 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; diff --git a/dccp_send.c b/dccp_send.c index fb2eafc9..6248ae80 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -70,9 +70,7 @@ static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds) 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; diff --git a/http_send.c b/http_send.c index c8879fec..424d63b2 100644 --- a/http_send.c +++ b/http_send.c @@ -122,9 +122,7 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds) 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)); diff --git a/net.c b/net.c index 64693bef..59b7f367 100644 --- a/net.c +++ b/net.c @@ -756,23 +756,36 @@ int recv_buffer(int fd, char *buf, size_t size) * 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); } /** diff --git a/net.h b/net.h index c43249ea..457c24dc 100644 --- a/net.h +++ b/net.h @@ -139,7 +139,7 @@ __printf_2_3 int send_va_buffer(int fd, const char *fmt, ...); 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); diff --git a/send.h b/send.h index 85e5ed1f..acf62db4 100644 --- a/send.h +++ b/send.h @@ -140,7 +140,7 @@ void generic_com_deny(struct sender_command_data *scd, 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); diff --git a/send_common.c b/send_common.c index f931fdaf..b44c8133 100644 --- a/send_common.c +++ b/send_common.c @@ -348,15 +348,18 @@ void generic_com_off(struct sender_status *ss) * \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; diff --git a/server.c b/server.c index 89a81372..2afb6db5 100644 --- a/server.c +++ b/server.c @@ -366,12 +366,9 @@ static void command_post_select(struct sched *s, struct task *t) 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++; -- 2.30.2