summaryrefslogtreecommitdiff
path: root/sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'sockets.c')
-rw-r--r--sockets.c128
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;
+}