03_TCP-socket-functions.diff
authorGerrit Renker <gerrit@erg.abdn.ac.uk>
Fri, 30 Nov 2007 09:23:51 +0000 (10:23 +0100)
committerAndre Noll <maan@systemlinux.org>
Fri, 30 Nov 2007 09:23:51 +0000 (10:23 +0100)
This converts the control connection and the HTTP streaming module to use the makesock() interface.

The specific changes are:
 * replace tcp_connect() directly with makesock();
 * replace tcp_listen() with para_listen() (in turn a wrapper around makesock());
 * init_sockaddr() becomes obsolete;
 * replaced use of sockaddr_in in para_accept() with NULL sockaddr argument
  -- the `remote' name of the socket is always available via getpeername(2),
-- this is exploited by replacing the reverse-name lookup with remote_name();
 * the sockaddr_in field `addr' of `struct http_client' has been replaced with `name' string
  -- name is filled in as in para_accept() above, using remote_name(),
-- unlike above, the remote_fd() call can later not be done, due to close_listed_fds().

The one thing I am really not sure about is host_in_access_perm_list():
 * It needed to be converted to allow address-independent HTTP streaming.
 * The conversion represents the obvious choice for doing this.
 * However, I have not (yet) tested it.
 * A problem that may arise is that when listening using AF_UNSPEC then _all_ addresses appear
   as IPv6 addresses (i.e. the test "family == AF_INET" would never hold true). In this case,
   a possible solution is to switch between AF_UNSPEC and AF_INET dependint on whether the
   configurable access-list is empty or non-empty, respectively.
 * A possible place for this chance would be http_send_init() or any other function calling
   open_tcp_port().

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
client_common.c
command.c
http_recv.c
http_send.c
net.c
net.h
server.c
server.h

index 1aab14f..7c31fcd 100644 (file)
@@ -81,7 +81,8 @@ static int client_connect(struct private_client_data *pcd)
        int ret;
 
        pcd->fd = -1;
-       ret = tcp_connect(pcd->conf.hostname_arg, pcd->conf.server_port_arg);
+       ret = makesock(AF_UNSPEC, IPPROTO_TCP, 0, pcd->conf.hostname_arg,
+                                                 pcd->conf.server_port_arg);
        if (ret < 0)
                return ret;
        pcd->fd = ret;
index c7d1c46..379cc4d 100644 (file)
--- a/command.c
+++ b/command.c
@@ -654,8 +654,8 @@ out:
 /**
  * perform user authentication and execute a command
  *
- * \param fd the file descriptor to send output to
- * \param addr socket address info of peer
+ * \param fd       The file descriptor to send output to
+ * \param peername  Identifies the connecting peer.
  *
  * \return EXIT_SUCCESS or EXIT_FAILURE
  *
@@ -680,7 +680,7 @@ out:
  *
  * \sa alarm(2), rc4(3), crypt.c, crypt.h
  */
-int handle_connect(int fd, struct sockaddr_in *addr)
+int handle_connect(int fd, const char *peername)
 {
        int ret, argc, use_rc4 = 0;
        char buf[4096];
@@ -790,7 +790,7 @@ int handle_connect(int fd, struct sockaddr_in *addr)
        mmd->num_commands++;
        mmd_unlock();
        PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name,
-               inet_ntoa(addr->sin_addr));
+                       peername);
        ret = cmd->handler(fd, argc, argv);
        if (ret >= 0) {
                ret = EXIT_SUCCESS;
index 13c7fb5..4283db4 100644 (file)
@@ -167,22 +167,18 @@ static int http_recv_open(struct receiver_node *rn)
 {
        struct private_http_recv_data *phd;
        struct http_recv_args_info *conf = rn->conf;
-       int ret;
+       int ret = makesock(AF_UNSPEC, IPPROTO_TCP, 0, conf->host_arg, conf->port_arg);
 
-       rn->buf = para_calloc(BUFSIZE);
-       rn->private_data = para_calloc(sizeof(struct private_http_recv_data));
-       phd = rn->private_data;
-       ret = tcp_connect(conf->host_arg, conf->port_arg);
        if (ret < 0)
-               goto err_out;
+               return ret;
+
+       rn->buf = para_calloc(BUFSIZE);
+       rn->private_data = phd = para_calloc(sizeof(struct private_http_recv_data));
+
        phd->fd = ret;
        mark_fd_nonblocking(phd->fd);
        phd->status = HTTP_CONNECTED;
        return 1;
-err_out:
-       free(rn->private_data);
-       free(rn->buf);
-       return ret;
 }
 
 /**
index 7be22da..799c06c 100644 (file)
 #include "fd.h"
 #include "chunk_queue.h"
 
-/** \cond convert sock_addr_in to ascii */
-#define CLIENT_ADDR(hc) inet_ntoa((hc)->addr.sin_addr)
-/* get the port number of a struct http_client */
-#define CLIENT_PORT(hc) (hc)->addr.sin_port
 #define HTTP_ERR_MSG "HTTP/1.0 400 Bad Request\n"
 /** \endcond */
 
@@ -59,8 +55,8 @@ static struct list_head access_perm_list;
 struct http_client {
        /** The file descriptor of the client. */
        int fd;
-       /** Address information about the client. */
-       struct sockaddr_in addr;
+       /** The socket `name' of the client. */
+       char *name;
        /** The client's current status. */
        enum http_status status;
        /** Non-zero if we included \a fd in the read set.*/
@@ -91,9 +87,10 @@ static struct sender *self;
 
 static void http_shutdown_client(struct http_client *hc, const char *msg)
 {
-       PARA_INFO_LOG("shutting down %s on fd %d (%s)\n", CLIENT_ADDR(hc),
-               hc->fd, msg);
+       PARA_INFO_LOG("shutting down %s on fd %d (%s)\n",
+                     hc->name, hc->fd, msg);
        numclients--;
+       free(hc->name);
        close(hc->fd);
        del_close_on_fork_list(hc->fd);
        cq_destroy(hc->cq);
@@ -192,7 +189,7 @@ static void http_send( long unsigned current_chunk,
                        queue_chunk_or_shutdown(hc, current_chunk, 0);
                        continue;
                }
-//             PARA_DEBUG_LOG("sending %d -> %s\n", len, CLIENT_ADDR(hc));
+//             PARA_DEBUG_LOG("sending %d -> %s\n", len, remote_name(hc->fd));
                ret = write(hc->fd, buf, len);
 //             PARA_DEBUG_LOG("ret: %d\n", ret);
                if (ret < 0) {
@@ -206,11 +203,21 @@ static void http_send( long unsigned current_chunk,
 
 static int host_in_access_perm_list(struct http_client *hc)
 {
-       struct access_info *ai, *tmp;
-       list_for_each_entry_safe(ai, tmp, &access_perm_list, node) {
-               unsigned mask = ((~0U) >> ai->netmask);
-               if ((hc->addr.sin_addr.s_addr & mask) == (ai->addr.s_addr & mask))
-                       return 1;
+       struct sockaddr_storage   ss;
+       socklen_t                 sslen = sizeof(ss);
+
+       if (getpeername(hc->fd, (struct sockaddr *)&ss, &sslen) < 0) {
+               PARA_ERROR_LOG("can not determine address family: %s\n", strerror(errno));
+       } else if (ss.ss_family == AF_INET) {
+               /* FIXME: access restriction is (currently) only supported for IPv4 */
+               struct access_info *ai, *tmp;
+               struct in_addr client_addr = ((struct sockaddr_in *)&ss)->sin_addr;
+
+               list_for_each_entry_safe(ai, tmp, &access_perm_list, node) {
+                       unsigned mask = ((~0U) >> ai->netmask);
+                       if ((client_addr.s_addr & mask) == (ai->addr.s_addr & mask))
+                               return 1;
+               }
        }
        return 0;
 }
@@ -223,7 +230,7 @@ static void http_post_select(fd_set *rfds, fd_set *wfds)
 
        list_for_each_entry_safe(hc, tmp, &clients, node) {
                i++;
-//             PARA_DEBUG_LOG("handling client %d: %s\n", i, CLIENT_ADDR(hc));
+//             PARA_DEBUG_LOG("handling client %d: %s\n", i, remote_name(hc->fd));
                switch (hc->status) {
                case HTTP_STREAMING: /* nothing to do */
                case HTTP_READY_TO_STREAM:
@@ -263,10 +270,11 @@ static void http_post_select(fd_set *rfds, fd_set *wfds)
                return;
        hc = para_calloc(sizeof(struct http_client));
        err_msg = "accept error";
-       hc->fd = para_accept(server_fd, &hc->addr, sizeof(struct sockaddr_in));
+       hc->fd = para_accept(server_fd, NULL, 0);
        if (hc->fd <= 0)
                goto err_out;
-       PARA_NOTICE_LOG("connection from %s (fd %d)\n", CLIENT_ADDR(hc), hc->fd);
+       hc->name = make_message("%s", remote_name(hc->fd));
+       PARA_NOTICE_LOG("connection from %s (fd %d)\n", hc->name, hc->fd);
        if (conf.http_max_clients_arg > 0 && numclients >=
                        conf.http_max_clients_arg) {
                err_msg = "server full";
@@ -281,16 +289,16 @@ static void http_post_select(fd_set *rfds, fd_set *wfds)
        }
        hc->status = HTTP_CONNECTED;
        hc->cq = cq_new(MAX_BACKLOG);
-       PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients,
-               CLIENT_ADDR(hc), hc->fd);
        numclients++;
+       PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients,
+                     hc->name, hc->fd);
        para_list_add(&hc->node, &clients);
        add_close_on_fork_list(hc->fd);
        mark_fd_nonblocking(hc->fd);
        return;
 err_out:
        PARA_WARNING_LOG("ignoring connect request from %s (%s)\n",
-               CLIENT_ADDR(hc), err_msg);
+                        hc->name, err_msg);
        if (hc->fd > 0)
                close(hc->fd);
        free(hc);
@@ -334,7 +342,7 @@ static int open_tcp_port(int port)
 {
        int ret;
 
-       server_fd = tcp_listen(port);
+       server_fd = para_listen(AF_UNSPEC, IPPROTO_TCP, port);
        if (server_fd < 0) {
                http_shutdown_clients();
                self->status = SENDER_OFF;
@@ -427,8 +435,8 @@ static char *http_info(void)
                ap = tmp;
        }
        list_for_each_entry_safe(hc, tmp_hc, &clients, node) {
-               char *tmp = make_message("%s%s:%d ", clnts? clnts : "",
-                       CLIENT_ADDR(hc), CLIENT_PORT(hc));
+               char *tmp = make_message("%s%s ", clnts? clnts : "",
+                                        hc->name);
                free(clnts);
                clnts = tmp;
        }
diff --git a/net.c b/net.c
index 8860312..f1c55b9 100644 (file)
--- a/net.c
+++ b/net.c
@@ -72,30 +72,6 @@ void disable_crypt(int fd)
 }
 
 
-/**
- * Initialize a struct sockaddr_in.
- *
- * \param addr A pointer to the struct to be initialized.
- * \param port The port number to use.
- * \param he The address to use.
- *
- * If \a he is null (server mode), \a addr->sin_addr is initialized with \p
- * INADDR_ANY.  Otherwise, the address given by \a he is copied to addr.
- */
-static void init_sockaddr(struct sockaddr_in *addr, int port, const struct hostent *he)
-{
-       /* host byte order */
-       addr->sin_family = AF_INET;
-       /* short, network byte order */
-       addr->sin_port = htons(port);
-       if (he)
-               addr->sin_addr = *((struct in_addr *)he->h_addr);
-       else
-               addr->sin_addr.s_addr = INADDR_ANY;
-       /* zero the rest of the struct */
-       memset(&addr->sin_zero, '\0', 8);
-}
-
 /**
  * Determine the socket type for a given layer-4 protocol.
  *
@@ -481,37 +457,6 @@ int recv_buffer(int fd, char *buf, size_t size)
        return n;
 }
 
-/**
- * Establish a tcp connection.
- *
- * \param host Hostname or IPv4 address.
- * \param port The tcp port.
- *
- * \return Negative on errors, a valid file descriptor on success.
- */
-int tcp_connect(char *host, int port)
-{
-       struct sockaddr_in addr;
-       struct hostent *he;
-       int ret, fd;
-
-       PARA_INFO_LOG("getting host info of %s\n", host);
-       /* FIXME: gethostbyname() is obsolete */
-       he = gethostbyname(host);
-       if (!he)
-               return -ERRNO_TO_PARA_ERROR(h_errno);
-       init_sockaddr(&addr, port, he);
-       ret = get_stream_socket(AF_INET);
-       if (ret < 0)
-               return ret;
-       fd = ret;
-       ret = PARA_CONNECT(fd, &addr);
-       if (ret >= 0)
-               return fd;
-       close(fd);
-       return ret;
-}
-
 /**
  * A wrapper around socket(2).
  *
@@ -736,50 +681,6 @@ int recv_cred_buffer(int fd, char *buf, size_t size)
 }
 #endif /* HAVE_UCRED */
 
-/**
- * Create a tcp socket, bind it and listen on the given port.
- *
- * \param port The tcp port to listen on.
- *
- * \return The file descriptor of the created socket, negative on errors.
- *
- * \sa get_stream_socket()
- * \sa setsockopt(2)
- * \sa bind(2)
- * \sa listen(2)
- */
-int tcp_listen(int port)
-{
-       struct sockaddr_in my_addr;
-       int fd, ret = get_stream_socket(AF_INET);
-
-       if (ret < 0)
-               return ret;
-       fd = ret;
-       ret = 1;
-       ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int));
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       init_sockaddr(&my_addr, port, NULL);
-       ret = bind(fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       ret = listen(fd, BACKLOG);
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       PARA_INFO_LOG("listening on port %d, fd %d\n", port, fd);
-       return fd;
-err:
-       close(fd);
-       return ret;
-}
-
 /**
  * receive a buffer and check for a pattern
  *
diff --git a/net.h b/net.h
index 965273a..7499ce6 100644 (file)
--- a/net.h
+++ b/net.h
@@ -46,7 +46,6 @@ extern char *remote_name(int sockfd);
 typedef void crypt_function(unsigned long len,
        const unsigned char *indata, unsigned char *outdata, void *private_data);
 
-int tcp_connect(char *host, int port);
 int get_stream_socket(int domain);
 int send_buffer(int, const char *);
 int send_bin_buffer(int, const char *, size_t);
@@ -60,7 +59,6 @@ int init_unix_addr(struct sockaddr_un *, const char *);
 int recv_cred_buffer(int, char *, size_t);
 ssize_t send_cred_buffer(int, char*);
 int recv_pattern(int fd, const char *pattern, size_t bufsize);
-int tcp_listen(int port);
 void enable_crypt(int fd, crypt_function *recv_f, crypt_function *send_f,
        void *private_data);
 void disable_crypt(int fd);
index 7fccea7..80cc8f4 100644 (file)
--- a/server.c
+++ b/server.c
@@ -303,7 +303,7 @@ static void setup_signal_handling(void)
 
 static unsigned init_network(void)
 {
-       int fd, ret = tcp_listen(conf.port_arg);
+       int fd, ret = para_listen(AF_UNSPEC, IPPROTO_TCP, conf.port_arg);
 
        if (ret < 0)
                goto err;
@@ -457,7 +457,7 @@ int main(int argc, char *argv[])
 {
        /* listen on sock_fd, new connection on new_fd */
        int sockfd, new_fd;
-       struct sockaddr_in their_addr;
+       char *peer_name;
        int i, max_fileno, ret;
        pid_t chld_pid;
        fd_set rfds, wfds;
@@ -539,11 +539,11 @@ genocide:
        if (!FD_ISSET(sockfd, &rfds))
                goto repeat;
 
-       new_fd = para_accept(sockfd, &their_addr, sizeof(struct sockaddr_in));
+       new_fd = para_accept(sockfd, NULL, 0);
        if (new_fd < 0)
                goto repeat;
-       PARA_INFO_LOG("got connection from %s, forking\n",
-               inet_ntoa(their_addr.sin_addr));
+       peer_name = remote_name(new_fd);
+       PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
        mmd->num_connects++;
        mmd->active_connections++;
        random();
@@ -566,7 +566,6 @@ genocide:
         */
        for (i = argc - 1; i >= 0; i--)
                memset(argv[i], 0, strlen(argv[i]));
-       sprintf(argv[0], "para_server (serving %s)",
-               inet_ntoa(their_addr.sin_addr));
-       return handle_connect(new_fd, &their_addr);
+       sprintf(argv[0], "para_server (serving %s)", peer_name);
+       return handle_connect(new_fd, peer_name);
 }
index c248f52..84338e9 100644 (file)
--- a/server.h
+++ b/server.h
@@ -108,6 +108,6 @@ extern struct server_args_info conf;
 /** Socket for afs-server communication. */
 extern int afs_socket;
 
-int handle_connect(int fd, struct sockaddr_in *addr);
+int handle_connect(int fd, const char *peername);
 void mmd_unlock(void);
 void mmd_lock(void);