#include #include #include #include #include #include #include #include #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); } }