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

1160 lines
44 KiB
C

/*
Copyright 2006 - 2017 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 "microstack/ILibAsyncSocket.h"
#include "microstack/ILibCrypto.h"
#include "microstack/ILibAsyncServerSocket.h"
typedef struct ILibDuktape_net_socket
{
duk_context *ctx;
ILibAsyncSocket_SocketModule socketModule;
void *object;
void *net;
void *duplexStream;
void *chain;
void *OnConnect;
void *OnClose;
void *OnError;
void *OnTimeout;
void *OnSetTimeout;
ILibDuktape_EventEmitter *emitter;
}ILibDuktape_net_socket;
typedef struct ILibDuktape_net_server
{
duk_context *ctx;
void *self;
ILibAsyncServerSocket_ServerModule server;
ILibDuktape_EventEmitter *emitter;
void *OnClose;
void *OnConnection;
void *OnListening;
void *OnError;
}ILibDuktape_net_server;
typedef struct ILibDuktape_net_server_session
{
duk_context *ctx;
void *self;
ILibAsyncServerSocket_ConnectionToken connection;
ILibDuktape_EventEmitter *emitter;
ILibDuktape_DuplexStream *stream;
void *OnTimeout;
}ILibDuktape_net_server_session;
#define ILibDuktape_GlobalTunnel_DataPtr "\xFF_GlobalTunnel_DataPtr"
#define ILibDuktape_GlobalTunnel_Stash "global-tunnel"
#define ILibDuktape_net_Server_buffer "\xFF_FixedBuffer"
#define ILibDuktape_net_Server_Session_buffer "\xFF_SessionFixedBuffer"
#define ILibDuktape_net_socket_ptr "\xFF_SocketPtr"
extern void ILibAsyncServerSocket_RemoveFromChain(ILibAsyncServerSocket_ServerModule serverModule);
// Prototypes
void ILibDuktape_net_socket_PUSH(duk_context *ctx, ILibAsyncSocket_SocketModule module);
#ifndef MICROSTACK_NOTLS
extern void ILibDuktape_X509_PUSH(duk_context *ctx, X509* cert);
#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; }
else { *p_beginPointer = endPointer; }
}
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;
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]
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]
duk_pop(ptrs->ctx); // ...
if (ptrs->OnConnect != NULL)
{
duk_push_heapptr(ptrs->ctx, ptrs->OnConnect); // [func]
ILibDuktape_net_socket_PUSH(ptrs->ctx, socketModule); // [func][this]
if (duk_pcall_method(ptrs->ctx, 0) != 0) // [retVal]
{
ILibDuktape_Process_UncaughtException(ptrs->ctx);
}
duk_pop(ptrs->ctx); // ...
}
}
else if(ptrs->OnError != NULL)
{
duk_push_heapptr(ptrs->ctx, ptrs->OnError); // [func]
ILibDuktape_net_socket_PUSH(ptrs->ctx, socketModule); // [func][this]
duk_push_object(ptrs->ctx); // [func][this][error]
duk_push_string(ptrs->ctx, "Connection Failed"); // [func][this][error][msg]
duk_put_prop_string(ptrs->ctx, -2, "message"); // [func][this][error]
if (duk_pcall_method(ptrs->ctx, 1) != 0) // [retVal]
{
ILibDuktape_Process_UncaughtException(ptrs->ctx);
}
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;
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;
return((ILibTransport_DoneState)ILibAsyncSocket_Send(ptrs->socketModule, buffer, bufferLen, ILibAsyncSocket_MemoryOwnership_USER));
}
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(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
int port = 0;
char *host = "127.0.0.1";
ILibDuktape_net_socket *ptrs;
struct sockaddr_in6 dest;
if (nargs == 0) { duk_push_string(ctx, "Too Few Arguments"); duk_throw(ctx); return(DUK_RET_ERROR); }
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);
if (nargs >= 2 && duk_is_function(ctx, 1))
{
ILibDuktape_EventEmitter_AddOn(ptrs->emitter, "connect", duk_require_heapptr(ctx, 1));
}
}
if (duk_is_string(ctx, 0))
{
// This is a PATH string
}
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));
}
}
ILibResolveEx(host, (unsigned short)port, &dest);
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;
if (ptrs->OnTimeout != NULL)
{
duk_push_heapptr(ptrs->ctx, ptrs->OnTimeout); // [func]
duk_push_heapptr(ptrs->ctx, ptrs->object); // [func][this]
if (duk_pcall_method(ptrs->ctx, 0) != 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 (timeout < 1000) { return(ILibDuktape_Error(ctx, "net.socket.setTimeout(): Error, timeout must be > 1000ms. Timeout was %d ms", timeout)); }
if (nargs > 1 && duk_is_function(ctx, 1))
{
ILibDuktape_EventEmitter_AddOnce(ptrs->emitter, "timeout", duk_require_heapptr(ctx, 1));
}
ILibAsyncSocket_SetTimeout(ptrs->socketModule, timeout / 1000, ILibDuktape_net_socket_timeoutSink);
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);
}
return 0;
}
void ILibDuktape_net_socket_PUSH(duk_context *ctx, ILibAsyncSocket_SocketModule module)
{
ILibDuktape_net_socket *ptrs = (ILibDuktape_net_socket*)((ILibChain_Link*)module)->ExtraMemoryPtr;
if (ptrs->object != NULL)
{
duk_push_heapptr(ctx, ptrs->object);
return;
}
duk_push_object(ctx); // [obj]
ptrs->ctx = ctx;
ptrs->chain = ((ILibChain_Link*)module)->ParentChain;
ptrs->object = duk_get_heapptr(ctx, -1);
ptrs->socketModule = module;
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_Init(ctx, ILibDuktape_net_socket_WriteHandler, ILibDuktape_net_socket_EndHandler, ILibDuktape_net_socket_PauseHandler, ILibDuktape_net_socket_ResumeHandler, ptrs);
ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "close", &(ptrs->OnClose));
ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "connect", &(ptrs->OnConnect));
ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "error", &(ptrs->OnError));
ILibDuktape_EventEmitter_CreateEvent(ptrs->emitter, "timeout", &(ptrs->OnTimeout));
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)) { duk_push_string(ctx, "Invalid Call"); duk_throw(ctx); return(DUK_RET_ERROR); }
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;
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;
duk_push_pointer(ctx, ptrs); // [net][ptrs]
duk_put_prop_string(ctx, -2, ILibDuktape_net_socket_ptr); // [net]
ILibDuktape_net_socket_PUSH(ctx, sm);
ILibDuktape_net_socket_connect(ctx);
duk_push_this(ctx);
duk_del_prop_string(ctx, -1, ILibDuktape_net_socket_ptr);
duk_push_heapptr(ctx, ptrs->object);
return 1;
}
#ifndef MICROSTACK_NOTLS
typedef struct ILibDuktape_net_sslStream_ptr
{
duk_context *ctx;
SSL_CTX *sslctx;
SSL* ssl;
void *sslStream_object;
void *sslStream_en_object;
void *OnVerify;
void *OnConnected;
int handshake;
int rejectUnauthorized;
ILibDuktape_DuplexStream *ds_clear;
ILibDuktape_DuplexStream *ds_encrypted;
int encrypted_processingLoop;
int decrypted_processingLoop;
char encryptedBuffer[4096];
char decryptedBuffer[4096];
}ILibDuktape_net_sslStream_ptr;
#define ILibDuktape_net_sslStream_key "\xFF_sslStreamPtr"
int ILibDuktape_net_sslStream_sslIndex = -1;
void ILibDuktape_net_sslStream_encryptedReadLoop(ILibDuktape_net_sslStream_ptr *ptrs)
{
int j;
if (ptrs->encrypted_processingLoop == 0)
{
ptrs->encrypted_processingLoop = 1;
while (ptrs->ds_encrypted->readableStream->paused == 0 && BIO_ctrl_pending(SSL_get_wbio(ptrs->ssl)) > 0)
{
// Data is pending in the write buffer, send it out
j = BIO_read(SSL_get_wbio(ptrs->ssl), ptrs->encryptedBuffer, sizeof(ptrs->encryptedBuffer));
ILibDuktape_DuplexStream_WriteData(ptrs->ds_encrypted, ptrs->encryptedBuffer, j);
}
ptrs->encrypted_processingLoop = 0;
}
}
int ILibDuktape_net_sslStream_decryptedReadLoop(ILibDuktape_net_sslStream_ptr *ptrs)
{
int retVal = 0;
int i = -1;
if (ptrs->decrypted_processingLoop == 0)
{
ptrs->decrypted_processingLoop = 1;
while (ptrs->ds_clear->readableStream->paused == 0 && (i = SSL_read(ptrs->ssl, ptrs->decryptedBuffer, sizeof(ptrs->decryptedBuffer)))>0)
{
// We got new TLS/DTLS data
ILibDuktape_DuplexStream_WriteData(ptrs->ds_clear, ptrs->decryptedBuffer, i);
}
if (i == 0)
{
// Session Closed
retVal = 1;
}
ptrs->decrypted_processingLoop = 0; // Compiler Warning is wrong here... This is to prevent re-entrancy problems, because DuplexStream_WriteData() can end up calling back in
}
return retVal;
}
ILibTransport_DoneState ILibDuktape_net_sslStream_writeSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
SSL_write(ptrs->ssl, buffer, bufferLen);
ILibDuktape_net_sslStream_encryptedReadLoop(ptrs);
return(ptrs->ds_encrypted->readableStream->paused == 0 ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE);
}
ILibTransport_DoneState ILibDuktape_net_sslStream_en_writeSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
int err;
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
ILibTransport_DoneState retVal = ILibTransport_DoneState_ERROR;
BIO_write(SSL_get_rbio(ptrs->ssl), buffer, bufferLen);
if (ptrs->handshake == 0)
{
switch (SSL_do_handshake(ptrs->ssl))
{
case 0:
// Handshake Failed!
while ((err = ERR_get_error()) != 0)
{
ERR_error_string_n(err, ILibScratchPad, sizeof(ILibScratchPad));
}
// TODO: We should probably do something
break;
case 1:
ptrs->handshake = 1;
retVal = ILibTransport_DoneState_COMPLETE;
if (ptrs->OnConnected != NULL)
{
duk_push_heapptr(ptrs->ctx, ptrs->OnConnected); // [func]
duk_push_heapptr(ptrs->ctx, ptrs->sslStream_object); // [func][this]
if (duk_pcall_method(ptrs->ctx, 0) != 0) { ILibDuktape_Process_UncaughtException(ptrs->ctx); }
duk_pop(ptrs->ctx); // ...
}
break;
default:
// SSL_WANT_READ most likely, so do nothing for now
retVal = ILibTransport_DoneState_COMPLETE;
break;
}
}
else
{
retVal = ILibDuktape_net_sslStream_decryptedReadLoop(ptrs) != 0 ? ILibTransport_DoneState_ERROR : (ptrs->ds_clear->readableStream->paused == 0 ? ILibTransport_DoneState_COMPLETE : ILibTransport_DoneState_INCOMPLETE);
}
ILibDuktape_net_sslStream_encryptedReadLoop(ptrs);
return retVal;
}
void ILibDuktape_net_sslStream_endSink(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
ILibDuktape_DuplexStream_WriteEnd(ptrs->ds_encrypted);
}
void ILibDuktape_net_sslStream_en_endSink(ILibDuktape_DuplexStream *stream, void *user)
{
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
ILibDuktape_DuplexStream_WriteEnd(ptrs->ds_clear);
}
void ILibDutkape_net_sslStream_pauseSink(ILibDuktape_DuplexStream *sender, void *user)
{
}
void ILibDuktape_net_sslStream_en_pauseSink(ILibDuktape_DuplexStream *sender, void *user)
{
}
void ILibDuktape_net_sslStream_resumeSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
if (ILibDuktape_net_sslStream_decryptedReadLoop(ptrs) == 0)
{
if (ptrs->ds_clear->readableStream->paused == 0) { ILibDuktape_DuplexStream_Ready(ptrs->ds_encrypted); }
}
else
{
// TLS Session was closed
}
}
void ILibDuktape_net_sslStream_en_resumeSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)user;
ILibDuktape_net_sslStream_encryptedReadLoop(ptrs);
if (ptrs->ds_encrypted->readableStream->paused == 0) { ILibDuktape_DuplexStream_Ready(ptrs->ds_clear); }
}
int ILibDuktape_net_sslStream_verifyServer(int preverify_ok, X509_STORE_CTX *ctx)
{
STACK_OF(X509) *certChain = X509_STORE_CTX_get_chain(ctx);
SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
ILibDuktape_net_sslStream_ptr *ptrs = (ILibDuktape_net_sslStream_ptr*)SSL_get_ex_data(ssl, ILibDuktape_net_sslStream_sslIndex);
int i;
int retVal = 0;
if (ptrs->rejectUnauthorized != 0) { return(preverify_ok); }
else { retVal = 0; }
if (ptrs->OnVerify == NULL) { return 1; }
duk_push_heapptr(ptrs->ctx, ptrs->OnVerify); // [func]
duk_push_heapptr(ptrs->ctx, ptrs->sslStream_object); // [func][this]
duk_push_array(ptrs->ctx); // [func][this][certs]
for (i = 0; i < sk_X509_num(certChain); ++i)
{
ILibDuktape_X509_PUSH(ptrs->ctx, sk_X509_value(certChain, i)); // [func][this][certs][cert]
duk_put_prop_index(ptrs->ctx, -2, i); // [func][this][certs]
}
if (duk_pcall_method(ptrs->ctx, 1) != 0) { retVal = 0; } else { retVal = 1; }
return retVal;
}
duk_ret_t ILibDuktape_net_sslStream_Finalizer(duk_context *ctx)
{
ILibDuktape_net_sslStream_ptr *ptrs;
duk_get_prop_string(ctx, 0, ILibDuktape_net_sslStream_key);
ptrs = (ILibDuktape_net_sslStream_ptr*)Duktape_GetBuffer(ctx, -1, NULL);
if (ptrs->ssl != NULL) { SSL_free(ptrs->ssl); }
if (ptrs->sslctx != NULL) { SSL_CTX_free(ptrs->sslctx); }
return 0;
}
duk_ret_t ILibDuktape_net_sslStream_create(duk_context *ctx)
{
int nargs = duk_get_top(ctx);
ILibDuktape_DuplexStream *ds, *en;
ILibDuktape_net_sslStream_ptr *ptrs;
BIO *read, *write;
int status, i;
int isClient;
struct util_cert *leafCert = NULL;
struct util_cert *nonLeafCert = NULL;
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "clientMode");
isClient = duk_get_int(ctx, -1);
duk_push_object(ctx); // [sslStream]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_net_sslStream_ptr)); // [sslStream][buffer]
ptrs = (ILibDuktape_net_sslStream_ptr*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_net_sslStream_key); // [sslStream]
memset(ptrs, 0, sizeof(ILibDuktape_net_sslStream_ptr));
ILibDuktape_CreateEventWithSetter(ctx, "connected", "\xFF_connected", &(ptrs->OnConnected));
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_net_sslStream_Finalizer);
ptrs->sslStream_object = duk_get_heapptr(ctx, -1);
if (nargs > 1)
{
ptrs->rejectUnauthorized = Duktape_GetIntPropertyValue(ctx, 1, "rejectUnauthorized", 0);
if (duk_has_prop_string(ctx, 1, "verify"))
{
duk_get_prop_string(ctx, 1, "verify"); // [sslStream][OnVerify]
ptrs->OnVerify = duk_get_heapptr(ctx, -1);
duk_put_prop_string(ctx, -2, "\xFF_OnVerify"); // [sslStream]
}
if (duk_has_prop_string(ctx, 1, "MeshAgent"))
{
duk_get_prop_string(ctx, 1, "MeshAgent"); // [sslStream][MeshAgent]
if (isClient == 0)
{
duk_get_prop_string(ctx, -1, ILibDuktape_MeshAgent_Cert_Server); // [sslStream][MeshAgent][cert]
leafCert = (struct util_cert*)duk_get_pointer(ctx, -1);
duk_pop_2(ctx); // [sslStream]
}
else
{
duk_get_prop_string(ctx, -1, ILibDuktape_MeshAgent_Cert_Client); // [sslStream][MeshAgent][clientCert]
duk_get_prop_string(ctx, -2, ILibDuktape_MeshAgent_Cert_NonLeaf); // [sslStream][MeshAgent][clientCert][nonLeafCert]
leafCert = (struct util_cert*)duk_get_pointer(ctx, -2);
nonLeafCert = (struct util_cert*)duk_get_pointer(ctx, -1);
duk_pop_3(ctx); // [sslStream]
}
}
if (duk_has_prop_string(ctx, 1, "pfx") && duk_has_prop_string(ctx, 1, "passphrase"))
{
char *pfx;
duk_size_t pfxLen;
char *pwd;
duk_get_prop_string(ctx, 1, "pfx"); // [sslStream][pfx]
pfx = Duktape_GetBuffer(ctx, -1, &pfxLen);
duk_get_prop_string(ctx, 1, "passphrase"); // [sslStream][pfx][pwd]
pwd = (char*)duk_get_string(ctx, -1);
util_from_p12(pfx, (int)pfxLen, pwd, leafCert);
duk_pop_2(ctx); // [sslStream]
}
}
ds = ILibDuktape_DuplexStream_Init(ctx, ILibDuktape_net_sslStream_writeSink, ILibDuktape_net_sslStream_endSink, ILibDutkape_net_sslStream_pauseSink, ILibDuktape_net_sslStream_resumeSink, ptrs);
duk_push_object(ctx); // [sslStream][encryptedStream]
ptrs->sslStream_en_object = duk_get_heapptr(ctx, -1);
en = ILibDuktape_DuplexStream_Init(ctx, ILibDuktape_net_sslStream_en_writeSink, ILibDuktape_net_sslStream_en_endSink, ILibDuktape_net_sslStream_en_pauseSink, ILibDuktape_net_sslStream_en_resumeSink, ptrs);
duk_put_prop_string(ctx, -2, "\xFF_internalStream"); // [sslStream]
ptrs->ds_clear = ds;
ptrs->ds_encrypted = en;
ptrs->ctx = ctx;
ptrs->sslctx = isClient != 0 ? SSL_CTX_new(SSLv23_client_method()) : SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_options(ptrs->sslctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
SSL_CTX_set_verify(ptrs->sslctx, isClient != 0 ? SSL_VERIFY_PEER : SSL_VERIFY_CLIENT_ONCE, ILibDuktape_net_sslStream_verifyServer); // Ask for authentication
if (leafCert != NULL)
{
SSL_CTX_use_certificate(ptrs->sslctx, leafCert->x509);
SSL_CTX_use_PrivateKey(ptrs->sslctx, leafCert->pkey);
if (nonLeafCert != NULL)
{
SSL_CTX_add_extra_chain_cert(ptrs->sslctx, X509_dup(nonLeafCert->x509));
}
}
ptrs->ssl = SSL_new(ptrs->sslctx);
if (ILibDuktape_net_sslStream_sslIndex < 0)
{
ILibDuktape_net_sslStream_sslIndex = SSL_get_ex_new_index(0, "ILibDuktape_net_sslstream index", NULL, NULL, NULL);
}
SSL_set_ex_data(ptrs->ssl, ILibDuktape_net_sslStream_sslIndex, ptrs);
duk_dup(ctx, 0); // [input]
duk_get_prop_string(ctx, -1, "pipe"); // [input][pipe]
duk_swap_top(ctx, -2); // [pipe][input/this]
duk_push_heapptr(ctx, ptrs->sslStream_en_object); // [pipe][input/this][stream]
if (duk_pcall_method(ctx, 1) != 0)
{
duk_push_string(ctx, "sslStream: Could not pipe with input stream");
duk_throw(ctx);
return(DUK_RET_ERROR);
}
duk_pop(ctx);
duk_push_heapptr(ctx, ptrs->sslStream_en_object); // [stream]
duk_get_prop_string(ctx, -1, "pipe"); // [stream][pipe]
duk_swap_top(ctx, -2); // [pipe][stream/this]
duk_dup(ctx, 0); // [pipe][stream/this][input]
if (duk_pcall_method(ctx, 1) != 0)
{
duk_push_string(ctx, "sslSTream: Could not pipe the input stream");
duk_throw(ctx);
return(DUK_RET_ERROR);
}
duk_pop(ctx);
// Set up the memory-buffer BIOs
read = BIO_new(BIO_s_mem());
write = BIO_new(BIO_s_mem());
BIO_set_mem_eof_return(read, -1);
BIO_set_mem_eof_return(write, -1);
SSL_set_bio(ptrs->ssl, read, write);
if (isClient != 0)
{
SSL_set_connect_state(ptrs->ssl);
status = SSL_do_handshake(ptrs->ssl);
if (status <= 0) { status = SSL_get_error(ptrs->ssl, (int)status); }
if (status == SSL_ERROR_WANT_READ)
{
while (BIO_ctrl_pending(write) > 0)
{
i = BIO_read(write, ptrs->encryptedBuffer, sizeof(ptrs->encryptedBuffer));
ILibDuktape_DuplexStream_WriteData(ptrs->ds_encrypted, ptrs->encryptedBuffer, i);
}
// We're going to drop out now, becuase we need to check for received data
}
}
else
{
SSL_set_accept_state(ptrs->ssl);
}
return 1;
}
#endif
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;
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;
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;
ILibAsyncSocket_Pause(session->connection);
}
void ILibDuktape_net_server_ResumeSink(ILibDuktape_DuplexStream *sender, void *user)
{
ILibDuktape_net_server_session *session = (ILibDuktape_net_server_session*)user;
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;
}
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;
if (ptr->OnConnection != NULL)
{
duk_push_heapptr(ptr->ctx, ptr->OnConnection); // [func]
duk_push_heapptr(ptr->ctx, ptr->self); // [func][this]
duk_push_object(ptr->ctx); // [func][this][socket]
ILibDuktape_CreateFinalizer(ptr->ctx, ILibDuktape_net_server_socket_Finalizer);
duk_push_fixed_buffer(ptr->ctx, sizeof(ILibDuktape_net_server_session)); // [func][this][socket][buffer]
session = (ILibDuktape_net_server_session*)Duktape_GetBuffer(ptr->ctx, -1, NULL);
memset(session, 0, sizeof(ILibDuktape_net_server_session));
duk_put_prop_string(ptr->ctx, -2, ILibDuktape_net_Server_Session_buffer); // [func][this][socket]
*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_CreateEvent(session->emitter, "timeout", &(session->OnTimeout));
session->stream = ILibDuktape_DuplexStream_Init(ptr->ctx, ILibDuktape_net_server_WriteSink, ILibDuktape_net_server_EndSink,
ILibDuktape_net_server_PauseSink, ILibDuktape_net_server_ResumeSink, session);
if (duk_pcall_method(ptr->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ptr->ctx, "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;
ILibDuktape_DuplexStream_WriteEnd(session->stream);
}
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;
ILibDuktape_DuplexStream_WriteData(session->stream, buffer + *p_beginPointer, endPointer);
*p_beginPointer = endPointer;
}
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;
ILibDuktape_DuplexStream_Ready(session->stream);
}
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 = 80;
int backlog = 0;
struct sockaddr_in6 local;
int maxConnections = 10;
int initalBufferSize = 4096;
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 (duk_is_object(ctx, 0))
{
// Options
port = (unsigned short)Duktape_GetIntPropertyValue(ctx, 0, "port", 0);
backlog = Duktape_GetIntPropertyValue(ctx, 0, "backlog", 64);
if (nargs > 1 && duk_is_function(ctx, 1))
{
// Callback
ILibDuktape_EventEmitter_AddOn(server->emitter, "listening", duk_require_heapptr(ctx, 1));
}
}
else
{
for (i = 0; i < nargs; ++i)
{
if (duk_is_number(ctx, i))
{
if (i == 0)
{
// Port
port = (unsigned short)duk_get_int(ctx, i);
}
else
{
// Backlog
backlog = duk_get_int(ctx, i);
}
}
if (duk_is_function(ctx, i)) { ILibDuktape_EventEmitter_AddOn(server->emitter, "listening", duk_require_heapptr(ctx, i)); }
if (duk_is_string(ctx, i))
{
ILibResolveEx((char*)duk_require_string(ctx, i), port, &local);
if (local.sin6_family == AF_UNSPEC)
{
return(ILibDuktape_Error(ctx, "server.listen(): Unknown Host '%s'", duk_require_string(ctx, i)));
}
}
}
}
server->server = ILibCreateAsyncServerSocketModuleWithMemory(Duktape_GetChain(ctx), maxConnections, port, initalBufferSize, 0,
ILibDuktape_net_server_OnConnect, ILibDuktape_net_server_OnDisconnect, ILibDuktape_net_server_OnReceive,
ILibDuktape_net_server_OnInterrupt, ILibDuktape_net_server_OnSendOK, sizeof(void*), sizeof(void*));
((void**)ILibMemory_GetExtraMemory(server->server, ILibMemory_ASYNCSERVERSOCKET_CONTAINERSIZE))[0] = server;
if (server->OnListening != NULL)
{
duk_push_heapptr(server->ctx, server->OnListening); // [func]
duk_push_heapptr(server->ctx, server->self); // [func][this]
if (duk_pcall_method(server->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(server->ctx, "net.server.listen(): Error "); }
duk_pop(server->ctx); // ...
}
#ifndef WIN32
ignore_result(backlog);
#endif
return 0;
}
duk_ret_t ILibDuktape_net_server_Finalizer(duk_context *ctx)
{
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);
}
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_object(ctx); // [server]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_net_server)); // [server][fbuffer]
server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL);
memset(server, 0, sizeof(ILibDuktape_net_server));
duk_put_prop_string(ctx, -2, ILibDuktape_net_Server_buffer); // [server]
server->self = duk_get_heapptr(ctx, -1);
server->ctx = ctx;
server->emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEvent(server->emitter, "close", &(server->OnClose));
ILibDuktape_EventEmitter_CreateEvent(server->emitter, "connection", &(server->OnConnection));
ILibDuktape_EventEmitter_CreateEvent(server->emitter, "error", &(server->OnError));
ILibDuktape_EventEmitter_CreateEvent(server->emitter, "listening", &(server->OnListening));
ILibDuktape_CreateInstanceMethod(ctx, "listen", ILibDuktape_net_server_listen, DUK_VARARGS);
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, "connection", duk_require_heapptr(ctx, i));
}
if (duk_is_object(ctx, i))
{
// Options
}
}
return 1;
}
void ILibDuktape_net_PUSH_net(duk_context *ctx, void *chain)
{
duk_push_object(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_CreateInstanceMethod(ctx, "createServer", ILibDuktape_net_createServer, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "createConnection", ILibDuktape_net_createConnection, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(ctx, "connect", ILibDuktape_net_createConnection, DUK_VARARGS);
#ifndef MICROSTACK_NOTLS
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "clientMode", 1, "createClientSslStream", ILibDuktape_net_sslStream_create, DUK_VARARGS);
ILibDuktape_CreateInstanceMethodWithIntProperty(ctx, "clientMode", 0, "createServerSslStream", ILibDuktape_net_sslStream_create, DUK_VARARGS);
#endif
}
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;
}
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_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);
duk_pop_2(ctx); // [stash]
}
duk_pop(ctx); // ...
return retVal;
}
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);
}
#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