1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-06 00:13:33 +00:00
Files
MeshAgent/microscript/ILibDuktape_net.c

2973 lines
119 KiB
C

/*
Copyright 2006 - 2022 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "duktape.h"
#include "ILibDuktape_net.h"
#include "ILibDuktape_Helpers.h"
#include "ILibDuktape_DuplexStream.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_EventEmitter.h"
#include "ILibDuktape_ChildProcess.h"
#include "microstack/ILibAsyncSocket.h"
#include "microstack/ILibCrypto.h"
#include "microstack/ILibAsyncServerSocket.h"
#include "microstack/ILibRemoteLogging.h"
#include "microstack/ILibProcessPipe.h"
#ifdef _POSIX
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
#ifdef WIN32
#include <accctrl.h>
#include <AclAPI.h>
#endif
#ifdef OLDSSL
#define TLS_method SSLv23_method
#endif
typedef struct ILibDuktape_net_socket
{
duk_context *ctx;
ILibAsyncSocket_SocketModule socketModule;
void *object;
void *net;
void *duplexStream;
void *chain;
void *OnSetTimeout;
int unshiftBytes;
ILibDuktape_EventEmitter *emitter;
#ifndef MICROSTACK_NOTLS
SSL_CTX *ssl_ctx;
SSL *ssl;
#endif
}ILibDuktape_net_socket;
typedef struct ILibDuktape_net_server
{
duk_context *ctx;
void *self;
ILibAsyncServerSocket_ServerModule server;
ILibDuktape_EventEmitter *emitter;
int isTLS;
}ILibDuktape_net_server;
typedef struct ILibDuktape_net_server_session
{
duk_context *ctx;
void *self;
ILibAsyncServerSocket_ConnectionToken connection;
ILibDuktape_EventEmitter *emitter;
ILibDuktape_DuplexStream *stream;
int unshiftBytes;
}ILibDuktape_net_server_session;
int ILibDuktape_TLS_ctx2socket = -1;
int ILibDuktape_TLS_ctx2server = -1;
#ifdef WIN32
#define ILibDuktape_net_IPC_BUFFERSIZE 4096
typedef struct ILibDuktape_net_WindowsIPC
{
duk_context *ctx;
void *mServer, *mSocket, *mChain;
HANDLE mPipeHandle;
int endCalled;
int paused;
DWORD totalRead;
void *user1;
void* ipcreserved;
OVERLAPPED read_overlapped;
OVERLAPPED write_overlapped;
OVERLAPPED overlapped;
ILibDuktape_DuplexStream *ds;
BOOL clientConnected;
void *reservedState;
char *metadata;
ULONG_PTR _reserved[5];
char *buffer;
DWORD bufferLength;
DWORD bufferOffset;
DWORD bytesLeft;
DWORD unshiftedBytes;
}ILibDuktape_net_WindowsIPC;
#endif
#define ILibDuktape_SecureContext2CertBuffer "\xFF_SecureContext2CertBuffer"
#define ILibDuktape_SecureContext2SSLCTXPTR "\xFF_SecureContext2SSLCTXPTR"
#define ILibDuktape_GlobalTunnel_DataPtr "\xFF_GlobalTunnel_DataPtr"
#define ILibDuktape_GlobalTunnel_Stash "global-tunnel"
#define ILibDuktape_net_Server_buffer "\xFF_FixedBuffer"
#define ILibDuktape_net_server_closed "\xFF_ILibDuktape_net_server_closed"
#define ILibDuktape_net_server_closed_needEmit "\xFF_ILibDuktape_net_server_closed_needEmit"
#define ILibDuktape_net_Server_Session_buffer "\xFF_SessionFixedBuffer"
#define ILibDuktape_net_socket_ptr "\xFF_SocketPtr"
#define ILibDuktape_net_WindowsIPC_Buffer "\xFF_WindowsIPC"
#define ILibDuktape_net_ConcurrencyArray "\xFF_ConcurrencyArray"
#define ILibDuktape_net_ConcurrencyMaxSize "\xFF_ConcurrencyMaxSize"
#define ILibDuktape_net_WindowsIPC_PendingArray "\xFF_WindowsIPC_PendingArray"
#define ILibDuktape_SERVER2ContextTable "\xFF_Server2ContextTable"
#define ILibDuktape_SERVER2OPTIONS "\xFF_ServerToOptions"
#define ILibDuktape_SERVER2LISTENOPTIONS "\xFF_ServerToListenOptions"
#define ILibDuktape_TLSSocket2SecureContext "\xFF_TLSSocket2SecureContext"
#define ILibDuktape_IPAddress_SockAddr "\xFF_IPAddress_SockAddr"
#define ILibDuktape_net_server_metadata "\xFF_net_server_metadata"
#define ILibDuktape_net_server_IPCPath "\xFF_net_server_IPCPath"
extern void ILibAsyncServerSocket_RemoveFromChain(ILibAsyncServerSocket_ServerModule serverModule);
// Prototypes
void ILibDuktape_net_socket_PUSH(duk_context *ctx, ILibAsyncSocket_SocketModule module);
#ifndef MICROSTACK_NOTLS
duk_ret_t ILibDuktape_tls_server_addContext(duk_context *ctx);
#endif
#ifdef WIN32
ILibTransport_DoneState ILibDuktape_net_server_IPC_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user);
void ILibDuktape_net_server_IPC_EndSink(ILibDuktape_DuplexStream *stream, void *user);
void ILibDuktape_net_server_IPC_PauseSink(ILibDuktape_DuplexStream *sender, void *user);
void ILibDuktape_net_server_IPC_ResumeSink(ILibDuktape_DuplexStream *sender, void *user);
int ILibDuktape_net_server_IPC_unshiftSink(ILibDuktape_DuplexStream *sender, int unshiftBytes, void *user);
duk_ret_t ILibDuktape_net_server_IPC_ConnectSink_Finalizer(duk_context *ctx);
BOOL ILibDuktape_server_ipc_ReadSink(void *chain, HANDLE h, ILibWaitHandle_ErrorStatus status, char *buffer, DWORD bytesRead, void* user);
#endif
void ILibDuktape_net_socket_OnData(ILibAsyncSocket_SocketModule socketModule, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncSocket_OnInterrupt* OnInterrupt, void **user, int *PAUSE)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
if (ILibDuktape_DuplexStream_WriteData((ILibDuktape_DuplexStream*)ptrs->duplexStream, buffer + *p_beginPointer, endPointer - *p_beginPointer) != 0)
{
*PAUSE = 1;
}
*p_beginPointer = endPointer - ptrs->unshiftBytes;
ptrs->unshiftBytes = 0;
}
void ILibDuktape_net_socket_OnConnect(ILibAsyncSocket_SocketModule socketModule, int Connected, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
struct sockaddr_in6 local;
if (ptrs->ctx == NULL) { return; }
duk_push_heapptr(ptrs->ctx, ptrs->object); // [sockat]
duk_push_false(ptrs->ctx); // [socket][connecting]
duk_put_prop_string(ptrs->ctx, -2, "connecting"); // [socket]
duk_pop(ptrs->ctx); // ...
if (Connected != 0)
{
duk_push_heapptr(ptrs->ctx, ptrs->object); // [sock]
if (ILibAsyncSocket_IsDomainSocket(socketModule) == 0)
{
ILibAsyncSocket_GetLocalInterface(socketModule, (struct sockaddr*)&local);
duk_push_string(ptrs->ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad))); // [sock][localAddr]
duk_put_prop_string(ptrs->ctx, -2, "localAddress"); // [sock]
duk_push_int(ptrs->ctx, (int)ntohs(local.sin6_port)); // [sock][port]
duk_put_prop_string(ptrs->ctx, -2, "localPort"); // [sock]
ILibAsyncSocket_GetRemoteInterface(socketModule, (struct sockaddr*)&local);
duk_push_string(ptrs->ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad))); // [sock][remoteAddr]
duk_put_prop_string(ptrs->ctx, -2, "remoteAddress"); // [sock]
duk_push_string(ptrs->ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4"); // [sock][remoteFamily]
duk_put_prop_string(ptrs->ctx, -2, "remoteFamily"); // [sock]
duk_push_int(ptrs->ctx, (int)ntohs(local.sin6_port)); // [sock][remotePort]
duk_put_prop_string(ptrs->ctx, -2, "remotePort"); // [sock]
}
else
{
duk_get_prop_string(ptrs->ctx, -1, "remoteHost"); // [sock][remoteHost]
duk_put_prop_string(ptrs->ctx, -2, "path"); // [sock]
}
duk_pop(ptrs->ctx); // ...
#ifndef MICROSTACK_NOTLS
if (ptrs->ssl != NULL)
{
const unsigned char *alpn = NULL;
size_t alpnLen = 0;
SSL_SESSION_get0_alpn_selected(SSL_get_session(ptrs->ssl), &alpn, &alpnLen);
duk_push_heapptr(ptrs->ctx, ptrs->object); // [socket]
if (alpnLen != 0)
{
duk_push_lstring(ptrs->ctx, (char*)alpn, alpnLen);
}
else
{
duk_push_null(ptrs->ctx);
}
duk_put_prop_string(ptrs->ctx, -2, "alpnProtocol");
duk_push_string(ptrs->ctx, SSL_get_servername(ptrs->ssl, TLSEXT_NAMETYPE_host_name));
duk_put_prop_string(ptrs->ctx, -2, "servername");
duk_get_prop_string(ptrs->ctx, -1, "emit"); // [socket][emit]
duk_swap_top(ptrs->ctx, -2); // [emit][this]
duk_push_string(ptrs->ctx, "secureConnect"); // [emit][this][secureConnect]
if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "tls.socket.OnSecureConnect(): "); }
duk_pop(ptrs->ctx); // ...
return;
}
#endif
duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
duk_swap_top(ptrs->ctx, -2); // [emit][this]
duk_push_string(ptrs->ctx, "connect"); // [emit][this][connect]
if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
duk_pop(ptrs->ctx); // ...
}
else
{
duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
duk_swap_top(ptrs->ctx, -2); // [emit][this]
duk_push_string(ptrs->ctx, "error"); // [emit][this][error]
duk_push_object(ptrs->ctx); // [emit][this][error][errorObj]
#ifndef MICROSTACK_NOTLS
if (ptrs->ssl != NULL && ILibAsyncSocket_TLS_WasHandshakeError(socketModule))
{
duk_push_string(ptrs->ctx, "TLS Handshake Error"); // [emit][this][error][errorObj][msg]
}
else
{
duk_push_string(ptrs->ctx, "Connection Failed"); // [emit][this][error][errorObj][msg]
}
#else
duk_push_string(ptrs->ctx, "Connection Failed"); // [emit][this][error][errorObj][msg]
#endif
duk_put_prop_string(ptrs->ctx, -2, "message"); // [emit][this][error][errorObj]
if (duk_pcall_method(ptrs->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
if (ptrs->ctx != NULL) { duk_pop(ptrs->ctx); } // ...
}
}
void ILibDuktape_net_socket_OnDisconnect(ILibAsyncSocket_SocketModule socketModule, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
if (ILibMemory_CanaryOK(ptrs->emitter))
{
duk_push_heapptr(ptrs->ctx, ptrs->object); // [sock]
duk_push_string(ptrs->ctx, "0.0.0.0"); // [sock][localAddr]
duk_put_prop_string(ptrs->ctx, -2, "localAddress"); // [sock]
duk_push_undefined(ptrs->ctx); // [sock][remoteAddr]
duk_put_prop_string(ptrs->ctx, -2, "remoteAddress");// [sock]
duk_pop(ptrs->ctx); // ...
ILibDuktape_DuplexStream_Closed((ILibDuktape_DuplexStream*)ptrs->duplexStream);
}
}
void ILibDuktape_net_socket_OnSendOK(ILibAsyncSocket_SocketModule socketModule, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
ILibDuktape_DuplexStream_Ready((ILibDuktape_DuplexStream*)ptrs->duplexStream);
}
ILibTransport_DoneState ILibDuktape_net_socket_WriteHandler(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)user;
#ifdef _DEBUG_NET_FRAGMENT_SEND
int x = bufferLen / 2;
printf("** Send 1/2: %d of %d bytes\n", x, bufferLen);
ILibAsyncSocket_Send(ptrs->socketModule, buffer, x, ILibAsyncSocket_MemoryOwnership_USER);
printf("** Send 2/2: %d of %d bytes\n", bufferLen - x, bufferLen);
return((ILibTransport_DoneState)ILibAsyncSocket_Send(ptrs->socketModule, buffer + x, bufferLen - x, ILibAsyncSocket_MemoryOwnership_USER));
#else
return((ILibTransport_DoneState)ILibAsyncSocket_Send(ptrs->socketModule, buffer, bufferLen, ILibAsyncSocket_MemoryOwnership_USER));
#endif
}
void ILibDuktape_net_socket_EndHandler(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)user;
ILibAsyncSocket_Disconnect(ptrs->socketModule);
}
void ILibDuktape_net_socket_PauseHandler(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)user;
ILibAsyncSocket_Pause(ptrs->socketModule);
}
void ILibDuktape_net_socket_ResumeHandler(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)user;
ILibAsyncSocket_Resume(ptrs->socketModule);
}
duk_ret_t ILibDuktape_net_socket_connect_errorDispatch(duk_context *ctx)
{
duk_dup(ctx, 0); // [socket]
duk_get_prop_string(ctx, -1, "emit"); // [socket][emit]
duk_swap_top(ctx, -2); // [emit][this]
duk_push_string(ctx, "error"); // [emit][this][error]
duk_dup(ctx, 1); // [emit][this][error][err]
duk_call_method(ctx, 2);
duk_pop(ctx); // ...
return(0);
}
#ifdef WIN32
void ILibDuktape_net_socket_ipc_error(duk_context *ctx, void ** args, int argsLen)
{
ILibDuktape_net_WindowsIPC *winIPC = ((ILibDuktape_net_WindowsIPC**)args)[0];
ILibDuktape_EventEmitter_SetupEmit(winIPC->ctx, winIPC->mSocket, "error"); // [emit][this][error]
duk_push_string(winIPC->ctx, "Error Connecting Named Pipe"); // [emit][this][error][err]
duk_pcall_method(winIPC->ctx, 2); duk_pop(winIPC->ctx); // ...
}
void ILibDuktape_net_Socket_ipc_dataHookCallbackCont(duk_context *ctx, void ** args, int argsLen)
{
ILibDuktape_EventEmitter *emitter = (ILibDuktape_EventEmitter*)args[0];
duk_push_heapptr(emitter->ctx, emitter->object); // [stream]
duk_get_prop_string(emitter->ctx, -1, "resume"); // [stream][resume]
duk_dup(emitter->ctx, -2); // [stream][resume][this]
duk_pcall_method(emitter->ctx, 0);
duk_pop(emitter->ctx); // ...
}
void ILibDuktape_net_socket_ipc_dataHookCallback(ILibDuktape_EventEmitter *sender, char *eventName, void *hookedCallback)
{
if (ILibDuktape_EventEmitter_HasListeners(sender, "data") == 0 && ILibDuktape_EventEmitter_HasListeners(sender, "end") == 0)
{
int top = duk_get_top(sender->ctx);
duk_push_heapptr(sender->ctx, sender->object); // [stream]
duk_get_prop_string(sender->ctx, -1, "isPaused"); // [stream][isPaused]
duk_dup(sender->ctx, -2); // [stream][isPaused][this]
if (duk_pcall_method(sender->ctx, 0) == 0)
{
if (duk_get_boolean(sender->ctx, -1)) // [stream][bool]
{
ILibDuktape_Immediate(sender->ctx, (void**)&sender, 1, ILibDuktape_net_Socket_ipc_dataHookCallbackCont);
}
}
duk_set_top(sender->ctx, top);
}
}
duk_ret_t ILibDuktape_net_ipcSocket_connectHook(duk_context *ctx)
{
char *eventName = (char*)duk_require_string(ctx, 0);
if (strcmp(eventName, "connect") == 0)
{
// Remove ourselves
duk_push_this(ctx); // [socket]
duk_get_prop_string(ctx, -1, "removeListener"); // [socket][removeListener]
duk_swap_top(ctx, -2); // [removeListener][this]
duk_push_string(ctx, "newListener"); // [removeListener][this][newListener]
duk_push_current_function(ctx); // [removeListener][this][newListener][func]
duk_pcall_method(ctx, 2); duk_pop(ctx); // ...
duk_dup(ctx, 1); // [listener]
duk_push_this(ctx); // [listenter][this]
duk_call_method(ctx, 0);
}
return(0);
}
#endif
duk_ret_t ILibDuktape_net_socket_connect(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
int port = 0;
char *host = "127.0.0.1";
char *path = NULL;
duk_size_t pathLen = 0;
ILibDuktape_net_socket *ptrs;
struct sockaddr_in6 dest;
struct sockaddr_in6 proxy;
memset(&proxy, 0, sizeof(struct sockaddr_in6));
int onConnectSpecified = 0;
if (nargs == 0) { return(ILibDuktape_Error(ctx, "Too few arguments")); }
duk_push_this(ctx); // [socket]
duk_get_prop_string(ctx, -1, ILibDuktape_net_socket_ptr); // [socket][ptrs]
ptrs = (ILibDuktape_net_socket*)duk_to_pointer(ctx, -1);
duk_pop(ctx); // [socket]
if (duk_is_object(ctx, 0))
{
/* This is an OPTIONS object
port: Port the client should connect to(Required).
host : Host the client should connect to.Defaults to 'localhost'.
localAddress : Local interface to bind to for network connections.
localPort : Local port to bind to for network connections.
family : Version of IP stack.Defaults to 4.
hints : dns.lookup() hints.Defaults to 0.
lookup : Custom lookup function.Defaults to dns.lookup.
*/
host = Duktape_GetStringPropertyValue(ctx, 0, "host", "127.0.0.1");
port = Duktape_GetIntPropertyValue(ctx, 0, "port", 0);
path = Duktape_GetStringPropertyValueEx(ctx, 0, "path", NULL, &pathLen);
if (duk_has_prop_string(ctx, 0, "proxy"))
{
duk_get_prop_string(ctx, 0, "proxy");
ILibResolveEx(Duktape_GetStringPropertyValue(ctx, -1, "host", NULL), (unsigned short)Duktape_GetIntPropertyValue(ctx, -1, "port", 0), &proxy);
duk_pop(ctx);
}
if (nargs >= 2 && duk_is_function(ctx, 1))
{
onConnectSpecified = 1;
ILibDuktape_EventEmitter_AddOn(ptrs->emitter, "connect", duk_require_heapptr(ctx, 1));
}
}
if (duk_is_string(ctx, 0) || (pathLen > 0 && port == 0))
{
// This is a PATH string (Domain Socket on Linux/MacOS, Named Pipe on Windows)
if (onConnectSpecified == 0 && duk_is_function(ctx, 1))
{
onConnectSpecified = 1;
ILibDuktape_EventEmitter_AddOn(ptrs->emitter, "connect", duk_require_heapptr(ctx, 1));
}
#ifdef WIN32
duk_push_this(ctx);
duk_push_array(ctx); duk_put_prop_string(ctx, -2, ILibDuktape_net_WindowsIPC_PendingArray);
ILibDuktape_WriteID(ctx, "net.ipcSocket");
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_net_WindowsIPC));
duk_put_prop_string(ctx, -2, ILibDuktape_net_WindowsIPC_Buffer);
winIPC->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->ctx = ctx;
winIPC->mSocket = duk_get_heapptr(ctx, -1);
winIPC->mChain = duk_ctx_chain(ctx);
winIPC->paused = 1;
winIPC->metadata = "net.ipcSocket";
winIPC->bufferLength = ILibDuktape_net_IPC_BUFFERSIZE;
ILibMemory_ReallocateRaw(&(winIPC->buffer), ILibDuktape_net_IPC_BUFFERSIZE);
if ((winIPC->mPipeHandle = CreateFileA(path, GENERIC_READ | FILE_WRITE_DATA, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)) == INVALID_HANDLE_VALUE)
{
// We'll emit the 'error' event on the next event loop, becuase if 'createConnection' was called, there is no way the event listener is set yet
ILibDuktape_Immediate(ctx, (void**)&winIPC, 1, ILibDuktape_net_socket_ipc_error);
}
else
{
// SUCCESS
winIPC->ds = ILibDuktape_DuplexStream_InitEx(winIPC->ctx, ILibDuktape_net_server_IPC_WriteSink, ILibDuktape_net_server_IPC_EndSink, ILibDuktape_net_server_IPC_PauseSink, ILibDuktape_net_server_IPC_ResumeSink, ILibDuktape_net_server_IPC_unshiftSink, winIPC);
winIPC->ds->readableStream->paused = 1;
ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter_GetEmitter(winIPC->ctx, -1), "data", ILibDuktape_net_socket_ipc_dataHookCallback);
ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter_GetEmitter(winIPC->ctx, -1), "end", ILibDuktape_net_socket_ipc_dataHookCallback);
winIPC->reservedState = ILibChain_ReadAndSaveStateEx(winIPC->mChain, winIPC->mPipeHandle, &(winIPC->read_overlapped), winIPC->buffer, winIPC->bufferLength, ILibDuktape_server_ipc_ReadSink, winIPC, winIPC->metadata);
if (onConnectSpecified == 0)
{
// No connectListener was specified, so we need to hook it, becuase otherwise the caller has no way to receive this event
ILibDuktape_EventEmitter_SetupOn(winIPC->ctx, winIPC->mSocket, "newListener"); // [on][this][newListener]
ILibDuktape_EventEmitter_PrependOnce(winIPC->ctx, -2, "~", ILibDuktape_net_server_IPC_ConnectSink_Finalizer);
duk_push_c_function(winIPC->ctx, ILibDuktape_net_ipcSocket_connectHook, 2); // [on][this][newListener][func]
if (duk_pcall_method(winIPC->ctx, 2) != 0)
{
ILibDuktape_Process_UncaughtExceptionEx(winIPC->ctx, "Error in net.socket.connect.onConnect(): ");
}
}
else
{
ILibDuktape_EventEmitter_SetupEmit(winIPC->ctx, winIPC->mSocket, "connect"); //[emit][this][connect]
ILibDuktape_EventEmitter_PrependOnce(winIPC->ctx, -2, "~", ILibDuktape_net_server_IPC_ConnectSink_Finalizer);
if (duk_pcall_method(winIPC->ctx, 1) != 0)
{
ILibDuktape_Process_UncaughtExceptionEx(winIPC->ctx, "Error in net.socket.connect.onConnect(): ");
}
}
duk_pop(winIPC->ctx); // ...
}
return(1);
#else
if (pathLen > 0)
{
host = path;
}
else
{
host = (char*)duk_require_string(ctx, 0);
}
duk_push_heapptr(ptrs->ctx, ptrs->object); // [socket]
duk_push_string(ctx, host); // [socket][host]
ILibDuktape_CreateReadonlyProperty(ctx, "remoteHost"); // [socket]
duk_pop(ctx); // ...
struct sockaddr_un serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sun_family = AF_UNIX;
strcpy(serveraddr.sun_path, host);
ILibAsyncSocket_ConnectTo(ptrs->socketModule, NULL, (struct sockaddr*)&serveraddr, NULL, ptrs);
duk_push_heapptr(ptrs->ctx, ptrs->object); // [sockat]
duk_push_true(ptrs->ctx); // [socket][connecting]
duk_put_prop_string(ptrs->ctx, -2, "connecting"); // [socket]
duk_pop(ptrs->ctx); // ...
if (duk_is_object(ptrs->ctx, 0))
{
if (duk_has_prop_string(ptrs->ctx, 0, "metadata"))
{
duk_size_t len;
char *tmp = (char*)duk_push_sprintf(ptrs->ctx, "net.ipcSocket, %s", (char*)Duktape_GetStringPropertyValueEx(ptrs->ctx, 0, "metadata", "", &len));
char *tmp2 = (char*)ILibMemory_SmartAllocate(len + 16);
memcpy_s(tmp2, ILibMemory_Size(tmp2), tmp, ILibMemory_Size(tmp2) - 1);
ILibChain_Link_SetMetadata(ptrs->socketModule, tmp2);
}
else
{
ILibChain_Link_SetMetadata(ptrs->socketModule, "net.ipcSocket");
}
}
return(0);
#endif
}
if (duk_is_number(ctx, 0))
{
// This is a PORT number
port = duk_require_int(ctx, 0);
host = nargs > 1 ? (char*)duk_require_string(ctx, 1) : "127.0.0.1";
if (nargs > 2 && duk_is_function(ctx, 2))
{
ILibDuktape_EventEmitter_AddOn(ptrs->emitter, "connect", duk_require_heapptr(ctx, 2));
}
}
duk_push_heapptr(ptrs->ctx, ptrs->object); // [socket]
duk_push_string(ctx, host); // [socket][host]
ILibDuktape_CreateReadonlyProperty(ctx, "remoteHost"); // [socket]
duk_pop(ctx); // ...
if (duk_is_object(ctx, 0) && duk_has_prop_string(ctx, 0, "proxy"))
{
duk_get_prop_string(ctx, 0, "proxy");
ILibResolveEx(Duktape_GetStringPropertyValue(ctx, -1, "host", NULL), (unsigned short)Duktape_GetIntPropertyValue(ctx, -1, "port", 0), &proxy);
duk_pop(ctx);
// If we are going to use a proxy, we need to have the proxy resolve the remote host
duk_push_sprintf(ctx, "%s:%d", host, port); // [socket][string]
duk_swap_top(ctx, -2); // [string][socket]
ILibAsyncSocket_ConnectToProxyEx(ptrs->socketModule, NULL, (char*)duk_get_string(ctx, -2), (struct sockaddr*)&proxy, Duktape_GetStringPropertyValue(ctx, -1, "username", NULL), Duktape_GetStringPropertyValue(ctx, -1, "password", NULL), NULL, ptrs);
return(0);
}
ILibResolveEx(host, (unsigned short)port, &dest);
if (dest.sin6_family == AF_UNSPEC || (duk_is_object(ctx, 0) && duk_has_prop_string(ctx, 0, "proxy") && proxy.sin6_family == AF_UNSPEC))
{
// Can't resolve, check to see if it's cached
duk_push_heap_stash(ctx); // [stash]
if (duk_has_prop_string(ctx, -1, "_sharedDB"))
{
ILibSimpleDataStore db = (ILibSimpleDataStore)Duktape_GetPointerProperty(ctx, -1, "_sharedDB");
char *dnsCache = (char*)duk_push_sprintf(ctx, "DNS[%s]", host); // [stash][dnsCache]
char dnsCacheBuffer[255];
if (ILibSimpleDataStore_Get(db, dnsCache, dnsCacheBuffer, sizeof(dnsCacheBuffer)) > 0)
{
ILibResolveEx(dnsCacheBuffer, (unsigned short)port, &dest);
}
duk_pop(ctx); // [stash]
}
duk_pop(ctx); // ...
}
if (dest.sin6_family == AF_UNSPEC || (duk_is_object(ctx, 0) && duk_has_prop_string(ctx, 0, "proxy") && proxy.sin6_family == AF_UNSPEC))
{
// Can't resolve... Delay event emit, until next event loop, because if app called net.createConnection(), they don't have the socket yet
duk_push_heapptr(ctx, ptrs->object); // [socket]
duk_push_global_object(ctx); // [socket][g]
duk_get_prop_string(ctx, -1, "setImmediate"); // [socket][g][immediate]
duk_swap_top(ctx, -2); // [socket][immediate][this]
duk_push_c_function(ctx, ILibDuktape_net_socket_connect_errorDispatch, DUK_VARARGS); // [socket][immediate][this][callback]
duk_dup(ctx, -4); // [socket][immediate][this][callback][socket]
duk_push_error_object(ptrs->ctx, DUK_ERR_ERROR, "Cannot Resolve Hostname: %s", host); // [socket][immediate][this][callback][socket][err]
if (duk_pcall_method(ptrs->ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptrs->ctx, "socket.connect(): "); }
duk_put_prop_string(ptrs->ctx, -2, "\xFF_Immediate"); // [socket]
duk_pop(ptrs->ctx);
}
else
{
ILibAsyncSocket_ConnectTo(ptrs->socketModule, NULL, (struct sockaddr*)&dest, NULL, ptrs);
duk_push_heapptr(ptrs->ctx, ptrs->object); // [sockat]
duk_push_true(ptrs->ctx); // [socket][connecting]
duk_put_prop_string(ptrs->ctx, -2, "connecting"); // [socket]
duk_pop(ptrs->ctx); // ...
}
return 0;
}
duk_ret_t ILibduktape_net_socket_bytesWritten(duk_context *ctx)
{
ILibDuktape_net_socket *ptrs;
duk_push_this(ctx); // [obj]
duk_get_prop_string(ctx, -1, ILibDuktape_net_socket_ptr); // [obj][ptrs]
ptrs = (ILibDuktape_net_socket*)duk_to_pointer(ctx, -1);
duk_push_int(ctx, (int)ILibAsyncSocket_GetTotalBytesSent(ptrs->socketModule));
return 1;
}
duk_ret_t ILibDuktape_net_socket_address(duk_context *ctx)
{
ILibDuktape_net_socket *ptrs;
struct sockaddr_in6 local;
duk_push_this(ctx); // [sock]
duk_get_prop_string(ctx, -1, ILibDuktape_net_socket_ptr); // [socks][ptrs]
ptrs = (ILibDuktape_net_socket*)duk_to_pointer(ctx, -1);
memset(&local, 0, sizeof(struct sockaddr_in6));
ILibAsyncSocket_GetLocalInterface(ptrs->socketModule, (struct sockaddr*)&local);
duk_push_object(ctx); // [retVal]
duk_push_int(ctx, (int)ntohs(local.sin6_port)); // [retVal][port]
duk_put_prop_string(ctx, -2, "port"); // [retVal]
duk_push_string(ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4"); // [retVal][family]
duk_put_prop_string(ctx, -2, "family"); // [retVal]
duk_push_string(ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad)));
duk_put_prop_string(ctx, -2, "address");
return 1;
}
void ILibDuktape_net_socket_timeoutSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)socketModule)->ExtraMemoryPtr;
duk_push_heapptr(ptrs->ctx, ptrs->object); // [this]
duk_get_prop_string(ptrs->ctx, -1, "emit"); // [this][emit]
duk_swap_top(ptrs->ctx, -2); // [emit][this]
duk_push_string(ptrs->ctx, "timeout"); // [emit][this][timeout]
if (duk_pcall_method(ptrs->ctx, 1) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
duk_pop(ptrs->ctx); // ...
}
duk_ret_t ILibDuktape_net_socket_setTimeout(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
ILibDuktape_net_socket *ptrs;
int timeout = duk_require_int(ctx, 0);
duk_push_this(ctx); // [sock]
duk_get_prop_string(ctx, -1, ILibDuktape_net_socket_ptr); // [socks][ptrs]
ptrs = (ILibDuktape_net_socket*)duk_to_pointer(ctx, -1);
duk_pop(ctx); // [socks]
if (nargs > 1 && duk_is_function(ctx, 1))
{
ILibDuktape_EventEmitter_AddOnce(ptrs->emitter, "timeout", duk_require_heapptr(ctx, 1));
}
if (timeout == 0)
{
// Disable
ILibDuktape_EventEmitter_RemoveAllListeners(ptrs->emitter, "timeout");
}
ILibAsyncSocket_SetTimeoutEx(ptrs->socketModule, timeout, timeout != 0 ? ILibDuktape_net_socket_timeoutSink : NULL);
return 0;
}
duk_ret_t ILibDuktape_net_socket_finalizer(duk_context *ctx)
{
void *chain = Duktape_GetChain(ctx);
ILibDuktape_net_socket* ptrs;
duk_get_prop_string(ctx, 0, ILibDuktape_net_socket_ptr);
ptrs = (ILibDuktape_net_socket*)duk_get_pointer(ctx, -1);
if (ptrs->socketModule != NULL)
{
if (ILibAsyncSocket_IsConnected(ptrs->socketModule) != 0) { ILibAsyncSocket_Disconnect(ptrs->socketModule); }
ILibChain_SafeRemove(chain, ptrs->socketModule);
}
ptrs->ctx = NULL;
return 0;
}
int ILibDuktape_net_socket_unshift(ILibDuktape_DuplexStream *sender, int unshiftBytes, void *user)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)user;
ptrs->unshiftBytes = unshiftBytes;
return(unshiftBytes);
}
void ILibDuktape_net_socket_PUSH(duk_context *ctx, ILibAsyncSocket_SocketModule module)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)module)->ExtraMemoryPtr;
if (ptrs != NULL && ptrs->object != NULL)
{
duk_push_heapptr(ctx, ptrs->object);
return;
}
duk_push_object(ctx); // [obj]
ILibDuktape_WriteID(ctx, "net.socket");
ptrs->ctx = ctx;
ptrs->chain = ((ILibChain_Link*)module)->ParentChain;
ptrs->object = duk_get_heapptr(ctx, -1);
ptrs->socketModule = module;
ILibChain_Link_SetMetadata(module, "net.socket");
duk_push_pointer(ctx, ptrs->socketModule); duk_put_prop_string(ctx, -2, ILibDuktape_ChainLinkPtr);
duk_push_pointer(ctx, ptrs); // [obj][ptrs]
duk_put_prop_string(ctx, -2, ILibDuktape_net_socket_ptr); // [obj]
duk_push_false(ctx); // [obj][connecting]
duk_put_prop_string(ctx, -2, "connecting"); // [obj]
duk_push_string(ctx, "0.0.0.0");
duk_put_prop_string(ctx, -2, "localAddress");
duk_push_int(ctx, 0);
duk_put_prop_string(ctx, -2, "localPort");
duk_push_undefined(ctx);
duk_put_prop_string(ctx, -2, "remoteAddress");
ptrs->emitter = ILibDuktape_EventEmitter_Create(ctx);
ptrs->duplexStream = ILibDuktape_DuplexStream_InitEx(ctx, ILibDuktape_net_socket_WriteHandler, ILibDuktape_net_socket_EndHandler, ILibDuktape_net_socket_PauseHandler, ILibDuktape_net_socket_ResumeHandler, ILibDuktape_net_socket_unshift, ptrs);
ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "close");
ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "connect");
ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "error");
ILibDuktape_EventEmitter_CreateEventEx(ptrs->emitter, "timeout");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "connect", ILibDuktape_net_socket_connect, DUK_VARARGS);
ILibDuktape_CreateEventWithGetter(ctx, "bytesWritten", ILibduktape_net_socket_bytesWritten);
ILibDuktape_CreateInstanceMethod(ctx, "address", ILibDuktape_net_socket_address, 0);
ILibDuktape_CreateInstanceMethod(ctx, "setTimeout", ILibDuktape_net_socket_setTimeout, DUK_VARARGS);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_net_socket_finalizer);
}
duk_ret_t ILibDuktape_net_socket_constructor(duk_context *ctx)
{
ILibDuktape_net_socket *ptrs;
ILibAsyncSocket_SocketModule sm;
void *chain;
void *net;
if (!duk_is_constructor_call(ctx)) { return(ILibDuktape_Error(ctx, "Invalid call")); }
duk_push_current_function(ctx); // [func]
duk_get_prop_string(ctx, -1, "chain"); // [func][chain]
chain = duk_to_pointer(ctx, -1);
duk_get_prop_string(ctx, -2, "net"); // [func][net]
net = duk_get_heapptr(ctx, -1);
sm = ILibCreateAsyncSocketModuleWithMemory(chain, 4096, ILibDuktape_net_socket_OnData, ILibDuktape_net_socket_OnConnect, ILibDuktape_net_socket_OnDisconnect, ILibDuktape_net_socket_OnSendOK, sizeof(ILibDuktape_net_socket));
ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)sm)->ExtraMemoryPtr;
ptrs->net = net;
ILibDuktape_net_socket_PUSH(ctx, sm);
return 1;
}
duk_ret_t ILibDuktape_net_createConnection(duk_context *ctx)
{
void *chain;
void *net;
ILibAsyncSocket_SocketModule sm;
ILibDuktape_net_socket *ptrs;
int nargs = duk_get_top(ctx), i;
duk_push_this(ctx); // [net]
duk_get_prop_string(ctx, -1, "chain"); // [net][chain]
chain = duk_to_pointer(ctx, -1);
net = duk_get_heapptr(ctx, -2);
duk_pop(ctx); // [net]
sm = ILibCreateAsyncSocketModuleWithMemory(chain, 4096, ILibDuktape_net_socket_OnData, ILibDuktape_net_socket_OnConnect, ILibDuktape_net_socket_OnDisconnect, ILibDuktape_net_socket_OnSendOK, sizeof(ILibDuktape_net_socket));
ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)sm)->ExtraMemoryPtr;
ptrs->net = net;
ILibDuktape_net_socket_PUSH(ctx, sm); // [net][socket]
duk_get_prop_string(ctx, -1, "connect"); // [net][socket][connect]
duk_dup(ctx, -2); // [net][socket][connect][this]
for (i = 0; i < nargs; ++i)
{
duk_dup(ctx, i); // [net][socket][connect][this][...args...]
}
duk_call_method(ctx, nargs); duk_pop(ctx); // [net][socket]
if (duk_is_object(ctx, 0))
{
duk_dup(ctx, 0); // [net][socket][options]
duk_put_prop_string(ctx, -2, ILibDuktape_SOCKET2OPTIONS); // [net][socket]
}
return 1;
}
ILibTransport_DoneState ILibDuktape_net_server_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return(ILibTransport_DoneState_ERROR); }
return((ILibTransport_DoneState)ILibAsyncServerSocket_Send(NULL, session->connection, buffer, bufferLen, ILibAsyncSocket_MemoryOwnership_USER));
}
void ILibDuktape_net_server_EndSink(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return; }
if (session->connection != NULL) { ILibAsyncServerSocket_Disconnect(NULL, session->connection); }
}
void ILibDuktape_net_server_PauseSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return; }
ILibAsyncSocket_Pause(session->connection);
}
void ILibDuktape_net_server_ResumeSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return; }
ILibAsyncSocket_Resume(session->connection);
}
duk_ret_t ILibDuktape_net_server_socket_Finalizer(duk_context *ctx)
{
ILibDuktape_net_server_session *session;
duk_get_prop_string(ctx, 0, ILibDuktape_net_Server_Session_buffer);
session = (ILibDuktape_net_server_session*)Duktape_GetBuffer(ctx, -1, NULL);
if (session != NULL && session->connection != NULL)
{
void *data = ILibAsyncSocket_GetUser(session->connection);
if (data != NULL) { free(data); ILibAsyncSocket_SetUser(session->connection, NULL); }
ILibAsyncServerSocket_Disconnect(NULL, session->connection);
}
return 0;
}
int ILibDuktape_net_server_unshiftSink(ILibDuktape_DuplexStream *sender, int unshiftBytes, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return(unshiftBytes); }
session->unshiftBytes = unshiftBytes;
return(unshiftBytes);
}
void ILibDuktape_net_server_OnConnect(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void **user)
{
ILibDuktape_net_server *ptr = (ILibDuktape_net_server*)((void**)ILibMemory_GetExtraMemory(AsyncServerSocketModule, ILibMemory_ASYNCSERVERSOCKET_CONTAINERSIZE))[0];
ILibDuktape_net_server_session *session;
#ifndef MICROSTACK_NOTLS
int isTLS = ILibAsyncSocket_IsUsingTls(ConnectionToken);
#else
int isTLS = 0;
#endif
if (!ILibMemory_CanaryOK(ptr)) { return; }
duk_push_heapptr(ptr->ctx, ptr->self); // [server]
if (strcmp(Duktape_GetStringPropertyValue(ptr->ctx, -1, ILibDuktape_OBJID, ""), "net.ipcServer") == 0)
{
((ILibChain_Link*)ConnectionToken)->MetaData = "net.ipcServer.ipcSocketConnection";
}
else
{
((ILibChain_Link*)ConnectionToken)->MetaData = isTLS == 0 ? "net.serverSocketConnection" : "tls.serverSocketConnection";
}
duk_get_prop_string(ptr->ctx, -1, "emit"); // [server][emit]
duk_swap_top(ptr->ctx, -2); // [emit][this]
duk_push_string(ptr->ctx, isTLS ? "secureConnection" : "connection"); // [emit][this][connection]
duk_push_object(ptr->ctx); // [emit][this][connection][socket]
ILibDuktape_WriteID(ptr->ctx, isTLS ? "tls.serverSocketConnection" : "net.serverSocketConnection");
ILibDuktape_CreateFinalizer(ptr->ctx, ILibDuktape_net_server_socket_Finalizer);
session = Duktape_PushBuffer(ptr->ctx, sizeof(ILibDuktape_net_server_session)); // [emit][this][connection][socket][buffer]
duk_put_prop_string(ptr->ctx, -2, ILibDuktape_net_Server_Session_buffer); // [emit][this][connection][socket]
if (isTLS)
{
const unsigned char *alpn = NULL;
size_t alpnLen = 0;
SSL_SESSION_get0_alpn_selected(SSL_get_session(ILibAsyncServerSocket_GetSSL(ConnectionToken)), &alpn, &alpnLen);
if (alpnLen != 0)
{
duk_push_lstring(ptr->ctx, (char*)alpn, alpnLen);
}
else
{
duk_push_null(ptr->ctx);
}
duk_put_prop_string(ptr->ctx, -2, "alpnProtocol");
duk_push_string(ptr->ctx, SSL_get_servername(ILibAsyncServerSocket_GetSSL(ConnectionToken), TLSEXT_NAMETYPE_host_name));
duk_put_prop_string(ptr->ctx, -2, "servername");
}
struct sockaddr_in6 local;
ILibAsyncSocket_GetLocalInterface(ConnectionToken, (struct sockaddr*)&local);
duk_push_string(ptr->ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad))); // [emit][this][connection][sock][localAddr]
duk_put_prop_string(ptr->ctx, -2, "localAddress"); // [emit][this][connection][sock]
duk_push_int(ptr->ctx, (int)ntohs(local.sin6_port)); // [emit][this][connection][sock][port]
duk_put_prop_string(ptr->ctx, -2, "localPort"); // [emit][this][connection][sock]
ILibAsyncSocket_GetRemoteInterface(ConnectionToken, (struct sockaddr*)&local);
duk_push_string(ptr->ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad))); // [emit][this][connection][sock][remoteAddr]
duk_put_prop_string(ptr->ctx, -2, "remoteAddress"); // [emit][this][connection][sock]
duk_push_string(ptr->ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4"); // [emit][this][connection][sock][remoteFamily]
duk_put_prop_string(ptr->ctx, -2, "remoteFamily"); // [emit][this][connection][sock]
duk_push_int(ptr->ctx, (int)ntohs(local.sin6_port)); // [emit][this][connection][sock][remotePort]
duk_put_prop_string(ptr->ctx, -2, "remotePort"); // [emit][this][connection][sock]
*user = session;
session->ctx = ptr->ctx;
session->connection = ConnectionToken;
session->self = duk_get_heapptr(ptr->ctx, -1);
session->emitter = ILibDuktape_EventEmitter_Create(ptr->ctx);
ILibDuktape_EventEmitter_CreateEventEx(session->emitter, "timeout");
session->stream = ILibDuktape_DuplexStream_InitEx(ptr->ctx, ILibDuktape_net_server_WriteSink, ILibDuktape_net_server_EndSink,
ILibDuktape_net_server_PauseSink, ILibDuktape_net_server_ResumeSink, ILibDuktape_net_server_unshiftSink, session);
if (duk_pcall_method(ptr->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptr->ctx, (isTLS ? "tls.server.OnSecureConnection(): Exception" : "net.server.OnConnect(): Exception")); }
duk_pop(ptr->ctx); // ...
}
void ILibDuktape_net_server_OnDisconnect(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return; }
if (session->connection != NULL)
{
ILibDuktape_DuplexStream_Closed(session->stream);
session->connection = NULL;
}
}
void ILibDuktape_net_server_OnReceive(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncServerSocket_OnInterrupt *OnInterrupt, void **user, int *PAUSE)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)*user;
if (!ILibMemory_CanaryOK(session)) { *p_beginPointer = endPointer; return; }
session->unshiftBytes = 0;
ILibDuktape_DuplexStream_WriteData(session->stream, buffer + *p_beginPointer, endPointer);
*p_beginPointer = endPointer - session->unshiftBytes;
}
void ILibDuktape_net_server_OnInterrupt(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
}
void ILibDuktape_net_server_OnSendOK(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
if (!ILibMemory_CanaryOK(session)) { return; }
ILibDuktape_DuplexStream_Ready(session->stream);
}
#ifdef WIN32
BOOL ILibDuktape_server_ipc_ReadSink(void *chain, HANDLE h, ILibWaitHandle_ErrorStatus status, char *buffer, DWORD bytesRead, void* user)
{
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
int consumed = 0;
if (status == ILibWaitHandle_ErrorStatus_NONE)
{
winIPC->totalRead += bytesRead;
do
{
winIPC->unshiftedBytes = 0;
if (winIPC->totalRead > 0)
{
ILibDuktape_DuplexStream_WriteData(winIPC->ds, winIPC->buffer + winIPC->bufferOffset, winIPC->totalRead);
}
if (winIPC->unshiftedBytes > winIPC->totalRead) { winIPC->unshiftedBytes = winIPC->totalRead; }
consumed = winIPC->totalRead - winIPC->unshiftedBytes;
winIPC->bufferOffset += (winIPC->totalRead - winIPC->unshiftedBytes);
winIPC->totalRead -= (winIPC->totalRead - winIPC->unshiftedBytes);
} while (winIPC->paused == 0 && consumed != 0 && winIPC->totalRead > 0);
if (winIPC->totalRead == 0) { winIPC->bufferOffset = 0; }
if (winIPC->paused == 0)
{
if (winIPC->bufferOffset > 0)
{
memmove_s(winIPC->buffer, winIPC->bufferLength, winIPC->buffer + winIPC->bufferOffset, winIPC->totalRead);
winIPC->bufferOffset = 0;
}
else if (winIPC->totalRead == winIPC->bufferLength)
{
ILibMemory_ReallocateRaw(&(winIPC->buffer), winIPC->bufferLength == 0 ? ILibDuktape_net_IPC_BUFFERSIZE : winIPC->bufferLength * 2);
winIPC->bufferLength = winIPC->bufferLength == 0 ? ILibDuktape_net_IPC_BUFFERSIZE : winIPC->bufferLength * 2;
}
ILibChain_ReadEx2(chain, h, &(winIPC->read_overlapped), winIPC->buffer + winIPC->bufferOffset + winIPC->totalRead, winIPC->bufferLength - winIPC->totalRead, ILibDuktape_server_ipc_ReadSink, winIPC, winIPC->metadata);
return(TRUE);
}
else
{
return(FALSE);
}
}
else
{
// I/O Errors
if (winIPC->mServer != NULL) { winIPC->clientConnected = 0; }
if (winIPC->reservedState != NULL) { ILibChain_WaitHandle_DestroySavedState(chain, winIPC->reservedState); winIPC->reservedState = NULL; }
winIPC->endCalled = 0;
ILibDuktape_DuplexStream_Closed(winIPC->ds);
if (ILibMemory_CanaryOK(winIPC) && winIPC->endCalled == 0)
{
duk_context *_ctx = winIPC->ctx;
duk_push_heapptr(winIPC->ctx, winIPC->ds->readableStream->object); // [obj]
duk_prepare_method_call(winIPC->ctx, -1, "end"); // [obj][end][this]
if (duk_pcall_method(winIPC->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(_ctx, "net.ipcServer.end() Error: "); }
duk_pop_2(_ctx); // ...
}
return(FALSE);
}
}
BOOL ILibDuktape_server_ipc_WriteSink(void *chain, HANDLE h, ILibWaitHandle_ErrorStatus status, DWORD bytesWritten, void* user)
{
if (!ILibMemory_CanaryOK(user)) { return(FALSE); }
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
duk_idx_t top = duk_get_top(winIPC->ctx);
duk_size_t bufLen;
char *buf;
ILibTransport_DoneState d = ILibTransport_DoneState_COMPLETE;
BOOL ret = FALSE;
duk_push_heapptr(winIPC->ctx, winIPC->mSocket); // [obj]
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_net_WindowsIPC_PendingArray); // [obj][array]
while (d == ILibTransport_DoneState_COMPLETE)
{
duk_dup(winIPC->ctx, -1); // [obj][array][array]
duk_get_prop_string(winIPC->ctx, -1, "shift"); // [obj][array][array][shift]
duk_swap_top(winIPC->ctx, -2); // [obj][array][shift][this]
if (duk_pcall_method(winIPC->ctx, 0) != 0) { duk_set_top(winIPC->ctx, top); return(FALSE); } // [obj][array][buffer]
duk_pop(winIPC->ctx); // [obj][array]
if (duk_get_length(winIPC->ctx, -1) == 0) { break; }
duk_get_prop_index(winIPC->ctx, -1, 0); // [obj][array][buffer]
buf = Duktape_GetBuffer(winIPC->ctx, -1, &bufLen);
d = ILibChain_WriteEx2(chain, h, &(winIPC->write_overlapped), buf, (DWORD)bufLen, ILibDuktape_server_ipc_WriteSink, winIPC, "server_ipc_WriteSink()");
duk_pop(winIPC->ctx); // [obj][array]
}
switch (d)
{
case ILibTransport_DoneState_COMPLETE:
// No more pending writes, so we can emit drain
ILibDuktape_DuplexStream_Ready(winIPC->ds);
ret = FALSE;
break;
case ILibTransport_DoneState_INCOMPLETE:
// Still pending writes, so return TRUE, so we can get evented later
ret = TRUE;
break;
case ILibTransport_DoneState_ERROR:
ret = FALSE;
break;
}
duk_set_top(winIPC->ctx, top); // ...
return(ret);
}
int ILibDuktape_net_server_IPC_unshiftSink(ILibDuktape_DuplexStream *sender, int unshiftBytes, void *user)
{
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
if (!ILibMemory_CanaryOK(user)) { return(0); }
winIPC->unshiftedBytes = unshiftBytes;
return(unshiftBytes);
}
void ILibDuktape_net_server_IPC_PauseSink(ILibDuktape_DuplexStream *sender, void *user)
{
// No-OP, becuase all we need to so is set Paused flag, which is already the case when we get here
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
winIPC->paused = 1;
if (winIPC->mServer != NULL && winIPC->clientConnected == 0) { return; } // Not connected, so just return. Probably unpiping
winIPC->reservedState = ILibChain_WaitHandle_RemoveAndSaveState(winIPC->mChain, winIPC->read_overlapped.hEvent);
}
void ILibDuktape_net_server_IPC_ResumeSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
winIPC->paused = 0;
if (winIPC->reservedState != NULL)
{
ILibChain_WaitHandle_RestoreState(winIPC->mChain, winIPC->reservedState);
winIPC->reservedState = NULL;
}
else
{
ILibDuktape_server_ipc_ReadSink(winIPC->mChain, winIPC->mPipeHandle, ILibWaitHandle_ErrorStatus_NONE, NULL, 0, winIPC);
}
}
ILibTransport_DoneState ILibDuktape_net_server_IPC_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
if (!ILibMemory_CanaryOK(user)) { return(ILibTransport_DoneState_ERROR); }
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
if (!duk_ctx_is_alive(winIPC->ctx) || winIPC->mPipeHandle == NULL) { return(ILibTransport_DoneState_ERROR); }
duk_push_heapptr(winIPC->ctx, winIPC->mSocket); // [obj]
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_net_WindowsIPC_PendingArray); // [obj][array]
char *q = duk_push_fixed_buffer(winIPC->ctx, bufferLen); // [obj][array][buffer]
duk_size_t len = duk_get_length(winIPC->ctx, -2);
duk_put_prop_index(winIPC->ctx, -2, (duk_uarridx_t)len); // [obj][array]
memcpy_s(q, bufferLen, buffer, bufferLen);
duk_pop_2(winIPC->ctx); // ...
if (len == 0)
{
// No Pending Writes
ILibTransport_DoneState ret = ILibChain_WriteEx2(winIPC->mChain, winIPC->mPipeHandle, &(winIPC->write_overlapped), q, bufferLen, ILibDuktape_server_ipc_WriteSink, winIPC, "net_server_IPC_WriteSink()");
if (ret != ILibTransport_DoneState_INCOMPLETE)
{
duk_push_heapptr(winIPC->ctx, winIPC->mSocket); // [obj]
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_net_WindowsIPC_PendingArray); // [obj][array]
duk_array_shift(winIPC->ctx, -1); // [obj][array][val]
duk_pop_3(winIPC->ctx); // ...
}
return(ret);
}
return(ILibTransport_DoneState_INCOMPLETE);
}
void ILibDuktape_net_server_IPC_EndSink(ILibDuktape_DuplexStream *stream, void *user)
{
if (!ILibMemory_CanaryOK(user)) { return; }
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
if (winIPC->mServer != NULL && winIPC->mPipeHandle == NULL) { return; } // Already Closed
winIPC->endCalled = 1;
if (winIPC->reservedState != NULL)
{
ILibChain_WaitHandle_DestroySavedState(winIPC->mChain, winIPC->reservedState);
winIPC->reservedState = NULL;
}
else
{
// We probably aren't paused, so we need to remove our wait handles
if (winIPC->read_overlapped.hEvent != NULL) { ILibChain_RemoveWaitHandle(winIPC->mChain, winIPC->read_overlapped.hEvent); }
if (winIPC->write_overlapped.hEvent != NULL) { ILibChain_RemoveWaitHandle(winIPC->mChain, winIPC->write_overlapped.hEvent); }
}
if (winIPC->mPipeHandle != NULL)
{
if (winIPC->mServer != NULL) { DisconnectNamedPipe(winIPC->mPipeHandle); }
CloseHandle(winIPC->mPipeHandle); winIPC->mPipeHandle = NULL;
}
if (winIPC->read_overlapped.hEvent != NULL) { CloseHandle(winIPC->read_overlapped.hEvent); winIPC->read_overlapped.hEvent = NULL; }
if (winIPC->write_overlapped.hEvent != NULL) { CloseHandle(winIPC->write_overlapped.hEvent); winIPC->write_overlapped.hEvent = NULL; }
if (winIPC != NULL && winIPC->mServer != NULL)
{
duk_context *_ctx = winIPC->ctx;
duk_push_heapptr(winIPC->ctx, winIPC->mServer); // [server]
int needEmitClose = Duktape_GetBooleanProperty(winIPC->ctx, -1, ILibDuktape_net_server_closed_needEmit, 0);
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_net_ConcurrencyArray); // [server][array]
duk_prepare_method_call(winIPC->ctx, -1, "indexOf"); // [server][array][indexOf][this]
duk_push_heapptr(winIPC->ctx, winIPC->ipcreserved); // [server][array][indexOf][this][buffer]
if (duk_pcall_method(winIPC->ctx, 1) == 0) // [server][array][index]
{
int ix = duk_get_int(winIPC->ctx, -1);
if (ix >= 0)
{
duk_uarridx_t numObjects = (duk_uarridx_t)duk_get_length(_ctx, -2);
int maxLen = Duktape_GetIntPropertyValue(_ctx, -3, ILibDuktape_net_ConcurrencyMaxSize, 1);
duk_uarridx_t z;
int setup = numObjects == maxLen ? 1 : 0;
int connected = 0;
for (z = 0; z < numObjects; ++z)
{
duk_get_prop_index(winIPC->ctx, -2, z); // [server][array][index][winIPC]
if (z != ix && ((ILibDuktape_net_WindowsIPC*)Duktape_GetBuffer(winIPC->ctx, -1, NULL))->clientConnected == FALSE)
{
setup = 0;
}
if (((ILibDuktape_net_WindowsIPC*)Duktape_GetBuffer(winIPC->ctx, -1, NULL))->clientConnected == TRUE)
{
++connected;
}
duk_pop(winIPC->ctx); // [server][array][index]
}
duk_array_remove(winIPC->ctx, -2, ix);
if (setup != 0 && needEmitClose == 0)
{
duk_prepare_method_call(_ctx, -3, "listen"); // [server][array][index][listen][this]
duk_get_prop_string(_ctx, -1, ILibDuktape_SERVER2LISTENOPTIONS);// [server][array][index][listen][this][options]
duk_pcall_method(_ctx, 1); duk_pop(_ctx); // [server][array][index]
}
else
{
if (needEmitClose != 0 && connected == 0)
{
// All connections are now closed, so we can emit 'close'
ILibDuktape_EventEmitter_SetupEmitEx(_ctx, -3, "close"); // [server][array][index][emit][this][close]
duk_pcall_method(_ctx, 1); duk_pop(_ctx); // [server][array][index]
}
}
}
}
duk_pop_3(_ctx); // ...
}
}
duk_ret_t ILibDuktape_net_server_IPC_ConnectSink_Finalizer(duk_context *ctx)
{
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_GetBufferProperty(ctx, 0, ILibDuktape_net_WindowsIPC_Buffer);
if (winIPC != NULL)
{
if (winIPC->mPipeHandle != NULL)
{
CloseHandle(winIPC->mPipeHandle);
winIPC->mPipeHandle = NULL;
}
if (winIPC->read_overlapped.hEvent != NULL)
{
ILibChain_RemoveWaitHandle(duk_ctx_chain(ctx), winIPC->read_overlapped.hEvent);
CloseHandle(winIPC->read_overlapped.hEvent);
winIPC->read_overlapped.hEvent = NULL;
}
if (winIPC->write_overlapped.hEvent != NULL)
{
ILibChain_RemoveWaitHandle(duk_ctx_chain(ctx), winIPC->write_overlapped.hEvent);
CloseHandle(winIPC->write_overlapped.hEvent);
winIPC->write_overlapped.hEvent = NULL;
}
if (winIPC->buffer != NULL) { free(winIPC->buffer); }
}
return(0);
}
duk_ret_t ILibDuktape_net_server_IPC_connection_metadata(duk_context *ctx)
{
duk_push_this(ctx); // [ipcSocket]
char *id = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_OBJID, NULL);
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_net_WindowsIPC_Buffer);
char *tmp = (char*)duk_push_sprintf(ctx, "%s, %s", winIPC->metadata, (char*)duk_require_string(ctx, 0));
char *tmp2 = (char*)ILibMemory_SmartAllocate(1 + duk_get_length(ctx, -1));
memcpy_s(tmp2, ILibMemory_Size(tmp2), tmp, ILibMemory_Size(tmp2) - 1);
ILibMemory_Free(winIPC->metadata);
winIPC->metadata = tmp2;
return(0);
}
BOOL ILibDuktape_net_server_IPC_ConnectSink(void *chain, HANDLE event, ILibWaitHandle_ErrorStatus status, void* user)
{
if (ILibMemory_CanaryOK(user) && status == ILibWaitHandle_ErrorStatus_NONE)
{
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)user;
if (winIPC->mServer != NULL)
{
duk_push_heapptr(winIPC->ctx, winIPC->mServer); // [server]
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_net_ConcurrencyArray); // [server][array]
int maxCount = Duktape_GetIntPropertyValue(winIPC->ctx, -2, ILibDuktape_net_ConcurrencyMaxSize, 0);
int curCount = (int)duk_get_length(winIPC->ctx, -1);
duk_pop_2(winIPC->ctx); // ...
if (curCount < maxCount)
{
// We are still within concurrency limits, so lets prepare for another connection
duk_push_heapptr(winIPC->ctx, winIPC->mServer); // [server]
duk_prepare_method_call(winIPC->ctx, -1, "listen"); // [server][listen][this]
duk_remove(winIPC->ctx, -3); // [listen][this]
duk_get_prop_string(winIPC->ctx, -1, ILibDuktape_SERVER2LISTENOPTIONS); // [listen][this][options]
duk_pcall_method(winIPC->ctx, 1);
duk_pop(winIPC->ctx); // ...
}
}
winIPC->clientConnected = TRUE;
ILibDuktape_EventEmitter_SetupEmit(winIPC->ctx, winIPC->mServer, "connection"); // [emit][this][connection]
duk_push_object(winIPC->ctx); // [emit][this][connection][socket]
ILibDuktape_WriteID(winIPC->ctx, "net.ipcSocket");
winIPC->metadata = "net.ipcSocket";
duk_push_heapptr(winIPC->ctx, winIPC->ipcreserved); // [emit][this][connection][socket][buffer]
duk_put_prop_string(winIPC->ctx, -2, ILibDuktape_net_WindowsIPC_Buffer); // [emit][this][connection][socket]
duk_push_array(winIPC->ctx); duk_put_prop_string(winIPC->ctx, -2, ILibDuktape_net_WindowsIPC_PendingArray);
winIPC->mSocket = duk_get_heapptr(winIPC->ctx, -1);
winIPC->ds = ILibDuktape_DuplexStream_InitEx(winIPC->ctx, ILibDuktape_net_server_IPC_WriteSink, ILibDuktape_net_server_IPC_EndSink, ILibDuktape_net_server_IPC_PauseSink, ILibDuktape_net_server_IPC_ResumeSink, ILibDuktape_net_server_IPC_unshiftSink, winIPC);
winIPC->ds->readableStream->paused = 1;
winIPC->paused = 1;
ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter_GetEmitter(winIPC->ctx, -1), "data", ILibDuktape_net_socket_ipc_dataHookCallback);
ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter_GetEmitter(winIPC->ctx, -1), "end", ILibDuktape_net_socket_ipc_dataHookCallback);
ILibDuktape_CreateEventWithSetterEx(winIPC->ctx, "descriptorMetadata", ILibDuktape_net_server_IPC_connection_metadata);
ILibDuktape_EventEmitter_PrependOnce(winIPC->ctx, -1, "~", ILibDuktape_net_server_IPC_ConnectSink_Finalizer);
if (duk_pcall_method(winIPC->ctx, 2) != 0)
{
ILibDuktape_Process_UncaughtExceptionEx(winIPC->ctx, "Error emitting net.ipcSocket.connection");
}
duk_pop(winIPC->ctx);
}
return(FALSE);
}
#endif
duk_ret_t ILibDuktape_net_server_connections(duk_context *ctx)
{
duk_push_this(ctx); // [server]
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_net_Server_buffer);
if (server->server == NULL)
{
#ifdef WIN32
// On Windows, IPC uses a ConcurrencyArray
ILibDuktape_net_WindowsIPC *winIPC = NULL;
duk_uarridx_t i;
duk_size_t len;
duk_get_prop_string(ctx, -1, ILibDuktape_net_ConcurrencyArray); // [server][array]
duk_push_array(ctx); // [server][array][retArray]
len = duk_get_length(ctx, -2);
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -2, i); // [server][array][retArray][buffer]
winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_GetBuffer(ctx, -1, NULL);
if (winIPC->clientConnected == TRUE)
{
duk_push_heapptr(ctx, winIPC->mSocket); // [server][array][retArray][buffer][socket]
duk_array_push(ctx, -3); // [server][array][retArray][buffer]
}
duk_pop(ctx); // [server][array][retArray]
}
#else
duk_push_array(ctx);
#endif
}
else
{
size_t i;
size_t s = ILibAsyncServerSocket_GetConnections(server->server, NULL, 0);
ILibAsyncServerSocket_ConnectionToken *connections = (ILibAsyncServerSocket_ConnectionToken*)Duktape_PushBuffer(ctx, s * sizeof(ILibAsyncServerSocket_ConnectionToken));
ILibDuktape_net_server_session *session;
duk_push_array(ctx); // [server][retArray]
s = ILibAsyncServerSocket_GetConnections(server->server, connections, s);
for (i = 0; i < s; ++i)
{
session = (ILibDuktape_net_server_session*)ILibAsyncServerSocket_GetUser(connections[i]);
if (ILibMemory_CanaryOK(session))
{
duk_push_heapptr(ctx, session->emitter->object);
duk_array_push(ctx, -2);
}
}
}
return(1);
}
duk_ret_t ILibDuktape_net_server_listen(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
ILibDuktape_net_server *server = NULL;
int i;
unsigned short port = 0;
int backlog = 0;
int maxConnections = 10;
struct sockaddr_in6 local;
#ifdef _POSIX
struct sockaddr_un ipcaddr;
memset(&ipcaddr, 0, sizeof(struct sockaddr_un));
#endif
int initalBufferSize = 4096;
char *host, *ipc;
duk_size_t ipcLen;
memset(&local, 0, sizeof(struct sockaddr_in6));
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_net_Server_buffer);
server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
if (nargs == 0 || !duk_is_object(ctx, 0))
{
duk_push_this(ctx); // [server]
duk_get_prop_string(ctx, -1, "listen"); // [server][listen]
duk_swap_top(ctx, -2); // [listen][this]
duk_push_object(ctx); // [listen][this][Options]
// let's call listen again, using an Options object
if (nargs > 0 && (duk_is_number(ctx, 0) || duk_is_string(ctx, 0)))
{
duk_dup(ctx, 0); duk_put_prop_string(ctx, -2, duk_is_number(ctx, 0) ? "port" : "path"); // [listen][this][Options]
for (i = 1; i < nargs; ++i)
{
if (duk_is_number(ctx, i)) { duk_dup(ctx, i); duk_put_prop_string(ctx, -2, "backlog"); }
if (duk_is_string(ctx, i)) { duk_dup(ctx, i); duk_put_prop_string(ctx, -2, "host"); }
if (duk_is_function(ctx, i)) { duk_dup(ctx, i); break; } // [listen][this][Options][callback]
}
duk_call_method(ctx, i < nargs ? 2 : 1);
return(1);
}
else
{
duk_call_method(ctx, 1);
return(1);
}
}
// If we are here, we were called with an Options Object
duk_push_this(ctx); // [server]
duk_dup(ctx, 0); // [server][Options]
duk_put_prop_string(ctx, -2, ILibDuktape_SERVER2LISTENOPTIONS); // [server]
port = (unsigned short)Duktape_GetIntPropertyValue(ctx, 0, "port", 0);
host = Duktape_GetStringPropertyValue(ctx, 0, "host", NULL);
ipc = Duktape_GetStringPropertyValueEx(ctx, 0, "path", NULL, &ipcLen);
maxConnections = Duktape_GetIntPropertyValue(ctx, 0, "maxConnections", (ipc != NULL && port == 0) ? 1 : 10);
if (nargs > 1 && duk_is_function(ctx, 1))
{
// Callback
ILibDuktape_EventEmitter_AddOn(server->emitter, "listening", duk_require_heapptr(ctx, 1));
}
if (host != NULL)
{
ILibResolveEx(host, port, &local);
if (local.sin6_family == AF_UNSPEC)
{
return(ILibDuktape_Error(ctx, "Socket.listen(): Could not resolve host: '%s'", host));
}
}
if (ipc != NULL && port == 0)
{
duk_push_this(ctx);
ILibDuktape_WriteID(ctx, "net.ipcServer");
duk_push_string(ctx, ipc); duk_put_prop_string(ctx, -2, ILibDuktape_net_server_IPCPath);
if (maxConnections >= 0 && !duk_has_prop_string(ctx, -1, ILibDuktape_net_ConcurrencyArray))
{
duk_push_array(ctx); duk_put_prop_string(ctx, -2, ILibDuktape_net_ConcurrencyArray);
duk_push_int(ctx, maxConnections); duk_put_prop_string(ctx, -2, ILibDuktape_net_ConcurrencyMaxSize);
}
duk_pop(ctx);
#if defined(_POSIX)
if (ipcLen > sizeof(ipcaddr.sun_path)) { return(ILibDuktape_Error(ctx, "Path too long")); }
ipcaddr.sun_family = AF_UNIX;
strcpy_s((char*)(ipcaddr.sun_path), sizeof(ipcaddr.sun_path), ipc);
int ipcmod = Duktape_GetBooleanProperty(ctx, 0, "writableAll", 0) == 0 ? 0 : 0777;
server->server = ILibCreateAsyncServerSocketModuleWithMemoryExMOD(Duktape_GetChain(ctx), maxConnections, initalBufferSize, (struct sockaddr*)&ipcaddr,
ILibDuktape_net_server_OnConnect, ILibDuktape_net_server_OnDisconnect, ILibDuktape_net_server_OnReceive,
ILibDuktape_net_server_OnInterrupt, ILibDuktape_net_server_OnSendOK, ipcmod, sizeof(void*), sizeof(void*));
#elif defined(WIN32)
// IPC on Windows Implemented as Named Pipe
SECURITY_ATTRIBUTES IPC_SA = { 0 };
SECURITY_ATTRIBUTES *pIPC_SA = &IPC_SA;
PACL IPC_ACL;
SECURITY_DESCRIPTOR IPC_SD;
EXPLICIT_ACCESS IPC_EA = { 0 };
duk_push_this(ctx); // [server]
duk_get_prop_string(ctx, -1, ILibDuktape_net_ConcurrencyArray); // [server][array]
ILibDuktape_net_WindowsIPC *winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_net_WindowsIPC));
duk_dup(ctx, -1); // [server][array][buffer][buffer]
duk_array_push(ctx, -3); // [server][array][buffer]
duk_remove(ctx, -2); // [server][buffer]
winIPC->ipcreserved = duk_get_heapptr(ctx, -1);
duk_pop(ctx); // [server]
winIPC->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
winIPC->ctx = ctx;
winIPC->mServer = duk_get_heapptr(ctx, -1);
winIPC->mChain = duk_ctx_chain(ctx);
winIPC->clientConnected = FALSE;
winIPC->metadata = "net.ipcServer";
duk_eval_string(ctx, "require('child_process');");
duk_pop(ctx);
if (Duktape_GetBooleanProperty(ctx, 0, "writableAll", 0) != 0)
{
// World Writable, so we need to set the Security Descriptor to reflect that
IPC_EA.grfAccessMode = SET_ACCESS;
IPC_EA.grfInheritance = NO_INHERITANCE;
IPC_EA.grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
IPC_EA.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
IPC_EA.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
IPC_EA.Trustee.ptstrName = "EVERYONE";
SetEntriesInAcl(1, &IPC_EA, NULL, &IPC_ACL);
InitializeSecurityDescriptor(&IPC_SD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&IPC_SD, TRUE, IPC_ACL, FALSE);
memset(&IPC_SA, 0, sizeof(SECURITY_ATTRIBUTES));
IPC_SA.nLength = sizeof(SECURITY_ATTRIBUTES);
IPC_SA.bInheritHandle = FALSE;
IPC_SA.lpSecurityDescriptor = &IPC_SD;
}
else
{
// Default security is Read/Write for LocalSystem and owner, and Read for everybody else
pIPC_SA = NULL;
}
winIPC->mPipeHandle = CreateNamedPipeA((LPCSTR)ipc, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS,
(DWORD)maxConnections, ILibDuktape_net_IPC_BUFFERSIZE, ILibDuktape_net_IPC_BUFFERSIZE, 0, pIPC_SA);
if (winIPC->mPipeHandle == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
CloseHandle(winIPC->overlapped.hEvent); winIPC->overlapped.hEvent = NULL;
return(ILibDuktape_Error(ctx, "Error Creating Named Pipe: %s", ipc));
}
//printf("ConnectNamedPipe(%s)\n", ipc);
duk_push_sprintf(ctx, "net.ipcServer [listen: %s]", ipc);
ConnectNamedPipe(winIPC->mPipeHandle, &winIPC->overlapped);
ILibChain_AddWaitHandleEx(duk_ctx_chain(ctx), winIPC->overlapped.hEvent, -1, ILibDuktape_net_server_IPC_ConnectSink, winIPC, (char*)duk_get_string(ctx, -1));
duk_pop(ctx);
if (pIPC_SA != NULL) { LocalFree(IPC_ACL); }
return(1);
#endif
}
else
{
local.sin6_family = AF_INET;
local.sin6_port = htons(port);
server->server = ILibCreateAsyncServerSocketModuleWithMemoryEx(Duktape_GetChain(ctx), maxConnections, initalBufferSize, (struct sockaddr*)&local,
ILibDuktape_net_server_OnConnect, ILibDuktape_net_server_OnDisconnect, ILibDuktape_net_server_OnReceive,
ILibDuktape_net_server_OnInterrupt, ILibDuktape_net_server_OnSendOK, sizeof(void*), sizeof(void*));
}
if (server->server == NULL)
{
return(ILibDuktape_Error(ctx, "server.listen(): Failed to bind"));
}
((void**)ILibMemory_GetExtraMemory(server->server, ILibMemory_ASYNCSERVERSOCKET_CONTAINERSIZE))[0] = server;
ILibAsyncServerSocket_SetTag(server->server, server);
#ifndef MICROSTACK_NOTLS
{
if (server->isTLS)
{
duk_push_this(ctx); // [server]
if (duk_has_prop_string(ctx, -1, "addContext"))
{
duk_get_prop_string(ctx, -1, "addContext"); // [server][addContext]
duk_swap_top(ctx, -2); // [addContext][this]
duk_push_string(ctx, "*"); // [addContext][this][*]
duk_eval_string(ctx, "require('tls');"); // [addContext][this][*][tls]
duk_get_prop_string(ctx, -1, "createSecureContext"); // [addContext][this][*][tls][createSecureContext]
duk_swap_top(ctx, -2); // [addContext][this][*][createSecureContext][this]
duk_get_prop_string(ctx, -4, ILibDuktape_SERVER2OPTIONS); // [addContext][this][*][createSecureContext][this][options]
duk_call_method(ctx, 1); // [addContext][this][*][secureContext]
duk_call_method(ctx, 2); duk_pop(ctx); // ...
}
else
{
duk_pop(ctx); // ...
}
}
}
#endif
duk_push_heapptr(server->ctx, server->self); // [this]
duk_get_prop_string(server->ctx, -1, "emit"); // [this][emit]
duk_swap_top(server->ctx, -2); // [emit][this]
duk_push_string(server->ctx, "listening"); // [emit][this][listenting]
if (duk_pcall_method(server->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(server->ctx, "net.server.listen(): Error "); }
duk_pop(server->ctx); // ...
#ifndef WIN32
ignore_result(backlog);
#endif
duk_push_this(ctx);
if (server->server != NULL)
{
duk_get_prop_string(ctx, -1, ILibDuktape_OBJID); // [server][str]
if (duk_has_prop_string(ctx, -2, ILibDuktape_net_server_metadata))
{
duk_push_string(ctx, ", "); // [server][str][newVal]
duk_string_concat(ctx, -2); duk_remove(ctx, -2); // [server][str]
duk_get_prop_string(ctx, -2, ILibDuktape_net_server_metadata); // [server][str][metadata]
duk_string_concat(ctx, -2); duk_remove(ctx, -2); // [server][metadata]
duk_dup(ctx, -1); // [server][metadata][clone]
duk_put_prop_string(ctx, -3, ILibDuktape_net_server_metadata); // [server][metadata]
}
ILibChain_Link_SetMetadata(server->server, (char*)duk_get_string(ctx, -1));
duk_pop(ctx);
}
return 1;
}
duk_ret_t ILibDuktape_net_server_Finalizer(duk_context *ctx)
{
duk_push_this(ctx); // [server]
duk_eval_string(ctx, "require('fs');"); // [server][fs]
duk_prepare_method_call(ctx, -1, "unlinkSync"); // [server][fs][unlinkSync][this]
duk_get_prop_string(ctx, -4, ILibDuktape_net_server_IPCPath); // [server][fs][unlinkSync][this][path]
duk_pcall_method(ctx, 1); // [server][fs][ret]
void *chain = Duktape_GetChain(ctx);
ILibDuktape_net_server *server;
duk_get_prop_string(ctx, 0, ILibDuktape_net_Server_buffer);
server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
if (server != NULL && server->server != NULL && ILibIsChainBeingDestroyed(chain) == 0)
{
ILibAsyncServerSocket_RemoveFromChain(server->server);
}
#ifdef WIN32
ILibDuktape_net_WindowsIPC *ipc = NULL;
duk_get_prop_string(ctx, 0, ILibDuktape_net_ConcurrencyArray); // [array]
while (duk_get_length(ctx, -1) > 0)
{
duk_array_pop(ctx, -1); // [array][winipc]
ipc = (ILibDuktape_net_WindowsIPC*)Duktape_GetBuffer(ctx, -1, NULL);
if (ipc != NULL && ipc->overlapped.hEvent != NULL)
{
ILibChain_RemoveWaitHandle(duk_ctx_chain(ctx), ipc->overlapped.hEvent);
if (ipc->mPipeHandle != NULL) { CloseHandle(ipc->mPipeHandle); ipc->mPipeHandle = NULL; }
if (ipc->overlapped.hEvent != NULL) { CloseHandle(ipc->overlapped.hEvent); ipc->overlapped.hEvent = NULL; }
}
duk_pop(ctx); // [array]
}
#endif
return 0;
}
duk_ret_t ILibDuktape_net_server_address(duk_context *ctx)
{
duk_push_this(ctx); // [server]
duk_get_prop_string(ctx, -1, ILibDuktape_net_Server_buffer); // [server][buffer]
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
struct sockaddr_in6 local;
memset(&local, 0, sizeof(struct sockaddr_in6));
ILibAsyncServerSocket_GetLocal(server->server, (struct sockaddr*)&local, sizeof(struct sockaddr_in6));
if (local.sin6_family == AF_UNSPEC) { return(ILibDuktape_Error(ctx, "net.server.address(): call to getsockname() failed")); }
duk_push_object(ctx);
duk_push_string(ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4");
duk_put_prop_string(ctx, -2, "family");
duk_push_int(ctx, (int)ntohs(local.sin6_port));
duk_put_prop_string(ctx, -2, "port");
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)&local));
duk_put_prop_string(ctx, -2, "address");
return(1);
}
duk_ret_t ILibDuktape_net_server_close(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
duk_push_this(ctx);
if (nargs > 0)
{
duk_get_prop_string(ctx, -1, "once"); // [server][once]
duk_dup(ctx, -2); // [server][once][this]
duk_push_string(ctx, "close"); // [server][once][this][close]
duk_dup(ctx, 0); // [server][once][this][close][callback]
duk_call_method(ctx, 2); duk_pop(ctx); // [server]
}
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_net_Server_buffer);
if (server != NULL && server->server != NULL)
{
if (!ILibIsChainBeingDestroyed(Duktape_GetChain(ctx)))
{
ILibAsyncServerSocket_RemoveFromChain(server->server);
server->server = NULL;
#ifdef _POSIX
duk_push_this(ctx); // [server]
if(duk_has_prop_string(ctx, -1, ILibDuktape_net_server_IPCPath))
{
duk_eval_string(ctx, "require('fs');"); // [server][fs]
duk_get_prop_string(ctx, -1, "unlinkSync"); // [server][fs][unlinkSync]
duk_swap_top(ctx, -2); // [server][unlinkSync][this]
duk_get_prop_string(ctx, -3, ILibDuktape_net_server_IPCPath); // [server][unlinkSync][this][path]
duk_pcall_method(ctx, 1); duk_pop(ctx); // [server]
}
duk_pop(ctx); // [...]
#endif
ILibDuktape_EventEmitter_SetupEmit(ctx, server->self, "close"); // [emit][this][close]
duk_call_method(ctx, 1);
}
}
#ifdef WIN32
else
{
duk_push_this(ctx); // [server]
duk_get_prop_string(ctx, -1, ILibDuktape_net_ConcurrencyArray); // [server][array]
int connections = 0;
ILibDuktape_net_WindowsIPC *winIPC = NULL;
duk_uarridx_t i;
duk_size_t len = duk_get_length(ctx, -1);
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -1, i); // [server][array][winipc]
winIPC = (ILibDuktape_net_WindowsIPC*)Duktape_GetBuffer(ctx, -1, NULL);
if (winIPC != NULL && winIPC->mPipeHandle != NULL)
{
if (winIPC->clientConnected == FALSE)
{
// This object is listening for a new connection
DisconnectNamedPipe(winIPC->mPipeHandle);
CancelIoEx(winIPC->mPipeHandle, NULL);
CloseHandle(winIPC->mPipeHandle);
winIPC->mPipeHandle = NULL;
ILibChain_RemoveWaitHandle(duk_ctx_chain(ctx), winIPC->overlapped.hEvent);
}
else
{
++connections;
}
}
duk_pop(ctx); // [server][array]
}
if (connections == 0)
{
// No active connections, so we can emit 'close' now
ILibDuktape_EventEmitter_SetupEmit(ctx, server->self, "close"); // [emit][this][close]
duk_call_method(ctx, 1);
}
else
{
// Set a flag, so we emit this when all connections are closed
duk_push_this(ctx);
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, ILibDuktape_net_server_closed_needEmit);
}
}
#endif
duk_push_this(ctx);
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, ILibDuktape_net_server_closed);
return(0);
}
duk_ret_t ILibDuktape_net_server_listening(duk_context *ctx)
{
duk_push_this(ctx); // [server]
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_net_Server_buffer);
if (server->server != NULL || duk_has_prop_string(ctx, -1, ILibDuktape_net_WindowsIPC_Buffer))
{
duk_push_true(ctx);
}
else
{
duk_push_false(ctx);
}
return(1);
}
duk_ret_t ILibDuktape_net_createServer_metadata(duk_context *ctx)
{
duk_push_this(ctx); // [serverSocket]
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_net_Server_buffer);
if (server->server != NULL)
{
// Non-IPC Server
char *tmp = (char*)duk_push_sprintf(ctx, "%s, %s", ILibChain_Link_GetMetadata(server->server), (char*)duk_require_string(ctx, 0));
char *tmp2 = (char*)ILibMemory_SmartAllocate(duk_get_length(ctx, -1) + 1);
memcpy_s(tmp2, ILibMemory_Size(tmp2), tmp, ILibMemory_Size(tmp2) - 1);
ILibChain_Link_SetMetadata(server->server, tmp2);
}
else
{
duk_dup(ctx, 0); // [server][string]
duk_put_prop_string(ctx, -2, ILibDuktape_net_server_metadata);
}
return(0);
}
duk_ret_t ILibDuktape_net_createServer(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
int i;
ILibDuktape_net_server *server;
duk_push_current_function(ctx);
int isTLS = Duktape_GetIntPropertyValue(ctx, -1, "tls", 0);
duk_pop(ctx);
duk_push_object(ctx); // [server]
ILibDuktape_WriteID(ctx, isTLS ? "tls.Server" : "net.Server");
if (nargs > 0 && duk_is_object(ctx, 0))
{
duk_dup(ctx, 0); // [server][Options]
duk_put_prop_string(ctx, -2, ILibDuktape_SERVER2OPTIONS); // [server]
}
server = Duktape_PushBuffer(ctx, sizeof(ILibDuktape_net_server)); // [server][fbuffer]
duk_put_prop_string(ctx, -2, ILibDuktape_net_Server_buffer); // [server]
server->isTLS = isTLS;
server->self = duk_get_heapptr(ctx, -1);
server->ctx = ctx;
server->emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "close");
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "connection");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "close", ILibDuktape_net_server_close, DUK_VARARGS);
#ifndef MICROSTACK_NOTLS
if (isTLS)
{
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "secureConnection");
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "tlsClientError");
ILibDuktape_CreateInstanceMethod(ctx, "addContext", ILibDuktape_tls_server_addContext, 2);
duk_push_object(ctx); duk_put_prop_string(ctx, -2, ILibDuktape_SERVER2ContextTable);
if (ILibDuktape_TLS_ctx2server < 0) { ILibDuktape_TLS_ctx2server = SSL_get_ex_new_index(0, "ILibDuktape_TLS_Server index", NULL, NULL, NULL); }
}
#endif
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "error");
ILibDuktape_EventEmitter_CreateEventEx(server->emitter, "listening");
ILibDuktape_CreateEventWithGetter(ctx, "listening", ILibDuktape_net_server_listening);
ILibDuktape_CreateEventWithSetterEx(ctx, "descriptorMetadata", ILibDuktape_net_createServer_metadata);
ILibDuktape_CreateEventWithGetter(ctx, "connections", ILibDuktape_net_server_connections);
ILibDuktape_CreateInstanceMethod(ctx, "listen", ILibDuktape_net_server_listen, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "address", ILibDuktape_net_server_address, 0);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_net_server_Finalizer);
for (i = 0; i < 2 && i < nargs; ++i)
{
if (duk_is_function(ctx, i))
{
// Callback
ILibDuktape_EventEmitter_AddOn(server->emitter, isTLS ? "secureConnection" : "connection", duk_require_heapptr(ctx, i));
}
if (duk_is_object(ctx, i))
{
// Options
if (isTLS && !duk_has_prop_string(ctx, i, "secureProtocol"))
{
duk_dup(ctx, i); // [options]
duk_push_string(ctx, "SSLv23_server_method"); // [options][secureProtocol]
duk_put_prop_string(ctx, -2, "secureProtocol"); // [options]
duk_pop(ctx); // ...
}
}
}
return 1;
}
duk_ret_t ILibDuktape_net_addr2int(duk_context *ctx)
{
struct sockaddr_in6 addr6;
ILibResolveEx((char*)duk_require_string(ctx, 0), 0, &addr6);
if (addr6.sin6_family == AF_INET)
{
duk_push_int(ctx, ((struct sockaddr_in*)&addr6)->sin_addr.s_addr);
return(1);
}
else
{
return(ILibDuktape_Error(ctx, "Error converting address"));
}
}
void ILibDuktape_net_PUSH_net(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [net]
ILibDuktape_WriteID(ctx, "net");
duk_push_pointer(ctx, chain); // [net][chain]
duk_put_prop_string(ctx, -2, "chain"); // [net]
duk_push_c_function(ctx, ILibDuktape_net_socket_constructor, DUK_VARARGS); // [net][constructor]
duk_push_pointer(ctx, chain); // [net][constructor][chain]
duk_put_prop_string(ctx, -2, "chain"); // [net][constructor]
duk_dup(ctx, -2); // [net][constructor][net]
duk_put_prop_string(ctx, -2, "net"); // [net][constructor]
duk_put_prop_string(ctx, -2, "socket"); // [net]
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "tls", 0, "createServer", ILibDuktape_net_createServer, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "createConnection", ILibDuktape_net_createConnection, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "connect", ILibDuktape_net_createConnection, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "addr2int", ILibDuktape_net_addr2int, 1);
}
duk_ret_t ILibDuktape_globalTunnel_end(duk_context *ctx)
{
duk_push_heap_stash(ctx);
duk_del_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_Stash);
return 0;
}
duk_ret_t ILibDuktape_globalTunnel_initialize(duk_context *ctx)
{
ILibDuktape_globalTunnel_data *data;
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_DataPtr);
data = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
if (duk_has_prop_string(ctx, 0, "host") && duk_has_prop_string(ctx, 0, "port"))
{
char *host = Duktape_GetStringPropertyValue(ctx, 0, "host", "127.0.0.1");
int port = Duktape_GetIntPropertyValue(ctx, 0, "port", 0);
ILibResolveEx(host, (unsigned short)port, &(data->proxyServer));
if (data->proxyServer.sin6_family == AF_UNSPEC)
{
return(ILibDuktape_Error(ctx, "globalTunnel.initialize(): Error, could not resolve: %s", host));
}
}
else
{
return(ILibDuktape_Error(ctx, "globalTunnel.initialize(): Error, invalid parameter"));
}
return 0;
}
duk_ret_t ILibDuktape_globalTunnel_finalizer(duk_context *ctx)
{
ILibDuktape_globalTunnel_data *data;
duk_get_prop_string(ctx, 0, ILibDuktape_GlobalTunnel_DataPtr);
data = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
ILibHashtable_Destroy(data->exceptionsTable);
return 0;
}
duk_ret_t ILibDuktape_globalTunnel_isProxying(duk_context *ctx)
{
ILibDuktape_globalTunnel_data *data;
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_DataPtr);
data = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
if (data->proxyServer.sin6_family == AF_UNSPEC)
{
duk_push_false(ctx);
}
else
{
duk_push_true(ctx);
}
return(1);
}
duk_ret_t ILibDuktape_globalTunnel_proxyConfig(duk_context *ctx)
{
ILibDuktape_globalTunnel_data *data;
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_DataPtr);
data = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
if (data->proxyServer.sin6_family == AF_UNSPEC)
{
duk_push_null(ctx);
}
else
{
duk_push_object(ctx);
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)&(data->proxyServer)));
duk_put_prop_string(ctx, -2, "host");
duk_push_int(ctx, (int)ntohs(data->proxyServer.sin6_port));
duk_put_prop_string(ctx, -2, "port");
}
return(1);
}
ILibDuktape_globalTunnel_data* ILibDuktape_GetNewGlobalTunnelEx(duk_context *ctx, int native)
{
ILibDuktape_globalTunnel_data *retVal;
if (native != 0) { duk_push_heap_stash(ctx); } // [stash]
duk_push_object(ctx); // [stash][tunnel]
duk_dup(ctx, -1); // [stash][tunnel][dup]
duk_put_prop_string(ctx, -3, ILibDuktape_GlobalTunnel_Stash); // [stash][tunnel]
duk_swap_top(ctx, -2); // [tunnel][stash]
duk_pop(ctx); // [tunnel]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_globalTunnel_data)); // [tunnel][buffer]
retVal = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
memset(retVal, 0, sizeof(ILibDuktape_globalTunnel_data));
duk_put_prop_string(ctx, -2, ILibDuktape_GlobalTunnel_DataPtr); // [tunnel]
retVal->exceptionsTable = ILibHashtable_Create();
ILibDuktape_CreateInstanceMethod(ctx, "initialize", ILibDuktape_globalTunnel_initialize, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "end", ILibDuktape_globalTunnel_end, 0);
ILibDuktape_CreateEventWithGetter(ctx, "proxyConfig", ILibDuktape_globalTunnel_proxyConfig);
ILibDuktape_CreateEventWithGetter(ctx, "isProxying", ILibDuktape_globalTunnel_isProxying);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_globalTunnel_finalizer);
if (native != 0) { duk_pop(ctx); } // ...
return retVal;
}
void ILibDuktape_globalTunnel_PUSH(duk_context *ctx, void *chain)
{
duk_push_heap_stash(ctx); // [stash]
if (duk_has_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_Stash))
{
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_Stash); // [stash][tunnel]
duk_swap_top(ctx, -2); // [tunnel][stash]
duk_pop(ctx); // [tunnel]
}
else
{
ILibDuktape_GetNewGlobalTunnelEx(ctx, 0); // [tunnel]
}
return;
}
ILibDuktape_globalTunnel_data* ILibDuktape_GetGlobalTunnel(duk_context *ctx)
{
ILibDuktape_globalTunnel_data *retVal = NULL;
duk_push_heap_stash(ctx); // [stash]
if (duk_has_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_Stash))
{
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_Stash); // [stash][tunnel]
duk_get_prop_string(ctx, -1, ILibDuktape_GlobalTunnel_DataPtr); // [stash][tunnel][buffer]
retVal = (ILibDuktape_globalTunnel_data*)Duktape_GetBuffer(ctx, -1, NULL);
if (retVal->proxyServer.sin6_family == AF_UNSPEC) { retVal = NULL; }
duk_pop_2(ctx); // [stash]
}
duk_pop(ctx); // ...
return retVal;
}
#ifndef MICROSTACK_NOTLS
SSL_CTX* ILibDuktape_TLS_SecureContext_GetCTX(duk_context *ctx, void *secureContext)
{
SSL_CTX *retVal = NULL;
duk_push_heapptr(ctx, secureContext); // [context]
if (duk_has_prop_string(ctx, -1, ILibDuktape_SecureContext2SSLCTXPTR))
{
retVal = (SSL_CTX*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_SecureContext2SSLCTXPTR);
}
duk_pop(ctx); // ...
return(retVal);
}
void ILibDuktape_TLS_X509_PUSH(duk_context *ctx, X509* cert)
{
char hash[UTIL_SHA384_HASHSIZE];
char fingerprint[150];
util_keyhash2(cert, hash);
util_tohex2(hash, UTIL_SHA384_HASHSIZE, fingerprint);
duk_push_object(ctx); // [cert]
duk_push_string(ctx, fingerprint); // [cert][fingerprint]
duk_put_prop_string(ctx, -2, "fingerprint"); // [cert]
util_certhash2(cert, hash);
util_tohex2(hash, UTIL_SHA384_HASHSIZE, fingerprint);
duk_push_string(ctx, fingerprint); // [cert][digest]
duk_put_prop_string(ctx, -2, "digest"); // [cert]
}
int ILibDuktape_TLS_verify(int preverify_ok, X509_STORE_CTX *storectx)
{
STACK_OF(X509) *certChain = X509_STORE_CTX_get_chain(storectx);
SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(storectx, SSL_get_ex_data_X509_STORE_CTX_idx());
ILibDuktape_net_socket *data = (ILibDuktape_net_socket*)SSL_get_ex_data(ssl, ILibDuktape_TLS_ctx2socket);
int i;
int retVal = 0;
duk_push_heapptr(data->ctx, data->object); // [Socket]
duk_get_prop_string(data->ctx, -1, ILibDuktape_SOCKET2OPTIONS); // [Socket][Options]
if (Duktape_GetBooleanProperty(data->ctx, -1, "rejectUnauthorized", 1)) { duk_pop_2(data->ctx); return(preverify_ok); }
void *OnVerify = Duktape_GetHeapptrProperty(data->ctx, -1, "checkServerIdentity");
if (OnVerify == NULL) { duk_pop_2(data->ctx); return(1); }
duk_push_heapptr(data->ctx, OnVerify); // [Socket][Options][func]
duk_push_heapptr(data->ctx, data->object); // [Socket][Options][func][this]
duk_push_array(data->ctx); // [Socket][Options][func][this][certs]
for (i = 0; i < sk_X509_num(certChain); ++i)
{
ILibDuktape_TLS_X509_PUSH(data->ctx, sk_X509_value(certChain, i)); // [Socket][Options][func][this][certs][cert]
duk_put_prop_index(data->ctx, -2, i); // [Socket][Options][func][this][certs]
}
retVal = duk_pcall_method(data->ctx, 1) == 0 ? 1 : 0; // [Socket][Options][undefined]
duk_pop_3(data->ctx); // ...
return retVal;
}
int ILibDuktape_TLS_server_verify(int preverify_ok, X509_STORE_CTX *storectx)
{
STACK_OF(X509) *certChain = X509_STORE_CTX_get_chain(storectx);
SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(storectx, SSL_get_ex_data_X509_STORE_CTX_idx());
ILibDuktape_net_server *data = (ILibDuktape_net_server*)SSL_get_ex_data(ssl, ILibDuktape_TLS_ctx2server);
int i;
int retVal = 0;
if (!ILibMemory_CanaryOK(data)) { return(0); }
duk_push_heapptr(data->ctx, data->self); // [Server]
duk_get_prop_string(data->ctx, -1, ILibDuktape_SERVER2OPTIONS); // [Server][Options]
if (Duktape_GetBooleanProperty(data->ctx, -1, "rejectUnauthorized", 1)) { duk_pop_2(data->ctx); return(preverify_ok); }
void *OnVerify = Duktape_GetHeapptrProperty(data->ctx, -1, "checkClientIdentity");
if (OnVerify == NULL) { return(1); }
duk_push_heapptr(data->ctx, OnVerify); // [func]
duk_push_heapptr(data->ctx, data->self); // [func][this]
duk_push_array(data->ctx); // [func][this][certs]
for (i = 0; i < sk_X509_num(certChain); ++i)
{
ILibDuktape_TLS_X509_PUSH(data->ctx, sk_X509_value(certChain, i)); // [func][this][certs][cert]
duk_put_prop_index(data->ctx, -2, i); // [func][this][certs]
}
retVal = duk_pcall_method(data->ctx, 1) == 0 ? 1 : 0; // [undefined]
duk_pop(data->ctx); // ...
return retVal;
}
void ILibDuktape_tls_server_OnSSL(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, void *ConnectionToken, SSL* ctx, void **user)
{
ILibDuktape_net_server *server = (ILibDuktape_net_server*)ILibAsyncServerSocket_GetTag(AsyncServerSocketModule);
if (!ILibMemory_CanaryOK(server)) { return; }
if (ctx != NULL && ILibDuktape_TLS_ctx2server)
{
SSL_set_ex_data(ctx, ILibDuktape_TLS_ctx2server, server);
}
}
static int ILibDuktape_tls_server_sniCallback(SSL *s, int *ad, void *arg)
{
const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
ILibDuktape_net_server *data = (ILibDuktape_net_server*)SSL_get_ex_data(s, ILibDuktape_TLS_ctx2server);
if (!ILibMemory_CanaryOK(data)) { return(SSL_TLSEXT_ERR_OK); }
duk_push_heapptr(data->ctx, data->self); // [server]
duk_get_prop_string(data->ctx, -1, ILibDuktape_SERVER2ContextTable); // [server][table]
if (duk_has_prop_string(data->ctx, -1, servername))
{
duk_get_prop_string(data->ctx, -1, servername); // [server][table][secureContext]
SSL_CTX *newCTX = ILibDuktape_TLS_SecureContext_GetCTX(data->ctx, duk_get_heapptr(data->ctx, -1));
if (newCTX != NULL)
{
SSL_set_SSL_CTX(s, newCTX);
}
duk_pop(data->ctx); // [server][table]
}
duk_pop_2(data->ctx); // ...
return(SSL_TLSEXT_ERR_OK);
}
int ILibDuktape_tls_server_alpnSink(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
{
int ix = 0;
int ret = SSL_TLSEXT_ERR_ALERT_FATAL;
unsigned char **ptr = NULL;
if (inlen > 255) { return(ret); }
const unsigned char *in2 = in;
unsigned int inlen2 = inlen;
while (inlen2 > 0)
{
ix++;
inlen2 -= (1 + in2[0]);
in2 += (1 + in2[0]);
}
ptr = (unsigned char**)ILibMemory_AllocateA(ix * sizeof(unsigned char*));
ix = 0;
ILibDuktape_net_server *server = (ILibDuktape_net_server*)arg;
duk_push_heapptr(server->ctx, server->self); // [server]
duk_push_array(server->ctx); // [server][array]
while (inlen > 0)
{
ptr[ix++] = (unsigned char*)in;
duk_push_lstring(server->ctx, (const char*)in + 1, (duk_size_t)in[0]); // [server][array][string]
duk_array_push(server->ctx, -2); // [server][array]
inlen -= (1 + in[0]);
in += (1 + in[0]);
}
duk_get_prop_string(server->ctx, -2, ILibDuktape_SERVER2OPTIONS); // [server][array][options]
duk_get_prop_string(server->ctx, -1, "alpnCallback"); // [server][array][options][callback]
if (!duk_is_null_or_undefined(server->ctx, -1))
{
duk_dup(server->ctx, -4); // [server][array][options][callback][this]
duk_dup(server->ctx, -4); // [server][array][options][callback][this][array]
if (duk_pcall_method(server->ctx, 1) == 0) // [server][array][options][ret]
{
if (!duk_is_null_or_undefined(server->ctx, -1))
{
ix = -1;
while (duk_get_length(server->ctx, -3) > 0)
{
++ix;
duk_array_shift(server->ctx, -3); // [server][array][options][ret][string]
const char *str1 = duk_get_string(server->ctx, -2);
const char *str2 = duk_get_string(server->ctx, -1);
if (strcmp(str1, str2) == 0)
{
*out = ptr[ix] + 1;
*outlen = ptr[ix][0];
ret = SSL_TLSEXT_ERR_OK;
duk_pop(server->ctx); // [server][array][options][ret]
break;
}
duk_pop(server->ctx); // [server][array][options][ret]
}
}
}
duk_pop(server->ctx); // [server][array][options]
}
else
{
duk_pop(server->ctx); // [server][array][options]
duk_get_prop_string(server->ctx, -1, "ALPNProtocols"); // [server][array][options][array]
char *a, *b;
int i, si;
int clientcount = (int)duk_get_length(server->ctx, -3);
int servercount = (int)duk_get_length(server->ctx, -1);
for (i = 0; i < clientcount; ++i)
{
a = Duktape_GetStringPropertyIndexValue(server->ctx, -3, i, "");
for (si = 0; si < servercount; ++si)
{
b = Duktape_GetStringPropertyIndexValue(server->ctx, -1, si, "");
if (strcmp(a, b) == 0)
{
*out = ptr[i] + 1;
*outlen = ptr[i][0];
ret = SSL_TLSEXT_ERR_OK;
break;
}
}
if (ret == SSL_TLSEXT_ERR_OK) { break; }
}
duk_pop(server->ctx); // [server][array][options]
}
duk_pop_3(server->ctx); // ...
return(ret);
}
duk_ret_t ILibDuktape_tls_server_addContext(duk_context *ctx)
{
duk_size_t hostLen;
char *host = (char*)duk_get_lstring(ctx, 0, &hostLen);
void *context = duk_require_heapptr(ctx, 1);
duk_push_this(ctx); // [server]
duk_get_prop_string(ctx, -1, ILibDuktape_SERVER2ContextTable); // [server][table]
duk_dup(ctx, 0); // [server][table][host]
duk_dup(ctx, 1); // [server][table][host][context]
duk_put_prop(ctx, -3); // [server][table]
if (hostLen == 1 && strncasecmp(host, "*", 1) == 0)
{
// Default CTX
SSL_CTX *ssl_ctx = ILibDuktape_TLS_SecureContext_GetCTX(ctx, context);
duk_get_prop_string(ctx, -2, ILibDuktape_SERVER2OPTIONS); // [server][table][options]
if (Duktape_GetBooleanProperty(ctx, -1, "requestCert", 0) || Duktape_GetHeapptrProperty(ctx, -1, "checkClientIdentity")!=NULL)
{
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, ILibDuktape_TLS_server_verify);
}
if (duk_has_prop_string(ctx, -1, "ALPNProtocols"))
{
duk_uarridx_t i;
duk_size_t protoLen = 0;
unsigned char *alpn = NULL;
duk_get_prop_string(ctx, -1, "ALPNProtocols"); // [server][table][options][Array]
duk_uarridx_t len = (duk_uarridx_t)duk_get_length(ctx, -1);
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -1, i); // [server][table][options][Array][string]
protoLen += (1 + (unsigned int)duk_get_length(ctx, -1));
duk_pop(ctx); // [server][table][options][Array]
}
if (protoLen > 0)
{
char *buf; duk_size_t bufLen;
alpn = (unsigned char*)Duktape_PushBuffer(ctx, protoLen); // [server][table][options][buffer]
duk_put_prop_string(ctx, -4, "_ALPN"); // [server][table][options][Array]
protoLen = 0;
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -1, i); // [server][table][options][Array][buffer]
buf = (char*)duk_get_lstring(ctx, -1, &bufLen);
alpn[protoLen] = (unsigned char)bufLen; ++protoLen;
memcpy_s(alpn + protoLen, ILibMemory_Size(alpn) - protoLen, buf, bufLen);
protoLen += (unsigned int)bufLen;
duk_pop(ctx); // [server][table][options][Array]
}
SSL_CTX_set_alpn_protos(ssl_ctx, alpn, (unsigned int)protoLen);
SSL_CTX_set_alpn_select_cb(ssl_ctx, ILibDuktape_tls_server_alpnSink, Duktape_GetBufferProperty(ctx, -4, ILibDuktape_net_Server_buffer));
}
duk_pop(ctx); // [server][table][options]
}
duk_get_prop_string(ctx, -3, ILibDuktape_net_Server_buffer);// [server][table][options][buffer]
ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
if (server->server != NULL)
{
#ifdef MICROSTACK_TLS_DETECT
ILibAsyncServerSocket_SetSSL_CTX(server->server, ssl_ctx, 1);
#else
ILibAsyncServerSocket_SetSSL_CTX(server->server, ssl_ctx);
#endif
ILibAsyncServerSocket_SSL_SetSink(server->server, ILibDuktape_tls_server_OnSSL);
}
SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ILibDuktape_tls_server_sniCallback);
}
return(0);
}
void ILibDuktape_TLS_connect_resolveError(duk_context *ctx, void ** args, int argsLen)
{
ILibDuktape_net_socket *data = (ILibDuktape_net_socket*)args[0];
ILibDuktape_EventEmitter_SetupEmit(ctx, data->emitter->object, "error"); // [emit][this][error]
duk_push_heapptr(ctx, args[1]); // [emit][this][error][err]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "tls.socket.OnError(): "); }
duk_pop(ctx);
}
#ifdef _SSL_KEYS_EXPORTABLE
duk_ret_t ILibDuktape_TLS_exportKeys(duk_context *ctx)
{
char buffer[2000];
int bufferLen;
ILibDuktape_net_socket *data;
duk_push_this(ctx); // [socket]
data = (ILibDuktape_net_socket*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_net_socket_ptr);
if (data != NULL)
{
bufferLen = util_exportkeys(data->ssl, buffer, sizeof(buffer));
duk_push_lstring(ctx, buffer, bufferLen);
return(1);
}
return(ILibDuktape_Error(ctx, "Error exporting OpenSSL Keys"));
}
#endif
duk_ret_t ILibDuktape_TLS_connect(duk_context *ctx)
{
unsigned char* alpn = NULL;
unsigned int protoLen = 0;
int nargs = duk_get_top(ctx), i;
if (nargs > 0 && duk_is_number(ctx, 0))
{
// tls.connect(port[, host][, options][, callback])
// let's convert to the other overload
duk_push_this(ctx); // [TLS]
duk_get_prop_string(ctx, -1, "connect"); // [TLS][connect]
duk_swap_top(ctx, -2); // [connect][this]
for (i = 1; i < nargs; ++i)
{
if (duk_is_object(ctx, i))
{
duk_dup(ctx, i); // [connect][this][Options]
break;
}
}
if (i == nargs) { duk_push_object(ctx); } // [connect][this][Options]
duk_dup(ctx, 0); // [connect][this][Options][port]
duk_put_prop_string(ctx, -2, "port");
if (nargs > 1 && duk_is_string(ctx, 1))
{
duk_dup(ctx, 1); // [connect][this][Options][host]
}
else
{
duk_push_string(ctx, "127.0.0.1"); // [connect][this][Options][host]
}
duk_put_prop_string(ctx, -2, "host"); // [connect][this][Options]
for (i = 1; i < nargs; ++i)
{
if (duk_is_function(ctx, i))
{
duk_dup(ctx, i); // [connect][this][Options][callback]
break;
}
}
duk_call_method(ctx, i == nargs ? 1 : 2); // [socket]
return(1);
}
// tls.connect(options[, callback])
ILibAsyncSocket_SocketModule module = ILibCreateAsyncSocketModuleWithMemory(Duktape_GetChain(ctx), 4096, ILibDuktape_net_socket_OnData, ILibDuktape_net_socket_OnConnect, ILibDuktape_net_socket_OnDisconnect, ILibDuktape_net_socket_OnSendOK, sizeof(ILibDuktape_net_socket));
ILibDuktape_net_socket *data = (ILibDuktape_net_socket*)((ILibChain_Link*)module)->ExtraMemoryPtr;
if (ILibDuktape_TLS_ctx2socket < 0)
{
ILibDuktape_TLS_ctx2socket = SSL_get_ex_new_index(0, "ILibDuktape_TLS index", NULL, NULL, NULL);
}
ILibDuktape_net_socket_PUSH(ctx, module); // [socket]
ILibDuktape_WriteID(ctx, "tls.socket");
ILibChain_Link_SetMetadata(module, "tls.socket")
#ifdef _SSL_KEYS_EXPORTABLE
ILibDuktape_CreateInstanceMethod(ctx, "_exportKeys", ILibDuktape_TLS_exportKeys, 0);
#endif
duk_dup(ctx, 0); // [socket][options]
if (duk_has_prop_string(ctx, -1, "secureContext"))
{
duk_get_prop_string(ctx, -1, "secureContext"); // [socket][options][secureContext]
}
else
{
duk_push_this(ctx); // [socket][options][tls]
duk_get_prop_string(ctx, -1, "createSecureContext"); // [socket][options][tls][createSecureContext]
duk_swap_top(ctx, -2); // [socket][options][createSecureContext][this]
duk_dup(ctx, -3); // [socket][options][createSecureContext][this][options]
duk_call_method(ctx, 1); // [socket][options][secureContext]
}
if ((data->ssl_ctx = (SSL_CTX*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_SecureContext2SSLCTXPTR)) == NULL)
{
return(ILibDuktape_Error(ctx, "Invalid SecureContext Object"));
}
SSL_CTX_set_verify(data->ssl_ctx, SSL_VERIFY_PEER, ILibDuktape_TLS_verify); /* Ask for authentication */
if (duk_has_prop_string(ctx, 0, "ALPNProtocols"))
{
duk_uarridx_t i;
duk_get_prop_string(ctx, 0, "ALPNProtocols"); // [Array]
duk_uarridx_t len = (duk_uarridx_t)duk_get_length(ctx, -1);
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -1, i); // [socket][options][secureContext][Array][string]
protoLen += (1 + (unsigned int)duk_get_length(ctx, -1));
duk_pop(ctx); // [socket][options][secureContext][Array]
}
if (protoLen > 0)
{
char *buf; duk_size_t bufLen;
alpn = (unsigned char*)Duktape_PushBuffer(ctx, protoLen);// [socket][options][secureContext][Array][buffer]
duk_put_prop_string(ctx, -5, "_ALPN"); // [socket][options][secureContext][Array]
protoLen = 0;
for (i = 0; i < len; ++i)
{
duk_get_prop_index(ctx, -1, i); // [socket][options][secureContext][Array][buffer]
buf = (char*)duk_get_lstring(ctx, -1, &bufLen);
alpn[protoLen] = (unsigned char)bufLen; ++protoLen;
memcpy_s(alpn + protoLen, ILibMemory_Size(alpn) - protoLen, buf, bufLen);
protoLen += (unsigned int)bufLen;
duk_pop(ctx); // [socket][options][secureContext][Array]
}
SSL_CTX_set_alpn_protos(data->ssl_ctx, alpn, protoLen);
}
duk_pop(ctx); // [socket][options][secureContext]
}
duk_remove(ctx, -2); // [socket][secureContext]
duk_put_prop_string(ctx, -2, ILibDuktape_TLSSocket2SecureContext);
duk_dup(ctx, 0); // [socket][options]
duk_put_prop_string(ctx, -2, ILibDuktape_SOCKET2OPTIONS); // [socket]
ILibDuktape_EventEmitter_CreateEventEx(data->emitter, "secureConnect");
if (nargs > 0 && duk_is_function(ctx, 1))
{
ILibDuktape_EventEmitter_AddOnce(data->emitter, "secureConnect", duk_require_heapptr(ctx, 1));
}
duk_size_t hostLen;
char *host = Duktape_GetStringPropertyValueEx(ctx, 0, "host", "127.0.0.1", &hostLen);
char *sniname = Duktape_GetStringPropertyValue(ctx, 0, "servername", host);
int port = Duktape_GetIntPropertyValue(ctx, 0, "port", 0);
struct sockaddr_in6 dest;
struct sockaddr_in6 proxy;
memset(&dest, 0, sizeof(struct sockaddr_in6));
memset(&proxy, 0, sizeof(struct sockaddr_in6));
if (duk_has_prop_string(ctx, 0, "proxy"))
{
duk_get_prop_string(ctx, 0, "proxy");
ILibResolveEx(Duktape_GetStringPropertyValue(ctx, -1, "host", NULL), (unsigned short)Duktape_GetIntPropertyValue(ctx, -1, "port", 0), &proxy);
duk_pop(ctx);
// If we are going to use a proxy, we need to have the proxy resolve the remote host
duk_push_sprintf(ctx, "%s:%d", host, port); // [socket][string]
duk_swap_top(ctx, -2); // [string][socket]
ILibAsyncSocket_ConnectToProxyEx(data->socketModule, NULL, (char*)duk_get_string(ctx, -2), (struct sockaddr*)&proxy, Duktape_GetStringPropertyValue(ctx, -1, "username", NULL), Duktape_GetStringPropertyValue(ctx, -1, "password", NULL), NULL, data);
data->ssl = ILibAsyncSocket_SetSSLContextEx(data->socketModule, data->ssl_ctx, ILibAsyncSocket_TLS_Mode_Client, sniname);
SSL_set_ex_data(data->ssl, ILibDuktape_TLS_ctx2socket, data);
return(1);
}
if (hostLen > 0 && hostLen < 1024 && host[0] == '[')
{
char hostCopy[1024];
int pct = ILibString_LastIndexOf(host, (int)hostLen, "%", 1);
memcpy_s(hostCopy, sizeof(hostCopy), host, hostLen);
hostCopy[(int)hostLen - 1] = 0;
if (pct > 0)
{
hostCopy[pct] = 0;
pct = ILib_atoi2_int32(hostCopy + pct + 1, sizeof(hostCopy));
}
else
{
pct = -1;
}
memset(&dest, 0, sizeof(struct sockaddr_in6));
dest.sin6_family = AF_INET6;
ILibInet_pton(AF_INET6, hostCopy + 1, &(dest.sin6_addr));
if (pct >= 0)
{
dest.sin6_scope_id = pct;
}
dest.sin6_port = (unsigned short)htons(port);
}
else
{
ILibResolveEx(host, (unsigned short)port, &dest);
}
if (dest.sin6_family == AF_UNSPEC || (duk_has_prop_string(ctx, 0, "proxy") && proxy.sin6_family == AF_UNSPEC))
{
// Can't resolve, check to see if it's cached
duk_push_heap_stash(ctx); // [stash]
if (duk_has_prop_string(ctx, -1, "_sharedDB"))
{
ILibSimpleDataStore db = (ILibSimpleDataStore)Duktape_GetPointerProperty(ctx, -1, "_sharedDB");
char *dnsCache = (char*)duk_push_sprintf(ctx, "DNS[%s]", host); // [stash][dnsCache]
char dnsCacheBuffer[255];
if (ILibSimpleDataStore_Get(db, dnsCache, dnsCacheBuffer, sizeof(dnsCacheBuffer)) > 0)
{
ILibResolveEx(dnsCacheBuffer, (unsigned short)port, &dest);
}
duk_pop(ctx); // [stash]
}
duk_pop(ctx); // ...
}
if (dest.sin6_family == AF_UNSPEC || (duk_has_prop_string(ctx, 0, "proxy") && proxy.sin6_family == AF_UNSPEC))
{
// Can't resolve... Delay event emit, until next event loop, because if app called net.createConnection(), they don't have the socket yet
duk_push_error_object(ctx, DUK_ERR_ERROR, "tls.socket.connect(): Cannot resolve host '%s'", host);
void *imm = ILibDuktape_Immediate(ctx, (void*[]) { data, duk_get_heapptr(ctx, -1) }, 2, ILibDuktape_TLS_connect_resolveError);
duk_push_heapptr(ctx, imm); // [socket][err][imm]
duk_swap_top(ctx, -2); // [socket][imm][err]
duk_put_prop_string(ctx, -2, "\xFF_tmp"); // [socket][imm]
duk_pop(ctx); // [socket]
}
else
{
if (duk_has_prop_string(ctx, 0, "proxy"))
{
duk_get_prop_string(ctx, 0, "proxy");
ILibAsyncSocket_ConnectToProxy(data->socketModule, NULL, (struct sockaddr*)&dest, (struct sockaddr*)&proxy, Duktape_GetStringPropertyValue(ctx, -1, "username", NULL), Duktape_GetStringPropertyValue(ctx, -1, "password", NULL), NULL, data);
duk_pop(ctx);
}
else
{
ILibAsyncSocket_ConnectTo(data->socketModule, NULL, (struct sockaddr*)&dest, NULL, data);
}
data->ssl = ILibAsyncSocket_SetSSLContextEx(data->socketModule, data->ssl_ctx, ILibAsyncSocket_TLS_Mode_Client, sniname);
SSL_set_ex_data(data->ssl, ILibDuktape_TLS_ctx2socket, data);
}
return(1);
}
duk_ret_t ILibDuktape_TLS_secureContext_Finalizer(duk_context *ctx)
{
SSL_CTX_free(ILibDuktape_TLS_SecureContext_GetCTX(ctx, duk_require_heapptr(ctx, 0)));
duk_get_prop_string(ctx, 0, ILibDuktape_SecureContext2CertBuffer);
struct util_cert *cert = (struct util_cert*)Duktape_GetBuffer(ctx, -1, NULL);
util_freecert(cert);
return(0);
}
duk_ret_t ILibDuktape_TLS_createSecureContext(duk_context *ctx)
{
duk_push_object(ctx); // [secureContext]
ILibDuktape_WriteID(ctx, "tls.secureContext");
struct util_cert *cert = (struct util_cert*)duk_push_fixed_buffer(ctx, sizeof(struct util_cert)); // [secureContext][cert]
duk_put_prop_string(ctx, -2, ILibDuktape_SecureContext2CertBuffer); // [secureContext]
memset(cert, 0, sizeof(struct util_cert));
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_TLS_secureContext_Finalizer);
duk_size_t secureProtocolLen;
char *secureProtocol = (char*)Duktape_GetStringPropertyValueEx(ctx, 0, "secureProtocol", "SSLv23_method", &secureProtocolLen);
SSL_CTX *ssl_ctx = NULL;
if (secureProtocolLen == 13 && strncmp(secureProtocol, "SSLv23_method", 13) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
}
else if (secureProtocolLen == 20 && strncmp(secureProtocol, "SSLv23_client_method", 20) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
}
else if (secureProtocolLen == 20 && strncmp(secureProtocol, "SSLv23_server_method", 20) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
}
else if (secureProtocolLen == 12 && strncmp(secureProtocol, "TLSv1_method", 12) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 19 && strncmp(secureProtocol, "TLSv1_client_method", 19) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 19 && strncmp(secureProtocol, "TLSv1_server_method", 19) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 14 && strncmp(secureProtocol, "TLSv1_1_method", 14) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_1_client_method", 21) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_1_server_method", 21) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
}
else if (secureProtocolLen == 14 && strncmp(secureProtocol, "TLSv1_2_method", 14) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
}
else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_2_client_method", 21) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
}
else if (secureProtocolLen == 21 && strncmp(secureProtocol, "TLSv1_2_server_method", 21) == 0)
{
ssl_ctx = SSL_CTX_new(TLS_method());
SSL_CTX_set_options(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
}
else if (secureProtocolLen == 11 && strncmp(secureProtocol, "DTLS_method", 11) == 0)
{
ssl_ctx = SSL_CTX_new(DTLS_method());
}
else
{
return(ILibDuktape_Error(ctx, "tls.createSecureContext(): secureProtocol[%s] not supported at this time", secureProtocol));
}
duk_push_pointer(ctx, ssl_ctx); duk_put_prop_string(ctx, -2, ILibDuktape_SecureContext2SSLCTXPTR);
if (duk_has_prop_string(ctx, 0, "pfx") && duk_has_prop_string(ctx, 0, "passphrase"))
{
duk_get_prop_string(ctx, 0, "pfx"); // [secureContext][pfx]
duk_size_t pfxLen;
char *pfx = (char*)Duktape_GetBuffer(ctx, -1, &pfxLen);
if (util_from_p12(pfx, (int)pfxLen, Duktape_GetStringPropertyValue(ctx, 0, "passphrase", ""), cert) == 0)
{
// Failed to load certificate
return(ILibDuktape_Error(ctx, "tls.createSecureContext(): Invalid passphrase"));
}
duk_pop(ctx);
SSL_CTX_use_certificate(ssl_ctx, cert->x509);
SSL_CTX_use_PrivateKey(ssl_ctx, cert->pkey);
}
return(1);
}
duk_ret_t ILibDuktape_TLS_generateCertificate(duk_context *ctx)
{
char *passphrase = (char*)duk_require_string(ctx, 0);
int len;
struct util_cert cert;
char *data;
int noUsages = 0;
int certType = CERTIFICATE_TLS_CLIENT;
if (!duk_is_null_or_undefined(ctx, 1) && duk_is_object(ctx, 1))
{
certType = Duktape_GetIntPropertyValue(ctx, 1, "certType", CERTIFICATE_TLS_CLIENT);
noUsages = Duktape_GetIntPropertyValue(ctx, 1, "noUsages", 0);
}
len = util_mkCertEx(NULL, &(cert), 3072, 10000, "localhost", certType, NULL, noUsages);
len = util_to_p12(cert, passphrase, &data);
duk_push_fixed_buffer(ctx, len);
memcpy_s((void*)Duktape_GetBuffer(ctx, -1, NULL), len, data, len);
duk_push_buffer_object(ctx, -1, 0, len, DUK_BUFOBJ_NODEJS_BUFFER);
ILibDuktape_WriteID(ctx, "tls.pfxCertificate");
util_free(data);
util_freecert(&cert);
passphrase = NULL;
return 1;
}
duk_ret_t ILibDuktape_TLS_loadpkcs7b(duk_context *ctx)
{
duk_size_t len;
char *buffer = (char*)Duktape_GetBuffer(ctx, 0, &len);
int val = util_from_pkcs7b_string(buffer, (int)len, NULL, 0);
char *out;
if (val > 0)
{
duk_push_fixed_buffer(ctx, val);
out = Duktape_GetBuffer(ctx, -1, NULL);
duk_push_buffer_object(ctx, -1, 0, val, DUK_BUFOBJ_NODEJS_BUFFER);
util_from_pkcs7b_string(buffer, (int)len, out, val);
return(1);
}
else
{
return(ILibDuktape_Error(ctx, "Error reading pkcs7b data"));
}
}
duk_ret_t ILibDuktape_TLS_loadCertificate_finalizer(duk_context *ctx)
{
struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, 0, ILibDuktape_TLS_util_cert);
util_freecert(cert);
return(0);
}
duk_ret_t ILibDuktape_TLS_loadCertificate_getKeyHash(duk_context *ctx)
{
duk_push_this(ctx);
struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_TLS_util_cert);
char *hash = duk_push_fixed_buffer(ctx, UTIL_SHA384_HASHSIZE);
duk_push_buffer_object(ctx, -1, 0, UTIL_SHA384_HASHSIZE, DUK_BUFOBJ_NODEJS_BUFFER);
util_keyhash(cert[0], hash);
return(1);
}
duk_ret_t ILibDuktape_TLS_toDER(duk_context *ctx)
{
duk_push_this(ctx);
struct util_cert *cert = (struct util_cert*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_TLS_util_cert);
int outLen = i2d_X509(cert->x509, NULL);
if (outLen <= 0)
{
return(ILibDuktape_Error(ctx, "Certificate Error"));
}
char *out = duk_push_fixed_buffer(ctx, outLen);
duk_push_buffer_object(ctx, -1, 0, outLen, DUK_BUFOBJ_NODEJS_BUFFER);
i2d_X509(cert->x509, (unsigned char**)&out);
return(1);
}
duk_ret_t ILibDuktape_TLS_loadCertificate(duk_context *ctx)
{
duk_size_t pfxLen, derLen;
char *pfx = Duktape_GetBufferPropertyEx(ctx, 0, "pfx", &pfxLen);
char *der = Duktape_GetBufferPropertyEx(ctx, 0, "der", &derLen);
if (der == NULL) { der = Duktape_GetBufferPropertyEx(ctx, 0, "cer", &derLen); }
if (pfx != NULL || der != NULL)
{
duk_push_object(ctx);
ILibDuktape_WriteID(ctx, "tls.certificate");
struct util_cert *cert = (struct util_cert*)Duktape_PushBuffer(ctx, sizeof(struct util_cert));
duk_put_prop_string(ctx, -2, ILibDuktape_TLS_util_cert);
if (pfx != NULL)
{
if (util_from_p12(pfx, (int)pfxLen, Duktape_GetStringPropertyValue(ctx, 0, "passphrase", NULL), cert) == 0)
{
// Failed to load certificate
return(ILibDuktape_Error(ctx, "tls.loadCertificate(): Invalid passphrase"));
}
}
else if (der != NULL)
{
if (util_from_cer(der, (int)derLen, cert) == 0)
{
// Failed to load certificate
return(ILibDuktape_Error(ctx, "tls.loadCertificate(): Failed to parse Certificate (%s)", ERR_reason_error_string(ERR_get_error())));
}
}
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_TLS_loadCertificate_finalizer);
ILibDuktape_CreateInstanceMethod(ctx, "getKeyHash", ILibDuktape_TLS_loadCertificate_getKeyHash, 0);
ILibDuktape_CreateInstanceMethod(ctx, "toDER", ILibDuktape_TLS_toDER, 0);
return(1);
}
else
{
return(ILibDuktape_Error(ctx, "tls.loadCertificate(): No certificate format specified"));
}
}
void ILibDuktape_tls_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [TLS]
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "tls", 1, "createServer", ILibDuktape_net_createServer, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "connect", ILibDuktape_TLS_connect, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "createSecureContext", ILibDuktape_TLS_createSecureContext, 1);
ILibDuktape_CreateInstanceMethod(ctx, "generateCertificate", ILibDuktape_TLS_generateCertificate, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "loadCertificate", ILibDuktape_TLS_loadCertificate, 1);
ILibDuktape_CreateInstanceMethod(ctx, "loadpkcs7b", ILibDuktape_TLS_loadpkcs7b, 1);
char generateRandomInteger[] = "exports.generateRandomInteger = function generateRandomInteger(low, high)\
{\
return(require('bignum').randomRange(require('bignum')(low), require('bignum')(high)).toString());\
};";
ILibDuktape_ModSearch_AddHandler_AlsoIncludeJS(ctx, generateRandomInteger, sizeof(generateRandomInteger) - 1);
}
#endif
duk_ret_t ILibDuktape_ipaddress_address4_mask(duk_context *ctx)
{
duk_push_this(ctx);
struct sockaddr_in6* addr = (struct sockaddr_in6*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_IPAddress_SockAddr);
int mask = duk_require_int(ctx, 0);
mask = 0xFFFFFFFF >> (32 - mask);
((struct sockaddr_in*)addr)->sin_addr.s_addr &= mask;
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)addr));
return(1);
}
duk_ret_t ILibDuktape_ipaddress_toString(duk_context *ctx)
{
duk_push_this(ctx);
struct sockaddr_in6* addr = (struct sockaddr_in6*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_IPAddress_SockAddr);
duk_push_string(ctx, (char*)ILibRemoteLogging_ConvertAddress((struct sockaddr*)addr));
return(1);
}
void ILibDuktape_ipaddress_PUSH(duk_context *ctx, struct sockaddr_in6* addr)
{
duk_push_object(ctx); // [Address4/6]
switch (addr->sin6_family)
{
case AF_INET:
ILibDuktape_WriteID(ctx, "ip-address.Address4");
ILibDuktape_CreateInstanceMethod(ctx, "mask", ILibDuktape_ipaddress_address4_mask, 1);
break;
case AF_INET6:
ILibDuktape_WriteID(ctx, "ip-address.Address6");
break;
default:
ILibDuktape_Error(ctx, "Unknown Address Family");
break;
}
ILibDuktape_CreateInstanceMethod(ctx, "toString", ILibDuktape_ipaddress_toString, 1);
struct sockaddr_in6* _addr = (struct sockaddr_in6*)Duktape_PushBuffer(ctx, sizeof(struct sockaddr_in6));// [Address4][addr]
duk_put_prop_string(ctx, -2, ILibDuktape_IPAddress_SockAddr); // [Address4]
memcpy_s(_addr, sizeof(struct sockaddr_in6), addr, sizeof(struct sockaddr_in6));
}
duk_ret_t ILibDuktape_ipaddress_address4_constructor(duk_context *ctx)
{
if (!duk_is_constructor_call(ctx)) { return(ILibDuktape_Error(ctx, "Invalid call")); }
ILibDuktape_ipaddress_PUSH(ctx, Duktape_IPAddress4_FromString((char*)duk_require_string(ctx, 0), 0));
return(1);
}
duk_ret_t ILibDuktape_ipaddress_address4_fromInteger(duk_context *ctx)
{
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
((struct sockaddr_in*)&addr)->sin_addr.s_addr = htonl(duk_require_int(ctx, 0));
((struct sockaddr_in*)&addr)->sin_family = AF_INET;
ILibDuktape_ipaddress_PUSH(ctx, &addr);
return(1);
}
duk_ret_t ILibDuktape_ipaddress_address4_fromString(duk_context *ctx)
{
ILibDuktape_ipaddress_PUSH(ctx, Duktape_IPAddress4_FromString((char*)duk_require_string(ctx, 0), 0));
return(1);
}
void ILibDuktape_ipaddress(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [ip-address]
ILibDuktape_WriteID(ctx, "ip-address");
duk_push_c_function(ctx, ILibDuktape_ipaddress_address4_constructor, 1); // [ip-address][Address4]
ILibDuktape_CreateInstanceMethod(ctx, "fromInteger", ILibDuktape_ipaddress_address4_fromInteger, 1); // [ip-address][Address4]
ILibDuktape_CreateInstanceMethod(ctx, "fromString", ILibDuktape_ipaddress_address4_fromString, 1); // [ip-address][Address4]
duk_put_prop_string(ctx, -2, "Address4"); // [ip-address]
}
void ILibDuktape_net_init(duk_context * ctx, void * chain)
{
ILibDuktape_ModSearch_AddHandler(ctx, "net", ILibDuktape_net_PUSH_net);
ILibDuktape_ModSearch_AddHandler(ctx, "global-tunnel", ILibDuktape_globalTunnel_PUSH);
ILibDuktape_ModSearch_AddHandler(ctx, "ip-address", ILibDuktape_ipaddress);
#ifndef MICROSTACK_NOTLS
ILibDuktape_ModSearch_AddHandler(ctx, "tls", ILibDuktape_tls_PUSH);
#endif
}
#ifdef __DOXY__
/*!
\implements DuplexStream
\brief TCP socket abstraction
*/
class Socket
{
public:
/*!
\brief If true, 'connect' was called and hasn't finished yet. Will be set to 'false' before 'connect' event is emitted.
*/
bool connecting;
/*!
\brief The string representation of the local IP address the remote client is connecting on.
*/
String localAddress;
/*!
\brief The numeric representation of the local port
*/
integer localPort;
/*!
\brief The string representation of the remote IP address.
*/
String remoteAddress;
/*!
\brief The amount of bytes sent.
*/
integer bytesWritten;
/*!
\brief Event emitted if the socket times out from inactivity. This is only to notify that the socket has been idle. The user must manually close the connection.
*/
void timeout;
/*!
\brief The 'close' event is emitted when the stream and any of its underlying resources have been closed.
*
The event indicates that no more events will be emitted, and no further computation will occur.
*/
void close;
/*!
\brief Event emitted when a socket connection is successfully established
*/
void connect;
/*!
\brief The 'error' event is emitted if an error occurred while writing or piping data.
\param arg Error argument describing the error that occured
*/
void error;
/*!
\brief Initiate a connection on a given socket
*
\par Possible signatures:\n
Socket connect(options[, connectListener]);\n
Socket connect(port[, host][, connectListener]);\n
\param options <Object> with the following fields:\n
<b>port</b> <number> Required. Port the socket should connect to.\n
<b>host</b> \<String\> Host the socket should connect to. Defaults to 'localhost'.\n
<b>localAddress</b> \<String\> Local address the socket should connect from.\n
<b>localPort</b> <number> Local port the socket should connect from.\n
<b>family</b> <number>: Version of IP stack, can be either 4 or 6. Defaults to 4.\n
\param connectListener <func> that will be added as one time listener for 'connect' event.
*/
Socket connect();
/*!
\brief Returns the bound address, the address family name, and port of the socket as reported by the OS (ie: {port: 12345, family: 'IPv4', address: '127.0.0.1'})
*/
Object address();
/*!
\brief Sets the socket to timeout after timeout milliseconds of inactivity on the socket. By default Socket do not have a timeout.
*
When an idle timeout is triggered the socket will receive a 'timeout' event but the connection <b>will not</b> be severed.
\param milliseconds <integer> Number of milliseconds to set the idle timeout to
\param timeout <func> Optional callback will be set as one time listener for to the 'timeout' event.
*/
void setTimeout(milliseconds[, timeout]);
};
#endif