Fix windows compilation errors

This commit is contained in:
2025-07-21 12:06:23 +02:00
parent acf4746611
commit 5cb3977c3c
14 changed files with 286 additions and 227 deletions
+3 -1
View File
@@ -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
+3 -2
View File
@@ -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?
+132 -107
View File
@@ -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)
+5 -2
View File
@@ -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);
+1 -1
View File
@@ -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]);
}
+1 -1
View File
@@ -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"));
+1 -1
View File
@@ -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:
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);