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