From ea30db59140373a5da1378f7da933da31d839d54 Mon Sep 17 00:00:00 2001 From: Emil Williams Date: Tue, 6 Feb 2024 03:17:23 +0000 Subject: [PATCH] update clients further, more usable state --- client/README | 2 +- client/moontalk-cli.c | 193 +++++++++++++++++++++++++------------------ server/blackhole/blackhole.c | 119 ++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 81 deletions(-) create mode 100644 server/blackhole/blackhole.c diff --git a/client/README b/client/README index 7834c5d..58b234b 100644 --- a/client/README +++ b/client/README @@ -12,7 +12,7 @@ moontalk.tcl: moontalk.c: - IS INCOMPLETE, do not use it. + Is incomplete, and limited, but is usable. To compile it, use bake or just run: gcc -O2 -std=gnu99 moontalk.c -o moontalk -lncurses -ltinfo diff --git a/client/moontalk-cli.c b/client/moontalk-cli.c index 57c1f94..37b2dd9 100644 --- a/client/moontalk-cli.c +++ b/client/moontalk-cli.c @@ -1,11 +1,10 @@ -/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic -Wno-format-truncation $@ -o $* \ - -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo -lreadline $+ - * Written by Emil. - * Licensed under the GPLv3 only. - * - * TODO Add proper editing facilities - * TODO Print sent messages - */ +/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -Wpedantic -Wno-format-truncation $@ -o $* \ + -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo $+ + * Written by Emil. + * Licensed under the GPLv3 only. + * + * TODO Add proper editing facilities + */ #include #include @@ -13,6 +12,7 @@ #include #include #include +#include #include #include @@ -22,18 +22,33 @@ #include #include -#include #define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion" #define PORT "50000" +#define TAB 9 /* */ #define BACKSPACE 263 /* ^G */ +#define C_C 4 /* ... */ +#define C_D 4 /* quit */ +#define C_A 1 /* BOL */ +#define C_B 2 /* BOL */ +#define C_E 5 /* EOL */ +#define C_U 21 /* CLR TO BOL */ +#define C_H 8 /* BACKSPACE */ +#define C_W 23 /* DELETE PREVWORD */ +#define C_L 12 /* Signal SIGWINCH */ +#define C_R 18 /* hah not going to implement that */ + +#define UP 258 +#define DOWN 259 +#define LEFT 260 +#define RIGHT 261 #define TIMESTR "<%Y/%m/%d %H:%M:%S " #define TIMESTRMAX 21 #define SENDMAX (1 << 8) - 1 -#define RECVMAX (1 << 11) +#define RECVMAX 17663 /* (1 << 11) */ #define streq(a,b) (!strcmp(a,b)) #define strneq(a,b,c) (!memcmp(a,b,c)) @@ -41,6 +56,24 @@ int g_y, g_x; int g_sockfd = -1; +void fillline(int y, int xstart, char c) { + int i = xstart, x = g_x; + for (; i < x; ++i) + { mvaddch(y,i,c); } +} + +#define TITLE(str) do { mvprintw(0,0,str); fillline(0,strlen(str),'-'); } while (0) + +void hardrefresh(void) { + mvprintw(g_y - 2, 0, "max screen %d; max ours %d", (g_y - 3) * SENDMAX, RECVMAX); + TITLE("-- MOONTALK "); + fillline(g_y - 3, 0, '-'); +} + +#undef TITLE + +int g_hardrefresh = 0; + void init_screen(int x) { (void)x; signal(SIGWINCH, SIG_IGN); @@ -51,17 +84,23 @@ void init_screen(int x) { g_y = w.ws_row; g_x = w.ws_col; initscr(); - cbreak(); + raw(); noecho(); keypad(stdscr, ERR); nodelay(stdscr, TRUE); + ESCDELAY = 0; clear(); + hardrefresh(); + g_hardrefresh = 1; signal(SIGWINCH, init_screen); } -void free_connection(void) { - close(g_sockfd); +void stop(void) { + int sockfd = g_sockfd; + endwin(); + printf("stopping now. maybe you forgot torify?\n"); + if (sockfd > -1) { close(sockfd); } g_sockfd = -1; } @@ -71,11 +110,11 @@ int init_connection(char * serv, char * port) { struct addrinfo hints, * res; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6 - hints.ai_socktype = SOCK_STREAM; // TCP stream sockets + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) { - fprintf(stderr, "init_connection: %s\n", gai_strerror(status)); + perror("init_connection"); exit(1); } @@ -89,6 +128,7 @@ int init_connection(char * serv, char * port) { g_sockfd = sockfd; return sockfd; error: + if (sockfd > -1) { close(sockfd); } perror("init_connection"); exit(1); __builtin_unreachable(); @@ -107,6 +147,15 @@ int countlines(char * buf, size_t len) { return i; } +size_t getoff(char * buf, size_t len, size_t count, char c) { + size_t i; + for (i = 0; count && i < len; ++i) { + count -= (buf[i] == c) * 1; + ++buf; + } + return i; +} + size_t lastline(char * buf, size_t len) { size_t ret; char * start = buf; @@ -151,39 +200,38 @@ int main (int argc, char ** argv) { return 1; } if (streq(*(argv-1), "-serv")) { - printf("serv: %s\n", *argv); serv = *argv; } else if (streq(*(argv-1), "-port")) { - printf("port: %s\n", *argv); port = *argv; } else if (streq(*(argv-1), "-name")) { - printf("name: %s\n", *argv); memset(name, 0, 31); strncpy(name, *argv, 31); } } - /* atexit(void (*endwin)(void)); */ init_screen(-1); + move(1,0); printw("Connecting to %s:%s as %s\n", serv, port, name); printw("g_y: %d; g_x: %d\n", g_y, g_x); refresh(); clear(); + atexit(stop); sockfd = init_connection(serv, port); char raw[SENDMAX + RECVMAX]; char * sendbuf = raw, * recvbuf = raw + SENDMAX; size_t sendminlen; - size_t sendlen = sendminlen, recvlen = 0; + size_t sendlen = sendminlen, recvlen = 1; time_t t; struct tm * tm; - int frame = 15.; - float interval = 1. / frame; + useconds_t frame = 25; + useconds_t interval = 1000000 / frame; int32_t ct = 0; + int lc, off; int ch; int ret; @@ -196,75 +244,60 @@ int main (int argc, char ** argv) { sendminlen += 2; sendlen = sendminlen; - rl_bind_key('\t', rl_insert); - rl_catch_signals = 0; - rl_catch_sigwinch = 0; - rl_prep_term_function = NULL; - rl_deprep_term_function = NULL; - rl_change_environment = 0; - - #if 0 - rl_getc_function = +[](FILE* ignore){ - input_available = false; - return (int)input; - }; - rl_input_available_hook = +[]{ - return input_available; - }; - rl_redisplay_function = +[]{ - wmove(myWindow, 1, 1); - wclrtoeol(myWindow); - box(myWindow, 0, 0); - waddstr(myWindow, rl_line_buffer); - wrefresh(myWindow); - return; - }; - rl_callback_handler_install("", +[](char *line){ - wmove(stdscr, 0, 0); - wclrtoeol(stdscr); - addstr(line); - refresh(); - return; - }); - #endif - + hardrefresh(); + mvaddnstr(g_y - 1, 0, sendbuf, sendlen); while (1) { /* update */ - if (ct % frame == 0) { + if (ct % (frame) == 0) { UPDATE_TIME(); + mvaddnstr(g_y - 1, 0, sendbuf, sendlen); } if (ct % (frame * 2) == 0) { ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT); - recvlen += (ret > 0) * ret; - mvaddnstr(0, 0, recvbuf, recvlen); - mvprintw(g_y - 2, 0, "recvlen %ld", recvlen); + if (ret > 0 || g_hardrefresh) { + recvlen += ret; + lc = countlines(recvbuf, recvlen); + off = lc - g_y - 4; + off = getoff(recvbuf, recvlen, (off > 0) * off, '\n'); + mvaddnstr(1, 0, recvbuf + off, recvlen - off); + g_hardrefresh = 0; + } } /* send */ - ch = getch(); - if (ch == -1); - else if (ch == '\n') { - if (sendlen == sendminlen) { continue; } - sendbuf[sendlen++] = '\n'; /* terminator */ - send(sockfd, sendbuf, sendlen, 0); - memset(sendbuf + sendminlen, 0, sendlen - sendminlen); - sendlen = sendminlen; - clearline(g_y - 1); + while ((ch = getch()) != -1) { + if (ch == '\n') { + if (sendlen == sendminlen) { continue; } + UPDATE_TIME(); + sendbuf[sendlen++] = '\n'; /* terminator */ + send(sockfd, sendbuf, sendlen, 0); + memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen); + recvlen += sendlen; + mvaddnstr(1, 0, recvbuf, recvlen); + mvaddch(g_y - 1, sendminlen, ' '); + clearline(g_y - 1); + sendlen = sendminlen; + } + else if (ch == C_D) { + exit(0); + } + else if (ch == BACKSPACE) { + clearline(g_y - 1); + if (sendlen - 1 >= sendminlen) + { mvaddch(g_y - 1, --sendlen, ' '); } + mvaddnstr(g_y - 1, 0, sendbuf, sendlen); + move(g_y - 1, sendlen); + } + else if (ch > 31 && ch < 127) { + if (sendlen + 1 < SENDMAX) + { sendbuf[sendlen++] = ch; } + mvaddnstr(g_y - 1, 0, sendbuf, sendlen); + } } - else if (ch == BACKSPACE) { - clearline(g_y - 1); - if (sendlen - 1 >= sendminlen) - { --sendlen; } - } - else if (ch > 31 && ch < 127) { - if (sendlen + 1 < SENDMAX) - { sendbuf[sendlen++] = ch; } - } - mvaddnstr(g_y - 1, 0, sendbuf, sendlen); move(g_y - 1, sendlen); - /* sleep */ ++ct; - sleep(interval); refresh(); + usleep(interval); } + return 0; } diff --git a/server/blackhole/blackhole.c b/server/blackhole/blackhole.c new file mode 100644 index 0000000..f2a3935 --- /dev/null +++ b/server/blackhole/blackhole.c @@ -0,0 +1,119 @@ +/* blackhole.c - eats incoming messages, does nothing, just for testing + * @BAKE cc -O2 -std=gnu89 -Wall -Wextra -Wpedantic $@ -o $* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT "91991" +#define BACKLOG 1 + +void sigchld_handler(int s) { + int saved_errno = errno; + (void)s; + while(waitpid(-1, NULL, WNOHANG) > 0); + errno = saved_errno; +} + +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); +} + +int main (void) { + int sockfd, connfd, rv, yes = 1; + struct addrinfo hints, *servinfo, *p; + struct sockaddr_storage their_addr; + char s[INET6_ADDRSTRLEN]; + socklen_t sin_size; + struct sigaction sa; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("server: socket"); + continue; + } + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + perror("setsockopt"); + exit(1); + } + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("server: bind"); + continue; + } + break; + } + + freeaddrinfo(servinfo); + + if (p == NULL) { + fprintf(stderr, "server: failed to bind\n"); + exit(1); + } + + if (listen(sockfd, BACKLOG) == -1) { + perror("listen"); + exit(1); + } + + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + perror("sigaction"); + exit(1); + } + + printf("server: waiting for connections...\n"); + + while (1) { + sin_size = sizeof their_addr; + connfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); + + if (connfd == -1) { + perror("accept"); + continue; + } + + inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); + + printf("server: got connection from %s\n", s); + + if (!fork()) { + close(sockfd); + while (1) { sleep(5); } + close(connfd); + exit(0); + } + close(connfd); + } + close(sockfd); + sockfd = -1; + return 0; +}