diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 5316267..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 79ee123..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/cws.iml b/.idea/cws.iml
deleted file mode 100644
index 55d7baf..0000000
--- a/.idea/cws.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
deleted file mode 100644
index 27e844a..0000000
--- a/.idea/editor.xml
+++ /dev/null
@@ -1,580 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 683c996..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 2ce65a9..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 9497029..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 5b91413..99d10f2 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,14 @@
# cws
-A minimal web server written in C. This is a personal project; it is not intended to be a production-ready tool, nor
-will it ever be. Use it at your own risk.
+A minimal web server. This is a personal project; it is not intended to be a production-ready tool, nor will it ever be. Use it at your own risk.
## Requirements
- [meson](https://mesonbuild.com/index.html)
-- [doxygen](https://www.doxygen.nl/)
- - Optional, just to build the docs.
- libcyaml
- libyaml
+- [doxygen](https://www.doxygen.nl/)
+ - Optional, just to build the docs.
## How to build
@@ -24,7 +23,6 @@ And then run `cws`!
## Docs
```bash
-# inside the cws directory
$ git submodule update --init
$ doxygen
```
@@ -33,23 +31,14 @@ And then open the `docs/html/index.html`.
## Roadmap
-- [x] Understanding basic web server concepts
-- [x] Basic server
-- [ ] CLI args
-- [ ] Enhance web server
- - [ ] IPv6 compatible
- - [ ] Request parser
- - [x] Serve static files
- - [ ] Implement Keep-Alive
- - [ ] Multithreading to handle concurrent requests
- - [ ] Logging
-- [ ] Advanced Features
- - [ ] HTTPS support with TLS
- - [ ] Compression (Gzip)
- - [ ] Support for virtual hosting
+- Request parser
+- Implement Keep-Alive
+- Support for virtual hosting
+- HTTPS support with TLS
-## Resources
-
-- [Beej's Guide to Network Programming](https://beej.us/guide/bgnet/)
-
-You can find my journey inside the `notes` directory.
+## Future
+- CLI args
+- IPv6 compatible
+- Multithreading to handle concurrent requests
+- Logging
+- Compression (Gzip)
diff --git a/include/utils/colors.h b/include/utils/colors.h
index c48e679..c648910 100644
--- a/include/utils/colors.h
+++ b/include/utils/colors.h
@@ -9,4 +9,28 @@
#define BOLD "\033[1m"
#define RESET "\033[0m"
+#ifdef USE_COLORS
+#define _ERR RED BOLD "[ERROR]" RESET
+#define _WARNING YELLOW "[WARNING]" RESET
+#define _INFO GREEN "[INFO]" RESET
+#define _DEBUG BLUE "[DEBUG]" RESET
+#else
+#define _ERR "[ERROR]"
+#define _WARNING "[WARNING]"
+#define _INFO "[INFO]"
+#define _DEBUG "[DEBUG]"
+#endif
+
+#ifdef EVELOPER
+#define CWS_LOG_DEBUG(msg, ...) fprintf(stdout, _DEBUG " " msg "\n", ##__VA_ARGS__)
+#else
+#define CWS_LOG_DEBUG(msg, ...)
+#endif
+
+#define CWS_LOG(level, msg, ...)
+
+#define CWS_LOG_ERROR(msg, ...) fprintf(stderr, _ERR " " msg "\n", ##__VA_ARGS__)
+#define CWS_LOG_WARNING(msg, ...) fprintf(stdout, _WARNING " " msg "\n", ##__VA_ARGS__)
+#define CWS_LOG_INFO(msg, ...) fprintf(stdout, _INFO " " msg "\n", ##__VA_ARGS__)
+
#endif
\ No newline at end of file
diff --git a/meson.build b/meson.build
index b807b0f..32e5c82 100644
--- a/meson.build
+++ b/meson.build
@@ -7,4 +7,7 @@ incdir = include_directories('include')
libyaml = dependency('yaml-0.1')
libcyaml = dependency('libcyaml')
+add_global_arguments('-DUSE_COLORS', language : 'c')
+add_global_arguments('-DEVELOPER', language : 'c')
+
executable('cws', server, include_directories : incdir, dependencies : [libyaml, libcyaml])
diff --git a/notes/advanced-techniques.md b/notes/advanced-techniques.md
deleted file mode 100644
index 496d4cb..0000000
--- a/notes/advanced-techniques.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Advanced Techniques
-
-- [Advanced Techniques](#advanced-techniques)
- - [Blocking](#blocking)
- - [poll() - Synchronous I/O Multiplexing](#poll---synchronous-io-multiplexing)
- - [epoll() - I/O Event Notification (Async)](#epoll---io-event-notification-async)
-
-### Blocking
-
-All the Unix networking functions are **blocking**. What does it mean? It means that if you write `accept()` or `recv()`
-it will wait until some data appears. So how we can avoid this? Making the socket non blocking so we can poll the socket
-for info:
-
-```c
-fcntl(sockfd, F_SETFL, O_NONBLOCK);
-```
-
-`F_SETFL`: set the file descriptor flags
-`O_NONBLOCK`: make the fd non blocking
-
-### poll() - Synchronous I/O Multiplexing
-
-The plan is to have a `struct pollfd` with the info about which sockets fd we want to monitor. The Operating System will
-block on the `poll()` call until one event occurs (e.g. "socket ready to write/read").
-
-```c
-#include
-
-int poll(struct pollfd fds[], nfds_t nfds, int timeout);
-```
-
-`fds` is our array of info (which sockets to monitor)
-`nfds` the elements in the array
-`timeout` in milliseconds (-1 to wait forever)
-
-```c
-struct pollfd {
- int fd; // the socket descriptor
- short events; // bitmap of events we're interested in
- short revents; // when poll() returns, bitmap of events that occurred
-};
-```
-
-`events` is a bitmap of the following values:
-
-- `POLLIN` (alert when I can read data)
-- `POLLOUT` (alert when I can send data)
-
-**I won't continue this section, read below**
-
-### epoll() - I/O Event Notification (Async)
-
-It is similar to `poll()` but more efficient when dealing with lots of fds. The array is in the kernel space, no further
-copies. Nice explaination [here](https://copyconstruct.medium.com/the-method-to-epolls-madness-d9d2d6378642).
-
-```c
-#include
-
-int epoll_create1(int flags);
-```
-
-Just pass 0 for the `flags`, it is an improved version of the `epoll_create()`. It creates a new epoll instance and
-returns the fd of that instance.
-
-```c
-#include
-
-int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
-```
-
-- `epoll_ctl()` is used to register new fds and add them to the interest list:
- - `epfd` epoll file descriptor
- - `op` the operation: `EPOLL_CTL_ADD`, `EPOLL_CTL_MOD` or `EPOLL_CTL_DEL`
- - `fd` the file descriptor to check
- - `event` a pointer to the `epoll_event` struct
-
-- `epoll_wait()` waits for I/O events, blocking the calling thread if no events are availables.
- - `epfd` epoll file descriptor
- - `events` array where there will be saved ready events
- - `maxevents` max events per array
- - `timeout` in milliseconds (-1 forever)
-
-```c
-struct epoll_event {
- uint32_t events; // bitmap
- epoll_data_t data;
-};
-
-union epoll_data {
- void *ptr;
- int fd; // just use this
- uint32_t u32;
- uint64_t u64;
-};
-```
diff --git a/notes/basic-concepts.md b/notes/basic-concepts.md
deleted file mode 100644
index fecd042..0000000
--- a/notes/basic-concepts.md
+++ /dev/null
@@ -1,279 +0,0 @@
-# Basic Concepts
-
-Before reading, this document could contain errors, please check everything you read.
-
-- [Basic Concepts](#basic-concepts)
- - [Socket](#socket)
- - [Internet sockets](#internet-sockets)
- - [Byte Order](#byte-order)
- - [Structs](#structs)
- - [struct addrinfo](#struct-addrinfo)
- - [struct sockaddr](#struct-sockaddr)
- - [struct sockaddr\_in](#struct-sockaddr_in)
- - [struct sockaddr\_storage](#struct-sockaddr_storage)
- - [IP Addresses](#ip-addresses)
- - [getaddrinfo()](#getaddrinfo)
- - [socket()](#socket-1)
- - [bind()](#bind)
- - [connect()](#connect)
- - [listen()](#listen)
- - [accept()](#accept)
- - [send() and recv()](#send-and-recv)
- - [sendto() and recvfrom()](#sendto-and-recvfrom)
- - [close() and shutdown()](#close-and-shutdown)
- - [getpeername()](#getpeername)
- - [gethostname()](#gethostname)
-
-### Socket
-
-When Unix programs do some I/O they do it reading/writing to a **file descriptor**. A file descriptor is an integer
-associated with an open file, it can be anything. To communicate over the internet using a file descriptor we'll make a
-call to the `socket()` system routine.
-
-### Internet sockets
-
-There are two types of Internet sockets:
-
-1. Stream Sockets (SOCK_STREAM) - error-free and a realiable two-way communication (TCP)
-2. Datagram Sockets (SOCK_DGRAM) - connectionless (UDP)
-
-### Byte Order
-
-- Big-Endian (also called **Network Byte Order**)
-- Little-Endian
-
-Before making any transmission we have to convert the byte order to a Network Byte Order, we can do this with simple
-functions:
-
-| Function | Description |
-|----------|-----------------------|
-| htons() | Host to Network Short |
-| htonl() | Host to Network Long |
-| ntohs() | Network to Host Short |
-| ntohl() | Network to Host Long |
-
-And convert the answer to the host byte order.
-
-### Structs
-
-#### struct addrinfo
-
-This struct prepares the socket address strcutures for subsequent use.
-
-```c
-struct addrinfo {
- int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
- int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
- int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
- int ai_protocol; // use 0 for "any"
- size_t ai_addrlen; // size of ai_addr in bytes
- struct sockaddr *ai_addr; // struct sockaddr_in or _in6
- char *ai_canonname; // full canonical hostname
-
- struct addrinfo *ai_next; // linked list, next node
-};
-```
-
-#### struct sockaddr
-
-Inside the struct we can see there is a pointer to the `struct sockaddr`, that is defined as follows:
-
-```c
-struct sockaddr {
- unsigned short sa_family; // address family, AF_xxx
- char sa_data[14]; // 14 bytes of protocol address
-};
-```
-
-#### struct sockaddr_in
-
-But, we can avoid to pack manually the stuff inside this struct and use the `struct sockaddr_in` (or
-`struct sockaddr_in6` for IPv6) with a fast cast that is made for the Internet:
-
-```c
-struct sockaddr_in {
- short int sin_family; // Address family, AF_INET
- unsigned short int sin_port; // Port number
- struct in_addr sin_addr; // Internet address
- unsigned char sin_zero[8]; // Same size as struct sockaddr
-};
-```
-
-`sin_zero` is used to pad the struct to the length of a sockaddr and it should be set to all zeros (`memset()`).
-
-#### struct sockaddr_storage
-
-This struct is designed to storage both IPv4 and IPv6 structures. Example, when a client is going to connect to your
-server you don't know if it is a IPv4 or IPv6 so you use this struct and then cast to what you need (check the
-`ss_family` first).
-
-```c
-struct sockaddr_storage {
- sa_family_t ss_family; // address family
-
- // all this is padding, implementation specific, ignore it:
- char __ss_pad1[_SS_PAD1SIZE];
- int64_t __ss_align;
- char __ss_pad2[_SS_PAD2SIZE];
-};
-```
-
-### IP Addresses
-
-Here's a way to convert an IP address string into a struct.
-
-```c
-struct sockaddr_in sa;
-struct sockaddr_in6 sa6;
-
-inet_pton(AF_INET, "192.168.0.1", &(sa.sin_addr));
-inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr));
-```
-
-There is a very easy function called `inet_pton()`, *pton* stands for **Presentation to network**. If you want to do the
-same but from binary to string you have `inet_ntop()`.
-
-### getaddrinfo()
-
-```c
-#include
-#include
-#include
-
-int getaddrinfo(const char *node, // e.g. "www.example.com" or IP
- const char *service, // e.g. "http" or port number
- const struct addrinfo *hints,
- struct addrinfo **res);
-```
-
-The `node` could be a host name or IP address. `service` could be a port number or a service found in `/etc/services` (
-e.g. "http" or "ftp" or "telnet").
-`hints` points to a struct you already filled and `res` contains a linked list of results.
-
-### socket()
-
-```c
-#include
-#include
-
-int socket(int domain, int type, int protocol);
-```
-
-`domain` could be `PF_INET` or `PF_INET6`, `type` instead TCP or UDP and `protocol` to 0. `PF_INET` is very close to
-`AF_INET`! However, we can avoid to put the stuff manually and use the results from `getaddrinfo()`.
-
-### bind()
-
-Do this if you're going to listen on a port. The port is used by the kernel to match an incoming packet to a socket
-descriptor.
-
-```c
-#include
-#include
-
-int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
-```
-
-### connect()
-
-```c
-#include
-#include
-
-int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
-```
-
-### listen()
-
-```c
-int listen(int sockfd, int backlog);
-```
-
-`backlog` is the amount of max clients allowed on the incoming queue. A client will wait in the queue until you accept
-it.
-
-### accept()
-
-```c
-#include
-#include
-
-int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-```
-
-After you accept a client, the function will return a new socket file descriptor used to communicate.
-
-### send() and recv()
-
-```c
-int send(int sockfd, const void *msg, int len, int flags);
-```
-
-Just put `flags` to 0. It will return the bytes sent, but sometimes it could not match the len of the data sent, it's up
-to you to send the rest of the string (it should sent 1K of data without splitting).
-
-```c
-int recv(int sockfd, void *buf, int len, int flags);
-```
-
-Put 0 at `flags` (see the man page for more info). The `sockfd` is the file descriptor to read from. The function could
-return 0 (this means the remote side has closed the connection).
-
-### sendto() and recvfrom()
-
-It's the DGRAM equivalent of STREAM. Marked as *TODO*.
-
-### close() and shutdown()
-
-To close the connection just use the regular Unix file descriptor `close()` function:
-
-```c
-close(sockfd);
-```
-
-If you want more control over how the socket closes there is `shutdown()`:
-
-```c
-int shutdown(int sockfd, int how);
-```
-
-`how` is one of the following:
-| how | Effect |
-| --- | ------------------------ |
-| 0 | No future receives |
-| 1 | No future sends |
-| 2 | No future receives/sends |
-The 2 is like `close()`, use `close()`.
-
-### getpeername()
-
-This function is quite simple. It will tell you who is in the other side of the connection.
-
-```c
-#include
-
-int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
-```
-
-Example of getting client's IP:
-
-```c
-struct sockaddr_storage their;
-socklen_t their_len = sizeof their;
-
-int clientfd = accept(sockfd, (struct sockaddr *)&their, &their_len);
-getpeername(clientfd, (struct sockaddr *)&their, &their_len);
-struct sockaddr_in *client = (struct sockaddr_in *)&their;
-char client_ip[INET_ADDRSTRLEN];
-inet_ntop(AF_INET, &client->sin_addr, client_ip, INET_ADDRSTRLEN);
-```
-
-### gethostname()
-
-```c
-#include
-
-int gethostname(char *hostname, size_t size);
-```
-
-Returns the name of the computer that your program is running on.
diff --git a/notes/hash-table.md b/notes/hash-table.md
deleted file mode 100644
index e10e9b4..0000000
--- a/notes/hash-table.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Hash Table
-
-Well, the moment has come. I never made a Hash Map algorithm, but in this scenario I have to save both fd and sockaddr (
-I could make a simply linked list, but it's a way to learn new things).
-
-Let's start with a little bit of theory.
-
-A *Hash Table* is a data structure also called **dictionary** or **map**. It maps *keys* to *values* thanks to a **hash
-function** that computes and *index* (**hash code**) into an array of **buckets**.
-
-One problem could be the *hash collision* where the hash function computes the same index for different values. A fix
-could be the **chaining** method, where for the same hash code you can make a linked list and append the index. Then the
-lookup function will go through the list and find the key.
-
-In a Hash Map you can insert, delete and lookup (simply search).
-
-### Hash function
-
-The easiest way... don't judge me.
-
-- Integer keys:
- $$ hash(\text{key}) = \text{key} \mod \text{table\_dim} $$
-
-- String keys:
- $$ hash(key) = \sum_{i=0}^{len(key) - 1} ascii\_value(key[i]) * prime\_number$$
diff --git a/notes/http-request.md b/notes/http-request.md
deleted file mode 100644
index 6d53c58..0000000
--- a/notes/http-request.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# HTTP Request
-
-This is an example of a basic HTTP request made from the browser:
-
-```bash
-GET / HTTP/1.1
-User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
-Host: www.tutorialspoint.com
-Accept-Language: en-us
-Accept-Encoding: gzip, deflate
-Connection: Keep-Alive
-```
-
-> Thanks tutorialspoint
-
-The first line is a *request line*. It has:
-
-- Method (GET, POST, HEAD, ...)
-- Location (the request resource, file)
-- HTTP version
-
-# HTTP Response
-
-```bash
-HTTP/1.1 200 OK\r\n
-Content-Type: text/html\r\n
-Content-Length: 88\r\n
-Connection: close\r\n
-\r\n
-
-```
-
-`Content-Length` is the length of the body (in the response case is the length of html page)
\ No newline at end of file
diff --git a/src/http/http.c b/src/http/http.c
index 60a2994..2f4466e 100644
--- a/src/http/http.c
+++ b/src/http/http.c
@@ -1,6 +1,6 @@
#include "http/http.h"
-#include /* Debug */
+#include
#include
#include
#include
@@ -21,7 +21,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd) {
if (pch == NULL) {
return NULL;
}
- printf("[client::http] method: %s\n", pch);
+ CWS_LOG_DEBUG("[client::http] method: %s", pch);
cws_http_parse_method(request, pch);
/* Parse location */
@@ -29,7 +29,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd) {
if (pch == NULL) {
return NULL;
}
- printf("[client::http] location: %s\n", pch);
+ CWS_LOG_DEBUG("[client::http] location: %s", pch);
strncpy(request->location, pch, CWS_HTTP_LOCATION_LEN);
/* Parse location path */
@@ -38,14 +38,14 @@ cws_http *cws_http_parse(char *request_str, int sockfd) {
} else {
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", CWS_WWW, request->location);
}
- fprintf(stdout, "[client::http] location path: %s\n", request->location_path);
+ CWS_LOG_DEBUG("[client::http] location path: %s", request->location_path);
/* Parse HTTP version */
pch = strtok(NULL, " \r\n");
if (pch == NULL) {
return NULL;
}
- printf("[client::http] version: %s\n", pch);
+ CWS_LOG_DEBUG("[client::http] version: %s", pch);
strncpy(request->http_version, pch, CWS_HTTP_VERSION_LEN);
/* Parse other stuff... */
@@ -90,7 +90,7 @@ void cws_http_send_response(cws_http *request) {
char *file_data = malloc(content_length);
if (file_data == NULL) {
fclose(file);
- fprintf(stderr, RED "Unable to allocate file data\n");
+ CWS_LOG_ERROR("Unable to allocate file data");
return;
}
diff --git a/src/main.c b/src/main.c
index 6b8bcec..e978220 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,36 +1,31 @@
#include
-#include
#include
+#include
#include
#include "server/server.h"
#include "utils/colors.h"
#include "utils/config.h"
-void cws_signal_handler(int signo) {
- fprintf(stdout, BLUE "[server] Cleaning up resources...\n" RESET);
- cws_server_run = false;
-}
+void cws_signal_handler(int signo) { cws_server_run = false; }
int main(int argc, char **argv) {
int ret;
cws_config *config = cws_config_init();
if (config == NULL) {
- fprintf(stderr, RED BOLD "[server] Unable to read config file\n" RESET);
+ CWS_LOG_ERROR("[server] Unable to read config file");
return 1;
}
- struct sigaction act = {
- .sa_handler = cws_signal_handler
- };
+ struct sigaction act = {.sa_handler = cws_signal_handler};
ret = sigaction(SIGINT, &act, NULL);
- fprintf(stdout, BOLD GREEN "[server] Running cws on http://%s:%s...\n" RESET, config->host, config->port);
+ CWS_LOG_INFO("[server] Running cws on http://%s:%s...", config->host, config->port);
ret = cws_server_start(config->host, config->port);
if (ret < 0) {
- fprintf(stderr, BOLD RED "[server] Unable to start web server\n" RESET);
+ CWS_LOG_ERROR("[server] Unable to start web server");
}
cws_config_free(config);
diff --git a/src/server/server.c b/src/server/server.c
index 34a6c00..0138eb2 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -26,7 +26,7 @@ int cws_server_start(const char *hostname, const char *service) {
int status = getaddrinfo(hostname, service, &hints, &res);
if (status != 0) {
- fprintf(stderr, RED BOLD "[server] getaddrinfo() error: %s\n" RESET, gai_strerror(status));
+ CWS_LOG_ERROR("[server] getaddrinfo() error: %s", gai_strerror(status));
exit(EXIT_FAILURE);
}
@@ -35,19 +35,19 @@ int cws_server_start(const char *hostname, const char *service) {
const int opt = 1;
status = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
if (status != 0) {
- fprintf(stderr, RED BOLD "[server] setsockopt(): %s\n" RESET, strerror(errno));
+ CWS_LOG_ERROR("[server] setsockopt(): %s", strerror(errno));
exit(EXIT_FAILURE);
}
status = bind(sockfd, res->ai_addr, res->ai_addrlen);
if (status != 0) {
- fprintf(stderr, RED BOLD "[server] bind(): %s\n" RESET, strerror(errno));
+ CWS_LOG_ERROR("[server] bind(): %s", strerror(errno));
exit(EXIT_FAILURE);
}
status = listen(sockfd, CWS_SERVER_BACKLOG);
if (status != 0) {
- fprintf(stderr, RED BOLD "[server] listen(): %s\n" RESET, gai_strerror(status));
+ CWS_LOG_ERROR("[server] listen(): %s", gai_strerror(status));
exit(EXIT_FAILURE);
}
@@ -61,10 +61,13 @@ int cws_server_start(const char *hostname, const char *service) {
void cws_server_setup_hints(struct addrinfo *hints, size_t len, const char *hostname) {
memset(hints, 0, len);
+
/* IPv4 or IPv6 */
hints->ai_family = AF_UNSPEC;
+
/* TCP */
hints->ai_socktype = SOCK_STREAM;
+
if (hostname == NULL) {
/* Fill in IP for me */
hints->ai_flags = AI_PASSIVE;
@@ -94,13 +97,14 @@ void cws_server_loop(int sockfd) {
char ip[INET_ADDRSTRLEN];
client_fd = cws_server_accept_client(sockfd, &their_sa, &theirsa_size);
cws_utils_get_client_ip(&their_sa, ip);
- fprintf(stdout, BLUE "[server] Client (%s) connected\n" RESET, ip);
+ CWS_LOG_INFO("[server] Client (%s) connected", ip);
cws_fd_set_nonblocking(client_fd);
cws_epoll_add(epfd, client_fd, EPOLLIN);
cws_hm_push(clients, client_fd, &their_sa);
} else {
char data[4096] = {0};
+
/* Incoming data */
client_fd = revents[i].data.fd;
const ssize_t bytes_read = recv(client_fd, data, sizeof data, 0);
@@ -110,7 +114,7 @@ void cws_server_loop(int sockfd) {
if (bytes_read == 0) {
/* Client disconnected */
- fprintf(stdout, BLUE "[server] Client (%s) disconnected\n" RESET, ip);
+ CWS_LOG_INFO("[server] Client (%s) disconnected", ip);
cws_server_close_client(epfd, client_fd, clients);
continue;
}
@@ -135,7 +139,7 @@ void cws_server_loop(int sockfd) {
}
cws_http_send_response(request);
- fprintf(stdout, BLUE "[server] Client (%s) disconnected\n" RESET, ip);
+ CWS_LOG_INFO("[server] Client (%s) disconnected", ip);
cws_server_close_client(epfd, client_fd, clients);
cws_http_free(request);
@@ -150,7 +154,7 @@ void cws_server_loop(int sockfd) {
close(epfd);
cws_server_close_all_fds(clients);
cws_hm_free(clients);
- fprintf(stdout, BLUE "[server] Closing...\n" RESET);
+ CWS_LOG_INFO("[server] Closing...");
}
void cws_epoll_add(int epfd, int sockfd, uint32_t events) {
@@ -160,7 +164,7 @@ void cws_epoll_add(int epfd, int sockfd, uint32_t events) {
const int status = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
if (status != 0) {
- fprintf(stderr, RED BOLD "[server] epoll_ctl_add(): %s\n" RESET, strerror(errno));
+ CWS_LOG_ERROR("[server] epoll_ctl_add(): %s", strerror(errno));
exit(EXIT_FAILURE);
}
}
@@ -169,7 +173,7 @@ void cws_epoll_del(int epfd, int sockfd) {
const int status = epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
if (status != 0) {
- fprintf(stdout, RED BOLD "[server] epoll_ctl_del(): %s\n" RESET, strerror(errno));
+ CWS_LOG_ERROR("[server] epoll_ctl_del(): %s", strerror(errno));
exit(EXIT_FAILURE);
}
}
@@ -178,7 +182,7 @@ void cws_fd_set_nonblocking(int sockfd) {
const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (status == -1) {
- fprintf(stderr, RED BOLD "[server] fcntl(): %s\n" RESET, gai_strerror(status));
+ CWS_LOG_ERROR("[server] fcntl(): %s", gai_strerror(status));
exit(EXIT_FAILURE);
}
}
@@ -188,7 +192,7 @@ int cws_server_accept_client(int sockfd, struct sockaddr_storage *their_sa, sock
if (client_fd == -1) {
if (errno != EWOULDBLOCK) {
- fprintf(stderr, RED BOLD "[server] accept(): %s\n" RESET, strerror(errno));
+ CWS_LOG_ERROR("[server] accept(): %s", strerror(errno));
}
return -1;
}
diff --git a/src/utils/utils.c b/src/utils/utils.c
index fc3880e..b9aa4a4 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -17,7 +17,7 @@ void cws_utils_print_ips(const char *hostname, const char *port) {
int status = getaddrinfo(hostname, port, &ai, &res);
if (status < 0) {
- fprintf(stderr, RED "getaddrinfo(): %s\n" RESET, gai_strerror(status));
+ CWS_LOG_ERROR("getaddrinfo(): %s", gai_strerror(status));
exit(1);
}
@@ -28,11 +28,11 @@ void cws_utils_print_ips(const char *hostname, const char *port) {
if (p->ai_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ai_addr;
inet_ntop(AF_INET, &sin->sin_addr, ipv4, INET_ADDRSTRLEN);
- fprintf(stdout, BLUE "%s\n" RESET, ipv4);
+ CWS_LOG_INFO("%s", ipv4);
} else if (p->ai_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)p->ai_addr;
inet_ntop(AF_INET6, &sin6->sin6_addr, ipv6, INET6_ADDRSTRLEN);
- fprintf(stdout, BLUE "%s\n" RESET, ipv6);
+ CWS_LOG_INFO("%s", ipv6);
}
}