Fix compiler errors

This commit is contained in:
2025-11-21 18:30:35 +01:00
parent aab1b8e7b8
commit 3c2ef70c66
12 changed files with 743 additions and 267 deletions
+1 -1
View File
@@ -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 -Wfatal-errors gcc main.c chttp.c -o example -Wfatal-errors
clean: clean:
rm chttp.c chttp.h rm chttp.c chttp.h
+293 -100
View File
@@ -1582,7 +1582,7 @@ static int set_socket_blocking(NATIVE_SOCKET sock, bool value)
return 0; return 0;
} }
static NATIVE_SOCKET create_listen_socket(String addr, static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
Port port, bool reuse_addr, int backlog) Port port, bool reuse_addr, int backlog)
{ {
NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -1683,7 +1683,7 @@ void socket_manager_free(SocketManager *sm)
} }
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
String addr, Port port) HTTP_String addr, Port port)
{ {
if (sm->plain_sock != NATIVE_SOCKET_INVALID) if (sm->plain_sock != NATIVE_SOCKET_INVALID)
return -1; return -1;
@@ -1698,8 +1698,8 @@ int socket_manager_listen_tcp(SocketManager *sm,
} }
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name) HTTP_String key_file_name)
{ {
if (sm->secure_sock != NATIVE_SOCKET_INVALID) if (sm->secure_sock != NATIVE_SOCKET_INVALID)
return -1; return -1;
@@ -1966,38 +1966,41 @@ int socket_manager_wakeup(SocketManager *sm)
} }
static int socket_manager_register_events_nolock( static int socket_manager_register_events_nolock(
SocketManager *sm, struct pollfd *polled, int max_polled) SocketManager *sm, EventRegister *reg)
{ {
// The poll array must be able to hold descriptors // The poll array must be able to hold descriptors
// for a socket manager at full capacity. Note that // for a socket manager at full capacity. Note that
// other than having a number of connection sockets, // other than having a number of connection sockets,
// the manager also needs 2 for the listeners and // the manager also needs 2 for the listeners and
// one for the wakeup self-pipe. // one for the wakeup self-pipe.
if (max_polled < sm->max_used+3) if (reg->max_polled < sm->max_used+3)
return -1; return -1;
int num_polled = 0; reg->num_polled = 0;
polled[num_polled].fd = sm->wait_sock; reg->polled[reg->num_polled].fd = sm->wait_sock;
polled[num_polled].events = 0; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
// If the manager isn't at full capacity, monitor // If the manager isn't at full capacity, monitor
// the listener sockets for incoming connections. // the listener sockets for incoming connections.
if (sm->num_used < sm->max_used) { if (sm->num_used < sm->max_used) {
if (sm->plain_sock != NATIVE_SOCKET_INVALID) { if (sm->plain_sock != NATIVE_SOCKET_INVALID) {
polled[num_polled].fd = sm->plain_sock; reg->polled[reg->num_polled].fd = sm->plain_sock;
polled[num_polled].events = POLLIN; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
} }
if (sm->secure_sock != NATIVE_SOCKET_INVALID) { if (sm->secure_sock != NATIVE_SOCKET_INVALID) {
polled[num_polled].fd = sm->secure_sock; reg->polled[reg->num_polled].fd = sm->secure_sock;
polled[num_polled].events = POLLIN; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
} }
} }
@@ -2012,28 +2015,25 @@ static int socket_manager_register_events_nolock(
continue; continue;
j++; j++;
if (s->state == SOCKET_STATE_DIED || s->state == SOCKET_STATE_ESTABLISHED_READY)
return 0;
if (s->events) { if (s->events) {
polled[num_polled].fd = s->sock; reg->polled[reg->num_polled].fd = s->sock;
polled[num_polled].events = s->events; reg->polled[reg->num_polled].events = s->events;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = s;
reg->num_polled++;
} }
} }
return num_polled; return 0;
} }
int socket_manager_register_events(SocketManager *sm, int socket_manager_register_events(SocketManager *sm,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
int ret = socket_manager_register_events_nolock( int ret = socket_manager_register_events_nolock(sm, reg);
sm, polled, max_polled);
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
@@ -2052,14 +2052,14 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
} }
static int socket_manager_translate_events_nolock( static int socket_manager_translate_events_nolock(
SocketManager *sm, SocketEvent *events, int max_events, SocketManager *sm, SocketEvent *events,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
int num_events = 0; int num_events = 0;
for (int i = 0; i < num_polled; i++) { for (int i = 0; i < reg->num_polled; i++) {
if (polled[i].fd == sm->plain_sock || if (reg->polled[i].fd == sm->plain_sock ||
polled[i].fd == sm->secure_sock) { reg->polled[i].fd == sm->secure_sock) {
// We only listen for input events from the listener // We only listen for input events from the listener
// if the socket pool isn't fool. This ensures that // if the socket pool isn't fool. This ensures that
@@ -2075,7 +2075,7 @@ static int socket_manager_translate_events_nolock(
// Determine whether the event came from // Determine whether the event came from
// the encrypted listener or not. // the encrypted listener or not.
bool secure = (polled[i].fd == sm->secure_sock); bool secure = (reg->polled[i].fd == sm->secure_sock);
Socket *s = sm->sockets; Socket *s = sm->sockets;
while (s->state != SOCKET_STATE_FREE) { while (s->state != SOCKET_STATE_FREE) {
@@ -2083,7 +2083,7 @@ static int socket_manager_translate_events_nolock(
assert(s - sm->sockets < + sm->max_used); assert(s - sm->sockets < + sm->max_used);
} }
NATIVE_SOCKET sock = accept(polled[i].fd, NULL, NULL); NATIVE_SOCKET sock = accept(reg->polled[i].fd, NULL, NULL);
if (sock == NATIVE_SOCKET_INVALID) if (sock == NATIVE_SOCKET_INVALID)
continue; continue;
@@ -2106,12 +2106,14 @@ static int socket_manager_translate_events_nolock(
sm->num_used++; sm->num_used++;
} else if (polled[i].fd == sm->wait_sock) { } else if (reg->polled[i].fd == sm->wait_sock) {
// TODO: consume // TODO: consume
} else { } else {
if (polled[i].revents)
Socket *s = reg->ptrs[i];
if (reg->polled[i].revents)
socket_update(s); socket_update(s);
} }
} }
@@ -2122,14 +2124,11 @@ static int socket_manager_translate_events_nolock(
continue; continue;
j++; j++;
if (num_events == max_events) if (s->state == SOCKET_STATE_DIED) {
break;
if (s->state == SOCKET_DIED) {
events[num_events++] = (SocketEvent) { events[num_events++] = (SocketEvent) {
SOCKET_EVENT_DISCONNECT, SOCKET_EVENT_DISCONNECT,
SOCKET_HANDE_INVALID, SOCKET_HANDLE_INVALID,
s->user s->user
}; };
@@ -2142,7 +2141,7 @@ static int socket_manager_translate_events_nolock(
if (s->num_addr > 1) if (s->num_addr > 1)
free(s->addrs); free(s->addrs);
} }
s->num_used--; sm->num_used--;
} else if (s->state == SOCKET_STATE_ESTABLISHED_READY) { } else if (s->state == SOCKET_STATE_ESTABLISHED_READY) {
events[num_events++] = (SocketEvent) { events[num_events++] = (SocketEvent) {
@@ -2157,18 +2156,16 @@ static int socket_manager_translate_events_nolock(
} }
int socket_manager_translate_events(SocketManager *sm, int socket_manager_translate_events(SocketManager *sm,
SocketEvent *events, int max_events, struct pollfd *polled, SocketEvent *events, EventRegister *reg)
int num_polled)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
socket_manager_translate_events_nolock( int ret = socket_manager_translate_events_nolock(sm, events, reg);
sm, events, max_events, polled, num_polled);
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
return 0; return ret;
} }
static int resolve_connect_targets(ConnectTarget *targets, static int resolve_connect_targets(ConnectTarget *targets,
@@ -2180,7 +2177,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
case CONNECT_TARGET_NAME: case CONNECT_TARGET_NAME:
{ {
char portstr[16]; char portstr[16];
int len = snprintf(portstr, sizeof(portstr), "%u", port); int len = snprintf(portstr, sizeof(portstr), "%u", targets[i].port);
if (len < 0 || len >= (int) sizeof(portstr)) if (len < 0 || len >= (int) sizeof(portstr))
return -1; return -1;
@@ -2188,8 +2185,14 @@ static int resolve_connect_targets(ConnectTarget *targets,
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
char hostname[1<<9]; // TODO: Is this a good length?
if (targets[i].name.len >= (int) sizeof(hostname))
return -1;
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
hostname[targets[i].name.len] = '\0';
struct addrinfo *res = NULL; struct addrinfo *res = NULL;
int ret = getaddrinfo(pending_connect->hostname, portstr, &hints, &res); int ret = getaddrinfo(hostname, portstr, &hints, &res);
if (ret != 0) if (ret != 0)
return -1; return -1;
@@ -2206,7 +2209,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
IPv6 ipv6 = *(IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr; IPv6 ipv6 = *(IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
if (num_resolved < max_resolved) { if (num_resolved < max_resolved) {
resolved[num_resolved].is_ipv4 = false; resolved[num_resolved].is_ipv4 = false;
resolved[num_resolved].ipv4 = ipv6; resolved[num_resolved].ipv6 = ipv6;
resolved[num_resolved].port = targets[i].port; resolved[num_resolved].port = targets[i].port;
num_resolved++; num_resolved++;
} }
@@ -2237,6 +2240,8 @@ static int resolve_connect_targets(ConnectTarget *targets,
return num_resolved; return num_resolved;
} }
#define MAX_CONNECT_TARGETS 16
int socket_connect(SocketManager *sm, int num_targets, int socket_connect(SocketManager *sm, int num_targets,
ConnectTarget *targets, bool secure, void *user) ConnectTarget *targets, bool secure, void *user)
{ {
@@ -2273,10 +2278,29 @@ int socket_connect(SocketManager *sm, int num_targets,
s->state = 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++; sm->num_used++;
return 0; return 0;
} }
static bool would_block(void)
{
#ifdef _WIN32
int err = WSAGetLastError();
return err == WSAEWOULDBLOCK;
#else
return errno == EAGAIN || errno == EWOULDBLOCK;
#endif
}
static bool interrupted(void)
{
#ifdef _WIN32
return false;
#else
return errno == EINTR;
#endif
}
static int socket_recv_nolock(SocketManager *sm, SocketHandle handle, static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
char *dst, int max) char *dst, int max)
{ {
@@ -2354,14 +2378,14 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
} }
if (!socket_secure(s)) { if (!is_secure(s)) {
int ret = send(s->sock, src, len, 0); int ret = send(s->sock, src, len, 0);
if (ret < 0) { if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; s->state = SOCKET_STATE_ESTABLISHED_WAIT;
s->events = POLLOUT; s->events = POLLOUT;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_DIED; s->state = SOCKET_STATE_DIED;
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -2402,19 +2426,25 @@ int socket_send(SocketManager *sm, SocketHandle handle,
return ret; return ret;
} }
void socket_close(SocketManager *sm, SocketHandle handle) int socket_close(SocketManager *sm, SocketHandle handle)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
int ret;
Socket *s = handle_to_socket(sm, handle);
if (s == NULL)
ret = -1;
else {
// TODO: maybe we don't want to always set to SHUTDOWN. What if the socket is DIED for instance? // TODO: maybe we don't want to always set to SHUTDOWN. What if the socket is DIED for instance?
s->state = SOCKET_STATE_SHUTDOWN; s->state = SOCKET_STATE_SHUTDOWN;
s->events = 0; s->events = 0;
socket_update(s); socket_update(s);
}
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
return 0; return ret;
} }
int socket_is_secure(SocketManager *sm, SocketHandle handle) int socket_is_secure(SocketManager *sm, SocketHandle handle)
@@ -2440,11 +2470,14 @@ 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;
int ret;
Socket *s = handle_to_socket(sm, handle); Socket *s = handle_to_socket(sm, handle);
if (s == NULL) if (s == NULL)
ret = -1; ret = -1;
else else {
s->user = user; s->user = user;
ret = 0;
}
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
@@ -2673,6 +2706,46 @@ void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len)
} }
} }
void byte_queue_write_fmt2(ByteQueue *queue,
const char *fmt, va_list args)
{
if (queue->flags & BYTE_QUEUE_ERROR)
return;
va_list args2;
va_copy(args2, args);
byte_queue_write_setmincap(queue, 128);
ByteView dst = byte_queue_write_buf(queue);
int len = vsnprintf(dst.ptr, dst.len, fmt, args);
if (len < 0) {
queue->flags |= BYTE_QUEUE_ERROR;
va_end(args2);
return;
}
if (len > dst.len) {
byte_queue_write_ack(queue, 0);
byte_queue_write_setmincap(queue, len+1);
dst = byte_queue_write_buf(queue);
vsnprintf(dst.ptr, dst.len, fmt, args2);
}
byte_queue_write_ack(queue, len);
va_end(args2);
}
void byte_queue_write_fmt(ByteQueue *queue,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
byte_queue_write_fmt2(queue, fmt, args);
va_end(args);
}
ByteQueueOffset byte_queue_offset(ByteQueue *queue) ByteQueueOffset byte_queue_offset(ByteQueue *queue)
{ {
if (queue->flags & BYTE_QUEUE_ERROR) if (queue->flags & BYTE_QUEUE_ERROR)
@@ -2874,6 +2947,16 @@ int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
// src/client.c // src/client.c
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
void http_client_conn_init(HTTP_ClientConn *conn)
{
// TODO
}
void http_client_conn_free(HTTP_ClientConn *conn)
{
// TODO
}
int http_client_init(HTTP_Client *client) int http_client_init(HTTP_Client *client)
{ {
client->num_conns = 0; client->num_conns = 0;
@@ -2910,22 +2993,26 @@ int http_client_wakeup(HTTP_Client *client)
return 0; return 0;
} }
int http_client_get_builder(HTTP_Client *client, HTTP_RequestBuilder *builder) int http_client_get_builder(HTTP_Client *client,
HTTP_Response *response, HTTP_RequestBuilder *builder)
{ {
// TODO // TODO
} }
void http_request_builder_line(HTTP_RequestBuilder builder, xxxx) void http_request_builder_url(HTTP_RequestBuilder builder,
HTTP_String url)
{ {
// TODO // TODO
} }
void http_request_builder_header(HTTP_RequestBuilder builder, String str) void http_request_builder_header(HTTP_RequestBuilder builder,
HTTP_String str)
{ {
// TODO // TODO
} }
void http_request_builder_body(HTTP_RequestBuilder builder, String str) void http_request_builder_body(HTTP_RequestBuilder builder,
HTTP_String str)
{ {
// TODO // TODO
} }
@@ -2936,18 +3023,19 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
} }
int http_client_register_events(HTTP_Client *client, int http_client_register_events(HTTP_Client *client,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
return socket_manager_register_events( if (socket_manager_register_events(&client->sockets, reg) < 0)
&client->sockets, polled, max_polled); return -1;
return 0;
} }
int http_client_process_events(HTTP_Client *client, int http_client_process_events(HTTP_Client *client,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
SocketEvent events[HTTP_CLIENT_CAPACITY]; SocketEvent events[HTTP_CLIENT_CAPACITY];
int num_events = socket_manager_translate_events( int num_events = socket_manager_translate_events(
&client->sockets, polled, num_polled); &client->sockets, events, reg);
for (int i = 0; i < num_events; i++) { for (int i = 0; i < num_events; i++) {
@@ -2967,9 +3055,9 @@ int http_client_process_events(HTTP_Client *client,
} }
bool http_client_next_response(HTTP_Client *client, bool http_client_next_response(HTTP_Client *client,
HTTP_Response **response); HTTP_Response **response)
{ {
if (server->num_ready == 0) if (client->num_ready == 0)
return false; return false;
HTTP_ClientConn *conn = &client->conns[client->ready_head]; HTTP_ClientConn *conn = &client->conns[client->ready_head];
@@ -2996,6 +3084,7 @@ static void http_server_conn_init(HTTP_ServerConn *conn,
{ {
conn->state = HTTP_SERVER_CONN_BUFFERING; conn->state = HTTP_SERVER_CONN_BUFFERING;
conn->handle = handle; conn->handle = handle;
conn->closing = false;
byte_queue_init(&conn->input, input_buffer_limit); byte_queue_init(&conn->input, input_buffer_limit);
byte_queue_init(&conn->output, output_buffer_limit); byte_queue_init(&conn->output, output_buffer_limit);
} }
@@ -3012,8 +3101,10 @@ int http_server_init(HTTP_Server *server)
server->output_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;
server->conns[i].gen = 0;
}
server->num_ready = 0; server->num_ready = 0;
server->ready_head = 0; server->ready_head = 0;
@@ -3049,7 +3140,7 @@ void http_server_set_output_limit(HTTP_Server *server, uint32_t limit)
} }
int http_server_listen_tcp(HTTP_Server *server, int http_server_listen_tcp(HTTP_Server *server,
String addr, Port port) HTTP_String addr, Port port)
{ {
if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0) if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0)
return -1; return -1;
@@ -3057,8 +3148,8 @@ int http_server_listen_tcp(HTTP_Server *server,
} }
int http_server_listen_tls(HTTP_Server *server, int http_server_listen_tls(HTTP_Server *server,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name) HTTP_String key_file_name)
{ {
if (socket_manager_listen_tls(&server->sockets, addr, if (socket_manager_listen_tls(&server->sockets, addr,
port, cert_file_name, key_file_name) < 0) port, cert_file_name, key_file_name) < 0)
@@ -3083,9 +3174,11 @@ int http_server_wakeup(HTTP_Server *server)
} }
int http_server_register_events(HTTP_Server *server, int http_server_register_events(HTTP_Server *server,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
return socket_manager_register_events(&server->sockets, polled, max_polled); if (socket_manager_register_events(&server->sockets, reg) < 0)
return -1;
return 0;
} }
// Look at the head of the input buffer to see if // Look at the head of the input buffer to see if
@@ -3133,27 +3226,11 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
} }
} }
bool http_server_next_request(HTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder)
{
if (server->num_ready == 0)
return false;
HTTP_ServerConn *conn = &server->conns[server->ready_head];
server->ready_head = (server->ready_head + 1) % HTTP_SERVER_CAPACITY;
server->num_ready--;
assert(conn->state == HTTP_SERVER_CONN_WAIT_STATUS);
*request = &conn->request;
*builder = (HTTP_ResponseBuilder) { server, conn - server->conns, conn->gen };
return true;
}
int http_server_process_events(HTTP_Server *server, int http_server_process_events(HTTP_Server *server,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
SocketEvent events[HTTP_SERVER_CAPACITY]; SocketEvent events[HTTP_SERVER_CAPACITY];
int num_events = socket_manager_translate_events(&server->sockets, polled, num_polled); int num_events = socket_manager_translate_events(&server->sockets, events, reg);
if (num_events < 0) if (num_events < 0)
return -1; return -1;
@@ -3236,6 +3313,22 @@ int http_server_process_events(HTTP_Server *server,
return 0; return 0;
} }
bool http_server_next_request(HTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder)
{
if (server->num_ready == 0)
return false;
HTTP_ServerConn *conn = &server->conns[server->ready_head];
server->ready_head = (server->ready_head + 1) % HTTP_SERVER_CAPACITY;
server->num_ready--;
assert(conn->state == HTTP_SERVER_CONN_WAIT_STATUS);
*request = &conn->request;
*builder = (HTTP_ResponseBuilder) { server, conn - server->conns, conn->gen };
return true;
}
// Get a connection pointer from a response builder. // Get a connection pointer from a response builder.
// If the builder is invalid, returns NULL. // If the builder is invalid, returns NULL.
// Note that only connections in the responding states // Note that only connections in the responding states
@@ -3252,17 +3345,86 @@ builder_to_conn(HTTP_ResponseBuilder builder)
if (builder.index > HTTP_SERVER_CAPACITY) if (builder.index > HTTP_SERVER_CAPACITY)
return NULL; return NULL;
HTTP_ServerConn *conn = server->conns[builder.index]; HTTP_ServerConn *conn = &server->conns[builder.index];
if (builder.gen != conn->gen) if (builder.gen != conn->gen)
return NULL; return NULL;
return conn; return conn;
} }
static const char*
get_status_text(int code)
{
switch(code) {
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 208: return "Already Reported";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 306: return "Switch Proxy";
case 307: return "Temporary Redirect";
case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request-URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 418: return "I'm a teapot";
case 420: return "Enhance your calm";
case 422: return "Unprocessable Entity";
case 426: return "Upgrade Required";
case 429: return "Too many requests";
case 431: return "Request Header Fields Too Large";
case 449: return "Retry With";
case 451: return "Unavailable For Legal Reasons";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
case 509: return "Bandwidth Limit Exceeded";
}
return "???";
}
static void static void
write_status(HTTP_ServerConn *conn, int status) write_status(HTTP_ServerConn *conn, int status)
{ {
byte_queue_write(&conn->output, xxx); byte_queue_write_fmt(&conn->output,
"HTTP/1.1 %d %s\r\n",
status, get_status_text(status));
} }
void http_response_builder_status(HTTP_ResponseBuilder builder, int status) void http_response_builder_status(HTTP_ResponseBuilder builder, int status)
@@ -3282,7 +3444,7 @@ void http_response_builder_status(HTTP_ResponseBuilder builder, int status)
conn->state = HTTP_SERVER_CONN_WAIT_HEADER; conn->state = HTTP_SERVER_CONN_WAIT_HEADER;
} }
void http_response_builder_header(HTTP_ResponseBuilder builder, String str) void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); HTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
@@ -3291,17 +3453,48 @@ void http_response_builder_header(HTTP_ResponseBuilder builder, String str)
if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER) if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER)
return; return;
byte_queue_write(&conn->output, xxx); // TODO: Check that the header is valid
byte_queue_write(&conn->output, str.ptr, str.len);
byte_queue_write(&conn->output, "\r\n", 2);
} }
static void append_special_headers(HTTP_ServerConn *conn) static void append_special_headers(HTTP_ServerConn *conn)
{ {
// TODO HTTP_String s;
if (conn->closing) {
s = HTTP_STR("Connection: Close");
byte_queue_write(&conn->output, s.ptr, s.len);
} else {
s = HTTP_STR("Connection: Keep-Alive");
byte_queue_write(&conn->output, s.ptr, s.len);
}
s = HTTP_STR("Content-Length: ");
byte_queue_write(&conn->output, s.ptr, s.len);
conn->content_length_value_offset = byte_queue_offset(&conn->output);
#define TEN_SPACES " "
_Static_assert(sizeof(TEN_SPACES) == 10+1);
s = HTTP_STR(TEN_SPACES "\r\n");
byte_queue_write(&conn->output, s.ptr, s.len);
byte_queue_write(&conn->output, "\r\n", 2);
conn->content_length_offset = byte_queue_offset(&conn->output);
} }
static void patch_special_headers(HTTP_ServerConn *conn) static void patch_special_headers(HTTP_ServerConn *conn)
{ {
// TODO int content_length = byte_queue_size_from_offset(&conn->output, conn->content_length_offset);
char tmp[11];
int len = snprintf(tmp, sizeof(tmp), "%d", content_length);
assert(len > 0 && len < 11);
byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len);
} }
void http_response_builder_body(HTTP_ResponseBuilder builder, String str) void http_response_builder_body(HTTP_ResponseBuilder builder, String str)
+74 -29
View File
@@ -19,6 +19,8 @@
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else #else
#include <limits.h>
#include <stdarg.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <poll.h> #include <poll.h>
@@ -457,7 +459,7 @@ void socket_manager_free(SocketManager *sm);
// can only be used once per manager. // can only be used once per manager.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
String addr, Port port); HTTP_String addr, Port port);
// Same as the previous function, but incoming // Same as the previous function, but incoming
// connections will be interpreted as TLS. You // connections will be interpreted as TLS. You
@@ -467,8 +469,8 @@ int socket_manager_listen_tcp(SocketManager *sm,
// and secure connections. // and secure connections.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name); HTTP_String key_file_name);
// If the socket manager was configures to accept // If the socket manager was configures to accept
// TLS connections, this adds additional certificates // TLS connections, this adds additional certificates
@@ -485,22 +487,32 @@ int socket_manager_add_certificate(SocketManager *sm,
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_wakeup(SocketManager *sm); int socket_manager_wakeup(SocketManager *sm);
// Writes to the polled array the list of sockets typedef struct {
// that the socket manager is monitoring and which void **ptrs;
// events associated to that socket. struct pollfd *polled;
// Returns the number of items written to the polled int num_polled;
// array. int max_polled;
} EventRegister;
// Resets the event register with the list of descriptors
// the socket manager wants monitored. Returns 0 on
// success, -1 if the event register's capacity isn't
// large enough.
int socket_manager_register_events(SocketManager *sm, int socket_manager_register_events(SocketManager *sm,
struct pollfd *polled, int max_polled); EventRegister *reg);
// After poll() is called on the previously registered // After poll() is called on the previously registered
// pollfd array and the revents fields are set, this // pollfd array and the revents fields are set, this
// function processes those events to produce higher-level // function processes those events to produce higher-level
// socket events. Returns the number of socket events // socket events. Returns the number of socket events
// written to the output array, or -1 on error. // written to the output array, or -1 on error.
//
// The maximum number of events this will write
// to the events array is equal to the numero of
// socket structs provided to the socket manager
// via the init function.
int socket_manager_translate_events(SocketManager *sm, int socket_manager_translate_events(SocketManager *sm,
SocketEvent *events, int max_events, struct pollfd *polled, SocketEvent *events, EventRegister *reg);
int num_polled);
typedef enum { typedef enum {
CONNECT_TARGET_NAME, CONNECT_TARGET_NAME,
@@ -531,7 +543,7 @@ int socket_recv(SocketManager *sm, SocketHandle handle,
int socket_send(SocketManager *sm, SocketHandle handle, int socket_send(SocketManager *sm, SocketHandle handle,
char *src, int len); char *src, int len);
void socket_close(SocketManager *sm, SocketHandle handle); int socket_close(SocketManager *sm, SocketHandle handle);
// Returns -1 on error, 0 if the socket was accepted // Returns -1 on error, 0 if the socket was accepted
// from the plaintext listener, or 1 if it was accepted // from the plaintext listener, or 1 if it was accepted
@@ -539,7 +551,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 *user); int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/byte_queue.h // src/byte_queue.h
@@ -663,6 +675,13 @@ int byte_queue_write_setmincap(ByteQueue *queue, uint32_t mincap);
// short hand for write_buf/memcpy/write_ack // short hand for write_buf/memcpy/write_ack
void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len); void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len);
// Write the result of the format into the queue
void byte_queue_write_fmt(ByteQueue *queue, const char *fmt, ...);
// Write the result of the format into the queue
void byte_queue_write_fmt2(ByteQueue *queue, const char *fmt,
va_list args);
// Returns the current offset inside the queue // Returns the current offset inside the queue
ByteQueueOffset byte_queue_offset(ByteQueue *queue); ByteQueueOffset byte_queue_offset(ByteQueue *queue);
@@ -724,6 +743,7 @@ typedef struct {
HTTP_ClientConnState state; HTTP_ClientConnState state;
ByteQueue input; ByteQueue input;
ByteQueue output; ByteQueue output;
HTTP_Response response;
} HTTP_ClientConn; } HTTP_ClientConn;
// Fields of this struct are private // Fields of this struct are private
@@ -781,31 +801,32 @@ int http_client_get_builder(HTTP_Client *client,
// Set the URL of the current request. This is the first // Set the URL of the current request. This is the first
// function of the request builder that the user must call. // function of the request builder that the user must call.
void http_request_builder_url(HTTP_RequestBuilder builder, String url); void http_request_builder_url(HTTP_RequestBuilder builder, HTTP_String url);
// After the URL, the user may set zero or more headers. // After the URL, the user may set zero or more headers.
void http_request_builder_header(HTTP_RequestBuilder builder, String str); void http_request_builder_header(HTTP_RequestBuilder builder, HTTP_String str);
// Append bytes to the request's body. You can call this // Append bytes to the request's body. You can call this
// any amount of times, as long as it's after having set // any amount of times, as long as it's after having set
// the URL. // the URL.
void http_request_builder_body(HTTP_RequestBuilder builder, String str); void http_request_builder_body(HTTP_RequestBuilder builder, HTTP_String str);
// Mark this request as complete. This invalidates the // Mark this request as complete. This invalidates the
// builder. // builder.
void http_request_builder_send(HTTP_RequestBuilder builder); // Returns 0 on success, -1 on error.
int http_request_builder_send(HTTP_RequestBuilder builder);
// List all low-level socket events the client is // Resets the event register with the list of descriptors
// waiting for such that the caller can call poll() // the client wants monitored. Returns 0 on success, -1 if
// with it. // the event register's capacity isn't large enough.
int http_client_register_events(HTTP_Client *client, int http_client_register_events(HTTP_Client *client,
struct pollfd *polled, int max_polled); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP client // I/O events to be triggered, so now the HTTP client
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
int http_client_process_events(HTTP_Client *client, int http_client_process_events(HTTP_Client *client,
struct pollfd *polled, int num_polled); EventRegister *reg);
// After some I/O events were processes, some responses // After some I/O events were processes, some responses
// may be availabe. This function returns one of the // may be availabe. This function returns one of the
@@ -875,6 +896,17 @@ typedef struct {
// Data being sent to the client // Data being sent to the client
ByteQueue output; ByteQueue output;
// Generation counter. This is used to invalidate
// response builders that refer to this connection.
uint16_t gen;
// This is set during the WAIT_XXX states or
// the FLUSHING state. When the connection
// completes flushing and no more bytes are
// in the output buffer, it frees the connection
// instead of turning it back to BUFFERING.
bool closing;
// When the state is WAIT_STATUS, WAIT_HEADER, // When the state is WAIT_STATUS, WAIT_HEADER,
// or WAIT_BODY, this contains the parsed version // or WAIT_BODY, this contains the parsed version
// of the buffered request. // of the buffered request.
@@ -890,6 +922,19 @@ typedef struct {
// scratch. // scratch.
ByteQueueOffset response_offset; ByteQueueOffset response_offset;
// When the first byte of the response content is
// written, before it are prepended special headers,
// including Content-Length and Connection. This
// offset points to the first byte that comes after
// the string "Content-Length: ".
ByteQueueOffset content_length_value_offset;
// Similarly to the previous field, this one points
// to the first byte of the body. This allows calculating
// the length of the response content byte subtracting
// it from the offset reached when the response is marked
// as done.
ByteQueueOffset content_length_offset;
} HTTP_ServerConn; } HTTP_ServerConn;
typedef struct { typedef struct {
@@ -944,7 +989,7 @@ 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,
String addr, Port port); HTTP_String addr, Port port);
// Enable listening for HTTPS requests at the specified // Enable listening for HTTPS requests at the specified
// interfact, using the specified certificate and key // interfact, using the specified certificate and key
@@ -962,17 +1007,17 @@ int http_server_add_certificate(HTTP_Server *server,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_server_wakeup(HTTP_Server *server); int http_server_wakeup(HTTP_Server *server);
// List all low-level socket events the server is // Resets the event register with the list of descriptors
// waiting for such that the caller can call poll() // the server wants monitored. Returns 0 on success, -1 if
// with it. // the event register's capacity isn't large enough.
int http_server_register_events(HTTP_Server *server, int http_server_register_events(HTTP_Server *server,
struct pollfd *polled, int max_polled); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP server // I/O events to be triggered, so now the HTTP server
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
int http_server_process_events(HTTP_Server *server, int http_server_process_events(HTTP_Server *server,
struct pollfd *polled, int num_polled); EventRegister *reg);
typedef struct { typedef struct {
HTTP_Server *server; HTTP_Server *server;
@@ -1000,7 +1045,7 @@ void http_response_builder_status(HTTP_ResponseBuilder builder, int status);
// Append a header to the response. This can only be // Append a header to the response. This can only be
// used after having set the status and before appending // used after having set the status and before appending
// to the body. // to the body.
void http_response_builder_header(HTTP_ResponseBuilder builder, String str); void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str);
// Append some bytes to the response's body // Append some bytes to the response's body
void http_response_builder_body(HTTP_ResponseBuilder builder, String str); void http_response_builder_body(HTTP_ResponseBuilder builder, String str);
+40
View File
@@ -217,6 +217,46 @@ void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len)
} }
} }
void byte_queue_write_fmt2(ByteQueue *queue,
const char *fmt, va_list args)
{
if (queue->flags & BYTE_QUEUE_ERROR)
return;
va_list args2;
va_copy(args2, args);
byte_queue_write_setmincap(queue, 128);
ByteView dst = byte_queue_write_buf(queue);
int len = vsnprintf(dst.ptr, dst.len, fmt, args);
if (len < 0) {
queue->flags |= BYTE_QUEUE_ERROR;
va_end(args2);
return;
}
if (len > dst.len) {
byte_queue_write_ack(queue, 0);
byte_queue_write_setmincap(queue, len+1);
dst = byte_queue_write_buf(queue);
vsnprintf(dst.ptr, dst.len, fmt, args2);
}
byte_queue_write_ack(queue, len);
va_end(args2);
}
void byte_queue_write_fmt(ByteQueue *queue,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
byte_queue_write_fmt2(queue, fmt, args);
va_end(args);
}
ByteQueueOffset byte_queue_offset(ByteQueue *queue) ByteQueueOffset byte_queue_offset(ByteQueue *queue)
{ {
if (queue->flags & BYTE_QUEUE_ERROR) if (queue->flags & BYTE_QUEUE_ERROR)
+7
View File
@@ -117,6 +117,13 @@ int byte_queue_write_setmincap(ByteQueue *queue, uint32_t mincap);
// short hand for write_buf/memcpy/write_ack // short hand for write_buf/memcpy/write_ack
void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len); void byte_queue_write(ByteQueue *queue, void *ptr, uint32_t len);
// Write the result of the format into the queue
void byte_queue_write_fmt(ByteQueue *queue, const char *fmt, ...);
// Write the result of the format into the queue
void byte_queue_write_fmt2(ByteQueue *queue, const char *fmt,
va_list args);
// Returns the current offset inside the queue // Returns the current offset inside the queue
ByteQueueOffset byte_queue_offset(ByteQueue *queue); ByteQueueOffset byte_queue_offset(ByteQueue *queue);
+26 -11
View File
@@ -1,4 +1,14 @@
void http_client_conn_init(HTTP_ClientConn *conn)
{
// TODO
}
void http_client_conn_free(HTTP_ClientConn *conn)
{
// TODO
}
int http_client_init(HTTP_Client *client) int http_client_init(HTTP_Client *client)
{ {
client->num_conns = 0; client->num_conns = 0;
@@ -35,22 +45,26 @@ int http_client_wakeup(HTTP_Client *client)
return 0; return 0;
} }
int http_client_get_builder(HTTP_Client *client, HTTP_RequestBuilder *builder) int http_client_get_builder(HTTP_Client *client,
HTTP_Response *response, HTTP_RequestBuilder *builder)
{ {
// TODO // TODO
} }
void http_request_builder_line(HTTP_RequestBuilder builder, xxxx) void http_request_builder_url(HTTP_RequestBuilder builder,
HTTP_String url)
{ {
// TODO // TODO
} }
void http_request_builder_header(HTTP_RequestBuilder builder, String str) void http_request_builder_header(HTTP_RequestBuilder builder,
HTTP_String str)
{ {
// TODO // TODO
} }
void http_request_builder_body(HTTP_RequestBuilder builder, String str) void http_request_builder_body(HTTP_RequestBuilder builder,
HTTP_String str)
{ {
// TODO // TODO
} }
@@ -61,18 +75,19 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
} }
int http_client_register_events(HTTP_Client *client, int http_client_register_events(HTTP_Client *client,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
return socket_manager_register_events( if (socket_manager_register_events(&client->sockets, reg) < 0)
&client->sockets, polled, max_polled); return -1;
return 0;
} }
int http_client_process_events(HTTP_Client *client, int http_client_process_events(HTTP_Client *client,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
SocketEvent events[HTTP_CLIENT_CAPACITY]; SocketEvent events[HTTP_CLIENT_CAPACITY];
int num_events = socket_manager_translate_events( int num_events = socket_manager_translate_events(
&client->sockets, polled, num_polled); &client->sockets, events, reg);
for (int i = 0; i < num_events; i++) { for (int i = 0; i < num_events; i++) {
@@ -92,9 +107,9 @@ int http_client_process_events(HTTP_Client *client,
} }
bool http_client_next_response(HTTP_Client *client, bool http_client_next_response(HTTP_Client *client,
HTTP_Response **response); HTTP_Response **response)
{ {
if (server->num_ready == 0) if (client->num_ready == 0)
return false; return false;
HTTP_ClientConn *conn = &client->conns[client->ready_head]; HTTP_ClientConn *conn = &client->conns[client->ready_head];
+11 -9
View File
@@ -20,6 +20,7 @@ typedef struct {
HTTP_ClientConnState state; HTTP_ClientConnState state;
ByteQueue input; ByteQueue input;
ByteQueue output; ByteQueue output;
HTTP_Response response;
} HTTP_ClientConn; } HTTP_ClientConn;
// Fields of this struct are private // Fields of this struct are private
@@ -77,31 +78,32 @@ int http_client_get_builder(HTTP_Client *client,
// Set the URL of the current request. This is the first // Set the URL of the current request. This is the first
// function of the request builder that the user must call. // function of the request builder that the user must call.
void http_request_builder_url(HTTP_RequestBuilder builder, String url); void http_request_builder_url(HTTP_RequestBuilder builder, HTTP_String url);
// After the URL, the user may set zero or more headers. // After the URL, the user may set zero or more headers.
void http_request_builder_header(HTTP_RequestBuilder builder, String str); void http_request_builder_header(HTTP_RequestBuilder builder, HTTP_String str);
// Append bytes to the request's body. You can call this // Append bytes to the request's body. You can call this
// any amount of times, as long as it's after having set // any amount of times, as long as it's after having set
// the URL. // the URL.
void http_request_builder_body(HTTP_RequestBuilder builder, String str); void http_request_builder_body(HTTP_RequestBuilder builder, HTTP_String str);
// Mark this request as complete. This invalidates the // Mark this request as complete. This invalidates the
// builder. // builder.
void http_request_builder_send(HTTP_RequestBuilder builder); // Returns 0 on success, -1 on error.
int http_request_builder_send(HTTP_RequestBuilder builder);
// List all low-level socket events the client is // Resets the event register with the list of descriptors
// waiting for such that the caller can call poll() // the client wants monitored. Returns 0 on success, -1 if
// with it. // the event register's capacity isn't large enough.
int http_client_register_events(HTTP_Client *client, int http_client_register_events(HTTP_Client *client,
struct pollfd *polled, int max_polled); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP client // I/O events to be triggered, so now the HTTP client
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
int http_client_process_events(HTTP_Client *client, int http_client_process_events(HTTP_Client *client,
struct pollfd *polled, int num_polled); EventRegister *reg);
// After some I/O events were processes, some responses // After some I/O events were processes, some responses
// may be availabe. This function returns one of the // may be availabe. This function returns one of the
+2
View File
@@ -11,6 +11,8 @@
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else #else
#include <limits.h>
#include <stdarg.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <poll.h> #include <poll.h>
+135 -30
View File
@@ -5,6 +5,7 @@ static void http_server_conn_init(HTTP_ServerConn *conn,
{ {
conn->state = HTTP_SERVER_CONN_BUFFERING; conn->state = HTTP_SERVER_CONN_BUFFERING;
conn->handle = handle; conn->handle = handle;
conn->closing = false;
byte_queue_init(&conn->input, input_buffer_limit); byte_queue_init(&conn->input, input_buffer_limit);
byte_queue_init(&conn->output, output_buffer_limit); byte_queue_init(&conn->output, output_buffer_limit);
} }
@@ -21,8 +22,10 @@ int http_server_init(HTTP_Server *server)
server->output_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;
server->conns[i].gen = 0;
}
server->num_ready = 0; server->num_ready = 0;
server->ready_head = 0; server->ready_head = 0;
@@ -58,7 +61,7 @@ void http_server_set_output_limit(HTTP_Server *server, uint32_t limit)
} }
int http_server_listen_tcp(HTTP_Server *server, int http_server_listen_tcp(HTTP_Server *server,
String addr, Port port) HTTP_String addr, Port port)
{ {
if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0) if (socket_manager_listen_tcp(&server->sockets, addr, port) < 0)
return -1; return -1;
@@ -66,8 +69,8 @@ int http_server_listen_tcp(HTTP_Server *server,
} }
int http_server_listen_tls(HTTP_Server *server, int http_server_listen_tls(HTTP_Server *server,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name) HTTP_String key_file_name)
{ {
if (socket_manager_listen_tls(&server->sockets, addr, if (socket_manager_listen_tls(&server->sockets, addr,
port, cert_file_name, key_file_name) < 0) port, cert_file_name, key_file_name) < 0)
@@ -92,9 +95,11 @@ int http_server_wakeup(HTTP_Server *server)
} }
int http_server_register_events(HTTP_Server *server, int http_server_register_events(HTTP_Server *server,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
return socket_manager_register_events(&server->sockets, polled, max_polled); if (socket_manager_register_events(&server->sockets, reg) < 0)
return -1;
return 0;
} }
// Look at the head of the input buffer to see if // Look at the head of the input buffer to see if
@@ -142,27 +147,11 @@ check_request_buffer(HTTP_Server *server, HTTP_ServerConn *conn)
} }
} }
bool http_server_next_request(HTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder)
{
if (server->num_ready == 0)
return false;
HTTP_ServerConn *conn = &server->conns[server->ready_head];
server->ready_head = (server->ready_head + 1) % HTTP_SERVER_CAPACITY;
server->num_ready--;
assert(conn->state == HTTP_SERVER_CONN_WAIT_STATUS);
*request = &conn->request;
*builder = (HTTP_ResponseBuilder) { server, conn - server->conns, conn->gen };
return true;
}
int http_server_process_events(HTTP_Server *server, int http_server_process_events(HTTP_Server *server,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
SocketEvent events[HTTP_SERVER_CAPACITY]; SocketEvent events[HTTP_SERVER_CAPACITY];
int num_events = socket_manager_translate_events(&server->sockets, polled, num_polled); int num_events = socket_manager_translate_events(&server->sockets, events, reg);
if (num_events < 0) if (num_events < 0)
return -1; return -1;
@@ -245,6 +234,22 @@ int http_server_process_events(HTTP_Server *server,
return 0; return 0;
} }
bool http_server_next_request(HTTP_Server *server,
HTTP_Request **request, HTTP_ResponseBuilder *builder)
{
if (server->num_ready == 0)
return false;
HTTP_ServerConn *conn = &server->conns[server->ready_head];
server->ready_head = (server->ready_head + 1) % HTTP_SERVER_CAPACITY;
server->num_ready--;
assert(conn->state == HTTP_SERVER_CONN_WAIT_STATUS);
*request = &conn->request;
*builder = (HTTP_ResponseBuilder) { server, conn - server->conns, conn->gen };
return true;
}
// Get a connection pointer from a response builder. // Get a connection pointer from a response builder.
// If the builder is invalid, returns NULL. // If the builder is invalid, returns NULL.
// Note that only connections in the responding states // Note that only connections in the responding states
@@ -261,17 +266,86 @@ builder_to_conn(HTTP_ResponseBuilder builder)
if (builder.index > HTTP_SERVER_CAPACITY) if (builder.index > HTTP_SERVER_CAPACITY)
return NULL; return NULL;
HTTP_ServerConn *conn = server->conns[builder.index]; HTTP_ServerConn *conn = &server->conns[builder.index];
if (builder.gen != conn->gen) if (builder.gen != conn->gen)
return NULL; return NULL;
return conn; return conn;
} }
static const char*
get_status_text(int code)
{
switch(code) {
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 208: return "Already Reported";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 306: return "Switch Proxy";
case 307: return "Temporary Redirect";
case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request-URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 418: return "I'm a teapot";
case 420: return "Enhance your calm";
case 422: return "Unprocessable Entity";
case 426: return "Upgrade Required";
case 429: return "Too many requests";
case 431: return "Request Header Fields Too Large";
case 449: return "Retry With";
case 451: return "Unavailable For Legal Reasons";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
case 509: return "Bandwidth Limit Exceeded";
}
return "???";
}
static void static void
write_status(HTTP_ServerConn *conn, int status) write_status(HTTP_ServerConn *conn, int status)
{ {
byte_queue_write(&conn->output, xxx); byte_queue_write_fmt(&conn->output,
"HTTP/1.1 %d %s\r\n",
status, get_status_text(status));
} }
void http_response_builder_status(HTTP_ResponseBuilder builder, int status) void http_response_builder_status(HTTP_ResponseBuilder builder, int status)
@@ -291,7 +365,7 @@ void http_response_builder_status(HTTP_ResponseBuilder builder, int status)
conn->state = HTTP_SERVER_CONN_WAIT_HEADER; conn->state = HTTP_SERVER_CONN_WAIT_HEADER;
} }
void http_response_builder_header(HTTP_ResponseBuilder builder, String str) void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str)
{ {
HTTP_ServerConn *conn = builder_to_conn(builder); HTTP_ServerConn *conn = builder_to_conn(builder);
if (conn == NULL) if (conn == NULL)
@@ -300,17 +374,48 @@ void http_response_builder_header(HTTP_ResponseBuilder builder, String str)
if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER) if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER)
return; return;
byte_queue_write(&conn->output, xxx); // TODO: Check that the header is valid
byte_queue_write(&conn->output, str.ptr, str.len);
byte_queue_write(&conn->output, "\r\n", 2);
} }
static void append_special_headers(HTTP_ServerConn *conn) static void append_special_headers(HTTP_ServerConn *conn)
{ {
// TODO HTTP_String s;
if (conn->closing) {
s = HTTP_STR("Connection: Close");
byte_queue_write(&conn->output, s.ptr, s.len);
} else {
s = HTTP_STR("Connection: Keep-Alive");
byte_queue_write(&conn->output, s.ptr, s.len);
}
s = HTTP_STR("Content-Length: ");
byte_queue_write(&conn->output, s.ptr, s.len);
conn->content_length_value_offset = byte_queue_offset(&conn->output);
#define TEN_SPACES " "
_Static_assert(sizeof(TEN_SPACES) == 10+1);
s = HTTP_STR(TEN_SPACES "\r\n");
byte_queue_write(&conn->output, s.ptr, s.len);
byte_queue_write(&conn->output, "\r\n", 2);
conn->content_length_offset = byte_queue_offset(&conn->output);
} }
static void patch_special_headers(HTTP_ServerConn *conn) static void patch_special_headers(HTTP_ServerConn *conn)
{ {
// TODO int content_length = byte_queue_size_from_offset(&conn->output, conn->content_length_offset);
char tmp[11];
int len = snprintf(tmp, sizeof(tmp), "%d", content_length);
assert(len > 0 && len < 11);
byte_queue_patch(&conn->output, conn->content_length_value_offset, tmp, len);
} }
void http_response_builder_body(HTTP_ResponseBuilder builder, String str) void http_response_builder_body(HTTP_ResponseBuilder builder, String str)
+31 -7
View File
@@ -49,6 +49,17 @@ typedef struct {
// Data being sent to the client // Data being sent to the client
ByteQueue output; ByteQueue output;
// Generation counter. This is used to invalidate
// response builders that refer to this connection.
uint16_t gen;
// This is set during the WAIT_XXX states or
// the FLUSHING state. When the connection
// completes flushing and no more bytes are
// in the output buffer, it frees the connection
// instead of turning it back to BUFFERING.
bool closing;
// When the state is WAIT_STATUS, WAIT_HEADER, // When the state is WAIT_STATUS, WAIT_HEADER,
// or WAIT_BODY, this contains the parsed version // or WAIT_BODY, this contains the parsed version
// of the buffered request. // of the buffered request.
@@ -64,6 +75,19 @@ typedef struct {
// scratch. // scratch.
ByteQueueOffset response_offset; ByteQueueOffset response_offset;
// When the first byte of the response content is
// written, before it are prepended special headers,
// including Content-Length and Connection. This
// offset points to the first byte that comes after
// the string "Content-Length: ".
ByteQueueOffset content_length_value_offset;
// Similarly to the previous field, this one points
// to the first byte of the body. This allows calculating
// the length of the response content byte subtracting
// it from the offset reached when the response is marked
// as done.
ByteQueueOffset content_length_offset;
} HTTP_ServerConn; } HTTP_ServerConn;
typedef struct { typedef struct {
@@ -118,7 +142,7 @@ 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,
String addr, Port port); HTTP_String addr, Port port);
// Enable listening for HTTPS requests at the specified // Enable listening for HTTPS requests at the specified
// interfact, using the specified certificate and key // interfact, using the specified certificate and key
@@ -136,17 +160,17 @@ int http_server_add_certificate(HTTP_Server *server,
// other threads can call this function to wake it up. // other threads can call this function to wake it up.
int http_server_wakeup(HTTP_Server *server); int http_server_wakeup(HTTP_Server *server);
// List all low-level socket events the server is // Resets the event register with the list of descriptors
// waiting for such that the caller can call poll() // the server wants monitored. Returns 0 on success, -1 if
// with it. // the event register's capacity isn't large enough.
int http_server_register_events(HTTP_Server *server, int http_server_register_events(HTTP_Server *server,
struct pollfd *polled, int max_polled); EventRegister *reg);
// The caller has waited for poll() to return and some // The caller has waited for poll() to return and some
// I/O events to be triggered, so now the HTTP server // I/O events to be triggered, so now the HTTP server
// can continue its buffering and flushing operations. // can continue its buffering and flushing operations.
int http_server_process_events(HTTP_Server *server, int http_server_process_events(HTTP_Server *server,
struct pollfd *polled, int num_polled); EventRegister *reg);
typedef struct { typedef struct {
HTTP_Server *server; HTTP_Server *server;
@@ -174,7 +198,7 @@ void http_response_builder_status(HTTP_ResponseBuilder builder, int status);
// Append a header to the response. This can only be // Append a header to the response. This can only be
// used after having set the status and before appending // used after having set the status and before appending
// to the body. // to the body.
void http_response_builder_header(HTTP_ResponseBuilder builder, String str); void http_response_builder_header(HTTP_ResponseBuilder builder, HTTP_String str);
// Append some bytes to the response's body // Append some bytes to the response's body
void http_response_builder_body(HTTP_ResponseBuilder builder, String str); void http_response_builder_body(HTTP_ResponseBuilder builder, String str);
+92 -59
View File
@@ -68,7 +68,7 @@ static int set_socket_blocking(NATIVE_SOCKET sock, bool value)
return 0; return 0;
} }
static NATIVE_SOCKET create_listen_socket(String addr, static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
Port port, bool reuse_addr, int backlog) Port port, bool reuse_addr, int backlog)
{ {
NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); NATIVE_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -169,7 +169,7 @@ void socket_manager_free(SocketManager *sm)
} }
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
String addr, Port port) HTTP_String addr, Port port)
{ {
if (sm->plain_sock != NATIVE_SOCKET_INVALID) if (sm->plain_sock != NATIVE_SOCKET_INVALID)
return -1; return -1;
@@ -184,8 +184,8 @@ int socket_manager_listen_tcp(SocketManager *sm,
} }
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name) HTTP_String key_file_name)
{ {
if (sm->secure_sock != NATIVE_SOCKET_INVALID) if (sm->secure_sock != NATIVE_SOCKET_INVALID)
return -1; return -1;
@@ -452,38 +452,41 @@ int socket_manager_wakeup(SocketManager *sm)
} }
static int socket_manager_register_events_nolock( static int socket_manager_register_events_nolock(
SocketManager *sm, struct pollfd *polled, int max_polled) SocketManager *sm, EventRegister *reg)
{ {
// The poll array must be able to hold descriptors // The poll array must be able to hold descriptors
// for a socket manager at full capacity. Note that // for a socket manager at full capacity. Note that
// other than having a number of connection sockets, // other than having a number of connection sockets,
// the manager also needs 2 for the listeners and // the manager also needs 2 for the listeners and
// one for the wakeup self-pipe. // one for the wakeup self-pipe.
if (max_polled < sm->max_used+3) if (reg->max_polled < sm->max_used+3)
return -1; return -1;
int num_polled = 0; reg->num_polled = 0;
polled[num_polled].fd = sm->wait_sock; reg->polled[reg->num_polled].fd = sm->wait_sock;
polled[num_polled].events = 0; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
// If the manager isn't at full capacity, monitor // If the manager isn't at full capacity, monitor
// the listener sockets for incoming connections. // the listener sockets for incoming connections.
if (sm->num_used < sm->max_used) { if (sm->num_used < sm->max_used) {
if (sm->plain_sock != NATIVE_SOCKET_INVALID) { if (sm->plain_sock != NATIVE_SOCKET_INVALID) {
polled[num_polled].fd = sm->plain_sock; reg->polled[reg->num_polled].fd = sm->plain_sock;
polled[num_polled].events = POLLIN; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
} }
if (sm->secure_sock != NATIVE_SOCKET_INVALID) { if (sm->secure_sock != NATIVE_SOCKET_INVALID) {
polled[num_polled].fd = sm->secure_sock; reg->polled[reg->num_polled].fd = sm->secure_sock;
polled[num_polled].events = POLLIN; reg->polled[reg->num_polled].events = POLLIN;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = NULL;
reg->num_polled++;
} }
} }
@@ -498,28 +501,25 @@ static int socket_manager_register_events_nolock(
continue; continue;
j++; j++;
if (s->state == SOCKET_STATE_DIED || s->state == SOCKET_STATE_ESTABLISHED_READY)
return 0;
if (s->events) { if (s->events) {
polled[num_polled].fd = s->sock; reg->polled[reg->num_polled].fd = s->sock;
polled[num_polled].events = s->events; reg->polled[reg->num_polled].events = s->events;
polled[num_polled].revents = 0; reg->polled[reg->num_polled].revents = 0;
num_polled++; reg->ptrs[reg->num_polled] = s;
reg->num_polled++;
} }
} }
return num_polled; return 0;
} }
int socket_manager_register_events(SocketManager *sm, int socket_manager_register_events(SocketManager *sm,
struct pollfd *polled, int max_polled) EventRegister *reg)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
int ret = socket_manager_register_events_nolock( int ret = socket_manager_register_events_nolock(sm, reg);
sm, polled, max_polled);
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
@@ -538,14 +538,14 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
} }
static int socket_manager_translate_events_nolock( static int socket_manager_translate_events_nolock(
SocketManager *sm, SocketEvent *events, int max_events, SocketManager *sm, SocketEvent *events,
struct pollfd *polled, int num_polled) EventRegister *reg)
{ {
int num_events = 0; int num_events = 0;
for (int i = 0; i < num_polled; i++) { for (int i = 0; i < reg->num_polled; i++) {
if (polled[i].fd == sm->plain_sock || if (reg->polled[i].fd == sm->plain_sock ||
polled[i].fd == sm->secure_sock) { reg->polled[i].fd == sm->secure_sock) {
// We only listen for input events from the listener // We only listen for input events from the listener
// if the socket pool isn't fool. This ensures that // if the socket pool isn't fool. This ensures that
@@ -561,7 +561,7 @@ static int socket_manager_translate_events_nolock(
// Determine whether the event came from // Determine whether the event came from
// the encrypted listener or not. // the encrypted listener or not.
bool secure = (polled[i].fd == sm->secure_sock); bool secure = (reg->polled[i].fd == sm->secure_sock);
Socket *s = sm->sockets; Socket *s = sm->sockets;
while (s->state != SOCKET_STATE_FREE) { while (s->state != SOCKET_STATE_FREE) {
@@ -569,7 +569,7 @@ static int socket_manager_translate_events_nolock(
assert(s - sm->sockets < + sm->max_used); assert(s - sm->sockets < + sm->max_used);
} }
NATIVE_SOCKET sock = accept(polled[i].fd, NULL, NULL); NATIVE_SOCKET sock = accept(reg->polled[i].fd, NULL, NULL);
if (sock == NATIVE_SOCKET_INVALID) if (sock == NATIVE_SOCKET_INVALID)
continue; continue;
@@ -592,12 +592,14 @@ static int socket_manager_translate_events_nolock(
sm->num_used++; sm->num_used++;
} else if (polled[i].fd == sm->wait_sock) { } else if (reg->polled[i].fd == sm->wait_sock) {
// TODO: consume // TODO: consume
} else { } else {
if (polled[i].revents)
Socket *s = reg->ptrs[i];
if (reg->polled[i].revents)
socket_update(s); socket_update(s);
} }
} }
@@ -608,14 +610,11 @@ static int socket_manager_translate_events_nolock(
continue; continue;
j++; j++;
if (num_events == max_events) if (s->state == SOCKET_STATE_DIED) {
break;
if (s->state == SOCKET_DIED) {
events[num_events++] = (SocketEvent) { events[num_events++] = (SocketEvent) {
SOCKET_EVENT_DISCONNECT, SOCKET_EVENT_DISCONNECT,
SOCKET_HANDE_INVALID, SOCKET_HANDLE_INVALID,
s->user s->user
}; };
@@ -628,7 +627,7 @@ static int socket_manager_translate_events_nolock(
if (s->num_addr > 1) if (s->num_addr > 1)
free(s->addrs); free(s->addrs);
} }
s->num_used--; sm->num_used--;
} else if (s->state == SOCKET_STATE_ESTABLISHED_READY) { } else if (s->state == SOCKET_STATE_ESTABLISHED_READY) {
events[num_events++] = (SocketEvent) { events[num_events++] = (SocketEvent) {
@@ -643,18 +642,16 @@ static int socket_manager_translate_events_nolock(
} }
int socket_manager_translate_events(SocketManager *sm, int socket_manager_translate_events(SocketManager *sm,
SocketEvent *events, int max_events, struct pollfd *polled, SocketEvent *events, EventRegister *reg)
int num_polled)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
socket_manager_translate_events_nolock( int ret = socket_manager_translate_events_nolock(sm, events, reg);
sm, events, max_events, polled, num_polled);
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
return 0; return ret;
} }
static int resolve_connect_targets(ConnectTarget *targets, static int resolve_connect_targets(ConnectTarget *targets,
@@ -666,7 +663,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
case CONNECT_TARGET_NAME: case CONNECT_TARGET_NAME:
{ {
char portstr[16]; char portstr[16];
int len = snprintf(portstr, sizeof(portstr), "%u", port); int len = snprintf(portstr, sizeof(portstr), "%u", targets[i].port);
if (len < 0 || len >= (int) sizeof(portstr)) if (len < 0 || len >= (int) sizeof(portstr))
return -1; return -1;
@@ -674,8 +671,14 @@ static int resolve_connect_targets(ConnectTarget *targets,
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
char hostname[1<<9]; // TODO: Is this a good length?
if (targets[i].name.len >= (int) sizeof(hostname))
return -1;
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
hostname[targets[i].name.len] = '\0';
struct addrinfo *res = NULL; struct addrinfo *res = NULL;
int ret = getaddrinfo(pending_connect->hostname, portstr, &hints, &res); int ret = getaddrinfo(hostname, portstr, &hints, &res);
if (ret != 0) if (ret != 0)
return -1; return -1;
@@ -692,7 +695,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
IPv6 ipv6 = *(IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr; IPv6 ipv6 = *(IPv6*) &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
if (num_resolved < max_resolved) { if (num_resolved < max_resolved) {
resolved[num_resolved].is_ipv4 = false; resolved[num_resolved].is_ipv4 = false;
resolved[num_resolved].ipv4 = ipv6; resolved[num_resolved].ipv6 = ipv6;
resolved[num_resolved].port = targets[i].port; resolved[num_resolved].port = targets[i].port;
num_resolved++; num_resolved++;
} }
@@ -723,6 +726,8 @@ static int resolve_connect_targets(ConnectTarget *targets,
return num_resolved; return num_resolved;
} }
#define MAX_CONNECT_TARGETS 16
int socket_connect(SocketManager *sm, int num_targets, int socket_connect(SocketManager *sm, int num_targets,
ConnectTarget *targets, bool secure, void *user) ConnectTarget *targets, bool secure, void *user)
{ {
@@ -759,10 +764,29 @@ int socket_connect(SocketManager *sm, int num_targets,
s->state = 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++; sm->num_used++;
return 0; return 0;
} }
static bool would_block(void)
{
#ifdef _WIN32
int err = WSAGetLastError();
return err == WSAEWOULDBLOCK;
#else
return errno == EAGAIN || errno == EWOULDBLOCK;
#endif
}
static bool interrupted(void)
{
#ifdef _WIN32
return false;
#else
return errno == EINTR;
#endif
}
static int socket_recv_nolock(SocketManager *sm, SocketHandle handle, static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
char *dst, int max) char *dst, int max)
{ {
@@ -840,14 +864,14 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
} }
if (!socket_secure(s)) { if (!is_secure(s)) {
int ret = send(s->sock, src, len, 0); int ret = send(s->sock, src, len, 0);
if (ret < 0) { if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; s->state = SOCKET_STATE_ESTABLISHED_WAIT;
s->events = POLLOUT; s->events = POLLOUT;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_DIED; s->state = SOCKET_STATE_DIED;
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -888,19 +912,25 @@ int socket_send(SocketManager *sm, SocketHandle handle,
return ret; return ret;
} }
void socket_close(SocketManager *sm, SocketHandle handle) int socket_close(SocketManager *sm, SocketHandle handle)
{ {
if (mutex_lock(&sm->mutex) < 0) if (mutex_lock(&sm->mutex) < 0)
return -1; return -1;
int ret;
Socket *s = handle_to_socket(sm, handle);
if (s == NULL)
ret = -1;
else {
// TODO: maybe we don't want to always set to SHUTDOWN. What if the socket is DIED for instance? // TODO: maybe we don't want to always set to SHUTDOWN. What if the socket is DIED for instance?
s->state = SOCKET_STATE_SHUTDOWN; s->state = SOCKET_STATE_SHUTDOWN;
s->events = 0; s->events = 0;
socket_update(s); socket_update(s);
}
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
return 0; return ret;
} }
int socket_is_secure(SocketManager *sm, SocketHandle handle) int socket_is_secure(SocketManager *sm, SocketHandle handle)
@@ -926,11 +956,14 @@ 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;
int ret;
Socket *s = handle_to_socket(sm, handle); Socket *s = handle_to_socket(sm, handle);
if (s == NULL) if (s == NULL)
ret = -1; ret = -1;
else else {
s->user = user; s->user = user;
ret = 0;
}
if (mutex_unlock(&sm->mutex) < 0) if (mutex_unlock(&sm->mutex) < 0)
return -1; return -1;
+23 -13
View File
@@ -221,7 +221,7 @@ void socket_manager_free(SocketManager *sm);
// can only be used once per manager. // can only be used once per manager.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tcp(SocketManager *sm, int socket_manager_listen_tcp(SocketManager *sm,
String addr, Port port); HTTP_String addr, Port port);
// Same as the previous function, but incoming // Same as the previous function, but incoming
// connections will be interpreted as TLS. You // connections will be interpreted as TLS. You
@@ -231,8 +231,8 @@ int socket_manager_listen_tcp(SocketManager *sm,
// and secure connections. // and secure connections.
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_listen_tls(SocketManager *sm, int socket_manager_listen_tls(SocketManager *sm,
String addr, Port port, String cert_file_name, HTTP_String addr, Port port, HTTP_String cert_file_name,
String key_file_name); HTTP_String key_file_name);
// If the socket manager was configures to accept // If the socket manager was configures to accept
// TLS connections, this adds additional certificates // TLS connections, this adds additional certificates
@@ -249,22 +249,32 @@ int socket_manager_add_certificate(SocketManager *sm,
// Returns 0 on success, -1 on error. // Returns 0 on success, -1 on error.
int socket_manager_wakeup(SocketManager *sm); int socket_manager_wakeup(SocketManager *sm);
// Writes to the polled array the list of sockets typedef struct {
// that the socket manager is monitoring and which void **ptrs;
// events associated to that socket. struct pollfd *polled;
// Returns the number of items written to the polled int num_polled;
// array. int max_polled;
} EventRegister;
// Resets the event register with the list of descriptors
// the socket manager wants monitored. Returns 0 on
// success, -1 if the event register's capacity isn't
// large enough.
int socket_manager_register_events(SocketManager *sm, int socket_manager_register_events(SocketManager *sm,
struct pollfd *polled, int max_polled); EventRegister *reg);
// After poll() is called on the previously registered // After poll() is called on the previously registered
// pollfd array and the revents fields are set, this // pollfd array and the revents fields are set, this
// function processes those events to produce higher-level // function processes those events to produce higher-level
// socket events. Returns the number of socket events // socket events. Returns the number of socket events
// written to the output array, or -1 on error. // written to the output array, or -1 on error.
//
// The maximum number of events this will write
// to the events array is equal to the numero of
// socket structs provided to the socket manager
// via the init function.
int socket_manager_translate_events(SocketManager *sm, int socket_manager_translate_events(SocketManager *sm,
SocketEvent *events, int max_events, struct pollfd *polled, SocketEvent *events, EventRegister *reg);
int num_polled);
typedef enum { typedef enum {
CONNECT_TARGET_NAME, CONNECT_TARGET_NAME,
@@ -295,7 +305,7 @@ int socket_recv(SocketManager *sm, SocketHandle handle,
int socket_send(SocketManager *sm, SocketHandle handle, int socket_send(SocketManager *sm, SocketHandle handle,
char *src, int len); char *src, int len);
void socket_close(SocketManager *sm, SocketHandle handle); int socket_close(SocketManager *sm, SocketHandle handle);
// Returns -1 on error, 0 if the socket was accepted // Returns -1 on error, 0 if the socket was accepted
// from the plaintext listener, or 1 if it was accepted // from the plaintext listener, or 1 if it was accepted
@@ -303,4 +313,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 *user); int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);