update clients further, more usable state
This commit is contained in:
parent
3f4161ef04
commit
ea30db5914
@ -12,7 +12,7 @@ moontalk.tcl:
|
|||||||
|
|
||||||
moontalk.c:
|
moontalk.c:
|
||||||
|
|
||||||
IS INCOMPLETE, do not use it.
|
Is incomplete, and limited, but is usable.
|
||||||
|
|
||||||
To compile it, use bake <https://git.lain.church/emil/bake> or just run:
|
To compile it, use bake <https://git.lain.church/emil/bake> or just run:
|
||||||
gcc -O2 -std=gnu99 moontalk.c -o moontalk -lncurses -ltinfo
|
gcc -O2 -std=gnu99 moontalk.c -o moontalk -lncurses -ltinfo
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic -Wno-format-truncation $@ -o $* \
|
/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -Wpedantic -Wno-format-truncation $@ -o $* \
|
||||||
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo -lreadline $+
|
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo $+
|
||||||
* Written by Emil.
|
* Written by Emil.
|
||||||
* Licensed under the GPLv3 only.
|
* Licensed under the GPLv3 only.
|
||||||
*
|
*
|
||||||
* TODO Add proper editing facilities
|
* TODO Add proper editing facilities
|
||||||
* TODO Print sent messages
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -13,6 +12,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -22,18 +22,33 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#include <readline/readline.h>
|
|
||||||
|
|
||||||
#define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
|
#define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
|
||||||
#define PORT "50000"
|
#define PORT "50000"
|
||||||
|
|
||||||
|
#define TAB 9 /* */
|
||||||
#define BACKSPACE 263 /* ^G */
|
#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 TIMESTR "<%Y/%m/%d %H:%M:%S "
|
||||||
#define TIMESTRMAX 21
|
#define TIMESTRMAX 21
|
||||||
|
|
||||||
#define SENDMAX (1 << 8) - 1
|
#define SENDMAX (1 << 8) - 1
|
||||||
#define RECVMAX (1 << 11)
|
#define RECVMAX 17663 /* (1 << 11) */
|
||||||
|
|
||||||
#define streq(a,b) (!strcmp(a,b))
|
#define streq(a,b) (!strcmp(a,b))
|
||||||
#define strneq(a,b,c) (!memcmp(a,b,c))
|
#define strneq(a,b,c) (!memcmp(a,b,c))
|
||||||
@ -41,6 +56,24 @@
|
|||||||
int g_y, g_x;
|
int g_y, g_x;
|
||||||
int g_sockfd = -1;
|
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 init_screen(int x) {
|
||||||
(void)x;
|
(void)x;
|
||||||
signal(SIGWINCH, SIG_IGN);
|
signal(SIGWINCH, SIG_IGN);
|
||||||
@ -51,17 +84,23 @@ void init_screen(int x) {
|
|||||||
g_y = w.ws_row;
|
g_y = w.ws_row;
|
||||||
g_x = w.ws_col;
|
g_x = w.ws_col;
|
||||||
initscr();
|
initscr();
|
||||||
cbreak();
|
raw();
|
||||||
noecho();
|
noecho();
|
||||||
keypad(stdscr, ERR);
|
keypad(stdscr, ERR);
|
||||||
nodelay(stdscr, TRUE);
|
nodelay(stdscr, TRUE);
|
||||||
|
ESCDELAY = 0;
|
||||||
clear();
|
clear();
|
||||||
|
hardrefresh();
|
||||||
|
g_hardrefresh = 1;
|
||||||
|
|
||||||
signal(SIGWINCH, init_screen);
|
signal(SIGWINCH, init_screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_connection(void) {
|
void stop(void) {
|
||||||
close(g_sockfd);
|
int sockfd = g_sockfd;
|
||||||
|
endwin();
|
||||||
|
printf("stopping now. maybe you forgot torify?\n");
|
||||||
|
if (sockfd > -1) { close(sockfd); }
|
||||||
g_sockfd = -1;
|
g_sockfd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,11 +110,11 @@ int init_connection(char * serv, char * port) {
|
|||||||
struct addrinfo hints, * res;
|
struct addrinfo hints, * res;
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
|
hints.ai_family = AF_UNSPEC;
|
||||||
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) {
|
if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) {
|
||||||
fprintf(stderr, "init_connection: %s\n", gai_strerror(status));
|
perror("init_connection");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +128,7 @@ int init_connection(char * serv, char * port) {
|
|||||||
g_sockfd = sockfd;
|
g_sockfd = sockfd;
|
||||||
return sockfd;
|
return sockfd;
|
||||||
error:
|
error:
|
||||||
|
if (sockfd > -1) { close(sockfd); }
|
||||||
perror("init_connection");
|
perror("init_connection");
|
||||||
exit(1);
|
exit(1);
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
@ -107,6 +147,15 @@ int countlines(char * buf, size_t len) {
|
|||||||
return i;
|
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 lastline(char * buf, size_t len) {
|
||||||
size_t ret;
|
size_t ret;
|
||||||
char * start = buf;
|
char * start = buf;
|
||||||
@ -151,39 +200,38 @@ int main (int argc, char ** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (streq(*(argv-1), "-serv")) {
|
if (streq(*(argv-1), "-serv")) {
|
||||||
printf("serv: %s\n", *argv);
|
|
||||||
serv = *argv;
|
serv = *argv;
|
||||||
}
|
}
|
||||||
else if (streq(*(argv-1), "-port")) {
|
else if (streq(*(argv-1), "-port")) {
|
||||||
printf("port: %s\n", *argv);
|
|
||||||
port = *argv;
|
port = *argv;
|
||||||
}
|
}
|
||||||
else if (streq(*(argv-1), "-name")) {
|
else if (streq(*(argv-1), "-name")) {
|
||||||
printf("name: %s\n", *argv);
|
|
||||||
memset(name, 0, 31);
|
memset(name, 0, 31);
|
||||||
strncpy(name, *argv, 31);
|
strncpy(name, *argv, 31);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* atexit(void (*endwin)(void)); */
|
|
||||||
init_screen(-1);
|
init_screen(-1);
|
||||||
|
move(1,0);
|
||||||
printw("Connecting to %s:%s as %s\n", serv, port, name);
|
printw("Connecting to %s:%s as %s\n", serv, port, name);
|
||||||
printw("g_y: %d; g_x: %d\n", g_y, g_x);
|
printw("g_y: %d; g_x: %d\n", g_y, g_x);
|
||||||
refresh();
|
refresh();
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
atexit(stop);
|
||||||
sockfd = init_connection(serv, port);
|
sockfd = init_connection(serv, port);
|
||||||
|
|
||||||
char raw[SENDMAX + RECVMAX];
|
char raw[SENDMAX + RECVMAX];
|
||||||
char * sendbuf = raw, * recvbuf = raw + SENDMAX;
|
char * sendbuf = raw, * recvbuf = raw + SENDMAX;
|
||||||
size_t sendminlen;
|
size_t sendminlen;
|
||||||
size_t sendlen = sendminlen, recvlen = 0;
|
size_t sendlen = sendminlen, recvlen = 1;
|
||||||
|
|
||||||
time_t t;
|
time_t t;
|
||||||
struct tm * tm;
|
struct tm * tm;
|
||||||
int frame = 15.;
|
useconds_t frame = 25;
|
||||||
float interval = 1. / frame;
|
useconds_t interval = 1000000 / frame;
|
||||||
int32_t ct = 0;
|
int32_t ct = 0;
|
||||||
|
int lc, off;
|
||||||
int ch;
|
int ch;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -196,75 +244,60 @@ int main (int argc, char ** argv) {
|
|||||||
sendminlen += 2;
|
sendminlen += 2;
|
||||||
sendlen = sendminlen;
|
sendlen = sendminlen;
|
||||||
|
|
||||||
rl_bind_key('\t', rl_insert);
|
hardrefresh();
|
||||||
rl_catch_signals = 0;
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* update */
|
/* update */
|
||||||
if (ct % frame == 0) {
|
if (ct % (frame) == 0) {
|
||||||
UPDATE_TIME();
|
UPDATE_TIME();
|
||||||
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||||
}
|
}
|
||||||
if (ct % (frame * 2) == 0) {
|
if (ct % (frame * 2) == 0) {
|
||||||
ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT);
|
ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT);
|
||||||
recvlen += (ret > 0) * ret;
|
if (ret > 0 || g_hardrefresh) {
|
||||||
mvaddnstr(0, 0, recvbuf, recvlen);
|
recvlen += ret;
|
||||||
mvprintw(g_y - 2, 0, "recvlen %ld", recvlen);
|
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 */
|
/* send */
|
||||||
ch = getch();
|
while ((ch = getch()) != -1) {
|
||||||
if (ch == -1);
|
if (ch == '\n') {
|
||||||
else if (ch == '\n') {
|
|
||||||
if (sendlen == sendminlen) { continue; }
|
if (sendlen == sendminlen) { continue; }
|
||||||
|
UPDATE_TIME();
|
||||||
sendbuf[sendlen++] = '\n'; /* terminator */
|
sendbuf[sendlen++] = '\n'; /* terminator */
|
||||||
send(sockfd, sendbuf, sendlen, 0);
|
send(sockfd, sendbuf, sendlen, 0);
|
||||||
memset(sendbuf + sendminlen, 0, sendlen - sendminlen);
|
memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen);
|
||||||
sendlen = sendminlen;
|
recvlen += sendlen;
|
||||||
|
mvaddnstr(1, 0, recvbuf, recvlen);
|
||||||
|
mvaddch(g_y - 1, sendminlen, ' ');
|
||||||
clearline(g_y - 1);
|
clearline(g_y - 1);
|
||||||
|
sendlen = sendminlen;
|
||||||
|
}
|
||||||
|
else if (ch == C_D) {
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
else if (ch == BACKSPACE) {
|
else if (ch == BACKSPACE) {
|
||||||
clearline(g_y - 1);
|
clearline(g_y - 1);
|
||||||
if (sendlen - 1 >= sendminlen)
|
if (sendlen - 1 >= sendminlen)
|
||||||
{ --sendlen; }
|
{ mvaddch(g_y - 1, --sendlen, ' '); }
|
||||||
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||||
|
move(g_y - 1, sendlen);
|
||||||
}
|
}
|
||||||
else if (ch > 31 && ch < 127) {
|
else if (ch > 31 && ch < 127) {
|
||||||
if (sendlen + 1 < SENDMAX)
|
if (sendlen + 1 < SENDMAX)
|
||||||
{ sendbuf[sendlen++] = ch; }
|
{ sendbuf[sendlen++] = ch; }
|
||||||
}
|
|
||||||
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
move(g_y - 1, sendlen);
|
move(g_y - 1, sendlen);
|
||||||
/* sleep */
|
|
||||||
++ct;
|
++ct;
|
||||||
sleep(interval);
|
|
||||||
refresh();
|
refresh();
|
||||||
|
usleep(interval);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
119
server/blackhole/blackhole.c
Normal file
119
server/blackhole/blackhole.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/* blackhole.c - eats incoming messages, does nothing, just for testing
|
||||||
|
* @BAKE cc -O2 -std=gnu89 -Wall -Wextra -Wpedantic $@ -o $*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user