summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blabouncer.c188
-rw-r--r--functions.c52
-rw-r--r--functions.h30
-rw-r--r--sockets.c128
-rw-r--r--sockets.h29
5 files changed, 242 insertions, 185 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 07784a9..4ed2c9a 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -16,197 +16,15 @@
#include <arpa/inet.h>
#include <sys/select.h>
+#include "functions.h"
+#include "sockets.h"
+
#define MAXDATASIZE 513 // max number of bytes we can get at once (RFC2812 says 512, plus one for null terminator)
#define STDIN 0 // stdin is fd 0
-#define BACKLOG 10 // maximum length to which the queue of pending connections for sockfd may grow
#define MAXCLIENTS 32 // maximum number of clients that can connect to the bouncer at a time
-#define BOUNCERLISTENPORT "1234" // TODO: change this to a config option!
-
-// getstdin() return codes
-#define OK 0
-#define NO_INPUT 1
-#define TOO_LONG 2
-
int debugmode = 0;
-// Print a debugging message, if debugging enabled
-void debug(char *string) {
- if (debugmode) {
- printf("DEBUG: %s\n", string);
- }
-}
-
-// Get stdin line with buffer overrun protection
-static int getstdin(char *prompt, char *buff, size_t sz) {
- int ch, extra;
-
- // Print optional prompt
- if (prompt != NULL) {
- printf ("%s", prompt);
- fflush (stdout);
- }
-
- // Get the intput from stdin
- if (fgets (buff, sz, stdin) == NULL) {
- return NO_INPUT;
- }
-
- // If it was too long, there'll be no newline. In that case, we flush
- // to end of line so that excess doesn't affect the next call.
- if (buff[strlen(buff) - 1] != '\n') { // strlen of the actually entered line, not the original array size
- extra = 0;
- while (((ch = getchar()) != '\n') && (ch != EOF)) {
- extra = 1;
- }
- return (extra == 1) ? TOO_LONG : OK;
- }
-
- // Otherwise remove newline and give string back to caller.
- buff[strlen(buff) - 1] = '\0';
- return OK;
-}
-
-// Append CR-LF to the end of a string (after cleaning up any existing trailing CR or LF)
-void appendcrlf(char *string) {
- // Make sure it doesn't already end with CR or LF
- while (string[strlen(string) - 1] == '\r' || string[strlen(string) - 1] == '\r') {
- string[strlen(string) - 1] = '\0';
- }
-
- int startlen = strlen(string);
- string[startlen] = '\r';
- string[startlen + 1] = '\n';
- string[startlen + 2] = '\0';
-}
-
-// 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;
-}
-
// Relay/send message to all clients (optionally except one)
// "except" is used to send to all clients _except_ the fd provided (except = 0 avoids this, i.e. sends to all)
int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int str_len, int except) {
diff --git a/functions.c b/functions.c
new file mode 100644
index 0000000..73302b8
--- /dev/null
+++ b/functions.c
@@ -0,0 +1,52 @@
+#include "functions.h"
+
+// Print a debugging message, if debugging enabled
+int debugmode;
+void debug(char *string) {
+ if (debugmode) {
+ printf("DEBUG: %s\n", string);
+ }
+}
+
+// Get stdin line with buffer overrun protection
+int getstdin(char *prompt, char *buff, size_t sz) {
+ int ch, extra;
+
+ // Print optional prompt
+ if (prompt != NULL) {
+ printf ("%s", prompt);
+ fflush (stdout);
+ }
+
+ // Get the intput from stdin
+ if (fgets (buff, sz, stdin) == NULL) {
+ return NO_INPUT;
+ }
+
+ // If it was too long, there'll be no newline. In that case, we flush
+ // to end of line so that excess doesn't affect the next call.
+ if (buff[strlen(buff) - 1] != '\n') { // strlen of the actually entered line, not the original array size
+ extra = 0;
+ while (((ch = getchar()) != '\n') && (ch != EOF)) {
+ extra = 1;
+ }
+ return (extra == 1) ? TOO_LONG : OK;
+ }
+
+ // Otherwise remove newline and give string back to caller.
+ buff[strlen(buff) - 1] = '\0';
+ return OK;
+}
+
+// Append CR-LF to the end of a string (after cleaning up any existing trailing CR or LF)
+void appendcrlf(char *string) {
+ // Make sure it doesn't already end with CR or LF
+ while (string[strlen(string) - 1] == '\r' || string[strlen(string) - 1] == '\r') {
+ string[strlen(string) - 1] = '\0';
+ }
+
+ int startlen = strlen(string);
+ string[startlen] = '\r';
+ string[startlen + 1] = '\n';
+ string[startlen + 2] = '\0';
+}
diff --git a/functions.h b/functions.h
new file mode 100644
index 0000000..4605da6
--- /dev/null
+++ b/functions.h
@@ -0,0 +1,30 @@
+#ifndef FUNCTIONS_H_INCLUDED
+#define FUNCTIONS_H_INCLUDED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+
+// getstdin() return codes
+#define OK 0
+#define NO_INPUT 1
+#define TOO_LONG 2
+
+// Print a debugging message, if debugging enabled
+void debug(char *string);
+
+// Get stdin line with buffer overrun protection
+int getstdin(char *prompt, char *buff, size_t sz);
+
+// Append CR-LF to the end of a string (after cleaning up any existing trailing CR or LF)
+void appendcrlf(char *string);
+
+#endif
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;
+}
diff --git a/sockets.h b/sockets.h
new file mode 100644
index 0000000..3c8fcbf
--- /dev/null
+++ b/sockets.h
@@ -0,0 +1,29 @@
+#ifndef SOCKETS_H_INCLUDED
+#define SOCKETS_H_INCLUDED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+
+#define BACKLOG 10 // maximum length to which the queue of pending connections for sockfd may grow
+
+#define BOUNCERLISTENPORT "1234" // TODO: change this to a config option!
+
+// get sockaddr, IPv4 or IPv6:
+void *get_in_addr(struct sockaddr *sa);
+
+// Create socket to connect to real IRC server
+int createserversocket(char *host, char *port);
+
+// Create listening socket to listen for bouncer client connections
+int createclientsocket(char *listenport);
+
+#endif