summaryrefslogtreecommitdiff
path: root/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils.c')
-rw-r--r--utils.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/utils.c b/utils.c
index 0718ea9..8749c75 100644
--- a/utils.c
+++ b/utils.c
@@ -164,7 +164,7 @@ debug_resource_usage()
}
void
-socket_set_gaming_options(struct cfg *cfg, int sfd)
+socket_set_low_latency(struct cfg *cfg, int sfd)
{
int option;
@@ -187,6 +187,98 @@ socket_set_gaming_options(struct cfg *cfg, int sfd)
perror("setsockopt");
}
+static void
+connection_set_local_addr(struct cfg *cfg, struct connection *conn, int fd)
+{
+ if (fd < 0 || getsockname(fd, (struct sockaddr *)&conn->local.storage,
+ &conn->local.addrlen) < 0)
+ sprintf(conn->localstr, "<unknown>");
+ else
+ sockaddr_to_str(&conn->local, conn->localstr, sizeof(conn->localstr));
+}
+
+static void connect_next(struct cfg *cfg, struct uring_task *task, struct connection *conn);
+
+static void
+connect_cb(struct cfg *cfg, struct uring_task *task, int res)
+{
+ struct connection *conn = task->priv;
+
+ if (res < 0) {
+ fprintf(stderr, "%s: connection to %s failed\n",
+ __func__, conn->remotestr);
+ uring_task_close_fd(cfg, task);
+ connect_next(cfg, task, conn);
+ return;
+ }
+
+ connection_set_local_addr(cfg, conn, task->fd);
+
+ fprintf(stderr, "%s: (%s) connection established %s -> %s\n",
+ __func__, task->name, conn->localstr, conn->remotestr);
+
+ conn->callback(cfg, conn, true);
+}
+
+static void
+connect_next(struct cfg *cfg, struct uring_task *task, struct connection *conn)
+{
+ struct sockaddr_in46 *remote, *tmp;
+ int sfd;
+ unsigned i;
+
+again:
+ i = 0;
+ remote = NULL;
+ list_for_each_entry(tmp, conn->addrs, list) {
+ if (i == conn->next_addr) {
+ remote = tmp;
+ break;
+ }
+ i++;
+ }
+
+ if (!remote) {
+ fprintf(stderr, "%s: no more remote addresses to attempt\n", __func__);
+ conn->callback(cfg, conn, false);
+ return;
+ }
+
+ conn->next_addr++;
+ conn->remote = *remote;
+ sockaddr_to_str(&conn->remote, conn->remotestr, sizeof(conn->remotestr));
+ fprintf(stderr, "%s: attempting to connect to %s\n",
+ task->name, conn->remotestr);
+
+ sfd = socket(conn->remote.storage.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sfd < 0) {
+ perror("socket");
+ goto again;
+ }
+
+ socket_set_low_latency(cfg, sfd);
+
+ task->priv = conn;
+ uring_task_set_fd(task, sfd);
+ uring_connect(cfg, task, &conn->remote, connect_cb);
+}
+
+void
+connect_any(struct cfg *cfg, struct uring_task *task,
+ struct list_head *addrs, struct connection *conn,
+ void (*callback)(struct cfg *, struct connection *, int res))
+{
+ if (!cfg || !task || !addrs || !conn || !callback) {
+ fprintf(stderr, "%s: invalid arguments\n", __func__);
+ return;
+ }
+
+ conn->next_addr = 0;
+ conn->addrs = addrs;
+ conn->callback = callback;
+ connect_next(cfg, task, conn);
+}
+
uint16_t sockaddr_port(struct sockaddr_in46 *addr)
{
switch (addr->storage.ss_family) {