From 84b3f43a97da2b305cfa5c620aceec543168f6bc Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Thu, 18 Apr 2019 01:58:02 +0200 Subject: Split functions into different files --- blabouncer.c | 188 +---------------------------------------------------------- functions.c | 52 +++++++++++++++++ functions.h | 30 ++++++++++ sockets.c | 128 ++++++++++++++++++++++++++++++++++++++++ sockets.h | 29 +++++++++ 5 files changed, 242 insertions(+), 185 deletions(-) create mode 100644 functions.c create mode 100644 functions.h create mode 100644 sockets.c create mode 100644 sockets.h diff --git a/blabouncer.c b/blabouncer.c index 07784a9..4ed2c9a 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -16,197 +16,15 @@ #include #include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 -- cgit v1.2.3