From d2e164526bed7f523043b7e4ec5bd282d5bc6f19 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Fri, 30 Nov 2007 10:23:51 +0100 Subject: [PATCH] 03_TCP-socket-functions.diff 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 --- client_common.c | 3 +- command.c | 8 ++-- http_recv.c | 16 +++----- http_send.c | 54 +++++++++++++++------------ net.c | 99 ------------------------------------------------- net.h | 2 - server.c | 15 ++++---- server.h | 2 +- 8 files changed, 51 insertions(+), 148 deletions(-) diff --git a/client_common.c b/client_common.c index 1aab14fb..7c31fcdd 100644 --- a/client_common.c +++ b/client_common.c @@ -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; diff --git a/command.c b/command.c index c7d1c467..379cc4d9 100644 --- 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; diff --git a/http_recv.c b/http_recv.c index 13c7fb57..4283db4b 100644 --- a/http_recv.c +++ b/http_recv.c @@ -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; } /** diff --git a/http_send.c b/http_send.c index 7be22da0..799c06cc 100644 --- a/http_send.c +++ b/http_send.c @@ -25,10 +25,6 @@ #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 8860312b..f1c55b91 100644 --- 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 965273a8..7499ce62 100644 --- 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); diff --git a/server.c b/server.c index 7fccea77..80cc8f46 100644 --- 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); } diff --git a/server.h b/server.h index c248f520..84338e92 100644 --- 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); -- 2.39.5