diff options
Diffstat (limited to 'sockets.c')
-rw-r--r-- | sockets.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/sockets.c b/sockets.c new file mode 100644 index 0000000..6c1370b --- /dev/null +++ b/sockets.c @@ -0,0 +1,128 @@ +#include "sockets.h" + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) { + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +// Create socket to connect to real IRC server +int createserversocket(char *host, char *port) { + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv;// return value for getaddrinfo (for error message) + char s[INET6_ADDRSTRLEN]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and connect to the first we can + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("bouncer-server: socket"); + continue; + } + + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("bouncer-server: connect"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "bouncer-server: failed to connect\n"); + return 2; + } + + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); + printf("bouncer-server: connecting to %s\n", s); + + freeaddrinfo(servinfo); // all done with this structure + + return sockfd; +} + +// Create listening socket to listen for bouncer client connections +int createclientsocket(char *listenport) { + listenport = BOUNCERLISTENPORT; + + int listener; // listening socket descriptor + int rv; // return value for getaddrinfo (for error message) + struct addrinfo hints, *ai, *p; + int yes = 1; // for enabling socket options with setsockopt + + // get us a socket and bind it + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((rv = getaddrinfo(NULL, listenport, &hints, &ai)) != 0) { + fprintf(stderr, "bouncer-client: %s\n", gai_strerror(rv)); + exit(1); + } + + // Try for IPv6 + for (p = ai; p != NULL; p = p->ai_next) { + if (p->ai_family == AF_INET6) { + listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (listener != -1) { + // success, got IPv6! + printf("success, got IPv6! ai_family: %d\n", p->ai_family); + break; + } + } + } + + // Try for IPv4 if IPv6 failed + if (listener < 0) { + for (p = ai; p != NULL; p = p->ai_next) { + if (p->ai_family == AF_INET) { + listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (listener != -1) { + // moderate success, got IPv4! + printf("moderate success, got IPv4! ai_family: %d\n", p->ai_family); + break; + } + } + } + } + + // allow address re-use + setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); // 1 as in non-zero as in enable + + if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { + // failed to bind + close(listener); + printf("bouncer-client: failed to bind, exiting...\n"); + exit(1); + } + + // if we got here, it means we didn't get bound + if (p == NULL) { + fprintf(stderr, "bouncer-client: failed to bind\n"); + exit(2); + } + + freeaddrinfo(ai); // all done with this + + // listen + if (listen(listener, BACKLOG) == -1) { + perror("listen"); + exit(1); + } + + return listener; +} |