diff options
author | kartofen <mladenovnasko0@gmail.com> | 2023-01-26 14:58:09 +0200 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2023-01-26 14:58:09 +0200 |
commit | 5e1ae8b33873661b669eda509fcd000f8a964126 (patch) | |
tree | 6099bee318d9f0033949d23a3eeded6974d34b35 /src |
very simple work withs html based on file path
Diffstat (limited to 'src')
-rw-r--r-- | src/log.h | 14 | ||||
-rw-r--r-- | src/main.c | 158 | ||||
-rw-r--r-- | src/server.c | 122 | ||||
-rw-r--r-- | src/server.h | 17 |
4 files changed, 311 insertions, 0 deletions
diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..000ce95 --- /dev/null +++ b/src/log.h @@ -0,0 +1,14 @@ +#ifndef LOG_H +#define LOG_H + +#define __RED__ "\033[0;31m" +#define __GREEN__ "\033[0;32m" +#define __RESET__ "\033[0m" + +#define STR(x) #x +#define XSTR(x) STR(x) + +#define info(...) fprintf(stdout, __GREEN__"[INFO]"__RESET__" "__VA_ARGS__); fprintf(stdout, "\n") +#define err(...) fprintf(stderr, __RED__"[ERROR]"__RESET__" "__FILE__":"XSTR(__LINE__)": "__VA_ARGS__); fprintf(stderr, "\n") + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..78a1069 --- /dev/null +++ b/src/main.c @@ -0,0 +1,158 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> + +#include "log.h" +#include "server.h" + +#define BUF_CAP 80000 +#define PORT "8079" + +#define SEND_BUF_ADD(str) do { \ + memcpy(&send_buf[*send_buf_sz], str, strlen(str)); \ + *send_buf_sz += strlen(str); \ + } while(0) + +#define SEND_BUF_ADD_LINE(str) do { \ + SEND_BUF_ADD(str); \ + SEND_BUF_ADD("\r\n"); \ + } while(0) + +static int try_file(char *req_path, FILE **fp) +{ + char file_path[1024]; + sprintf(file_path, "%s%s", FILES, + (strlen(req_path) == 1) ? "/index.html" : req_path); + + *fp = fopen(file_path, "r"); + if(!(*fp)) { + err("fopen: file %s: %s", file_path, strerror(errno)); + return 1; + } + info("fopen: file %s was opened", file_path); + return 0; +} + +static int on_get(char *send_buf, ssize_t *send_buf_sz, char *req_path) +{ + SEND_BUF_ADD("HTTP/1.1 "); + + FILE *fp; + if(try_file(req_path, &fp) != 0) { + if(errno == 2) { // 2 is 'No such file or directory' + SEND_BUF_ADD_LINE("404"); + if(try_file("/404.html", &fp) != 0) return 1; + } else { + SEND_BUF_ADD_LINE("500"); + if(try_file("/505.html", &fp) != 0) return 1; + } + } else { + SEND_BUF_ADD_LINE("200"); + } + + SEND_BUF_ADD_LINE("Server: potato"); + // SEND_BUF_ADD_LINE("Content-Type: image/x-icon"); + SEND_BUF_ADD("\r\n"); + + // fseek(fp, 0, SEEK_END); + // size_t file_sz = ftell(fp); + // rewind(fp); + + // fread(&send_buf[*send_buf_sz], sizeof(char), file_sz, fp); + // *send_buf_sz += file_sz; + + char line[BUF_CAP]; + while(fgets(line, sizeof(line), fp) != NULL) + { + if(line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; + SEND_BUF_ADD_LINE(line); + } + + fclose(fp); + return 0; +} + +static int handle_connection(sock_t *conn) +{ + char recv_buf[BUF_CAP] = {0}; + ssize_t recv_buf_len = server_recv(conn, recv_buf, BUF_CAP); + + if(recv_buf_len == 0) { + return 0; + } else if(recv_buf_len < 0) { + err("server_recv: %s", strerror(errno)); + return 1; + } + + /* HANDLE REQUEST */ + + char send_buf[BUF_CAP]; + ssize_t send_buf_sz = 0; + + char recv_buf_cpy[BUF_CAP]; + memcpy(recv_buf_cpy, recv_buf, recv_buf_len); + + char *req_method = strtok(recv_buf_cpy, " "); + if(strcmp(req_method, "GET") == 0) { + if(on_get(send_buf, &send_buf_sz, strtok(NULL, " "))) { + err("on_get: failed"); + return 1; + } + } else { + err("request method %s has not been implemented", req_method); + return 1; + } + + // TODO: handle when the whole message is not sent + ssize_t sent_sz = server_send(conn, send_buf, send_buf_sz); + if(sent_sz < 0) { + err("server_send: %s", strerror(errno)); + return 1; + } + + info("server_send: sent %ld out of %ld bytes", sent_sz, send_buf_sz); + return 0; +} + +int main(void) +{ + signal(SIGCHLD, SIG_IGN); // now i dont have to wait() + + sock_t *sock = server_sock_create(); + + if(server_start(PORT, sock) != 0) { + err("server_init: failed"); + return 1; + } + + for(int i = 0; ; i++) { + sock_t *conn = server_sock_create(); + if(server_accept(sock, conn) != 0) { + err("server_accept: failed"); + } + + info("server: got connection with %s", server_connection_ip(conn)); + + pid_t p = fork(); + if(p == 0) { + server_sock_close(sock); + if(handle_connection(conn) != 0) { + err("handle_connection: failed"); + } else { + info("server: got disconnected with %s", server_connection_ip(conn)); + } + server_sock_close(conn); + return 0; + } else if (p < 0){ + err("fork: %s", strerror(errno)); + return 1; + } + server_sock_close(conn); + } + + server_sock_close(sock); + return 0; +} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..73a8d59 --- /dev/null +++ b/src/server.c @@ -0,0 +1,122 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> + +#include "log.h" +#include "server.h" + +struct sock_t { + int sockfd; + char ip[INET6_ADDRSTRLEN]; +}; + +static void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int server_start(char *port, sock_t *sock) +{ + struct addrinfo hints, *servinfo; + int rv; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // use my IP + + if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) { + err("getaddrinfo: %s", gai_strerror(rv)); + return 1; + } + + // loop through all the results and bind to the first we can + struct addrinfo *p = NULL; + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sock->sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + err("socker: %s", strerror(errno)); + continue; + } + + int yes=1; + if (setsockopt(sock->sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + err("setsockopt: %s", strerror(errno)); + return 1; + } + + if (bind(sock->sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sock->sockfd); + err("bind: %s", strerror(errno)); + continue; + } + + break; + } + + if (p == NULL) { + err("server: failed to bind"); + return 1; + } + + freeaddrinfo(servinfo); + + if(listen(sock->sockfd, 10) == -1) { + err("listen: %s", strerror(errno)); + return 1; + } + return 0; +} + +int server_accept(sock_t *sock, sock_t *conn) +{ + struct sockaddr_storage conn_addr; + socklen_t sz = sizeof(conn_addr); + conn->sockfd = accept(sock->sockfd, (struct sockaddr *)&conn_addr, &sz); + if(conn->sockfd == -1) { + err("accept: %s", strerror(errno)); + return 1; + } + + inet_ntop(conn_addr.ss_family, + get_in_addr((struct sockaddr *)&conn_addr), + conn->ip, sizeof(conn->ip)); + + return 0; +} + +ssize_t server_send(sock_t *sock, char *buf, size_t sz) +{ + return send(sock->sockfd, buf, sz, 0); +} + +ssize_t server_recv(sock_t *sock, char *buf, size_t sz) +{ + return recv(sock->sockfd, buf, sz, 0); +} + +char *server_connection_ip(sock_t *conn) +{ + return conn->ip; +} + +sock_t *server_sock_create() +{ + return (sock_t *)malloc(sizeof(sock_t)); +} + +void server_sock_close(sock_t *s) +{ + close(s->sockfd); + free(s); +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..f5107b5 --- /dev/null +++ b/src/server.h @@ -0,0 +1,17 @@ +#ifndef SERVER_H +#define SERVER_H + +typedef struct sock_t sock_t; +struct sock_t; + +int server_start(char *port, sock_t *sock); +int server_accept(sock_t *sock, sock_t *conn); + +ssize_t server_send(sock_t *sock, char *buf, size_t sz); +ssize_t server_recv(sock_t *sock, char *buf, size_t sz); +char *server_connection_ip(sock_t *conn); + +sock_t *server_sock_create(); +void server_sock_close(sock_t *s); + +#endif |