From 7e5e0f49dcb6ba416da5fc9e536109c04f338f95 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 24 Sep 2024 02:27:44 -0400 Subject: Initial commit Signed-off-by: Ian Moffett --- .gitignore | 3 + Makefile | 27 ++++++ client/main.c | 107 +++++++++++++++++++++ lib/crypto/ecdh.c | 134 +++++++++++++++++++++++++++ lib/include/crypto/ecdh.h | 45 +++++++++ lib/include/defs.h | 37 ++++++++ lib/include/net/stpsession.h | 75 +++++++++++++++ ostp.d/net/otd_listen.c | 215 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 643 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 client/main.c create mode 100644 lib/crypto/ecdh.c create mode 100644 lib/include/crypto/ecdh.h create mode 100644 lib/include/defs.h create mode 100644 lib/include/net/stpsession.h create mode 100644 ostp.d/net/otd_listen.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..88e66e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +so/ +bin/ +*.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..af6d185 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +CFILES_OTD = $(shell find ostp.d/ -name "*.c") +CFILES_OTLIB = $(shell find lib/ -name "*.c") +CFILES_CLIENT = $(shell find client/ -name "*.c") +CFLAGS_OTD = -pedantic -Iostp.d/include/ -Ilib/include/ +CFLAGS_CLIENT = -pedantic -Iclient/include/ -Ilib/include/ +CFLAGS_OTLIB = -pedantic -Ilib/include/ -fPIC -lssl -lcrypto +OTLIB_OBJ = $(CFILES_OTLIB:.c=.o) +CC = gcc + +.PHONY: all +all: $(OTLIB_OBJ) bin/ostp.d bin/client + +bin/ostp.d: $(CFILES_OTD) + mkdir -p $(@D) + $(CC) $(CFLAGS_OTD) $(OTLIB_OBJ) $^ -lssl -lcrypto -o $@ + +bin/client: $(CFILES_CLIENT) + mkdir -p $(@D) + $(CC) $(CFLAGS_CLIENT) $(OTLIB_OBJ) $^ -lssl -lcrypto -o $@ + +%.o: %.c + mkdir -p $(@D) + $(CC) -c $(CFLAGS_OTLIB) $< -o $@ + +.PHONY: clean +clean: + rm -rf bin/ $(OTLIB_OBJ) diff --git a/client/main.c b/client/main.c new file mode 100644 index 0000000..1551065 --- /dev/null +++ b/client/main.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CENTRAL_SERVER "149.248.6.149" +#define OSTP_PORT 5352 + +static void +log_pubkey(unsigned char *pubkey) +{ + for (size_t i = 0; i < 32; ++i) { + printf("%02X ", pubkey[i] & 0xFF); + if (i != 0 && i % 4 == 0) { + printf("\n"); + } + } + printf("\n"); +} + +static int +request_session(void) +{ + struct sockaddr_in addr; + struct session_request stp_sq; + struct x25519_keypair keypair; + int error, sockfd; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(CENTRAL_SERVER); + addr.sin_port = htons(OSTP_PORT); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + return sockfd; + } + + error = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (error < 0) { + printf("Failed to connect!\n"); + close(sockfd); + return error; + } + + printf("Generating keys...\n"); + + /* Generate an ephemeral keypair */ + if ((error = gen_x25519_keypair(&keypair)) < 0) { + printf("Key generation failed!\n"); + close(sockfd); + return error; + } + + /* + * Setup the session request and add our public + * key to it. + * + * TODO: Use the 'U' bit in options. + */ + memset(stp_sq.hash, 0, sizeof(stp_sq.hash)); + stp_sq.options = 0; + memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey)); + log_pubkey(keypair.pubkey); + + printf("Sending session request...\n"); + send(sockfd, &stp_sq, sizeof(stp_sq), 0); + close(sockfd); + return 0; +} + +int +main(void) +{ + return request_session(); +} diff --git a/lib/crypto/ecdh.c b/lib/crypto/ecdh.c new file mode 100644 index 0000000..9062d6b --- /dev/null +++ b/lib/crypto/ecdh.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +static inline int +x25519_check_clamp(unsigned char *key) +{ + key[0] &= 248; + key[31] &= 127; + key[31] |= 64; + return 0; +} + +int +gen_x25519_keypair(struct x25519_keypair *res) +{ + EVP_PKEY_CTX *ctx; + EVP_PKEY *keypair_raw = NULL; + struct x25519_keypair keypair; + int retor; + + if (res == NULL) { + return -1; + } + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + if (ctx == NULL) { + printf("ecdh: Failed to create X25519 keygen context\n"); + return -1; + } + + if (EVP_PKEY_keygen_init(ctx) <= 0) { + printf("ecdh: Failed to init X25519 keygen context\n"); + EVP_PKEY_CTX_free(ctx); + return -1; + } + + /* Create X25519 key pair */ + if (EVP_PKEY_keygen(ctx, &keypair_raw) <= 0) { + printf("ecdh: Failed to generate X25519 keypair\n"); + EVP_PKEY_CTX_free(ctx); + return -1; + } + + /* Allocate a buffer for the public key */ + EVP_PKEY_get_raw_public_key(keypair_raw, NULL, &keypair.pubkey_len); + keypair.pubkey = malloc(keypair.pubkey_len); + + if (keypair.pubkey == NULL) { + printf(" ecdh: Failed to allocate memory for public key\n"); + EVP_PKEY_free(keypair_raw); + EVP_PKEY_CTX_free(ctx); + return -1; + } + + /* Allocate a buffer for the private key */ + EVP_PKEY_get_raw_private_key(keypair_raw, NULL, &keypair.privkey_len); + keypair.privkey = malloc(keypair.privkey_len); + + if (keypair.privkey == NULL) { + printf("ecdh: Failed allocating memory for private key\n"); + EVP_PKEY_free(keypair_raw); + EVP_PKEY_CTX_free(ctx); + return -1; + } + + retor = EVP_PKEY_get_raw_private_key(keypair_raw, keypair.privkey, + &keypair.privkey_len); + + if (retor <= 0) { + printf("Failed to extract private key\n"); + EVP_PKEY_free(keypair_raw); + EVP_PKEY_CTX_free(ctx); + } + + retor = EVP_PKEY_get_raw_public_key(keypair_raw, keypair.pubkey, + &keypair.pubkey_len); + + if (retor <= 0) { + printf("Failed to extract public key\n"); + EVP_PKEY_free(keypair_raw); + EVP_PKEY_CTX_free(ctx); + } + + EVP_PKEY_free(keypair_raw); + EVP_PKEY_CTX_free(ctx); + *res = keypair; + return 0; +} + +int +free_x25519_keypair(struct x25519_keypair *xkp) +{ + if (xkp == NULL) { + return -1; + } + + free(xkp->pubkey); + free(xkp->privkey); + return 0; +} diff --git a/lib/include/crypto/ecdh.h b/lib/include/crypto/ecdh.h new file mode 100644 index 0000000..6c87bbe --- /dev/null +++ b/lib/include/crypto/ecdh.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_ECDH_H_ +#define CRYPTO_ECDH_H_ + +#include + +struct x25519_keypair { + unsigned char *pubkey; + unsigned char *privkey; + size_t pubkey_len; + size_t privkey_len; +}; + +int gen_x25519_keypair(struct x25519_keypair *res); +int free_x25519_keypair(struct x25519_keypair *xkp); + +#endif /* CRYPTO_ECDH_H_ */ diff --git a/lib/include/defs.h b/lib/include/defs.h new file mode 100644 index 0000000..4fce06d --- /dev/null +++ b/lib/include/defs.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEFS_H_ +#define DEFS_H_ + +#define ATTR(X) __attribute__((X)) +#define PACKED ATTR(packed) +#define NORETURN ATTR(noreturn) + +#endif diff --git a/lib/include/net/stpsession.h b/lib/include/net/stpsession.h new file mode 100644 index 0000000..6564cc4 --- /dev/null +++ b/lib/include/net/stpsession.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NSTP LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NSTP LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR STPHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STP_SESSION_H_ +#define STP_SESSION_H_ + +#include +#include + +/* + * The Session Request is sent from the client to the + * server and contains a HOP (hash, options, pubkey) + * payload along with some optional padding. If the 'U' + * bit of options (see Options/flag bits below) is to + * be set, then everything but the 'hash' field must + * be encrypted with the server's AES-128-CBC key and + * the 'hash' field should contain a SHA256 hash of the + * username as well as an FNV-1a hash (used for internal + * lookups in the server) after it. However, if the 'U' + * bit is to be left unset, the session request packet + * can be left unencrypted and 'hash' may be zeroed. + * + * @hash: SHA256 username hash + FNV-1a username hash. + * @options: Flags/options + * @pubkey: Ephemeral public key. + * @pad: Random padding used to obsecure message length + * (can be 8 to 32 bytes, optional) + * + * -- Option/flag bits -- + * + * Bit number + * / + * 0 1 2 3 4 5 6 + * ~ ~ ~ ~ ~ ~ ~ + * U R R R R R R + * \ + * Purpose + * + * U: User auth. + * R: Reserved, keep zero. + */ +struct session_request { + char hash[64]; + uint8_t options; + char pubkey[32]; + char pad[8]; +} PACKED; + +#endif /* STP_SESSION_H_ */ diff --git a/ostp.d/net/otd_listen.c b/ostp.d/net/otd_listen.c new file mode 100644 index 0000000..87744c2 --- /dev/null +++ b/ostp.d/net/otd_listen.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LISTEN_PORT 5352 +#define KEY_BYTE_WIDTH 32 +#define MAX_BACKLOG 4 +#define MAX_CLIENTS 32 + +static int serv_sock; +static int clients[MAX_CLIENTS] = {0}; + +static void +signal_handle(int sig) +{ + printf("Cleaning up... goodbye!\n"); + + for (int i = 0; i < MAX_CLIENTS; ++i) { + close(clients[i]); + } + + close(serv_sock); + exit(0); +} + +static void +log_pubkey(char pubkey[KEY_BYTE_WIDTH]) +{ + for (size_t i = 0; i < KEY_BYTE_WIDTH; ++i) { + printf("%02X ", pubkey[i] & 0xFF); + if (i != 0 && i % 4 == 0) { + printf("\n"); + } + } +} + +static int +handle_client(struct sockaddr_in *caddr, int clientno) +{ + struct session_request srq; + struct x25519_keypair keypair; + ssize_t nread; + int client_fd; + + client_fd = clients[clientno]; + + /* Try to read in the session request */ + if ((nread = read(client_fd, &srq, sizeof(srq))) < 0) { + printf("Read failure...\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + if (nread == 0) { + printf("Connection closed by peer\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + /* Is this even a session request? */ + if (nread != sizeof(srq)) { + printf("Rejecting data - not a session request...\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + printf("Got public key from peer: \n"); + log_pubkey(srq.pubkey); + printf("Generating keys...\n"); + + if (gen_x25519_keypair(&keypair) < 0) { + printf("Key generation failed!\n"); + close(client_fd); + clients[clientno] = -1; + return -1; + } + + return 0; +} + +static void +read_clients(void) +{ + struct sockaddr_in caddr; + fd_set fds; + socklen_t caddr_len; + int client_sock, error = 0; + char *ip; + + memset(clients, -1, sizeof(clients)); + clients[0] = serv_sock; + + while (1) { + FD_ZERO(&fds); + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (clients[i] >= 0) + FD_SET(clients[i], &fds); + } + + if (select(1024, &fds, NULL, NULL, NULL) < 0) { + perror("select"); + continue; + } + + /* Check if the servers socket has new connections */ + if (FD_ISSET(serv_sock, &fds)) { + caddr_len = sizeof(caddr); + client_sock = accept(serv_sock, (struct sockaddr *)&caddr, + &caddr_len); + + if (client_sock < 0) { + perror("accept"); + continue; + } + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (clients[i] < 0) { + clients[i] = client_sock; + ip = inet_ntoa(caddr.sin_addr); + printf("Incoming connection from %s\n", ip); + break; + } + } + } + + /* Handle from data from clients */ + for (int i = 1; i < MAX_CLIENTS; ++i) { + if (clients[i] <= 0) + continue; + if (FD_ISSET(clients[i], &fds) <= 0) + continue; + + handle_client(&caddr, i); + break; + } + } + + close(client_sock); + close(serv_sock); +} + +int +main(void) +{ + struct sockaddr_in saddr; + int error; + + signal(SIGTERM, signal_handle); + signal(SIGINT, signal_handle); + + serv_sock = socket(AF_INET, SOCK_STREAM, 0); + if (serv_sock < 0) { + perror("Failed to create socket\n"); + return -1; + } + + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = INADDR_ANY; + saddr.sin_port = htons(LISTEN_PORT); + error = bind(serv_sock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (error < -1) { + perror("Failed to bind socket\n"); + close(serv_sock); + return error; + } + + if ((error = listen(serv_sock, MAX_BACKLOG)) < -1) { + perror("Failed to listen"); + return error; + } + + read_clients(); + return 0; +} -- cgit v1.2.3