From 999ce761bae19a3827acc2bdd39aefb783c5e399 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Wed, 14 Sep 2022 10:07:25 +0300 Subject: [PATCH] initial commit --- Makefile | 2 + main.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 Makefile create mode 100644 main.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..516e7c3 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +main: main.c + cc -o main main.c diff --git a/main.c b/main.c new file mode 100644 index 0000000..79b26d2 --- /dev/null +++ b/main.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include + +#define MAX_CLIENTS 512 +#define BACKLOG 10 +#define DIE(info) ({perror((info)); exit(EXIT_FAILURE);}) + +static const char *socket_path = "/tmp/plumb-unix0"; + +struct plumb_client { + int fd; +}; + +struct plumb_server { + int socket_fd; + int fd_num; + struct plumb_client clients[MAX_CLIENTS]; + struct pollfd fds[MAX_CLIENTS + 1]; +}; + + +int plumb_server_client_add(struct plumb_server *s, int fd) +{ + printf("adding new connection, fd=%d\n", fd); + + for (int i = 0; i < MAX_CLIENTS; i++) { + if (s->clients[i].fd < 0) { + s->clients[i].fd = fd; + s->fds[i].fd = fd; + s->fds[i].events = POLLIN; + return i; + } + } + return -1; +} + +void plumb_server_client_remove(struct plumb_server *s, int i) +{ + if (i >= MAX_CLIENTS) + return; + + printf("removing client i=%d\n", i); + + if (s->clients[i].fd >= 0) { + close(s->clients[i].fd); + } + s->clients[i].fd = -1; + s->fds[i].fd = -1; + s->fds[i].events = 0; + s->fds[i].revents = 0; +} + + +void plumb_server_free(struct plumb_server *s) +{ + if (!s) return; + if (s->socket_fd) close(s->socket_fd); + free(s); +} + +struct plumb_server *plumb_server_create() +{ + struct plumb_server *s = malloc(sizeof(struct plumb_server)); + if (s == NULL) { + DIE("malloc"); + return NULL; + } + + s->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->socket_fd == -1) { + free(s); + DIE("socket"); + return NULL; + } + + struct sockaddr_un name; + memset(&name, 0, sizeof(name)); + name.sun_family = AF_UNIX; + strncpy(name.sun_path, socket_path, sizeof(name.sun_path) - 1); + + if (bind(s->socket_fd, (const struct sockaddr *)&name, sizeof(name)) == -1) { + free(s); + close(s->socket_fd); + DIE("bind"); + return NULL; + } + if (listen(s->socket_fd, BACKLOG) == -1) { + free(s); + close(s->socket_fd); + DIE("listen"); + return NULL; + } + + for (int i = 0; i < MAX_CLIENTS; i++) { + s->clients[i].fd = -1; + s->fds[i].fd = -1; + s->fds[i].events = 0; + s->fds[i].revents = 0; + } + + s->fds[MAX_CLIENTS].fd = s->socket_fd; + s->fds[MAX_CLIENTS].events = POLLIN; + + s->fd_num = MAX_CLIENTS + 1; + + return s; +} + +int plumb_server_turn(struct plumb_server *s) +{ + if (poll(s->fds, s->fd_num, -1) < 0) { + DIE("poll"); + return -1; + } + + for (int i = 0; i < s->fd_num; i++) { + if (s->fds[i].revents & POLLIN) { // file descriptor ready for reading + if (s->fds[i].fd == s->socket_fd) { // new connection + int fd = accept(s->socket_fd, NULL, NULL); + if (fd == -1) { + DIE("accept"); + return -1; + } + + if (plumb_server_client_add(s, fd) == -1) { + close(fd); + continue; + } + } else { // data from socket + char data[256]; + memset(data, 0, sizeof(data)); + ssize_t bytes = recv(s->fds[i].fd, data, sizeof(data), 0); + if (bytes == -1) { + DIE("recv"); + return -1; + } else if (bytes == 0) { // client disconnected + plumb_server_client_remove(s, i); + } else { + send(s->fds[i].fd, data, sizeof(data), 0); + } + } + } + } + + return 0; +} + +int main() +{ + struct plumb_server *srv = plumb_server_create(); + if (srv == NULL) { + fprintf(stderr, "plumb_server_create failed\n"); + return EXIT_FAILURE; + } + + while (1) { + if (plumb_server_turn(srv) < 0) { + fprintf(stderr, "plumb_server_turn failed\n"); + plumb_server_free(srv); + return EXIT_FAILURE; + } + } + + plumb_server_free(srv); + + return EXIT_SUCCESS; +}