forked from cory/tildefriends
Trying to fix socket lifetime issues.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3886 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
58f459fb3b
commit
5622db92a7
@ -175,10 +175,12 @@ function handleRequest(request, response) {
|
||||
if (promise) {
|
||||
promise.catch(function(error) {
|
||||
response.reportError(error);
|
||||
request.client.close();
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
response.reportError(error);
|
||||
request.client.close();
|
||||
}
|
||||
} else {
|
||||
response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"});
|
||||
@ -412,6 +414,7 @@ function handleConnection(client) {
|
||||
}
|
||||
} catch (error) {
|
||||
response.reportError(error);
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,8 +564,9 @@ if (tildefriends.https_port) {
|
||||
tls.keyStat = stat[1];
|
||||
}
|
||||
|
||||
let result = client.startTls(tls.context);
|
||||
handleConnection(client);
|
||||
return client.startTls(tls.context);
|
||||
return result;
|
||||
} catch (error) {
|
||||
logError("[" + new Date() + "] [" + client.peerName + "] " + error);
|
||||
}
|
||||
|
177
src/socket.js.c
177
src/socket.js.c
@ -31,6 +31,8 @@ typedef struct _socket_t {
|
||||
promiseid_t _closePromise;
|
||||
bool _connected;
|
||||
bool _noDelay;
|
||||
bool _reading;
|
||||
bool _listening;
|
||||
char _peerName[256];
|
||||
socket_direction_t _direction;
|
||||
JSValue _object;
|
||||
@ -80,6 +82,30 @@ static void _socket_processOutgoingTls(socket_t* socket);
|
||||
static void _socket_reportTlsErrors(socket_t* socket);
|
||||
static void _socket_reportError(socket_t* socket, const char* error);
|
||||
|
||||
static void _socket_set_handler(socket_t* socket, JSValue* handler, JSValue new_value)
|
||||
{
|
||||
JSContext* context = tf_task_get_context(socket->_task);
|
||||
bool had_handler = !JS_IsUndefined(*handler);
|
||||
if (!had_handler && !JS_IsUndefined(new_value))
|
||||
{
|
||||
JS_DupValue(context, socket->_object);
|
||||
}
|
||||
if (had_handler)
|
||||
{
|
||||
JSValue value = *handler;
|
||||
*handler = JS_UNDEFINED;
|
||||
JS_FreeValue(context, value);
|
||||
}
|
||||
if (!JS_IsUndefined(new_value))
|
||||
{
|
||||
*handler = JS_DupValue(context, new_value);
|
||||
}
|
||||
if (had_handler && JS_IsUndefined(new_value))
|
||||
{
|
||||
JS_FreeValue(context, socket->_object);
|
||||
}
|
||||
}
|
||||
|
||||
static void _socket_gc_mark(JSRuntime* runtime, JSValueConst value, JS_MarkFunc mark_func)
|
||||
{
|
||||
socket_t* socket = JS_GetOpaque(value, _classId);
|
||||
@ -127,9 +153,6 @@ socket_t* _socket_create_internal(JSContext* context)
|
||||
socket_t* socket = malloc(sizeof(socket_t));
|
||||
memset(socket, 0, sizeof(*socket));
|
||||
|
||||
socket->_onRead = JS_UNDEFINED;
|
||||
socket->_onError = JS_UNDEFINED;
|
||||
socket->_onConnect = JS_UNDEFINED;
|
||||
socket->_closePromise = -1;
|
||||
socket->_startTlsPromise = -1;
|
||||
|
||||
@ -139,6 +162,10 @@ socket_t* _socket_create_internal(JSContext* context)
|
||||
socket->_object = object;
|
||||
JS_SetOpaque(object, socket);
|
||||
|
||||
socket->_onRead = JS_UNDEFINED;
|
||||
socket->_onError = JS_UNDEFINED;
|
||||
socket->_onConnect = JS_UNDEFINED;
|
||||
|
||||
JS_SetPropertyStr(context, object, "bind", JS_NewCFunction(context, _socket_bind, "bind", 2));
|
||||
JS_SetPropertyStr(context, object, "connect", JS_NewCFunction(context, _socket_connect, "connect", 2));
|
||||
JS_SetPropertyStr(context, object, "listen", JS_NewCFunction(context, _socket_listen, "listen", 2));
|
||||
@ -183,30 +210,16 @@ JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSVa
|
||||
|
||||
void _socket_close_internal(socket_t* socket)
|
||||
{
|
||||
if (!JS_IsUndefined(socket->_onRead))
|
||||
{
|
||||
JSValue value = socket->_onRead;
|
||||
socket->_onRead = JS_UNDEFINED;
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), value);
|
||||
}
|
||||
if (!JS_IsUndefined(socket->_onError))
|
||||
{
|
||||
JSValue value = socket->_onError;
|
||||
socket->_onError = JS_UNDEFINED;
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), value);
|
||||
}
|
||||
if (!JS_IsUndefined(socket->_onConnect))
|
||||
{
|
||||
JSValue value = socket->_onConnect;
|
||||
socket->_onConnect = JS_UNDEFINED;
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), value);
|
||||
}
|
||||
_socket_set_handler(socket, &socket->_onRead, JS_UNDEFINED);
|
||||
_socket_set_handler(socket, &socket->_onError, JS_UNDEFINED);
|
||||
_socket_set_handler(socket, &socket->_onConnect, JS_UNDEFINED);
|
||||
if (socket->_tls)
|
||||
{
|
||||
tf_tls_session_destroy(socket->_tls);
|
||||
socket->_tls = NULL;
|
||||
}
|
||||
if (!uv_is_closing((uv_handle_t*)&socket->_socket))
|
||||
if (socket->_socket.data &&
|
||||
!uv_is_closing((uv_handle_t*)&socket->_socket))
|
||||
{
|
||||
uv_close((uv_handle_t*)&socket->_socket, _socket_onClose);
|
||||
}
|
||||
@ -222,28 +235,32 @@ void _socket_close_internal(socket_t* socket)
|
||||
void _socket_finalizer(JSRuntime *runtime, JSValue value)
|
||||
{
|
||||
socket_t* socket = JS_GetOpaque(value, _classId);
|
||||
if (socket->_listening)
|
||||
{
|
||||
printf("FINALIZING A LISTENING SOCKET!\n");
|
||||
abort();
|
||||
}
|
||||
socket->_object = JS_UNDEFINED;
|
||||
_socket_close_internal(socket);
|
||||
}
|
||||
|
||||
void _socket_reportError(socket_t* socket, const char* error)
|
||||
{
|
||||
if (JS_IsFunction(tf_task_get_context(socket->_task),socket-> _onError))
|
||||
JSContext* context = tf_task_get_context(socket->_task);
|
||||
JSValue ref = JS_DupValue(context, socket->_object);
|
||||
if (JS_IsFunction(context, socket-> _onError))
|
||||
{
|
||||
JSValue exception = JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error);
|
||||
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onError, socket->_object, 1, &exception);
|
||||
if (JS_IsException(result))
|
||||
{
|
||||
printf("Socket error.\n");
|
||||
js_std_dump_error(tf_task_get_context(socket->_task));
|
||||
}
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), exception);
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), result);
|
||||
JSValue exception = JS_ThrowInternalError(context, "%s", error);
|
||||
JSValue result = JS_Call(context, socket->_onError, socket->_object, 1, &exception);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, exception);
|
||||
JS_FreeValue(context, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Socket::reportError: %s\n", error);
|
||||
}
|
||||
JS_FreeValue(context, ref);
|
||||
}
|
||||
|
||||
void _socket_reportTlsErrors(socket_t* socket)
|
||||
@ -501,11 +518,12 @@ void _socket_onConnect(uv_connect_t* request, int status)
|
||||
JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
||||
socket->_listening = true;
|
||||
int backlog = 1;
|
||||
JS_ToInt32(context, &backlog, argv[0]);
|
||||
if (JS_IsUndefined(socket->_onConnect))
|
||||
{
|
||||
socket->_onConnect = JS_DupValue(context, argv[1]);
|
||||
_socket_set_handler(socket, &socket->_onConnect, argv[1]);
|
||||
int result = uv_listen((uv_stream_t*)&socket->_socket, backlog, _socket_onNewConnection);
|
||||
if (result != 0)
|
||||
{
|
||||
@ -524,15 +542,15 @@ JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSVa
|
||||
void _socket_onNewConnection(uv_stream_t* server, int status)
|
||||
{
|
||||
socket_t* socket = server->data;
|
||||
JSContext* context = tf_task_get_context(socket->_task);
|
||||
JSValue ref = JS_DupValue(context, socket->_object);
|
||||
if (!JS_IsUndefined(socket->_onConnect))
|
||||
{
|
||||
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onConnect, socket->_object, 0, NULL);
|
||||
if (JS_IsException(result))
|
||||
{
|
||||
printf("Socket error on connection.\n");
|
||||
js_std_dump_error(tf_task_get_context(socket->_task));
|
||||
}
|
||||
JSValue result = JS_Call(context, socket->_onConnect, socket->_object, 0, NULL);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, result);
|
||||
}
|
||||
JS_FreeValue(context, ref);
|
||||
}
|
||||
|
||||
JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
@ -629,32 +647,38 @@ void _socket_onTlsShutdown(uv_write_t* request, int status)
|
||||
JSValue _socket_onError(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
||||
if (!JS_IsUndefined(socket->_onError))
|
||||
{
|
||||
JS_FreeValue(context, socket->_onError);
|
||||
socket->_onError = JS_UNDEFINED;
|
||||
}
|
||||
socket->_onError = JS_DupValue(context, argv[0]);
|
||||
_socket_set_handler(socket, &socket->_onError, argv[0]);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
JSValue _socket_read(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
||||
socket->_onRead = JS_DupValue(context, argv[0]);
|
||||
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
|
||||
JSValue ref = JS_DupValue(context, socket->_object);
|
||||
_socket_set_handler(socket, &socket->_onRead, argv[0]);
|
||||
|
||||
promiseid_t promise = -1;
|
||||
JSValue read_result = tf_task_allocate_promise(socket->_task, &promise);
|
||||
if (result != 0)
|
||||
if (!socket->_reading)
|
||||
{
|
||||
char error[256];
|
||||
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result));
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
|
||||
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
|
||||
if (result != 0)
|
||||
{
|
||||
char error[256];
|
||||
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result));
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
|
||||
}
|
||||
else
|
||||
{
|
||||
socket->_reading = true;
|
||||
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
|
||||
}
|
||||
JS_FreeValue(context, ref);
|
||||
return read_result;
|
||||
}
|
||||
|
||||
@ -666,19 +690,17 @@ void _socket_allocateBuffer(uv_handle_t* handle, size_t suggestedSize, uv_buf_t*
|
||||
void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffer)
|
||||
{
|
||||
socket_t* socket = stream->data;
|
||||
JSContext* context = tf_task_get_context(socket->_task);
|
||||
JSValue ref = JS_DupValue(context, socket->_object);
|
||||
if (readSize <= 0)
|
||||
{
|
||||
socket->_connected = false;
|
||||
if (!JS_IsUndefined(socket->_onRead))
|
||||
{
|
||||
JSValue args[] = { JS_UNDEFINED };
|
||||
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
|
||||
if (JS_IsException(result))
|
||||
{
|
||||
printf("Socket error on read.\n");
|
||||
js_std_dump_error(tf_task_get_context(socket->_task));
|
||||
}
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), result);
|
||||
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, result);
|
||||
}
|
||||
_socket_close_internal(socket);
|
||||
}
|
||||
@ -704,7 +726,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
||||
char buffer[8192];
|
||||
if (tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer)))
|
||||
{
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), buffer));
|
||||
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -713,7 +735,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
while (socket->_tls)
|
||||
{
|
||||
char plain[8192];
|
||||
int result = tf_tls_session_read_plain(socket->_tls, plain, sizeof(plain));
|
||||
@ -732,13 +754,9 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
||||
if (!JS_IsUndefined(socket->_onRead))
|
||||
{
|
||||
JSValue args[] = { JS_UNDEFINED };
|
||||
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
|
||||
if (JS_IsException(result))
|
||||
{
|
||||
printf("Socket error on read plain.\n");
|
||||
js_std_dump_error(tf_task_get_context(socket->_task));
|
||||
}
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), result);
|
||||
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -747,6 +765,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket->_tls)
|
||||
{
|
||||
_socket_processOutgoingTls(socket);
|
||||
@ -758,6 +777,7 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
||||
}
|
||||
}
|
||||
free(buffer->base);
|
||||
JS_FreeValue(context, ref);
|
||||
}
|
||||
|
||||
static JSValue _newUint8Array(JSContext* context, const void* data, size_t length)
|
||||
@ -774,21 +794,20 @@ static JSValue _newUint8Array(JSContext* context, const void* data, size_t lengt
|
||||
|
||||
void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length)
|
||||
{
|
||||
if (!JS_IsUndefined(socket->_onRead))
|
||||
if (data && length > 0)
|
||||
{
|
||||
if (data && length > 0)
|
||||
JSContext* context = tf_task_get_context(socket->_task);
|
||||
JSValue ref = JS_DupValue(context, socket->_object);
|
||||
JSValue typedArray = _newUint8Array(context, data, length);
|
||||
JSValue args[] = { typedArray };
|
||||
if (!JS_IsUndefined(socket->_onRead))
|
||||
{
|
||||
JSValue typedArray = _newUint8Array(tf_task_get_context(socket->_task), data, length);
|
||||
JSValue args[] = { typedArray };
|
||||
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
|
||||
if (JS_IsException(result))
|
||||
{
|
||||
printf("Socket error on data read.\n");
|
||||
js_std_dump_error(tf_task_get_context(socket->_task));
|
||||
}
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), typedArray);
|
||||
JS_FreeValue(tf_task_get_context(socket->_task), result);
|
||||
JSValue result = JS_Call(context, socket->_onRead, socket->_object, 1, args);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, result);
|
||||
}
|
||||
JS_FreeValue(context, typedArray);
|
||||
JS_FreeValue(context, ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -732,6 +732,8 @@ static JSValue _tf_task_getStats(JSContext* context, JSValueConst this_val, int
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(context, result, "sqlite3_memory_percent", JS_NewFloat64(context, 100.0f * sqlite3_memory_used() / total_memory));
|
||||
JS_SetPropertyStr(context, result, "socket_count", JS_NewInt32(context, tf_socket_get_count()));
|
||||
JS_SetPropertyStr(context, result, "socket_open_count", JS_NewInt32(context, tf_socket_get_open_count()));
|
||||
|
||||
if (task->_ssb)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user