diff options
author | mrb0nk500 <b0nk@b0nk.xyz> | 2022-08-02 22:35:50 -0300 |
---|---|---|
committer | mrb0nk500 <b0nk@b0nk.xyz> | 2022-08-02 22:41:16 -0300 |
commit | ca4284c2160617bb57292f56ba6b9bd7fc0814db (patch) | |
tree | 567744447d63e15e1c3374afe706abeb8adbcdb2 /pullreqd.c | |
parent | 33cfc0eff6153aabcebca99c98275931e9b88a58 (diff) |
pullreqd: Add support for multiple sockets for all resolved addresses
This get's rid of a long standing TODO.
Diffstat (limited to 'pullreqd.c')
-rw-r--r-- | pullreqd.c | 103 |
1 files changed, 68 insertions, 35 deletions
@@ -8,6 +8,7 @@ #include <unistd.h> #include "config.h" #include "git.h" +#include "linked_list.h" #include "macros.h" #include "network.h" @@ -80,14 +81,9 @@ int init_config(char *config_file, config **cfg) { return (*cfg != NULL); } -int init_socket(config *cfg) { - union sock_addr { - struct sockaddr sa; - struct sockaddr_un sa_un; - struct sockaddr_in sa_in; - } sock_addr; - /* Size of the socket address we're using. */ - size_t sockaddr_size = 0; +int *init_socket(config *cfg) { + linked_list *sock_list = NULL; + int *sock_arr = NULL; /* Set socket type to unix socket, if socket-type was set to unix, otherwise set it to network socket. */ const int sock_type = (strcasecmp(cfg->sock_type, "unix") == 0) ? AF_UNIX : AF_INET; @@ -96,12 +92,23 @@ int init_socket(config *cfg) { /* Is the path too long? */ if (path_length >= UNIX_PATH_MAX) { log(LOG_ERR, "The socket path is too long, and exceeded %i characters.", UNIX_PATH_MAX); - return -1; + return NULL; + } else { + int fd; + struct sockaddr_un sa_un; + sa_un.sun_family = sock_type; + memcpy(sa_un.sun_path, cfg->sock, path_length+1); + + fd = create_socket((struct sockaddr *)&sa_un, sizeof(struct sockaddr_un)); + + if (fd < 0) { + return NULL; + } else { + int *sock = calloc(1, sizeof(int)); + *sock = fd; + sock_list = add_node(&sock_list, sock); + } } - - sockaddr_size = sizeof(sock_addr.sa_un); - sock_addr.sa_un.sun_family = sock_type; - memcpy(sock_addr.sa_un.sun_path, cfg->sock, path_length+1); } else { struct addrinfo hints, *ainfo_root, *ainfo; @@ -109,30 +116,48 @@ int init_socket(config *cfg) { hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_SEQPACKET; - /*hints.ai_protocol = IPPROTO_SCTP;*/ + hints.ai_protocol = IPPROTO_SCTP; hints.ai_flags = AI_PASSIVE; const int gai_ret = getaddrinfo(cfg->sock, cfg->port, &hints, &ainfo_root); /* Did getaddrinfo fail? */ if (gai_ret) { log_reason(LOG_ERR, "getaddrinfo() failed for hostname %s.", cfg->sock, gai_strerror(gai_ret)); - return -1; + return NULL; } - /* TODO: Create sockets for all resolved addresses, instead of just the first. */ - sockaddr_size = ainfo_root->ai_addrlen; - sock_addr.sa = *ainfo_root->ai_addr; + for (struct addrinfo *ai = ainfo_root; ai != NULL; ai = ai->ai_next) { + const int fd = create_socket(ai->ai_addr, ai->ai_addrlen); + if (fd >= 0) { + int *sock = calloc(1, sizeof(int)); + *sock = fd; + sock_list = add_node(&sock_list, sock); + log(LOG_DEBUG, "ip addr: \"%s\"", addr_to_str(ai->ai_addr, ai->ai_addrlen)); + } + } freeaddrinfo(ainfo_root); } - /* Create a new listen socket. */ - const int fd = socket_create(&sock_addr.sa, sockaddr_size); + int sock_count = linked_list_size(sock_list); + sock_arr = calloc(sock_count+1, sizeof(int)); + sock_arr[sock_count--] = -1; + + for (linked_list *node = sock_list; node != NULL; node = node->prev, --sock_count) { + int *sock = (int *)node->data; + sock_arr[sock_count] = *sock; + node->data = NULL; + free(sock); + } + + log(LOG_NOTICE, "Successfully created %i sockets for hostname \"%s\".", linked_list_size(sock_list), (cfg->sock != NULL) ? cfg->sock : "*"); + + cleanup_linked_list(sock_list); - return fd; + return sock_arr; } -int main_loop(config *cfg, int listen_socket, git_repo **repos) { +int main_loop(config *cfg, int *listen_sockets, git_repo **repos) { int done = 0; struct stat st; @@ -149,13 +174,21 @@ int main_loop(config *cfg, int listen_socket, git_repo **repos) { return 0; } -void cleanup(config *cfg, int listen_socket, git_repo **repos) { - if (listen_socket > 0) { - close(listen_socket); - /* Is this a unix domain socket? */ - if (strcasecmp(cfg->sock_type, "unix") == 0) { - unlink(cfg->sock); +void cleanup(config *cfg, int *listen_sockets, git_repo **repos) { + if (listen_sockets != NULL) { + for (int i = 0; listen_sockets[i] >= 0; ++i) { + struct sockaddr *sa = get_sock_addr(listen_sockets[i]); + /* Close the socket. */ + close(listen_sockets[i]); + /* Is this a unix domain socket? */ + if (sa->sa_family == AF_UNIX) { + struct sockaddr_un *sa_un = (struct sockaddr_un *)sa; + /* Unlink the path. */ + unlink(sa_un->sun_path); + } + free(sa); } + free(listen_sockets); } if (cfg) { @@ -172,7 +205,7 @@ int main(int argc, char **argv) { git_repo **repos = NULL; char *config_file = "test.conf"; int config_read = 0; - int listen_socket = -1; + int *listen_sockets = NULL; int exit_status = EXIT_FAILURE; /* Start it in daemon mode. */ @@ -188,19 +221,19 @@ int main(int argc, char **argv) { /* Did we successfully read the config file? */ if (config_read) { - /* Create the Listen socket. */ - listen_socket = init_socket(cfg); + /* Create the Listen socket(s). */ + listen_sockets = init_socket(cfg); } - /* Did we successfully read the config file, and create the listen socket? */ - if (config_read && listen_socket >= 0) { + /* Did we successfully read the config file, and create any listen sockets? */ + if (config_read && listen_sockets != NULL) { repos = init_git(cfg); if (repos != NULL) { - exit_status = main_loop(cfg, listen_socket, repos); + exit_status = main_loop(cfg, listen_sockets, repos); } } - cleanup(cfg, listen_socket, repos); + cleanup(cfg, listen_sockets, repos); log(LOG_NOTICE, "pullreqd stopped."); |