/* version 2026-02-12 */ /* compilation: gcc -Wall -o central central.c */ #include #include #include #include #include #include #include #include #include #include int fullread(int fd, void *_buf, int count) { char *buf = _buf; int ret = 0; int l; while (count) { l = read(fd, buf, count); if (l <= 0) return -1; count -= l; buf += l; ret += l; } return ret; } int fullwrite(int fd, void *_buf, int count) { char *buf = _buf; int ret = 0; int l; while (count) { l = write(fd, buf, count); if (l <= 0) return -1; count -= l; buf += l; ret += l; } return ret; } void central(int sock, int remote_port) { int s = fork(); if (s == -1) abort(); if (s) { waitpid(s, 0, 0); close(sock); return; } /* son - detach from parent */ s = fork(); if (s == -1) abort(); if (s) exit(0); /* wait for remote on port 'remote_port' */ s = socket(AF_INET, SOCK_STREAM, 0); int t; if (s == -1) abort(); int v = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } v = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int))) { perror("setsockopt"); exit(1); } struct sockaddr_in a; a.sin_family = AF_INET; a.sin_port = htons(remote_port); a.sin_addr.s_addr = inet_addr("0.0.0.0"); if (bind(s, (struct sockaddr *)&a, sizeof(a))) abort(); if (listen(s, 5)) abort(); socklen_t alen = sizeof(a); if ((t = accept(s, (struct sockaddr *)&a, &alen)) == -1) abort(); printf("connect from %s\n", inet_ntoa(a.sin_addr)); v = 1; if (setsockopt(t, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } close(s); /* get key from client */ char key[512]; if (fullread(sock, key, 512) != 512) abort(); /* get key from remote */ char remote_key[512]; if (fullread(t, remote_key, 512) != 512) abort(); /* key not equal -> bad */ if (memcmp(key, remote_key, 512)) { printf("bad remote/client keys\n"); exit(1); } printf("good connection, go\n"); /* loop */ while (1) { struct pollfd fds[2]; fds[0].fd = sock; fds[0].events = POLLIN; fds[0].revents = 0; fds[1].fd = t; fds[1].events = POLLIN; fds[1].revents = 0; int r = poll(fds, 2, -1); if (r == -1) abort(); if (r == 0) continue; char b[512]; if (fds[0].revents) { /* from sock to t */ int count = read(sock, b, 512); if (count <= 0) { printf("fullwrite fails\n"); exit(1); } if (fullwrite(t, b, count) != count) { printf("ERROR: connection_send_rx failed, dropping\n"); exit(1); } } if (fds[1].revents) { /* from t to sock */ int count = read(t, b, 512); if (count <= 0) { printf("fullwrite fails\n"); exit(1); } if (fullwrite(sock, b, count) != count) { printf("ERROR: connection_send_rx failed, dropping\n"); exit(1); } } } } int main(int n, char **v) { int port = 8001; int remote_port = 8000; int s = socket(AF_INET, SOCK_STREAM, 0); int t; if (s == -1) abort(); int vv = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &vv, sizeof(v)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } vv = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &vv, sizeof(int))) { perror("setsockopt"); exit(1); } struct sockaddr_in a; a.sin_family = AF_INET; a.sin_port = htons(port); a.sin_addr.s_addr = inet_addr("0.0.0.0"); if (bind(s, (struct sockaddr *)&a, sizeof(a))) abort(); if (listen(s, 5)) abort(); while (1) { socklen_t alen = sizeof(a); if ((t = accept(s, (struct sockaddr *)&a, &alen)) == -1) abort(); printf("connect from %s\n", inet_ntoa(a.sin_addr)); vv = 1; if (setsockopt(t, IPPROTO_TCP, TCP_NODELAY, &vv, sizeof(vv)) == -1) { perror("setsockopt(NODELAY)"); exit(1); } central(t, remote_port); } return 0; }