Race parallel connects
parent
6aecd7a712
commit
e3e2b36ecf
79
irc.c
79
irc.c
|
@ -15,9 +15,11 @@
|
|||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -29,6 +31,60 @@
|
|||
|
||||
#include "chat.h"
|
||||
|
||||
static int connectRace(const char *host, const char *port) {
|
||||
int error;
|
||||
struct addrinfo *head;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
error = getaddrinfo(host, port, &hints, &head);
|
||||
if (error) errx(EX_NOHOST, "getaddrinfo: %s", gai_strerror(error));
|
||||
|
||||
nfds_t len = 0;
|
||||
enum { SocksLen = 16 };
|
||||
struct pollfd socks[SocksLen];
|
||||
for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
|
||||
if (len == SocksLen) break;
|
||||
|
||||
socks[len].events = POLLOUT;
|
||||
socks[len].fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (socks[len].fd < 0) err(EX_OSERR, "socket");
|
||||
|
||||
error = fcntl(socks[len].fd, F_SETFL, O_NONBLOCK);
|
||||
if (error) err(EX_OSERR, "fcntl");
|
||||
|
||||
error = connect(socks[len].fd, ai->ai_addr, ai->ai_addrlen);
|
||||
if (error && errno != EINPROGRESS && errno != EINTR) {
|
||||
close(socks[len].fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
if (!len) err(EX_UNAVAILABLE, "connect");
|
||||
freeaddrinfo(head);
|
||||
|
||||
int ready = poll(socks, len, -1);
|
||||
if (ready < 0) err(EX_IOERR, "poll");
|
||||
|
||||
int sock = -1;
|
||||
for (nfds_t i = 0; i < len; ++i) {
|
||||
if ((socks[i].revents & POLLOUT) && sock < 0) {
|
||||
sock = socks[i].fd;
|
||||
} else {
|
||||
close(socks[i].fd);
|
||||
}
|
||||
}
|
||||
if (sock < 0) errx(EX_UNAVAILABLE, "no socket became writable");
|
||||
|
||||
error = fcntl(sock, F_SETFL, 0);
|
||||
if (error) err(EX_IOERR, "fcntl");
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static struct tls *client;
|
||||
|
||||
static void webirc(const char *pass) {
|
||||
|
@ -59,28 +115,7 @@ int ircConnect(
|
|||
if (error) errx(EX_SOFTWARE, "tls_configure");
|
||||
tls_config_free(config);
|
||||
|
||||
struct addrinfo *head;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
error = getaddrinfo(host, port, &hints, &head);
|
||||
if (error) errx(EX_NOHOST, "getaddrinfo: %s", gai_strerror(error));
|
||||
|
||||
int sock = -1;
|
||||
for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
|
||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (sock < 0) err(EX_OSERR, "socket");
|
||||
|
||||
error = connect(sock, ai->ai_addr, ai->ai_addrlen);
|
||||
if (!error) break;
|
||||
|
||||
close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
if (sock < 0) err(EX_UNAVAILABLE, "connect");
|
||||
freeaddrinfo(head);
|
||||
int sock = connectRace(host, port);
|
||||
|
||||
error = fcntl(sock, F_SETFD, FD_CLOEXEC);
|
||||
if (error) err(EX_IOERR, "fcntl");
|
||||
|
|
Loading…
Reference in New Issue