Fix more compilation errors
This commit is contained in:
@@ -6,7 +6,7 @@ chttp.c chttp.h: $(wildcard src/*.c src/*.h) misc/amalg.py Makefile
|
|||||||
python misc/amalg.py
|
python misc/amalg.py
|
||||||
|
|
||||||
example: main.c chttp.c chttp.h
|
example: main.c chttp.c chttp.h
|
||||||
gcc main.c chttp.c -o example.exe
|
gcc main.c chttp.c -o example.exe -Wfatal-errors
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm chttp.c chttp.h
|
rm chttp.c chttp.h
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -82,6 +84,120 @@ void print_bytes(HTTP_String prefix, HTTP_String src);
|
|||||||
// TODO: comment
|
// TODO: comment
|
||||||
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// src/parse.h
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define HTTP_MAX_HEADERS 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int data;
|
||||||
|
} HTTP_IPv4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short data[8];
|
||||||
|
} HTTP_IPv6;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HTTP_HOST_MODE_VOID = 0,
|
||||||
|
HTTP_HOST_MODE_NAME,
|
||||||
|
HTTP_HOST_MODE_IPV4,
|
||||||
|
HTTP_HOST_MODE_IPV6,
|
||||||
|
} HTTP_HostMode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HTTP_HostMode mode;
|
||||||
|
HTTP_String text;
|
||||||
|
union {
|
||||||
|
HTTP_String name;
|
||||||
|
HTTP_IPv4 ipv4;
|
||||||
|
HTTP_IPv6 ipv6;
|
||||||
|
};
|
||||||
|
} HTTP_Host;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HTTP_String userinfo;
|
||||||
|
HTTP_Host host;
|
||||||
|
int port;
|
||||||
|
} HTTP_Authority;
|
||||||
|
|
||||||
|
// ZII
|
||||||
|
typedef struct {
|
||||||
|
HTTP_String scheme;
|
||||||
|
HTTP_Authority authority;
|
||||||
|
HTTP_String path;
|
||||||
|
HTTP_String query;
|
||||||
|
HTTP_String fragment;
|
||||||
|
} HTTP_URL;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HTTP_METHOD_GET,
|
||||||
|
HTTP_METHOD_HEAD,
|
||||||
|
HTTP_METHOD_POST,
|
||||||
|
HTTP_METHOD_PUT,
|
||||||
|
HTTP_METHOD_DELETE,
|
||||||
|
HTTP_METHOD_CONNECT,
|
||||||
|
HTTP_METHOD_OPTIONS,
|
||||||
|
HTTP_METHOD_TRACE,
|
||||||
|
HTTP_METHOD_PATCH,
|
||||||
|
} HTTP_Method;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HTTP_String name;
|
||||||
|
HTTP_String value;
|
||||||
|
} HTTP_Header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool secure;
|
||||||
|
HTTP_Method method;
|
||||||
|
HTTP_URL url;
|
||||||
|
int minor;
|
||||||
|
int num_headers;
|
||||||
|
HTTP_Header headers[HTTP_MAX_HEADERS];
|
||||||
|
HTTP_String body;
|
||||||
|
} HTTP_Request;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void* context;
|
||||||
|
int minor;
|
||||||
|
int status;
|
||||||
|
HTTP_String reason;
|
||||||
|
int num_headers;
|
||||||
|
HTTP_Header headers[HTTP_MAX_HEADERS];
|
||||||
|
HTTP_String body;
|
||||||
|
} HTTP_Response;
|
||||||
|
|
||||||
|
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4);
|
||||||
|
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6);
|
||||||
|
int http_parse_url (char *src, int len, HTTP_URL *url);
|
||||||
|
int http_parse_request (char *src, int len, HTTP_Request *req);
|
||||||
|
int http_parse_response (char *src, int len, HTTP_Response *res);
|
||||||
|
|
||||||
|
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name);
|
||||||
|
|
||||||
|
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name);
|
||||||
|
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap);
|
||||||
|
int http_get_param_i (HTTP_String body, HTTP_String str);
|
||||||
|
|
||||||
|
// Checks whether the request was meant for the host with the given
|
||||||
|
// domain an port. If port is -1, the default value of 80 is assumed.
|
||||||
|
bool http_match_host(HTTP_Request *req, HTTP_String domain, int port);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// src/thread.h
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef CRITICAL_SECTION Mutex;
|
||||||
|
#else
|
||||||
|
typedef pthread_mutex_t Mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int mutex_init(Mutex *mutex);
|
||||||
|
int mutex_free(Mutex *mutex);
|
||||||
|
int mutex_lock(Mutex *mutex);
|
||||||
|
int mutex_unlock(Mutex *mutex);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/secure_context.h
|
// src/secure_context.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -222,10 +338,14 @@ typedef enum {
|
|||||||
// still pending.
|
// still pending.
|
||||||
SOCKET_STATE_CONNECTING,
|
SOCKET_STATE_CONNECTING,
|
||||||
|
|
||||||
// The connection was estabished, but a TLS
|
// Outgoing connection was established, but
|
||||||
// handshake may need to be performed.
|
// a TLS handshake may need to be performed.
|
||||||
SOCKET_STATE_CONNECTED,
|
SOCKET_STATE_CONNECTED,
|
||||||
|
|
||||||
|
// Incoming connection was established, but
|
||||||
|
// a TLS handshake may need to be performed.
|
||||||
|
SOCKET_STATE_ACCEPTED,
|
||||||
|
|
||||||
// The connection was esablished, but the user
|
// The connection was esablished, but the user
|
||||||
// wants to perform a read or write operation that
|
// wants to perform a read or write operation that
|
||||||
// would block.
|
// would block.
|
||||||
@@ -419,20 +539,7 @@ void socket_close(SocketManager *sm, SocketHandle handle);
|
|||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
||||||
|
|
||||||
// Set the user pointer of a socket
|
// Set the user pointer of a socket
|
||||||
void socket_set_user(SocketManager *sm, SocketHandle handle);
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// src/thread.h
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char unused; // TODO
|
|
||||||
} Mutex;
|
|
||||||
|
|
||||||
int mutex_init(Mutex *mutex);
|
|
||||||
int mutex_free(Mutex *mutex);
|
|
||||||
int mutex_lock(Mutex *mutex);
|
|
||||||
int mutex_unlock(Mutex *mutex);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/byte_queue.h
|
// src/byte_queue.h
|
||||||
@@ -714,105 +821,6 @@ bool http_client_next_response(HTTP_Client *client,
|
|||||||
// again after this.
|
// again after this.
|
||||||
void http_free_response(HTTP_Response *res);
|
void http_free_response(HTTP_Response *res);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// src/parse.h
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define HTTP_MAX_HEADERS 32
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned int data;
|
|
||||||
} HTTP_IPv4;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned short data[8];
|
|
||||||
} HTTP_IPv6;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HTTP_HOST_MODE_VOID = 0,
|
|
||||||
HTTP_HOST_MODE_NAME,
|
|
||||||
HTTP_HOST_MODE_IPV4,
|
|
||||||
HTTP_HOST_MODE_IPV6,
|
|
||||||
} HTTP_HostMode;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HTTP_HostMode mode;
|
|
||||||
HTTP_String text;
|
|
||||||
union {
|
|
||||||
HTTP_String name;
|
|
||||||
HTTP_IPv4 ipv4;
|
|
||||||
HTTP_IPv6 ipv6;
|
|
||||||
};
|
|
||||||
} HTTP_Host;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HTTP_String userinfo;
|
|
||||||
HTTP_Host host;
|
|
||||||
int port;
|
|
||||||
} HTTP_Authority;
|
|
||||||
|
|
||||||
// ZII
|
|
||||||
typedef struct {
|
|
||||||
HTTP_String scheme;
|
|
||||||
HTTP_Authority authority;
|
|
||||||
HTTP_String path;
|
|
||||||
HTTP_String query;
|
|
||||||
HTTP_String fragment;
|
|
||||||
} HTTP_URL;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HTTP_METHOD_GET,
|
|
||||||
HTTP_METHOD_HEAD,
|
|
||||||
HTTP_METHOD_POST,
|
|
||||||
HTTP_METHOD_PUT,
|
|
||||||
HTTP_METHOD_DELETE,
|
|
||||||
HTTP_METHOD_CONNECT,
|
|
||||||
HTTP_METHOD_OPTIONS,
|
|
||||||
HTTP_METHOD_TRACE,
|
|
||||||
HTTP_METHOD_PATCH,
|
|
||||||
} HTTP_Method;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HTTP_String name;
|
|
||||||
HTTP_String value;
|
|
||||||
} HTTP_Header;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool secure;
|
|
||||||
HTTP_Method method;
|
|
||||||
HTTP_URL url;
|
|
||||||
int minor;
|
|
||||||
int num_headers;
|
|
||||||
HTTP_Header headers[HTTP_MAX_HEADERS];
|
|
||||||
HTTP_String body;
|
|
||||||
} HTTP_Request;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void* context;
|
|
||||||
int minor;
|
|
||||||
int status;
|
|
||||||
HTTP_String reason;
|
|
||||||
int num_headers;
|
|
||||||
HTTP_Header headers[HTTP_MAX_HEADERS];
|
|
||||||
HTTP_String body;
|
|
||||||
} HTTP_Response;
|
|
||||||
|
|
||||||
int http_parse_ipv4 (char *src, int len, HTTP_IPv4 *ipv4);
|
|
||||||
int http_parse_ipv6 (char *src, int len, HTTP_IPv6 *ipv6);
|
|
||||||
int http_parse_url (char *src, int len, HTTP_URL *url);
|
|
||||||
int http_parse_request (char *src, int len, HTTP_Request *req);
|
|
||||||
int http_parse_response (char *src, int len, HTTP_Response *res);
|
|
||||||
|
|
||||||
int http_find_header (HTTP_Header *headers, int num_headers, HTTP_String name);
|
|
||||||
|
|
||||||
HTTP_String http_get_cookie (HTTP_Request *req, HTTP_String name);
|
|
||||||
HTTP_String http_get_param (HTTP_String body, HTTP_String str, char *mem, int cap);
|
|
||||||
int http_get_param_i (HTTP_String body, HTTP_String str);
|
|
||||||
|
|
||||||
// Checks whether the request was meant for the host with the given
|
|
||||||
// domain an port. If port is -1, the default value of 80 is assumed.
|
|
||||||
bool http_match_host(HTTP_Request *req, HTTP_String domain, int port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/server.h
|
// src/server.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -886,6 +894,11 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
// Size limit of the input and output buffer of each
|
||||||
|
// connection.
|
||||||
|
uint32_t input_buffer_limit;
|
||||||
|
uint32_t output_buffer_limit;
|
||||||
|
|
||||||
// Array of connections. The counter contains the
|
// Array of connections. The counter contains the
|
||||||
// number of structs such that state=FREE.
|
// number of structs such that state=FREE.
|
||||||
int num_conns;
|
int num_conns;
|
||||||
@@ -923,6 +936,11 @@ int http_server_init(HTTP_Server *server);
|
|||||||
// Release resources associated to the server.
|
// Release resources associated to the server.
|
||||||
void http_server_free(HTTP_Server *server);
|
void http_server_free(HTTP_Server *server);
|
||||||
|
|
||||||
|
// Set input and output buffer size limit for any
|
||||||
|
// given connection. The default value is 1MB
|
||||||
|
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit);
|
||||||
|
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit);
|
||||||
|
|
||||||
// Enable listening for plain HTTP requests at the
|
// Enable listening for plain HTTP requests at the
|
||||||
// specified interface.
|
// specified interface.
|
||||||
int http_server_listen_tcp(HTTP_Server *server,
|
int http_server_listen_tcp(HTTP_Server *server,
|
||||||
|
|||||||
+4
-4
@@ -56,13 +56,13 @@ header = Amalgamator()
|
|||||||
header.append_text(desc)
|
header.append_text(desc)
|
||||||
header.append_file("src/includes.h")
|
header.append_file("src/includes.h")
|
||||||
header.append_file("src/basic.h")
|
header.append_file("src/basic.h")
|
||||||
|
header.append_file("src/parse.h")
|
||||||
|
header.append_file("src/thread.h")
|
||||||
header.append_file("src/secure_context.h")
|
header.append_file("src/secure_context.h")
|
||||||
header.append_file("src/socket.h")
|
header.append_file("src/socket.h")
|
||||||
header.append_file("src/thread.h")
|
|
||||||
header.append_file("src/byte_queue.h")
|
header.append_file("src/byte_queue.h")
|
||||||
header.append_file("src/cert.h")
|
header.append_file("src/cert.h")
|
||||||
header.append_file("src/client.h")
|
header.append_file("src/client.h")
|
||||||
header.append_file("src/parse.h")
|
|
||||||
header.append_file("src/server.h")
|
header.append_file("src/server.h")
|
||||||
header.append_text(license)
|
header.append_text(license)
|
||||||
header.save("chttp.h")
|
header.save("chttp.h")
|
||||||
@@ -74,13 +74,13 @@ source.append_text("#ifndef HTTP_DONT_INCLUDE\n")
|
|||||||
source.append_text('#include "chttp.h"\n')
|
source.append_text('#include "chttp.h"\n')
|
||||||
source.append_text("#endif\n")
|
source.append_text("#endif\n")
|
||||||
source.append_file("src/basic.c")
|
source.append_file("src/basic.c")
|
||||||
|
source.append_file("src/parse.c")
|
||||||
|
source.append_file("src/thread.c")
|
||||||
source.append_file("src/secure_context.c")
|
source.append_file("src/secure_context.c")
|
||||||
source.append_file("src/socket.c")
|
source.append_file("src/socket.c")
|
||||||
source.append_file("src/thread.c")
|
|
||||||
source.append_file("src/byte_queue.c")
|
source.append_file("src/byte_queue.c")
|
||||||
source.append_file("src/cert.c")
|
source.append_file("src/cert.c")
|
||||||
source.append_file("src/client.c")
|
source.append_file("src/client.c")
|
||||||
source.append_file("src/parse.c")
|
|
||||||
source.append_file("src/server.c")
|
source.append_file("src/server.c")
|
||||||
header.append_text(license)
|
header.append_text(license)
|
||||||
source.save("chttp.c")
|
source.save("chttp.c")
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|||||||
+40
-8
@@ -1,6 +1,25 @@
|
|||||||
|
|
||||||
|
static void http_server_conn_init(HTTP_ServerConn *conn,
|
||||||
|
SocketHandle handle, uint32_t input_buffer_limit,
|
||||||
|
uint32_t output_buffer_limit)
|
||||||
|
{
|
||||||
|
conn->state = HTTP_SERVER_CONN_BUFFERING;
|
||||||
|
conn->handle = handle;
|
||||||
|
byte_queue_init(&conn->input, input_buffer_limit);
|
||||||
|
byte_queue_init(&conn->output, output_buffer_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void http_server_conn_free(HTTP_ServerConn *conn)
|
||||||
|
{
|
||||||
|
byte_queue_free(&conn->output);
|
||||||
|
byte_queue_free(&conn->input);
|
||||||
|
}
|
||||||
|
|
||||||
int http_server_init(HTTP_Server *server)
|
int http_server_init(HTTP_Server *server)
|
||||||
{
|
{
|
||||||
|
server->input_buffer_limit = 1<<20;
|
||||||
|
server->output_buffer_limit = 1<<20;
|
||||||
|
|
||||||
server->num_conns = 0;
|
server->num_conns = 0;
|
||||||
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++)
|
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++)
|
||||||
server->conns[i].state = HTTP_SERVER_CONN_FREE;
|
server->conns[i].state = HTTP_SERVER_CONN_FREE;
|
||||||
@@ -9,7 +28,7 @@ int http_server_init(HTTP_Server *server)
|
|||||||
server->ready_head = 0;
|
server->ready_head = 0;
|
||||||
|
|
||||||
if (socket_manager_init(&server->sockets,
|
if (socket_manager_init(&server->sockets,
|
||||||
&server->socket_pool, HTTP_SERVER_CAPACITY) < 0)
|
server->socket_pool, HTTP_SERVER_CAPACITY) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -28,6 +47,16 @@ void http_server_free(HTTP_Server *server)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit)
|
||||||
|
{
|
||||||
|
server->input_buffer_limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit)
|
||||||
|
{
|
||||||
|
server->output_buffer_limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
int http_server_listen_tcp(HTTP_Server *server,
|
int http_server_listen_tcp(HTTP_Server *server,
|
||||||
String addr, Port port)
|
String addr, Port port)
|
||||||
{
|
{
|
||||||
@@ -101,7 +130,7 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
|
|||||||
// Ready
|
// Ready
|
||||||
assert(ret == 1);
|
assert(ret == 1);
|
||||||
|
|
||||||
conn->state = HTTP_SERVER_CONN_STATUS;
|
conn->state = HTTP_SERVER_CONN_WAIT_STATUS;
|
||||||
conn->request_len = ret;
|
conn->request_len = ret;
|
||||||
conn->response_offset = byte_queue_offset(&conn->output);
|
conn->response_offset = byte_queue_offset(&conn->output);
|
||||||
|
|
||||||
@@ -133,7 +162,7 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
struct pollfd *polled, int num_polled)
|
struct pollfd *polled, int num_polled)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_SERVER_CAPACITY];
|
SocketEvent events[HTTP_SERVER_CAPACITY];
|
||||||
int num_events = socket_manger_translate_events(&server->sockets, polled, num_polled);
|
int num_events = socket_manager_translate_events(&server->sockets, polled, num_polled);
|
||||||
if (num_events < 0)
|
if (num_events < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -162,7 +191,10 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn = &server->conns[i];
|
conn = &server->conns[i];
|
||||||
http_server_conn_init(conn, events[i].handle);
|
http_server_conn_init(conn,
|
||||||
|
events[i].handle,
|
||||||
|
server->input_buffer_limit,
|
||||||
|
server->output_buffer_limit);
|
||||||
server->num_conns++;
|
server->num_conns++;
|
||||||
|
|
||||||
socket_set_user(&server->sockets, events[i].handle, conn);
|
socket_set_user(&server->sockets, events[i].handle, conn);
|
||||||
@@ -226,11 +258,11 @@ builder_to_conn(HTTP_ResponseBuilder builder)
|
|||||||
if (server == NULL)
|
if (server == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (server->index > HTTP_SERVER_CAPACITY)
|
if (builder.index > HTTP_SERVER_CAPACITY)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
HTTP_ServerConn *conn = server->conns[server->index];
|
HTTP_ServerConn *conn = server->conns[builder.index];
|
||||||
if (conn->gen != builder.gen)
|
if (builder.gen != conn->gen)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
@@ -295,7 +327,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, String str)
|
|||||||
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY)
|
if (conn->state != HTTP_SERVER_CONN_WAIT_BODY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
byte_queue_write(&conn->output, str);
|
byte_queue_write(&conn->output, str.ptr, str.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_response_builder_send(HTTP_ResponseBuilder builder, String str)
|
void http_response_builder_send(HTTP_ResponseBuilder builder, String str)
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
// Size limit of the input and output buffer of each
|
||||||
|
// connection.
|
||||||
|
uint32_t input_buffer_limit;
|
||||||
|
uint32_t output_buffer_limit;
|
||||||
|
|
||||||
// Array of connections. The counter contains the
|
// Array of connections. The counter contains the
|
||||||
// number of structs such that state=FREE.
|
// number of structs such that state=FREE.
|
||||||
int num_conns;
|
int num_conns;
|
||||||
@@ -105,6 +110,11 @@ int http_server_init(HTTP_Server *server);
|
|||||||
// Release resources associated to the server.
|
// Release resources associated to the server.
|
||||||
void http_server_free(HTTP_Server *server);
|
void http_server_free(HTTP_Server *server);
|
||||||
|
|
||||||
|
// Set input and output buffer size limit for any
|
||||||
|
// given connection. The default value is 1MB
|
||||||
|
void http_server_set_input_limit(HTTP_Server *server, uint32_t limit);
|
||||||
|
void http_server_set_output_limit(HTTP_Server *server, uint32_t limit);
|
||||||
|
|
||||||
// Enable listening for plain HTTP requests at the
|
// Enable listening for plain HTTP requests at the
|
||||||
// specified interface.
|
// specified interface.
|
||||||
int http_server_listen_tcp(HTTP_Server *server,
|
int http_server_listen_tcp(HTTP_Server *server,
|
||||||
|
|||||||
+82
-67
@@ -219,6 +219,15 @@ int socket_manager_add_certificate(SocketManager *sm,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_secure(Socket *s)
|
||||||
|
{
|
||||||
|
#ifdef HTTPS_ENABLED
|
||||||
|
return (s->ssl != NULL);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static bool connect_pending(void)
|
static bool connect_pending(void)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -228,17 +237,6 @@ static bool connect_pending(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
connect_failed_because_of_peer(void)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
int err = WSAGetLastError();
|
|
||||||
#else
|
|
||||||
int err = errno;
|
|
||||||
#endif
|
|
||||||
return connect_failed_because_of_peer_2(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
connect_failed_because_of_peer_2(int err)
|
connect_failed_because_of_peer_2(int err)
|
||||||
{
|
{
|
||||||
@@ -255,10 +253,21 @@ connect_failed_because_of_peer_2(int err)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
connect_failed_because_of_peer(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
#else
|
||||||
|
int err = errno;
|
||||||
|
#endif
|
||||||
|
return connect_failed_because_of_peer_2(err);
|
||||||
|
}
|
||||||
|
|
||||||
// This function moves the socket state machine
|
// This function moves the socket state machine
|
||||||
// to the next state until an I/O event would
|
// to the next state until an I/O event would
|
||||||
// be required to continue.
|
// be required to continue.
|
||||||
static void socket_update(Socket *socket)
|
static void socket_update(Socket *s)
|
||||||
{
|
{
|
||||||
// Each case of this switch encodes a state transition.
|
// Each case of this switch encodes a state transition.
|
||||||
// If the evaluated case requires a given I/O event to
|
// If the evaluated case requires a given I/O event to
|
||||||
@@ -269,7 +278,7 @@ static void socket_update(Socket *socket)
|
|||||||
bool again;
|
bool again;
|
||||||
do {
|
do {
|
||||||
again = false;
|
again = false;
|
||||||
switch (socket->state) {
|
switch (s->state) {
|
||||||
case SOCKET_STATE_PENDING:
|
case SOCKET_STATE_PENDING:
|
||||||
{
|
{
|
||||||
// This point may be reached because
|
// This point may be reached because
|
||||||
@@ -280,17 +289,17 @@ static void socket_update(Socket *socket)
|
|||||||
// If (2) is true, we have some resources
|
// If (2) is true, we have some resources
|
||||||
// to clean up.
|
// to clean up.
|
||||||
|
|
||||||
if (socket->sock != NATIVE_SOCKET_INVALID) {
|
if (s->sock != NATIVE_SOCKET_INVALID) {
|
||||||
// This is not the first attempt
|
// This is not the first attempt
|
||||||
|
|
||||||
CLOSE_NATIVE_SOCKET(socket->sock);
|
CLOSE_NATIVE_SOCKET(s->sock);
|
||||||
|
|
||||||
socket->next_addr++;
|
s->next_addr++;
|
||||||
if (socket->next_addr == socket->num_addr) {
|
if (s->next_addr == s->num_addr) {
|
||||||
assert(0); // TODO
|
assert(0); // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AddressAndPort addr = socket->addrs[socket->next_addr];
|
AddressAndPort addr = s->addrs[s->next_addr];
|
||||||
|
|
||||||
int family = (addr.is_ipv4 ? AF_INET : AF_INET6);
|
int family = (addr.is_ipv4 ? AF_INET : AF_INET6);
|
||||||
NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0);
|
NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0);
|
||||||
@@ -307,41 +316,39 @@ static void socket_update(Socket *socket)
|
|||||||
struct sockaddr_in buf;
|
struct sockaddr_in buf;
|
||||||
buf.sin_family = AF_INET;
|
buf.sin_family = AF_INET;
|
||||||
buf.sin_port = htons(addr.port);
|
buf.sin_port = htons(addr.port);
|
||||||
memset(&buf.sin_addr, &addr.ipv4, sizeof(IPv4));
|
memcpy(&buf.sin_addr, &addr.ipv4, sizeof(IPv4));
|
||||||
ret = connect(sock, (struct sockaddr*) &connect_buf,
|
ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf));
|
||||||
sizeof(connect_buf));
|
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in6 buf;
|
struct sockaddr_in6 buf;
|
||||||
buf.sin6_family = AF_INET6;
|
buf.sin6_family = AF_INET6;
|
||||||
buf.sin6_port = htons(addr.port);
|
buf.sin6_port = htons(addr.port);
|
||||||
memset(&buf.sin6_addr, &addr.ipv6, sizeof(IPv6));
|
memcpy(&buf.sin6_addr, &addr.ipv6, sizeof(IPv6));
|
||||||
ret = connect(sock, (struct sockaddr*) &connect_buf,
|
ret = connect(sock, (struct sockaddr*) &buf, sizeof(buf));
|
||||||
sizeof(connect_buf));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
// Connect resolved immediately
|
// Connect resolved immediately
|
||||||
socket->sock = sock;
|
s->sock = sock;
|
||||||
socket->state = SOCKET_STATE_CONNECTED;
|
s->state = SOCKET_STATE_CONNECTED;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
again = true;
|
again = true;
|
||||||
} else if (connect_pending()) {
|
} else if (connect_pending()) {
|
||||||
// Connect is pending, which is expected
|
// Connect is pending, which is expected
|
||||||
socket->sock = sock;
|
s->sock = sock;
|
||||||
socket->state = SOCKET_STATE_CONNECTING;
|
s->state = SOCKET_STATE_CONNECTING;
|
||||||
socket->events = POLLOUT;
|
s->events = POLLOUT;
|
||||||
} else if (connect_failed_because_of_peer()) {
|
} else if (connect_failed_because_of_peer()) {
|
||||||
// Conenct failed due to the peer host
|
// Conenct failed due to the peer host
|
||||||
// We should try a different address.
|
// We should try a different address.
|
||||||
socket->sock = sock;
|
s->sock = sock;
|
||||||
socket->state = SOCKET_STATE_PENDING;
|
s->state = SOCKET_STATE_PENDING;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
again = true;
|
again = true;
|
||||||
} else {
|
} else {
|
||||||
// An error occurred that we can't recover from
|
// An error occurred that we can't recover from
|
||||||
socket->sock = sock;
|
s->sock = sock;
|
||||||
socket->state = SOCKET_STATE_DIED;
|
s->state = SOCKET_STATE_DIED;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
again = true;
|
again = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,23 +361,23 @@ static void socket_update(Socket *socket)
|
|||||||
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
socklen_t len = sizeof(err);
|
socklen_t len = sizeof(err);
|
||||||
if (getsockopt(socket->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) {
|
if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) {
|
||||||
assert(0); // TODO
|
assert(0); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
// Connection succeded
|
// Connection succeded
|
||||||
socket->state = SOCKET_STATE_CONNECTED;
|
s->state = SOCKET_STATE_CONNECTED;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
again = true;
|
again = true;
|
||||||
} else if (connect_failed_because_of_peer_2(err)) {
|
} else if (connect_failed_because_of_peer_2(err)) {
|
||||||
// Try the next address
|
// Try the next address
|
||||||
socket->state = SOCKET_STATE_PENDING;
|
s->state = SOCKET_STATE_PENDING;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
again = true;
|
again = true;
|
||||||
} else {
|
} else {
|
||||||
socket->state = SOCKET_STATE_DIED;
|
s->state = SOCKET_STATE_DIED;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -380,12 +387,25 @@ static void socket_update(Socket *socket)
|
|||||||
// We managed to connect to the peer.
|
// We managed to connect to the peer.
|
||||||
// We can free the target array if it
|
// We can free the target array if it
|
||||||
// was allocated dynamically.
|
// was allocated dynamically.
|
||||||
if (socket->num_addr > 1)
|
if (s->num_addr > 1)
|
||||||
free(socket->addrs);
|
free(s->addrs);
|
||||||
|
|
||||||
if (!is_secure(socket)) {
|
if (!is_secure(s)) {
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
socket->state = SOCKET_STATE_ESTABLISHED_READY;
|
s->state = SOCKET_STATE_ESTABLISHED_READY;
|
||||||
|
} else {
|
||||||
|
#ifdef HTTPS_ENABLED
|
||||||
|
assert(0); // TODO
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOCKET_STATE_ACCEPTED:
|
||||||
|
{
|
||||||
|
if (!is_secure(s)) {
|
||||||
|
s->state = SOCKET_STATE_ESTABLISHED_READY;
|
||||||
|
s->events = 0;
|
||||||
} else {
|
} else {
|
||||||
#ifdef HTTPS_ENABLED
|
#ifdef HTTPS_ENABLED
|
||||||
assert(0); // TODO
|
assert(0); // TODO
|
||||||
@@ -395,15 +415,15 @@ static void socket_update(Socket *socket)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SOCKET_STATE_ESTABLISHED_WAIT:
|
case SOCKET_STATE_ESTABLISHED_WAIT:
|
||||||
socket->state = SOCKET_STATE_ESTABLISHED_READY;
|
s->state = SOCKET_STATE_ESTABLISHED_READY;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOCKET_STATE_SHUTDOWN:
|
case SOCKET_STATE_SHUTDOWN:
|
||||||
{
|
{
|
||||||
if (!is_secure(socket)) {
|
if (!is_secure(s)) {
|
||||||
socket->state = SOCKET_STATE_DIED;
|
s->state = SOCKET_STATE_DIED;
|
||||||
socket->events = 0;
|
s->events = 0;
|
||||||
} else {
|
} else {
|
||||||
#ifdef HTTPS_ENABLED
|
#ifdef HTTPS_ENABLED
|
||||||
assert(0); // TODO
|
assert(0); // TODO
|
||||||
@@ -544,7 +564,7 @@ static int socket_manager_translate_events_nolock(
|
|||||||
bool secure = (polled[i].fd == sm->secure_sock);
|
bool secure = (polled[i].fd == sm->secure_sock);
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->type != SOCKET_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
s++;
|
s++;
|
||||||
assert(s - sm->sockets < + sm->max_used);
|
assert(s - sm->sockets < + sm->max_used);
|
||||||
}
|
}
|
||||||
@@ -570,7 +590,7 @@ static int socket_manager_translate_events_nolock(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool->num_used++;
|
sm->num_used++;
|
||||||
|
|
||||||
} else if (polled[i].fd == sm->wait_sock) {
|
} else if (polled[i].fd == sm->wait_sock) {
|
||||||
|
|
||||||
@@ -584,7 +604,7 @@ static int socket_manager_translate_events_nolock(
|
|||||||
|
|
||||||
for (int i = 0, j = 0; j < sm->num_used; i++) {
|
for (int i = 0, j = 0; j < sm->num_used; i++) {
|
||||||
Socket *s = &sm->sockets[i];
|
Socket *s = &sm->sockets[i];
|
||||||
if (s->state == SOCKET_FREE)
|
if (s->state == SOCKET_STATE_FREE)
|
||||||
continue;
|
continue;
|
||||||
j++;
|
j++;
|
||||||
|
|
||||||
@@ -600,7 +620,7 @@ static int socket_manager_translate_events_nolock(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Free resources associated to socket
|
// Free resources associated to socket
|
||||||
s->state = SOCKET_FREE;
|
s->state = SOCKET_STATE_FREE;
|
||||||
if (s->sock != NATIVE_SOCKET_INVALID)
|
if (s->sock != NATIVE_SOCKET_INVALID)
|
||||||
CLOSE_NATIVE_SOCKET(s->sock);
|
CLOSE_NATIVE_SOCKET(s->sock);
|
||||||
if (s->sock == SOCKET_STATE_PENDING ||
|
if (s->sock == SOCKET_STATE_PENDING ||
|
||||||
@@ -717,7 +737,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->type != SOCKET_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
s++;
|
s++;
|
||||||
assert(s - sm->sockets < + sm->max_used);
|
assert(s - sm->sockets < + sm->max_used);
|
||||||
}
|
}
|
||||||
@@ -736,7 +756,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
s->addrs[i] = resolved[i];
|
s->addrs[i] = resolved[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
s->type = SOCKET_STATE_PENDING;
|
s->state = SOCKET_STATE_PENDING;
|
||||||
s->sock = NATIVE_SOCKET_INVALID;
|
s->sock = NATIVE_SOCKET_INVALID;
|
||||||
s->user = user;
|
s->user = user;
|
||||||
s->num_used++;
|
s->num_used++;
|
||||||
@@ -888,25 +908,20 @@ int socket_is_secure(SocketManager *sm, SocketHandle handle)
|
|||||||
if (mutex_lock(&sm->mutex) < 0)
|
if (mutex_lock(&sm->mutex) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#ifdef HTTPS_ENABLED
|
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
else {
|
else
|
||||||
ret = (s->ssl != NULL);
|
ret = is_secure(s);
|
||||||
}
|
|
||||||
#else
|
|
||||||
int ret = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
if (mutex_unlock(&sm->mutex) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_set_user(SocketManager *sm, SocketHandle handle)
|
int socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
if (mutex_lock(&sm->mutex) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
+7
-3
@@ -102,10 +102,14 @@ typedef enum {
|
|||||||
// still pending.
|
// still pending.
|
||||||
SOCKET_STATE_CONNECTING,
|
SOCKET_STATE_CONNECTING,
|
||||||
|
|
||||||
// The connection was estabished, but a TLS
|
// Outgoing connection was established, but
|
||||||
// handshake may need to be performed.
|
// a TLS handshake may need to be performed.
|
||||||
SOCKET_STATE_CONNECTED,
|
SOCKET_STATE_CONNECTED,
|
||||||
|
|
||||||
|
// Incoming connection was established, but
|
||||||
|
// a TLS handshake may need to be performed.
|
||||||
|
SOCKET_STATE_ACCEPTED,
|
||||||
|
|
||||||
// The connection was esablished, but the user
|
// The connection was esablished, but the user
|
||||||
// wants to perform a read or write operation that
|
// wants to perform a read or write operation that
|
||||||
// would block.
|
// would block.
|
||||||
@@ -299,4 +303,4 @@ void socket_close(SocketManager *sm, SocketHandle handle);
|
|||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
||||||
|
|
||||||
// Set the user pointer of a socket
|
// Set the user pointer of a socket
|
||||||
void socket_set_user(SocketManager *sm, SocketHandle handle);
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
||||||
|
|||||||
+5
-3
@@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
typedef struct {
|
#ifdef _WIN32
|
||||||
char unused; // TODO
|
typedef CRITICAL_SECTION Mutex;
|
||||||
} Mutex;
|
#else
|
||||||
|
typedef pthread_mutex_t Mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
int mutex_init(Mutex *mutex);
|
int mutex_init(Mutex *mutex);
|
||||||
int mutex_free(Mutex *mutex);
|
int mutex_free(Mutex *mutex);
|
||||||
|
|||||||
Reference in New Issue
Block a user