Add debug code to trace socket state transitions and fix bug in response parser where a space was consumed twice

This commit is contained in:
2025-11-26 15:33:15 +01:00
parent aa158980f5
commit 749aef7c8d
6 changed files with 336 additions and 228 deletions
+164 -114
View File
@@ -1179,12 +1179,11 @@ static int parse_response(Scanner *s, HTTP_Response *res)
return -1; return -1;
} }
if (s->len - s->cur < 5 if (s->len - s->cur < 4
|| s->src[s->cur+0] != ' ' || !is_digit(s->src[s->cur+0])
|| !is_digit(s->src[s->cur+1]) || !is_digit(s->src[s->cur+1])
|| !is_digit(s->src[s->cur+2]) || !is_digit(s->src[s->cur+2])
|| !is_digit(s->src[s->cur+3]) || s->src[s->cur+3] != ' ')
|| s->src[s->cur+4] != ' ')
return -1; return -1;
s->cur += 5; s->cur += 5;
@@ -1969,6 +1968,35 @@ int server_secure_context_add_certificate(ServerSecureContext *ctx,
// src/socket.c // src/socket.c
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
#define TRACE_STATE_CHANGES
#ifndef TRACE_STATE_CHANGES
#define UPDATE_STATE(a, b) a = b
#else
static char *state_to_str(SocketState state)
{
switch (state) {
case SOCKET_STATE_FREE : return "FREE";
case SOCKET_STATE_PENDING : return "PENDING";
case SOCKET_STATE_CONNECTING: return "CONNECTING";
case SOCKET_STATE_CONNECTED : return "CONNECTED";
case SOCKET_STATE_ACCEPTED : return "ACCEPTED";
case SOCKET_STATE_ESTABLISHED_WAIT : return "ESTABLISHED_WAIT";
case SOCKET_STATE_ESTABLISHED_READY: return "ESTABLISHED_READY";
case SOCKET_STATE_SHUTDOWN : return "SHUTDOWN";
case SOCKET_STATE_DIED : return "DIED";
}
return "???";
}
#define UPDATE_STATE(a, b) { \
printf("%s -> %s %s:%d\n", \
state_to_str(a), \
state_to_str(b), \
__FILE__, __LINE__); \
a = b; \
}
#endif
static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b) static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b)
{ {
#ifdef _WIN32 #ifdef _WIN32
@@ -2300,7 +2328,7 @@ static void socket_update(Socket *s)
s->next_addr++; s->next_addr++;
if (s->next_addr == s->num_addr) { if (s->next_addr == s->num_addr) {
// All addresses have been tried and failed // All addresses have been tried and failed
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
@@ -2315,14 +2343,14 @@ static void socket_update(Socket *s)
int family = (addr.is_ipv4 ? AF_INET : AF_INET6); int family = (addr.is_ipv4 ? AF_INET : AF_INET6);
NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0); NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0);
if (sock == NATIVE_SOCKET_INVALID) { if (sock == NATIVE_SOCKET_INVALID) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
if (set_socket_blocking(sock, false) < 0) { if (set_socket_blocking(sock, false) < 0) {
CLOSE_NATIVE_SOCKET(sock); CLOSE_NATIVE_SOCKET(sock);
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
@@ -2345,25 +2373,25 @@ static void socket_update(Socket *s)
if (ret == 0) { if (ret == 0) {
// Connect resolved immediately // Connect resolved immediately
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_CONNECTED; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTED);
s->events = 0; s->events = 0;
again = true; again = true;
} else if (connect_pending()) { } else if (connect_pending()) {
// Connect is pending, which is expected // Connect is pending, which is expected
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_CONNECTING; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTING);
s->events = POLLOUT; s->events = POLLOUT;
} else if (connect_failed_because_of_peer()) { } else if (connect_failed_because_of_peer()) {
// Conenct failed due to the peer host // Conenct failed due to the peer host
// We should try a different address. // We should try a different address.
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
} else { } else {
// An error occurred that we can't recover from // An error occurred that we can't recover from
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
again = true; again = true;
} }
@@ -2379,23 +2407,23 @@ static void socket_update(Socket *s)
socklen_t len = sizeof(err); socklen_t len = sizeof(err);
if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) { if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) {
// Failed to get socket error status // Failed to get socket error status
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
if (err == 0) { if (err == 0) {
// Connection succeded // Connection succeded
s->state = SOCKET_STATE_CONNECTED; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTED);
s->events = 0; s->events = 0;
again = true; again = true;
} else if (connect_failed_because_of_peer_2(err)) { } else if (connect_failed_because_of_peer_2(err)) {
// Try the next address // Try the next address
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
} else { } else {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
} }
@@ -2412,19 +2440,19 @@ static void socket_update(Socket *s)
free(s->addrs); free(s->addrs);
s->events = 0; s->events = 0;
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->ssl = SSL_new(s->client_secure_context->p); s->ssl = SSL_new(s->client_secure_context->p);
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
if (SSL_set_fd(s->ssl, s->sock) != 1) { if (SSL_set_fd(s->ssl, s->sock) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2439,7 +2467,7 @@ static void socket_update(Socket *s)
// Set expected hostname for verification // Set expected hostname for verification
if (SSL_set1_host(s->ssl, addr.name->data) != 1) { if (SSL_set1_host(s->ssl, addr.name->data) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2468,7 +2496,7 @@ static void socket_update(Socket *s)
free(s->addrs); free(s->addrs);
} }
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2484,7 +2512,7 @@ static void socket_update(Socket *s)
break; break;
} }
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
#endif #endif
@@ -2495,7 +2523,7 @@ static void socket_update(Socket *s)
case SOCKET_STATE_ACCEPTED: case SOCKET_STATE_ACCEPTED:
{ {
if (!is_secure(s)) { if (!is_secure(s)) {
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
@@ -2504,13 +2532,13 @@ static void socket_update(Socket *s)
s->ssl = SSL_new(s->server_secure_context->p); s->ssl = SSL_new(s->server_secure_context->p);
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
if (SSL_set_fd(s->ssl, s->sock) != 1) { if (SSL_set_fd(s->ssl, s->sock) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2519,7 +2547,7 @@ static void socket_update(Socket *s)
int ret = SSL_accept(s->ssl); int ret = SSL_accept(s->ssl);
if (ret == 1) { if (ret == 1) {
// Handshake done // Handshake done
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2536,7 +2564,7 @@ static void socket_update(Socket *s)
} }
// Server socket error - close the connection // Server socket error - close the connection
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
#endif #endif
} }
@@ -2544,20 +2572,20 @@ static void socket_update(Socket *s)
break; break;
case SOCKET_STATE_ESTABLISHED_WAIT: case SOCKET_STATE_ESTABLISHED_WAIT:
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
case SOCKET_STATE_SHUTDOWN: case SOCKET_STATE_SHUTDOWN:
{ {
if (!is_secure(s)) { if (!is_secure(s)) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
int ret = SSL_shutdown(s->ssl); int ret = SSL_shutdown(s->ssl);
if (ret == 1) { if (ret == 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -2573,7 +2601,7 @@ static void socket_update(Socket *s)
break; break;
} }
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
#endif #endif
} }
@@ -2758,7 +2786,7 @@ static int socket_manager_translate_events_nolock(
socket_update(s); socket_update(s);
if (s->state == SOCKET_STATE_DIED) { if (s->state == SOCKET_STATE_DIED) {
CLOSE_NATIVE_SOCKET(sock); CLOSE_NATIVE_SOCKET(sock);
s->state = SOCKET_STATE_FREE; UPDATE_STATE(s->state, SOCKET_STATE_FREE);
s->gen++; s->gen++;
if (s->gen == 0) if (s->gen == 0)
s->gen = 1; s->gen = 1;
@@ -2800,7 +2828,7 @@ static int socket_manager_translate_events_nolock(
}; };
// Free resources associated to socket // Free resources associated to socket
s->state = SOCKET_STATE_FREE; UPDATE_STATE(s->state, SOCKET_STATE_FREE);
if (s->sock != NATIVE_SOCKET_INVALID) if (s->sock != NATIVE_SOCKET_INVALID)
CLOSE_NATIVE_SOCKET(s->sock); CLOSE_NATIVE_SOCKET(s->sock);
if (s->sock == SOCKET_STATE_PENDING || if (s->sock == SOCKET_STATE_PENDING ||
@@ -2989,7 +3017,7 @@ int socket_connect(SocketManager *sm, int num_targets,
s->addrs[i] = resolved[i]; s->addrs[i] = resolved[i];
} }
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->sock = NATIVE_SOCKET_INVALID; s->sock = NATIVE_SOCKET_INVALID;
s->user = user; s->user = user;
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
@@ -3032,7 +3060,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
if (s->state != SOCKET_STATE_ESTABLISHED_READY) { if (s->state != SOCKET_STATE_ESTABLISHED_READY) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
return 0; return 0;
} }
@@ -3040,14 +3068,14 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
if (!is_secure(s)) { if (!is_secure(s)) {
int ret = recv(s->sock, dst, max, 0); int ret = recv(s->sock, dst, max, 0);
if (ret == 0) { if (ret == 0) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} else if (ret < 0) { } else if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLIN; s->events = POLLIN;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -3062,7 +3090,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
s->state = SOCKET_STATE_ESTABLISHED_WAIT; s->state = SOCKET_STATE_ESTABLISHED_WAIT;
s->events = POLLIN; s->events = POLLIN;
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLOUT; s->events = POLLOUT;
} else { } else {
s->state = SOCKET_STATE_DIED; s->state = SOCKET_STATE_DIED;
@@ -3096,7 +3124,7 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
if (s->state != SOCKET_STATE_ESTABLISHED_READY) { if (s->state != SOCKET_STATE_ESTABLISHED_READY) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
return 0; return 0;
} }
@@ -3105,10 +3133,10 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
int ret = send(s->sock, src, len, 0); int ret = send(s->sock, src, len, 0);
if (ret < 0) { if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLOUT; s->events = POLLOUT;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -3161,7 +3189,7 @@ int socket_close(SocketManager *sm, SocketHandle handle)
else { else {
// Only transition to SHUTDOWN if socket is not already DIED // Only transition to SHUTDOWN if socket is not already DIED
if (s->state != SOCKET_STATE_DIED) { if (s->state != SOCKET_STATE_DIED) {
s->state = SOCKET_STATE_SHUTDOWN; UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
s->events = 0; s->events = 0;
socket_update(s); socket_update(s);
} }
@@ -3209,6 +3237,24 @@ int socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
return ret; return ret;
} }
bool socket_ready(SocketManager *sm, SocketHandle handle)
{
if (mutex_lock(&sm->mutex) < 0) {
assert(0); // TODO
}
bool ready = false;
Socket *s = handle_to_socket(sm, handle);
if (s && s->events == 0 && s->state != SOCKET_STATE_DIED) {
ready = true;
}
if (mutex_unlock(&sm->mutex) < 0) {
assert(0); // TODO
}
return ready;
}
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/byte_queue.c // src/byte_queue.c
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@@ -4196,88 +4242,92 @@ int http_client_process_events(HTTP_Client *client,
if (conn->handle == SOCKET_HANDLE_INVALID) if (conn->handle == SOCKET_HANDLE_INVALID)
conn->handle = events[i].handle; conn->handle = events[i].handle;
if (conn->state == HTTP_CLIENT_CONN_FLUSHING) { while (socket_ready(&client->sockets, conn->handle)) {
ByteView src = byte_queue_read_buf(&conn->output); if (conn->state == HTTP_CLIENT_CONN_FLUSHING) {
int num = 0; ByteView src = byte_queue_read_buf(&conn->output);
if (src.len)
num = socket_send(&client->sockets, conn->handle, src.ptr, src.len);
if (conn->trace_bytes) int num = 0;
print_bytes(HTTP_STR("<< "), (HTTP_String){src.ptr, num}); if (src.len)
num = socket_send(&client->sockets, conn->handle, src.ptr, src.len);
byte_queue_read_ack(&conn->output, num); if (conn->trace_bytes)
print_bytes(HTTP_STR("<< "), (HTTP_String){src.ptr, num});
if (byte_queue_error(&conn->output)) { byte_queue_read_ack(&conn->output, num);
socket_close(&client->sockets, conn->handle);
continue;
}
// Request fully sent, now wait for response if (byte_queue_error(&conn->output)) {
if (byte_queue_empty(&conn->output))
conn->state = HTTP_CLIENT_CONN_BUFFERING;
}
if (conn->state == HTTP_CLIENT_CONN_BUFFERING) {
// Receive response data
int min_recv = 1<<10;
byte_queue_write_setmincap(&conn->input, min_recv);
ByteView dst = byte_queue_write_buf(&conn->input);
int num = 0;
if (dst.len)
num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len);
if (conn->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String){dst.ptr, num});
byte_queue_write_ack(&conn->input, num);
if (byte_queue_error(&conn->input)) {
socket_close(&client->sockets, conn->handle);
continue;
}
ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_response(src.ptr, src.len, &conn->response);
if (ret == 0) {
// Still waiting
byte_queue_read_ack(&conn->input, 0);
// If the queue reached its limit and we still didn't receive
// a complete response, abort the exchange.
if (byte_queue_full(&conn->input))
socket_close(&client->sockets, conn->handle); socket_close(&client->sockets, conn->handle);
continue; continue;
}
// Request fully sent, now wait for response
if (byte_queue_empty(&conn->output))
conn->state = HTTP_CLIENT_CONN_BUFFERING;
} }
if (ret < 0) { if (conn->state == HTTP_CLIENT_CONN_BUFFERING) {
// Invalid response
byte_queue_read_ack(&conn->input, 0); // Receive response data
socket_close(&client->sockets, conn->handle); int min_recv = 1<<10;
continue; byte_queue_write_setmincap(&conn->input, min_recv);
ByteView dst = byte_queue_write_buf(&conn->input);
int num = 0;
if (dst.len)
num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len);
if (conn->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String){dst.ptr, num});
byte_queue_write_ack(&conn->input, num);
if (byte_queue_error(&conn->input)) {
socket_close(&client->sockets, conn->handle);
continue;
}
ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_response(src.ptr, src.len, &conn->response);
if (ret == 0) {
// Still waiting
byte_queue_read_ack(&conn->input, 0);
// If the queue reached its limit and we still didn't receive
// a complete response, abort the exchange.
if (byte_queue_full(&conn->input))
socket_close(&client->sockets, conn->handle);
continue;
}
if (ret < 0) {
// Invalid response
byte_queue_read_ack(&conn->input, 0);
socket_close(&client->sockets, conn->handle);
continue;
}
// Ready
assert(ret > 0);
conn->state = HTTP_CLIENT_CONN_COMPLETE;
conn->result = 0;
conn->response.context = client;
// Store received cookies in the cookie jar
save_cookies(&client->cookie_jar,
conn->response.headers,
conn->response.num_headers,
conn->url.authority.host.text,
conn->url.path);
// TODO: Handle redirects here
break;
} }
// Ready
assert(ret == 1);
conn->state = HTTP_CLIENT_CONN_COMPLETE;
conn->result = 0;
conn->response.context = client;
// Store received cookies in the cookie jar
save_cookies(&client->cookie_jar,
conn->response.headers,
conn->response.num_headers,
conn->url.authority.host.text,
conn->url.path);
// TODO: Handle redirects here
} }
} }
+4
View File
@@ -649,6 +649,10 @@ int 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); int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
// Returns true iff the socket is ready for reading or
// writing.
bool socket_ready(SocketManager *sm, SocketHandle handle);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// src/byte_queue.h // src/byte_queue.h
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
+76 -72
View File
@@ -523,88 +523,92 @@ int http_client_process_events(HTTP_Client *client,
if (conn->handle == SOCKET_HANDLE_INVALID) if (conn->handle == SOCKET_HANDLE_INVALID)
conn->handle = events[i].handle; conn->handle = events[i].handle;
if (conn->state == HTTP_CLIENT_CONN_FLUSHING) { while (socket_ready(&client->sockets, conn->handle)) {
ByteView src = byte_queue_read_buf(&conn->output); if (conn->state == HTTP_CLIENT_CONN_FLUSHING) {
int num = 0; ByteView src = byte_queue_read_buf(&conn->output);
if (src.len)
num = socket_send(&client->sockets, conn->handle, src.ptr, src.len);
if (conn->trace_bytes) int num = 0;
print_bytes(HTTP_STR("<< "), (HTTP_String){src.ptr, num}); if (src.len)
num = socket_send(&client->sockets, conn->handle, src.ptr, src.len);
byte_queue_read_ack(&conn->output, num); if (conn->trace_bytes)
print_bytes(HTTP_STR("<< "), (HTTP_String){src.ptr, num});
if (byte_queue_error(&conn->output)) { byte_queue_read_ack(&conn->output, num);
socket_close(&client->sockets, conn->handle);
continue;
}
// Request fully sent, now wait for response if (byte_queue_error(&conn->output)) {
if (byte_queue_empty(&conn->output))
conn->state = HTTP_CLIENT_CONN_BUFFERING;
}
if (conn->state == HTTP_CLIENT_CONN_BUFFERING) {
// Receive response data
int min_recv = 1<<10;
byte_queue_write_setmincap(&conn->input, min_recv);
ByteView dst = byte_queue_write_buf(&conn->input);
int num = 0;
if (dst.len)
num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len);
if (conn->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String){dst.ptr, num});
byte_queue_write_ack(&conn->input, num);
if (byte_queue_error(&conn->input)) {
socket_close(&client->sockets, conn->handle);
continue;
}
ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_response(src.ptr, src.len, &conn->response);
if (ret == 0) {
// Still waiting
byte_queue_read_ack(&conn->input, 0);
// If the queue reached its limit and we still didn't receive
// a complete response, abort the exchange.
if (byte_queue_full(&conn->input))
socket_close(&client->sockets, conn->handle); socket_close(&client->sockets, conn->handle);
continue; continue;
}
// Request fully sent, now wait for response
if (byte_queue_empty(&conn->output))
conn->state = HTTP_CLIENT_CONN_BUFFERING;
} }
if (ret < 0) { if (conn->state == HTTP_CLIENT_CONN_BUFFERING) {
// Invalid response
byte_queue_read_ack(&conn->input, 0); // Receive response data
socket_close(&client->sockets, conn->handle); int min_recv = 1<<10;
continue; byte_queue_write_setmincap(&conn->input, min_recv);
ByteView dst = byte_queue_write_buf(&conn->input);
int num = 0;
if (dst.len)
num = socket_recv(&client->sockets, conn->handle, dst.ptr, dst.len);
if (conn->trace_bytes)
print_bytes(HTTP_STR(">> "), (HTTP_String){dst.ptr, num});
byte_queue_write_ack(&conn->input, num);
if (byte_queue_error(&conn->input)) {
socket_close(&client->sockets, conn->handle);
continue;
}
ByteView src = byte_queue_read_buf(&conn->input);
int ret = http_parse_response(src.ptr, src.len, &conn->response);
if (ret == 0) {
// Still waiting
byte_queue_read_ack(&conn->input, 0);
// If the queue reached its limit and we still didn't receive
// a complete response, abort the exchange.
if (byte_queue_full(&conn->input))
socket_close(&client->sockets, conn->handle);
continue;
}
if (ret < 0) {
// Invalid response
byte_queue_read_ack(&conn->input, 0);
socket_close(&client->sockets, conn->handle);
continue;
}
// Ready
assert(ret > 0);
conn->state = HTTP_CLIENT_CONN_COMPLETE;
conn->result = 0;
conn->response.context = client;
// Store received cookies in the cookie jar
save_cookies(&client->cookie_jar,
conn->response.headers,
conn->response.num_headers,
conn->url.authority.host.text,
conn->url.path);
// TODO: Handle redirects here
break;
} }
// Ready
assert(ret == 1);
conn->state = HTTP_CLIENT_CONN_COMPLETE;
conn->result = 0;
conn->response.context = client;
// Store received cookies in the cookie jar
save_cookies(&client->cookie_jar,
conn->response.headers,
conn->response.num_headers,
conn->url.authority.host.text,
conn->url.path);
// TODO: Handle redirects here
} }
} }
+3 -4
View File
@@ -1067,12 +1067,11 @@ static int parse_response(Scanner *s, HTTP_Response *res)
return -1; return -1;
} }
if (s->len - s->cur < 5 if (s->len - s->cur < 4
|| s->src[s->cur+0] != ' ' || !is_digit(s->src[s->cur+0])
|| !is_digit(s->src[s->cur+1]) || !is_digit(s->src[s->cur+1])
|| !is_digit(s->src[s->cur+2]) || !is_digit(s->src[s->cur+2])
|| !is_digit(s->src[s->cur+3]) || s->src[s->cur+3] != ' ')
|| s->src[s->cur+4] != ' ')
return -1; return -1;
s->cur += 5; s->cur += 5;
+85 -38
View File
@@ -1,4 +1,33 @@
//#define TRACE_STATE_CHANGES
#ifndef TRACE_STATE_CHANGES
#define UPDATE_STATE(a, b) a = b
#else
static char *state_to_str(SocketState state)
{
switch (state) {
case SOCKET_STATE_FREE : return "FREE";
case SOCKET_STATE_PENDING : return "PENDING";
case SOCKET_STATE_CONNECTING: return "CONNECTING";
case SOCKET_STATE_CONNECTED : return "CONNECTED";
case SOCKET_STATE_ACCEPTED : return "ACCEPTED";
case SOCKET_STATE_ESTABLISHED_WAIT : return "ESTABLISHED_WAIT";
case SOCKET_STATE_ESTABLISHED_READY: return "ESTABLISHED_READY";
case SOCKET_STATE_SHUTDOWN : return "SHUTDOWN";
case SOCKET_STATE_DIED : return "DIED";
}
return "???";
}
#define UPDATE_STATE(a, b) { \
printf("%s -> %s %s:%d\n", \
state_to_str(a), \
state_to_str(b), \
__FILE__, __LINE__); \
a = b; \
}
#endif
static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b) static int create_socket_pair(NATIVE_SOCKET *a, NATIVE_SOCKET *b)
{ {
#ifdef _WIN32 #ifdef _WIN32
@@ -330,7 +359,7 @@ static void socket_update(Socket *s)
s->next_addr++; s->next_addr++;
if (s->next_addr == s->num_addr) { if (s->next_addr == s->num_addr) {
// All addresses have been tried and failed // All addresses have been tried and failed
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
@@ -345,14 +374,14 @@ static void socket_update(Socket *s)
int family = (addr.is_ipv4 ? AF_INET : AF_INET6); int family = (addr.is_ipv4 ? AF_INET : AF_INET6);
NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0); NATIVE_SOCKET sock = socket(family, SOCK_STREAM, 0);
if (sock == NATIVE_SOCKET_INVALID) { if (sock == NATIVE_SOCKET_INVALID) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
if (set_socket_blocking(sock, false) < 0) { if (set_socket_blocking(sock, false) < 0) {
CLOSE_NATIVE_SOCKET(sock); CLOSE_NATIVE_SOCKET(sock);
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
@@ -375,25 +404,25 @@ static void socket_update(Socket *s)
if (ret == 0) { if (ret == 0) {
// Connect resolved immediately // Connect resolved immediately
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_CONNECTED; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTED);
s->events = 0; s->events = 0;
again = true; again = true;
} else if (connect_pending()) { } else if (connect_pending()) {
// Connect is pending, which is expected // Connect is pending, which is expected
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_CONNECTING; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTING);
s->events = POLLOUT; s->events = POLLOUT;
} else if (connect_failed_because_of_peer()) { } else if (connect_failed_because_of_peer()) {
// Conenct failed due to the peer host // Conenct failed due to the peer host
// We should try a different address. // We should try a different address.
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
} else { } else {
// An error occurred that we can't recover from // An error occurred that we can't recover from
s->sock = sock; s->sock = sock;
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
again = true; again = true;
} }
@@ -409,23 +438,23 @@ static void socket_update(Socket *s)
socklen_t len = sizeof(err); socklen_t len = sizeof(err);
if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) { if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) < 0) {
// Failed to get socket error status // Failed to get socket error status
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
continue; continue;
} }
if (err == 0) { if (err == 0) {
// Connection succeded // Connection succeded
s->state = SOCKET_STATE_CONNECTED; UPDATE_STATE(s->state, SOCKET_STATE_CONNECTED);
s->events = 0; s->events = 0;
again = true; again = true;
} else if (connect_failed_because_of_peer_2(err)) { } else if (connect_failed_because_of_peer_2(err)) {
// Try the next address // Try the next address
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
} else { } else {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
} }
@@ -442,19 +471,19 @@ static void socket_update(Socket *s)
free(s->addrs); free(s->addrs);
s->events = 0; s->events = 0;
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->ssl = SSL_new(s->client_secure_context->p); s->ssl = SSL_new(s->client_secure_context->p);
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
if (SSL_set_fd(s->ssl, s->sock) != 1) { if (SSL_set_fd(s->ssl, s->sock) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -469,7 +498,7 @@ static void socket_update(Socket *s)
// Set expected hostname for verification // Set expected hostname for verification
if (SSL_set1_host(s->ssl, addr.name->data) != 1) { if (SSL_set1_host(s->ssl, addr.name->data) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -498,7 +527,7 @@ static void socket_update(Socket *s)
free(s->addrs); free(s->addrs);
} }
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
} }
@@ -514,7 +543,7 @@ static void socket_update(Socket *s)
break; break;
} }
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->events = 0; s->events = 0;
again = true; again = true;
#endif #endif
@@ -525,7 +554,7 @@ static void socket_update(Socket *s)
case SOCKET_STATE_ACCEPTED: case SOCKET_STATE_ACCEPTED:
{ {
if (!is_secure(s)) { if (!is_secure(s)) {
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
@@ -534,13 +563,13 @@ static void socket_update(Socket *s)
s->ssl = SSL_new(s->server_secure_context->p); s->ssl = SSL_new(s->server_secure_context->p);
if (s->ssl == NULL) { if (s->ssl == NULL) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
if (SSL_set_fd(s->ssl, s->sock) != 1) { if (SSL_set_fd(s->ssl, s->sock) != 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -549,7 +578,7 @@ static void socket_update(Socket *s)
int ret = SSL_accept(s->ssl); int ret = SSL_accept(s->ssl);
if (ret == 1) { if (ret == 1) {
// Handshake done // Handshake done
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
} }
@@ -566,7 +595,7 @@ static void socket_update(Socket *s)
} }
// Server socket error - close the connection // Server socket error - close the connection
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
#endif #endif
} }
@@ -574,20 +603,20 @@ static void socket_update(Socket *s)
break; break;
case SOCKET_STATE_ESTABLISHED_WAIT: case SOCKET_STATE_ESTABLISHED_WAIT:
s->state = SOCKET_STATE_ESTABLISHED_READY; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_READY);
s->events = 0; s->events = 0;
break; break;
case SOCKET_STATE_SHUTDOWN: case SOCKET_STATE_SHUTDOWN:
{ {
if (!is_secure(s)) { if (!is_secure(s)) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} else { } else {
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
int ret = SSL_shutdown(s->ssl); int ret = SSL_shutdown(s->ssl);
if (ret == 1) { if (ret == 1) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
break; break;
} }
@@ -603,7 +632,7 @@ static void socket_update(Socket *s)
break; break;
} }
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
#endif #endif
} }
@@ -788,7 +817,7 @@ static int socket_manager_translate_events_nolock(
socket_update(s); socket_update(s);
if (s->state == SOCKET_STATE_DIED) { if (s->state == SOCKET_STATE_DIED) {
CLOSE_NATIVE_SOCKET(sock); CLOSE_NATIVE_SOCKET(sock);
s->state = SOCKET_STATE_FREE; UPDATE_STATE(s->state, SOCKET_STATE_FREE);
s->gen++; s->gen++;
if (s->gen == 0) if (s->gen == 0)
s->gen = 1; s->gen = 1;
@@ -830,7 +859,7 @@ static int socket_manager_translate_events_nolock(
}; };
// Free resources associated to socket // Free resources associated to socket
s->state = SOCKET_STATE_FREE; UPDATE_STATE(s->state, SOCKET_STATE_FREE);
if (s->sock != NATIVE_SOCKET_INVALID) if (s->sock != NATIVE_SOCKET_INVALID)
CLOSE_NATIVE_SOCKET(s->sock); CLOSE_NATIVE_SOCKET(s->sock);
if (s->sock == SOCKET_STATE_PENDING || if (s->sock == SOCKET_STATE_PENDING ||
@@ -1019,7 +1048,7 @@ int socket_connect(SocketManager *sm, int num_targets,
s->addrs[i] = resolved[i]; s->addrs[i] = resolved[i];
} }
s->state = SOCKET_STATE_PENDING; UPDATE_STATE(s->state, SOCKET_STATE_PENDING);
s->sock = NATIVE_SOCKET_INVALID; s->sock = NATIVE_SOCKET_INVALID;
s->user = user; s->user = user;
#ifdef HTTPS_ENABLED #ifdef HTTPS_ENABLED
@@ -1062,7 +1091,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
if (s->state != SOCKET_STATE_ESTABLISHED_READY) { if (s->state != SOCKET_STATE_ESTABLISHED_READY) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
return 0; return 0;
} }
@@ -1070,14 +1099,14 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
if (!is_secure(s)) { if (!is_secure(s)) {
int ret = recv(s->sock, dst, max, 0); int ret = recv(s->sock, dst, max, 0);
if (ret == 0) { if (ret == 0) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} else if (ret < 0) { } else if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLIN; s->events = POLLIN;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -1092,7 +1121,7 @@ static int socket_recv_nolock(SocketManager *sm, SocketHandle handle,
s->state = SOCKET_STATE_ESTABLISHED_WAIT; s->state = SOCKET_STATE_ESTABLISHED_WAIT;
s->events = POLLIN; s->events = POLLIN;
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLOUT; s->events = POLLOUT;
} else { } else {
s->state = SOCKET_STATE_DIED; s->state = SOCKET_STATE_DIED;
@@ -1126,7 +1155,7 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
return 0; return 0;
if (s->state != SOCKET_STATE_ESTABLISHED_READY) { if (s->state != SOCKET_STATE_ESTABLISHED_READY) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
return 0; return 0;
} }
@@ -1135,10 +1164,10 @@ static int socket_send_nolock(SocketManager *sm, SocketHandle handle,
int ret = send(s->sock, src, len, 0); int ret = send(s->sock, src, len, 0);
if (ret < 0) { if (ret < 0) {
if (would_block()) { if (would_block()) {
s->state = SOCKET_STATE_ESTABLISHED_WAIT; UPDATE_STATE(s->state, SOCKET_STATE_ESTABLISHED_WAIT);
s->events = POLLOUT; s->events = POLLOUT;
} else if (!interrupted()) { } else if (!interrupted()) {
s->state = SOCKET_STATE_DIED; UPDATE_STATE(s->state, SOCKET_STATE_DIED);
s->events = 0; s->events = 0;
} }
ret = 0; ret = 0;
@@ -1191,7 +1220,7 @@ int socket_close(SocketManager *sm, SocketHandle handle)
else { else {
// Only transition to SHUTDOWN if socket is not already DIED // Only transition to SHUTDOWN if socket is not already DIED
if (s->state != SOCKET_STATE_DIED) { if (s->state != SOCKET_STATE_DIED) {
s->state = SOCKET_STATE_SHUTDOWN; UPDATE_STATE(s->state, SOCKET_STATE_SHUTDOWN);
s->events = 0; s->events = 0;
socket_update(s); socket_update(s);
} }
@@ -1238,3 +1267,21 @@ int socket_set_user(SocketManager *sm, SocketHandle handle, void *user)
return -1; return -1;
return ret; return ret;
} }
bool socket_ready(SocketManager *sm, SocketHandle handle)
{
if (mutex_lock(&sm->mutex) < 0) {
assert(0); // TODO
}
bool ready = false;
Socket *s = handle_to_socket(sm, handle);
if (s && s->events == 0 && s->state != SOCKET_STATE_DIED) {
ready = true;
}
if (mutex_unlock(&sm->mutex) < 0) {
assert(0); // TODO
}
return ready;
}
+4
View File
@@ -331,3 +331,7 @@ int 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); int socket_set_user(SocketManager *sm, SocketHandle handle, void *user);
// Returns true iff the socket is ready for reading or
// writing.
bool socket_ready(SocketManager *sm, SocketHandle handle);