aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/log.h14
-rw-r--r--src/main.c158
-rw-r--r--src/server.c122
-rw-r--r--src/server.h17
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