From ca8c31cdb180bd5758a4a4f9d868eca31197081c Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Sat, 8 Apr 2023 17:36:49 +0200 Subject: Improve stdin handling (only available when running in foreground mode) - don't get stuck in a loop when handling EOF/^D/Ctrl+D, improve debug output, improve comments, initialise variables more safely, exit main loop on errors. --- TODO | 2 -- blabouncer.c | 22 ++++++++++++++++++---- functions.c | 14 +++++++++++++- functions.h | 3 ++- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index bf8e642..a800c79 100644 --- a/TODO +++ b/TODO @@ -37,8 +37,6 @@ Some servers have a user send ^VERSION^ upon connection - (optionally?) respond Git version in code. -Sending ^D when running with ./blabouncer -f does crazy stuff. - Connecting from irssi triggers doautoreplay() from "USER received" in message.c twice. Use the line number based replay log reading method from lastspoke rather than the inefficient re-read + line offset method in time replays? (And potentially remove a bunch of code re-use.) diff --git a/blabouncer.c b/blabouncer.c index 89add3e..c7b5f6f 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -715,42 +715,56 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { // see if there's anything from stdin (unless we're in background/daemon mode) if (!settings->background && FD_ISSET(STDIN, &rfds)) { - debugprint(DEBUG_FULL, "reading stdin!\n"); + debugprint(DEBUG_FULL, "dochat(): stdin: reading stdin!\n"); char outgoingmsg[MAXDATASIZE]; // String to send to server + outgoingmsg[0] = '\0'; int outgoingmsgrc; // Return code from getstdin() for outgoing message outgoingmsgrc = getstdin(NULL, outgoingmsg, sizeof(outgoingmsg)); if (outgoingmsgrc == NO_INPUT) { - printf("\nError! No input.\n"); + printf("Error, no input.\n"); + debugprint(DEBUG_SOME, "dochat(): stdin: Error, no input.\n"); + continue; } else if (outgoingmsgrc == TOO_LONG) { - printf ("Error! Too long. Would have allowed up to: [%s]\n", outgoingmsg); + debugprint(DEBUG_SOME, "dochat(): stdin: Error, input too long. Max length is %d.\n", MAXDATASIZE - 1); + printf ("Error, input too long. Max length is %d.\n", MAXDATASIZE - 1); + continue; + } else { + debugprint(DEBUG_FULL, "dochat(): stdin: Got '%s'.\n", outgoingmsg); } // STDIN based commands for debugging if (strncmp(outgoingmsg, "listchannels", strlen("listchannels")) == 0) { printf("STDIN command starting: listchannels\n"); + debugprint(DEBUG_SOME, "dochat(): stdin: STDIN command starting: listchannels\n"); int channelcount = getchannelcount(channels, ircdstate.maxchannelcount); for (int i = 0; i < ircdstate.maxchannelcount; i++) { printf("Checking channel[%d] out of %d.\n", i, channelcount); + debugprint(DEBUG_FULL, "dochat(): stdin: Checking channel[%d] out of %d.\n", i, channelcount); // Skip this one if it's a blank channel if (!channels[i].name[0]) { - debugprint(DEBUG_FULL, "Skipping blank channel channel[%d].\n", i); + debugprint(DEBUG_FULL, "dochat(): stdin: Skipping blank channel channel[%d].\n", i); continue; } + debugprint(DEBUG_FULL, "dochat(): stdin: Found channel '%s'.\n", channels[i].name); printf("Found channel '%s'.\n", channels[i].name); } + debugprint(DEBUG_SOME, "dochat(): stdin: STDIN command complete: listchannels\n"); printf("STDIN command complete: listchannels\n"); + continue; } + debugprint(DEBUG_FULL, "dochat(): stdin: '%s' not processed as a command, sending to server.\n", outgoingmsg); // sourcefd = 0 as this is a trusted message sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings); + continue; } // go through all the remaining sockets to see if there's anything from the client sockets (either new connections or existing clients sending messages) diff --git a/functions.c b/functions.c index cd56904..31282ed 100644 --- a/functions.c +++ b/functions.c @@ -132,8 +132,15 @@ void debugprint(int level, char *format, ...) { va_end(args); } -// Get stdin line with buffer overrun protection +// Get stdin line with buffer overrun protection. +// Returns OK, NO_INPUT, or TOO_LONG as appropriate. int getstdin(char *prompt, char *buff, size_t sz) { + if (prompt != NULL) { + debugprint(DEBUG_FULL, "getstdin(): '%s' (len %d), '%s' (len %d), size %zu.\n", prompt, strlen(prompt), buff, strlen(buff), sz); + } else { + debugprint(DEBUG_FULL, "getstdin(): '' (len ), '%s' (len %d), size %zu.\n", buff, strlen(buff), sz); + } + int ch, extra; // Print optional prompt @@ -144,6 +151,11 @@ int getstdin(char *prompt, char *buff, size_t sz) { // Get the intput from stdin if (fgets (buff, sz, stdin) == NULL) { + if (feof(stdin)) { + debugprint(DEBUG_FULL, "getstdin(): Clearing EOF indicator on stdin.\n"); + clearerr(stdin); + } + return NO_INPUT; } diff --git a/functions.h b/functions.h index 5799aa6..30ae4e4 100644 --- a/functions.h +++ b/functions.h @@ -62,7 +62,8 @@ // Debug is only written if the global int "debug" is greater than or equal to the level. void debugprint(int level, char *format, ...); -// Get stdin line with buffer overrun protection +// Get stdin line with buffer overrun protection. +// Returns OK, NO_INPUT, or TOO_LONG as appropriate. 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) -- cgit v1.2.3