diff options
Diffstat (limited to 'lib/libostp/server.c')
-rw-r--r-- | lib/libostp/server.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/lib/libostp/server.c b/lib/libostp/server.c new file mode 100644 index 0000000..0013ce2 --- /dev/null +++ b/lib/libostp/server.c @@ -0,0 +1,195 @@ +/* + * 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 <libostp/server.h> +#include <net/auth.h> +#include <net/stpsession.h> +#include <arpa/inet.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#define MAX_BACKLOG 4 +#define LISTEN_PORT 5352 + +static int +handle_client(struct sockaddr_in *caddr, struct ostp_session *sp, struct ostp_listener *lp, + int clientno) +{ + struct session_request srq; + ssize_t nread; + + sp->sockfd = lp->clients[clientno]; + + /* Try to read in the session request */ + if ((nread = read(sp->sockfd, &srq, sizeof(srq))) < 0) { + printf("Read failure...\n"); + close(sp->sockfd); + lp->clients[clientno] = -1; + return -1; + } + + if (nread == 0) { + printf("Connection closed by peer\n"); + close(sp->sockfd); + lp->clients[clientno] = -1; + return -1; + } + + /* Is this even a session request? */ + if (nread != sizeof(srq)) { + printf("Rejecting data - not a session request...\n"); + close(sp->sockfd); + lp->clients[clientno] = -1; + return -1; + } + + /* Handle the session request */ + if (handle_srq(sp, lp, &srq) < 0) { + close(sp->sockfd); + lp->clients[clientno] = -1; + return -1; + } + + return 0; +} + +/* + * Put a listener in a known state during + * initialization. + */ +void +listener_init(struct ostp_listener *lp) +{ + lp->port = LISTEN_PORT; + lp->on_recv = NULL; +} + +int +listener_bind(struct ostp_session *sp, struct ostp_listener *lp) +{ + struct sockaddr_in saddr; + int error; + + lp->serv_sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sp->sockfd < 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(lp->serv_sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (error < 0) { + perror("Failed to bind socket\n"); + close(lp->serv_sockfd); + return error; + } + + if ((error = listen(lp->serv_sockfd, MAX_BACKLOG)) < 0) { + perror("Failed to listen"); + return error; + } + + return 0; +} + +int +listener_poll(struct ostp_session *sp, struct ostp_listener *lp) +{ + struct sockaddr_in caddr; + socklen_t caddr_len; + int client_sock, error = 0; + char *ip; + + memset(lp->clients, -1, sizeof(lp->clients)); + lp->clients[0] = lp->serv_sockfd; + + while (1) { + FD_ZERO(&lp->client_fds); + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (lp->clients[i] >= 0) + FD_SET(lp->clients[i], &lp->client_fds); + } + + if (select(1024, &lp->client_fds, NULL, NULL, NULL) < 0) { + perror("select"); + continue; + } + + /* Check if the servers socket has new connections */ + if (FD_ISSET(lp->serv_sockfd, &lp->client_fds)) { + caddr_len = sizeof(caddr); + client_sock = accept(lp->serv_sockfd, (struct sockaddr *)&caddr, + &caddr_len); + + if (client_sock < 0) { + perror("accept"); + continue; + } + + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (lp->clients[i] < 0) { + lp->clients[i] = client_sock; + ip = inet_ntoa(caddr.sin_addr); + printf("Incoming connection from %s\n", ip); + break; + } + } + } + + /* Handle from data from lp->clients */ + for (int i = 1; i < MAX_CLIENTS; ++i) { + if (lp->clients[i] <= 0) + continue; + if (FD_ISSET(lp->clients[i], &lp->client_fds) <= 0) + continue; + + handle_client(&caddr, sp, lp, i); + break; + } + } + + close(client_sock); + close(lp->serv_sockfd); +} + +void +listener_cleanup(struct ostp_listener *lp) +{ + for (int i = 0; i < MAX_CLIENTS; ++i) { + if (lp->clients[i] > 0) { + close(lp->clients[i]); + } + } + + close(lp->serv_sockfd); +} |