commit 9ee1c93a7e753dc44db096fc136dc7f82072f0a9
parent 4f334f568a65edd7b47d3e71bedde49fd565299f
Author: kocotian <kocotian@kocotian.pl>
Date: Mon, 15 Feb 2021 13:28:38 +0100
networking
Diffstat:
M | nchk.c | | | 181 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
1 file changed, 179 insertions(+), 2 deletions(-)
diff --git a/nchk.c b/nchk.c
@@ -1,7 +1,14 @@
+#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
#include "arg.h"
#include "util.c"
@@ -24,6 +31,7 @@ static int16_t *getcheckerbypos(int16_t *checkers, int16_t row, int16_t col);
static void go(int16_t col, int16_t row);
static int16_t makechecker(int16_t superpowered, int16_t color, int16_t col, int16_t row);
static void prepare(int16_t *checkers);
+static void usage(void);
static const char t[] =
"\033[1;97m a b c d e f g h\n"
@@ -36,6 +44,8 @@ static const char t[] =
"\033[1;97m7 \033[0;37m[ ]\033[33m[ ]\033[37m[ ]\033[33m[ ]\033[37m[ ]\033[33m[ ]\033[37m[ ]\033[33m[ ]\n"
"\033[1;97m8 \033[0;33m[ ]\033[37m[ ]\033[33m[ ]\033[37m[ ]\033[33m[ ]\033[37m[ ]\033[33m[ ]\033[37m[ ]\n";
+char *argv0;
+
static const char yxstr[] = "\033[%d;%dH";
static int16_t color;
@@ -162,10 +172,68 @@ prepare(int16_t *checkers)
}
}
+static void
+usage(void)
+{
+ die("usage: %s [-h HOSTIP] [-p HOSTPORT] [CLIENT_IP [CLIENT_PORT]]", argv0);
+}
+
+static size_t
+message(char *ip, uint16_t port, char *msg, size_t msgsiz, char **buf, size_t bufsiz)
+{
+ int sockfd;
+ struct sockaddr_in addr;
+ size_t rb = 0;
+
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(ip);
+
+ if ((sockfd = socket(addr.sin_family = AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ return -1;
+
+ if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ return -1;
+
+ if (send(sockfd, msg, msgsiz, 0) < 0)
+ return -1;
+
+ if (buf != NULL) {
+ if ((rb = read(sockfd, *buf, bufsiz)) < 0)
+ return -1;
+ }
+
+ close(sockfd);
+ return rb;
+}
+
+static void
+sendupdate(int16_t *checkers, char *ip, uint16_t port)
+{
+ char msg[39];
+ msg[0] = 'U';
+ memcpy(msg + 1, checkers, 38);
+ if (message(ip, port, msg, 39, NULL, 0) < 0)
+ die("message:");
+}
+
+static void
+requestjoin(char *ip, uint16_t port, struct sockaddr_in addr)
+{
+ char msg[1 + sizeof(addr)] = "J";
+ memcpy(msg + 1, &addr, sizeof(addr));
+ if (message(ip, port, (char *)&msg, 1 + sizeof(addr), NULL, 0) < 0)
+ die("message:");
+}
+
int
main(int argc, char *argv[])
{
char *line = NULL; size_t lnsiz = 0;
+ uint16_t hport, cport; char *hip, *cip;
+ pid_t forkpid, parentpid;
+ int move;
+
+ struct sockaddr_in haddr, caddr;
/* 2 arrays of 12 checkers
in format:
@@ -173,9 +241,116 @@ main(int argc, char *argv[])
int16_t *checkers = mmap(NULL, sizeof(*checkers) * 24, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, 0, 0);
+ hport = cport = 2321;
+ hip = cip = "127.0.0.1";
+
+ ARGBEGIN {
+ case 'h': hip = ARGF(); break;
+ case 'p': hport = strtol(ARGF(), NULL, 10); break;
+ default: usage(); break;
+ } ARGEND
+
+ if (argc > 2)
+ die("too many arguments (given: %d; required: from 0 to 2)", argc);
+
+ move = 0;
+ if (!argc) /* argc not given, hosting */
+ color = 0;
+ else /* argc given, joining */
+ color = 1;
+
+ if (argc > 0)
+ cip = argv[0];
+ if (argc > 1)
+ cport = strtol(argv[1], NULL, 10);
+
color = 1;
prepare(checkers);
+ parentpid = getpid();
+
+ fork:
+ {
+ int sockfd, clientfd, opt;
+ socklen_t caddrsiz;
+ size_t resplen;
+
+ char buffer[BUFSIZ];
+
+ if ((sockfd = socket(haddr.sin_family = AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ die("socket:");
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+ &opt, sizeof(opt)) < 0)
+ die("setsockopt:");
+
+ haddr.sin_port = htons(hport);
+ haddr.sin_addr.s_addr = inet_addr(hip);
+ caddrsiz = sizeof(caddr);
+
+ if (bind(sockfd, (const struct sockaddr *)&haddr, sizeof(haddr)) < 0)
+ die("bind:");
+ if (listen(sockfd, 3) < 0)
+ die("listen:");
+
+ if ((forkpid = fork()) < 0)
+ die("fork:");
+
+ if (!forkpid) {
+ while (1) {
+ if ((clientfd = accept(sockfd, (struct sockaddr *)&caddr, &caddrsiz)) < 0)
+ die("accept:");
+
+ if ((resplen = read(clientfd, buffer, BUFSIZ)) < 0)
+ die("read:");
+
+ switch (*buffer) {
+ case 'A': /* Accepted */
+ kill(parentpid, SIGUSR1);
+ break;
+ case 'J': /* Join */ {
+ char *l = malloc(BUFSIZ); size_t lsiz;
+ char A = 'A'; struct sockaddr_in chost;
+ memcpy(&chost, buffer + 1, resplen - 1);
+ printf("accept connection request from %s:%d (hosts at %s:%d)? [y/n]: ",
+ inet_ntoa(caddr.sin_addr), htons(caddr.sin_port),
+ inet_ntoa(chost.sin_addr), htons(chost.sin_port));
+ if (getline(&l, &lsiz, stdin) < 0)
+ die("error while getting line:");
+ if (*l == 'y' || *l == 'Y')
+ kill(parentpid, SIGUSR1);
+ message(inet_ntoa(chost.sin_addr), ntohs(chost.sin_port), &A, 1, NULL, 0);
+ free(l);
+ break;
+ }
+ case 'R': /* Return */
+ break;
+ case 'U': /* Update */
+ memcpy(checkers, buffer + 1, resplen - 1);
+ break;
+ }
+
+ close(clientfd);
+ }
+ }
+ }
+
+ {
+ sigset_t sig; int signo;
+ if (!argc)
+ printf("\033[2J\033[Hhosting under %s:%d\nwaiting for other users...\n",
+ hip, hport);
+ else {
+ printf("\033[2J\033[Hwaiting for %s:%d to acceptation...\n",
+ cip, cport);
+ requestjoin(cip, cport, haddr);
+ }
+ sigemptyset(&sig);
+ sigaddset(&sig, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &sig, NULL);
+ sigwait(&sig, &signo);
+ }
+
printf("\033[2J\033[H");
while (1) {
@@ -191,9 +366,10 @@ main(int argc, char *argv[])
printf("\033[2J\033[H");
GOTOXY(1, 12);
- if (COMMAND_ARG(line, "mv"))
+ if (COMMAND_ARG(line, "mv")) {
cmdmv(checkers, line + 3);
- else if (COMMAND(line, "return"))
+ sendupdate(checkers, cip, cport);
+ } else if (COMMAND(line, "return"))
cmdreturn(checkers);
else if (COMMAND_ARG(line, "rm"))
printf("removed '%s'\n", line + 3);
@@ -204,6 +380,7 @@ main(int argc, char *argv[])
printf("%s: unknown command or bad syntax\n", line);
}
+ kill(forkpid, SIGTERM);
munmap(checkers, sizeof(*checkers) * 24);
printf("\033[2J\033[H");
puts("goodbye!");