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) | |
| download | libactivity-main.tar.xz | |
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); + +	} +} | 
