Skip to content

Instantly share code, notes, and snippets.

@romuloceccon
Last active July 5, 2018 09:11
Show Gist options
  • Save romuloceccon/c50cc1ebec38fa86bfe42948ea47e8e9 to your computer and use it in GitHub Desktop.
Save romuloceccon/c50cc1ebec38fa86bfe42948ea47e8e9 to your computer and use it in GitHub Desktop.
EventMachine/ECONNREFUSED bug on OSX
/*
This program demonstrates a bug with eventmachine on OSX. When /etc/hosts is
set like this:
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
the program will fail with a ECONNREFUSED (61) error when localhost is used
to resolve the local interface address. The program shows that in such
scenario getaddrinfo returns 4 addrinfo structures, with families 0x1e, 0x1e,
0x02, 0x02. When using 127.0.0.1 or 0.0.0.0 only families 0x02, 0x02 are
returned. It looks like the correct behavior would be to try connecting to
all address until one succeeds (see
http://www.tortonesi.com/blog/2015/03/13/fixing-getaddrinfo/). eventmachine
tries only the first one, so in the "localhost" case it creates a socket with
family set to 0x1e, which appears to be the main reason why ECONNREFUSED is
returned.
Removing the "::1" line from /etc/hosts workarounds the problem.
Compile: $ gcc -o tcptest -Wall tcptest.c
Start listener: $ nc -kl 9001
Test: $ tcptest 127.0.0.1 9001; tcptest 0.0.0.0 9001; tcptest localhost 9001
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <errno.h>
int main(int argc, char **argv)
{
struct sockaddr_storage bind_as;
size_t bind_as_len;
struct addrinfo *ai;
struct addrinfo hints;
int gai;
int sd;
int i;
struct addrinfo *ptr;
if (argc != 3) {
printf("invalid args\n");
return 1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
gai = getaddrinfo(argv[1], argv[2], &hints, &ai);
if (gai != 0) {
printf("getaddrinfo error: %d\n", gai);
return 1;
}
for (ptr = ai; ptr != NULL; ptr = ptr->ai_next) {
printf("%04x: ", ptr->ai_family);
for (i = 0; i < ptr->ai_addrlen; i++)
printf("%02x ", (unsigned int) *(((unsigned char *) ptr->ai_addr) + i));
printf("\n");
}
memcpy(&bind_as, ai->ai_addr, ai->ai_addrlen);
bind_as_len = ai->ai_addrlen;
freeaddrinfo(ai);
sd = socket(bind_as.ss_family, SOCK_STREAM, 0);
if (sd == -1) {
printf("invalid socket\n");
return 1;
}
if (connect(sd, (struct sockaddr *)&bind_as, bind_as_len) != 0) {
printf("connect error: %d\n", errno);
return 1;
}
printf("ok\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment