diff options
author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2023-07-09 15:39:51 -0300 |
---|---|---|
committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2023-07-09 16:04:33 -0300 |
commit | 3c36d76be739b6975fac4e6adee3b91002056db1 (patch) | |
tree | 82f26ce27c21cca23367b3b40849e710216ab8b2 /src/server.c | |
parent | 7a388dad85152a203033c14fee3c64607301865a (diff) |
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..66c1ac5 --- /dev/null +++ b/src/server.c @@ -0,0 +1,160 @@ +#include <assert.h> +#include <stdbool.h> +#include <pthread.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "server.h" +#include "buffer.h" +#include "http.h" + +static bool enqueue(struct fd_queue *queue, int fd) { + if (queue->count == MAX_FD_QUEUE) { + return false; + } + + queue->queue[queue->back] = fd; + queue->count++; + queue->back = (queue->back + 1) % MAX_FD_QUEUE; + + return true; +} + +static int dequeue(struct fd_queue *queue) { + if (queue->count == 0) { + return -1; + } + + int fd = queue->queue[queue->front]; + queue->count--; + queue->front = (queue->front + 1) % MAX_FD_QUEUE; + + return fd; +} + +static void *handle_connection(void *data) { + assert(data); + struct thread_data *tdata = (struct thread_data*)data; + int fd = -1; + char buf[BUFSIZ + 1]; + ssize_t rlen; + struct buffer *request_buf, *reply_buf; + struct reply *reply; + + while(true) { + pthread_mutex_lock(&tdata->lock); + fd = dequeue(&tdata->queue); + if (fd == -1) { + pthread_cond_wait(&tdata->cond, &tdata->lock); + fd = dequeue(&tdata->queue); + } + pthread_mutex_unlock(&tdata->lock); + + printf("got fd %d\n", fd); + + if ((rlen = read(fd, buf, BUFSIZ)) < 0) { + perror("read failed"); + close(fd); + continue; + } + + buf[rlen] = '\0'; + request_buf = buf_new(buf); + + while (rlen >= BUFSIZ) { + if ((rlen = read(fd, buf, BUFSIZ)) < 0) { + perror("read failed"); + close(fd); + continue; + } + buf[rlen] = '\0'; + buf_append(request_buf, buf); + } + + reply = http_handle_request(tdata->http, request_buf); + reply_buf = http_build_reply(reply); + free(reply); + + write(fd, reply_buf->data, reply_buf->size); + + buf_del(&reply_buf); + buf_del(&request_buf); + + close(fd); + } +} + +struct server *server_init(struct http *http) { + struct server *server = malloc(sizeof(struct server)); + + server->server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server->server_fd < 0) { + perror("socket failure"); + return NULL; + } + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY, + .sin_port = htons(45748), + }; + + int addrlen = sizeof(addr); + int opt = 1; + + if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, + &opt, sizeof(opt)) < 0) { + perror("setsockopt failed"); + return NULL; + } + + if (bind(server->server_fd, (struct sockaddr*)&addr, addrlen) < 0) { + perror("bind failed"); + return NULL; + } + + if (listen(server->server_fd, 16) < 0) { + perror("listen failed"); + return NULL; + } + + server->addr = addr; + server->addrlen = addrlen; + server->thread_pool_size = THREAD_POOL_NUM; + server->data.http = http; + server->pool = calloc(server->thread_pool_size, sizeof(pthread_t)); + pthread_mutex_init(&server->data.lock, NULL); + pthread_cond_init(&server->data.cond, NULL); + server->data.queue.back = -1; + server->data.queue.front = -1; + server->data.queue.count = 0; + + for (size_t i = 0; i < server->thread_pool_size; i++) { + pthread_create(&server->pool[i], NULL, handle_connection, &server->data); + } + + return server; +} + +void server_poll(struct server *server) { + int client_fd; + + while (true) { + if ((client_fd = accept(server->server_fd, (struct sockaddr*)&server->addr, + (socklen_t*)&server->addrlen)) < 0) { + perror("accept failed"); + return; + } + + printf("connection accepted on fd %d\n", client_fd); + + pthread_mutex_lock(&server->data.lock); + enqueue(&server->data.queue, client_fd); + pthread_cond_signal(&server->data.cond); + pthread_mutex_unlock(&server->data.lock); + + } +} |