Merge pull request #9 from cozis/claude/set-sockets-nonblocking-011CUxtZsiieE2szQupw9Ghm
Set sockets as non-blocking in tcp.c and add blocking checks
This commit is contained in:
+106
@@ -4,6 +4,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "chunk_server.h"
|
#include "chunk_server.h"
|
||||||
@@ -98,6 +99,9 @@ typedef struct {
|
|||||||
// last "poll" call.
|
// last "poll" call.
|
||||||
void *context;
|
void *context;
|
||||||
|
|
||||||
|
// Whether this socket is configured as non-blocking
|
||||||
|
bool is_nonblocking;
|
||||||
|
|
||||||
// Address bound to this descriptor by the
|
// Address bound to this descriptor by the
|
||||||
// "bind" call.
|
// "bind" call.
|
||||||
DescriptorAddress address;
|
DescriptorAddress address;
|
||||||
@@ -811,6 +815,7 @@ SOCKET mock_socket(int domain, int type, int protocol)
|
|||||||
desc->events = 0;
|
desc->events = 0;
|
||||||
desc->revents = 0;
|
desc->revents = 0;
|
||||||
desc->context = NULL;
|
desc->context = NULL;
|
||||||
|
desc->is_nonblocking = false;
|
||||||
desc->address = (DescriptorAddress) { .type=DESC_ADDR_VOID };
|
desc->address = (DescriptorAddress) { .type=DESC_ADDR_VOID };
|
||||||
|
|
||||||
current_process->num_desc++;
|
current_process->num_desc++;
|
||||||
@@ -912,6 +917,11 @@ SOCKET mock_accept(SOCKET fd, void *addr, socklen_t *addr_len)
|
|||||||
|
|
||||||
DescriptorHandle peer_handle;
|
DescriptorHandle peer_handle;
|
||||||
if (!accept_queue_pop(&desc->accept_queue, &peer_handle)) {
|
if (!accept_queue_pop(&desc->accept_queue, &peer_handle)) {
|
||||||
|
// Socket would block - abort if not configured as non-blocking
|
||||||
|
if (!desc->is_nonblocking) {
|
||||||
|
fprintf(stderr, "SIMULATION ERROR: accept() would block on socket %d but socket is not configured as non-blocking\n", (int)fd);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK); // Would block (no pending connections)
|
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK); // Would block (no pending connections)
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
@@ -937,6 +947,7 @@ SOCKET mock_accept(SOCKET fd, void *addr, socklen_t *addr_len)
|
|||||||
new_desc->events = 0;
|
new_desc->events = 0;
|
||||||
new_desc->revents = 0;
|
new_desc->revents = 0;
|
||||||
new_desc->context = NULL;
|
new_desc->context = NULL;
|
||||||
|
new_desc->is_nonblocking = false;
|
||||||
new_desc->address = (DescriptorAddress) { .type=DESC_ADDR_VOID };
|
new_desc->address = (DescriptorAddress) { .type=DESC_ADDR_VOID };
|
||||||
new_desc->connection_state = CONNECTION_ESTABLISHED;
|
new_desc->connection_state = CONNECTION_ESTABLISHED;
|
||||||
new_desc->connection_peer = peer_handle;
|
new_desc->connection_peer = peer_handle;
|
||||||
@@ -1063,6 +1074,11 @@ int mock_recv(SOCKET fd, void *dst, int len, int flags)
|
|||||||
|
|
||||||
// If no data available, would block
|
// If no data available, would block
|
||||||
if (bytes_read == 0) {
|
if (bytes_read == 0) {
|
||||||
|
// Socket would block - abort if not configured as non-blocking
|
||||||
|
if (!desc->is_nonblocking) {
|
||||||
|
fprintf(stderr, "SIMULATION ERROR: recv() would block on socket %d but socket is not configured as non-blocking\n", (int)fd);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK);
|
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1106,6 +1122,11 @@ int mock_send(SOCKET fd, void *src, int len, int flags)
|
|||||||
|
|
||||||
// If queue is full, we would block
|
// If queue is full, we would block
|
||||||
if (bytes_written < len) {
|
if (bytes_written < len) {
|
||||||
|
// Socket would block - abort if not configured as non-blocking
|
||||||
|
if (!desc->is_nonblocking && bytes_written == 0) {
|
||||||
|
fprintf(stderr, "SIMULATION ERROR: send() would block on socket %d but socket is not configured as non-blocking\n", (int)fd);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK);
|
SET_SOCKET_ERROR(SOCKET_ERROR_WOULDBLOCK);
|
||||||
return bytes_written > 0 ? bytes_written : -1;
|
return bytes_written > 0 ? bytes_written : -1;
|
||||||
}
|
}
|
||||||
@@ -1451,6 +1472,37 @@ BOOL mock_QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mock_ioctlsocket(SOCKET fd, long cmd, u_long *argp)
|
||||||
|
{
|
||||||
|
if (fd == INVALID_SOCKET || (int)fd < 0 || (int)fd >= MAX_DESCRIPTORS) {
|
||||||
|
SET_SOCKET_ERROR(SOCKET_ERROR_BADF);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = (int) fd;
|
||||||
|
Descriptor *desc = ¤t_process->desc[idx];
|
||||||
|
|
||||||
|
if (desc->type == DESC_EMPTY) {
|
||||||
|
SET_SOCKET_ERROR(SOCKET_ERROR_BADF);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->type != DESC_SOCKET &&
|
||||||
|
desc->type != DESC_LISTEN_SOCKET &&
|
||||||
|
desc->type != DESC_CONNECTION_SOCKET) {
|
||||||
|
SET_SOCKET_ERROR(SOCKET_ERROR_NOTSOCK);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == FIONBIO) {
|
||||||
|
desc->is_nonblocking = (*argp != 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_SOCKET_ERROR(SOCKET_ERROR_INVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int mock_clock_gettime(clockid_t clockid, struct timespec *tp)
|
int mock_clock_gettime(clockid_t clockid, struct timespec *tp)
|
||||||
@@ -1630,6 +1682,60 @@ int mock_mkdir(char *path, mode_t mode)
|
|||||||
return mkdir(path, mode);
|
return mkdir(path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mock_fcntl(int fd, int cmd, ...)
|
||||||
|
{
|
||||||
|
if (fd < 0 || fd >= MAX_DESCRIPTORS) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = fd;
|
||||||
|
Descriptor *desc = ¤t_process->desc[idx];
|
||||||
|
|
||||||
|
if (desc->type == DESC_EMPTY) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == F_GETFL) {
|
||||||
|
// Return flags - only O_NONBLOCK is tracked
|
||||||
|
if (desc->type == DESC_FILE) {
|
||||||
|
// For files, forward to real fcntl
|
||||||
|
return fcntl(desc->real_fd, cmd);
|
||||||
|
}
|
||||||
|
return desc->is_nonblocking ? O_NONBLOCK : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == F_SETFL) {
|
||||||
|
if (desc->type == DESC_FILE) {
|
||||||
|
// For files, forward to real fcntl
|
||||||
|
va_list args;
|
||||||
|
va_start(args, cmd);
|
||||||
|
int flags = va_arg(args, int);
|
||||||
|
va_end(args);
|
||||||
|
return fcntl(desc->real_fd, cmd, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->type != DESC_SOCKET &&
|
||||||
|
desc->type != DESC_LISTEN_SOCKET &&
|
||||||
|
desc->type != DESC_CONNECTION_SOCKET) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, cmd);
|
||||||
|
int flags = va_arg(args, int);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
desc->is_nonblocking = (flags & O_NONBLOCK) != 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // !_WIN32
|
#endif // !_WIN32
|
||||||
|
|
||||||
#endif // BUILD_TEST
|
#endif // BUILD_TEST
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ int mock_connect(SOCKET fd, void *addr, size_t addr_len);
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int mock_closesocket(SOCKET fd);
|
int mock_closesocket(SOCKET fd);
|
||||||
|
int mock_ioctlsocket(SOCKET fd, long cmd, u_long *argp);
|
||||||
HANDLE mock_CreateFileW(WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
HANDLE mock_CreateFileW(WCHAR *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||||
BOOL mock_CloseHandle(HANDLE handle);
|
BOOL mock_CloseHandle(HANDLE handle);
|
||||||
BOOL mock_LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh);
|
BOOL mock_LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh);
|
||||||
@@ -80,6 +81,7 @@ int mock_fstat(int fd, struct stat *buf);
|
|||||||
int mock_mkstemp(char *path);
|
int mock_mkstemp(char *path);
|
||||||
char* mock_realpath(char *path, char *dst);
|
char* mock_realpath(char *path, char *dst);
|
||||||
int mock_mkdir(char *path, mode_t mode);
|
int mock_mkdir(char *path, mode_t mode);
|
||||||
|
int mock_fcntl(int fd, int cmd, ...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
@@ -100,6 +102,7 @@ int mock_mkdir(char *path, mode_t mode);
|
|||||||
// Windows
|
// Windows
|
||||||
#define sys__mkdir mock__mkdir
|
#define sys__mkdir mock__mkdir
|
||||||
#define sys_closesocket mock_closesocket
|
#define sys_closesocket mock_closesocket
|
||||||
|
#define sys_ioctlsocket mock_ioctlsocket
|
||||||
#define sys_CreateFileW mock_CreateFileW
|
#define sys_CreateFileW mock_CreateFileW
|
||||||
#define sys_CloseHandle mock_CloseHandle
|
#define sys_CloseHandle mock_CloseHandle
|
||||||
#define sys_LockFile mock_LockFile
|
#define sys_LockFile mock_LockFile
|
||||||
@@ -124,6 +127,7 @@ int mock_mkdir(char *path, mode_t mode);
|
|||||||
#define sys_mkstemp mock_mkstemp
|
#define sys_mkstemp mock_mkstemp
|
||||||
#define sys_realpath mock_realpath
|
#define sys_realpath mock_realpath
|
||||||
#define sys_clock_gettime mock_clock_gettime
|
#define sys_clock_gettime mock_clock_gettime
|
||||||
|
#define sys_fcntl mock_fcntl
|
||||||
#define sys_getrandom mock_getrandom
|
#define sys_getrandom mock_getrandom
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -146,6 +150,7 @@ int mock_mkdir(char *path, mode_t mode);
|
|||||||
// Windows
|
// Windows
|
||||||
#define sys__mkdir _mkdir
|
#define sys__mkdir _mkdir
|
||||||
#define sys_closesocket closesocket
|
#define sys_closesocket closesocket
|
||||||
|
#define sys_ioctlsocket ioctlsocket
|
||||||
#define sys_CreateFileW CreateFileW
|
#define sys_CreateFileW CreateFileW
|
||||||
#define sys_CloseHandle CloseHandle
|
#define sys_CloseHandle CloseHandle
|
||||||
#define sys_LockFile LockFile
|
#define sys_LockFile LockFile
|
||||||
@@ -170,6 +175,7 @@ int mock_mkdir(char *path, mode_t mode);
|
|||||||
#define sys_mkstemp mkstemp
|
#define sys_mkstemp mkstemp
|
||||||
#define sys_realpath realpath
|
#define sys_realpath realpath
|
||||||
#define sys_clock_gettime clock_gettime
|
#define sys_clock_gettime clock_gettime
|
||||||
|
#define sys_fcntl fcntl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // SYSTEM_INCLUDED
|
#endif // SYSTEM_INCLUDED
|
||||||
|
|||||||
@@ -30,6 +30,21 @@ static SOCKET create_listen_socket(string addr, uint16_t port)
|
|||||||
if (fd == INVALID_SOCKET)
|
if (fd == INVALID_SOCKET)
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
|
// Set socket as non-blocking
|
||||||
|
#ifdef _WIN32
|
||||||
|
u_long mode = 1;
|
||||||
|
if (sys_ioctlsocket(fd, FIONBIO, &mode) != 0) {
|
||||||
|
CLOSE_SOCKET(fd);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int flags = sys_fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags < 0 || sys_fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
|
CLOSE_SOCKET(fd);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
char tmp[1<<10];
|
char tmp[1<<10];
|
||||||
if (addr.len >= (int) sizeof(tmp))
|
if (addr.len >= (int) sizeof(tmp))
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
@@ -200,6 +215,20 @@ int tcp_translate_events(TCP *tcp, Event *events, void **contexts, struct pollfd
|
|||||||
|
|
||||||
SOCKET new_fd = sys_accept(tcp->listen_fd, NULL, NULL);
|
SOCKET new_fd = sys_accept(tcp->listen_fd, NULL, NULL);
|
||||||
if (new_fd != INVALID_SOCKET) {
|
if (new_fd != INVALID_SOCKET) {
|
||||||
|
// Set accepted socket as non-blocking
|
||||||
|
#ifdef _WIN32
|
||||||
|
u_long mode = 1;
|
||||||
|
if (sys_ioctlsocket(new_fd, FIONBIO, &mode) != 0) {
|
||||||
|
CLOSE_SOCKET(new_fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int flags = sys_fcntl(new_fd, F_GETFL, 0);
|
||||||
|
if (flags < 0 || sys_fcntl(new_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
|
CLOSE_SOCKET(new_fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
events[num_events++] = (Event) { EVENT_CONNECT, tcp->num_conns };
|
events[num_events++] = (Event) { EVENT_CONNECT, tcp->num_conns };
|
||||||
conn_init(&tcp->conns[tcp->num_conns++], new_fd, false);
|
conn_init(&tcp->conns[tcp->num_conns++], new_fd, false);
|
||||||
}
|
}
|
||||||
@@ -304,6 +333,21 @@ int tcp_connect(TCP *tcp, Address addr, int tag, ByteQueue **output)
|
|||||||
if (fd == INVALID_SOCKET)
|
if (fd == INVALID_SOCKET)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
// Set socket as non-blocking
|
||||||
|
#ifdef _WIN32
|
||||||
|
u_long mode = 1;
|
||||||
|
if (sys_ioctlsocket(fd, FIONBIO, &mode) != 0) {
|
||||||
|
CLOSE_SOCKET(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int flags = sys_fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags < 0 || sys_fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
|
CLOSE_SOCKET(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (addr.is_ipv4) {
|
if (addr.is_ipv4) {
|
||||||
struct sockaddr_in buf;
|
struct sockaddr_in buf;
|
||||||
|
|||||||
Reference in New Issue
Block a user