summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrb0nk500 <b0nk@b0nk.xyz>2022-08-02 22:35:50 -0300
committermrb0nk500 <b0nk@b0nk.xyz>2022-08-02 22:41:16 -0300
commitca4284c2160617bb57292f56ba6b9bd7fc0814db (patch)
tree567744447d63e15e1c3374afe706abeb8adbcdb2
parent33cfc0eff6153aabcebca99c98275931e9b88a58 (diff)
pullreqd: Add support for multiple sockets for all resolved addresses
This get's rid of a long standing TODO.
-rw-r--r--pullreqd.c103
1 files changed, 68 insertions, 35 deletions
diff --git a/pullreqd.c b/pullreqd.c
index dc9cd45..113bb11 100644
--- a/pullreqd.c
+++ b/pullreqd.c
@@ -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.");