Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If socket allocations fails try again without IPv6 #245

Merged
merged 1 commit into from
May 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 44 additions & 46 deletions src/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,47 +44,15 @@ static uint16_t get_next_port_in_range(uint16_t begin, uint16_t end) {
return next;
}

socket_t udp_create_socket(const udp_socket_config_t *config) {
socket_t sock = INVALID_SOCKET;

// Obtain local Address
struct addrinfo *ai_list = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
if (getaddrinfo(config->bind_address, "0", &hints, &ai_list) != 0) {
JLOG_ERROR("getaddrinfo for binding address failed, errno=%d", sockerrno);
return INVALID_SOCKET;
}

static socket_t create_socket_for_addrinfo(const udp_socket_config_t *config,
const struct addrinfo *ai) {
// Create socket
struct addrinfo *ai = NULL;
const int families[2] = {AF_INET6, AF_INET}; // Prefer IPv6
const char *names[2] = {"IPv6", "IPv4"};
for (int i = 0; i < 2; ++i) {
ai = find_family(ai_list, families[i]);
if (!ai)
continue;

sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == INVALID_SOCKET) {
JLOG_WARN("UDP socket creation for %s family failed, errno=%d", names[i], sockerrno);
continue;
}

break;
}

socket_t sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == INVALID_SOCKET) {
JLOG_ERROR("UDP socket creation failed: no suitable address family");
goto error;
JLOG_WARN("UDP socket creation failed, errno=%d", sockerrno);
return INVALID_SOCKET;
}

assert(ai != NULL);

// Listen on both IPv6 and IPv4
const sockopt_t disabled = 0;
if (ai->ai_family == AF_INET6)
Expand Down Expand Up @@ -126,11 +94,10 @@ socket_t udp_create_socket(const udp_socket_config_t *config) {
if (bind(sock, ai->ai_addr, (socklen_t)ai->ai_addrlen) == 0) {
JLOG_DEBUG("UDP socket bound to %s:%hu",
config->bind_address ? config->bind_address : "any", udp_get_port(sock));
freeaddrinfo(ai_list);
return sock;
}

JLOG_ERROR("UDP socket binding failed, errno=%d", sockerrno);
JLOG_WARN("UDP socket binding failed, errno=%d", sockerrno);

} else if (config->port_begin == config->port_end) {
uint16_t port = config->port_begin;
Expand All @@ -142,11 +109,10 @@ socket_t udp_create_socket(const udp_socket_config_t *config) {
if (bind(sock, (struct sockaddr *)&addr, addrlen) == 0) {
JLOG_DEBUG("UDP socket bound to %s:%hu",
config->bind_address ? config->bind_address : "any", port);
freeaddrinfo(ai_list);
return sock;
}

JLOG_ERROR("UDP socket binding failed on port %hu, errno=%d", port, sockerrno);
JLOG_WARN("UDP socket binding failed on port %hu, errno=%d", port, sockerrno);

} else {
struct sockaddr_storage addr;
Expand All @@ -160,24 +126,56 @@ socket_t udp_create_socket(const udp_socket_config_t *config) {
if (bind(sock, (struct sockaddr *)&addr, addrlen) == 0) {
JLOG_DEBUG("UDP socket bound to %s:%hu",
config->bind_address ? config->bind_address : "any", port);
freeaddrinfo(ai_list);
return sock;
}
} while ((sockerrno == SEADDRINUSE || sockerrno == SEACCES) && retries-- > 0);

JLOG_ERROR("UDP socket binding failed on port range %s:[%hu,%hu], errno=%d",
config->bind_address ? config->bind_address : "any", config->port_begin,
config->port_end, sockerrno);
JLOG_WARN("UDP socket binding failed on port range %s:[%hu,%hu], errno=%d",
config->bind_address ? config->bind_address : "any", config->port_begin,
config->port_end, sockerrno);
}

error:
freeaddrinfo(ai_list);
if (sock != INVALID_SOCKET)
closesocket(sock);

return INVALID_SOCKET;
}

socket_t udp_create_socket(const udp_socket_config_t *config) {
// Obtain local Address
struct addrinfo *ai_list = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
if (getaddrinfo(config->bind_address, "0", &hints, &ai_list) != 0) {
JLOG_ERROR("getaddrinfo for binding address failed, errno=%d", sockerrno);
return INVALID_SOCKET;
}

const int families[2] = {AF_INET6, AF_INET}; // Prefer IPv6
const char *names[2] = {"IPv6", "IPv4"};
for (int i = 0; i < 2; ++i) {
const struct addrinfo *ai = find_family(ai_list, families[i]);
if (!ai)
continue;

JLOG_DEBUG("Opening UDP socket for %s family", names[i]);
socket_t sock = create_socket_for_addrinfo(config, ai);
if (sock != INVALID_SOCKET) {
freeaddrinfo(ai_list);
return sock;
}
}

JLOG_ERROR("UDP socket opening failed");
freeaddrinfo(ai_list);
return INVALID_SOCKET;
}

int udp_recvfrom(socket_t sock, char *buffer, size_t size, addr_record_t *src) {
while (true) {
src->len = sizeof(src->addr);
Expand Down
Loading