Add error codes
This commit is contained in:
@@ -107,6 +107,20 @@ void print_bytes(HTTP_String prefix, HTTP_String src)
|
|||||||
putc('\n', stream);
|
putc('\n', stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *http_strerror(int code)
|
||||||
|
{
|
||||||
|
switch (code) {
|
||||||
|
case HTTP_OK: return "No error";
|
||||||
|
case HTTP_ERROR_UNSPECIFIED: return "Unspecified error";
|
||||||
|
case HTTP_ERROR_OOM: return "Out of memory";
|
||||||
|
case HTTP_ERROR_BADURL: return "Invalid URL";
|
||||||
|
case HTTP_ERROR_REQLIMIT: return "Parallel request limit reached";
|
||||||
|
case HTTP_ERROR_BADHANDLE: return "Invalid handle";
|
||||||
|
case HTTP_ERROR_NOTLS: return "TLS support not built-in";
|
||||||
|
}
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/parse.c
|
// src/parse.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1702,58 +1716,6 @@ int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// src/thread.c
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int mutex_init(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
InitializeCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_init(mutex, NULL))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_free(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
DeleteCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_destroy(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_lock(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
EnterCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_lock(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_unlock(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
LeaveCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_unlock(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/secure_context.c
|
// src/secure_context.c
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -2008,7 +1970,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
if (WSAStartup(wVersionRequested, &wsaData))
|
if (WSAStartup(wVersionRequested, &wsaData))
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (sock == INVALID_SOCKET && *global_cleanup)
|
if (sock == INVALID_SOCKET && *global_cleanup)
|
||||||
@@ -2018,7 +1980,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
if (sock == INVALID_SOCKET) {
|
if (sock == INVALID_SOCKET) {
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to loopback address with port 0 (dynamic port assignment)
|
// Bind to loopback address with port 0 (dynamic port assignment)
|
||||||
@@ -2033,21 +1995,21 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) {
|
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Set socket to non-blocking mode
|
// Optional: Set socket to non-blocking mode
|
||||||
@@ -2057,20 +2019,20 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
*a = sock;
|
*a = sock;
|
||||||
*b = sock;
|
*b = sock;
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
#else
|
#else
|
||||||
*global_cleanup = false;
|
*global_cleanup = false;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
if (pipe(fds) < 0)
|
if (pipe(fds) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
*a = fds[0];
|
*a = fds[0];
|
||||||
*b = fds[1];
|
*b = fds[1];
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2079,20 +2041,20 @@ static int set_socket_blocking(NATIVE_SOCKET sock, bool value)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
u_long mode = !value;
|
u_long mode = !value;
|
||||||
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int flags = fcntl(sock, F_GETFL, 0);
|
int flags = fcntl(sock, F_GETFL, 0);
|
||||||
if (flags < 0)
|
if (flags < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
if (value) flags &= ~O_NONBLOCK;
|
if (value) flags &= ~O_NONBLOCK;
|
||||||
else flags |= O_NONBLOCK;
|
else flags |= O_NONBLOCK;
|
||||||
if (fcntl(sock, F_SETFL, flags) < 0)
|
if (fcntl(sock, F_SETFL, flags) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
|
static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
|
||||||
@@ -2162,13 +2124,15 @@ static void close_socket_pair(NATIVE_SOCKET a, NATIVE_SOCKET b)
|
|||||||
int socket_manager_init(SocketManager *sm, Socket *socks,
|
int socket_manager_init(SocketManager *sm, Socket *socks,
|
||||||
int num_socks)
|
int num_socks)
|
||||||
{
|
{
|
||||||
if (mutex_init(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
sm->plain_sock = NATIVE_SOCKET_INVALID;
|
sm->plain_sock = NATIVE_SOCKET_INVALID;
|
||||||
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
||||||
if (create_socket_pair(&sm->wait_sock, &sm->signal_sock,
|
|
||||||
&sm->global_cleanup) < 0)
|
int ret = create_socket_pair(
|
||||||
return -1;
|
&sm->wait_sock,
|
||||||
|
&sm->signal_sock,
|
||||||
|
&sm->global_cleanup);
|
||||||
|
if (ret < 0) return ret;
|
||||||
|
|
||||||
sm->at_least_one_secure_connect = false;
|
sm->at_least_one_secure_connect = false;
|
||||||
|
|
||||||
sm->num_used = 0;
|
sm->num_used = 0;
|
||||||
@@ -2179,7 +2143,7 @@ int socket_manager_init(SocketManager *sm, Socket *socks,
|
|||||||
socks[i].state = SOCKET_STATE_FREE;
|
socks[i].state = SOCKET_STATE_FREE;
|
||||||
socks[i].gen = 1;
|
socks[i].gen = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_manager_free(SocketManager *sm)
|
void socket_manager_free(SocketManager *sm)
|
||||||
@@ -2202,8 +2166,6 @@ void socket_manager_free(SocketManager *sm)
|
|||||||
if (sm->global_cleanup)
|
if (sm->global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mutex_free(&sm->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_listen_tcp(SocketManager *sm,
|
int socket_manager_listen_tcp(SocketManager *sm,
|
||||||
@@ -2211,13 +2173,13 @@ int socket_manager_listen_tcp(SocketManager *sm,
|
|||||||
bool reuse_addr)
|
bool reuse_addr)
|
||||||
{
|
{
|
||||||
if (sm->plain_sock != NATIVE_SOCKET_INVALID)
|
if (sm->plain_sock != NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
||||||
if (sm->plain_sock == NATIVE_SOCKET_INVALID)
|
if (sm->plain_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_listen_tls(SocketManager *sm,
|
int socket_manager_listen_tls(SocketManager *sm,
|
||||||
@@ -2225,35 +2187,39 @@ int socket_manager_listen_tls(SocketManager *sm,
|
|||||||
bool reuse_addr, HTTP_String cert_file,
|
bool reuse_addr, HTTP_String cert_file,
|
||||||
HTTP_String key_file)
|
HTTP_String key_file)
|
||||||
{
|
{
|
||||||
|
#ifndef HTTPS_ENABLED
|
||||||
|
return HTTP_ERROR_NOTLS;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sm->secure_sock != NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock != NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
||||||
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
if (server_secure_context_init(&sm->server_secure_context,
|
if (server_secure_context_init(&sm->server_secure_context,
|
||||||
cert_file, key_file) < 0) {
|
cert_file, key_file) < 0) {
|
||||||
CLOSE_NATIVE_SOCKET(sm->secure_sock);
|
CLOSE_NATIVE_SOCKET(sm->secure_sock);
|
||||||
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_add_certificate(SocketManager *sm,
|
int socket_manager_add_certificate(SocketManager *sm,
|
||||||
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
||||||
{
|
{
|
||||||
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
int ret = server_secure_context_add_certificate(
|
int ret = server_secure_context_add_certificate(
|
||||||
&sm->server_secure_context, domain, cert_file, key_file);
|
&sm->server_secure_context, domain, cert_file, key_file);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_secure(Socket *s)
|
static bool is_secure(Socket *s)
|
||||||
@@ -2649,27 +2615,21 @@ static void socket_update(Socket *s)
|
|||||||
|
|
||||||
int socket_manager_wakeup(SocketManager *sm)
|
int socket_manager_wakeup(SocketManager *sm)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
// NOTE: It's assumed send/write operate atomically
|
||||||
return -1;
|
// on The descriptor.
|
||||||
|
|
||||||
// Send a byte through the signal socket to wake up any thread
|
|
||||||
// blocked on poll() with the wait socket
|
|
||||||
char byte = 1;
|
char byte = 1;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (send(sm->signal_sock, &byte, 1, 0) < 0)
|
if (send(sm->signal_sock, &byte, 1, 0) < 0)
|
||||||
ret = -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
#else
|
#else
|
||||||
if (write(sm->signal_sock, &byte, 1) < 0)
|
if (write(sm->signal_sock, &byte, 1) < 0)
|
||||||
ret = -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
#endif
|
#endif
|
||||||
|
return HTTP_OK;
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void socket_manager_register_events_nolock(
|
void socket_manager_register_events(
|
||||||
SocketManager *sm, EventRegister *reg)
|
SocketManager *sm, EventRegister *reg)
|
||||||
{
|
{
|
||||||
reg->num_polled = 0;
|
reg->num_polled = 0;
|
||||||
@@ -2729,19 +2689,6 @@ static void socket_manager_register_events_nolock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_register_events(SocketManager *sm,
|
|
||||||
EventRegister *reg)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
socket_manager_register_events_nolock(sm, reg);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SocketHandle
|
static SocketHandle
|
||||||
socket_to_handle(SocketManager *sm, Socket *s)
|
socket_to_handle(SocketManager *sm, Socket *s)
|
||||||
{
|
{
|
||||||
@@ -2759,7 +2706,7 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
|
|||||||
return &sm->sockets[idx];
|
return &sm->sockets[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_manager_translate_events_nolock(
|
int socket_manager_translate_events(
|
||||||
SocketManager *sm, SocketEvent *events,
|
SocketManager *sm, SocketEvent *events,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
@@ -2882,19 +2829,6 @@ static int socket_manager_translate_events_nolock(
|
|||||||
return num_events;
|
return num_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_translate_events(SocketManager *sm,
|
|
||||||
SocketEvent *events, EventRegister *reg)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_manager_translate_events_nolock(sm, events, reg);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int resolve_connect_targets(ConnectTarget *targets,
|
static int resolve_connect_targets(ConnectTarget *targets,
|
||||||
int num_targets, AddressAndPort *resolved, int max_resolved)
|
int num_targets, AddressAndPort *resolved, int max_resolved)
|
||||||
{
|
{
|
||||||
@@ -2915,7 +2849,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1);
|
RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1);
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
free_addr_list(resolved, num_resolved);
|
free_addr_list(resolved, num_resolved);
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
}
|
}
|
||||||
name->refs = 0;
|
name->refs = 0;
|
||||||
memcpy(name->data, targets[i].name.ptr, targets[i].name.len);
|
memcpy(name->data, targets[i].name.ptr, targets[i].name.len);
|
||||||
@@ -2925,7 +2859,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
// 512 bytes is more than enough for a DNS hostname (max 253 chars)
|
// 512 bytes is more than enough for a DNS hostname (max 253 chars)
|
||||||
char hostname[1<<9];
|
char hostname[1<<9];
|
||||||
if (targets[i].name.len >= (int) sizeof(hostname))
|
if (targets[i].name.len >= (int) sizeof(hostname))
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
|
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
|
||||||
hostname[targets[i].name.len] = '\0';
|
hostname[targets[i].name.len] = '\0';
|
||||||
#endif
|
#endif
|
||||||
@@ -2937,7 +2871,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
free(name);
|
free(name);
|
||||||
#endif
|
#endif
|
||||||
free_addr_list(resolved, num_resolved);
|
free_addr_list(resolved, num_resolved);
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||||
@@ -3009,17 +2943,17 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
ConnectTarget *targets, bool secure, void *user)
|
ConnectTarget *targets, bool secure, void *user)
|
||||||
{
|
{
|
||||||
if (sm->num_used == sm->max_used)
|
if (sm->num_used == sm->max_used)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
#ifdef HTTPS_ENABLED
|
#ifdef HTTPS_ENABLED
|
||||||
if (!sm->at_least_one_secure_connect) {
|
if (!sm->at_least_one_secure_connect) {
|
||||||
if (client_secure_context_init(&sm->client_secure_context) < 0)
|
if (client_secure_context_init(&sm->client_secure_context) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
sm->at_least_one_secure_connect = true;
|
sm->at_least_one_secure_connect = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (secure)
|
if (secure)
|
||||||
return -1;
|
return HTTP_ERROR_NOTLS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AddressAndPort resolved[MAX_CONNECT_TARGETS];
|
AddressAndPort resolved[MAX_CONNECT_TARGETS];
|
||||||
@@ -3027,7 +2961,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
targets, num_targets, resolved, MAX_CONNECT_TARGETS);
|
targets, num_targets, resolved, MAX_CONNECT_TARGETS);
|
||||||
|
|
||||||
if (num_resolved <= 0)
|
if (num_resolved <= 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->state != SOCKET_STATE_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
@@ -3044,7 +2978,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
s->next_addr = 0;
|
s->next_addr = 0;
|
||||||
s->addrs = malloc(num_resolved * sizeof(AddressAndPort));
|
s->addrs = malloc(num_resolved * sizeof(AddressAndPort));
|
||||||
if (s->addrs == NULL)
|
if (s->addrs == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
for (int i = 0; i < num_resolved; i++)
|
for (int i = 0; i < num_resolved; i++)
|
||||||
s->addrs[i] = resolved[i];
|
s->addrs[i] = resolved[i];
|
||||||
}
|
}
|
||||||
@@ -3062,7 +2996,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
sm->num_used++;
|
sm->num_used++;
|
||||||
|
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool would_block(void)
|
static bool would_block(void)
|
||||||
@@ -3084,7 +3018,7 @@ static bool interrupted(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
|
int socket_recv(SocketManager *sm, SocketHandle handle,
|
||||||
char *dst, int max)
|
char *dst, int max)
|
||||||
{
|
{
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
@@ -3135,20 +3069,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_recv(SocketManager *sm, SocketHandle handle,
|
int socket_send(SocketManager *sm, SocketHandle handle,
|
||||||
char *dst, int max)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_recv_nolock(sm, handle, dst, max);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
|
|
||||||
char *src, int len)
|
char *src, int len)
|
||||||
{
|
{
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
@@ -3196,95 +3117,48 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_send(SocketManager *sm, SocketHandle handle,
|
void socket_close(SocketManager *sm, SocketHandle handle)
|
||||||
char *src, int len)
|
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_send_nolock(sm, handle, src, len);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socket_close(SocketManager *sm, SocketHandle handle)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
ret = -1;
|
return;
|
||||||
else {
|
|
||||||
// Only transition to SHUTDOWN if socket is not already DIED
|
|
||||||
if (s->state != SOCKET_STATE_DIED) {
|
if (s->state != SOCKET_STATE_DIED) {
|
||||||
UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
|
UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
|
||||||
s->events = 0;
|
s->events = 0;
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle)
|
bool socket_is_secure(SocketManager *sm, SocketHandle handle)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
|
|
||||||
int ret;
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
ret = -1;
|
return false;
|
||||||
else
|
return is_secure(s);
|
||||||
ret = is_secure(s);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
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;
|
return;
|
||||||
else {
|
|
||||||
s->user = user;
|
s->user = user;
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool socket_ready(SocketManager *sm, SocketHandle handle)
|
bool socket_ready(SocketManager *sm, SocketHandle handle)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0) {
|
|
||||||
assert(0); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
if (s && s->events == 0 && s->state != SOCKET_STATE_DIED) {
|
if (s == NULL)
|
||||||
ready = true;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0) {
|
if (s->events == 0 && s->state != SOCKET_STATE_DIED)
|
||||||
assert(0); // TODO
|
return true;
|
||||||
}
|
|
||||||
return ready;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -3772,10 +3646,8 @@ int http_client_init(HTTP_Client *client)
|
|||||||
client->num_ready = 0;
|
client->num_ready = 0;
|
||||||
client->ready_head = 0;
|
client->ready_head = 0;
|
||||||
|
|
||||||
if (socket_manager_init(&client->sockets,
|
return socket_manager_init(&client->sockets,
|
||||||
client->socket_pool, HTTP_CLIENT_CAPACITY) < 0)
|
client->socket_pool, HTTP_CLIENT_CAPACITY);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_client_free(HTTP_Client *client)
|
void http_client_free(HTTP_Client *client)
|
||||||
@@ -3807,9 +3679,7 @@ void http_client_set_output_limit(HTTP_Client *client, uint32_t limit)
|
|||||||
|
|
||||||
int http_client_wakeup(HTTP_Client *client)
|
int http_client_wakeup(HTTP_Client *client)
|
||||||
{
|
{
|
||||||
if (socket_manager_wakeup(&client->sockets) < 0)
|
return socket_manager_wakeup(&client->sockets);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a connection pointer from a request builder.
|
// Get a connection pointer from a request builder.
|
||||||
@@ -3985,7 +3855,7 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
char *url_copy = malloc(url.len);
|
char *url_copy = malloc(url.len);
|
||||||
if (url_copy == NULL) {
|
if (url_copy == NULL) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_OOM;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(url_copy, url.ptr, url.len);
|
memcpy(url_copy, url.ptr, url.len);
|
||||||
@@ -3996,14 +3866,14 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
// Parse the copied URL (all url.* pointers will reference url_buffer)
|
// Parse the copied URL (all url.* pointers will reference url_buffer)
|
||||||
if (http_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) {
|
if (http_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!http_streq(conn->url.scheme, HTTP_STR("http")) &&
|
if (!http_streq(conn->url.scheme, HTTP_STR("http")) &&
|
||||||
!http_streq(conn->url.scheme, HTTP_STR("https"))) {
|
!http_streq(conn->url.scheme, HTTP_STR("https"))) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4011,7 +3881,9 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
if (conn->url.path.len == 0)
|
if (conn->url.path.len == 0)
|
||||||
byte_queue_write(&conn->output, "/", 1);
|
byte_queue_write(&conn->output, "/", 1);
|
||||||
else
|
else
|
||||||
byte_queue_write(&conn->output, conn->url.path.ptr, conn->url.path.len);
|
byte_queue_write(&conn->output,
|
||||||
|
conn->url.path.ptr,
|
||||||
|
conn->url.path.len);
|
||||||
|
|
||||||
// Write query string
|
// Write query string
|
||||||
HTTP_String query = conn->url.query;
|
HTTP_String query = conn->url.query;
|
||||||
@@ -4103,47 +3975,45 @@ void http_request_builder_body(HTTP_RequestBuilder builder,
|
|||||||
byte_queue_write(&conn->output, str.ptr, str.len);
|
byte_queue_write(&conn->output, str.ptr, str.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static ConnectTarget url_to_connect_target(HTTP_URL url)
|
||||||
url_to_connect_target(HTTP_URL url,
|
|
||||||
ConnectTarget *target)
|
|
||||||
{
|
{
|
||||||
HTTP_Authority authority = url.authority;
|
HTTP_Authority authority = url.authority;
|
||||||
|
|
||||||
|
ConnectTarget target;
|
||||||
if (authority.port < 1) {
|
if (authority.port < 1) {
|
||||||
if (http_streq(url.scheme, HTTP_STR("https")))
|
if (http_streq(url.scheme, HTTP_STR("https")))
|
||||||
target->port = 443;
|
target.port = 443;
|
||||||
else
|
else
|
||||||
target->port = 80;
|
target.port = 80;
|
||||||
} else {
|
} else {
|
||||||
target->port = authority.port;
|
target.port = authority.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up target based on host type
|
|
||||||
if (authority.host.mode == HTTP_HOST_MODE_NAME) {
|
if (authority.host.mode == HTTP_HOST_MODE_NAME) {
|
||||||
target->type = CONNECT_TARGET_NAME;
|
target.type = CONNECT_TARGET_NAME;
|
||||||
target->name = authority.host.name;
|
target.name = authority.host.name;
|
||||||
} else if (authority.host.mode == HTTP_HOST_MODE_IPV4) {
|
} else if (authority.host.mode == HTTP_HOST_MODE_IPV4) {
|
||||||
target->type = CONNECT_TARGET_IPV4;
|
target.type = CONNECT_TARGET_IPV4;
|
||||||
target->ipv4 = authority.host.ipv4;
|
target.ipv4 = authority.host.ipv4;
|
||||||
} else if (authority.host.mode == HTTP_HOST_MODE_IPV6) {
|
} else if (authority.host.mode == HTTP_HOST_MODE_IPV6) {
|
||||||
target->type = CONNECT_TARGET_IPV6;
|
target.type = CONNECT_TARGET_IPV6;
|
||||||
target->ipv6 = authority.host.ipv6;
|
target.ipv6 = authority.host.ipv6;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
HTTP_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_builder_send(HTTP_RequestBuilder builder)
|
int http_request_builder_send(HTTP_RequestBuilder builder)
|
||||||
{
|
{
|
||||||
HTTP_Client *client = builder.client;
|
HTTP_Client *client = builder.client;
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_REQLIMIT;
|
||||||
|
|
||||||
HTTP_ClientConn *conn = request_builder_to_conn(builder);
|
HTTP_ClientConn *conn = request_builder_to_conn(builder);
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_BADHANDLE;
|
||||||
|
|
||||||
if (conn->state == HTTP_CLIENT_CONN_COMPLETE)
|
if (conn->state == HTTP_CLIENT_CONN_COMPLETE)
|
||||||
goto error; // Early completion due to an error
|
goto error; // Early completion due to an error
|
||||||
@@ -4160,17 +4030,14 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
|
|||||||
if (byte_queue_error(&conn->output))
|
if (byte_queue_error(&conn->output))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ConnectTarget target;
|
ConnectTarget target = url_to_connect_target(conn->url);
|
||||||
if (url_to_connect_target(conn->url, &target) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
bool secure = http_streq(conn->url.scheme, HTTP_STR("https"));
|
bool secure = http_streq(conn->url.scheme, HTTP_STR("https"));
|
||||||
if (socket_connect(&client->sockets, 1, &target, secure, conn) < 0)
|
if (socket_connect(&client->sockets, 1, &target, secure, conn) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
conn->state = HTTP_CLIENT_CONN_FLUSHING;
|
conn->state = HTTP_CLIENT_CONN_FLUSHING;
|
||||||
conn->gen++;
|
conn->gen++;
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
conn->state = HTTP_CLIENT_CONN_FREE;
|
conn->state = HTTP_CLIENT_CONN_FREE;
|
||||||
@@ -4178,7 +4045,7 @@ error:
|
|||||||
byte_queue_free(&conn->input);
|
byte_queue_free(&conn->input);
|
||||||
byte_queue_free(&conn->output);
|
byte_queue_free(&conn->output);
|
||||||
client->num_conns--;
|
client->num_conns--;
|
||||||
return -1;
|
return conn->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_one_cookie(HTTP_CookieJar *cookie_jar,
|
static void save_one_cookie(HTTP_CookieJar *cookie_jar,
|
||||||
@@ -4251,22 +4118,20 @@ static void save_cookies(HTTP_CookieJar *cookie_jar,
|
|||||||
save_one_cookie(cookie_jar, headers[i], domain, path);
|
save_one_cookie(cookie_jar, headers[i], domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_register_events(HTTP_Client *client,
|
void http_client_register_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
if (socket_manager_register_events(&client->sockets, reg) < 0)
|
socket_manager_register_events(&client->sockets, reg);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_process_events(HTTP_Client *client,
|
int http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
||||||
int num_events = socket_manager_translate_events(
|
int ret = socket_manager_translate_events(&client->sockets, events, reg);
|
||||||
&client->sockets, events, reg);
|
if (ret < 0)
|
||||||
if (num_events < 0)
|
return ret;
|
||||||
return -1;
|
int num_events = ret;
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -4389,11 +4254,11 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
HTTP_Response **response, void **user)
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
if (client->num_ready == 0)
|
if (client->num_ready == 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -4404,13 +4269,13 @@ bool http_client_next_response(HTTP_Client *client,
|
|||||||
|
|
||||||
assert(conn->state == HTTP_CLIENT_CONN_COMPLETE);
|
assert(conn->state == HTTP_CLIENT_CONN_COMPLETE);
|
||||||
|
|
||||||
if (conn->result == 0) {
|
*result = conn->result;
|
||||||
|
*user = conn->user;
|
||||||
|
if (conn->result == HTTP_OK) {
|
||||||
*response = &conn->response;
|
*response = &conn->response;
|
||||||
} else {
|
} else {
|
||||||
assert(conn->result == -1);
|
|
||||||
*response = NULL;
|
*response = NULL;
|
||||||
}
|
}
|
||||||
*user = conn->user;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -4446,32 +4311,29 @@ void http_free_response(HTTP_Response *response)
|
|||||||
#define POLL poll
|
#define POLL poll
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int http_client_wait_response(HTTP_Client *client, HTTP_Response **response, void **user)
|
int http_client_wait_response(HTTP_Client *client,
|
||||||
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
void *ptrs[HTTP_CLIENT_POLL_CAPACITY];
|
void *ptrs[HTTP_CLIENT_POLL_CAPACITY];
|
||||||
struct pollfd polled[HTTP_CLIENT_POLL_CAPACITY];
|
struct pollfd polled[HTTP_CLIENT_POLL_CAPACITY];
|
||||||
|
|
||||||
EventRegister reg = {
|
EventRegister reg = { ptrs, polled, 0 };
|
||||||
.ptrs=ptrs,
|
http_client_register_events(client, ®);
|
||||||
.polled=polled,
|
|
||||||
.num_polled=0,
|
|
||||||
.max_polled=HTTP_CLIENT_POLL_CAPACITY,
|
|
||||||
};
|
|
||||||
if (http_client_register_events(client, ®) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
if (http_client_process_events(client, ®) < 0)
|
int ret = http_client_process_events(client, ®);
|
||||||
return -1;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (http_client_next_response(client, response, user))
|
if (http_client_next_response(client, result, user, response))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -4513,10 +4375,8 @@ int http_server_init(HTTP_Server *server)
|
|||||||
server->num_ready = 0;
|
server->num_ready = 0;
|
||||||
server->ready_head = 0;
|
server->ready_head = 0;
|
||||||
|
|
||||||
if (socket_manager_init(&server->sockets,
|
return socket_manager_init(&server->sockets,
|
||||||
server->socket_pool, HTTP_SERVER_CAPACITY) < 0)
|
server->socket_pool, HTTP_SERVER_CAPACITY);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_server_free(HTTP_Server *server)
|
void http_server_free(HTTP_Server *server)
|
||||||
@@ -4561,45 +4421,35 @@ void http_server_set_backlog(HTTP_Server *server, int backlog)
|
|||||||
int http_server_listen_tcp(HTTP_Server *server,
|
int http_server_listen_tcp(HTTP_Server *server,
|
||||||
HTTP_String addr, Port port)
|
HTTP_String addr, Port port)
|
||||||
{
|
{
|
||||||
if (socket_manager_listen_tcp(&server->sockets, addr,
|
return socket_manager_listen_tcp(&server->sockets,
|
||||||
port, server->backlog, server->reuse_addr) < 0)
|
addr, port, server->backlog, server->reuse_addr);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_listen_tls(HTTP_Server *server,
|
int http_server_listen_tls(HTTP_Server *server,
|
||||||
HTTP_String addr, Port port, HTTP_String cert_file_name,
|
HTTP_String addr, Port port, HTTP_String cert_file_name,
|
||||||
HTTP_String key_file_name)
|
HTTP_String key_file_name)
|
||||||
{
|
{
|
||||||
if (socket_manager_listen_tls(&server->sockets, addr,
|
return socket_manager_listen_tls(&server->sockets,
|
||||||
port, server->backlog, server->reuse_addr,
|
addr, port, server->backlog, server->reuse_addr,
|
||||||
cert_file_name, key_file_name) < 0)
|
cert_file_name, key_file_name);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_add_certificate(HTTP_Server *server,
|
int http_server_add_certificate(HTTP_Server *server,
|
||||||
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
||||||
{
|
{
|
||||||
if (socket_manager_add_certificate(&server->sockets,
|
return socket_manager_add_certificate(&server->sockets,
|
||||||
domain, cert_file, key_file) < 0)
|
domain, cert_file, key_file);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_wakeup(HTTP_Server *server)
|
int http_server_wakeup(HTTP_Server *server)
|
||||||
{
|
{
|
||||||
if (socket_manager_wakeup(&server->sockets) < 0)
|
return socket_manager_wakeup(&server->sockets);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_register_events(HTTP_Server *server,
|
void http_server_register_events(HTTP_Server *server,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
if (socket_manager_register_events(&server->sockets, reg) < 0)
|
socket_manager_register_events(&server->sockets, reg);
|
||||||
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
|
||||||
@@ -4712,9 +4562,10 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_SERVER_CAPACITY];
|
SocketEvent events[HTTP_SERVER_CAPACITY];
|
||||||
int num_events = socket_manager_translate_events(&server->sockets, events, reg);
|
int ret = socket_manager_translate_events(&server->sockets, events, reg);
|
||||||
if (num_events < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return ret;
|
||||||
|
int num_events = ret;
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -4756,7 +4607,7 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
@@ -4775,6 +4626,30 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int http_server_wait_request(HTTP_Server *server,
|
||||||
|
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
void *ptrs[HTTP_SERVER_POLL_CAPACITY];
|
||||||
|
struct pollfd polled[HTTP_SERVER_POLL_CAPACITY];
|
||||||
|
|
||||||
|
EventRegister reg = { ptrs, polled, 0 };
|
||||||
|
http_server_register_events(server, ®);
|
||||||
|
|
||||||
|
if (reg.num_polled > 0)
|
||||||
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
|
int ret = http_server_process_events(server, ®);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (http_server_next_request(server, request, builder))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HTTP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -41,6 +40,29 @@
|
|||||||
// src/basic.h
|
// src/basic.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum {
|
||||||
|
|
||||||
|
HTTP_OK = 0,
|
||||||
|
|
||||||
|
// A generic error occurred
|
||||||
|
HTTP_ERROR_UNSPECIFIED = -1,
|
||||||
|
|
||||||
|
// Out of memory
|
||||||
|
HTTP_ERROR_OOM = -2,
|
||||||
|
|
||||||
|
// Invalid URL
|
||||||
|
HTTP_ERROR_BADURL = -3,
|
||||||
|
|
||||||
|
// Parallel request limit reached
|
||||||
|
HTTP_ERROR_REQLIMIT = -4,
|
||||||
|
|
||||||
|
// Invalid handle
|
||||||
|
HTTP_ERROR_BADHANDLE = -5,
|
||||||
|
|
||||||
|
// TLS support not built-in
|
||||||
|
HTTP_ERROR_NOTLS = -6,
|
||||||
|
};
|
||||||
|
|
||||||
// String type used throughout cHTTP.
|
// String type used throughout cHTTP.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -65,6 +87,9 @@ HTTP_String http_trim(HTTP_String s);
|
|||||||
// This is primarily used for debugging purposes.
|
// This is primarily used for debugging purposes.
|
||||||
void print_bytes(HTTP_String prefix, HTTP_String src);
|
void print_bytes(HTTP_String prefix, HTTP_String src);
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
char *http_strerror(int code);
|
||||||
|
|
||||||
// Macro to simplify converting string literals to
|
// Macro to simplify converting string literals to
|
||||||
// HTTP_String.
|
// HTTP_String.
|
||||||
//
|
//
|
||||||
@@ -94,6 +119,9 @@ void print_bytes(HTTP_String prefix, HTTP_String src);
|
|||||||
// Example: printf("%.*s", HTTP_UNPACK(str));
|
// Example: printf("%.*s", HTTP_UNPACK(str));
|
||||||
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
#define HTTP_UNREACHABLE __builtin_trap()
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// src/parse.h
|
// src/parse.h
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -253,21 +281,6 @@ typedef struct {
|
|||||||
// Returns 0 on success, -1 on error
|
// Returns 0 on success, -1 on error
|
||||||
int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out);
|
int http_parse_set_cookie(HTTP_String str, HTTP_SetCookie *out);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -499,11 +512,6 @@ typedef struct {
|
|||||||
// header.
|
// header.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
// This guards access to the main thread using
|
|
||||||
// the manager from other threads calling the
|
|
||||||
// wakeup function.
|
|
||||||
Mutex mutex;
|
|
||||||
|
|
||||||
// TCP listener sockets. The first is intended
|
// TCP listener sockets. The first is intended
|
||||||
// for plaintext, while the second is for TLS.
|
// for plaintext, while the second is for TLS.
|
||||||
// The socket manager will accept and add new
|
// The socket manager will accept and add new
|
||||||
@@ -593,14 +601,11 @@ typedef struct {
|
|||||||
void **ptrs;
|
void **ptrs;
|
||||||
struct pollfd *polled;
|
struct pollfd *polled;
|
||||||
int num_polled;
|
int num_polled;
|
||||||
int max_polled;
|
|
||||||
} EventRegister;
|
} EventRegister;
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the socket manager wants monitored. Returns 0 on
|
// the socket manager wants monitored.
|
||||||
// success, -1 if the event register's capacity isn't
|
void socket_manager_register_events(SocketManager *sm,
|
||||||
// large enough.
|
|
||||||
int socket_manager_register_events(SocketManager *sm,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// After poll() is called on the previously registered
|
// After poll() is called on the previously registered
|
||||||
@@ -645,15 +650,15 @@ 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);
|
||||||
|
|
||||||
int socket_close(SocketManager *sm, SocketHandle handle);
|
void 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
|
||||||
// by the secure listener.
|
// by the secure listener.
|
||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
bool socket_is_secure(SocketManager *sm, SocketHandle handle);
|
||||||
|
|
||||||
// Set the user pointer of a socket
|
// Set the user pointer of a socket
|
||||||
int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
||||||
|
|
||||||
// Returns true iff the socket is ready for reading or
|
// Returns true iff the socket is ready for reading or
|
||||||
// writing.
|
// writing.
|
||||||
@@ -1025,9 +1030,8 @@ void http_request_builder_body(HTTP_RequestBuilder builder,
|
|||||||
int http_request_builder_send(HTTP_RequestBuilder builder);
|
int http_request_builder_send(HTTP_RequestBuilder builder);
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the client wants monitored. Returns 0 on success, -1 if
|
// the client wants monitored.
|
||||||
// the event register's capacity isn't large enough.
|
void http_client_register_events(HTTP_Client *client,
|
||||||
int http_client_register_events(HTTP_Client *client,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
@@ -1044,10 +1048,11 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
// http_free_response function.
|
// http_free_response function.
|
||||||
// TODO: Better comment talking about output arguments
|
// TODO: Better comment talking about output arguments
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
HTTP_Response **response, void **user);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_client_wait_response(HTTP_Client *client, HTTP_Response **response, void **user);
|
int http_client_wait_response(HTTP_Client *client,
|
||||||
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// Free a response object. You can't access its fields
|
// Free a response object. You can't access its fields
|
||||||
// again after this.
|
// again after this.
|
||||||
@@ -1236,9 +1241,8 @@ int http_server_add_certificate(HTTP_Server *server,
|
|||||||
int http_server_wakeup(HTTP_Server *server);
|
int http_server_wakeup(HTTP_Server *server);
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the server wants monitored. Returns 0 on success, -1 if
|
// the server wants monitored.
|
||||||
// the event register's capacity isn't large enough.
|
void http_server_register_events(HTTP_Server *server,
|
||||||
int http_server_register_events(HTTP_Server *server,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
@@ -1264,6 +1268,10 @@ typedef struct {
|
|||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
int http_server_wait_request(HTTP_Server *server,
|
||||||
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// This function is called to set the status code of
|
// This function is called to set the status code of
|
||||||
// a request's response. If this function is called
|
// a request's response. If this function is called
|
||||||
// after the other response builder functions, it will
|
// after the other response builder functions, it will
|
||||||
|
|||||||
+23
-12
@@ -1,31 +1,42 @@
|
|||||||
#include "../chttp.h"
|
#include "../chttp.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define POLL WSAPoll
|
|
||||||
#else
|
|
||||||
#define POLL poll
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
HTTP_Client client;
|
HTTP_Client client;
|
||||||
if (http_client_init(&client) < 0)
|
ret = http_client_init(&client);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Couldn't initialize client (%s)\n", http_strerror(ret));
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
HTTP_RequestBuilder builder = http_client_get_builder(&client);
|
HTTP_RequestBuilder builder = http_client_get_builder(&client);
|
||||||
http_request_builder_trace(builder, true);
|
|
||||||
http_request_builder_method(builder, HTTP_METHOD_GET);
|
http_request_builder_method(builder, HTTP_METHOD_GET);
|
||||||
http_request_builder_target(builder, HTTP_STR("http://coz.is"));
|
http_request_builder_target(builder, HTTP_STR("http://coz.is"));
|
||||||
http_request_builder_header(builder, HTTP_STR("Greeting: Hello from the cHTTP example!"));
|
http_request_builder_header(builder, HTTP_STR("Greeting: Hello from the cHTTP example!"));
|
||||||
if (http_request_builder_send(builder) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
|
ret = http_request_builder_send(builder);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Couldn't build request (%s)\n", http_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
void *user;
|
void *user;
|
||||||
HTTP_Response *response;
|
HTTP_Response *response;
|
||||||
if (http_client_wait_response(&client, &response, &user) < 0)
|
ret = http_client_wait_response(&client, &result, &user, &response);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Couldn't wait for response (%s)\n", http_strerror(ret));
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
printf("Received a response!\n");
|
if (result == HTTP_OK) {
|
||||||
|
printf("Received %d bytes\n", response->body.len);
|
||||||
|
} else {
|
||||||
|
printf("Couldn't receive response (%s)\n", http_strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
http_client_free(&client);
|
http_client_free(&client);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+16
-29
@@ -1,52 +1,39 @@
|
|||||||
#include "../chttp.h"
|
#include "../chttp.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define POLL WSAPoll
|
|
||||||
#else
|
|
||||||
#define POLL poll
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
HTTP_Server server;
|
HTTP_Server server;
|
||||||
if (http_server_init(&server) < 0)
|
ret = http_server_init(&server);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret));
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
http_server_set_reuse_addr(&server, true);
|
http_server_set_reuse_addr(&server, true);
|
||||||
http_server_set_trace_bytes(&server, true);
|
http_server_set_trace_bytes(&server, true);
|
||||||
|
|
||||||
if (http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080) < 0)
|
ret = http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret));
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
void *ptrs[HTTP_SERVER_POLL_CAPACITY];
|
|
||||||
struct pollfd polled[HTTP_SERVER_POLL_CAPACITY];
|
|
||||||
|
|
||||||
EventRegister reg = {
|
|
||||||
.ptrs=ptrs,
|
|
||||||
.polled=polled,
|
|
||||||
.max_polled=HTTP_SERVER_POLL_CAPACITY,
|
|
||||||
.num_polled=0,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (http_server_register_events(&server, ®) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (reg.num_polled > 0)
|
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
|
||||||
|
|
||||||
if (http_server_process_events(&server, ®) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
HTTP_Request *request;
|
HTTP_Request *request;
|
||||||
HTTP_ResponseBuilder builder;
|
HTTP_ResponseBuilder builder;
|
||||||
if (http_server_next_request(&server, &request, &builder)) {
|
int ret = http_server_wait_request(&server, &request, &builder);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't wait for request (%s)\n", http_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
http_response_builder_status(builder, 200);
|
http_response_builder_status(builder, 200);
|
||||||
http_response_builder_body(builder, HTTP_STR("Hello, world!"));
|
http_response_builder_body(builder, HTTP_STR("Hello, world!"));
|
||||||
http_response_builder_send(builder);
|
http_response_builder_send(builder);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
http_server_free(&server);
|
http_server_free(&server);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ 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/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/byte_queue.h")
|
header.append_file("src/byte_queue.h")
|
||||||
@@ -75,7 +74,6 @@ 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/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/byte_queue.c")
|
source.append_file("src/byte_queue.c")
|
||||||
|
|||||||
+14
@@ -94,3 +94,17 @@ void print_bytes(HTTP_String prefix, HTTP_String src)
|
|||||||
}
|
}
|
||||||
putc('\n', stream);
|
putc('\n', stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *http_strerror(int code)
|
||||||
|
{
|
||||||
|
switch (code) {
|
||||||
|
case HTTP_OK: return "No error";
|
||||||
|
case HTTP_ERROR_UNSPECIFIED: return "Unspecified error";
|
||||||
|
case HTTP_ERROR_OOM: return "Out of memory";
|
||||||
|
case HTTP_ERROR_BADURL: return "Invalid URL";
|
||||||
|
case HTTP_ERROR_REQLIMIT: return "Parallel request limit reached";
|
||||||
|
case HTTP_ERROR_BADHANDLE: return "Invalid handle";
|
||||||
|
case HTTP_ERROR_NOTLS: return "TLS support not built-in";
|
||||||
|
}
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|||||||
+29
@@ -1,4 +1,27 @@
|
|||||||
|
|
||||||
|
enum {
|
||||||
|
|
||||||
|
HTTP_OK = 0,
|
||||||
|
|
||||||
|
// A generic error occurred
|
||||||
|
HTTP_ERROR_UNSPECIFIED = -1,
|
||||||
|
|
||||||
|
// Out of memory
|
||||||
|
HTTP_ERROR_OOM = -2,
|
||||||
|
|
||||||
|
// Invalid URL
|
||||||
|
HTTP_ERROR_BADURL = -3,
|
||||||
|
|
||||||
|
// Parallel request limit reached
|
||||||
|
HTTP_ERROR_REQLIMIT = -4,
|
||||||
|
|
||||||
|
// Invalid handle
|
||||||
|
HTTP_ERROR_BADHANDLE = -5,
|
||||||
|
|
||||||
|
// TLS support not built-in
|
||||||
|
HTTP_ERROR_NOTLS = -6,
|
||||||
|
};
|
||||||
|
|
||||||
// String type used throughout cHTTP.
|
// String type used throughout cHTTP.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -23,6 +46,9 @@ HTTP_String http_trim(HTTP_String s);
|
|||||||
// This is primarily used for debugging purposes.
|
// This is primarily used for debugging purposes.
|
||||||
void print_bytes(HTTP_String prefix, HTTP_String src);
|
void print_bytes(HTTP_String prefix, HTTP_String src);
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
char *http_strerror(int code);
|
||||||
|
|
||||||
// Macro to simplify converting string literals to
|
// Macro to simplify converting string literals to
|
||||||
// HTTP_String.
|
// HTTP_String.
|
||||||
//
|
//
|
||||||
@@ -51,3 +77,6 @@ void print_bytes(HTTP_String prefix, HTTP_String src);
|
|||||||
// Useful for passing HTTP_String to printf-style functions with "%.*s" format.
|
// Useful for passing HTTP_String to printf-style functions with "%.*s" format.
|
||||||
// Example: printf("%.*s", HTTP_UNPACK(str));
|
// Example: printf("%.*s", HTTP_UNPACK(str));
|
||||||
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
#define HTTP_UNPACK(X) (X).len, (X).ptr
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
#define HTTP_UNREACHABLE __builtin_trap()
|
||||||
|
|||||||
+48
-60
@@ -21,10 +21,8 @@ int http_client_init(HTTP_Client *client)
|
|||||||
client->num_ready = 0;
|
client->num_ready = 0;
|
||||||
client->ready_head = 0;
|
client->ready_head = 0;
|
||||||
|
|
||||||
if (socket_manager_init(&client->sockets,
|
return socket_manager_init(&client->sockets,
|
||||||
client->socket_pool, HTTP_CLIENT_CAPACITY) < 0)
|
client->socket_pool, HTTP_CLIENT_CAPACITY);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_client_free(HTTP_Client *client)
|
void http_client_free(HTTP_Client *client)
|
||||||
@@ -56,9 +54,7 @@ void http_client_set_output_limit(HTTP_Client *client, uint32_t limit)
|
|||||||
|
|
||||||
int http_client_wakeup(HTTP_Client *client)
|
int http_client_wakeup(HTTP_Client *client)
|
||||||
{
|
{
|
||||||
if (socket_manager_wakeup(&client->sockets) < 0)
|
return socket_manager_wakeup(&client->sockets);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a connection pointer from a request builder.
|
// Get a connection pointer from a request builder.
|
||||||
@@ -234,7 +230,7 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
char *url_copy = malloc(url.len);
|
char *url_copy = malloc(url.len);
|
||||||
if (url_copy == NULL) {
|
if (url_copy == NULL) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_OOM;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(url_copy, url.ptr, url.len);
|
memcpy(url_copy, url.ptr, url.len);
|
||||||
@@ -245,14 +241,14 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
// Parse the copied URL (all url.* pointers will reference url_buffer)
|
// Parse the copied URL (all url.* pointers will reference url_buffer)
|
||||||
if (http_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) {
|
if (http_parse_url(conn->url_buffer.ptr, conn->url_buffer.len, &conn->url) < 0) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!http_streq(conn->url.scheme, HTTP_STR("http")) &&
|
if (!http_streq(conn->url.scheme, HTTP_STR("http")) &&
|
||||||
!http_streq(conn->url.scheme, HTTP_STR("https"))) {
|
!http_streq(conn->url.scheme, HTTP_STR("https"))) {
|
||||||
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
conn->result = -1;
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +256,9 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
if (conn->url.path.len == 0)
|
if (conn->url.path.len == 0)
|
||||||
byte_queue_write(&conn->output, "/", 1);
|
byte_queue_write(&conn->output, "/", 1);
|
||||||
else
|
else
|
||||||
byte_queue_write(&conn->output, conn->url.path.ptr, conn->url.path.len);
|
byte_queue_write(&conn->output,
|
||||||
|
conn->url.path.ptr,
|
||||||
|
conn->url.path.len);
|
||||||
|
|
||||||
// Write query string
|
// Write query string
|
||||||
HTTP_String query = conn->url.query;
|
HTTP_String query = conn->url.query;
|
||||||
@@ -352,47 +350,45 @@ void http_request_builder_body(HTTP_RequestBuilder builder,
|
|||||||
byte_queue_write(&conn->output, str.ptr, str.len);
|
byte_queue_write(&conn->output, str.ptr, str.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static ConnectTarget url_to_connect_target(HTTP_URL url)
|
||||||
url_to_connect_target(HTTP_URL url,
|
|
||||||
ConnectTarget *target)
|
|
||||||
{
|
{
|
||||||
HTTP_Authority authority = url.authority;
|
HTTP_Authority authority = url.authority;
|
||||||
|
|
||||||
|
ConnectTarget target;
|
||||||
if (authority.port < 1) {
|
if (authority.port < 1) {
|
||||||
if (http_streq(url.scheme, HTTP_STR("https")))
|
if (http_streq(url.scheme, HTTP_STR("https")))
|
||||||
target->port = 443;
|
target.port = 443;
|
||||||
else
|
else
|
||||||
target->port = 80;
|
target.port = 80;
|
||||||
} else {
|
} else {
|
||||||
target->port = authority.port;
|
target.port = authority.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up target based on host type
|
|
||||||
if (authority.host.mode == HTTP_HOST_MODE_NAME) {
|
if (authority.host.mode == HTTP_HOST_MODE_NAME) {
|
||||||
target->type = CONNECT_TARGET_NAME;
|
target.type = CONNECT_TARGET_NAME;
|
||||||
target->name = authority.host.name;
|
target.name = authority.host.name;
|
||||||
} else if (authority.host.mode == HTTP_HOST_MODE_IPV4) {
|
} else if (authority.host.mode == HTTP_HOST_MODE_IPV4) {
|
||||||
target->type = CONNECT_TARGET_IPV4;
|
target.type = CONNECT_TARGET_IPV4;
|
||||||
target->ipv4 = authority.host.ipv4;
|
target.ipv4 = authority.host.ipv4;
|
||||||
} else if (authority.host.mode == HTTP_HOST_MODE_IPV6) {
|
} else if (authority.host.mode == HTTP_HOST_MODE_IPV6) {
|
||||||
target->type = CONNECT_TARGET_IPV6;
|
target.type = CONNECT_TARGET_IPV6;
|
||||||
target->ipv6 = authority.host.ipv6;
|
target.ipv6 = authority.host.ipv6;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
HTTP_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request_builder_send(HTTP_RequestBuilder builder)
|
int http_request_builder_send(HTTP_RequestBuilder builder)
|
||||||
{
|
{
|
||||||
HTTP_Client *client = builder.client;
|
HTTP_Client *client = builder.client;
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_REQLIMIT;
|
||||||
|
|
||||||
HTTP_ClientConn *conn = request_builder_to_conn(builder);
|
HTTP_ClientConn *conn = request_builder_to_conn(builder);
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_BADHANDLE;
|
||||||
|
|
||||||
if (conn->state == HTTP_CLIENT_CONN_COMPLETE)
|
if (conn->state == HTTP_CLIENT_CONN_COMPLETE)
|
||||||
goto error; // Early completion due to an error
|
goto error; // Early completion due to an error
|
||||||
@@ -409,17 +405,14 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
|
|||||||
if (byte_queue_error(&conn->output))
|
if (byte_queue_error(&conn->output))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ConnectTarget target;
|
ConnectTarget target = url_to_connect_target(conn->url);
|
||||||
if (url_to_connect_target(conn->url, &target) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
bool secure = http_streq(conn->url.scheme, HTTP_STR("https"));
|
bool secure = http_streq(conn->url.scheme, HTTP_STR("https"));
|
||||||
if (socket_connect(&client->sockets, 1, &target, secure, conn) < 0)
|
if (socket_connect(&client->sockets, 1, &target, secure, conn) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
conn->state = HTTP_CLIENT_CONN_FLUSHING;
|
conn->state = HTTP_CLIENT_CONN_FLUSHING;
|
||||||
conn->gen++;
|
conn->gen++;
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
conn->state = HTTP_CLIENT_CONN_FREE;
|
conn->state = HTTP_CLIENT_CONN_FREE;
|
||||||
@@ -427,7 +420,7 @@ error:
|
|||||||
byte_queue_free(&conn->input);
|
byte_queue_free(&conn->input);
|
||||||
byte_queue_free(&conn->output);
|
byte_queue_free(&conn->output);
|
||||||
client->num_conns--;
|
client->num_conns--;
|
||||||
return -1;
|
return conn->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_one_cookie(HTTP_CookieJar *cookie_jar,
|
static void save_one_cookie(HTTP_CookieJar *cookie_jar,
|
||||||
@@ -500,22 +493,20 @@ static void save_cookies(HTTP_CookieJar *cookie_jar,
|
|||||||
save_one_cookie(cookie_jar, headers[i], domain, path);
|
save_one_cookie(cookie_jar, headers[i], domain, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_register_events(HTTP_Client *client,
|
void http_client_register_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
if (socket_manager_register_events(&client->sockets, reg) < 0)
|
socket_manager_register_events(&client->sockets, reg);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_process_events(HTTP_Client *client,
|
int http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
||||||
int num_events = socket_manager_translate_events(
|
int ret = socket_manager_translate_events(&client->sockets, events, reg);
|
||||||
&client->sockets, events, reg);
|
if (ret < 0)
|
||||||
if (num_events < 0)
|
return ret;
|
||||||
return -1;
|
int num_events = ret;
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -638,11 +629,11 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
HTTP_Response **response, void **user)
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
if (client->num_ready == 0)
|
if (client->num_ready == 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -653,13 +644,13 @@ bool http_client_next_response(HTTP_Client *client,
|
|||||||
|
|
||||||
assert(conn->state == HTTP_CLIENT_CONN_COMPLETE);
|
assert(conn->state == HTTP_CLIENT_CONN_COMPLETE);
|
||||||
|
|
||||||
if (conn->result == 0) {
|
*result = conn->result;
|
||||||
|
*user = conn->user;
|
||||||
|
if (conn->result == HTTP_OK) {
|
||||||
*response = &conn->response;
|
*response = &conn->response;
|
||||||
} else {
|
} else {
|
||||||
assert(conn->result == -1);
|
|
||||||
*response = NULL;
|
*response = NULL;
|
||||||
}
|
}
|
||||||
*user = conn->user;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -695,30 +686,27 @@ void http_free_response(HTTP_Response *response)
|
|||||||
#define POLL poll
|
#define POLL poll
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int http_client_wait_response(HTTP_Client *client, HTTP_Response **response, void **user)
|
int http_client_wait_response(HTTP_Client *client,
|
||||||
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
void *ptrs[HTTP_CLIENT_POLL_CAPACITY];
|
void *ptrs[HTTP_CLIENT_POLL_CAPACITY];
|
||||||
struct pollfd polled[HTTP_CLIENT_POLL_CAPACITY];
|
struct pollfd polled[HTTP_CLIENT_POLL_CAPACITY];
|
||||||
|
|
||||||
EventRegister reg = {
|
EventRegister reg = { ptrs, polled, 0 };
|
||||||
.ptrs=ptrs,
|
http_client_register_events(client, ®);
|
||||||
.polled=polled,
|
|
||||||
.num_polled=0,
|
|
||||||
.max_polled=HTTP_CLIENT_POLL_CAPACITY,
|
|
||||||
};
|
|
||||||
if (http_client_register_events(client, ®) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
if (http_client_process_events(client, ®) < 0)
|
int ret = http_client_process_events(client, ®);
|
||||||
return -1;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (http_client_next_response(client, response, user))
|
if (http_client_next_response(client, result, user, response))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -196,9 +196,8 @@ void http_request_builder_body(HTTP_RequestBuilder builder,
|
|||||||
int http_request_builder_send(HTTP_RequestBuilder builder);
|
int http_request_builder_send(HTTP_RequestBuilder builder);
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the client wants monitored. Returns 0 on success, -1 if
|
// the client wants monitored.
|
||||||
// the event register's capacity isn't large enough.
|
void http_client_register_events(HTTP_Client *client,
|
||||||
int http_client_register_events(HTTP_Client *client,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
@@ -215,10 +214,11 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
// http_free_response function.
|
// http_free_response function.
|
||||||
// TODO: Better comment talking about output arguments
|
// TODO: Better comment talking about output arguments
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
HTTP_Response **response, void **user);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_client_wait_response(HTTP_Client *client, HTTP_Response **response, void **user);
|
int http_client_wait_response(HTTP_Client *client,
|
||||||
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// Free a response object. You can't access its fields
|
// Free a response object. You can't access its fields
|
||||||
// again after this.
|
// again after this.
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
+41
-28
@@ -34,10 +34,8 @@ int http_server_init(HTTP_Server *server)
|
|||||||
server->num_ready = 0;
|
server->num_ready = 0;
|
||||||
server->ready_head = 0;
|
server->ready_head = 0;
|
||||||
|
|
||||||
if (socket_manager_init(&server->sockets,
|
return socket_manager_init(&server->sockets,
|
||||||
server->socket_pool, HTTP_SERVER_CAPACITY) < 0)
|
server->socket_pool, HTTP_SERVER_CAPACITY);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void http_server_free(HTTP_Server *server)
|
void http_server_free(HTTP_Server *server)
|
||||||
@@ -82,45 +80,35 @@ void http_server_set_backlog(HTTP_Server *server, int backlog)
|
|||||||
int http_server_listen_tcp(HTTP_Server *server,
|
int http_server_listen_tcp(HTTP_Server *server,
|
||||||
HTTP_String addr, Port port)
|
HTTP_String addr, Port port)
|
||||||
{
|
{
|
||||||
if (socket_manager_listen_tcp(&server->sockets, addr,
|
return socket_manager_listen_tcp(&server->sockets,
|
||||||
port, server->backlog, server->reuse_addr) < 0)
|
addr, port, server->backlog, server->reuse_addr);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_listen_tls(HTTP_Server *server,
|
int http_server_listen_tls(HTTP_Server *server,
|
||||||
HTTP_String addr, Port port, HTTP_String cert_file_name,
|
HTTP_String addr, Port port, HTTP_String cert_file_name,
|
||||||
HTTP_String key_file_name)
|
HTTP_String key_file_name)
|
||||||
{
|
{
|
||||||
if (socket_manager_listen_tls(&server->sockets, addr,
|
return socket_manager_listen_tls(&server->sockets,
|
||||||
port, server->backlog, server->reuse_addr,
|
addr, port, server->backlog, server->reuse_addr,
|
||||||
cert_file_name, key_file_name) < 0)
|
cert_file_name, key_file_name);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_add_certificate(HTTP_Server *server,
|
int http_server_add_certificate(HTTP_Server *server,
|
||||||
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
||||||
{
|
{
|
||||||
if (socket_manager_add_certificate(&server->sockets,
|
return socket_manager_add_certificate(&server->sockets,
|
||||||
domain, cert_file, key_file) < 0)
|
domain, cert_file, key_file);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_wakeup(HTTP_Server *server)
|
int http_server_wakeup(HTTP_Server *server)
|
||||||
{
|
{
|
||||||
if (socket_manager_wakeup(&server->sockets) < 0)
|
return socket_manager_wakeup(&server->sockets);
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_register_events(HTTP_Server *server,
|
void http_server_register_events(HTTP_Server *server,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
if (socket_manager_register_events(&server->sockets, reg) < 0)
|
socket_manager_register_events(&server->sockets, reg);
|
||||||
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
|
||||||
@@ -233,9 +221,10 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_SERVER_CAPACITY];
|
SocketEvent events[HTTP_SERVER_CAPACITY];
|
||||||
int num_events = socket_manager_translate_events(&server->sockets, events, reg);
|
int ret = socket_manager_translate_events(&server->sockets, events, reg);
|
||||||
if (num_events < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return ret;
|
||||||
|
int num_events = ret;
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -277,7 +266,7 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
@@ -296,6 +285,30 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int http_server_wait_request(HTTP_Server *server,
|
||||||
|
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
void *ptrs[HTTP_SERVER_POLL_CAPACITY];
|
||||||
|
struct pollfd polled[HTTP_SERVER_POLL_CAPACITY];
|
||||||
|
|
||||||
|
EventRegister reg = { ptrs, polled, 0 };
|
||||||
|
http_server_register_events(server, ®);
|
||||||
|
|
||||||
|
if (reg.num_polled > 0)
|
||||||
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
|
int ret = http_server_process_events(server, ®);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (http_server_next_request(server, request, builder))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HTTP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
+6
-3
@@ -178,9 +178,8 @@ int http_server_add_certificate(HTTP_Server *server,
|
|||||||
int http_server_wakeup(HTTP_Server *server);
|
int http_server_wakeup(HTTP_Server *server);
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the server wants monitored. Returns 0 on success, -1 if
|
// the server wants monitored.
|
||||||
// the event register's capacity isn't large enough.
|
void http_server_register_events(HTTP_Server *server,
|
||||||
int http_server_register_events(HTTP_Server *server,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
@@ -206,6 +205,10 @@ typedef struct {
|
|||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
|
// TODO: comment
|
||||||
|
int http_server_wait_request(HTTP_Server *server,
|
||||||
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// This function is called to set the status code of
|
// This function is called to set the status code of
|
||||||
// a request's response. If this function is called
|
// a request's response. If this function is called
|
||||||
// after the other response builder functions, it will
|
// after the other response builder functions, it will
|
||||||
|
|||||||
+69
-157
@@ -39,7 +39,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
if (WSAStartup(wVersionRequested, &wsaData))
|
if (WSAStartup(wVersionRequested, &wsaData))
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (sock == INVALID_SOCKET && *global_cleanup)
|
if (sock == INVALID_SOCKET && *global_cleanup)
|
||||||
@@ -49,7 +49,7 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
if (sock == INVALID_SOCKET) {
|
if (sock == INVALID_SOCKET) {
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to loopback address with port 0 (dynamic port assignment)
|
// Bind to loopback address with port 0 (dynamic port assignment)
|
||||||
@@ -64,21 +64,21 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) {
|
if (getsockname(sock, (struct sockaddr*)&addr, &addr_len) == SOCKET_ERROR) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Set socket to non-blocking mode
|
// Optional: Set socket to non-blocking mode
|
||||||
@@ -88,20 +88,20 @@ static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b, bool *global_c
|
|||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
if (*global_cleanup)
|
if (*global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
*a = sock;
|
*a = sock;
|
||||||
*b = sock;
|
*b = sock;
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
#else
|
#else
|
||||||
*global_cleanup = false;
|
*global_cleanup = false;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
if (pipe(fds) < 0)
|
if (pipe(fds) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
*a = fds[0];
|
*a = fds[0];
|
||||||
*b = fds[1];
|
*b = fds[1];
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,20 +110,20 @@ static int set_socket_blocking(NATIVE_SOCKET sock, bool value)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
u_long mode = !value;
|
u_long mode = !value;
|
||||||
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
if (ioctlsocket(sock, FIONBIO, &mode) == SOCKET_ERROR)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int flags = fcntl(sock, F_GETFL, 0);
|
int flags = fcntl(sock, F_GETFL, 0);
|
||||||
if (flags < 0)
|
if (flags < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
if (value) flags &= ~O_NONBLOCK;
|
if (value) flags &= ~O_NONBLOCK;
|
||||||
else flags |= O_NONBLOCK;
|
else flags |= O_NONBLOCK;
|
||||||
if (fcntl(sock, F_SETFL, flags) < 0)
|
if (fcntl(sock, F_SETFL, flags) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
return HTTP_OK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
|
static NATIVE_SOCKET create_listen_socket(HTTP_String addr,
|
||||||
@@ -193,13 +193,15 @@ static void close_socket_pair(NATIVE_SOCKET a, NATIVE_SOCKET b)
|
|||||||
int socket_manager_init(SocketManager *sm, Socket *socks,
|
int socket_manager_init(SocketManager *sm, Socket *socks,
|
||||||
int num_socks)
|
int num_socks)
|
||||||
{
|
{
|
||||||
if (mutex_init(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
sm->plain_sock = NATIVE_SOCKET_INVALID;
|
sm->plain_sock = NATIVE_SOCKET_INVALID;
|
||||||
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
||||||
if (create_socket_pair(&sm->wait_sock, &sm->signal_sock,
|
|
||||||
&sm->global_cleanup) < 0)
|
int ret = create_socket_pair(
|
||||||
return -1;
|
&sm->wait_sock,
|
||||||
|
&sm->signal_sock,
|
||||||
|
&sm->global_cleanup);
|
||||||
|
if (ret < 0) return ret;
|
||||||
|
|
||||||
sm->at_least_one_secure_connect = false;
|
sm->at_least_one_secure_connect = false;
|
||||||
|
|
||||||
sm->num_used = 0;
|
sm->num_used = 0;
|
||||||
@@ -210,7 +212,7 @@ int socket_manager_init(SocketManager *sm, Socket *socks,
|
|||||||
socks[i].state = SOCKET_STATE_FREE;
|
socks[i].state = SOCKET_STATE_FREE;
|
||||||
socks[i].gen = 1;
|
socks[i].gen = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_manager_free(SocketManager *sm)
|
void socket_manager_free(SocketManager *sm)
|
||||||
@@ -233,8 +235,6 @@ void socket_manager_free(SocketManager *sm)
|
|||||||
if (sm->global_cleanup)
|
if (sm->global_cleanup)
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mutex_free(&sm->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_listen_tcp(SocketManager *sm,
|
int socket_manager_listen_tcp(SocketManager *sm,
|
||||||
@@ -242,13 +242,13 @@ int socket_manager_listen_tcp(SocketManager *sm,
|
|||||||
bool reuse_addr)
|
bool reuse_addr)
|
||||||
{
|
{
|
||||||
if (sm->plain_sock != NATIVE_SOCKET_INVALID)
|
if (sm->plain_sock != NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
sm->plain_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
||||||
if (sm->plain_sock == NATIVE_SOCKET_INVALID)
|
if (sm->plain_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_listen_tls(SocketManager *sm,
|
int socket_manager_listen_tls(SocketManager *sm,
|
||||||
@@ -256,35 +256,39 @@ int socket_manager_listen_tls(SocketManager *sm,
|
|||||||
bool reuse_addr, HTTP_String cert_file,
|
bool reuse_addr, HTTP_String cert_file,
|
||||||
HTTP_String key_file)
|
HTTP_String key_file)
|
||||||
{
|
{
|
||||||
|
#ifndef HTTPS_ENABLED
|
||||||
|
return HTTP_ERROR_NOTLS;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sm->secure_sock != NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock != NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
sm->secure_sock = create_listen_socket(addr, port, reuse_addr, backlog);
|
||||||
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
if (server_secure_context_init(&sm->server_secure_context,
|
if (server_secure_context_init(&sm->server_secure_context,
|
||||||
cert_file, key_file) < 0) {
|
cert_file, key_file) < 0) {
|
||||||
CLOSE_NATIVE_SOCKET(sm->secure_sock);
|
CLOSE_NATIVE_SOCKET(sm->secure_sock);
|
||||||
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
sm->secure_sock = NATIVE_SOCKET_INVALID;
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_add_certificate(SocketManager *sm,
|
int socket_manager_add_certificate(SocketManager *sm,
|
||||||
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
HTTP_String domain, HTTP_String cert_file, HTTP_String key_file)
|
||||||
{
|
{
|
||||||
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
if (sm->secure_sock == NATIVE_SOCKET_INVALID)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
int ret = server_secure_context_add_certificate(
|
int ret = server_secure_context_add_certificate(
|
||||||
&sm->server_secure_context, domain, cert_file, key_file);
|
&sm->server_secure_context, domain, cert_file, key_file);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_secure(Socket *s)
|
static bool is_secure(Socket *s)
|
||||||
@@ -680,27 +684,21 @@ static void socket_update(Socket *s)
|
|||||||
|
|
||||||
int socket_manager_wakeup(SocketManager *sm)
|
int socket_manager_wakeup(SocketManager *sm)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
// NOTE: It's assumed send/write operate atomically
|
||||||
return -1;
|
// on The descriptor.
|
||||||
|
|
||||||
// Send a byte through the signal socket to wake up any thread
|
|
||||||
// blocked on poll() with the wait socket
|
|
||||||
char byte = 1;
|
char byte = 1;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (send(sm->signal_sock, &byte, 1, 0) < 0)
|
if (send(sm->signal_sock, &byte, 1, 0) < 0)
|
||||||
ret = -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
#else
|
#else
|
||||||
if (write(sm->signal_sock, &byte, 1) < 0)
|
if (write(sm->signal_sock, &byte, 1) < 0)
|
||||||
ret = -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
#endif
|
#endif
|
||||||
|
return HTTP_OK;
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void socket_manager_register_events_nolock(
|
void socket_manager_register_events(
|
||||||
SocketManager *sm, EventRegister *reg)
|
SocketManager *sm, EventRegister *reg)
|
||||||
{
|
{
|
||||||
reg->num_polled = 0;
|
reg->num_polled = 0;
|
||||||
@@ -760,19 +758,6 @@ static void socket_manager_register_events_nolock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_register_events(SocketManager *sm,
|
|
||||||
EventRegister *reg)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
socket_manager_register_events_nolock(sm, reg);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SocketHandle
|
static SocketHandle
|
||||||
socket_to_handle(SocketManager *sm, Socket *s)
|
socket_to_handle(SocketManager *sm, Socket *s)
|
||||||
{
|
{
|
||||||
@@ -790,7 +775,7 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
|
|||||||
return &sm->sockets[idx];
|
return &sm->sockets[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_manager_translate_events_nolock(
|
int socket_manager_translate_events(
|
||||||
SocketManager *sm, SocketEvent *events,
|
SocketManager *sm, SocketEvent *events,
|
||||||
EventRegister *reg)
|
EventRegister *reg)
|
||||||
{
|
{
|
||||||
@@ -913,19 +898,6 @@ static int socket_manager_translate_events_nolock(
|
|||||||
return num_events;
|
return num_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_manager_translate_events(SocketManager *sm,
|
|
||||||
SocketEvent *events, EventRegister *reg)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_manager_translate_events_nolock(sm, events, reg);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int resolve_connect_targets(ConnectTarget *targets,
|
static int resolve_connect_targets(ConnectTarget *targets,
|
||||||
int num_targets, AddressAndPort *resolved, int max_resolved)
|
int num_targets, AddressAndPort *resolved, int max_resolved)
|
||||||
{
|
{
|
||||||
@@ -946,7 +918,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1);
|
RegisteredName *name = malloc(sizeof(RegisteredName) + targets[i].name.len + 1);
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
free_addr_list(resolved, num_resolved);
|
free_addr_list(resolved, num_resolved);
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
}
|
}
|
||||||
name->refs = 0;
|
name->refs = 0;
|
||||||
memcpy(name->data, targets[i].name.ptr, targets[i].name.len);
|
memcpy(name->data, targets[i].name.ptr, targets[i].name.len);
|
||||||
@@ -956,7 +928,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
// 512 bytes is more than enough for a DNS hostname (max 253 chars)
|
// 512 bytes is more than enough for a DNS hostname (max 253 chars)
|
||||||
char hostname[1<<9];
|
char hostname[1<<9];
|
||||||
if (targets[i].name.len >= (int) sizeof(hostname))
|
if (targets[i].name.len >= (int) sizeof(hostname))
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
|
memcpy(hostname, targets[i].name.ptr, targets[i].name.len);
|
||||||
hostname[targets[i].name.len] = '\0';
|
hostname[targets[i].name.len] = '\0';
|
||||||
#endif
|
#endif
|
||||||
@@ -968,7 +940,7 @@ static int resolve_connect_targets(ConnectTarget *targets,
|
|||||||
free(name);
|
free(name);
|
||||||
#endif
|
#endif
|
||||||
free_addr_list(resolved, num_resolved);
|
free_addr_list(resolved, num_resolved);
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
for (struct addrinfo *rp = res; rp; rp = rp->ai_next) {
|
||||||
@@ -1040,17 +1012,17 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
ConnectTarget *targets, bool secure, void *user)
|
ConnectTarget *targets, bool secure, void *user)
|
||||||
{
|
{
|
||||||
if (sm->num_used == sm->max_used)
|
if (sm->num_used == sm->max_used)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
#ifdef HTTPS_ENABLED
|
#ifdef HTTPS_ENABLED
|
||||||
if (!sm->at_least_one_secure_connect) {
|
if (!sm->at_least_one_secure_connect) {
|
||||||
if (client_secure_context_init(&sm->client_secure_context) < 0)
|
if (client_secure_context_init(&sm->client_secure_context) < 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
sm->at_least_one_secure_connect = true;
|
sm->at_least_one_secure_connect = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (secure)
|
if (secure)
|
||||||
return -1;
|
return HTTP_ERROR_NOTLS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AddressAndPort resolved[MAX_CONNECT_TARGETS];
|
AddressAndPort resolved[MAX_CONNECT_TARGETS];
|
||||||
@@ -1058,7 +1030,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
targets, num_targets, resolved, MAX_CONNECT_TARGETS);
|
targets, num_targets, resolved, MAX_CONNECT_TARGETS);
|
||||||
|
|
||||||
if (num_resolved <= 0)
|
if (num_resolved <= 0)
|
||||||
return -1;
|
return HTTP_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->state != SOCKET_STATE_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
@@ -1075,7 +1047,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
s->next_addr = 0;
|
s->next_addr = 0;
|
||||||
s->addrs = malloc(num_resolved * sizeof(AddressAndPort));
|
s->addrs = malloc(num_resolved * sizeof(AddressAndPort));
|
||||||
if (s->addrs == NULL)
|
if (s->addrs == NULL)
|
||||||
return -1;
|
return HTTP_ERROR_OOM;
|
||||||
for (int i = 0; i < num_resolved; i++)
|
for (int i = 0; i < num_resolved; i++)
|
||||||
s->addrs[i] = resolved[i];
|
s->addrs[i] = resolved[i];
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1065,7 @@ int socket_connect(SocketManager *sm, int num_targets,
|
|||||||
sm->num_used++;
|
sm->num_used++;
|
||||||
|
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
return 0;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool would_block(void)
|
static bool would_block(void)
|
||||||
@@ -1115,7 +1087,7 @@ static bool interrupted(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
|
int socket_recv(SocketManager *sm, SocketHandle handle,
|
||||||
char *dst, int max)
|
char *dst, int max)
|
||||||
{
|
{
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
@@ -1166,20 +1138,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_recv(SocketManager *sm, SocketHandle handle,
|
int socket_send(SocketManager *sm, SocketHandle handle,
|
||||||
char *dst, int max)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_recv_nolock(sm, handle, dst, max);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
|
|
||||||
char *src, int len)
|
char *src, int len)
|
||||||
{
|
{
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
@@ -1227,93 +1186,46 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_send(SocketManager *sm, SocketHandle handle,
|
void socket_close(SocketManager *sm, SocketHandle handle)
|
||||||
char *src, int len)
|
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = socket_send_nolock(sm, handle, src, len);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socket_close(SocketManager *sm, SocketHandle handle)
|
|
||||||
{
|
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
ret = -1;
|
return;
|
||||||
else {
|
|
||||||
// Only transition to SHUTDOWN if socket is not already DIED
|
|
||||||
if (s->state != SOCKET_STATE_DIED) {
|
if (s->state != SOCKET_STATE_DIED) {
|
||||||
UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
|
UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
|
||||||
s->events = 0;
|
s->events = 0;
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle)
|
bool socket_is_secure(SocketManager *sm, SocketHandle handle)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
|
|
||||||
int ret;
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
ret = -1;
|
return false;
|
||||||
else
|
return is_secure(s);
|
||||||
ret = is_secure(s);
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0)
|
|
||||||
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;
|
return;
|
||||||
else {
|
|
||||||
s->user = user;
|
s->user = user;
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0)
|
|
||||||
return -1;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool socket_ready(SocketManager *sm, SocketHandle handle)
|
bool socket_ready(SocketManager *sm, SocketHandle handle)
|
||||||
{
|
{
|
||||||
if (mutex_lock(&sm->mutex) < 0) {
|
|
||||||
assert(0); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
Socket *s = handle_to_socket(sm, handle);
|
Socket *s = handle_to_socket(sm, handle);
|
||||||
if (s && s->events == 0 && s->state != SOCKET_STATE_DIED) {
|
if (s == NULL)
|
||||||
ready = true;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (mutex_unlock(&sm->mutex) < 0) {
|
if (s->events == 0 && s->state != SOCKET_STATE_DIED)
|
||||||
assert(0); // TODO
|
return true;
|
||||||
}
|
|
||||||
return ready;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-13
@@ -182,11 +182,6 @@ typedef struct {
|
|||||||
// header.
|
// header.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
// This guards access to the main thread using
|
|
||||||
// the manager from other threads calling the
|
|
||||||
// wakeup function.
|
|
||||||
Mutex mutex;
|
|
||||||
|
|
||||||
// TCP listener sockets. The first is intended
|
// TCP listener sockets. The first is intended
|
||||||
// for plaintext, while the second is for TLS.
|
// for plaintext, while the second is for TLS.
|
||||||
// The socket manager will accept and add new
|
// The socket manager will accept and add new
|
||||||
@@ -276,14 +271,11 @@ typedef struct {
|
|||||||
void **ptrs;
|
void **ptrs;
|
||||||
struct pollfd *polled;
|
struct pollfd *polled;
|
||||||
int num_polled;
|
int num_polled;
|
||||||
int max_polled;
|
|
||||||
} EventRegister;
|
} EventRegister;
|
||||||
|
|
||||||
// Resets the event register with the list of descriptors
|
// Resets the event register with the list of descriptors
|
||||||
// the socket manager wants monitored. Returns 0 on
|
// the socket manager wants monitored.
|
||||||
// success, -1 if the event register's capacity isn't
|
void socket_manager_register_events(SocketManager *sm,
|
||||||
// large enough.
|
|
||||||
int socket_manager_register_events(SocketManager *sm,
|
|
||||||
EventRegister *reg);
|
EventRegister *reg);
|
||||||
|
|
||||||
// After poll() is called on the previously registered
|
// After poll() is called on the previously registered
|
||||||
@@ -328,15 +320,15 @@ 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);
|
||||||
|
|
||||||
int socket_close(SocketManager *sm, SocketHandle handle);
|
void 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
|
||||||
// by the secure listener.
|
// by the secure listener.
|
||||||
int socket_is_secure(SocketManager *sm, SocketHandle handle);
|
bool socket_is_secure(SocketManager *sm, SocketHandle handle);
|
||||||
|
|
||||||
// Set the user pointer of a socket
|
// Set the user pointer of a socket
|
||||||
int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
void socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
|
||||||
|
|
||||||
// Returns true iff the socket is ready for reading or
|
// Returns true iff the socket is ready for reading or
|
||||||
// writing.
|
// writing.
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
|
|
||||||
int mutex_init(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
InitializeCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_init(mutex, NULL))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_free(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
DeleteCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_destroy(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_lock(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
EnterCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_lock(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int mutex_unlock(Mutex *mutex)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
LeaveCriticalSection(mutex);
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
if (pthread_mutex_unlock(mutex))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
#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);
|
|
||||||
Reference in New Issue
Block a user