Rework para_accept().
authorAndre Noll <maan@systemlinux.org>
Sun, 25 Apr 2010 18:01:06 +0000 (20:01 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 25 Apr 2010 18:01:06 +0000 (20:01 +0200)
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
audiod.c
audiod.h
audiod_command.c
dccp_send.c
http_send.c
net.c
net.h
send.h
send_common.c
server.c

diff --git a/afs.c b/afs.c
index d738c3d..6286806 100644 (file)
--- 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));
index 380e53e..f0d450a 100644 (file)
--- 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();
index f0cb6ca..44b430c 100644 (file)
--- 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);
index 8024ec5..f9349a1 100644 (file)
@@ -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;
index fb2eafc..6248ae8 100644 (file)
@@ -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;
 
index c8879fe..424d63b 100644 (file)
@@ -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 64693be..59b7f36 100644 (file)
--- 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 c43249e..457c24d 100644 (file)
--- 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 85e5ed1..acf62db 100644 (file)
--- 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);
index f931fda..b44c813 100644 (file)
@@ -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;
index 89a8137..2afb6db 100644 (file)
--- 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++;