Fix windows compilation errors
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -I. -Wall -Wextra -O0 -g3
|
||||
LFLAGS = -lssl -lcrypto
|
||||
LFLAGS =
|
||||
AR = ar
|
||||
|
||||
CFILES = $(shell find src -name "*.c")
|
||||
@@ -15,8 +15,10 @@ STATIC_LIB = lib$(LIBNAME).a
|
||||
# Detect OS and set executable extension
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXT = .exe
|
||||
LFLAGS = -lws2_32
|
||||
else
|
||||
EXT = .out
|
||||
LFLAGS += -lssl -lcrypto
|
||||
endif
|
||||
|
||||
# Installation directories
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Allow no TLS builds
|
||||
make sure no TLS builds work on windows
|
||||
Allow resolving requests from different threads
|
||||
Find a way to make sure http.h and http.c are always up to date
|
||||
Find a way to make sure chttp.h and chttp.c are always up to date
|
||||
parse Transfer-Encoding
|
||||
Make it cross-platform
|
||||
Find a way to compile OpenSSL on windows
|
||||
@@ -9,4 +9,5 @@ handle 3xx client redirections
|
||||
add discussion on string management
|
||||
add discussion on error management
|
||||
check that virtual hosts over HTTPS work
|
||||
add examples for the router
|
||||
add examples for the router
|
||||
what is client-side SNI? Do we need it?
|
||||
@@ -62,6 +62,27 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#define SOCKET_TYPE SOCKET
|
||||
#define BAD_SOCKET INVALID_SOCKET
|
||||
#define POLL WSAPoll
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#define SOCKET_TYPE int
|
||||
#define BAD_SOCKET -1
|
||||
#define POLL poll
|
||||
#define CLOSE_SOCKET close
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HTTPS_ENABLED
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -100,7 +121,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
SocketState state;
|
||||
SocketWantEvent event;
|
||||
int fd;
|
||||
SOCKET_TYPE fd;
|
||||
#if HTTPS_ENABLED
|
||||
SSL *ssl;
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -128,6 +149,9 @@ typedef struct {
|
||||
#endif
|
||||
} SocketGroup;
|
||||
|
||||
SOCKET_TYPE listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog);
|
||||
|
||||
|
||||
void socket_global_init (void);
|
||||
void socket_global_free (void);
|
||||
int socket_group_init (SocketGroup *group);
|
||||
@@ -135,7 +159,7 @@ int socket_group_init_server(SocketGroup *group, HTTP_String cert_file,
|
||||
int socket_group_add_domain(SocketGroup *group, HTTP_String domain, HTTP_String cert_key, HTTP_String private_key);
|
||||
void socket_group_free (SocketGroup *group);
|
||||
SocketState socket_state (Socket *sock);
|
||||
void socket_accept (Socket *sock, SocketGroup *group, int fd);
|
||||
void socket_accept (Socket *sock, SocketGroup *group, SOCKET_TYPE fd);
|
||||
void socket_connect (Socket *sock, SocketGroup *group, HTTP_String host, uint16_t port);
|
||||
void socket_connect_ipv4 (Socket *sock, SocketGroup *group, HTTP_IPv4 addr, uint16_t port);
|
||||
void socket_connect_ipv6 (Socket *sock, SocketGroup *group, HTTP_IPv6 addr, uint16_t port);
|
||||
@@ -2491,11 +2515,15 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define POLL WSAPoll
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <poll.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#define POLL poll
|
||||
#endif
|
||||
|
||||
#ifdef HTTPS_ENABLED
|
||||
@@ -2511,6 +2539,71 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
|
||||
#include "socket.h"
|
||||
#endif
|
||||
|
||||
static int set_socket_blocking(SOCKET_TYPE sock, bool value)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long mode = !value;
|
||||
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
int flags = fcntl(listen_fd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return -1;
|
||||
if (fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
return BAD_SOCKET;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SOCKET_TYPE listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog)
|
||||
{
|
||||
SOCKET_TYPE listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd == BAD_SOCKET)
|
||||
return BAD_SOCKET;
|
||||
|
||||
if (set_socket_blocking(listen_fd, false) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (reuse_addr) {
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
|
||||
}
|
||||
|
||||
struct in_addr addr_buf;
|
||||
if (addr.len == 0)
|
||||
addr_buf.s_addr = htonl(INADDR_ANY);
|
||||
else {
|
||||
|
||||
_Static_assert(sizeof(struct in_addr) == sizeof(HTTP_IPv4));
|
||||
if (http_parse_ipv4(addr.ptr, addr.len, (HTTP_IPv4*) &addr_buf) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in bind_buf;
|
||||
bind_buf.sin_family = AF_INET;
|
||||
bind_buf.sin_addr = addr_buf;
|
||||
bind_buf.sin_port = htons(port);
|
||||
if (bind(listen_fd, (struct sockaddr*) &bind_buf, sizeof(bind_buf)) < 0) { // TODO: how does bind fail on windows?
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (listen(listen_fd, backlog) < 0) { // TODO: how does listen fail on windows?
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
|
||||
void socket_global_init(void)
|
||||
{
|
||||
#ifdef HTTPS_ENABLED
|
||||
@@ -2764,7 +2857,7 @@ SocketState socket_state(Socket *sock)
|
||||
return sock->state;
|
||||
}
|
||||
|
||||
void socket_accept(Socket *sock, SocketGroup *group, int fd)
|
||||
void socket_accept(Socket *sock, SocketGroup *group, SOCKET_TYPE fd)
|
||||
{
|
||||
#ifdef HTTPS_ENABLED
|
||||
sock->ssl = NULL;
|
||||
@@ -2785,13 +2878,12 @@ void socket_accept(Socket *sock, SocketGroup *group, int fd)
|
||||
sock->addr_cursor = 0;
|
||||
sock->hostname = NULL;
|
||||
sock->port = 0;
|
||||
|
||||
// Set non-blocking mode for the accepted socket
|
||||
int flags = fcntl(fd, F_GETFL, 0); // TODO: fail on error
|
||||
if (flags >= 0) {
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
if (set_socket_blocking(fd, false) < 0) {
|
||||
sock->state = SOCKET_STATE_DIED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Start the TLS handshake process
|
||||
socket_update(sock);
|
||||
}
|
||||
@@ -2946,8 +3038,8 @@ void socket_update(Socket *sock)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sock->fd != -1)
|
||||
close(sock->fd);
|
||||
if (sock->fd != BAD_SOCKET)
|
||||
CLOSE_SOCKET(sock->fd);
|
||||
|
||||
// If cursor reached the end, die
|
||||
if (sock->addr_cursor >= sock->addr_count) {
|
||||
@@ -2959,8 +3051,8 @@ void socket_update(Socket *sock)
|
||||
// Take current address
|
||||
AddrInfo *ai = &sock->addr_list[sock->addr_cursor];
|
||||
int family = ai->is_ipv6 ? AF_INET6 : AF_INET;
|
||||
int fd = socket(family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
SOCKET_TYPE fd = socket(family, SOCK_STREAM, 0);
|
||||
if (fd == BAD_SOCKET) {
|
||||
// Try next address
|
||||
sock->addr_cursor++;
|
||||
sock->event = SOCKET_WANT_NONE;
|
||||
@@ -2969,9 +3061,12 @@ void socket_update(Socket *sock)
|
||||
break;
|
||||
}
|
||||
|
||||
// Set non-blocking
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags >= 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK); // TODO: Handle error by setting the socket to DIED
|
||||
if (set_socket_blocking(fd, false) < 0) {
|
||||
CLOSE_SOCKET(fd);
|
||||
sock->event = SOCKET_WANT_NONE;
|
||||
sock->state = SOCKET_STATE_DIED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Prepare sockaddr
|
||||
int ret;
|
||||
@@ -2998,7 +3093,7 @@ void socket_update(Socket *sock)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0 && errno == EINPROGRESS) {
|
||||
if (ret < 0 && errno == EINPROGRESS) { // TODO: I'm pretty sure all the error numbers need to be changed for windows
|
||||
// Connection pending
|
||||
sock->fd = fd;
|
||||
sock->event = SOCKET_WANT_WRITE;
|
||||
@@ -3025,7 +3120,7 @@ void socket_update(Socket *sock)
|
||||
// Check connect result
|
||||
int err = 0;
|
||||
socklen_t len = sizeof(err);
|
||||
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0 || err != 0) {
|
||||
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0 || err != 0) {
|
||||
close(sock->fd);
|
||||
// If remote peer not working, try next address
|
||||
if (err == ECONNREFUSED || err == ETIMEDOUT || err == ENETUNREACH || err == EHOSTUNREACH) {
|
||||
@@ -3302,9 +3397,9 @@ void socket_free(Socket *sock)
|
||||
SSL_free(sock->ssl);
|
||||
#endif
|
||||
|
||||
if (sock->fd >= 0) {
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
if (sock->fd != BAD_SOCKET) {
|
||||
CLOSE_SOCKET(sock->fd);
|
||||
sock->fd = BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (sock->hostname) {
|
||||
@@ -3344,7 +3439,7 @@ int socket_wait(Socket **socks, int num_socks) // TODO: is this used?
|
||||
polled[i].revents = 0;
|
||||
}
|
||||
|
||||
int ret = poll(polled, num_socks, -1);
|
||||
int ret = POLL(polled, num_socks, -1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
@@ -3842,23 +3937,6 @@ HTTP_Response *http_post(HTTP_String url, HTTP_String *headers, int num_headers,
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#define POLL WSAPoll
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#define POLL poll
|
||||
#define CLOSE_SOCKET close
|
||||
#endif
|
||||
|
||||
#ifndef HTTP_AMALGAMATION
|
||||
#include "engine.h"
|
||||
#include "socket.h"
|
||||
@@ -3877,8 +3955,8 @@ typedef struct {
|
||||
struct HTTP_Server {
|
||||
SocketGroup group;
|
||||
|
||||
int listen_fd;
|
||||
int secure_fd;
|
||||
SOCKET_TYPE listen_fd;
|
||||
SOCKET_TYPE secure_fd;
|
||||
|
||||
int num_conns;
|
||||
Connection conns[MAX_CONNS];
|
||||
@@ -3888,59 +3966,6 @@ struct HTTP_Server {
|
||||
int ready[MAX_CONNS];
|
||||
};
|
||||
|
||||
static int listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog)
|
||||
{
|
||||
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0)
|
||||
return -1;
|
||||
|
||||
{
|
||||
int flags = fcntl(listen_fd, F_GETFL, 0);
|
||||
if (flags < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (reuse_addr) {
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
}
|
||||
|
||||
struct in_addr addr_buf;
|
||||
if (addr.len == 0)
|
||||
addr_buf.s_addr = htonl(INADDR_ANY);
|
||||
else {
|
||||
|
||||
_Static_assert(sizeof(struct in_addr) == sizeof(HTTP_IPv4));
|
||||
if (http_parse_ipv4(addr.ptr, addr.len, (HTTP_IPv4*) &addr_buf) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in bind_buf;
|
||||
bind_buf.sin_family = AF_INET;
|
||||
bind_buf.sin_addr = addr_buf;
|
||||
bind_buf.sin_port = htons(port);
|
||||
if (bind(listen_fd, (struct sockaddr*) &bind_buf, sizeof(bind_buf)) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(listen_fd, backlog) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
HTTP_Server *http_server_init(HTTP_String addr, uint16_t port)
|
||||
{
|
||||
return http_server_init_ex(addr, port, 0, HTTP_STR(""), HTTP_STR(""));
|
||||
@@ -3963,17 +3988,17 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
server->listen_fd = -1;
|
||||
server->listen_fd = BAD_SOCKET;
|
||||
else {
|
||||
server->listen_fd = listen_socket(addr, port, reuse_addr, backlog);
|
||||
if (server->listen_fd < 0) {
|
||||
if (server->listen_fd == BAD_SOCKET) {
|
||||
free(server);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (secure_port == 0)
|
||||
server->secure_fd = -1;
|
||||
server->secure_fd = BAD_SOCKET;
|
||||
else {
|
||||
|
||||
if (socket_group_init_server(&server->group, cert_key, private_key) < 0) {
|
||||
@@ -3983,7 +4008,7 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
|
||||
}
|
||||
|
||||
server->secure_fd = listen_socket(addr, secure_port, reuse_addr, backlog);
|
||||
if (server->secure_fd < 0) {
|
||||
if (server->secure_fd == BAD_SOCKET) {
|
||||
socket_group_free(&server->group);
|
||||
CLOSE_SOCKET(server->listen_fd);
|
||||
free(server);
|
||||
@@ -4016,7 +4041,7 @@ void http_server_free(HTTP_Server *server)
|
||||
|
||||
CLOSE_SOCKET(server->secure_fd);
|
||||
CLOSE_SOCKET(server->listen_fd);
|
||||
if (server->secure_fd != -1)
|
||||
if (server->secure_fd != BAD_SOCKET)
|
||||
socket_group_free(&server->group);
|
||||
free(server);
|
||||
}
|
||||
@@ -4048,7 +4073,7 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
|
||||
if (server->num_conns < MAX_CONNS) {
|
||||
|
||||
if (server->listen_fd != -1) {
|
||||
if (server->listen_fd != BAD_SOCKET) {
|
||||
polled[num_polled].fd = server->listen_fd;
|
||||
polled[num_polled].events = POLLIN;
|
||||
polled[num_polled].revents = 0;
|
||||
@@ -4056,7 +4081,7 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
num_polled++;
|
||||
}
|
||||
|
||||
if (server->secure_fd != -1) {
|
||||
if (server->secure_fd != BAD_SOCKET) {
|
||||
polled[num_polled].fd = server->secure_fd;
|
||||
polled[num_polled].events = POLLIN;
|
||||
polled[num_polled].revents = 0;
|
||||
@@ -4102,7 +4127,10 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
|
||||
if ((polled[i].revents & POLLIN) && server->num_conns < MAX_CONNS) {
|
||||
|
||||
int new_fd = accept(polled[i].fd, NULL, NULL);
|
||||
SOCKET_TYPE new_fd = accept(polled[i].fd, NULL, NULL);
|
||||
if (new_fd == BAD_SOCKET) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int k = 0;
|
||||
while (server->conns[k].used)
|
||||
@@ -4211,16 +4239,13 @@ void http_response_status(HTTP_ResponseHandle res, int status)
|
||||
http_engine_status(&conn->engine, status);
|
||||
}
|
||||
|
||||
void http_response_header(HTTP_ResponseHandle res, const char *fmt, ...)
|
||||
void http_response_header(HTTP_ResponseHandle res, HTTP_String str)
|
||||
{
|
||||
Connection *conn = handle2conn(res);
|
||||
if (conn == NULL)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
http_engine_header_fmt2(&conn->engine, fmt, args);
|
||||
va_end(args);
|
||||
http_engine_header(&conn->engine, str);
|
||||
}
|
||||
|
||||
void http_response_body(HTTP_ResponseHandle res, HTTP_String str)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// String type used throughout cHTTP.
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
long len;
|
||||
int len;
|
||||
} HTTP_String;
|
||||
|
||||
// Compare two strings and return true iff they have
|
||||
@@ -33,6 +33,9 @@ bool http_streqcase(HTTP_String s1, HTTP_String s2);
|
||||
// the new one references the contents of the original one.
|
||||
HTTP_String http_trim(HTTP_String s);
|
||||
|
||||
// TODO: comment
|
||||
void print_bytes(HTTP_String prefix, HTTP_String src);
|
||||
|
||||
// Macro to simplify converting string literals to
|
||||
// HTTP_String.
|
||||
//
|
||||
@@ -491,7 +494,7 @@ void http_server_free (HTTP_Server *server);
|
||||
int http_server_wait (HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandle *handle);
|
||||
int http_server_add_website (HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file);
|
||||
void http_response_status (HTTP_ResponseHandle res, int status);
|
||||
void http_response_header (HTTP_ResponseHandle res, const char *fmt, ...);
|
||||
void http_response_header (HTTP_ResponseHandle res, HTTP_String str);
|
||||
void http_response_body (HTTP_ResponseHandle res, HTTP_String str);
|
||||
void http_response_bodycap (HTTP_ResponseHandle res, int mincap);
|
||||
char* http_response_bodybuf (HTTP_ResponseHandle res, int *cap);
|
||||
|
||||
@@ -207,7 +207,7 @@ int main(void)
|
||||
// See blocking_server_with_engine.c to learn about how to
|
||||
// build a response
|
||||
http_engine_status(&engs[key], 200);
|
||||
http_engine_body(&engs[key], "Hello, world!", -1);
|
||||
http_engine_body(&engs[key], HTTP_STR("Hello, world!"));
|
||||
http_engine_done(&engs[key]);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ int main(void)
|
||||
http_response_status(res, 200);
|
||||
|
||||
// Then zero or more headers
|
||||
http_response_header(res, "Content-Type: text/plain");
|
||||
http_response_header(res, HTTP_STR("Content-Type: text/plain"));
|
||||
|
||||
// Then you can write zero or more chunks of the response body
|
||||
http_response_body(res, HTTP_STR("Hello"));
|
||||
|
||||
@@ -23,7 +23,7 @@ int main(void)
|
||||
if (ret < 0) return -1;
|
||||
|
||||
http_response_status(res, 200);
|
||||
http_response_header(res, "Content-Type: text/plain");
|
||||
http_response_header(res, HTTP_STR("Content-Type: text/plain"));
|
||||
|
||||
// The previous example used the *_body function to
|
||||
// write the response body in chunks:
|
||||
|
||||
@@ -21,7 +21,7 @@ int main(void)
|
||||
// Say we are building a request..
|
||||
|
||||
http_response_status(res, 200);
|
||||
http_response_header(res, "Content-Type: text/plain");
|
||||
http_response_header(res, HTTP_STR("Content-Type: text/plain"));
|
||||
|
||||
// .. and in the middle of building an error condition
|
||||
// occurs. Maybe a file was missing or an allocation fails.
|
||||
@@ -39,7 +39,7 @@ int main(void)
|
||||
|
||||
// Now we are back to setting the status code
|
||||
http_response_status(res, 500);
|
||||
http_response_header(res, "Content-Type: text/plain");
|
||||
http_response_header(res, HTTP_STR("Content-Type: text/plain"));
|
||||
http_response_body(res, HTTP_STR("An error occurred!"));
|
||||
http_response_done(res);
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ int main(void)
|
||||
if (ret < 0) return -1;
|
||||
|
||||
http_response_status(res, 200);
|
||||
http_response_header(res, "Content-Type: text/plain");
|
||||
http_response_header(res, HTTP_STR("Content-Type: text/plain"));
|
||||
http_response_body(res, HTTP_STR("Hello"));
|
||||
http_response_body(res, HTTP_STR(", world!"));
|
||||
http_response_done(res);
|
||||
|
||||
+4
-1
@@ -6,7 +6,7 @@
|
||||
// String type used throughout cHTTP.
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
long len;
|
||||
int len;
|
||||
} HTTP_String;
|
||||
|
||||
// Compare two strings and return true iff they have
|
||||
@@ -23,6 +23,9 @@ bool http_streqcase(HTTP_String s1, HTTP_String s2);
|
||||
// the new one references the contents of the original one.
|
||||
HTTP_String http_trim(HTTP_String s);
|
||||
|
||||
// TODO: comment
|
||||
void print_bytes(HTTP_String prefix, HTTP_String src);
|
||||
|
||||
// Macro to simplify converting string literals to
|
||||
// HTTP_String.
|
||||
//
|
||||
|
||||
+15
-85
@@ -3,23 +3,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#define POLL WSAPoll
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#define POLL poll
|
||||
#define CLOSE_SOCKET close
|
||||
#endif
|
||||
|
||||
#ifndef HTTP_AMALGAMATION
|
||||
#include "engine.h"
|
||||
#include "socket.h"
|
||||
@@ -38,8 +21,8 @@ typedef struct {
|
||||
struct HTTP_Server {
|
||||
SocketGroup group;
|
||||
|
||||
int listen_fd;
|
||||
int secure_fd;
|
||||
SOCKET_TYPE listen_fd;
|
||||
SOCKET_TYPE secure_fd;
|
||||
|
||||
int num_conns;
|
||||
Connection conns[MAX_CONNS];
|
||||
@@ -49,59 +32,6 @@ struct HTTP_Server {
|
||||
int ready[MAX_CONNS];
|
||||
};
|
||||
|
||||
static int listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog)
|
||||
{
|
||||
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0)
|
||||
return -1;
|
||||
|
||||
{
|
||||
int flags = fcntl(listen_fd, F_GETFL, 0);
|
||||
if (flags < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (reuse_addr) {
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
}
|
||||
|
||||
struct in_addr addr_buf;
|
||||
if (addr.len == 0)
|
||||
addr_buf.s_addr = htonl(INADDR_ANY);
|
||||
else {
|
||||
|
||||
_Static_assert(sizeof(struct in_addr) == sizeof(HTTP_IPv4));
|
||||
if (http_parse_ipv4(addr.ptr, addr.len, (HTTP_IPv4*) &addr_buf) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in bind_buf;
|
||||
bind_buf.sin_family = AF_INET;
|
||||
bind_buf.sin_addr = addr_buf;
|
||||
bind_buf.sin_port = htons(port);
|
||||
if (bind(listen_fd, (struct sockaddr*) &bind_buf, sizeof(bind_buf)) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(listen_fd, backlog) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
HTTP_Server *http_server_init(HTTP_String addr, uint16_t port)
|
||||
{
|
||||
return http_server_init_ex(addr, port, 0, HTTP_STR(""), HTTP_STR(""));
|
||||
@@ -124,17 +54,17 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
server->listen_fd = -1;
|
||||
server->listen_fd = BAD_SOCKET;
|
||||
else {
|
||||
server->listen_fd = listen_socket(addr, port, reuse_addr, backlog);
|
||||
if (server->listen_fd < 0) {
|
||||
if (server->listen_fd == BAD_SOCKET) {
|
||||
free(server);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (secure_port == 0)
|
||||
server->secure_fd = -1;
|
||||
server->secure_fd = BAD_SOCKET;
|
||||
else {
|
||||
|
||||
if (socket_group_init_server(&server->group, cert_key, private_key) < 0) {
|
||||
@@ -144,7 +74,7 @@ HTTP_Server *http_server_init_ex(HTTP_String addr, uint16_t port,
|
||||
}
|
||||
|
||||
server->secure_fd = listen_socket(addr, secure_port, reuse_addr, backlog);
|
||||
if (server->secure_fd < 0) {
|
||||
if (server->secure_fd == BAD_SOCKET) {
|
||||
socket_group_free(&server->group);
|
||||
CLOSE_SOCKET(server->listen_fd);
|
||||
free(server);
|
||||
@@ -177,7 +107,7 @@ void http_server_free(HTTP_Server *server)
|
||||
|
||||
CLOSE_SOCKET(server->secure_fd);
|
||||
CLOSE_SOCKET(server->listen_fd);
|
||||
if (server->secure_fd != -1)
|
||||
if (server->secure_fd != BAD_SOCKET)
|
||||
socket_group_free(&server->group);
|
||||
free(server);
|
||||
}
|
||||
@@ -209,7 +139,7 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
|
||||
if (server->num_conns < MAX_CONNS) {
|
||||
|
||||
if (server->listen_fd != -1) {
|
||||
if (server->listen_fd != BAD_SOCKET) {
|
||||
polled[num_polled].fd = server->listen_fd;
|
||||
polled[num_polled].events = POLLIN;
|
||||
polled[num_polled].revents = 0;
|
||||
@@ -217,7 +147,7 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
num_polled++;
|
||||
}
|
||||
|
||||
if (server->secure_fd != -1) {
|
||||
if (server->secure_fd != BAD_SOCKET) {
|
||||
polled[num_polled].fd = server->secure_fd;
|
||||
polled[num_polled].events = POLLIN;
|
||||
polled[num_polled].revents = 0;
|
||||
@@ -263,7 +193,10 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandl
|
||||
|
||||
if ((polled[i].revents & POLLIN) && server->num_conns < MAX_CONNS) {
|
||||
|
||||
int new_fd = accept(polled[i].fd, NULL, NULL);
|
||||
SOCKET_TYPE new_fd = accept(polled[i].fd, NULL, NULL);
|
||||
if (new_fd == BAD_SOCKET) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int k = 0;
|
||||
while (server->conns[k].used)
|
||||
@@ -372,16 +305,13 @@ void http_response_status(HTTP_ResponseHandle res, int status)
|
||||
http_engine_status(&conn->engine, status);
|
||||
}
|
||||
|
||||
void http_response_header(HTTP_ResponseHandle res, const char *fmt, ...)
|
||||
void http_response_header(HTTP_ResponseHandle res, HTTP_String str)
|
||||
{
|
||||
Connection *conn = handle2conn(res);
|
||||
if (conn == NULL)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
http_engine_header_fmt2(&conn->engine, fmt, args);
|
||||
va_end(args);
|
||||
http_engine_header(&conn->engine, str);
|
||||
}
|
||||
|
||||
void http_response_body(HTTP_ResponseHandle res, HTTP_String str)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ void http_server_free (HTTP_Server *server);
|
||||
int http_server_wait (HTTP_Server *server, HTTP_Request **req, HTTP_ResponseHandle *handle);
|
||||
int http_server_add_website (HTTP_Server *server, HTTP_String domain, HTTP_String cert_file, HTTP_String key_file);
|
||||
void http_response_status (HTTP_ResponseHandle res, int status);
|
||||
void http_response_header (HTTP_ResponseHandle res, const char *fmt, ...);
|
||||
void http_response_header (HTTP_ResponseHandle res, HTTP_String str);
|
||||
void http_response_body (HTTP_ResponseHandle res, HTTP_String str);
|
||||
void http_response_bodycap (HTTP_ResponseHandle res, int mincap);
|
||||
char* http_response_bodybuf (HTTP_ResponseHandle res, int *cap);
|
||||
|
||||
+91
-20
@@ -9,11 +9,15 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define POLL WSAPoll
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <poll.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#define POLL poll
|
||||
#endif
|
||||
|
||||
#ifdef HTTPS_ENABLED
|
||||
@@ -29,6 +33,71 @@
|
||||
#include "socket.h"
|
||||
#endif
|
||||
|
||||
static int set_socket_blocking(SOCKET_TYPE sock, bool value)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long mode = !value;
|
||||
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
int flags = fcntl(listen_fd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return -1;
|
||||
if (fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
return BAD_SOCKET;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SOCKET_TYPE listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog)
|
||||
{
|
||||
SOCKET_TYPE listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd == BAD_SOCKET)
|
||||
return BAD_SOCKET;
|
||||
|
||||
if (set_socket_blocking(listen_fd, false) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (reuse_addr) {
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
|
||||
}
|
||||
|
||||
struct in_addr addr_buf;
|
||||
if (addr.len == 0)
|
||||
addr_buf.s_addr = htonl(INADDR_ANY);
|
||||
else {
|
||||
|
||||
_Static_assert(sizeof(struct in_addr) == sizeof(HTTP_IPv4));
|
||||
if (http_parse_ipv4(addr.ptr, addr.len, (HTTP_IPv4*) &addr_buf) < 0) {
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in bind_buf;
|
||||
bind_buf.sin_family = AF_INET;
|
||||
bind_buf.sin_addr = addr_buf;
|
||||
bind_buf.sin_port = htons(port);
|
||||
if (bind(listen_fd, (struct sockaddr*) &bind_buf, sizeof(bind_buf)) < 0) { // TODO: how does bind fail on windows?
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (listen(listen_fd, backlog) < 0) { // TODO: how does listen fail on windows?
|
||||
CLOSE_SOCKET(listen_fd);
|
||||
return BAD_SOCKET;
|
||||
}
|
||||
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
|
||||
void socket_global_init(void)
|
||||
{
|
||||
#ifdef HTTPS_ENABLED
|
||||
@@ -282,7 +351,7 @@ SocketState socket_state(Socket *sock)
|
||||
return sock->state;
|
||||
}
|
||||
|
||||
void socket_accept(Socket *sock, SocketGroup *group, int fd)
|
||||
void socket_accept(Socket *sock, SocketGroup *group, SOCKET_TYPE fd)
|
||||
{
|
||||
#ifdef HTTPS_ENABLED
|
||||
sock->ssl = NULL;
|
||||
@@ -303,13 +372,12 @@ void socket_accept(Socket *sock, SocketGroup *group, int fd)
|
||||
sock->addr_cursor = 0;
|
||||
sock->hostname = NULL;
|
||||
sock->port = 0;
|
||||
|
||||
// Set non-blocking mode for the accepted socket
|
||||
int flags = fcntl(fd, F_GETFL, 0); // TODO: fail on error
|
||||
if (flags >= 0) {
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
if (set_socket_blocking(fd, false) < 0) {
|
||||
sock->state = SOCKET_STATE_DIED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Start the TLS handshake process
|
||||
socket_update(sock);
|
||||
}
|
||||
@@ -464,8 +532,8 @@ void socket_update(Socket *sock)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sock->fd != -1)
|
||||
close(sock->fd);
|
||||
if (sock->fd != BAD_SOCKET)
|
||||
CLOSE_SOCKET(sock->fd);
|
||||
|
||||
// If cursor reached the end, die
|
||||
if (sock->addr_cursor >= sock->addr_count) {
|
||||
@@ -477,8 +545,8 @@ void socket_update(Socket *sock)
|
||||
// Take current address
|
||||
AddrInfo *ai = &sock->addr_list[sock->addr_cursor];
|
||||
int family = ai->is_ipv6 ? AF_INET6 : AF_INET;
|
||||
int fd = socket(family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
SOCKET_TYPE fd = socket(family, SOCK_STREAM, 0);
|
||||
if (fd == BAD_SOCKET) {
|
||||
// Try next address
|
||||
sock->addr_cursor++;
|
||||
sock->event = SOCKET_WANT_NONE;
|
||||
@@ -487,9 +555,12 @@ void socket_update(Socket *sock)
|
||||
break;
|
||||
}
|
||||
|
||||
// Set non-blocking
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags >= 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK); // TODO: Handle error by setting the socket to DIED
|
||||
if (set_socket_blocking(fd, false) < 0) {
|
||||
CLOSE_SOCKET(fd);
|
||||
sock->event = SOCKET_WANT_NONE;
|
||||
sock->state = SOCKET_STATE_DIED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Prepare sockaddr
|
||||
int ret;
|
||||
@@ -516,7 +587,7 @@ void socket_update(Socket *sock)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0 && errno == EINPROGRESS) {
|
||||
if (ret < 0 && errno == EINPROGRESS) { // TODO: I'm pretty sure all the error numbers need to be changed for windows
|
||||
// Connection pending
|
||||
sock->fd = fd;
|
||||
sock->event = SOCKET_WANT_WRITE;
|
||||
@@ -543,7 +614,7 @@ void socket_update(Socket *sock)
|
||||
// Check connect result
|
||||
int err = 0;
|
||||
socklen_t len = sizeof(err);
|
||||
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0 || err != 0) {
|
||||
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0 || err != 0) {
|
||||
close(sock->fd);
|
||||
// If remote peer not working, try next address
|
||||
if (err == ECONNREFUSED || err == ETIMEDOUT || err == ENETUNREACH || err == EHOSTUNREACH) {
|
||||
@@ -820,9 +891,9 @@ void socket_free(Socket *sock)
|
||||
SSL_free(sock->ssl);
|
||||
#endif
|
||||
|
||||
if (sock->fd >= 0) {
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
if (sock->fd != BAD_SOCKET) {
|
||||
CLOSE_SOCKET(sock->fd);
|
||||
sock->fd = BAD_SOCKET;
|
||||
}
|
||||
|
||||
if (sock->hostname) {
|
||||
@@ -862,7 +933,7 @@ int socket_wait(Socket **socks, int num_socks) // TODO: is this used?
|
||||
polled[i].revents = 0;
|
||||
}
|
||||
|
||||
int ret = poll(polled, num_socks, -1);
|
||||
int ret = POLL(polled, num_socks, -1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
+26
-2
@@ -55,6 +55,27 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#define SOCKET_TYPE SOCKET
|
||||
#define BAD_SOCKET INVALID_SOCKET
|
||||
#define POLL WSAPoll
|
||||
#define CLOSE_SOCKET closesocket
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#define SOCKET_TYPE int
|
||||
#define BAD_SOCKET -1
|
||||
#define POLL poll
|
||||
#define CLOSE_SOCKET close
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HTTPS_ENABLED
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -93,7 +114,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
SocketState state;
|
||||
SocketWantEvent event;
|
||||
int fd;
|
||||
SOCKET_TYPE fd;
|
||||
#if HTTPS_ENABLED
|
||||
SSL *ssl;
|
||||
SSL_CTX *ssl_ctx;
|
||||
@@ -121,6 +142,9 @@ typedef struct {
|
||||
#endif
|
||||
} SocketGroup;
|
||||
|
||||
SOCKET_TYPE listen_socket(HTTP_String addr, uint16_t port, bool reuse_addr, int backlog);
|
||||
|
||||
|
||||
void socket_global_init (void);
|
||||
void socket_global_free (void);
|
||||
int socket_group_init (SocketGroup *group);
|
||||
@@ -128,7 +152,7 @@ int socket_group_init_server(SocketGroup *group, HTTP_String cert_file,
|
||||
int socket_group_add_domain(SocketGroup *group, HTTP_String domain, HTTP_String cert_key, HTTP_String private_key);
|
||||
void socket_group_free (SocketGroup *group);
|
||||
SocketState socket_state (Socket *sock);
|
||||
void socket_accept (Socket *sock, SocketGroup *group, int fd);
|
||||
void socket_accept (Socket *sock, SocketGroup *group, SOCKET_TYPE fd);
|
||||
void socket_connect (Socket *sock, SocketGroup *group, HTTP_String host, uint16_t port);
|
||||
void socket_connect_ipv4 (Socket *sock, SocketGroup *group, HTTP_IPv4 addr, uint16_t port);
|
||||
void socket_connect_ipv6 (Socket *sock, SocketGroup *group, HTTP_IPv6 addr, uint16_t port);
|
||||
|
||||
Reference in New Issue
Block a user