1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2026-01-09 12:03:41 +00:00

First commit of MeshAgent for MeshCentral

This commit is contained in:
Ylian Saint-Hilaire
2017-10-12 14:28:03 -07:00
commit 75d86eb4c8
349 changed files with 210459 additions and 0 deletions

View File

@@ -0,0 +1,723 @@
/*
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.
*/
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#if defined(WINSOCK2)
#include <winsock2.h>
#include <ws2tcpip.h>
#elif defined(WINSOCK1)
#include <winsock.h>
#include <wininet.h>
#endif
#include "ILibParsers.h"
#include "ILibAsyncServerSocket.h"
#include "ILibAsyncSocket.h"
#define DEBUGSTATEMENT(x)
#define INET_SOCKADDR_LENGTH(x) ((x==AF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
typedef struct ILibAsyncServerSocketModule
{
ILibChain_Link ChainLink;
int MaxConnection;
void **AsyncSockets;
ILibServerScope scope;
SOCKET ListenSocket;
unsigned short portNumber, initialPortNumber;
int listening;
int loopbackFlag;
ILibAsyncServerSocket_OnReceive OnReceive;
ILibAsyncServerSocket_OnConnect OnConnect;
ILibAsyncServerSocket_OnDisconnect OnDisconnect;
ILibAsyncServerSocket_OnInterrupt OnInterrupt;
ILibAsyncServerSocket_OnSendOK OnSendOK;
void *Tag;
int Tag2;
#ifndef MICROSTACK_NOTLS
ILibAsyncServerSocket_OnSSL OnSSLContext;
SSL_CTX *ssl_ctx;
#ifdef MICROSTACK_TLS_DETECT
int TLSDetectEnabled;
#endif
#endif
}ILibAsyncServerSocketModule;
struct ILibAsyncServerSocket_Data
{
struct ILibAsyncServerSocketModule *module;
ILibAsyncServerSocket_BufferReAllocated Callback;
void *user;
};
const int ILibMemory_ASYNCSERVERSOCKET_CONTAINERSIZE = (const int)sizeof(ILibAsyncServerSocketModule);
// Prototypes
void ILibAsyncServerSocket_OnData(ILibAsyncSocket_SocketModule socketModule, char* buffer, int *p_beginPointer, int endPointer, void(**OnInterrupt)(void *AsyncSocketMoudle, void *user), void **user, int *PAUSE);
void ILibAsyncServerSocket_OnConnectSink(ILibAsyncSocket_SocketModule socketModule, int Connected, void *user);
void ILibAsyncServerSocket_OnDisconnectSink(ILibAsyncSocket_SocketModule socketModule, void *user);
void ILibAsyncServerSocket_OnSendOKSink(ILibAsyncSocket_SocketModule socketModule, void *user);
/*! \fn ILibAsyncServerSocket_GetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule)
\brief Returns the user Tag associated with the AsyncServer
\param ILibAsyncSocketModule The ILibAsyncServerSocket to query
\returns The user Tag
*/
void *ILibAsyncServerSocket_GetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule)
{
return (((struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule)->Tag);
}
/*! \fn ILibAsyncServerSocket_SetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *tag)
\brief Sets the user Tag associated with the AsyncServer
\param ILibAsyncSocketModule The ILibAsyncServerSocket to save the tag to
\param tag The value to save
*/
void ILibAsyncServerSocket_SetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *tag)
{
((struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule)->Tag = tag;
}
/*! \fn ILibAsyncServerSocket_GetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule)
\brief Returns the user Tag associated with the AsyncServer
\param ILibAsyncSocketModule The ILibAsyncServerSocket to query
\returns The user Tag
*/
int ILibAsyncServerSocket_GetTag2(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule)
{
return(((struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule)->Tag2);
}
/*! \fn ILibAsyncServerSocket_SetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *tag)
\brief Sets the user Tag associated with the AsyncServer
\param ILibAsyncSocketModule The ILibAsyncServerSocket to save the tag to
\param tag The value to save
*/
void ILibAsyncServerSocket_SetTag2(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, int tag)
{
((struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule)->Tag2 = tag;
}
//
// Internal method called by ILibAsyncSocket, to signal an interrupt condition
//
// <param name="socketModule">The ILibAsyncServerSocket that was interrupted</param>
// <param name="user">The associated user tag</param>
void ILibAsyncServerSocket_OnInterruptSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)user;
if (data == NULL) return;
if (data->module->OnInterrupt != NULL) data->module->OnInterrupt(data->module, socketModule, data->user);
free(user);
}
//
// Chain PreSelect handler
//
// <param name="socketModule"></param>
// <param name="readset"></param>
// <param name="writeset"></param>
// <param name="errorset"></param>
// <param name="blocktime"></param>
void ILibAsyncServerSocket_PreSelect(void* socketModule, fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime)
{
struct ILibAsyncServerSocketModule *module = (struct ILibAsyncServerSocketModule*)socketModule;
int flags,i;
UNREFERENCED_PARAMETER( writeset );
UNREFERENCED_PARAMETER( errorset );
UNREFERENCED_PARAMETER( blocktime );
//
// The socket isn't put in listening mode, until the chain is started.
// If this variable == 0, that means we need to do that.
//
if (module->listening == 0)
{
//
// Set the socket to non-block mode, so we can play nice and share the thread
//
#ifdef _WIN32_WCE
flags = 1;
ioctlsocket(module->ListenSocket, FIONBIO, &flags);
#elif WIN32
flags = 1;
ioctlsocket(module->ListenSocket, FIONBIO, (u_long *)(&flags));
#elif _POSIX
flags = fcntl(module->ListenSocket, F_GETFL,0);
fcntl(module->ListenSocket, F_SETFL, O_NONBLOCK | flags);
#endif
//
// Put the socket in Listen, and add it to the fdset for the Select loop
//
module->listening = 1;
listen(module->ListenSocket, 4);
#if defined(WIN32)
#pragma warning( push, 3 ) // warning C4127: conditional expression is constant
#endif
FD_SET(module->ListenSocket, readset);
#if defined(WIN32)
#pragma warning( pop )
#endif
}
else if (module->ListenSocket != ~0)
{
// Only put the ListenSocket in the readset, if we are able to handle a new socket
for(i = 0; i < module->MaxConnection; ++i)
{
if (ILibAsyncSocket_IsFree(module->AsyncSockets[i]) != 0)
{
#if defined(WIN32)
#pragma warning( push, 3 ) // warning C4127: conditional expression is constant
#endif
FD_SET(module->ListenSocket, readset);
#if defined(WIN32)
#pragma warning( pop )
#endif
break;
}
}
}
}
/*! \fn ILibAsyncServerSocket_SetReAllocateNotificationCallback(ILibAsyncServerSocket_ServerModule AsyncServerSocketToken, ILibAsyncServerSocket_ConnectionToken ConnectionToken, ILibAsyncServerSocket_BufferReAllocated Callback)
\brief Set the callback handler for when the internal data buffer has been resized
\param AsyncServerSocketToken The ILibAsyncServerSocket to query
\param ConnectionToken The specific connection to set the callback with
\param Callback The callback handler to set
*/
void ILibAsyncServerSocket_SetReAllocateNotificationCallback(ILibAsyncServerSocket_ServerModule AsyncServerSocketToken, ILibAsyncServerSocket_ConnectionToken ConnectionToken, ILibAsyncServerSocket_BufferReAllocated Callback)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)ILibAsyncSocket_GetUser(ConnectionToken);
UNREFERENCED_PARAMETER( AsyncServerSocketToken );
if (data != NULL) data->Callback = Callback;
}
//
// Chain PostSelect handler
//
// <param name="socketModule"></param>
// <param name="slct"></param>
// <param name="readset"></param>
// <param name="writeset"></param>
// <param name="errorset"></param>
void ILibAsyncServerSocket_PostSelect(void* socketModule, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset)
{
struct ILibAsyncServerSocket_Data *data;
struct sockaddr_in6 addr;
//struct sockaddr_in6 receivingAddress;
#ifdef _POSIX
socklen_t addrlen;
//socklen_t receivingAddressLength = sizeof(struct sockaddr_in6);
#else
int addrlen;
//int receivingAddressLength = sizeof(struct sockaddr_in6);
#endif
struct ILibAsyncServerSocketModule *module = (struct ILibAsyncServerSocketModule*)socketModule;
int i,flags;
#ifdef _WIN32_WCE
SOCKET NewSocket;
#elif WIN32
SOCKET NewSocket;
#elif defined( _POSIX)
int NewSocket;
#endif
UNREFERENCED_PARAMETER( slct );
UNREFERENCED_PARAMETER( writeset );
UNREFERENCED_PARAMETER( errorset );
if (FD_ISSET(module->ListenSocket, readset) != 0)
{
//
// There are pending TCP connection requests
//
for(i = 0; i < module->MaxConnection; ++i)
{
//
// Check to see if we have available resources to handle this connection request
//
if (ILibAsyncSocket_IsFree(module->AsyncSockets[i]) != 0)
{
addrlen = sizeof(addr);
NewSocket = accept(module->ListenSocket, (struct sockaddr*)&addr, &addrlen); // Klocwork claims we could lose the resource acquired fom the declaration, but that is not possible in this case
//printf("Accept NewSocket=%d\r\n", NewSocket);
// This code rejects connections that are from out-of-scope addresses (Outside the subnet, outside local host...)
// It needs to be updated to IPv6.
/*
if (NewSocket != ~0)
{
switch(module->scope)
{
case ILibServerScope_LocalLoopback:
// Check that the caller ip address is the same as the receive IP address
getsockname(NewSocket, (struct sockaddr*)&receivingAddress, &receivingAddressLength);
if (((struct sockaddr_in*)&receivingAddress)->sin_addr.s_addr != ((struct sockaddr_in*)&addr)->sin_addr.s_addr) // TODO: NOT IPv6 COMPILANT!!!!!!!!!!!!!!!!!!!!!!!!
{
#if defined(WIN32) || defined(_WIN32_WCE)
closesocket(NewSocket);
#else
close(NewSocket);
#endif
NewSocket = ~0;
}
break;
case ILibServerScope_LocalSegment:
getsockname(NewSocket, (struct sockaddr*)&receivingAddress, &receivingAddressLength);
break;
default:
break;
}
}
*/
if (NewSocket != ~0)
{
//printf("Accepting new connection, socket = %d\r\n", NewSocket);
//
// Set this new socket to non-blocking mode, so we can play nice and share thread
//
#ifdef _WIN32_WCE
flags = 1;
ioctlsocket(NewSocket ,FIONBIO, &flags);
#elif WIN32
flags = 1;
ioctlsocket(NewSocket, FIONBIO, (u_long *)(&flags));
#elif _POSIX
flags = fcntl(NewSocket, F_GETFL,0);
fcntl(NewSocket, F_SETFL, O_NONBLOCK|flags);
#endif
//
// Instantiate a module to contain all the data about this connection
//
if ((data = (struct ILibAsyncServerSocket_Data*)malloc(sizeof(struct ILibAsyncServerSocket_Data))) == NULL) ILIBCRITICALEXIT(254);
memset(data, 0, sizeof(struct ILibAsyncServerSocket_Data));
data->module = (struct ILibAsyncServerSocketModule*)socketModule;
ILibAsyncSocket_UseThisSocket(module->AsyncSockets[i], NewSocket, &ILibAsyncServerSocket_OnInterruptSink, data);
ILibAsyncSocket_UpdateCallbacks(module->AsyncSockets[i], ILibAsyncServerSocket_OnData, ILibAsyncServerSocket_OnConnectSink, ILibAsyncServerSocket_OnDisconnectSink, ILibAsyncServerSocket_OnSendOKSink);
ILibAsyncSocket_SetRemoteAddress(module->AsyncSockets[i], (struct sockaddr*)&addr);
#ifndef MICROSTACK_NOTLS
if (module->ssl_ctx != NULL)
{
// Accept a new TLS connection
#ifdef MICROSTACK_TLS_DETECT
SSL* ctx = ILibAsyncSocket_SetSSLContext(module->AsyncSockets[i], module->ssl_ctx, module->TLSDetectEnabled == 0 ? ILibAsyncSocket_TLS_Mode_Server : ILibAsyncSocket_TLS_Mode_Server_with_TLSDetectLogic);
#else
SSL* ctx = ILibAsyncSocket_SetSSLContext(module->AsyncSockets[i], module->ssl_ctx, ILibAsyncSocket_TLS_Mode_Server);
#endif
if (ctx != NULL && module->OnSSLContext != NULL) { module->OnSSLContext(module, module->AsyncSockets[i], ctx, &(data->user)); }
}
else
#endif
if (module->OnConnect != NULL)
{
// Notify the user about this new connection
module->OnConnect(module, module->AsyncSockets[i], &(data->user));
}
}
else {break;}
}
}
}
} // Klocwork claims that we could lose the resource acquired in the declaration, but that is not possible in this case
//
// Chain Destroy handler
//
// <param name="socketModule"></param>
void ILibAsyncServerSocket_Destroy(void *socketModule)
{
struct ILibAsyncServerSocketModule *module =(struct ILibAsyncServerSocketModule*)socketModule;
free(module->AsyncSockets);
module->AsyncSockets = NULL;
if (module->ListenSocket != (SOCKET)~0)
{
#ifdef _WIN32_WCE
closesocket(module->ListenSocket);
#elif WIN32
closesocket(module->ListenSocket);
#elif _POSIX
close(module->ListenSocket);
#endif
module->ListenSocket = (SOCKET)~0;
}
}
//
// Internal method dispatched by the OnData event of the underlying ILibAsyncSocket
//
// <param name="socketModule"></param>
// <param name="buffer"></param>
// <param name="p_beginPointer"></param>
// <param name="endPointer"></param>
// <param name="OnInterrupt"></param>
// <param name="user"></param>
// <param name="PAUSE"></param>
void ILibAsyncServerSocket_OnData(ILibAsyncSocket_SocketModule socketModule,char* buffer,int *p_beginPointer, int endPointer,void (**OnInterrupt)(void *AsyncSocketMoudle, void *user),void **user, int *PAUSE)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)(*user);
int bpointer = *p_beginPointer;
UNREFERENCED_PARAMETER( OnInterrupt );
// Pass the received data up
if (data != NULL && data->module->OnReceive != NULL)
{
data->module->OnReceive(data->module, socketModule, buffer, &bpointer, endPointer, &(data->module->OnInterrupt), &(data->user), PAUSE);
if (ILibAsyncSocket_IsFree(socketModule))
{
*p_beginPointer = endPointer;
}
else
{
*p_beginPointer = bpointer;
}
}
}
//
// Internal method dispatched by the OnConnect event of the underlying ILibAsyncSocket. In this case, it will only occur when TLS connection is established.
//
// <param name="socketModule"></param>
// <param name="user"></param>
void ILibAsyncServerSocket_OnConnectSink(ILibAsyncSocket_SocketModule socketModule, int Connected, void *user)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)user;
if (data == NULL) return;
if (Connected == 0) { free(data); data = NULL; return; } // Connection Failed, clean up
if (data->module->OnConnect != NULL) data->module->OnConnect(data->module, socketModule, &(data->user));
}
//
// Internal method dispatched by the OnDisconnect event of the underlying ILibAsyncSocket
//
// <param name="socketModule"></param>
// <param name="user"></param>
void ILibAsyncServerSocket_OnDisconnectSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)user;
// Pass this Disconnect event up
if (data == NULL) return;
if (data->module->OnDisconnect != NULL) data->module->OnDisconnect(data->module, socketModule, data->user);
// If the chain is shutting down, we need to free some resources
if (ILibIsChainBeingDestroyed(data->module->ChainLink.ParentChain) == 0) { free(data); data = NULL; }
}
//
// Internal method dispatched by the OnSendOK event of the underlying ILibAsyncSocket
//
// <param name="socketModule"></param>
// <param name="user"></param>
void ILibAsyncServerSocket_OnSendOKSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)user;
// Pass the OnSendOK event up
if (data != NULL && data->module->OnSendOK != NULL) data->module->OnSendOK(data->module, socketModule, data->user);
}
//
// Internal method dispatched by ILibAsyncSocket, to signal that the buffers have been reallocated
//
// <param name="ConnectionToken">The ILibAsyncSocket sender</param>
// <param name="user">The ILibAsyncServerSocket_Data object</param>
// <param name="offSet">The offset to the new buffer location</param>
void ILibAsyncServerSocket_OnBufferReAllocated(ILibAsyncSocket_SocketModule ConnectionToken, void *user, ptrdiff_t offSet)
{
struct ILibAsyncServerSocket_Data *data = (struct ILibAsyncServerSocket_Data*)user;
if (data!=NULL && data->Callback!=NULL)
{
//
// If someone above us, has registered for this callback, we need to fire it,
// with the correct user object
//
data->Callback(data->module,ConnectionToken,data->user,offSet);
}
}
#ifndef MICROSTACK_NOTLS
void* ILibAsyncServerSocket_GetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule)
{
return(((struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule)->ssl_ctx);
}
#ifdef MICROSTACK_TLS_DETECT
void ILibAsyncServerSocket_SetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *ssl_ctx, int enableTLSDetect)
#else
void ILibAsyncServerSocket_SetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *ssl_ctx)
#endif
{
if (ILibAsyncSocketModule != NULL && ssl_ctx != NULL)
{
struct ILibAsyncServerSocketModule *module = (struct ILibAsyncServerSocketModule*)ILibAsyncSocketModule;
module->ssl_ctx = (SSL_CTX *)ssl_ctx;
#ifdef MICROSTACK_TLS_DETECT
module->TLSDetectEnabled = enableTLSDetect;
#endif
}
}
#endif
void ILibAsyncServerSocket_ResumeListeningSink(void *chain, void* user)
{
ILibAsyncServerSocketModule *m = (ILibAsyncServerSocketModule*)user;
int ra = 1;
int off = 0;
int receivingAddressLength = sizeof(struct sockaddr_in6);
struct sockaddr_in6 localif;
struct sockaddr_in6 localAddress;
UNREFERENCED_PARAMETER(chain);
memset(&localif, 0, sizeof(struct sockaddr_in6));
if (m->loopbackFlag != 2 && ILibDetectIPv6Support())
{
// Setup the IPv6 any or loopback address, this socket will also work for IPv4 traffic on IPv6 stack
localif.sin6_family = AF_INET6;
localif.sin6_addr = (m->loopbackFlag != 0 ? in6addr_loopback : in6addr_any);
localif.sin6_port = htons(m->initialPortNumber);
}
else
{
// IPv4-only detected
localif.sin6_family = AF_INET;
#ifdef WINSOCK2
((struct sockaddr_in*)&localif)->sin_addr.S_un.S_addr = htonl((m->loopbackFlag != 0 ? INADDR_LOOPBACK : INADDR_ANY));
#else
((struct sockaddr_in*)&localif)->sin_addr.s_addr = htonl((m->loopbackFlag != 0 ? INADDR_LOOPBACK : INADDR_ANY));
#endif
((struct sockaddr_in*)&localif)->sin_port = htons(m->initialPortNumber);
}
// Get our listening socket
if ((m->ListenSocket = socket(localif.sin6_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { m->ListenSocket = (SOCKET)~0; return; }
// Setup the IPv6 & IPv4 support on same socket
if (localif.sin6_family == AF_INET6) if (setsockopt(m->ListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off)) != 0) ILIBCRITICALERREXIT(253);
#ifdef SO_NOSIGPIPE
setsockopt(m->ListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&ra, sizeof(int)); // Turn off SIGPIPE if writing to disconnected socket
#endif
#if defined(WIN32)
// On Windows. Lets make sure no one else can bind to this addr/port. This stops socket hijacking (not a problem on Linux).
if (setsockopt(m->ListenSocket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&ra, sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#else
// On Linux. Setting the re-use on a TCP socket allows reuse of the socket even in timeout state. Allows for fast stop/start (Not a problem on Windows).
if (setsockopt(m->ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&ra, sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#endif
// Bind the socket
#if defined(WIN32)
if (bind(m->ListenSocket, (struct sockaddr*)&localif, INET_SOCKADDR_LENGTH(localif.sin6_family)) != 0) { closesocket(m->ListenSocket); m->ListenSocket = (SOCKET)~0; return; }
#else
if (bind(m->ListenSocket, (struct sockaddr*)&localif, INET_SOCKADDR_LENGTH(localif.sin6_family)) != 0) { close(m->ListenSocket); m->ListenSocket = (SOCKET)~0; return; }
#endif
// Fetch the local port number
#if defined(WINSOCK2)
getsockname(m->ListenSocket, (struct sockaddr*)&localAddress, (int*)&receivingAddressLength);
#else
getsockname(m->ListenSocket, (struct sockaddr*)&localAddress, (socklen_t*)&receivingAddressLength);
#endif
if (localAddress.sin6_family == AF_INET6) m->portNumber = ntohs(localAddress.sin6_port); else m->portNumber = ntohs(((struct sockaddr_in*)&localAddress)->sin_port);
m->listening = 0;
}
void ILibAsyncServerSocket_StopListeningSink(void *chain, void* user)
{
ILibAsyncServerSocketModule *m = (ILibAsyncServerSocketModule*)user;
UNREFERENCED_PARAMETER(chain);
if (m->ListenSocket != (SOCKET)~0)
{
#ifdef WIN32
closesocket(m->ListenSocket);
#else
close(m->ListenSocket);
#endif
m->ListenSocket = (SOCKET)~0;
}
}
//! Take the server socket out of listening mode, rejecting new incoming connection requests
/*!
\param module ILibAsyncServerSocket_ServerModule Server Listening Module
*/
void ILibAsyncServerSocket_StopListening(ILibAsyncServerSocket_ServerModule module)
{
ILibAsyncServerSocketModule *m = (ILibAsyncServerSocketModule*)module;
ILibChain_RunOnMicrostackThread(m->ChainLink.ParentChain, ILibAsyncServerSocket_StopListeningSink, m);
}
//! Put the server socket back in listening mode, to allow new incoming connection requests
/*!
\param module ILibAsyncServerSocket_ServerModule Server Listening Module
*/
void ILibAsyncServerSocket_ResumeListening(ILibAsyncServerSocket_ServerModule module)
{
ILibAsyncServerSocketModule *m = (ILibAsyncServerSocketModule*)module;
ILibChain_RunOnMicrostackThread(m->ChainLink.ParentChain, ILibAsyncServerSocket_ResumeListeningSink, m);
}
void ILibAsyncServerSocket_RemoveFromChainSink(void *chain, void *user)
{
ILibAsyncServerSocketModule *module = (ILibAsyncServerSocketModule*)user;
int i;
for (i = 0; i < module->MaxConnection; ++i)
{
ILibChain_SafeRemoveEx(chain, module->AsyncSockets[i]);
}
ILibChain_SafeRemoveEx(chain, module);
}
void ILibAsyncServerSocket_RemoveFromChain(ILibAsyncServerSocket_ServerModule serverModule)
{
ILibChain_RunOnMicrostackThreadEx(((ILibAsyncServerSocketModule*)serverModule)->ChainLink.ParentChain, ILibAsyncServerSocket_RemoveFromChainSink, serverModule);
}
/*! \fn ILibCreateAsyncServerSocketModule(void *Chain, int MaxConnections, int PortNumber, int initialBufferSize, ILibAsyncServerSocket_OnConnect OnConnect,ILibAsyncServerSocket_OnDisconnect OnDisconnect,ILibAsyncServerSocket_OnReceive OnReceive,ILibAsyncServerSocket_OnInterrupt OnInterrupt, ILibAsyncServerSocket_OnSendOK OnSendOK)
\brief Instantiates a new ILibAsyncServerSocket
\param Chain The chain to add this module to. (Chain must <B>not</B> be running)
\param MaxConnections The max number of simultaneous connections that will be allowed
\param PortNumber The port number to bind to. 0 will select a random port
\param initialBufferSize The initial size of the receive buffer
\param loopbackFlag 0 to bind to ANY, 1 to bind to IPv6 loopback first, 2 to bind to IPv4 loopback first.
\param OnConnect Function Pointer that triggers when a connection is established
\param OnDisconnect Function Pointer that triggers when a connection is closed
\param OnReceive Function Pointer that triggers when data is received
\param OnInterrupt Function Pointer that triggers when connection interrupted
\param OnSendOK Function Pointer that triggers when pending sends are complete
\param ServerAutoFreeMemorySize Size of AutoFreeMemory on Server to co-allocate
\param SessionAutoFreeMemorySize Size of AutoFreeMemory on Session to co-allocate
\returns An ILibAsyncServerSocket module
*/
ILibAsyncServerSocket_ServerModule ILibCreateAsyncServerSocketModuleWithMemory(void *Chain, int MaxConnections, unsigned short PortNumber, int initialBufferSize, int loopbackFlag, ILibAsyncServerSocket_OnConnect OnConnect, ILibAsyncServerSocket_OnDisconnect OnDisconnect, ILibAsyncServerSocket_OnReceive OnReceive, ILibAsyncServerSocket_OnInterrupt OnInterrupt, ILibAsyncServerSocket_OnSendOK OnSendOK, int ServerUserMappedMemorySize, int SessionUserMappedMemorySize)
{
int i;
int ra = 1;
int off = 0;
int receivingAddressLength = sizeof(struct sockaddr_in6);
struct sockaddr_in6 localif;
struct sockaddr_in6 localAddress;
struct ILibAsyncServerSocketModule *RetVal;
memset(&localif, 0, sizeof(struct sockaddr_in6));
if (loopbackFlag != 2 && ILibDetectIPv6Support())
{
// Setup the IPv6 any or loopback address, this socket will also work for IPv4 traffic on IPv6 stack
localif.sin6_family = AF_INET6;
localif.sin6_addr = (loopbackFlag != 0?in6addr_loopback:in6addr_any);
localif.sin6_port = htons(PortNumber);
}
else
{
// IPv4-only detected
localif.sin6_family = AF_INET;
#ifdef WINSOCK2
((struct sockaddr_in*)&localif)->sin_addr.S_un.S_addr = htonl((loopbackFlag != 0?INADDR_LOOPBACK:INADDR_ANY));
#else
((struct sockaddr_in*)&localif)->sin_addr.s_addr = htonl((loopbackFlag != 0?INADDR_LOOPBACK:INADDR_ANY));
#endif
((struct sockaddr_in*)&localif)->sin_port = htons(PortNumber);
}
// Instantiate a new AsyncServer module
RetVal = (struct ILibAsyncServerSocketModule*)ILibChain_Link_Allocate(sizeof(struct ILibAsyncServerSocketModule), ServerUserMappedMemorySize);
RetVal->ChainLink.PreSelectHandler = &ILibAsyncServerSocket_PreSelect;
RetVal->ChainLink.PostSelectHandler = &ILibAsyncServerSocket_PostSelect;
RetVal->ChainLink.DestroyHandler = &ILibAsyncServerSocket_Destroy;
RetVal->ChainLink.ParentChain = Chain;
RetVal->OnConnect = OnConnect;
RetVal->OnDisconnect = OnDisconnect;
RetVal->OnInterrupt = OnInterrupt;
RetVal->OnSendOK = OnSendOK;
RetVal->OnReceive = OnReceive;
RetVal->MaxConnection = MaxConnections;
RetVal->AsyncSockets = (void**)malloc(MaxConnections * sizeof(void*));
if (RetVal->AsyncSockets == NULL) { free(RetVal); ILIBMARKPOSITION(253); return NULL; }
RetVal->portNumber = (unsigned short)PortNumber;
RetVal->loopbackFlag = loopbackFlag;
RetVal->initialPortNumber = PortNumber;
// Get our listening socket
if ((RetVal->ListenSocket = socket(localif.sin6_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { free(RetVal->AsyncSockets); free(RetVal); return 0; }
// Setup the IPv6 & IPv4 support on same socket
if (localif.sin6_family == AF_INET6) if (setsockopt(RetVal->ListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&off, sizeof(off)) != 0) ILIBCRITICALERREXIT(253);
#ifdef SO_NOSIGPIPE
setsockopt(RetVal->ListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&ra, sizeof(int)); // Turn off SIGPIPE if writing to disconnected socket
#endif
#if defined(WIN32)
// On Windows. Lets make sure no one else can bind to this addr/port. This stops socket hijacking (not a problem on Linux).
if (setsockopt(RetVal->ListenSocket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&ra, sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#else
// On Linux. Setting the re-use on a TCP socket allows reuse of the socket even in timeout state. Allows for fast stop/start (Not a problem on Windows).
if (setsockopt(RetVal->ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&ra, sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#endif
// Bind the socket
#if defined(WIN32)
if (bind(RetVal->ListenSocket, (struct sockaddr*)&localif, INET_SOCKADDR_LENGTH(localif.sin6_family)) != 0) { closesocket(RetVal->ListenSocket); free(RetVal->AsyncSockets); free(RetVal); return 0; }
#else
if (bind(RetVal->ListenSocket, (struct sockaddr*)&localif, INET_SOCKADDR_LENGTH(localif.sin6_family)) != 0) { close(RetVal->ListenSocket); free(RetVal->AsyncSockets); free(RetVal); return 0; }
#endif
// Fetch the local port number
#if defined(WINSOCK2)
getsockname(RetVal->ListenSocket, (struct sockaddr*)&localAddress, (int*)&receivingAddressLength);
#else
getsockname(RetVal->ListenSocket, (struct sockaddr*)&localAddress, (socklen_t*)&receivingAddressLength);
#endif
if (localAddress.sin6_family == AF_INET6) RetVal->portNumber = ntohs(localAddress.sin6_port); else RetVal->portNumber = ntohs(((struct sockaddr_in*)&localAddress)->sin_port);
// Create our socket pool
for(i = 0; i < MaxConnections; ++i)
{
RetVal->AsyncSockets[i] = ILibCreateAsyncSocketModuleWithMemory(Chain, initialBufferSize, &ILibAsyncServerSocket_OnData, &ILibAsyncServerSocket_OnConnectSink, &ILibAsyncServerSocket_OnDisconnectSink, &ILibAsyncServerSocket_OnSendOKSink, SessionUserMappedMemorySize);
//
// We want to know about any buffer reallocations, because anything above us may want to know
//
ILibAsyncSocket_SetReAllocateNotificationCallback(RetVal->AsyncSockets[i], &ILibAsyncServerSocket_OnBufferReAllocated);
}
ILibAddToChain(Chain, RetVal);
return RetVal;
}
/*! \fn ILibAsyncServerSocket_GetPortNumber(ILibAsyncServerSocket_ServerModule ServerSocketModule)
\brief Returns the port number the server is bound to
\param ServerSocketModule The ILibAsyncServer to query
\returns The listening port number
*/
unsigned short ILibAsyncServerSocket_GetPortNumber(ILibAsyncServerSocket_ServerModule ServerSocketModule)
{
return(((struct ILibAsyncServerSocketModule*)ServerSocketModule)->portNumber);
}
#ifndef MICROSTACK_NOTLS
void ILibAsyncServerSocket_SSL_SetSink(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_OnSSL handler)
{
((struct ILibAsyncServerSocketModule*)AsyncServerSocketModule)->OnSSLContext = handler;
}
#endif

View File

@@ -0,0 +1,177 @@
/*
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.
*/
#ifndef ___ILibAsyncServerSocket___
#define ___ILibAsyncServerSocket___
/*! \file ILibAsyncServerSocket.h
\brief MicroStack APIs for TCP Server Functionality
*/
/*! \defgroup ILibAsyncServerSocket ILibAsyncServerSocket Module
\{
*/
#if defined(WIN32) || defined(_WIN32_WCE)
#include <STDDEF.H>
#elif defined(_POSIX)
#if !defined(__APPLE__) && !defined(_VX_CPU)
#include <malloc.h>
#endif
#endif
#include "ILibAsyncSocket.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \typedef ILibAsyncServerSocket_ServerModule
\brief The handle for an ILibAsyncServerSocket module
*/
typedef void* ILibAsyncServerSocket_ServerModule;
/*! \typedef ILibAsyncServerSocket_ConnectionToken
\brief Connection state, for a connected session
*/
typedef ILibAsyncSocket_SocketModule ILibAsyncServerSocket_ConnectionToken;
/*! \typedef ILibAsyncServerSocket_BufferReAllocated
\brief BufferReAllocation Handler
\param AsyncServerSocketToken The ILibAsyncServerSocket token
\param ConnectionToken The ILibAsyncServerSocket_Connection token
\param user The User object
\param newOffset The buffer has shifted by this offset
*/
typedef void (*ILibAsyncServerSocket_BufferReAllocated)(ILibAsyncServerSocket_ServerModule AsyncServerSocketToken, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user, ptrdiff_t newOffset);
void ILibAsyncServerSocket_SetReAllocateNotificationCallback(ILibAsyncServerSocket_ServerModule AsyncServerSocketToken, ILibAsyncServerSocket_ConnectionToken ConnectionToken, ILibAsyncServerSocket_BufferReAllocated Callback);
/*! \typedef ILibAsyncServerSocket_OnInterrupt
\brief Handler for when a session was interrupted by a call to ILibStopChain
\param AsyncServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param user
*/
typedef void (*ILibAsyncServerSocket_OnInterrupt)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user);
/*! \typedef ILibAsyncServerSocket_OnReceive
\brief Handler for when data is received
\par
<B>Note on memory handling:</B>
When you process the received buffer, you must advance \a p_beginPointer the number of bytes that you
have processed. If \a p_beginPointer does not equal \a endPointer when this method completes,
the system will continue to reclaim any memory that has already been processed, and call this method again
until no more memory has been processed. If no memory has been processed, and more data has been received
on the network, the buffer will be automatically grown (according to a specific alogrythm), to accomodate any new data.
\param AsyncServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param buffer The data that was received
\param[in,out] p_beginPointer The start index of the data that was received
\param endPointer The end index of the data that was received
\param[in,out] OnInterrupt Set this pointer to receive notification if this session is interrupted
\param[in,out] user Set a custom user object
\param[out] PAUSE Flag to indicate if the system should continue reading data off the network
*/
typedef void (*ILibAsyncServerSocket_OnReceive)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncServerSocket_OnInterrupt *OnInterrupt, void **user, int *PAUSE);
/*! \typedef ILibAsyncServerSocket_OnConnect
\brief Handler for when a connection is made
\param AsyncServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param[in,out] user Set a user object to associate with this connection
*/
typedef void (*ILibAsyncServerSocket_OnConnect)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void **user);
/*! \typedef ILibAsyncServerSocket_OnDisconnect
\brief Handler for when a connection is terminated normally
\param AsyncServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param user User object that was associated with this connection
*/
typedef void (*ILibAsyncServerSocket_OnDisconnect)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user);
/*! \typedef ILibAsyncServerSocket_OnSendOK
\brief Handler for when pending send operations have completed
\par
This handler will only be called if a call to \a ILibAsyncServerSocket_Send returned a value greater
than 0, which indicates that not all of the data could be sent.
\param AsyncServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param user User object that was associated with this connection
*/
typedef void (*ILibAsyncServerSocket_OnSendOK)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_ConnectionToken ConnectionToken, void *user);
extern const int ILibMemory_ASYNCSERVERSOCKET_CONTAINERSIZE;
#define ILibCreateAsyncServerSocketModule(Chain, MaxConnections, PortNumber, initialBufferSize, loopbackFlag, OnConnect, OnDisconnect, OnReceive, OnInterrupt, OnSendOK) ILibCreateAsyncServerSocketModuleWithMemory(Chain, MaxConnections, PortNumber, initialBufferSize, loopbackFlag, OnConnect, OnDisconnect, OnReceive, OnInterrupt, OnSendOK, 0, 0)
ILibAsyncServerSocket_ServerModule ILibCreateAsyncServerSocketModuleWithMemory(void *Chain, int MaxConnections, unsigned short PortNumber, int initialBufferSize, int loopbackFlag, ILibAsyncServerSocket_OnConnect OnConnect, ILibAsyncServerSocket_OnDisconnect OnDisconnect, ILibAsyncServerSocket_OnReceive OnReceive, ILibAsyncServerSocket_OnInterrupt OnInterrupt, ILibAsyncServerSocket_OnSendOK OnSendOK, int ServerUserMappedMemorySize, int SessionUserMappedMemorySize);
void *ILibAsyncServerSocket_GetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule);
void ILibAsyncServerSocket_SetTag(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *user);
int ILibAsyncServerSocket_GetTag2(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule);
void ILibAsyncServerSocket_SetTag2(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, int user);
#ifndef MICROSTACK_NOTLS
typedef void(*ILibAsyncServerSocket_OnSSL)(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, void* ConnectionToken, SSL* ctx, void **user);
void ILibAsyncServerSocket_SSL_SetSink(ILibAsyncServerSocket_ServerModule AsyncServerSocketModule, ILibAsyncServerSocket_OnSSL handler);
void* ILibAsyncServerSocket_GetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule);
#ifdef MICROSTACK_TLS_DETECT
void ILibAsyncServerSocket_SetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *ssl_ctx, int enableTLSDetect);
#else
void ILibAsyncServerSocket_SetSSL_CTX(ILibAsyncServerSocket_ServerModule ILibAsyncSocketModule, void *ssl_ctx);
#endif
#endif
void ILibAsyncServerSocket_StopListening(ILibAsyncServerSocket_ServerModule module);
void ILibAsyncServerSocket_ResumeListening(ILibAsyncServerSocket_ServerModule module);
unsigned short ILibAsyncServerSocket_GetPortNumber(ILibAsyncServerSocket_ServerModule ServerSocketModule);
/*! \def ILibAsyncServerSocket_Send
\brief Sends data onto the TCP stream
\param ServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
\param buffer The data to be sent
\param bufferLength The length of \a buffer
\param UserFreeBuffer The \a ILibAsyncSocket_MemoryOwnership enumeration, that identifies how the memory pointer to by \a buffer is to be handled
\returns \a ILibAsyncSocket_SendStatus indicating the send status
*/
#define ILibAsyncServerSocket_Send(ServerSocketModule, ConnectionToken, buffer, bufferLength, UserFreeBuffer) ILibAsyncSocket_Send(ConnectionToken, buffer, bufferLength, UserFreeBuffer)
/*! \def ILibAsyncServerSocket_Disconnect
\brief Disconnects a TCP stream
\param ServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
*/
#define ILibAsyncServerSocket_Disconnect(ServerSocketModule, ConnectionToken) ILibAsyncSocket_Disconnect(ConnectionToken)
/*! \def ILibAsyncServerSocket_GetPendingBytesToSend
\brief Gets the outstanding number of bytes to be sent
*/
#define ILibAsyncServerSocket_GetPendingBytesToSend(ServerSocketModule, ConnectionToken) ILibAsyncSocket_GetPendingBytesToSend(ConnectionToken)
/*! \def ILibAsyncServerSocket_GetTotalBytesSent
\brief Gets the total number of bytes that have been sent
\param ServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
*/
#define ILibAsyncServerSocket_GetTotalBytesSent(ServerSocketModule, ConnectionToken) ILibAsyncSocket_GetTotalBytesSent(ConnectionToken)
/*! \def ILibAsyncServerSocket_ResetTotalBytesSent
\brief Resets the total bytes sent counter
\param ServerSocketModule The parent ILibAsyncServerSocket_ServerModule
\param ConnectionToken The connection state for this session
*/
#define ILibAsyncServerSocket_ResetTotalBytesSent(ServerSocketModule, ConnectionToken) ILibAsyncSocket_ResetTotalBytesSent(ConnectionToken)
#ifdef __cplusplus
}
#endif
#endif

2312
microstack/ILibAsyncSocket.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
/*
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.
*/
#ifndef ___ILibAsyncSocket___
#define ___ILibAsyncSocket___
/*! \file ILibAsyncSocket.h
\brief MicroStack APIs for TCP Client Functionality
*/
/*! \defgroup ILibAsyncSocket ILibAsyncSocket Module
\{
*/
#if defined(WIN32) || defined(_WIN32_WCE)
#include <STDDEF.H>
#elif defined(_POSIX)
#if !defined(__APPLE__) && !defined(_VX_CPU)
#include <malloc.h>
#endif
#endif
//#include "ssl.h"
#ifndef MICROSTACK_NOTLS
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32_WCE)
#ifndef ptrdiff_t
#define ptrdiff_t long
#endif
#endif
/*! \def MEMORYCHUNKSIZE
\brief Incrementally grow the buffer by this amount of bytes
*/
#define MEMORYCHUNKSIZE 4096
#define ILibTransports_AsyncSocket 0x40
typedef enum ILibAsyncSocket_SendStatus
{
ILibAsyncSocket_ALL_DATA_SENT = 1, /*!< All of the data has already been sent */
ILibAsyncSocket_NOT_ALL_DATA_SENT_YET = 0, /*!< Not all of the data could be sent, but is queued to be sent as soon as possible */
ILibAsyncSocket_SEND_ON_CLOSED_SOCKET_ERROR = -4 /*!< A send operation was attmepted on a closed socket */
}ILibAsyncSocket_SendStatus;
/*! \enum ILibAsyncSocket_MemoryOwnership
\brief Enumeration values for Memory Ownership of variables
*/
typedef enum ILibAsyncSocket_MemoryOwnership
{
ILibAsyncSocket_MemoryOwnership_CHAIN = 0, /*!< The Microstack will own this memory, and free it when it is done with it */
ILibAsyncSocket_MemoryOwnership_STATIC = 1, /*!< This memory is static, so the Microstack will not free it, and assume it will not go away, so it won't copy it either */
ILibAsyncSocket_MemoryOwnership_USER = 2, /*!< The Microstack doesn't own this memory, so if necessary the memory will be copied */
#ifndef MICROSTACK_NOTLS
ILibAsyncSocket_MemoryOwnership_BIO = 3
#endif
}ILibAsyncSocket_MemoryOwnership;
/*! \typedef ILibAsyncSocket_SocketModule
\brief The handle for an ILibAsyncSocket module
*/
typedef void* ILibAsyncSocket_SocketModule;
/*! \typedef ILibAsyncSocket_OnInterrupt
\brief Handler for when a session was interrupted by a call to ILibStopChain
\param socketModule The \a ILibAsyncSocket_SocketModule that was interrupted
\param user The user object that was associated with this connection
*/
//typedef void(*ILibAsyncSocket_OnReplaceSocket)(ILibAsyncSocket_SocketModule socketModule, void *user);
typedef void(*ILibAsyncSocket_OnBufferSizeExceeded)(ILibAsyncSocket_SocketModule socketModule, void *user);
typedef void(*ILibAsyncSocket_OnInterrupt)(ILibAsyncSocket_SocketModule socketModule, void *user);
/*! \typedef ILibAsyncSocket_OnData
\brief Handler for when data is received
\par
<B>Note on memory handling:</B>
When you process the received buffer, you must advance \a p_beginPointer the number of bytes that you
have processed. If \a p_beginPointer does not equal \a endPointer when this method completes,
the system will continue to reclaim any memory that has already been processed, and call this method again
until no more memory has been processed. If no memory has been processed, and more data has been received
on the network, the buffer will be automatically grown (according to a specific alogrythm), to accomodate any new data.
\param socketModule The \a ILibAsyncSocket_SocketModule that received data
\param buffer The data that was received
\param[in,out] p_beginPointer The start index of the data that was received
\param endPointer The end index of the data that was received
\param[in,out] OnInterrupt Set this pointer to receive notification if this session is interrupted
\param[in,out] user Set a custom user object
\param[out] PAUSE Flag to indicate if the system should continue reading data off the network
*/
typedef void(*ILibAsyncSocket_OnData)(ILibAsyncSocket_SocketModule socketModule, char* buffer, int *p_beginPointer, int endPointer,ILibAsyncSocket_OnInterrupt* OnInterrupt, void **user, int *PAUSE);
/*! \typedef ILibAsyncSocket_OnConnect
\brief Handler for when a connection is made
\param socketModule The \a ILibAsyncSocket_SocketModule that was connected
\param user The user object that was associated with this object
*/
typedef void(*ILibAsyncSocket_OnConnect)(ILibAsyncSocket_SocketModule socketModule, int Connected, void *user);
/*! \typedef ILibAsyncSocket_OnDisconnect
\brief Handler for when a connection is terminated normally
\param socketModule The \a ILibAsyncSocket_SocketModule that was disconnected
\param user User object that was associated with this connection
*/
typedef void(*ILibAsyncSocket_OnDisconnect)(ILibAsyncSocket_SocketModule socketModule, void *user);
/*! \typedef ILibAsyncSocket_OnSendOK
\brief Handler for when pending send operations have completed
\par
This handler will only be called if a call to \a ILibAsyncSocket_Send returned a value greater
than 0, which indicates that not all of the data could be sent.
\param socketModule The \a ILibAsyncSocket_SocketModule whos pending sends have completed
\param user User object that was associated with this connection
*/
typedef void(*ILibAsyncSocket_OnSendOK)(ILibAsyncSocket_SocketModule socketModule, void *user);
/*! \typedef ILibAsyncSocket_OnBufferReAllocated
\brief Handler for when the internal data buffer has been resized.
\par
<B>Note:</B> This is only useful if you are storing pointer values into the buffer supplied in \a ILibAsyncSocket_OnData.
\param AsyncSocketToken The \a ILibAsyncSocket_SocketModule whos buffer was resized
\param user The user object that was associated with this connection
\param newOffset The new offset differential. Simply add this value to your existing pointers, to obtain the correct pointer into the resized buffer.
*/
typedef void(*ILibAsyncSocket_OnBufferReAllocated)(ILibAsyncSocket_SocketModule AsyncSocketToken, void *user, ptrdiff_t newOffset);
/*! \defgroup TLSGroup TLS Related Methods
* @{
*/
#ifndef MICROSTACK_NOTLS
#ifdef MICROSTACK_TLS_DETECT
int ILibAsyncSocket_IsUsingTls(ILibAsyncSocket_SocketModule AsyncSocketToken);
#endif
#endif
/*! @} */
extern const int ILibMemory_ASYNCSOCKET_CONTAINERSIZE;
#define ILibAsyncSocket_LOCK_OVERRIDE 0x40000000
void ILibAsyncSocket_SetReAllocateNotificationCallback(ILibAsyncSocket_SocketModule AsyncSocketToken, ILibAsyncSocket_OnBufferReAllocated Callback);
void *ILibAsyncSocket_GetUser(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_SetUser(ILibAsyncSocket_SocketModule socketModule, void* user);
void *ILibAsyncSocket_GetUser2(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_SetUser2(ILibAsyncSocket_SocketModule socketModule, void* user);
int ILibAsyncSocket_GetUser3(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_SetUser3(ILibAsyncSocket_SocketModule socketModule, int user);
void ILibAsyncSocket_UpdateOnData(ILibAsyncSocket_SocketModule module, ILibAsyncSocket_OnData OnData);
void ILibAsyncSocket_UpdateCallbacks(ILibAsyncSocket_SocketModule module, ILibAsyncSocket_OnData OnData, ILibAsyncSocket_OnConnect OnConnect, ILibAsyncSocket_OnDisconnect OnDisconnect, ILibAsyncSocket_OnSendOK OnSendOK);
#define ILibCreateAsyncSocketModule(Chain, initialBufferSize, OnData, OnConnect, OnDisconnect, OnSendOK) ILibCreateAsyncSocketModuleWithMemory(Chain, initialBufferSize, OnData, OnConnect, OnDisconnect, OnSendOK, 0)
ILibAsyncSocket_SocketModule ILibCreateAsyncSocketModuleWithMemory(void *Chain, int initialBufferSize, ILibAsyncSocket_OnData OnData, ILibAsyncSocket_OnConnect OnConnect, ILibAsyncSocket_OnDisconnect OnDisconnect, ILibAsyncSocket_OnSendOK OnSendOK, int UserMappedMemorySize);
void *ILibAsyncSocket_GetSocket(ILibAsyncSocket_SocketModule module);
unsigned int ILibAsyncSocket_GetPendingBytesToSend(ILibAsyncSocket_SocketModule socketModule);
unsigned int ILibAsyncSocket_GetTotalBytesSent(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_ResetTotalBytesSent(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_ConnectTo(void* socketModule, struct sockaddr *localInterface, struct sockaddr *remoteAddress, ILibAsyncSocket_OnInterrupt InterruptPtr, void *user);
#ifdef MICROSTACK_PROXY
void ILibAsyncSocket_ConnectToProxy(void* socketModule, struct sockaddr *localInterface, struct sockaddr *remoteAddress, struct sockaddr *proxyAddress, char* proxyUser, char* proxyPass, ILibAsyncSocket_OnInterrupt InterruptPtr, void *user);
#endif
enum ILibAsyncSocket_SendStatus ILibAsyncSocket_SendTo_MultiWrite(ILibAsyncSocket_SocketModule socketModule, struct sockaddr *remoteAddress, unsigned int count, ...);
/*! \def ILibAsyncSocket_Send
\brief Sends data onto the TCP stream
\param socketModule The \a ILibAsyncSocket_SocketModule to send data on
\param buffer The data to be sent
\param length The length of \a buffer
\param UserFree The \a ILibAsyncSocket_MemoryOwnership enumeration, that identifies how the memory pointer to by \a buffer is to be handled
\returns \a ILibAsyncSocket_SendStatus indicating the send status
*/
#define ILibAsyncSocket_Send(socketModule, buffer, length, UserFree) ILibAsyncSocket_SendTo_MultiWrite(socketModule, NULL, 1, buffer, length, UserFree)
#define ILibAsyncSocket_SendTo(socketModule, buffer, length, remoteAddress, UserFree) ILibAsyncSocket_SendTo_MultiWrite(socketModule, remoteAddress, 1, buffer, length, UserFree)
void ILibAsyncSocket_Disconnect(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_GetBuffer(ILibAsyncSocket_SocketModule socketModule, char **buffer, int *BeginPointer, int *EndPointer);
#if defined(_WIN32_WCE) || defined(WIN32)
void ILibAsyncSocket_UseThisSocket(ILibAsyncSocket_SocketModule socketModule, SOCKET UseThisSocket, ILibAsyncSocket_OnInterrupt InterruptPtr, void *user);
#elif defined(_POSIX)
void ILibAsyncSocket_UseThisSocket(ILibAsyncSocket_SocketModule socketModule, int UseThisSocket, ILibAsyncSocket_OnInterrupt InterruptPtr, void *user);
#endif
#ifndef MICROSTACK_NOTLS
//! TLS Mode for OpenSSL Configuration
/*! \ingroup TLSGroup */
typedef enum ILibAsyncSocket_TLS_Mode
{
ILibAsyncSocket_TLS_Mode_Client = 0, //!< Client Mode
ILibAsyncSocket_TLS_Mode_Server = 1, //!< Server Mode
#ifdef MICROSTACK_TLS_DETECT
ILibAsyncSocket_TLS_Mode_Server_with_TLSDetectLogic = 2, //!< Server Mode with TLS Detection logic enabled
#endif
}ILibAsyncSocket_TLS_Mode;
SSL* ILibAsyncSocket_SetSSLContext(ILibAsyncSocket_SocketModule socketModule, SSL_CTX *ssl_ctx, ILibAsyncSocket_TLS_Mode server);
SSL_CTX *ILibAsyncSocket_GetSSLContext(ILibAsyncSocket_SocketModule socketModule);
#endif
void ILibAsyncSocket_SetRemoteAddress(ILibAsyncSocket_SocketModule socketModule, struct sockaddr *remoteAddress);
void ILibAsyncSocket_SetLocalInterface(ILibAsyncSocket_SocketModule module, struct sockaddr *localAddress);
int ILibAsyncSocket_IsFree(ILibAsyncSocket_SocketModule socketModule);
int ILibAsyncSocket_IsConnected(ILibAsyncSocket_SocketModule socketModule);
int ILibAsyncSocket_GetLocalInterface(ILibAsyncSocket_SocketModule socketModule, struct sockaddr *localAddress);
int ILibAsyncSocket_GetRemoteInterface(ILibAsyncSocket_SocketModule socketModule, struct sockaddr *remoteAddress);
unsigned short ILibAsyncSocket_GetLocalPort(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_Resume(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_Pause(ILibAsyncSocket_SocketModule socketModule);
int ILibAsyncSocket_WasClosedBecauseBufferSizeExceeded(ILibAsyncSocket_SocketModule socketModule);
void ILibAsyncSocket_SetMaximumBufferSize(ILibAsyncSocket_SocketModule module, int maxSize, ILibAsyncSocket_OnBufferSizeExceeded OnBufferSizeExceededCallback, void *user);
void ILibAsyncSocket_SetSendOK(ILibAsyncSocket_SocketModule module, ILibAsyncSocket_OnSendOK OnSendOK);
int ILibAsyncSocket_IsIPv6LinkLocal(struct sockaddr *LocalAddress);
int ILibAsyncSocket_IsModuleIPv6LinkLocal(ILibAsyncSocket_SocketModule module);
typedef void(*ILibAsyncSocket_TimeoutHandler)(ILibAsyncSocket_SocketModule module, void *user);
void ILibAsyncSocket_SetTimeout(ILibAsyncSocket_SocketModule module, int timeoutSeconds, ILibAsyncSocket_TimeoutHandler timeoutHandler);
#ifndef MICROSTACK_NOTLS
X509 *ILibAsyncSocket_SslGetCert(ILibAsyncSocket_SocketModule socketModule);
STACK_OF(X509) *ILibAsyncSocket_SslGetCerts(ILibAsyncSocket_SocketModule socketModule);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,311 @@
/*
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.
*/
#ifdef MEMORY_CHECK
#define MEMCHECK(x) x
#else
#define MEMCHECK(x)
#endif
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#if defined(WINSOCK2)
#include <winsock2.h>
#include <ws2ipdef.h>
#elif defined(WINSOCK1)
#include <winsock.h>
#include <wininet.h>
#endif
#include "ILibParsers.h"
#include "ILibAsyncUDPSocket.h"
#include "ILibAsyncSocket.h"
#define INET_SOCKADDR_LENGTH(x) ((x==AF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
#define INET_SOCKADDR_PORT(x) (x->sa_family==AF_INET6?(unsigned short)(((struct sockaddr_in6*)x)->sin6_port):(unsigned short)(((struct sockaddr_in*)x)->sin_port))
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
struct ILibAsyncUDPSocket_Data
{
void *user1;
void *user2;
ILibAsyncSocket_SocketModule UDPSocket;
unsigned short BoundPortNumber;
ILibAsyncUDPSocket_OnData OnData;
ILibAsyncUDPSocket_OnSendOK OnSendOK;
};
void ILibAsyncUDPSocket_OnDataSink(ILibAsyncSocket_SocketModule socketModule, char* buffer, int *p_beginPointer, int endPointer, ILibAsyncSocket_OnInterrupt* OnInterrupt, void **user, int *PAUSE)
{
struct ILibAsyncUDPSocket_Data *data = (struct ILibAsyncUDPSocket_Data*)*user;
char RemoteAddress[8 + sizeof(struct sockaddr_in6)];
UNREFERENCED_PARAMETER( OnInterrupt );
UNREFERENCED_PARAMETER( RemoteAddress );
ILibAsyncSocket_GetRemoteInterface(socketModule, (struct sockaddr*)&RemoteAddress);
((int*)(RemoteAddress + sizeof(struct sockaddr_in6)))[0] = 4;
((int*)(RemoteAddress + sizeof(struct sockaddr_in6)))[1] = 0;
if (data->OnData != NULL)
{
data->OnData(
socketModule,
buffer,
endPointer,
(struct sockaddr_in6*)&RemoteAddress,
data->user1,
data->user2,
PAUSE);
}
*p_beginPointer = endPointer;
}
void ILibAsyncUDPSocket_OnSendOKSink(ILibAsyncSocket_SocketModule socketModule, void *user)
{
struct ILibAsyncUDPSocket_Data *data = (struct ILibAsyncUDPSocket_Data*)user;
if (data->OnSendOK!=NULL)
{
data->OnSendOK(socketModule, data->user1, data->user2);
}
}
void ILibAsyncUDPSocket_OnDisconnect(ILibAsyncSocket_SocketModule socketModule, void *user)
{
UNREFERENCED_PARAMETER( socketModule );
free(user);
}
/*! \fn ILibAsyncUDPSocket_SocketModule ILibAsyncUDPSocket_CreateEx(void *Chain, int BufferSize, int localInterface, unsigned short localPortStartRange, unsigned short localPortEndRange, enum ILibAsyncUDPSocket_Reuse reuse, ILibAsyncUDPSocket_OnData OnData, ILibAsyncUDPSocket_OnSendOK OnSendOK, void *user)
\brief Creates a new instance of an ILibAsyncUDPSocket module, using a random port number between \a localPortStartRange and \a localPortEndRange inclusive.
\param Chain The chain to add this object to. (Chain must <B>not</B> not be running)
\param BufferSize The size of the buffer to use
\param localInterface The IP address to bind this socket to, in network order
\param localPortStartRange The begin range to select a port number from (host order)
\param localPortEndRange The end range to select a port number from (host order)
\param reuse Reuse type
\param OnData The handler to receive data
\param OnSendOK The handler to receive notification that pending sends have completed
\param user User object to associate with this object
\returns The ILibAsyncUDPSocket_SocketModule handle that was created
*/
ILibAsyncUDPSocket_SocketModule ILibAsyncUDPSocket_CreateEx(void *Chain, int BufferSize, struct sockaddr *localInterface, enum ILibAsyncUDPSocket_Reuse reuse, ILibAsyncUDPSocket_OnData OnData, ILibAsyncUDPSocket_OnSendOK OnSendOK, void *user)
{
int off = 0;
SOCKET sock;
int ra = (int)reuse;
void *RetVal = NULL;
struct ILibAsyncUDPSocket_Data *data;
#ifdef WINSOCK2
DWORD dwBytesReturned = 0;
BOOL bNewBehavior = FALSE;
#endif
// Initialize the UDP socket data structure
data = (struct ILibAsyncUDPSocket_Data*)malloc(sizeof(struct ILibAsyncUDPSocket_Data));
if (data == NULL) return NULL;
memset(data, 0, sizeof(struct ILibAsyncUDPSocket_Data));
data->OnData = OnData;
data->OnSendOK = OnSendOK;
data->user1 = user;
// Create a new socket & set REUSE if needed. If it's IPv6, use the same socket for both IPv4 and IPv6.
if ((sock = socket(localInterface->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) { free(data); return 0; }
if (reuse == ILibAsyncUDPSocket_Reuse_SHARED) if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&ra, sizeof(ra)) != 0) ILIBCRITICALERREXIT(253);
#ifdef __APPLE__
if (reuse == ILibAsyncUDPSocket_Reuse_SHARED) if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&ra, sizeof(ra)) != 0) ILIBCRITICALERREXIT(253);
#endif
if (localInterface->sa_family == AF_INET6) if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)) != 0) ILIBCRITICALERREXIT(253);
// Attempt to bind the UDP socket
#ifdef WIN32
if ( bind(sock, localInterface, INET_SOCKADDR_LENGTH(localInterface->sa_family)) != 0 ) { closesocket(sock); free(data); return NULL; }
#else
if ( bind(sock, localInterface, INET_SOCKADDR_LENGTH(localInterface->sa_family)) != 0 ) { close(sock); free(data); return NULL; }
#endif
#ifdef WINSOCK2
WSAIoctl(sock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);
#endif
// Set the BoundPortNumber
if (localInterface->sa_family == AF_INET6) { data->BoundPortNumber = ntohs(((struct sockaddr_in6*)localInterface)->sin6_port); } else { data->BoundPortNumber = ntohs(((struct sockaddr_in*)localInterface)->sin_port); }
// Create an Async Socket to handle the data
RetVal = ILibCreateAsyncSocketModule(Chain, BufferSize, &ILibAsyncUDPSocket_OnDataSink, NULL, &ILibAsyncUDPSocket_OnDisconnect, &ILibAsyncUDPSocket_OnSendOKSink);
if (RetVal == NULL)
{
#if defined(WIN32) || defined(_WIN32_WCE)
closesocket(sock);
#else
close(sock);
#endif
free(data);
return NULL;
}
ILibAsyncSocket_UseThisSocket(RetVal, sock, &ILibAsyncUDPSocket_OnDisconnect, data);
return RetVal; // Klockwork claims we could be losing the resource acquired with the call to socket(), however, we aren't becuase we are saving it with the above call to ILibAsyncSocket_UseThisSocket()
}
SOCKET ILibAsyncUDPSocket_GetSocket(ILibAsyncUDPSocket_SocketModule module)
{
return *((SOCKET*)ILibAsyncSocket_GetSocket(module));
}
void ILibAsyncUDPSocket_SetBroadcast(ILibAsyncSocket_SocketModule module, int enable)
{
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&enable, sizeof(enable));
}
void ILibAsyncUDPSocket_DropMulticastGroupV4(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in *multicastAddr, struct sockaddr *localAddr)
{
struct ip_mreq mreq;
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
// We start with the multicast structure
memcpy_s(&mreq.imr_multiaddr, sizeof(mreq.imr_multiaddr), &(((struct sockaddr_in*)multicastAddr)->sin_addr), sizeof(mreq.imr_multiaddr));
#ifdef WIN32
mreq.imr_interface.s_addr = ((struct sockaddr_in*)localAddr)->sin_addr.S_un.S_addr;
#else
mreq.imr_interface.s_addr = ((struct sockaddr_in*)localAddr)->sin_addr.s_addr;
#endif
setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
}
/*! \fn int ILibAsyncUDPSocket_JoinMulticastGroup(ILibAsyncUDPSocket_SocketModule module, int localInterface, int remoteInterface)
\brief Joins a multicast group
\param module The ILibAsyncUDPSocket_SocketModule to join the multicast group
\param localInterface The local IP address in network order, to join the multicast group
\param remoteInterface The multicast ip address in network order, to join
\returns 0 = Success, Nonzero = Failure
*/
void ILibAsyncUDPSocket_JoinMulticastGroupV4(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in *multicastAddr, struct sockaddr *localAddr)
{
struct ip_mreq mreq;
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
// We start with the multicast structure
memcpy_s(&mreq.imr_multiaddr, sizeof(mreq.imr_multiaddr), &(((struct sockaddr_in*)multicastAddr)->sin_addr), sizeof(mreq.imr_multiaddr));
#ifdef WIN32
mreq.imr_interface.s_addr = ((struct sockaddr_in*)localAddr)->sin_addr.S_un.S_addr;
#else
mreq.imr_interface.s_addr = ((struct sockaddr_in*)localAddr)->sin_addr.s_addr;
#endif
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));
}
void ILibAsyncUDPSocket_JoinMulticastGroupV6(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in6 *multicastAddr, int ifIndex)
{
struct ipv6_mreq mreq6;
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
memcpy_s(&mreq6.ipv6mr_multiaddr, sizeof(mreq6.ipv6mr_multiaddr), &(((struct sockaddr_in6*)multicastAddr)->sin6_addr), sizeof(mreq6.ipv6mr_multiaddr));
mreq6.ipv6mr_interface = ifIndex;
setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq6, sizeof(mreq6)); // IPV6_ADD_MEMBERSHIP
}
void ILibAsyncUDPSocket_DropMulticastGroupV6(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in6 *multicastAddr, int ifIndex)
{
struct ipv6_mreq mreq6;
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
memcpy_s(&mreq6.ipv6mr_multiaddr, sizeof(mreq6.ipv6mr_multiaddr), &(((struct sockaddr_in6*)multicastAddr)->sin6_addr), sizeof(mreq6.ipv6mr_multiaddr));
mreq6.ipv6mr_interface = ifIndex;
setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char*)&mreq6, sizeof(mreq6)); // IPV6_ADD_MEMBERSHIP
}
/*! \fn int ILibAsyncUDPSocket_SetMulticastInterface(ILibAsyncUDPSocket_SocketModule module, int localInterface)
\brief Sets the local interface to use, when multicasting
\param module The ILibAsyncUDPSocket_SocketModule handle to set the interface on
\param localInterface The local IP address in network order, to use when multicasting
\returns 0 = Success, Nonzero = Failure
*/
void ILibAsyncUDPSocket_SetMulticastInterface(ILibAsyncUDPSocket_SocketModule module, struct sockaddr *localInterface)
{
#if defined(WIN32)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
if (localInterface->sa_family == AF_INET6)
{
// Uses the interface index of the desired outgoing interface
if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&(((struct sockaddr_in6*)localInterface)->sin6_scope_id), sizeof(((struct sockaddr_in6*) localInterface)->sin6_scope_id)) != 0) ILIBCRITICALERREXIT(253);
}
else
{
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&(((struct sockaddr_in*)localInterface)->sin_addr.s_addr), sizeof(struct in_addr)) != 0) ILIBCRITICALERREXIT(253);
}
}
/*! \fn int ILibAsyncUDPSocket_SetMulticastTTL(ILibAsyncUDPSocket_SocketModule module, unsigned char TTL)
\brief Sets the Multicast TTL value
\param module The ILibAsyncUDPSocket_SocketModule handle to set the Multicast TTL value
\param TTL The Multicast-TTL value to use
\returns 0 = Success, Nonzero = Failure
*/
void ILibAsyncUDPSocket_SetMulticastTTL(ILibAsyncUDPSocket_SocketModule module, int TTL)
{
struct sockaddr_in6 localAddress;
#if defined(__SYMBIAN32__)
return 0;
#else
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
ILibAsyncSocket_GetLocalInterface(module, (struct sockaddr*)&localAddress);
if (setsockopt(s, localAddress.sin6_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, localAddress.sin6_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL, (char*)&TTL, sizeof(TTL)) != 0) ILIBCRITICALERREXIT(253);
#endif
}
void ILibAsyncUDPSocket_SetMulticastLoopback(ILibAsyncUDPSocket_SocketModule module, int loopback)
{
struct sockaddr_in6 localAddress;
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET s = *((SOCKET*)ILibAsyncSocket_GetSocket(module));
#else
int s = *((int*)ILibAsyncSocket_GetSocket(module));
#endif
ILibAsyncSocket_GetLocalInterface(module, (struct sockaddr*)&localAddress);
if (setsockopt(s, localAddress.sin6_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, localAddress.sin6_family == PF_INET6 ? IPV6_MULTICAST_LOOP : IP_MULTICAST_LOOP, (char*)&loopback, sizeof(loopback)) != 0) ILIBCRITICALERREXIT(253);
}

View File

@@ -0,0 +1,158 @@
/*
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.
*/
#ifndef ___ILibAsyncUDPSocket___
#define ___ILibAsyncUDPSocket___
/*! \file ILibAsyncUDPSocket.h
\brief MicroStack APIs for UDP Functionality
*/
/*! \defgroup ILibAsyncUDPSocket ILibAsyncUDPSocket Module
\{
*/
#if defined(WIN32) || defined(_WIN32_WCE)
#include <STDDEF.H>
#elif defined(_POSIX)
#if !defined(__APPLE__) && !defined(_VX_CPU)
#include <malloc.h>
#endif
#endif
#include "ILibAsyncSocket.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum ILibAsyncUDPSocket_Reuse
{
ILibAsyncUDPSocket_Reuse_EXCLUSIVE = 0, /*!< A socket is to be bound for exclusive access */
ILibAsyncUDPSocket_Reuse_SHARED = 1 /*!< A socket is to be bound for shared access */
}ILibAsyncUDPSocket_Reuse;
/*! \typedef ILibAsyncUDPSocket_SocketModule
\brief The handle for an ILibAsyncUDPSocket module
*/
typedef void* ILibAsyncUDPSocket_SocketModule;
/*! \typedef ILibAsyncUDPSocket_OnData
\brief The handler that is called when data is received
\param socketModule The \a ILibAsyncUDPSocket_SocketModule handle that received data
\param buffer The buffer that contains the read data
\param bufferLength The amount of data that was read
\param remoteInterface The IP address of the source, in network order
\param remotePort The port number of the source, in host order
\param user User object associated with this module
\param user2 User2 object associated with this module
\param[out] PAUSE Set this flag to non-zero, to prevent more data from being read
*/
typedef void(*ILibAsyncUDPSocket_OnData)(ILibAsyncUDPSocket_SocketModule socketModule, char* buffer, int bufferLength, struct sockaddr_in6 *remoteInterface, void *user, void *user2, int *PAUSE);
/*! \typedef ILibAsyncUDPSocket_OnSendOK
\brief Handler for when pending send operations have completed
\par
This handler will only be called if a call to \a ILibAsyncUDPSocket_SendTo returned a value greater
than 0, which indicates that not all of the data could be sent.
<P><B>Note:</B> On most systems, UDP data that cannot be sent will be dropped, which means that this handler
may actually never be called.
\param socketModule The \a ILibAsyncUDPSocket_SocketModule whos pending sends have completed
\param user1 User object that was associated with this connection
\param user2 User2 object that was associated with this connection
*/
typedef void(*ILibAsyncUDPSocket_OnSendOK)(ILibAsyncUDPSocket_SocketModule socketModule, void *user1, void *user2);
ILibAsyncUDPSocket_SocketModule ILibAsyncUDPSocket_CreateEx(void *Chain, int BufferSize, struct sockaddr *localInterface, enum ILibAsyncUDPSocket_Reuse reuse, ILibAsyncUDPSocket_OnData OnData, ILibAsyncUDPSocket_OnSendOK OnSendOK, void *user);
/*! \def ILibAsyncUDPSocket_Create
\brief Creates a new instance of an ILibAsyncUDPSocket module.
\param Chain The chain to add this object to. (Chain must <B>not</B> not be running)
\param BufferSize The size of the buffer to use
\param localInterface The IP address to bind this socket to, in network order
\param localPort The port to bind this socket to, in host order. (0 = Random IANA specified generic port)
\param reuse Reuse type
\param OnData The handler to receive data
\param OnSendOK The handler to receive notification that pending sends have completed
\param user User object to associate with this object
\returns The ILibAsyncUDPSocket_SocketModule handle that was created
*/
//#define ILibAsyncUDPSocket_Create(Chain, BufferSize, localInterface, localInterfaceSize, reuse, OnData , OnSendOK, user)localPort==0?ILibAsyncUDPSocket_CreateEx(Chain, BufferSize, localInterface, 50000, 65500, reuse, OnData, OnSendOK, user):ILibAsyncUDPSocket_CreateEx(Chain, BufferSize, localInterface, localPort, localPort, reuse, OnData, OnSendOK, user)
void ILibAsyncUDPSocket_JoinMulticastGroupV4(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in *multicastAddr, struct sockaddr *localAddr);
void ILibAsyncUDPSocket_JoinMulticastGroupV6(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in6 *multicastAddr, int ifIndex);
void ILibAsyncUDPSocket_DropMulticastGroupV4(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in *multicastAddr, struct sockaddr *localAddr);
void ILibAsyncUDPSocket_DropMulticastGroupV6(ILibAsyncUDPSocket_SocketModule module, struct sockaddr_in6 *multicastAddr, int ifIndex);
void ILibAsyncUDPSocket_SetMulticastInterface(ILibAsyncUDPSocket_SocketModule module, struct sockaddr *localInterface);
void ILibAsyncUDPSocket_SetMulticastTTL(ILibAsyncUDPSocket_SocketModule module, int TTL);
void ILibAsyncUDPSocket_SetMulticastLoopback(ILibAsyncUDPSocket_SocketModule module, int loopback);
void ILibAsyncUDPSocket_SetBroadcast(ILibAsyncSocket_SocketModule module, int enable);
/*! \def ILibAsyncUDPSocket_GetPendingBytesToSend
\brief Returns the number of bytes that are pending to be sent
\param socketModule The ILibAsyncUDPSocket_SocketModule handle to query
\returns Number of pending bytes
*/
#define ILibAsyncUDPSocket_GetPendingBytesToSend(socketModule) ILibAsyncSocket_GetPendingBytesToSend(socketModule)
/*! \def ILibAsyncUDPSocket_GetTotalBytesSent
\brief Returns the total number of bytes that have been sent, since the last reset
\param socketModule The ILibAsyncUDPSocket_SocketModule handle to query
\returns Number of bytes sent
*/
#define ILibAsyncUDPSocket_GetTotalBytesSent(socketModule) ILibAsyncSocket_GetTotalBytesSent(socketModule)
/*! \def ILibAsyncUDPSocket_ResetTotalBytesSent
\brief Resets the total bytes sent counter
\param socketModule The ILibAsyncUDPSocket_SocketModule handle to reset
*/
#define ILibAsyncUDPSocket_ResetTotalBytesSent(socketModule) ILibAsyncSocket_ResetTotalBytesSent(socketModule)
/*! \def ILibAsyncUDPSocket_SendTo
\brief Sends a UDP packet
\param socketModule The ILibAsyncUDPSocket_SocketModule handle to send a packet on
\param remoteInterface The IP address in network order, to send the packet to
\param remotePort The port numer in host order to send the packet to
\param buffer The buffer to send
\param length The length of \a buffer
\param UserFree The ILibAsyncSocket_MemoryOwnership flag indicating how the memory in \a buffer is to be handled
\returns The ILibAsyncSocket_SendStatus status of the packet that was sent
*/
#define ILibAsyncUDPSocket_SendTo(socketModule, remoteInterface, buffer, length, UserFree) ILibAsyncSocket_SendTo(socketModule, buffer, length, remoteInterface, UserFree)
/*! \def ILibAsyncUDPSocket_GetLocalInterface
\brief Get's the bounded IP address in network order
\param socketModule The ILibAsyncUDPSocket_SocketModule to query
\returns The local bounded IP address in network order
*/
#define ILibAsyncUDPSocket_GetLocalInterface(socketModule, localAddress) ILibAsyncSocket_GetLocalInterface(socketModule, localAddress)
#define ILibAsyncUDPSocket_SetLocalInterface(socketModule, localAddress) ILibAsyncSocket_SetLocalInterface(socketModule, localAddress)
/*! \def ILibAsyncUDPSocket_GetLocalPort
\brief Get's the bounded port in host order
\param socketModule The ILibAsyncUDPSocket_SocketModule to query
\returns The local bounded port in host order
*/
#define ILibAsyncUDPSocket_GetLocalPort(socketModule) ILibAsyncSocket_GetLocalPort(socketModule)
#define ILibAsyncUDPSocket_Resume(socketModule) ILibAsyncSocket_Resume(socketModule)
SOCKET ILibAsyncUDPSocket_GetSocket(ILibAsyncUDPSocket_SocketModule module);
#ifdef __cplusplus
}
#endif
#endif

936
microstack/ILibCrypto.c Normal file
View File

@@ -0,0 +1,936 @@
#if defined(WIN32) && !defined(_WIN32_WCE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "ILibCrypto.h"
#ifndef MICROSTACK_NOTLS
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/pkcs12.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#else
#include "md5.h"
#include "sha1.h"
#include <time.h>
#endif
char utils_HexTable[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
char utils_HexTable2[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
void __fastcall util_md5(char* data, int datalen, char* result)
{
MD5_CTX c;
MD5_Init(&c);
MD5_Update(&c, data, datalen);
MD5_Final((unsigned char*)result, &c);
}
void __fastcall util_md5hex(char* data, int datalen, char *out)
{
int i = 0;
unsigned char *temp = (unsigned char*)out;
MD5_CTX mdContext;
unsigned char digest[16];
MD5_Init(&mdContext);
MD5_Update(&mdContext, (unsigned char *)data, datalen);
MD5_Final(digest, &mdContext);
for (i = 0; i < HALF_NONCE_SIZE; i++)
{
*(temp++) = utils_HexTable2[(unsigned char)digest[i] >> 4];
*(temp++) = utils_HexTable2[(unsigned char)digest[i] & 0x0F];
}
*temp = '\0';
}
void __fastcall util_sha1(char* data, int datalen, char* result)
{
SHA_CTX c;
SHA1_Init(&c);
SHA1_Update(&c, data, datalen);
SHA1_Final((unsigned char*)result, &c);
result[20] = 0;
}
void __fastcall util_sha256(char* data, int datalen, char* result)
{
SHA256_CTX c;
SHA256_Init(&c);
SHA256_Update(&c, data, datalen);
SHA256_Final((unsigned char*)result, &c);
}
int __fastcall util_sha256file(char* filename, char* result)
{
FILE *pFile = NULL;
SHA256_CTX c;
size_t len = 0;
char *buf = NULL;
if (filename == NULL) return -1;
#ifdef WIN32
fopen_s(&pFile, filename, "rbN");
#else
pFile = fopen(filename, "rb");
#endif
if (pFile == NULL) goto error;
SHA256_Init(&c);
if ((buf = (char*)malloc(4096)) == NULL) goto error;
while ((len = fread(buf, 1, 4096, pFile)) > 0) SHA256_Update(&c, buf, len);
free(buf);
buf = NULL;
fclose(pFile);
pFile = NULL;
SHA256_Final((unsigned char*)result, &c);
return 0;
error:
if (buf != NULL) free(buf);
if (pFile != NULL) fclose(pFile);
return -1;
}
// Frees a block of memory returned from this module.
void __fastcall util_free(char* ptr)
{
free(ptr);
//ptr = NULL;
}
char* __fastcall util_tohex(char* data, int len, char* out)
{
int i;
char *p = out;
if (data == NULL || len == 0) { *p = 0; return NULL; }
for (i = 0; i < len; i++)
{
*(p++) = utils_HexTable[((unsigned char)data[i]) >> 4];
*(p++) = utils_HexTable[((unsigned char)data[i]) & 0x0F];
}
*p = 0;
return out;
}
char* __fastcall util_tohex_lower(char* data, int len, char* out)
{
int i;
char *p = out;
if (data == NULL || len == 0) { *p = 0; return NULL; }
for (i = 0; i < len; i++)
{
*(p++) = utils_HexTable2[((unsigned char)data[i]) >> 4];
*(p++) = utils_HexTable2[((unsigned char)data[i]) & 0x0F];
}
*p = 0;
return out;
}
char* __fastcall util_tohex2(char* data, int len, char* out)
{
int i;
char *p = out;
if (data == NULL || len == 0) { *p = 0; return NULL; }
for (i = 0; i < len; i++)
{
*(p++) = utils_HexTable[((unsigned char)data[i]) >> 4];
*(p++) = utils_HexTable[((unsigned char)data[i]) & 0x0F];
if (i + 1<len)
{
*(p++) = ':';
}
}
*p = 0;
return out;
}
// Convert hex string to int
int __fastcall util_hexToint(char *hexString, int hexStringLength)
{
int i, res = 0;
// Ignore the leading zeroes
while (*hexString == '0' && hexStringLength > 0) { hexString++; hexStringLength--; }
// Process the rest of the string
for (i = 0; i < hexStringLength; i++)
{
if (hexString[i] >= '0' && hexString[i] <= '9') { res = (res << 4) + (hexString[i] - '0'); }
else if (hexString[i] >= 'a' && hexString[i] <= 'f') { res = (res << 4) + (hexString[i] - 'a' + 10); }
else if (hexString[i] >= 'A' && hexString[i] <= 'F') { res = (res << 4) + (hexString[i] - 'A' + 10); }
}
return res;
}
// Convert hex string to int
int __fastcall util_hexToBuf(char *hexString, int hexStringLength, char* output)
{
int i, x = hexStringLength / 2;
for (i = 0; i < x; i++) { output[i] = (char)util_hexToint(hexString + (i * 2), 2); }
return i;
}
// Generates a random string of data. TODO: Use Hardware RNG if possible
#ifdef MICROSTACK_NOTLS
int util_random_seeded = 0;
#endif
void __fastcall util_random(int length, char* result)
{
#ifndef MICROSTACK_NOTLS
RAND_bytes((unsigned char*)result, length);
#else
short val;
int i;
if (util_random_seeded == 0)
{
time_t t;
srand((unsigned int)time(&t));
util_random_seeded = 1;
}
for (i = 0; i < length; i += 2)
{
val = rand();
memcpy_s(result + i, length - i, &val, (length - i) >= 2 ? 2 : (length - i));
}
#endif
}
// Generates a random text string, useful for HTTP nonces.
void __fastcall util_randomtext(int length, char* result)
{
int l;
util_random(length, result);
for (l = 0; l<length; l++) result[l] = (unsigned char)((((unsigned char)result[l]) % 10) + '0');
}
size_t __fastcall util_writefile(char* filename, char* data, int datalen)
{
FILE * pFile = NULL;
size_t count = 0;
#ifdef WIN32
fopen_s(&pFile, filename, "wbN");
#else
pFile = fopen(filename, "wb");
#endif
if (pFile != NULL)
{
count = fwrite(data, datalen, 1, pFile);
fclose(pFile);
}
return count;
}
size_t __fastcall util_appendfile(char* filename, char* data, int datalen)
{
FILE * pFile = NULL;
size_t count = 0;
#ifdef WIN32
fopen_s(&pFile, filename, "abN");
#else
pFile = fopen(filename, "ab");
#endif
if (pFile != NULL)
{
count = fwrite(data, datalen, 1, pFile);
fclose(pFile);
}
return count;
}
// Read a file into memory up to maxlen. If *data is NULL, a new buffer is allocated otherwise, the given one is used.
size_t __fastcall util_readfile(char* filename, char** data, size_t maxlen)
{
FILE *pFile = NULL;
size_t count = 0;
size_t len = 0;
size_t r = 1;
if (filename == NULL) return 0;
#ifdef WIN32
fopen_s(&pFile, filename, "rbN");
#else
pFile = fopen(filename, "rb");
#endif
if (pFile != NULL)
{
// If *data is null, we need to allocate memory to read the data. Start by getting the size of the file.
if (*data == NULL)
{
fseek(pFile, 0, SEEK_END);
count = ftell(pFile);
if (count > maxlen) count = maxlen;
fseek(pFile, 0, SEEK_SET);
*data = (char*)malloc(count + 1);
if (*data == NULL) { fclose(pFile); return 0; }
}
else { count = maxlen - 1; }
while (r != 0 && len < count)
{
r = fread(*data, 1, count - len, pFile);
len += r;
}
(*data)[len] = 0;
fclose(pFile);
}
return len;
}
#ifdef _POSIX
// This method reads a stream where the length of the file can't be determined. Useful in POSIX only
int __fastcall util_readfile2(char* filename, char** data)
{
FILE * pFile;
int count = 0;
int len = 0;
*data = NULL;
if (filename == NULL) return 0;
pFile = fopen(filename, "rb");
if (pFile != NULL)
{
*data = malloc(1024);
if (*data == NULL) { fclose(pFile); return 0; }
do
{
len = (int)fread((*data) + count, 1, 1023, pFile);
count += len;
if (len == 1023) *data = realloc(*data, count + 1024);
} while (len == 100);
(*data)[count] = 0;
fclose(pFile);
}
return count;
}
#endif
int __fastcall util_deletefile(char* filename)
{
if (filename == NULL) return 0;
return remove(filename);
}
#ifdef WIN32
// Really fast CRC-like method. Used for the KVM.
int __fastcall util_crc(unsigned char *buffer, int len, int initial_value)
{
int hval = initial_value;
int *bp = (int*)buffer;
int *be = bp + (len >> 2);
while (bp < be)
{
//hval *= 0x01000193;
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
hval ^= *bp++;
}
// TODO: Handle left over bytes (len % 4)
return hval;
}
#ifdef _MINCORE
BOOL util_MoveFile(_In_ LPCTSTR lpExistingFileName, _In_ LPCTSTR lpNewFileName)
{
size_t convertedChars = 0;
wchar_t lpExistingFileNameW[MAX_PATH];
wchar_t lpNewFileNameW[MAX_PATH];
mbstowcs_s(&convertedChars, lpExistingFileNameW, MAX_PATH, (const char*)lpExistingFileName, MAX_PATH);
mbstowcs_s(&convertedChars, lpNewFileNameW, MAX_PATH, (const char*)lpNewFileName, MAX_PATH);
return MoveFileExW(lpExistingFileNameW, lpNewFileNameW, 0);
}
BOOL util_CopyFile(_In_ LPCSTR lpExistingFileName, _In_ LPCSTR lpNewFileName, _In_ BOOL bFailIfExists)
{
size_t convertedChars = 0;
wchar_t lpExistingFileNameW[MAX_PATH];
wchar_t lpNewFileNameW[MAX_PATH];
mbstowcs_s(&convertedChars, lpExistingFileNameW, MAX_PATH, (const char*)lpExistingFileName, MAX_PATH);
mbstowcs_s(&convertedChars, lpNewFileNameW, MAX_PATH, (const char*)lpNewFileName, MAX_PATH);
return (CopyFile2(lpExistingFileNameW, lpNewFileNameW, NULL) == S_OK);
}
#else
BOOL util_MoveFile(_In_ LPCSTR lpExistingFileName, _In_ LPCSTR lpNewFileName) { return MoveFileA(lpExistingFileName, lpNewFileName); }
BOOL util_CopyFile(_In_ LPCSTR lpExistingFileName, _In_ LPCSTR lpNewFileName, _In_ BOOL bFailIfExists) { return CopyFileA(lpExistingFileName, lpNewFileName, bFailIfExists); }
#endif
#endif
#ifndef MICROSTACK_NOTLS
// Setup OpenSSL
int InitCounter = 0;
void __fastcall util_openssl_init()
{
char* tbuf[64];
#if defined(WIN32)
HMODULE g_hAdvLib = NULL;
BOOLEAN(APIENTRY *g_CryptGenRandomPtr)(void*, ULONG) = NULL;
#endif
#ifdef _POSIX
int l;
#endif
++InitCounter;
if (InitCounter > 1) { return; }
SSL_library_init(); // TWO LEAKS COMING FROM THIS LINE. Seems to be a well known OpenSSL problem.
SSL_load_error_strings();
ERR_load_crypto_strings(); // ONE LEAK IN LINUX
OpenSSL_add_all_algorithms(); // OpenSSL 1.1
OpenSSL_add_all_ciphers(); // OpenSSL 1.1
OpenSSL_add_all_digests(); // OpenSSL 1.1
// Add more random seeding in Windows (This is probably useful since OpenSSL in Windows has weaker seeding)
#if defined(WIN32) && !defined(_MINCORE)
//RAND_screen(); // On Windows, add more random seeding using a screen dump (this is very expensive).
if ((g_hAdvLib = LoadLibrary(TEXT("ADVAPI32.DLL"))) != 0) g_CryptGenRandomPtr = (BOOLEAN(APIENTRY *)(void*, ULONG))GetProcAddress(g_hAdvLib, "SystemFunction036");
if (g_CryptGenRandomPtr != 0 && g_CryptGenRandomPtr(tbuf, 64) != 0) RAND_add(tbuf, 64, 64); // Use this high quality random as added seeding
if (g_hAdvLib != NULL) FreeLibrary(g_hAdvLib);
#endif
// Add more random seeding in Linux (May be overkill since OpenSSL already uses /dev/urandom)
#ifdef _POSIX
// Under Linux we use "/dev/urandom" if available. This is the best source of random on Linux & variants
FILE *pFile = fopen("/dev/urandom", "rb");
if (pFile != NULL)
{
l = (int)fread(tbuf, 1, 64, pFile);
fclose(pFile);
if (l > 0) RAND_add(tbuf, l, l);
}
#endif
}
// Cleanup OpenSSL
void __fastcall util_openssl_uninit()
{
--InitCounter;
if (InitCounter > 0) { return; }
//RAND_cleanup(); // Does nothing.
//CRYPTO_set_dynlock_create_callback(NULL); // Does nothing.
//CRYPTO_set_dynlock_destroy_callback(NULL); // Does nothing.
//CRYPTO_set_dynlock_lock_callback(NULL); // Does nothing.
//CRYPTO_set_locking_callback(NULL); // Does nothing.
//CRYPTO_set_id_callback(NULL); // Does nothing.
CRYPTO_cleanup_all_ex_data();
//sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); // Does something, but it causes heap corruption...
//CONF_modules_unload(1); // Does nothing.
CONF_modules_free();
EVP_cleanup();
ERR_free_strings();
//ERR_remove_state(0); // Deprecated in OpenSSL/1.1.x
OPENSSL_cleanup();
}
// Add extension using V3 code: we can set the config file as NULL because we wont reference any other sections.
int __fastcall util_add_ext(X509 *cert, int nid, char *value)
{
X509_EXTENSION *ex;
X509V3_CTX ctx;
// This sets the 'context' of the extensions. No configuration database
X509V3_set_ctx_nodb(&ctx);
// Issuer and subject certs: both the target since it is self signed, no request and no CRL
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex) return 0;
X509_add_ext(cert, ex, -1);
X509_EXTENSION_free(ex);
return 1;
}
void __fastcall util_freecert(struct util_cert* cert)
{
if (cert->x509 != NULL) X509_free(cert->x509);
if (cert->pkey != NULL) EVP_PKEY_free(cert->pkey);
cert->x509 = NULL;
cert->pkey = NULL;
}
int __fastcall util_to_cer(struct util_cert cert, char** data)
{
*data = NULL;
return i2d_X509(cert.x509, (unsigned char**)data);
}
int __fastcall util_from_cer(char* data, int datalen, struct util_cert* cert)
{
cert->pkey = NULL;
cert->x509 = d2i_X509(NULL, (const unsigned char**)&data, datalen);
return ((cert->x509) == NULL);
}
int __fastcall util_from_pem_string(char *data, int datalen, struct util_cert* cert)
{
BIO* bio = BIO_new_mem_buf((void*)data, datalen);
int retVal = 0;
if ((cert->pkey = PEM_read_bio_PrivateKey(bio, NULL, 0, NULL)) == NULL) { retVal = -1; }
if ((cert->x509 = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL) { retVal = -1; }
BIO_free(bio);
return retVal;
}
int __fastcall util_from_pem(char* filename, struct util_cert* cert)
{
FILE *pFile = NULL;
if (filename == NULL) return -1;
#ifdef WIN32
fopen_s(&pFile, filename, "rbN");
#else
pFile = fopen(filename, "rb");
#endif
if (pFile == NULL) goto error;
if ((cert->pkey = PEM_read_PrivateKey(pFile, NULL, 0, NULL)) == NULL) goto error;
if ((cert->x509 = PEM_read_X509(pFile, NULL, 0, NULL)) == NULL) goto error;
fclose(pFile);
return 0;
error:
if (pFile != NULL) fclose(pFile);
return -1;
}
int __fastcall util_to_p12(struct util_cert cert, char *password, char** data)
{
PKCS12 *p12;
int len;
p12 = PKCS12_create(password, "Certificate", cert.pkey, cert.x509, NULL, 0, 0, 0, 0, 0);
*data = NULL;
len = i2d_PKCS12(p12, (unsigned char**)data);
PKCS12_free(p12);
return len;
}
int __fastcall util_from_p12(char* data, int datalen, char* password, struct util_cert* cert)
{
int r = 0;
PKCS12 *p12 = NULL;
if (data == NULL || datalen == 0) return 0;
cert->x509 = NULL;
cert->pkey = NULL;
p12 = d2i_PKCS12(&p12, (const unsigned char**)&data, datalen);
r = PKCS12_parse(p12, password, &(cert->pkey), &(cert->x509), NULL);
PKCS12_free(p12);
return r;
}
void __fastcall util_printcert(struct util_cert cert)
{
if (cert.x509 == NULL) return;
X509_print_fp(stdout, cert.x509);
}
void __fastcall util_printcert_pk(struct util_cert cert)
{
if (cert.pkey == NULL) return;
//RSA_print_fp(stdout, cert.pkey->pkey.rsa, 0);
RSA_print_fp(stdout, EVP_PKEY_get1_RSA(cert.pkey), 0);
}
// Creates a X509 certificate, if rootcert is NULL this creates a root (self-signed) certificate.
// Is the name parameter is NULL, the hex value of the hash of the public key will be the subject name.
int __fastcall util_mkCert(struct util_cert *rootcert, struct util_cert* cert, int bits, int days, char* name, enum CERTIFICATE_TYPES certtype, struct util_cert* initialcert)
{
X509 *x = NULL;
X509_EXTENSION *ex = NULL;
EVP_PKEY *pk = NULL;
RSA *rsa = NULL;
X509_NAME *cname = NULL;
X509 **x509p = NULL;
EVP_PKEY **pkeyp = NULL;
int hashlen = UTIL_HASHSIZE;
char hash[UTIL_HASHSIZE];
char serial[8];
char nameStr[(UTIL_HASHSIZE * 2) + 2];
BIGNUM *oBigNbr;
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
if (initialcert != NULL)
{
pk = X509_get_pubkey(initialcert->x509);
rsa = EVP_PKEY_get1_RSA(initialcert->pkey);
if ((x = X509_new()) == NULL) goto err;
}
else
{
if ((pkeyp == NULL) || (*pkeyp == NULL)) { if ((pk = EVP_PKEY_new()) == NULL) return 0; }
else pk = *pkeyp;
if ((x509p == NULL) || (*x509p == NULL)) { if ((x = X509_new()) == NULL) goto err; }
else x = *x509p;
oBigNbr = BN_new();
rsa = RSA_new();
BN_set_word(oBigNbr, RSA_F4);
if (RSA_generate_key_ex(rsa, bits, oBigNbr, NULL) == -1)
{
RSA_free(rsa);
BN_free(oBigNbr);
abort();
}
BN_free(oBigNbr);
}
if (!EVP_PKEY_assign_RSA(pk, rsa))
{
RSA_free(rsa);
abort();
}
rsa = NULL;
util_randomtext(8, serial);
X509_set_version(x, 2);
ASN1_STRING_set(X509_get_serialNumber(x), serial, 8);
X509_gmtime_adj(X509_get_notBefore(x), (long)60 * 60 * 24 * -10);
X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days);
X509_set_pubkey(x, pk);
// Set the subject name
cname = X509_get_subject_name(x);
if (name == NULL)
{
// Computer the hash of the public key
//util_sha256((char*)x->cert_info->key->public_key->data, x->cert_info->key->public_key->length, hash); // OpenSSL 1.0
X509_pubkey_digest(x, EVP_sha256(), (unsigned char*)hash, (unsigned int*)&hashlen); // OpenSSL 1.1
util_tohex(hash, UTIL_HASHSIZE, nameStr);
X509_NAME_add_entry_by_txt(cname, "CN", MBSTRING_ASC, (unsigned char*)nameStr, -1, -1, 0);
}
else
{
// This function creates and adds the entry, working out the correct string type and performing checks on its length. Normally we'd check the return value for errors...
X509_NAME_add_entry_by_txt(cname, "CN", MBSTRING_ASC, (unsigned char*)name, -1, -1, 0);
}
if (rootcert == NULL)
{
// Its self signed so set the issuer name to be the same as the subject.
X509_set_issuer_name(x, cname);
// Add various extensions: standard extensions
util_add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
util_add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
util_add_ext(x, NID_subject_key_identifier, "hash");
//util_add_ext(x, NID_netscape_cert_type, "sslCA");
//util_add_ext(x, NID_netscape_comment, "example comment extension");
if (!X509_sign(x, pk, EVP_sha256())) goto err;
}
else
{
// This is a sub-certificate
cname = X509_get_subject_name(rootcert->x509);
X509_set_issuer_name(x, cname);
// Add usual cert stuff
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, "digitalSignature, keyEncipherment, keyAgreement");
X509_add_ext(x, ex, -1);
X509_EXTENSION_free(ex);
// Add usages: TLS server, TLS client, Intel(R) AMT Console
//ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, "TLS Web Server Authentication, TLS Web Client Authentication, 2.16.840.1.113741.1.2.1, 2.16.840.1.113741.1.2.2");
if (certtype == CERTIFICATE_TLS_SERVER)
{
// TLS server
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, "TLS Web Server Authentication");
X509_add_ext(x, ex, -1);
X509_EXTENSION_free(ex);
}
else if (certtype == CERTIFICATE_TLS_CLIENT)
{
// TLS client
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, "TLS Web Client Authentication");
X509_add_ext(x, ex, -1);
X509_EXTENSION_free(ex);
}
if (!X509_sign(x, rootcert->pkey, EVP_sha256())) goto err;
}
cert->x509 = x;
cert->pkey = pk;
return 1;
err:
return 0;
}
int __fastcall util_keyhash(struct util_cert cert, char* result)
{
int hashlen = UTIL_HASHSIZE;
if (cert.x509 == NULL) return -1;
//util_sha256((char*)(cert.x509->cert_info->key->public_key->data), cert.x509->cert_info->key->public_key->length, result); // OpenSSL 1.0
X509_pubkey_digest(cert.x509, EVP_sha256(), (unsigned char*)result,(unsigned int *) &hashlen); // OpenSSL 1.1
return 0;
}
int __fastcall util_keyhash2(X509* cert, char* result)
{
int hashlen = UTIL_HASHSIZE;
if (cert == NULL) return -1;
//util_sha256((char*)(cert->cert_info->key->public_key->data), cert->cert_info->key->public_key->length, result); // OpenSSL 1.0
X509_pubkey_digest(cert, EVP_sha256(), (unsigned char*)result, (unsigned int*)&hashlen); // OpenSSL 1.1
return 0;
}
// Sign this block of data, the first 32 bytes of the block must be avaialble to add the certificate hash.
int __fastcall util_sign(struct util_cert cert, char* data, int datalen, char** signature)
{
int size = 0;
unsigned int hashsize = UTIL_HASHSIZE;
BIO *in = NULL;
PKCS7 *message = NULL;
*signature = NULL;
if (datalen <= UTIL_HASHSIZE) return 0;
// Add hash of the certificate to start of data
X509_digest(cert.x509, EVP_sha256(), (unsigned char*)data, &hashsize);
// Sign the block
in = BIO_new_mem_buf(data, datalen);
message = PKCS7_sign(cert.x509, cert.pkey, NULL, in, PKCS7_BINARY);
if (message == NULL) goto error;
size = i2d_PKCS7(message, (unsigned char**)signature);
error:
if (message != NULL) PKCS7_free(message);
if (in != NULL) BIO_free(in);
return size;
}
// Verify the signed block, the first 32 bytes of the data must be the certificate hash to work.
int __fastcall util_verify(char* signature, int signlen, struct util_cert* cert, char** data)
{
unsigned int size, r;
BIO *out = NULL;
PKCS7 *message = NULL;
char* data2 = NULL;
char hash[UTIL_HASHSIZE];
STACK_OF(X509) *st = NULL;
cert->x509 = NULL;
cert->pkey = NULL;
*data = NULL;
message = d2i_PKCS7(NULL, (const unsigned char**)&signature, signlen);
if (message == NULL) goto error;
out = BIO_new(BIO_s_mem());
// Lets rebuild the original message and check the size
size = i2d_PKCS7(message, NULL);
if (size < (unsigned int)signlen) goto error;
// Check the PKCS7 signature, but not the certificate chain.
r = PKCS7_verify(message, NULL, NULL, NULL, out, PKCS7_NOVERIFY);
if (r == 0) goto error;
// If data block contains less than 32 bytes, fail.
size = (unsigned int)BIO_get_mem_data(out, &data2);
if (size <= UTIL_HASHSIZE) goto error;
// Copy the data block
*data = (char*)malloc(size + 1);
if (*data == NULL) goto error;
memcpy_s(*data, size + 1, data2, size);
(*data)[size] = 0;
// Get the certificate signer
st = PKCS7_get0_signers(message, NULL, PKCS7_NOVERIFY);
cert->x509 = X509_dup(sk_X509_value(st, 0));
sk_X509_free(st);
// Get a full certificate hash of the signer
r = UTIL_HASHSIZE;
X509_digest(cert->x509, EVP_sha256(), (unsigned char*)hash, &r);
// Check certificate hash with first 32 bytes of data.
if (memcmp(hash, *data, UTIL_HASHSIZE) != 0) goto error;
// Approved, cleanup and return.
BIO_free(out);
PKCS7_free(message);
return size;
error:
if (out != NULL) BIO_free(out);
if (message != NULL) PKCS7_free(message);
if (*data != NULL) free(*data);
if (cert->x509 != NULL) { X509_free(cert->x509); cert->x509 = NULL; }
return 0;
}
// Encrypt a block of data for a target certificate
int __fastcall util_encrypt(struct util_cert cert, char* data, int datalen, char** encdata)
{
int size = 0;
BIO *in = NULL;
PKCS7 *message = NULL;
STACK_OF(X509) *encerts = NULL;
*encdata = NULL;
if (datalen == 0) return 0;
// Setup certificates
encerts = sk_X509_new_null();
sk_X509_push(encerts, cert.x509);
// Encrypt the block
*encdata = NULL;
in = BIO_new_mem_buf(data, datalen);
message = PKCS7_encrypt(encerts, in, EVP_aes_128_cbc(), PKCS7_BINARY);
if (message == NULL) return 0;
size = i2d_PKCS7(message, (unsigned char**)encdata);
BIO_free(in);
PKCS7_free(message);
sk_X509_free(encerts);
return size;
}
// Encrypt a block of data using multiple target certificates
int __fastcall util_encrypt2(STACK_OF(X509) *certs, char* data, int datalen, char** encdata)
{
int size = 0;
BIO *in = NULL;
PKCS7 *message = NULL;
*encdata = NULL;
if (datalen == 0) return 0;
// Encrypt the block
*encdata = NULL;
in = BIO_new_mem_buf(data, datalen);
message = PKCS7_encrypt(certs, in, EVP_aes_128_cbc(), PKCS7_BINARY);
if (message == NULL) return 0;
size = i2d_PKCS7(message, (unsigned char**)encdata);
BIO_free(in);
PKCS7_free(message);
return size;
}
// Decrypt a block of data using the specified certificate. The certificate must have a private key.
int __fastcall util_decrypt(char* encdata, int encdatalen, struct util_cert cert, char** data)
{
unsigned int size, r;
BIO *out = NULL;
PKCS7 *message = NULL;
char* data2 = NULL;
*data = NULL;
if (cert.pkey == NULL) return 0;
message = d2i_PKCS7(NULL, (const unsigned char**)&encdata, encdatalen);
if (message == NULL) goto error;
out = BIO_new(BIO_s_mem());
// Lets rebuild the original message and check the size
size = i2d_PKCS7(message, NULL);
if (size < (unsigned int)encdatalen) goto error;
// Decrypt the PKCS7
r = PKCS7_decrypt(message, cert.pkey, cert.x509, out, 0);
if (r == 0) goto error;
// If data block contains 0 bytes, fail.
size = (unsigned int)BIO_get_mem_data(out, &data2);
if (size == 0) goto error;
// Copy the data block
*data = (char*)malloc(size + 1);
if (*data == NULL) goto error;
memcpy_s(*data, size + 1, data2, size);
(*data)[size] = 0;
// Cleanup and return.
BIO_free(out);
PKCS7_free(message);
return size;
error:
if (out != NULL) BIO_free(out);
if (message != NULL) PKCS7_free(message);
if (*data != NULL) free(*data);
if (data2 != NULL) free(data2);
return 0;
}
// Encrypt a block of data using raw RSA. This is used to handle data in the most compact possible way.
int __fastcall util_rsaencrypt(X509 *cert, char* data, int datalen, char** encdata)
{
int len;
RSA *rsa;
EVP_PKEY *pkey;
pkey = X509_get_pubkey(cert);
rsa = EVP_PKEY_get1_RSA(pkey);
if (datalen > RSA_size(rsa)) { EVP_PKEY_free(pkey); RSA_free(rsa); return 0; }
*encdata = (char*)malloc(RSA_size(rsa));
len = RSA_public_encrypt(datalen, (const unsigned char*)data, (unsigned char*)*encdata, rsa, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_free(pkey);
RSA_free(rsa);
if (len == RSA_size(rsa)) return len;
free(*encdata);
*encdata = NULL;
return 0;
}
// Decrypt a block of data using raw RSA. This is used to handle data in the most compact possible way.
int __fastcall util_rsadecrypt(struct util_cert cert, char* data, int datalen, char** decdata)
{
int len;
RSA *rsa;
rsa = EVP_PKEY_get1_RSA(cert.pkey);
*decdata = (char*)malloc(RSA_size(rsa));
len = RSA_private_decrypt(datalen, (const unsigned char*)data, (unsigned char*)*decdata, rsa, RSA_PKCS1_OAEP_PADDING);
RSA_free(rsa);
if (len != 0) return len;
free(*decdata);
*decdata = NULL;
return 0;
}
// Verify the RSA signature of a block using SHA1 hash
int __fastcall util_rsaverify(X509 *cert, char* data, int datalen, char* sign, int signlen)
{
int r;
RSA *rsa = NULL;
EVP_PKEY *pkey = NULL;
SHA_CTX c;
char hash[20];
SHA1_Init(&c);
SHA1_Update(&c, data, datalen);
SHA1_Final((unsigned char*)hash, &c);
pkey = X509_get_pubkey(cert);
rsa = EVP_PKEY_get1_RSA(pkey);
//rsa->pad = RSA_PKCS1_PADDING; // OPENSSL 1.0
#ifdef WIN32
r = RSA_verify(NID_sha1, (const unsigned char*)hash, 20, (const unsigned char*)sign, signlen, rsa);
#else
r = RSA_verify(NID_sha1, (const unsigned char*)hash, 20, (unsigned char*)sign, signlen, rsa);
#endif
EVP_PKEY_free(pkey);
RSA_free(rsa);
return r;
}
#endif

122
microstack/ILibCrypto.h Normal file
View File

@@ -0,0 +1,122 @@
#ifndef __ILIB_CRYPTO__
#define __ILIB_CRYPTO__
#include "ILibParsers.h"
#if !defined(WIN32)
#define __fastcall
#endif
void __fastcall util_md5(char* data, int datalen, char* result);
void __fastcall util_md5hex(char* data, int datalen, char *out);
void __fastcall util_sha1(char* data, int datalen, char* result);
char* __fastcall util_tohex(char* data, int len, char* out);
char* __fastcall util_tohex2(char* data, int len, char* out);
char* __fastcall util_tohex_lower(char* data, int len, char* out);
int __fastcall util_hexToint(char *hexString, int hexStringLength);
int __fastcall util_hexToBuf(char *hexString, int hexStringLength, char* output);
void __fastcall util_sha256(char* data, int datalen, char* result);
int __fastcall util_sha256file(char* filename, char* result);
// File and data methods
size_t __fastcall util_writefile(char* filename, char* data, int datalen);
size_t __fastcall util_appendfile(char* filename, char* data, int datalen);
size_t __fastcall util_readfile(char* filename, char** data, size_t maxlen);
int __fastcall util_deletefile(char* filename);
#ifdef WIN32
int __fastcall util_crc(unsigned char *buffer, int len, int initial_value);
BOOL util_MoveFile(_In_ LPCSTR lpExistingFileName, _In_ LPCSTR lpNewFileName);
BOOL util_CopyFile(_In_ LPCSTR lpExistingFileName, _In_ LPCSTR lpNewFileName, _In_ BOOL bFailIfExists);
#endif
void __fastcall util_random(int length, char* result);
void __fastcall util_randomtext(int length, char* result);
#define UTIL_HASHSIZE 32
#define NONCE_SIZE 32
#define HALF_NONCE_SIZE 16
#ifdef MICROSTACK_NOTLS
#include "md5.h"
#include "sha1.h"
#include "microstack/SHA256.h"
#define SHA256_CTX struct sha256_ctx
#define SHA256_Init(ctx) __sha256_init_ctx(ctx)
#define SHA256_Update(ctx, data, len) __sha256_process_bytes(data, len, ctx)
#define SHA256_Final(md, ctx) __sha256_finish_ctx(ctx, md)
#endif
#ifndef MICROSTACK_NOTLS
#include <openssl/ssl.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/err.h>
// Certificate structure
typedef struct util_cert
{
X509 *x509;
EVP_PKEY *pkey;
}util_cert;
typedef enum CERTIFICATE_TYPES
{
CERTIFICATE_ROOT = 1,
CERTIFICATE_TLS_SERVER = 2,
CERTIFICATE_TLS_CLIENT = 3
}CERTIFICATE_TYPES;
void __fastcall util_openssl_init();
void __fastcall util_openssl_uninit();
void __fastcall util_free(char* ptr);
// Certificate & crypto methods
void __fastcall util_freecert(struct util_cert* cert);
int __fastcall util_to_p12(struct util_cert cert, char *password, char** data);
int __fastcall util_from_p12(char* data, int datalen, char* password, struct util_cert* cert);
int __fastcall util_to_cer(struct util_cert cert, char** data);
int __fastcall util_from_cer(char* data, int datalen, struct util_cert* cert);
int __fastcall util_from_pem(char* filename, struct util_cert* cert);
int __fastcall util_from_pem_string(char *data, int datalen, struct util_cert* cert);
int __fastcall util_mkCert(struct util_cert *rootcert, struct util_cert* cert, int bits, int days, char* name, enum CERTIFICATE_TYPES certtype, struct util_cert* initialcert);
void __fastcall util_printcert(struct util_cert cert);
void __fastcall util_printcert_pk(struct util_cert cert);
int __fastcall util_keyhash(struct util_cert cert, char* result);
int __fastcall util_keyhash2(X509* cert, char* result);
int __fastcall util_sign(struct util_cert cert, char* data, int datalen, char** signature);
int __fastcall util_verify(char* signature, int signlen, struct util_cert* cert, char** data);
int __fastcall util_encrypt(struct util_cert cert, char* data, int datalen, char** encdata);
int __fastcall util_encrypt2(STACK_OF(X509) *certs, char* data, int datalen, char** encdata);
int __fastcall util_decrypt(char* encdata, int encdatalen, struct util_cert cert, char** data);
int __fastcall util_rsaencrypt(X509 *cert, char* data, int datalen, char** encdata);
int __fastcall util_rsadecrypt(struct util_cert cert, char* data, int datalen, char** decdata);
int __fastcall util_rsaverify(X509 *cert, char* data, int datalen, char* sign, int signlen);
#endif
#if defined(_DEBUG)
// Display only
#ifdef ANDROID
#include <android/log.h>
#define MSG(...) __android_log_print(ANDROID_LOG_DEBUG, "MeshAgent", __VA_ARGS__);
#elif NACL
#include "chrome/nacl.h"
#define MSG(...) ni_log(__VA_ARGS__);
#else
#define MSG(...) printf(__VA_ARGS__);fflush(NULL)
#endif
#define DEBUGSTATEMENT(x) x
#else
#ifndef MSG
#define MSG(...)
#endif
#define DEBUGSTATEMENT(x)
#endif
#endif

View File

@@ -0,0 +1,136 @@
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <Dbghelp.h>
#endif
#include "ILibParsers.h"
#ifdef _POSIX
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#endif
typedef void* ILibIPAddressMonitor;
typedef void(*ILibIPAddressMonitor_Handler)(ILibIPAddressMonitor sender, void *user);
typedef struct _ILibIPAddressMonitor
{
ILibChain_Link chainLink;
ILibIPAddressMonitor_Handler onUpdate;
void *user;
#ifdef WIN32
SOCKET mSocket;
DWORD bytesReturned;
WSAOVERLAPPED reserved;
#elif defined (_POSIX)
int mSocket;
struct sockaddr_nl addr;
#endif
}_ILibIPAddressMonitor;
int ILibMemory_IPAddressMonitor_CONTAINER_SIZE = sizeof(_ILibIPAddressMonitor);
void ILibIPAddressMonitor_MicrostackThreadDispatch(void *chain, void *user);
#ifdef WIN32
void CALLBACK ILibIPAddressMonitor_dispatch(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
)
{
if (dwError == 0)
{
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)lpOverlapped->hEvent;
ILibChain_RunOnMicrostackThread(obj->chainLink.ParentChain, ILibIPAddressMonitor_MicrostackThreadDispatch, obj);
}
}
void ILibIPAddressMonitor_MicrostackThreadDispatch(void *chain, void *user)
{
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)user;
if (obj->onUpdate != NULL) { obj->onUpdate(obj, obj->user); }
WSAIoctl(obj->mSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &(obj->bytesReturned), &(obj->reserved), ILibIPAddressMonitor_dispatch);
}
#endif
void ILibIPAddressMonitor_Destroy(void *object)
{
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)object;
#ifdef WIN32
closesocket(obj->mSocket);
obj->mSocket = INVALID_SOCKET;
#elif defined(_POSIX)
close(obj->mSocket);
obj->mSocket = -1;
#endif
}
#if defined(_POSIX)
void ILibIPAddressMonitor_PreSelect(void* object, fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime)
{
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)object;
FD_SET(obj->mSocket, readset);
}
void ILibIPAddressMonitor_PostSelect(void* object, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset)
{
char buffer[4096];
int len;
int update = 0;
struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)object;
if (FD_ISSET(obj->mSocket, readset) != 0)
{
while ((len = recv(obj->mSocket, nlh, sizeof(buffer), 0)) > 0)
{
while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
{
if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR)
{
update = 1;
}
nlh = NLMSG_NEXT(nlh, len);
}
}
if (update != 0 && obj->onUpdate != NULL) { obj->onUpdate(obj, obj->user); }
}
}
#endif
ILibIPAddressMonitor ILibIPAddressMonitor_Create(void *chain, ILibIPAddressMonitor_Handler handler, void *user)
{
_ILibIPAddressMonitor *obj = (_ILibIPAddressMonitor*)ILibChain_Link_Allocate(ILibMemory_IPAddressMonitor_CONTAINER_SIZE, 0);
obj->onUpdate = handler;
obj->user = user;
#ifdef WIN32
obj->reserved.hEvent = (HANDLE)obj;
obj->mSocket = socket(AF_INET, SOCK_DGRAM, 0);
WSAIoctl(obj->mSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &(obj->bytesReturned), &(obj->reserved), ILibIPAddressMonitor_dispatch);
#elif defined (_POSIX)
obj->mSocket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
int flags = fcntl(obj->mSocket, F_GETFL, 0);
fcntl(obj->mSocket, F_SETFL, O_NONBLOCK | flags);
memset(&(obj->addr), 0, sizeof(obj->addr));
obj->addr.nl_family = AF_NETLINK;
obj->addr.nl_groups = RTMGRP_IPV4_IFADDR;
if (bind(obj->mSocket, (struct sockaddr *)&(obj->addr), sizeof(obj->addr)) == -1)
{
close(obj->mSocket);
free(obj);
return(NULL);
}
obj->chainLink.PreSelectHandler = ILibIPAddressMonitor_PreSelect;
obj->chainLink.PostSelectHandler = ILibIPAddressMonitor_PostSelect;
#endif
obj->chainLink.DestroyHandler = ILibIPAddressMonitor_Destroy;
ILibAddToChain(chain, obj);
return((ILibIPAddressMonitor)obj);
}

View File

@@ -0,0 +1,11 @@
#ifndef __ILIBIPADDRESSMONITOR__
#define __ILIBIPADDRESSMONITOR__
typedef void* ILibIPAddressMonitor;
typedef void(*ILibIPAddressMonitor_Handler)(ILibIPAddressMonitor sender, void *user);
extern int ILibMemory_IPAddressMonitor_CONTAINER_SIZE;
ILibIPAddressMonitor ILibIPAddressMonitor_Create(void *chain, ILibIPAddressMonitor_Handler handler, void *user);
#endif

View File

@@ -0,0 +1,444 @@
/*
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.
*/
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#if defined(WINSOCK2)
#include <winsock2.h>
#include <ws2ipdef.h>
#elif defined(WINSOCK1)
#include <winsock.h>
#include <wininet.h>
#endif
#include "ILibParsers.h"
#include "ILibAsyncUDPSocket.h"
#include "ILibAsyncSocket.h"
#define INET_SOCKADDR_LENGTH(x) ((x==AF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)))
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
struct ILibMulticastSocket_StateModule
{
ILibChain_Link ChainLink;
void *UDPServer;
void *UDPServer6;
void **UDPServers;
void *User;
void *Tag;
int TTL;
int Loopback;
unsigned short LocalPort;
ILibAsyncUDPSocket_OnData OnData;
// The IPv4 and IPv6 multicast addresses.
struct sockaddr_in MulticastAddr;
struct sockaddr_in6 MulticastAddr6;
// Lists of local IPv4 and IPv6 interfaces
struct sockaddr_in *AddressListV4;
int AddressListLengthV4;
int* IndexListV6;
int IndexListLenV6;
// Sockets used to sent and receive messages
#if defined(WIN32) || defined(_WIN32_WCE)
SOCKET NOTIFY_SEND_socks;
SOCKET NOTIFY_SEND_socks6;
#else
int NOTIFY_SEND_socks;
int NOTIFY_SEND_socks6;
#endif
};
// Received a UDP packet on the IPv4 socket, process it.
void UDPSocket_OnDataV4(ILibAsyncUDPSocket_SocketModule socketModule, char* buffer, int bufferLength, struct sockaddr_in6 *remoteInterface, void *user, void *user2, int *PAUSE)
{
struct ILibMulticastSocket_StateModule* module = (struct ILibMulticastSocket_StateModule*)user;
// Call the user
if (module->OnData != NULL) module->OnData(socketModule, buffer, bufferLength, remoteInterface, module->User, user2, PAUSE);
}
// Received a UDP packet on the IPv6 socket, process it.
void UDPSocket_OnDataV6(ILibAsyncUDPSocket_SocketModule socketModule, char* buffer, int bufferLength, struct sockaddr_in6 *remoteInterface, void *user, void *user2, int *PAUSE)
{
struct ILibMulticastSocket_StateModule* module = (struct ILibMulticastSocket_StateModule*)user;
// Remove any traffic from IPv4 mapped addresses because the IPv4 socket will take care of it.
if (ILibIsIPv4MappedAddr((struct sockaddr*)remoteInterface)) return;
// Call the user
if (module->OnData != NULL) module->OnData(socketModule, buffer, bufferLength, remoteInterface, module->User, user2, PAUSE);
}
int ILibMulticastSocket_ResetMulticast(struct ILibMulticastSocket_StateModule *module, int cleanuponly)
{
int i;
int change = 0;
struct sockaddr_in any4;
struct sockaddr_in6 any6;
int tAddressListLengthV4 = 0;
struct sockaddr_in* tAddressListV4 = NULL;
int tIndexListLenV6 = 0;
int* tIndexListV6 = NULL;
SOCKET socket;
#ifdef WINSOCK2
DWORD dwBytesReturned = 0;
BOOL bNewBehavior = FALSE;
#endif
// If this is not just cleanup, lets check to see if this operation is really needed
if (!cleanuponly)
{
tAddressListLengthV4 = ILibGetLocalIPv4AddressList(&tAddressListV4, 0);
// See if there are any changes in IPv4 interfaces
if (tAddressListLengthV4 != module->AddressListLengthV4) change = 1;
else if (tAddressListV4 == NULL && module->AddressListV4 != NULL) change = 1;
else if (tAddressListV4 != NULL && module->AddressListV4 == NULL) change = 1;
else if (tAddressListV4 != NULL && module->AddressListV4 != NULL && memcmp(tAddressListV4, module->AddressListV4, sizeof(struct sockaddr_in) * tAddressListLengthV4) != 0) change = 1;
if (module->UDPServer6 != NULL)
{
tIndexListLenV6 = ILibGetLocalIPv6IndexList(&tIndexListV6);
// See if there are any changes in IPv6 interfaces
if (tIndexListLenV6 != module->IndexListLenV6) change = 1;
else if (tIndexListV6 != NULL && module->IndexListV6 == NULL) change = 1;
else if (tIndexListV6 == NULL && module->IndexListV6 != NULL) change = 1;
else if (tIndexListV6 != NULL && module->IndexListV6 != NULL && memcmp(tIndexListV6, module->IndexListV6, sizeof(int) * tIndexListLenV6) != 0) change = 1;
}
// If change is zero, this update is not needed.
if (change == 0) { free(tAddressListV4); free(tIndexListV6); return 0; }
}
// Free the address lists
if (module->AddressListV4 != NULL) { free(module->AddressListV4); module->AddressListV4 = NULL; }
if (module->IndexListV6 != NULL) { free(module->IndexListV6); module->IndexListV6 = NULL; }
// Free the IPv4 server sockets
if (module->UDPServers != NULL)
{
for(i = 0; i < module->AddressListLengthV4; ++i) { if (module->UDPServers[i] != NULL) { ILibChain_SafeRemove(module->ChainLink.ParentChain, module->UDPServers[i]); } }
free(module->UDPServers);
module->UDPServers = NULL;
}
// If we only want to cleanup, exit now
if (cleanuponly) return 0;
// Setup Any4 address
memset(&any4, 0, sizeof(struct sockaddr_in));
any4.sin_family = AF_INET;
any4.sin_port = htons(module->LocalPort);
// Setup Any6 address
memset(&any6, 0, sizeof(struct sockaddr_in6));
any6.sin6_family = AF_INET6;
any6.sin6_port = htons(module->LocalPort);
// Join the IPv4 multicast group
if (tAddressListV4 != NULL && module->MulticastAddr.sin_family != 0)
{
// Get the list of local interfaces
module->AddressListLengthV4 = tAddressListLengthV4;
module->AddressListV4 = tAddressListV4;
if (module->AddressListLengthV4 > 0 && module->AddressListV4 != NULL)
{
if ((module->UDPServers = (void**)malloc(sizeof(void*) * module->AddressListLengthV4)) == NULL) ILIBCRITICALEXIT(254);
// Join the same multicast group on all interfaces & create interface-specific sockets
for(i = 0; i < module->AddressListLengthV4; ++i)
{
module->AddressListV4[i].sin_port = htons(module->LocalPort);
module->UDPServers[i] = ILibAsyncUDPSocket_CreateEx(module->ChainLink.ParentChain, 0, (struct sockaddr*)&(module->AddressListV4[i]), ILibAsyncUDPSocket_Reuse_SHARED, UDPSocket_OnDataV4, NULL, module);
if (module->UDPServers[i] != NULL)
{
ILibAsyncUDPSocket_JoinMulticastGroupV4(module->UDPServers[i], &(module->MulticastAddr), (struct sockaddr*)&(module->AddressListV4[i]));
ILibAsyncUDPSocket_SetLocalInterface(module->UDPServers[i], (struct sockaddr*)&(module->AddressListV4[i]));
socket = ILibAsyncUDPSocket_GetSocket(module->UDPServers[i]);
#if !defined(NACL)
if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&(module->TTL), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&(module->Loopback), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&(module->Loopback), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#endif
module->AddressListV4[i].sin_port = 0;
// This will cause the socket not to stop if sending a packet to an invalid UDP port
#ifdef WINSOCK2
WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL, NULL);
#endif
}
}
}
} else if (tAddressListV4 != NULL) free(tAddressListV4);
// Join the IPv6 multicast group
if (tIndexListLenV6 != 0 && tIndexListV6 != NULL && module->MulticastAddr6.sin6_family != 0 && module->UDPServer6 != NULL)
{
// Get the list of local interfaces
module->IndexListLenV6 = tIndexListLenV6;
module->IndexListV6 = tIndexListV6;
// Join the same multicast group on all interfaces
for(i = 0; i<module->IndexListLenV6; ++i) { ILibAsyncUDPSocket_JoinMulticastGroupV6(module->UDPServer6, &(module->MulticastAddr6), module->IndexListV6[i]); }
}
else if (tIndexListV6 != NULL) free(tIndexListV6);
return 1;
}
// Perform a local network broadcast of this packet
void ILibMulticastSocket_BroadcastUdpPacketV4(struct ILibMulticastSocket_StateModule *module, struct sockaddr_in* addr, char* data, int datalen, int count, struct sockaddr *localif)
{
int i,j;
SOCKET socket;
//printf("IPv4 Broadcasting %d bytes.\r\n", datalen);
for(i = 0; i < module->AddressListLengthV4; ++i)
{
#ifdef WINSOCK2
if (localif == NULL || ((struct sockaddr_in*)localif)->sin_addr.S_un.S_addr == module->AddressListV4[i].sin_addr.S_un.S_addr)
#else
if (localif == NULL || ((struct sockaddr_in*)localif)->sin_addr.s_addr == module->AddressListV4[i].sin_addr.s_addr)
#endif
{
if (module->NOTIFY_SEND_socks != 0)
{
#if (!defined(_WIN32_WCE) || (defined(_WIN32_WCE) && _WIN32_WCE>=400)) && !defined(NACL)
setsockopt(module->NOTIFY_SEND_socks, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&(module->AddressListV4[i].sin_addr), sizeof(struct in_addr));
for (j = 0; j < count; j++) sendto(module->NOTIFY_SEND_socks, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
#else
for (j = 0; j < count; j++) sendto(module->NOTIFY_SEND_socks, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
#endif
}
else
{
#if (!defined(_WIN32_WCE) || (defined(_WIN32_WCE) && _WIN32_WCE>=400)) && !defined(NACL)
if (module->UDPServers[i] != NULL)
{
socket = ILibAsyncUDPSocket_GetSocket(module->UDPServers[i]);
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&(module->AddressListV4[i].sin_addr), sizeof(struct in_addr));
for (j = 0; j < count; j++) sendto(socket, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
}
#else
for (j=0;j<count;j++) sendto(socket, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
#endif
}
}
}
if (i == 0)
{
if (module->NOTIFY_SEND_socks != 0)
{
struct in_addr tmp;
tmp.s_addr = addr->sin_addr.s_addr;
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
#if (!defined(_WIN32_WCE) || (defined(_WIN32_WCE) && _WIN32_WCE>=400)) && !defined(NACL)
for (j = 0; j < count; j++) sendto(module->NOTIFY_SEND_socks, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
#else
for (j = 0; j < count; j++) sendto(module->NOTIFY_SEND_socks, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
#endif
addr->sin_addr.s_addr = tmp.s_addr;
}
}
}
// Perform a local network broadcast of this packet
void ILibMulticastSocket_BroadcastUdpPacketV6(struct ILibMulticastSocket_StateModule *module, struct sockaddr_in6* addr, char* data, int datalen, int count, struct sockaddr *localif)
{
int i,j;
//printf("IPv6 Broadcasting %d bytes.\r\n", datalen);
// TODO: Consider the local interface
UNREFERENCED_PARAMETER( localif );
if (module->NOTIFY_SEND_socks6 == 0) return;
for(i = 0; i < module->IndexListLenV6; i++)
{
#if (!defined(_WIN32_WCE) || (defined(_WIN32_WCE) && _WIN32_WCE>=400)) && !defined(NACL)
setsockopt(module->NOTIFY_SEND_socks6, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char*)&(module->IndexListV6[i]), 4);
for (j=0;j<count;j++) sendto(module->NOTIFY_SEND_socks6, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in6));
#else
for (j=0;j<count;j++) sendto(module->NOTIFY_SEND_socks6, data, datalen, 0, (struct sockaddr*)addr, sizeof(struct sockaddr_in6));
#endif
}
}
// Perform network broadcast of this packet
void ILibMulticastSocket_Broadcast(struct ILibMulticastSocket_StateModule *module, char* data, int datalen, int count)
{
// Broadcast on both IPv4 and IPv6, but lets use IPv6 first.
if (module->MulticastAddr6.sin6_family != 0) ILibMulticastSocket_BroadcastUdpPacketV6(module, &(module->MulticastAddr6), data, datalen, count, NULL);
if (module->MulticastAddr.sin_family != 0) ILibMulticastSocket_BroadcastUdpPacketV4(module, &(module->MulticastAddr), data, datalen, count, NULL);
}
// Perform network broadcast of this packet on a specific local interface
void ILibMulticastSocket_BroadcastIF(struct ILibMulticastSocket_StateModule *module, char* data, int datalen, int count, struct sockaddr *localif)
{
// Broadcast on both IPv4 and IPv6, but lets use IPv6 first.
if ((localif == NULL || localif->sa_family == AF_INET6) && module->MulticastAddr6.sin6_family != 0) ILibMulticastSocket_BroadcastUdpPacketV6(module, &(module->MulticastAddr6), data, datalen, count, localif);
if ((localif == NULL || localif->sa_family == AF_INET) && module->MulticastAddr.sin_family != 0) ILibMulticastSocket_BroadcastUdpPacketV4(module, &(module->MulticastAddr), data, datalen, count, localif);
}
// Perform unicast transmit using this socket.
int ILibMulticastSocket_Unicast(struct ILibMulticastSocket_StateModule *module, struct sockaddr* target, char* data, int datalen)
{
if (target->sa_family == AF_INET6) return sendto(module->NOTIFY_SEND_socks6, data, datalen, 0, target, INET_SOCKADDR_LENGTH(target->sa_family));
if (target->sa_family == AF_INET) return sendto(module->NOTIFY_SEND_socks, data, datalen, 0, target, INET_SOCKADDR_LENGTH(target->sa_family));
return -1;
}
// Private method called when the chain is destroyed, we want to do our cleanup here
void ILibMulticastSocket_Destroy(void *object)
{
ILibMulticastSocket_ResetMulticast((struct ILibMulticastSocket_StateModule*)object, 1);
}
// Create a new MulticastSocket module. This module handles all send and receive traffic for IPv4 and IPv6 on a given multicast group.
struct ILibMulticastSocket_StateModule *ILibMulticastSocket_Create(void *Chain, int BufferSize, unsigned short LocalPort, struct sockaddr_in *MulticastAddr, struct sockaddr_in6 *MulticastAddr6, ILibAsyncUDPSocket_OnData OnData, void *user, int loopback)
{
int optval = 1;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
struct ILibMulticastSocket_StateModule* module;
UNREFERENCED_PARAMETER( BufferSize );
// Allocate the new socket state
module = (struct ILibMulticastSocket_StateModule*)malloc(sizeof(struct ILibMulticastSocket_StateModule));
if (module == NULL) { PRINTERROR(); return NULL; }
memset(module, 0, sizeof(struct ILibMulticastSocket_StateModule));
// Setup local IPv4 binding address
memset(&addr4, 0, sizeof(struct sockaddr_in));
addr4.sin_family = AF_INET;
addr4.sin_port = htons(LocalPort);
// Setup local IPv6 binding address
memset(&addr6, 0, sizeof(struct sockaddr_in6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(LocalPort);
// Setup the multicasting module
module->ChainLink.DestroyHandler = &ILibMulticastSocket_Destroy;
module->ChainLink.ParentChain = Chain;
module->LocalPort = LocalPort;
module->TTL = 4;
module->Loopback = loopback;
module->OnData = OnData;
module->User = user;
if (MulticastAddr != NULL)
{
// Setup the IPv4 multicast address
memcpy(&(module->MulticastAddr), MulticastAddr, sizeof(struct sockaddr_in));
if (module->MulticastAddr.sin_port == 0) module->MulticastAddr.sin_port = htons(LocalPort);
// Setup incoming IPv4 socket
module->UDPServer = ILibAsyncUDPSocket_CreateEx(Chain, 0, (struct sockaddr*)&addr4, ILibAsyncUDPSocket_Reuse_SHARED, UDPSocket_OnDataV4, NULL, module);
if (module->UDPServer == NULL) { free(module); PRINTERROR(); return NULL; }
// Set TTL, Reuse, Loop flags assumed to already be set
module->NOTIFY_SEND_socks = ILibAsyncUDPSocket_GetSocket(module->UDPServer);
#ifdef NACL
#else
if (setsockopt(module->NOTIFY_SEND_socks, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&(module->TTL), sizeof(int)) != 0) {ILIBCRITICALERREXIT(253);}
if (setsockopt(module->NOTIFY_SEND_socks, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&(module->Loopback), sizeof(int)) != 0) {ILIBCRITICALERREXIT(253);}
// Allow IPv4 Broadcast on this socket
if (setsockopt(module->NOTIFY_SEND_socks, SOL_SOCKET, SO_BROADCAST, (char*)&optval, 4) != 0) ILIBCRITICALERREXIT(253);
#endif
}
if (MulticastAddr6 != NULL)
{
// Setup incoming IPv6 socket
module->UDPServer6 = ILibAsyncUDPSocket_CreateEx(Chain, 0, (struct sockaddr*)&addr6, ILibAsyncUDPSocket_Reuse_SHARED, UDPSocket_OnDataV6, NULL, module);
if (module->UDPServer6 != NULL)
{
// Setup the IPv6 multicast address
memcpy(&(module->MulticastAddr6), MulticastAddr6, sizeof(struct sockaddr_in6));
if (module->MulticastAddr6.sin6_port == 0) module->MulticastAddr6.sin6_port = htons(LocalPort);
// Set TTL, IPv6, Loop and Reuse flags assumed to already be set
module->NOTIFY_SEND_socks6 = ILibAsyncUDPSocket_GetSocket(module->UDPServer6);
#ifdef NACL
#else
if (setsockopt(module->NOTIFY_SEND_socks6, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&(module->TTL), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
if (setsockopt(module->NOTIFY_SEND_socks6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&(module->Loopback), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#endif
}
}
#if !defined( NACL )
ILibMulticastSocket_ResetMulticast(module, 0);
#endif
ILibAddToChain(Chain, module);
return module;
}
void ILibSetTTL(void *vmodule, int ttl)
{
struct ILibMulticastSocket_StateModule* module = (struct ILibMulticastSocket_StateModule*)vmodule;
module->TTL = ttl;
#ifdef NACL
#else
if (module->NOTIFY_SEND_socks != 0 && setsockopt(module->NOTIFY_SEND_socks, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&(module->TTL), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
if (module->NOTIFY_SEND_socks6 != 0 && setsockopt(module->NOTIFY_SEND_socks6, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&(module->TTL), sizeof(int)) != 0) ILIBCRITICALERREXIT(253);
#endif
}
void ILibMulticastSocket_WakeOnLan(void *module, char* mac)
{
int i;
struct sockaddr_in addr4;
// Create an IPv4 broadcast address
memset(&addr4, 0, sizeof(struct sockaddr_in));
addr4.sin_family = AF_INET;
addr4.sin_port = htons(16990);
#ifdef WINSOCK2
addr4.sin_addr.S_un.S_addr = INADDR_BROADCAST; // Broadcast
#else
addr4.sin_addr.s_addr = INADDR_BROADCAST; // Broadcast
#endif
// Create the magic packet
memset(ILibScratchPad, 0xFF, 6);
for (i = 1; i < 17; i++) memcpy(ILibScratchPad + (6 * i), mac, 6);
// Send it
for (i = 0; i < 2; i++)
{
// IPv4 Broadcast, works only in the same subnet
sendto(((struct ILibMulticastSocket_StateModule*)module)->NOTIFY_SEND_socks, ILibScratchPad, 102, 0, (const struct sockaddr*)&addr4, sizeof(struct sockaddr_in));
// IPv4 & IPv6 Multicast. Only works if the machine still is subscribed to SSDP messages (S1 or S3 usualy), but has out-of-subnet range.
ILibMulticastSocket_Broadcast((struct ILibMulticastSocket_StateModule*)module, ILibScratchPad, 102, 1);
}
}

View File

@@ -0,0 +1,42 @@
/*
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.
*/
/*! \file MulticastSocket.h
\brief MicroStack APIs for UDP multicasting functionality
*/
#ifndef __ILibMulticastSocket__
#define __ILibMulticastSocket__
#include "ILibAsyncSocket.h"
#ifdef __cplusplus
extern "C" {
#endif
void *ILibMulticastSocket_Create(void *Chain, int BufferSize, unsigned short LocalPort, struct sockaddr_in *MulticastAddr, struct sockaddr_in6 *MulticastAddr6, ILibAsyncUDPSocket_OnData OnData, void *user, int loopback);
int ILibMulticastSocket_Unicast(void *module, struct sockaddr* target, char* data, int datalen);
void ILibMulticastSocket_BroadcastIF(void *module, char* data, int datalen, int count, struct sockaddr *localif);
void ILibMulticastSocket_Broadcast(void *module, char* data, int datalen, int count);
int ILibMulticastSocket_ResetMulticast(void *module, int cleanuponly);
void ILibMulticastSocket_WakeOnLan(void *module, char* mac);
void ILibSetTTL(void *module, int ttl);
#ifdef __cplusplus
}
#endif
#endif

9084
microstack/ILibParsers.c Normal file

File diff suppressed because it is too large Load Diff

1329
microstack/ILibParsers.h Normal file

File diff suppressed because it is too large Load Diff

1373
microstack/ILibProcessPipe.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
/*
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.
*/
/*! \file ILibNamedPipe.h
\brief MicroStack APIs for various functions and tasks related to named pipes
*/
#ifndef __ILibProcessPipe__
#define __ILibProcessPipe__
#include "ILibParsers.h"
typedef void* ILibProcessPipe_Manager;
typedef void* ILibProcessPipe_Process;
typedef void(*ILibProcessPipe_Process_OutputHandler)(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user);
typedef void(*ILibProcessPipe_Process_SendOKHandler)(ILibProcessPipe_Process sender, void* user);
typedef void(*ILibProcessPipe_Process_ExitHandler)(ILibProcessPipe_Process sender, int exitCode, void* user);
typedef void* ILibProcessPipe_Pipe;
typedef void(*ILibProcessPipe_Pipe_ReadHandler)(ILibProcessPipe_Pipe sender, char *buffer, int bufferLen, int* bytesConsumed);
typedef void(*ILibProcessPipe_Pipe_BrokenPipeHandler)(ILibProcessPipe_Pipe sender);
typedef enum ILibProcessPipe_SpawnTypes
{
ILibProcessPipe_SpawnTypes_DEFAULT = 0,
ILibProcessPipe_SpawnTypes_USER = 1,
ILibProcessPipe_SpawnTypes_WINLOGON = 2,
ILibProcessPipe_SpawnTypes_TERM = 3,
}ILibProcessPipe_SpawnTypes;
extern const int ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE;
#ifdef WIN32
typedef enum ILibProcessPipe_Pipe_ReaderHandleType
{
ILibProcessPipe_Pipe_ReaderHandleType_NotOverLapped = 0, //!< Spawn a I/O processing thread
ILibProcessPipe_Pipe_ReaderHandleType_Overlapped = 1 //!< Use Overlapped I/O
}ILibProcessPipe_Pipe_ReaderHandleType;
#endif
ILibTransport_DoneState ILibProcessPipe_Pipe_Write(ILibProcessPipe_Pipe writePipe, char* buffer, int bufferLen, ILibTransport_MemoryOwnership ownership);
void ILibProcessPipe_Pipe_AddPipeReadHandler(ILibProcessPipe_Pipe targetPipe, int bufferSize, ILibProcessPipe_Pipe_ReadHandler OnReadHandler);
#ifdef WIN32
ILibProcessPipe_Pipe ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(ILibProcessPipe_Manager manager, HANDLE existingPipe, ILibProcessPipe_Pipe_ReaderHandleType handleType, int extraMemorySize);
#define ILibProcessPipe_Pipe_CreateFromExisting(PipeManager, ExistingPipe, HandleType) ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(PipeManager, ExistingPipe, HandleType, 0)
#else
ILibProcessPipe_Pipe ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(ILibProcessPipe_Manager manager, int existingPipe, int extraMemorySize);
#define ILibProcessPipe_Pipe_CreateFromExisting(PipeManager, ExistingPipe) ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(PipeManager, ExistingPipe, 0)
#endif
void ILibProcessPipe_Pipe_SetBrokenPipeHandler(ILibProcessPipe_Pipe targetPipe, ILibProcessPipe_Pipe_BrokenPipeHandler handler);
ILibProcessPipe_Manager ILibProcessPipe_Manager_Create(void *chain);
ILibProcessPipe_Process ILibProcessPipe_Manager_SpawnProcessEx2(ILibProcessPipe_Manager pipeManager, char* target, char* const * parameters, ILibProcessPipe_SpawnTypes spawnType, int extraMemorySize);
#define ILibProcessPipe_Manager_SpawnProcess(pipeManager, target, parameters) ILibProcessPipe_Manager_SpawnProcessEx2(pipeManager, target, parameters, ILibProcessPipe_SpawnTypes_DEFAULT, 0)
#define ILibProcessPipe_Manager_SpawnProcessEx(pipeManager, target, parameters, spawnType) ILibProcessPipe_Manager_SpawnProcessEx2(pipeManager, target, parameters, spawnType, 0)
#define ILibProcessPipe_Manager_SpawnProcessWithExtraPipeMemory(pipeManager, target, parameters, memorySize) ILibProcessPipe_Manager_SpawnProcessEx2(pipeManager, target, parameters, ILibProcessPipe_SpawnTypes_DEFAULT, memorySize)
void* ILibProcessPipe_Process_Kill(ILibProcessPipe_Process p);
void* ILibProcessPipe_Process_KillEx(ILibProcessPipe_Process p);
void ILibProcessPipe_Process_SoftKill(ILibProcessPipe_Process p);
void ILibProcessPipe_Process_AddHandlers(ILibProcessPipe_Process module, int bufferSize, ILibProcessPipe_Process_ExitHandler exitHandler, ILibProcessPipe_Process_OutputHandler stdOut, ILibProcessPipe_Process_OutputHandler stdErr, ILibProcessPipe_Process_SendOKHandler sendOk, void *user);
void ILibProcessPipe_Process_UpdateUserObject(ILibProcessPipe_Process module, void *userObj);
ILibTransport_DoneState ILibProcessPipe_Process_WriteStdIn(ILibProcessPipe_Process p, char* buffer, int bufferLen, ILibTransport_MemoryOwnership ownership);
void ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Pipe pipeObject);
void ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Pipe pipeObject);
void ILibProcessPipe_Pipe_SwapBuffers(ILibProcessPipe_Pipe pipeObject, char* newBuffer, int newBufferLen, int newBufferReadOffset, int newBufferTotalBytesRead, char **oldBuffer, int *oldBufferLen, int *oldBufferReadOffset, int *oldBufferTotalBytesRead);
ILibProcessPipe_Pipe ILibProcessPipe_Process_GetStdErr(ILibProcessPipe_Process p);
ILibProcessPipe_Pipe ILibProcessPipe_Process_GetStdOut(ILibProcessPipe_Process p);
#ifdef WIN32
DWORD ILibProcessPipe_Process_GetPID(ILibProcessPipe_Process p);
#else
pid_t ILibProcessPipe_Process_GetPID(ILibProcessPipe_Process p);
#endif
#ifdef WIN32
typedef BOOL(*ILibProcessPipe_WaitHandle_Handler)(HANDLE event, void* user);
void ILibProcessPipe_WaitHandle_Add(ILibProcessPipe_Manager mgr, HANDLE event, void *user, ILibProcessPipe_WaitHandle_Handler callback);
void ILibProcessPipe_WaitHandle_Remove(ILibProcessPipe_Manager mgr, HANDLE event);
#endif
#define ILibTransports_ProcessPipe 0x60
#endif

View File

@@ -0,0 +1,687 @@
/*
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.
*/
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "ILibRemoteLogging.h"
#include "ILibParsers.h"
#include "ILibWebServer.h"
#include "ILibCrypto.h"
#include <stdarg.h>
char ILibScratchPad_RemoteLogging[255];
//! Converts a sockaddr to a friendly string, using static memory, for logging purposes
/*!
\param addr sockaddr to convert
\return friendly string representation (NULL Terminated)
*/
char* ILibRemoteLogging_ConvertAddress(struct sockaddr* addr)
{
ILibInet_ntop2((struct sockaddr*)addr, ILibScratchPad_RemoteLogging, sizeof(ILibScratchPad_RemoteLogging));
return(ILibScratchPad_RemoteLogging);
}
#ifdef _REMOTELOGGING
typedef struct ILibRemoteLogging_Session
{
unsigned int Flags;
void* UserContext;
}ILibRemoteLogging_Session;
typedef struct ILibRemoteLogging_Module
{
sem_t LogSyncLock;
unsigned int LogFlags;
ILibRemoteLogging_OnWrite OutputSink;
ILibRemoteLogging_OnRawForward RawForwardSink;
int RawForwardOffset;
ILibRemoteLogging_OnCommand CommandSink[15];
ILibRemoteLogging_Session Sessions[5];
}ILibRemoteLogging_Module;
void ILibRemoteLogging_Destroy(ILibRemoteLogging module)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)module;
if (obj != NULL)
{
sem_destroy(&(obj->LogSyncLock));
free(module);
}
}
void ILibRemoteLogging_CompactSessions(ILibRemoteLogging_Session sessions[], int sessionsLength)
{
int x=0,y=0;
for(x=0;x<sessionsLength;++x)
{
if(sessions[x].UserContext == NULL)
{
for(y=x+1;y<sessionsLength;++y)
{
if(sessions[y].UserContext != NULL)
{
memcpy_s(&sessions[x], sizeof(ILibRemoteLogging_Session), &sessions[y], sizeof(ILibRemoteLogging_Session));
memset(&sessions[y], 0, sizeof(ILibRemoteLogging_Session));
break;
}
}
}
}
}
void ILibRemoteLogging_RemoveUserContext(ILibRemoteLogging_Session sessions[], int sessionsLength, void *userContext)
{
int i;
for(i=0;i<sessionsLength;++i)
{
if(sessions[i].UserContext == NULL){break;}
if(sessions[i].UserContext == userContext)
{
memset(&sessions[i], 0, sizeof(ILibRemoteLogging_Session));
ILibRemoteLogging_CompactSessions(sessions, sessionsLength);
break;
}
}
}
ILibRemoteLogging_Session* ILibRemoteLogging_GetSession(ILibRemoteLogging_Session sessions[], int sessionsLength, void *userContext)
{
int i;
ILibRemoteLogging_Session *retVal = NULL;
for(i=0;i<sessionsLength;++i)
{
if(sessions[i].UserContext == NULL)
{
sessions[i].Flags = 0x00;
sessions[i].UserContext = userContext;
retVal = &sessions[i];
break;
}
else if(sessions[i].UserContext == userContext)
{
retVal = &sessions[i];
break;
}
}
return retVal;
}
void ILibRemoteLogging_LoggerCommand_Default(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, unsigned short flags, char* data, int dataLen, void *userContext)
{
int len;
char buf[72];
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "*** ILibRemoteLogging_FileTransport [No Logfile Set] ***");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
void ILibRemoteLogging_SetRawForward(ILibRemoteLogging logger, int bufferOffset, ILibRemoteLogging_OnRawForward onRawForward)
{
((ILibRemoteLogging_Module*)logger)->RawForwardSink = onRawForward;
((ILibRemoteLogging_Module*)logger)->RawForwardOffset = bufferOffset;
}
ILibRemoteLogging ILibRemoteLogging_Create(ILibRemoteLogging_OnWrite onOutput)
{
ILibRemoteLogging_Module *retVal;
if((retVal = (ILibRemoteLogging_Module*)malloc(sizeof(ILibRemoteLogging_Module)))==NULL) {ILIBCRITICALEXIT(254);}
memset(retVal, 0, sizeof(ILibRemoteLogging_Module));
sem_init(&(retVal->LogSyncLock), 0, 1);
retVal->OutputSink = onOutput;
ILibRemoteLogging_RegisterCommandSink(retVal, ILibRemoteLogging_Modules_Logger, ILibRemoteLogging_LoggerCommand_Default);
return retVal;
}
void ILibRemoteLogging_RegisterCommandSink(ILibRemoteLogging logger, ILibRemoteLogging_Modules module, ILibRemoteLogging_OnCommand sink)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)logger;
sem_wait(&(obj->LogSyncLock));
obj->CommandSink[ILibWhichPowerOfTwo((int)module)] = sink;
sem_post(&(obj->LogSyncLock));
}
void ILibRemoteLogging_DeleteUserContext(ILibRemoteLogging logger, void *userContext)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)logger;
if (obj == NULL) { return; }
sem_wait(&(obj->LogSyncLock));
ILibRemoteLogging_RemoveUserContext(obj->Sessions, sizeof(obj->Sessions) / sizeof(ILibRemoteLogging_Session), userContext);
sem_post(&(obj->LogSyncLock));
}
//! Converts binary data into a hex string, using static memory, for logging purposes
/*!
\param inVal Binary data to convert
\param inValLength Binary data length
\return hex string representation of binary data (NULL Terminated)
*/
char* ILibRemoteLogging_ConvertToHex(char* inVal, int inValLength)
{
util_tohex(inVal, inValLength<255?inValLength:254, ILibScratchPad_RemoteLogging);
return(ILibScratchPad_RemoteLogging);
}
void ILibRemoteLogging_SendCommand(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *data, int dataLen, void *userContext)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)loggingModule;
char dest[4096];
if(obj->OutputSink != NULL && ((dataLen + 4) < 4096))
{
((unsigned short*)dest)[0] = htons(module);
((unsigned short*)dest)[1] = htons(flags);
if(dataLen > 0) {memcpy_s(dest+4, sizeof(dest) - 4, data, dataLen);}
obj->OutputSink(loggingModule, dest, 4+dataLen, userContext);
}
}
//! Logging method using printf notation
/*!
\b NOTE: NO-OP if there is no connected viewers
\param loggingModule ILibRemoteLogging Logging Module
\param module ILibRemoteLogging_Modules Describing the source of the message
\param flags ILibRemoteLogging_Flags Logging Flags
\param format printf Format String
\param ... Optional parameters
*/
void ILibRemoteLogging_printf(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char* format, ...)
{
int i;
char dest[4096];
int len;
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)loggingModule;
va_list argptr;
if (obj != NULL && obj->RawForwardSink != NULL)
{
// When Forwarding, TimeStamp will be added later
len = obj->RawForwardOffset;
}
else
{
// Add TimeStamp to Log
len = ILibGetLocalTime(dest + 4, (int)sizeof(dest) - 4);
dest[len + 4] = ':';
dest[len + 5] = ' ';
len += 2;
len += 4; // Space for header (which isn't needed when forwarding)
}
va_start(argptr, format);
len += vsnprintf(dest+len, 4096 - len, format, argptr);
va_end(argptr);
if (obj != NULL && obj->RawForwardSink != NULL)
{
obj->RawForwardSink(obj, module, flags, dest, len);
}
else if(obj != NULL && obj->OutputSink != NULL)
{
((unsigned short*)dest)[0] = htons((unsigned short)module | (unsigned short)0x8000);
((unsigned short*)dest)[1] = htons(flags);
if ((module & ILibRemoteLogging_Modules_ConsolePrint) == ILibRemoteLogging_Modules_ConsolePrint) { printf("%s\n", dest + 4); }
sem_wait(&(obj->LogSyncLock));
for(i=0;i<(sizeof(obj->Sessions)/sizeof(ILibRemoteLogging_Session)); ++i)
{
if(obj->Sessions[i].UserContext == NULL) {break;} // No more Sessions
if((obj->Sessions[i].Flags & (unsigned int)module) == 0) {continue;} // Logging for this module is not enabled
if(((obj->Sessions[i].Flags >> 16) & 0x3E) < (unsigned short)flags) {continue;} // Verbosity is not high enough
sem_post(&(obj->LogSyncLock));
obj->OutputSink(obj, dest, len, obj->Sessions[i].UserContext);
sem_wait(&(obj->LogSyncLock));
}
sem_post(&(obj->LogSyncLock));
}
else if (obj == NULL && (module & ILibRemoteLogging_Modules_ConsolePrint) == ILibRemoteLogging_Modules_ConsolePrint)
{
printf("%s\n", dest + 4);
}
}
void ILibRemoteLogging_Dispatch_Update(ILibRemoteLogging_Module *obj, unsigned short module, char* updateString, void *userContext)
{
char temp[255];
int tempLen;
tempLen = ILibGetLocalTime((char*)temp, (int)sizeof(temp));
temp[tempLen] = ':';
temp[tempLen + 1] = ' ';
tempLen += 2;
if((module & ILibRemoteLogging_Modules_WebRTC_STUN_ICE) == ILibRemoteLogging_Modules_WebRTC_STUN_ICE)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "WebRTC Module: STUN/ICE [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_WebRTC_STUN_ICE | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if((module & ILibRemoteLogging_Modules_WebRTC_DTLS) == ILibRemoteLogging_Modules_WebRTC_DTLS)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "WebRTC Module: DTLS [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_WebRTC_DTLS | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if((module & ILibRemoteLogging_Modules_WebRTC_SCTP) == ILibRemoteLogging_Modules_WebRTC_SCTP)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "WebRTC Module: SCTP [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_WebRTC_SCTP | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Agent_GuardPost) == ILibRemoteLogging_Modules_Agent_GuardPost)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Agent Module: GuardPost [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Agent_GuardPost | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Agent_P2P) == ILibRemoteLogging_Modules_Agent_P2P)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Agent Module: Peer2Peer [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Agent_P2P | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Microstack_AsyncSocket) == ILibRemoteLogging_Modules_Microstack_AsyncSocket)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Microstack Module: AsyncSocket [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Microstack_AsyncSocket | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Microstack_Web) == ILibRemoteLogging_Modules_Microstack_Web)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Microstack Module: WebServer/Client [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Microstack_Web | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Microstack_Generic) == ILibRemoteLogging_Modules_Microstack_Generic)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Microstack Module: Generic [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Microstack_Generic | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Agent_KVM) == ILibRemoteLogging_Modules_Agent_KVM)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Agent Module: KVM [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Agent_KVM | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
if ((module & ILibRemoteLogging_Modules_Microstack_Pipe) == ILibRemoteLogging_Modules_Microstack_Pipe)
{
tempLen += sprintf_s(temp + tempLen, sizeof(temp) - tempLen, "Microstack Module: NamedPipe [%s]", updateString);
ILibRemoteLogging_SendCommand(obj, (ILibRemoteLogging_Modules)(ILibRemoteLogging_Modules_Microstack_Pipe | 0x8000), ILibRemoteLogging_Flags_VerbosityLevel_1, temp, tempLen, userContext);
}
}
int ILibRemoteLogging_IsModuleSet(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules module)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)loggingModule;
int i;
int retVal = 0;
sem_wait(&(obj->LogSyncLock));
for (i = 0; i < sizeof(obj->Sessions) / sizeof(ILibRemoteLogging_Session); ++i)
{
if (obj->Sessions[i].UserContext == NULL) { break; }
if ((obj->Sessions[i].Flags & (unsigned int)module) == (unsigned int)module) { retVal = 1; break; }
}
sem_post(&(obj->LogSyncLock));
return retVal;
}
void ILibRemoteLogging_Forward(ILibRemoteLogging loggingModule, char* data, int dataLen)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)loggingModule;
int i;
if (obj->OutputSink == NULL) { return; }
sem_wait(&(obj->LogSyncLock));
for (i = 0; i < sizeof(obj->Sessions) / sizeof(ILibRemoteLogging_Session); ++i)
{
if (obj->Sessions[i].UserContext == NULL) { sem_post(&(obj->LogSyncLock)); return; }
sem_post(&(obj->LogSyncLock));
obj->OutputSink(obj, data, dataLen, obj->Sessions[i].UserContext);
sem_wait(&(obj->LogSyncLock));
}
sem_post(&(obj->LogSyncLock));
}
int ILibRemoteLogging_Dispatch(ILibRemoteLogging loggingModule, char* data, int dataLen, void *userContext)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)loggingModule;
unsigned short module;
unsigned short flags;
ILibRemoteLogging_Session *session = NULL;
if(dataLen == 0 || userContext == NULL)
{
return 1;
}
module = ILibRemoteLogging_ReadModuleType(data);
flags = ILibRemoteLogging_ReadFlags(data);
sem_wait(&(obj->LogSyncLock));
session = ILibRemoteLogging_GetSession(obj->Sessions, sizeof(obj->Sessions) / sizeof(ILibRemoteLogging_Session), userContext);
if(session == NULL) {sem_post(&(obj->LogSyncLock)); return 1;} // Too many users
if((flags & 0x3F) != 0x00)
{
// Change Verbosity of Logs
if((flags & 0x01) == 0x01)
{
// Disable Modules
session->Flags &= (0xFFFFFFFF ^ module);
sem_post(&(obj->LogSyncLock));
ILibRemoteLogging_Dispatch_Update(obj, module, "DISABLED", userContext);
}
else
{
// Enable Modules and Set Verbosity
session->Flags &= 0xFFC0FFFF; // Reset Verbosity Flags
session->Flags |= (flags << 16); // Set Verbosity Flags
session->Flags |= (unsigned int)module; // Enable Modules
sem_post(&(obj->LogSyncLock));
ILibRemoteLogging_Dispatch_Update(obj, module, "ENABLED", userContext);
}
}
else if(module != 0x00)
{
// Module Specific Commands
ILibRemoteLogging_OnCommand command = obj->CommandSink[ILibWhichPowerOfTwo((int)module)];
sem_post(&(obj->LogSyncLock));
if(command!=NULL)
{
command(loggingModule, (ILibRemoteLogging_Modules)module, flags, data+4, dataLen-4, userContext);
}
}
else
{
sem_post(&(obj->LogSyncLock));
}
return 0;
}
typedef struct ILibRemoteLogging_FileTransport
{
ILibTransport transport;
ILibLinkedList_FileBacked_Root *logFile;
char* localFilePath;
int enabled;
ILibRemoteLogging_Module* parent;
}ILibRemoteLogging_FileTransport;
ILibTransport_DoneState ILibFileTransport_SendSink(void *transport, char* buffer, int bufferLength, ILibTransport_MemoryOwnership ownership, ILibTransport_DoneState done)
{
ILibRemoteLogging_FileTransport *ft = (ILibRemoteLogging_FileTransport*)transport;
if (ft->logFile != NULL && ft->enabled != 0)
{
ILibLinkedList_FileBacked_AddTail(ft->logFile, buffer, bufferLength);
}
return(ILibTransport_DoneState_COMPLETE);
}
unsigned int ILibFileTransport_PendingBytes(void *transport)
{
UNREFERENCED_PARAMETER(transport);
return 0;
}
void ILibFileTransport_CloseSink(void* transport)
{
ILibRemoteLogging_FileTransport *ft = (ILibRemoteLogging_FileTransport*)transport;
ILibRemoteLogging_DeleteUserContext(ft->parent, transport);
if (ft->logFile != NULL) { ILibLinkedList_FileBacked_Close(ft->logFile); }
if (ft->localFilePath != NULL) { free(ft->localFilePath); }
free(transport);
}
int ILibRemoteLogging_FileTransport_ReadLogs(ILibRemoteLogging_FileTransport* ft, void *userContext)
{
ILibLinkedList_FileBacked_Node *node = NULL;
if (ILibLinkedList_FileBacked_IsEmpty(ft->logFile) != 0)
{
// No log entries
return 1;
}
while ((node = ILibLinkedList_FileBacked_ReadNext(ft->logFile, node)) != NULL)
{
ILibTransport_Send(userContext, node->data, node->dataLen, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
return 0;
}
void ILibRemoteLogging_FileTransport_Report(void* userContext, ILibRemoteLogging_FileTransport *ft)
{
int len;
char buf[72];
unsigned short newModules = 0;
unsigned short flags = 0;
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
if (ft->logFile == NULL)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "*** ILibRemoteLogging_FileTransport [No Logfile Set] ***");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
return;
}
ILibLinkedList_FileBacked_ReloadRoot(ft->logFile);
newModules = (unsigned short)(ft->logFile->flags & 0xFFFF);
flags = (unsigned short)((ft->logFile->flags >> 16) & 0x3F);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "*** Verbosity = %d ***", ILibWhichPowerOfTwo((int)flags));
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
if ((newModules & ILibRemoteLogging_Modules_WebRTC_STUN_ICE) == ILibRemoteLogging_Modules_WebRTC_STUN_ICE)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...WebRTC [STUN/ICE]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_WebRTC_DTLS) == ILibRemoteLogging_Modules_WebRTC_DTLS)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...WebRTC [DTLS]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_WebRTC_SCTP) == ILibRemoteLogging_Modules_WebRTC_SCTP)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...WebRTC [SCTP]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Agent_GuardPost) == ILibRemoteLogging_Modules_Agent_GuardPost)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...MeshAgent [GUARDPOST]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Agent_KVM) == ILibRemoteLogging_Modules_Agent_KVM)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...MeshAgent [KVM]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Agent_P2P) == ILibRemoteLogging_Modules_Agent_P2P)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...MeshAgent [P2P]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Microstack_AsyncSocket) == ILibRemoteLogging_Modules_Microstack_AsyncSocket)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...Microstack [AsyncSocket]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Microstack_Web) == ILibRemoteLogging_Modules_Microstack_Web)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...Microstack [WebServer]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Microstack_Pipe) == ILibRemoteLogging_Modules_Microstack_Pipe)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...Microstack [Pipe]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
if ((newModules & ILibRemoteLogging_Modules_Microstack_Generic) == ILibRemoteLogging_Modules_Microstack_Generic)
{
len = sprintf_s(buf + 4, sizeof(buf) - 4, "...Microstack [Generic]");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
}
void ILibRemoteLogging_FileTransport_CommandSink(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, unsigned short flags, char* data, int dataLen, void *userContext)
{
ILibRemoteLogging_Module *obj = (ILibRemoteLogging_Module*)sender;
int i, len;
char buf[72];
sem_wait(&(obj->LogSyncLock));
for (i = 0; i < (sizeof(obj->Sessions) / sizeof(ILibRemoteLogging_Session)); ++i)
{
if (obj->Sessions[i].UserContext == NULL) { break; } // End of Sessions
if (((ILibTransport*)obj->Sessions[i].UserContext)->IdentifierFlags == ILibTransports_RemoteLogging_FileTransport)
{
ILibRemoteLogging_FileTransport *ft = (ILibRemoteLogging_FileTransport*)obj->Sessions[i].UserContext;
// This command applies to this type of ILibTransport
if ((flags & ILibRemoteLogging_Command_Logger_Flags_ENABLE) == ILibRemoteLogging_Command_Logger_Flags_ENABLE)
{
switch (data[0])
{
case 0:
case 1:
// Enable/Disable
ILibLinkedList_FileBacked_ReloadRoot(ft->logFile);
ft->logFile->flags &= (unsigned int)0x7FFFFFFF;
ft->enabled = data[0];
if (ft->enabled != 0)
{
ft->logFile->flags |= (unsigned int)0x80000000;
}
ILibLinkedList_FileBacked_SaveRoot(ft->logFile);
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "ILibRemoteLogging_FileTransport [%s]", ft->enabled == 0 ? "DISABLED" : "ENABLED");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
if (ft->enabled != 0)
{
ILibRemoteLogging_FileTransport_Report(userContext, ft);
}
break;
case 3:
// Return the current state
((unsigned short*)buf)[0] = htons(ILibRemoteLogging_Modules_Logger);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Command_Logger_Flags_ENABLE);
buf[4] = ft->enabled == 0 ? 0 : 1;
ILibTransport_Send(userContext, buf, 5, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
if (ft->enabled != 0)
{
ILibRemoteLogging_FileTransport_Report(userContext, ft);
}
break;
default:
break;
}
}
if ((flags & ILibRemoteLogging_Command_Logger_Flags_READ_FILE) == ILibRemoteLogging_Command_Logger_Flags_READ_FILE)
{
if (ILibRemoteLogging_FileTransport_ReadLogs(ft, userContext) != 0)
{
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "ILibRemoteLogging_FileTransport: (No Log Entries)");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
}
if ((flags & ILibRemoteLogging_Command_Logger_Flags_RESET_FILE) == ILibRemoteLogging_Command_Logger_Flags_RESET_FILE)
{
// Clear the Log File
if (ft->logFile != NULL)
{
ILibLinkedList_FileBacked_Reset(ft->logFile);
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "ILibRemoteLogging_FileTransport: (Logfile was reset)");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
else
{
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "ILibRemoteLogging_FileTransport: (No Log File)");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
}
}
if ((flags & ILibRemoteLogging_Command_Logger_Flags_RESET_FLAGS) == ILibRemoteLogging_Command_Logger_Flags_RESET_FLAGS)
{
if (dataLen == 4 && ft->logFile != NULL)
{
unsigned short newModules = ntohs(((unsigned short*)data)[0]);
unsigned short newFlags = ntohs(((unsigned short*)data)[1]);
obj->Sessions[i].Flags = (newFlags & 0x3F) << 16;
obj->Sessions[i].Flags |= (unsigned int)newModules;
ILibLinkedList_FileBacked_ReloadRoot(ft->logFile);
ft->logFile->flags = (unsigned int)ft->enabled << 31;
ft->logFile->flags |= (obj->Sessions[i].Flags & 0x7FFFFFFF);
ILibLinkedList_FileBacked_SaveRoot(ft->logFile);
((unsigned short*)buf)[0] = htons((unsigned short)ILibRemoteLogging_Modules_Logger | (unsigned short)0x8000);
((unsigned short*)buf)[1] = htons(ILibRemoteLogging_Flags_VerbosityLevel_1);
len = sprintf_s(buf + 4, sizeof(buf) - 4, "ILibRemoteLogging_FileTransport: (LogFile Flags RESET)");
ILibTransport_Send(userContext, buf, len + 4, ILibTransport_MemoryOwnership_USER, ILibTransport_DoneState_COMPLETE);
ILibRemoteLogging_FileTransport_Report(userContext, ft);
}
}
}
}
sem_post(&(obj->LogSyncLock));
}
ILibTransport* ILibRemoteLogging_CreateFileTransport(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules modules, ILibRemoteLogging_Flags flags, char* path, int pathLen)
{
ILibRemoteLogging_FileTransport *retVal = ILibMemory_Allocate(sizeof(ILibRemoteLogging_FileTransport), 0, NULL, NULL);
char data[4];
if (pathLen < 0) { pathLen = (int)strnlen_s(path, _MAX_PATH); }
retVal->transport.IdentifierFlags = (int)ILibTransports_RemoteLogging_FileTransport;
retVal->transport.SendPtr = ILibFileTransport_SendSink;
retVal->transport.PendingBytesPtr = ILibFileTransport_PendingBytes;
retVal->transport.ClosePtr = ILibFileTransport_CloseSink;
retVal->parent = (ILibRemoteLogging_Module*)loggingModule;
retVal->localFilePath = ILibString_Copy(path, pathLen);
retVal->logFile = ILibLinkedList_FileBacked_Create(retVal->localFilePath, 2048000, 4096);
if (retVal->logFile->flags != 0)
{
modules = (unsigned short)(retVal->logFile->flags & 0xFFFF);
flags = (unsigned short)(retVal->logFile->flags >> 16);
retVal->enabled = ((flags & 0x8000) == 0x8000) ? 1 : 0;
}
((unsigned short*)data)[0] = htons((unsigned short)modules);
((unsigned short*)data)[1] = htons((unsigned short)flags & (unsigned short)0x3F);
ILibRemoteLogging_Dispatch(loggingModule, data, (int)sizeof(data), retVal);
ILibRemoteLogging_RegisterCommandSink(loggingModule, ILibRemoteLogging_Modules_Logger, ILibRemoteLogging_FileTransport_CommandSink);
return((ILibTransport*)retVal);
}
#endif

View File

@@ -0,0 +1,103 @@
/*
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.
*/
#ifndef __ILIBREMOTELOGGING__
#define __ILIBREMOTELOGGING__
#include "ILibParsers.h"
/*! \defgroup ILibRemoteLogging ILibRemoteLogging Module
@{
*/
//! Module Types
typedef enum ILibRemoteLogging_Modules
{
ILibRemoteLogging_Modules_UNKNOWN = 0x00, //!< UNKNOWN Module
ILibRemoteLogging_Modules_Logger = 0x01, //!< RESERVED: Logger
ILibRemoteLogging_Modules_WebRTC_STUN_ICE = 0x02, //!< WebRTC: STUN/ICE
ILibRemoteLogging_Modules_WebRTC_DTLS = 0x04, //!< WebRTC: DTLS
ILibRemoteLogging_Modules_WebRTC_SCTP = 0x08, //!< WebRTC: SCTP
ILibRemoteLogging_Modules_Agent_GuardPost = 0x10, //!< Mesh Agent: Guard Post
ILibRemoteLogging_Modules_Agent_P2P = 0x20, //!< Mesh Agent: Peer to Peer
ILibRemoteLogging_Modules_Agent_KVM = 0x200, //!< Mesh AGent: KVM
ILibRemoteLogging_Modules_Microstack_AsyncSocket = 0x40, //!< Microstack: AsyncSocket, AsyncServerSocket, AsyncUDPSocket
ILibRemoteLogging_Modules_Microstack_Web = 0x80, //!< Microstack: WebServer, WebSocket, WebClient
ILibRemoteLogging_Modules_Microstack_Pipe = 0x400,//!< Microstack: Pipe
ILibRemoteLogging_Modules_Microstack_Generic = 0x100,//!< Microstack: Generic
ILibRemoteLogging_Modules_ConsolePrint = 0x4000
}ILibRemoteLogging_Modules;
//! Logging Flags
typedef enum ILibRemoteLogging_Flags
{
ILibRemoteLogging_Flags_NONE = 0x00, //!< NONE
ILibRemoteLogging_Flags_DisableLogging = 0x01, //!< DISABLED
ILibRemoteLogging_Flags_VerbosityLevel_1 = 0x02, //!< Verbosity Level 1
ILibRemoteLogging_Flags_VerbosityLevel_2 = 0x04, //!< Verbosity Level 2
ILibRemoteLogging_Flags_VerbosityLevel_3 = 0x08, //!< Verbosity Level 3
ILibRemoteLogging_Flags_VerbosityLevel_4 = 0x10, //!< Verbosity Level 4
ILibRemoteLogging_Flags_VerbosityLevel_5 = 0x20, //!< Verbosity Level 5
}ILibRemoteLogging_Flags;
typedef enum ILibRemoteLogging_Command_Logger_Flags
{
ILibRemoteLogging_Command_Logger_Flags_ENABLE = 0x100, //!< Enables/Disables File Logging
ILibRemoteLogging_Command_Logger_Flags_RESET_FILE = 0x200, //!< Erases the log file
ILibRemoteLogging_Command_Logger_Flags_READ_FILE = 0x400, //!< Reads the log file
ILibRemoteLogging_Command_Logger_Flags_RESET_FLAGS = 0x800, //!< Sets the Module/Flags to log to file
}ILibRemoteLogging_Command_Logger_Flags;
#define ILibTransports_RemoteLogging_FileTransport 0x70
typedef void* ILibRemoteLogging;
typedef void (*ILibRemoteLogging_OnWrite)(ILibRemoteLogging module, char* data, int dataLen, void *userContext);
typedef void (*ILibRemoteLogging_OnCommand)(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, unsigned short flags, char* data, int dataLen, void *userContext);
typedef void(*ILibRemoteLogging_OnRawForward)(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *buffer, int bufferLen);
char* ILibRemoteLogging_ConvertAddress(struct sockaddr* addr);
#ifdef _REMOTELOGGING
char* ILibRemoteLogging_ConvertToHex(char* inVal, int inValLength);
void ILibRemoteLogging_printf(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char* format, ...);
ILibRemoteLogging ILibRemoteLogging_Create(ILibRemoteLogging_OnWrite onOutput);
ILibTransport* ILibRemoteLogging_CreateFileTransport(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules modules, ILibRemoteLogging_Flags flags, char* path, int pathLen);
void ILibRemoteLogging_Destroy(ILibRemoteLogging logger);
void ILibRemoteLogging_SetRawForward(ILibRemoteLogging logger, int bufferOffset, ILibRemoteLogging_OnRawForward onRawForward);
void ILibRemoteLogging_DeleteUserContext(ILibRemoteLogging logger, void *userContext);
void ILibRemoteLogging_RegisterCommandSink(ILibRemoteLogging logger, ILibRemoteLogging_Modules module, ILibRemoteLogging_OnCommand sink);
int ILibRemoteLogging_Dispatch(ILibRemoteLogging loggingModule, char* data, int dataLen, void *userContext);
#define ILibRemoteLogging_ReadModuleType(data) ((ILibRemoteLogging_Modules)ntohs(((unsigned short*)data)[0]))
#define ILibRemoteLogging_ReadFlags(data) ((ILibRemoteLogging_Flags)ntohs(((unsigned short*)data)[1]))
int ILibRemoteLogging_IsModuleSet(ILibRemoteLogging loggingModule, ILibRemoteLogging_Modules module);
void ILibRemoteLogging_Forward(ILibRemoteLogging loggingModule, char* data, int dataLen);
#else
#define ILibRemoteLogging_ConvertToHex(...) ;
#define ILibRemoteLogging_printf(...) ;
#define ILibRemoteLogging_Create(...) NULL;
#define ILibRemoteLogging_SetRawForward(...) ;
#define ILibRemoteLogging_CreateFileTransport(...) NULL;
#define ILibRemoteLogging_Destroy(...) ;
#define ILibRemoteLogging_DeleteUserContext(...) ;
#define ILibRemoteLogging_RegisterCommandSink(...) ;
#define ILibRemoteLogging_Dispatch(...) ;
#define ILibRemoteLogging_ReadModuleType(data) ILibRemoteLogging_Modules_UNKNOWN
#define ILibRemoteLogging_ReadFlags(data) ILibRemoteLogging_Flags_NONE
#define ILibRemoteLogging_IsModuleSet(...) 0
#define ILibRemoteLogging_Forward(...) ;
#endif
/*! @} */
#endif

View File

@@ -0,0 +1,450 @@
/*
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 "ILibSimpleDataStore.h"
#include "ILibCrypto.h"
#ifndef WIN32
#include <sys/file.h>
#endif
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#define SHA256HASHSIZE 32
#ifdef _WIN64
#define ILibSimpleDataStore_GetPosition(filePtr) _ftelli64(filePtr)
#define ILibSimpleDataStore_SeekPosition(filePtr, position, seekMode) _fseeki64(filePtr, position, seekMode)
typedef long long DS_Long;
#else
#define ILibSimpleDataStore_GetPosition(filePtr) ftell(filePtr)
#define ILibSimpleDataStore_SeekPosition(filePtr, position, seekMode) fseek(filePtr, position, seekMode)
typedef long DS_Long;
#endif
typedef struct ILibSimpleDataStore_Root
{
FILE* dataFile;
char* filePath;
char scratchPad[4096];
ILibHashtable keyTable; // keys --> ILibSimpleDataStore_TableEntry
DS_Long fileSize;
int error;
} ILibSimpleDataStore_Root;
/* File Format
------------------------------------------
4 Bytes - Node size
4 Bytes - Key length
4 Bytes - Value length
32 Bytes - SHA256 hash check value
Variable - Key
Variable - Value
------------------------------------------ */
typedef struct ILibSimpleDataStore_RecordHeader
{
int nodeSize;
int keyLen;
int valueLength;
char hash[SHA256HASHSIZE];
} ILibSimpleDataStore_RecordHeader;
typedef struct ILibSimpleDataStore_RecordNode
{
int nodeSize;
int keyLen;
int valueLength;
char valueHash[SHA256HASHSIZE];
DS_Long valueOffset;
char key[];
} ILibSimpleDataStore_RecordNode;
typedef struct ILibSimpleDataStore_TableEntry
{
int valueLength;
char valueHash[SHA256HASHSIZE];
DS_Long valueOffset;
} ILibSimpleDataStore_TableEntry;
const int ILibMemory_SimpleDataStore_CONTAINERSIZE = sizeof(ILibSimpleDataStore_Root);
// Perform a SHA256 hash of some data
void ILibSimpleDataStore_SHA256(char *data, int datalen, char* result) { util_sha256(data, datalen, result); }
// Write a key/value pair to file, the hash is already calculated
DS_Long ILibSimpleDataStore_WriteRecord(FILE *f, char* key, int keyLen, char* value, int valueLen, char* hash)
{
char headerBytes[sizeof(ILibSimpleDataStore_RecordNode)];
ILibSimpleDataStore_RecordHeader *header = (ILibSimpleDataStore_RecordHeader*)headerBytes;
DS_Long offset;
fseek(f, 0, SEEK_END);
header->nodeSize = htonl(sizeof(ILibSimpleDataStore_RecordNode) + keyLen + valueLen);
header->keyLen = htonl(keyLen);
header->valueLength = htonl(valueLen);
if (hash != NULL) { memcpy_s(header->hash, sizeof(header->hash), hash, SHA256HASHSIZE); } else { memset(header->hash, 0, SHA256HASHSIZE); }
if (fwrite(headerBytes, 1, sizeof(ILibSimpleDataStore_RecordNode), f)) {}
if (fwrite(key, 1, keyLen, f)) {}
offset = ILibSimpleDataStore_GetPosition(f);
if (value != NULL) { if (fwrite(value, 1, valueLen, f)) {} }
fflush(f);
return offset;
}
// Read the next record in the file
ILibSimpleDataStore_RecordNode* ILibSimpleDataStore_ReadNextRecord(ILibSimpleDataStore_Root *root)
{
SHA256_CTX c;
char data[4096];
char result[SHA256HASHSIZE];
int i, bytesLeft;
ILibSimpleDataStore_RecordNode *node = (ILibSimpleDataStore_RecordNode*)(root->scratchPad );
// If the current position is the end of the file, exit now.
if (ILibSimpleDataStore_GetPosition(root->dataFile) == root->fileSize) { return NULL; }
// Read sizeof(ILibSimpleDataStore_RecordNode) bytes to get record Size
i = (int)fread((void*)node, 1, sizeof(ILibSimpleDataStore_RecordNode), root->dataFile);
if (i < sizeof(ILibSimpleDataStore_RecordNode)) { return NULL; }
// Correct the struct, valueHash stays the same
node->nodeSize = (int)ntohl(node->nodeSize);
node->keyLen = (int)ntohl(node->keyLen);
node->valueLength = (int)ntohl(node->valueLength);
node->valueOffset = ILibSimpleDataStore_GetPosition(root->dataFile) + (DS_Long)node->keyLen;
// Read the key name
i = (int)fread((char*)node + sizeof(ILibSimpleDataStore_RecordNode), 1, node->keyLen, root->dataFile);
if (i != node->keyLen) { return NULL; } // Reading Key Failed
// Validate Data, in 4k chunks at a time
bytesLeft = node->valueLength;
// Hash SHA256 the data
SHA256_Init(&c);
while (bytesLeft > 0)
{
i = (int)fread(data, 1, bytesLeft > 4096 ? 4096 : bytesLeft, root->dataFile);
if (i <= 0) { bytesLeft = 0; break; }
SHA256_Update(&c, data, i);
bytesLeft -= i;
}
SHA256_Final((unsigned char*)result, &c);
if (node->valueLength > 0)
{
// Check the hash
if (memcmp(node->valueHash, result, SHA256HASHSIZE) == 0) {
return node; // Data is correct
}
return NULL; // Data is corrupt
}
else
{
return(node);
}
}
// ???
void ILibSimpleDataStore_TableClear_Sink(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
{
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(Key1);
UNREFERENCED_PARAMETER(Key2);
UNREFERENCED_PARAMETER(Key2Len);
UNREFERENCED_PARAMETER(user);
free(Data);
}
// Rebuild the in-memory key to record table, done when starting up the data store
void ILibSimpleDataStore_RebuildKeyTable(ILibSimpleDataStore_Root *root)
{
ILibSimpleDataStore_RecordNode *node = NULL;
ILibSimpleDataStore_TableEntry *entry;
ILibHashtable_ClearEx(root->keyTable, ILibSimpleDataStore_TableClear_Sink, root); // Wipe the key table, we will rebulit it
fseek(root->dataFile, 0, SEEK_SET); // See the start of the file
root->fileSize = -1; // Indicate we can't write to the data store
// Start reading records
while ((node = ILibSimpleDataStore_ReadNextRecord(root)) != NULL)
{
// Get the entry from the memory table
entry = (ILibSimpleDataStore_TableEntry*)ILibHashtable_Get(root->keyTable, NULL, node->key, node->keyLen);
if (node->valueLength > 0)
{
// If the value is not empty, we need to create/overwrite this value in memory
if (entry == NULL) { entry = (ILibSimpleDataStore_TableEntry*)ILibMemory_Allocate(sizeof(ILibSimpleDataStore_TableEntry), 0, NULL, NULL); }
memcpy_s(entry->valueHash, sizeof(entry->valueHash), node->valueHash, SHA256HASHSIZE);
entry->valueLength = node->valueLength;
entry->valueOffset = node->valueOffset;
ILibHashtable_Put(root->keyTable, NULL, node->key, node->keyLen, entry);
}
else if (entry != NULL)
{
// If value is empty, remove the in-memory entry.
ILibHashtable_Remove(root->keyTable, NULL, node->key, node->keyLen);
free(entry);
}
}
// Set the size of the entire data store file
root->fileSize = ILibSimpleDataStore_GetPosition(root->dataFile);
}
// Open the data store file
FILE* ILibSimpleDataStore_OpenFileEx(char* filePath, int forceTruncateIfNonZero)
{
FILE* f = NULL;
#ifdef WIN32
if (forceTruncateIfNonZero !=0 || fopen_s(&f, filePath, "rb+N") != 0)
{
fopen_s(&f, filePath, "wb+N");
}
#else
if (forceTruncateIfNonZero != 0 || (f = fopen(filePath, "rb+")) == NULL)
{
f = fopen(filePath, "wb+");
}
if (flock(fileno(f), LOCK_EX | LOCK_NB) != 0) { fclose(f); return NULL; } // Request exclusive lock on this file, no blocking.
#endif
return f;
}
#define ILibSimpleDataStore_OpenFile(filePath) ILibSimpleDataStore_OpenFileEx(filePath, 0)
// Open the data store file. Optionally allocate spare user memory
__EXPORT_TYPE ILibSimpleDataStore ILibSimpleDataStore_CreateEx(char* filePath, int userExtraMemorySize)
{
ILibSimpleDataStore_Root* retVal = (ILibSimpleDataStore_Root*)ILibMemory_Allocate(ILibMemory_SimpleDataStore_CONTAINERSIZE, userExtraMemorySize, NULL, NULL);
retVal->filePath = ILibString_Copy(filePath, (int)strnlen_s(filePath, ILibSimpleDataStore_MaxFilePath));
retVal->dataFile = ILibSimpleDataStore_OpenFile(retVal->filePath);
if (retVal->dataFile == NULL)
{
free(retVal->filePath);
free(retVal);
return NULL;
}
retVal->keyTable = ILibHashtable_Create();
ILibSimpleDataStore_RebuildKeyTable(retVal);
return retVal;
}
// Close the data store file
__EXPORT_TYPE void ILibSimpleDataStore_Close(ILibSimpleDataStore dataStore)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibHashtable_DestroyEx(root->keyTable, ILibSimpleDataStore_TableClear_Sink, root);
free(root->filePath);
fclose(root->dataFile);
free(root);
}
// Store a key/value pair in the data store
__EXPORT_TYPE int ILibSimpleDataStore_PutEx(ILibSimpleDataStore dataStore, char* key, int keyLen, char* value, int valueLen)
{
char hash[SHA256HASHSIZE];
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibSimpleDataStore_TableEntry *entry = (ILibSimpleDataStore_TableEntry*)ILibHashtable_Get(root->keyTable, NULL, key, keyLen);
ILibSimpleDataStore_SHA256(value, valueLen, hash); // Hash the value
// Create a new record for the key and value
if (entry == NULL) {
entry = (ILibSimpleDataStore_TableEntry*)ILibMemory_Allocate(sizeof(ILibSimpleDataStore_TableEntry), 0, NULL, NULL); }
else {
if (memcmp(entry->valueHash, hash, SHA256HASHSIZE) == 0) { return 0; }
}
memcpy_s(entry->valueHash, sizeof(entry->valueHash), hash, SHA256HASHSIZE);
entry->valueLength = valueLen;
entry->valueOffset = ILibSimpleDataStore_WriteRecord(root->dataFile, key, keyLen, value, valueLen, entry->valueHash); // Write the key and value
root->fileSize = ILibSimpleDataStore_GetPosition(root->dataFile); // Update the size of the data store;
// Add the record to the data store
return ILibHashtable_Put(root->keyTable, NULL, key, keyLen, entry) == NULL ? 0 : 1;
}
// Get a value from the data store given a key
__EXPORT_TYPE int ILibSimpleDataStore_GetEx(ILibSimpleDataStore dataStore, char* key, int keyLen, char *buffer, int bufferLen)
{
char hash[32];
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibSimpleDataStore_TableEntry *entry = (ILibSimpleDataStore_TableEntry*)ILibHashtable_Get(root->keyTable, NULL, key, keyLen);
if (entry == NULL) return 0; // If there is no in-memory entry for this key, return zero now.
if ((buffer != NULL) && (bufferLen >= entry->valueLength)) // If the buffer is not null and can hold the value, place the value in the buffer.
{
if (ILibSimpleDataStore_SeekPosition(root->dataFile, entry->valueOffset, SEEK_SET) != 0) return 0; // Seek to the position of the value in the data store
if (fread(buffer, 1, entry->valueLength, root->dataFile) == 0) return 0; // Read the value into the buffer
util_sha256(buffer, entry->valueLength, hash); // Compute the hash of the read value
if (memcmp(hash, entry->valueHash, SHA256HASHSIZE) != 0) return 0; // Check the hash, return 0 if not valid
if (bufferLen > entry->valueLength) { buffer[entry->valueLength] = 0; } // Add a zero at the end to be nice, if the buffer can take it.
}
return entry->valueLength;
}
// Get the reference to the SHA256 hash value from the datastore for a given a key.
__EXPORT_TYPE char* ILibSimpleDataStore_GetHashEx(ILibSimpleDataStore dataStore, char* key, int keyLen)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibSimpleDataStore_TableEntry *entry = (ILibSimpleDataStore_TableEntry*)ILibHashtable_Get(root->keyTable, NULL, key, keyLen);
if (entry == NULL) return NULL; // If there is no in-memory entry for this key, return zero now.
return entry->valueHash;
}
// Delete a key and value from the data store
__EXPORT_TYPE int ILibSimpleDataStore_DeleteEx(ILibSimpleDataStore dataStore, char* key, int keyLen)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibSimpleDataStore_TableEntry *entry = (ILibSimpleDataStore_TableEntry*)ILibHashtable_Remove(root->keyTable, NULL, key, keyLen);
if (entry != NULL) { ILibSimpleDataStore_WriteRecord(root->dataFile, key, keyLen, NULL, 0, NULL); free(entry); return 1; }
return 0;
}
// Lock the data store file
__EXPORT_TYPE void ILibSimpleDataStore_Lock(ILibSimpleDataStore dataStore)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibHashtable_Lock(root->keyTable);
}
// Unlock the data store file
__EXPORT_TYPE void ILibSimpleDataStore_UnLock(ILibSimpleDataStore dataStore)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
ILibHashtable_UnLock(root->keyTable);
}
// Called by the compaction method, for each key in the enumeration we write the key/value to the temporary data store
void ILibSimpleDataStore_Compact_EnumerateSink(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
{
ILibSimpleDataStore_TableEntry *entry = (ILibSimpleDataStore_TableEntry*)Data;
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)((void**)user)[0];
FILE *compacted = (FILE*)((void**)user)[1];
DS_Long offset;
char value[4096];
int valueLen;
int bytesLeft = entry->valueLength;
int totalBytesWritten = 0;
int bytesWritten = 0;
if (root->error != 0) return; // There was an error, ABORT!
offset = ILibSimpleDataStore_WriteRecord(compacted, Key2, Key2Len, NULL, entry->valueLength, entry->valueHash);
while (bytesLeft > 0)
{
if (ILibSimpleDataStore_SeekPosition(root->dataFile, entry->valueOffset + totalBytesWritten, SEEK_SET) == 0)
{
valueLen = (int)fread(value, 1, bytesLeft > 4096 ? 4096 : bytesLeft, root->dataFile);
bytesWritten = (int)fwrite(value, 1, valueLen, compacted);
if (bytesWritten != valueLen)
{
// Error
root->error = 1;
break;
}
totalBytesWritten += bytesWritten;
bytesLeft -= valueLen;
}
else
{
// Error
root->error = 1;
break;
}
}
if (root->error == 0) { entry->valueOffset = offset; }
}
// Used to help with key enumeration
void ILibSimpleDataStore_EnumerateKeysSink(ILibHashtable sender, void *Key1, char* Key2, int Key2Len, void *Data, void *user)
{
ILibSimpleDataStore_KeyEnumerationHandler handler = (ILibSimpleDataStore_KeyEnumerationHandler)((void**)user)[0];
ILibSimpleDataStore_KeyEnumerationHandler dataStore = (ILibSimpleDataStore)((void**)user)[1];
ILibSimpleDataStore_KeyEnumerationHandler userX = ((void**)user)[2];
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(Key1);
UNREFERENCED_PARAMETER(Key2);
UNREFERENCED_PARAMETER(Key2Len);
handler(dataStore, Key2, Key2Len, userX); // Call the user
}
// Enumerate each key in the data store, call the handler for each key
__EXPORT_TYPE void ILibSimpleDataStore_EnumerateKeys(ILibSimpleDataStore dataStore, ILibSimpleDataStore_KeyEnumerationHandler handler, void * user)
{
void* users[3];
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
users[0] = (void*)handler;
users[1] = (void*)dataStore;
users[2] = (void*)user;
if (handler != NULL) { ILibHashtable_Enumerate(root->keyTable, ILibSimpleDataStore_EnumerateKeysSink, users); }
}
// Compact the data store
__EXPORT_TYPE int ILibSimpleDataStore_Compact(ILibSimpleDataStore dataStore)
{
ILibSimpleDataStore_Root *root = (ILibSimpleDataStore_Root*)dataStore;
char* tmp = ILibString_Cat(root->filePath, -1, ".tmp", -1); // Create the name of the temporary data store
FILE* compacted;
void* state[2];
int retVal = 0;
// Start by opening a temporary .tmp file. Will be used to write the compacted data store.
if ((compacted = ILibSimpleDataStore_OpenFileEx(tmp, 1)) == NULL) { free(tmp); return 1; }
// Enumerate all keys and write them all into the temporary data store
state[0] = root;
state[1] = compacted;
root->error = 0;
ILibHashtable_Enumerate(root->keyTable, ILibSimpleDataStore_Compact_EnumerateSink, state);
// Check if the enumeration went as planned
if (root->error == 0)
{
// Success in writing new temporary file
fclose(root->dataFile); // Close the data store
fclose(compacted); // Close the temporary data store
// Now we copy the temporary data store over the data store, making it the new valid version
#ifdef WIN32
if (CopyFileA(tmp, root->filePath, FALSE) == FALSE) { retVal = 1; }
DeleteFile(tmp);
#else
if (rename(tmp, root->filePath) != 0) { retVal = 1; }
#endif
// We then open the newly compacted data store
if ((root->dataFile = ILibSimpleDataStore_OpenFile(root->filePath)) != NULL) { root->fileSize = ILibSimpleDataStore_GetPosition(root->dataFile); } else { retVal = 1; }
}
free(tmp); // Free the temporary file name
return retVal; // Return 1 if we got an error, 0 if everything finished correctly
}

View File

@@ -0,0 +1,76 @@
/*
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.
*/
/*
This is a simple data store that implements a hash table in a file. New keys are appended at the end of the file and the file can be compacted when needed.
The store will automatically create a hash of each value and store the hash. Upon reading the data, the hash is always checked.
*/
#ifndef __ILIBSIMPLEDATASTORE__
#define __ILIBSIMPLEDATASTORE__
#include "ILibParsers.h"
#if defined(WIN32) && defined(EXPORT_LIB)
#define __EXPORT_TYPE __declspec(dllexport)
#else
#define __EXPORT_TYPE
#endif
#define ILibSimpleDataStore_MaxKeyLength 1024
#define ILibSimpleDataStore_MaxUnspecifiedValueLen 16384
#define ILibSimpleDataStore_MaxFilePath 4096
typedef void* ILibSimpleDataStore;
const extern int ILibMemory_SimpleDataStore_CONTAINERSIZE;
typedef void(*ILibSimpleDataStore_KeyEnumerationHandler)(ILibSimpleDataStore sender, char* Key, int KeyLen, void *user);
// Create the data store.
__EXPORT_TYPE ILibSimpleDataStore ILibSimpleDataStore_CreateEx(char* filePath, int userExtraMemorySize);
#define ILibSimpleDataStore_Create(filePath) ILibSimpleDataStore_CreateEx(filePath, 0)
// Close the data store.
__EXPORT_TYPE void ILibSimpleDataStore_Close(ILibSimpleDataStore dataStore);
__EXPORT_TYPE int ILibSimpleDataStore_PutEx(ILibSimpleDataStore dataStore, char* key, int keyLen, char* value, int valueLen);
#define ILibSimpleDataStore_Put(dataStore, key, value) ILibSimpleDataStore_PutEx(dataStore, key, (int)strnlen_s(key, ILibSimpleDataStore_MaxKeyLength), value, (int)strnlen_s(value, ILibSimpleDataStore_MaxUnspecifiedValueLen))
// Get a value from the datastore of given a key.
__EXPORT_TYPE int ILibSimpleDataStore_GetEx(ILibSimpleDataStore dataStore, char* key, int keyLen, char* buffer, int bufferLen);
#define ILibSimpleDataStore_Get(dataStore, key, buffer, bufferLen) ILibSimpleDataStore_GetEx(dataStore, key, (int)strnlen_s(key, ILibSimpleDataStore_MaxKeyLength), buffer, bufferLen)
// Get the SHA256 hash value from the datastore for a given a key.
__EXPORT_TYPE char* ILibSimpleDataStore_GetHashEx(ILibSimpleDataStore dataStore, char* key, int keyLen);
#define ILibSimpleDataStore_GetHash(dataStore, key) ILibSimpleDataStore_GetHashEx(dataStore, key, (int)strnlen_s(key, ILibSimpleDataStore_MaxKeyLength))
// Delete a key from the data store
__EXPORT_TYPE int ILibSimpleDataStore_DeleteEx(ILibSimpleDataStore dataStore, char* key, int keyLen);
#define ILibSimpleDataStore_Delete(dataStore, key) ILibSimpleDataStore_DeleteEx(dataStore, key, (int)strnlen_s(key, ILibSimpleDataStore_MaxKeyLength))
// Enumerate all keys from the data store
__EXPORT_TYPE void ILibSimpleDataStore_EnumerateKeys(ILibSimpleDataStore dataStore, ILibSimpleDataStore_KeyEnumerationHandler handler, void *user);
// Compacts the data store
__EXPORT_TYPE int ILibSimpleDataStore_Compact(ILibSimpleDataStore dataStore);
// Lock and unlock the data store. This is useful if we need to access this store from many threads.
__EXPORT_TYPE void ILibSimpleDataStore_Lock(ILibSimpleDataStore dataStore);
__EXPORT_TYPE void ILibSimpleDataStore_UnLock(ILibSimpleDataStore dataStore);
#endif

3727
microstack/ILibWebClient.c Normal file

File diff suppressed because it is too large Load Diff

319
microstack/ILibWebClient.h Normal file
View File

@@ -0,0 +1,319 @@
/*
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.
*/
#ifndef __ILibWebClient__
#define __ILibWebClient__
#include "ILibParsers.h"
#include "ILibAsyncSocket.h"
#include "ILibCrypto.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \file ILibWebClient.h
\brief MicroStack APIs for HTTP Client functionality
*/
#define ILibWebClientIsStatusOk(statusCode) (statusCode>=200 && statusCode<=299)
/*! \defgroup ILibWebClient ILibWebClient Module
\{
*/
/*! \def WEBCLIENT_DESTROYED
\brief The ILibWebClient object was destroyed
*/
#define WEBCLIENT_DESTROYED 5
/*! \def WEBCLIENT_DELETED
\brief The ILibWebClient object was deleted with a call to ILibWebClient_DeleteRequests
*/
#define WEBCLIENT_DELETED 6
#if defined(WIN32) || defined(_WIN32_WCE)
#include <STDDEF.h>
#elif defined(_POSIX)
#if !defined(__APPLE__) && !defined(_VX_CPU)
#include <malloc.h>
#endif
#endif
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WEBSOCKET_FIN 0x08000
#define WEBSOCKET_RSV1 0x04000
#define WEBSOCKET_RSV2 0x02000
#define WEBSOCKET_RSV3 0x01000
#define WEBSOCKET_OPCODE 0x00F00
#define WEBSOCKET_MASK 0x00080
#define WEBSOCKET_PLEN 0x0007F
#define WEBSOCKET_MAX_OUTPUT_FRAMESIZE 4096
#define WEBSOCKET_OPCODE_FRAMECONT 0x0
#define WEBSOCKET_OPCODE_TEXTFRAME 0x1
#define WEBSOCKET_OPCODE_BINARYFRAME 0x2
#define WEBSOCKET_OPCODE_CLOSE 0x8
#define WEBSOCKET_OPCODE_PING 0x9
#define WEBSOCKET_OPCODE_PONG 0xA
enum ILibWebClient_DoneCode
{
ILibWebClient_DoneCode_NoErrors = 1,
ILibWebClient_DoneCode_StillReading = 0,
ILibWebClient_DoneCode_HeaderTooBig = -2,
ILibWebClient_DoneCode_BodyTooBig = -3,
};
enum ILibWebClient_Range_Result
{
ILibWebClient_Range_Result_OK = 0,
ILibWebClient_Range_Result_INVALID_RANGE = 1,
ILibWebClient_Range_Result_BAD_REQUEST = 2,
};
typedef enum
{
ILibWebClient_ReceiveStatus_MoreDataToBeReceived = 0,
ILibWebClient_ReceiveStatus_Complete = 1,
ILibWebClient_ReceiveStatus_Partial = 10,
ILibWebClient_ReceiveStatus_LastPartial = 11,
ILibWebClient_ReceiveStatus_Connection_Established = 12
}ILibWebClient_ReceiveStatus;
/*! \typedef ILibWebClient_RequestToken
\brief The handle for a request, obtained from a call to \a ILibWebClient_PipelineRequest
*/
typedef void* ILibWebClient_RequestToken;
/*! \typedef ILibWebClient_RequestManager
\brief An object that manages HTTP Client requests. Obtained from \a ILibCreateWebClient
*/
typedef void* ILibWebClient_RequestManager;
/*! \typedef ILibWebClient_StateObject
\brief Handle for an HTTP Client Connection.
*/
typedef void* ILibWebClient_StateObject;
/*! \typedef ILibWebClient_OnResponse
\brief Function Callback Pointer, dispatched to process received data
\param WebStateObject The ILibWebClient that received a response
\param InterruptFlag A flag indicating if this request was interrupted with a call to ILibStopChain
\param header The packetheader object containing the HTTP headers.
\param bodyBuffer The buffer containing the body
\param[in,out] beginPointer The start index of the buffer referenced by \a bodyBuffer
\param endPointer The end index of the buffer referenced by \a bodyBuffer
\param done Flag indicating if all of the response has been received.
\param user1
\param user2
\param[out] PAUSE Set to nonzero value if you do not want the system to read any more data from the network
*/
typedef void(*ILibWebClient_OnResponse)(ILibWebClient_StateObject WebStateObject,int InterruptFlag,struct packetheader *header,char *bodyBuffer,int *beginPointer,int endPointer,ILibWebClient_ReceiveStatus recvStatus,void *user1,void *user2,int *PAUSE);
/*! \typedef ILibWebClient_OnSendOK
\brief Handler for when pending send operations have completed
\par
<B>Note:</B> This handler will only be called after all data from any call(s) to \a ILibWebClient_StreamRequestBody
have completed.
\param sender The \a ILibWebClient_StateObject whos pending sends have completed
\param user1 User1 object that was associated with this connection
\param user2 User2 object that was associated with this connection
*/
typedef void(*ILibWebClient_OnSendOK)(ILibWebClient_StateObject sender, void *user1, void *user2);
/*! \typedef ILibWebClient_OnDisconnect
\brief Handler for when the session has disconnected
\param sender The \a ILibWebClient_StateObject that has been disconnected
\param request The ILibWebClient_RequestToken that represents the request that was in progress when the disconnect happened.
*/
typedef void(*ILibWebClient_OnDisconnect)(ILibWebClient_StateObject sender, ILibWebClient_RequestToken request);
#ifndef MICROSTACK_NOTLS
typedef int(*ILibWebClient_OnSslConnection)(ILibWebClient_StateObject sender, STACK_OF(X509) *certs, struct sockaddr_in6 *address, void *user);
typedef int(*ILibWebClient_OnHttpsConnection)(ILibWebClient_RequestToken sender, int preverify_ok, STACK_OF(X509) *certs, struct sockaddr_in6 *address);
#endif
//
// This is the number of seconds that a connection must be idle for, before it will
// be automatically closed. Idle means there are no pending requests
//
/*! \def HTTP_SESSION_IDLE_TIMEOUT
\brief This is the number of seconds that a connection must be idle for, before it will be automatically closed.
\par
Idle means there are no pending requests
*/
#define HTTP_SESSION_IDLE_TIMEOUT 10
/*! \def HTTP_CONNECT_RETRY_COUNT
\brief This is the number of times, an HTTP connection will be attempted, before it fails.
\par
This module utilizes an exponential backoff algorithm. That is, it will retry immediately, then it will retry after 1 second, then 2, then 4, etc.
*/
#define HTTP_CONNECT_RETRY_COUNT 2
/*! \def INITIAL_BUFFER_SIZE
\brief This initial size of the receive buffer
*/
#define INITIAL_BUFFER_SIZE 65535
extern const int ILibMemory_WebClient_RequestToken_CONTAINERSIZE;
ILibWebClient_RequestManager ILibCreateWebClient(int PoolSize, void *Chain);
ILibWebClient_StateObject ILibCreateWebClientEx(ILibWebClient_OnResponse OnResponse, ILibAsyncSocket_SocketModule socketModule, void *user1, void *user2);
void ILibWebClient_OnBufferReAllocate(ILibAsyncSocket_SocketModule token, void *user, ptrdiff_t offSet);
void ILibWebClient_OnData(ILibAsyncSocket_SocketModule socketModule,char* buffer,int *p_beginPointer, int endPointer,ILibAsyncSocket_OnInterrupt *InterruptPtr, void **user, int *PAUSE);
void ILibDestroyWebClient(void *object);
void ILibWebClient_DestroyWebClientDataObject(ILibWebClient_StateObject token);
struct packetheader *ILibWebClient_GetHeaderFromDataObject(ILibWebClient_StateObject token);
ILibWebClient_RequestToken ILibWebClient_PipelineRequestEx(
ILibWebClient_RequestManager WebClient,
struct sockaddr *RemoteEndpoint,
char *headerBuffer,
int headerBufferLength,
int headerBuffer_FREE,
char *bodyBuffer,
int bodyBufferLength,
int bodyBuffer_FREE,
ILibWebClient_OnResponse OnResponse,
void *user1,
void *user2);
ILibWebClient_RequestToken ILibWebClient_PipelineRequest(
ILibWebClient_RequestManager WebClient,
struct sockaddr *RemoteEndpoint,
struct packetheader *packet,
ILibWebClient_OnResponse OnResponse,
void *user1,
void *user2);
ILibTransport_DoneState ILibWebClient_StreamRequestBody(
ILibWebClient_RequestToken token,
char *body,
int bodyLength,
enum ILibAsyncSocket_MemoryOwnership MemoryOwnership,
ILibTransport_DoneState done
);
ILibWebClient_RequestToken ILibWebClient_PipelineStreamedRequest(
ILibWebClient_RequestManager WebClient,
struct sockaddr *RemoteEndpoint,
struct packetheader *packet,
ILibWebClient_OnResponse OnResponse,
ILibWebClient_OnSendOK OnSendOK,
void *user1,
void *user2);
typedef enum ILibWebClient_WebSocket_DataTypes
{
ILibWebClient_WebSocket_DataType_UNKNOWN = 0x0,
ILibWebClient_WebSocket_DataType_REQUEST = 0xFF,
ILibWebClient_WebSocket_DataType_BINARY = 0x2,
ILibWebClient_WebSocket_DataType_TEXT = 0x1
}ILibWebClient_WebSocket_DataTypes;
typedef enum ILibWebClient_WebSocket_FragmentFlags
{
ILibWebClient_WebSocket_FragmentFlag_Incomplete = 0,
ILibWebClient_WebSocket_FragmentFlag_Complete = 1
}ILibWebClient_WebSocket_FragmentFlags;
void ILibWebClient_FinishedResponse_Server(ILibWebClient_StateObject wcdo);
void ILibWebClient_DeleteRequests(ILibWebClient_RequestManager WebClientToken, struct sockaddr* addr);
void ILibWebClient_Resume(ILibWebClient_StateObject wcdo);
void ILibWebClient_Pause(ILibWebClient_StateObject wcdo);
void ILibWebClient_Disconnect(ILibWebClient_StateObject wcdo);
void ILibWebClient_CancelRequest(ILibWebClient_RequestToken RequestToken);
void ILibWebClient_ResetUserObjects(ILibWebClient_StateObject webstate, void *user1, void *user2);
ILibWebClient_RequestToken ILibWebClient_GetRequestToken_FromStateObject(ILibWebClient_StateObject WebStateObject);
ILibWebClient_StateObject ILibWebClient_GetStateObjectFromRequestToken(ILibWebClient_RequestToken token);
void **ILibWebClient_RequestToken_GetUserObjects(ILibWebClient_RequestToken tok);
void ILibWebClient_Parse_ContentRange(char *contentRange, int *Start, int *End, int *TotalLength);
enum ILibWebClient_Range_Result ILibWebClient_Parse_Range(char *Range, long *Start, long *Length, long TotalLength);
void ILibWebClient_SetMaxConcurrentSessionsToServer(ILibWebClient_RequestManager WebClient, int maxConnections);
void ILibWebClient_SetUser(ILibWebClient_RequestManager manager, void *user);
void* ILibWebClient_GetUser(ILibWebClient_RequestManager manager);
void* ILibWebClient_GetChain(ILibWebClient_RequestManager manager);
void* ILibWebClient_GetChainFromWebStateObject(ILibWebClient_StateObject wcdo);
typedef enum ILibWebClient_RequestToken_HTTPS
{
#ifndef MICROSTACK_NOTLS
ILibWebClient_RequestToken_USE_HTTPS = 0,
#endif
ILibWebClient_RequestToken_USE_HTTP = 1
}ILibWebClient_RequestToken_HTTPS;
#ifndef MICROSTACK_NOTLS
void ILibWebClient_SetTLS(ILibWebClient_RequestManager manager, void *ssl_ctx, ILibWebClient_OnSslConnection OnSslConnection);
int ILibWebClient_EnableHTTPS(ILibWebClient_RequestManager manager, struct util_cert* leafCert, X509* nonLeafCert, ILibWebClient_OnHttpsConnection OnHttpsConnection);
void ILibWebClient_Request_SetHTTPS(ILibWebClient_RequestToken reqToken, ILibWebClient_RequestToken_HTTPS requestMode);
#endif
// Added methods
int ILibWebClient_GetLocalInterface(void* socketModule, struct sockaddr *localAddress);
int ILibWebClient_GetRemoteInterface(void* socketModule, struct sockaddr *remoteAddress);
int ILibWebClient_Digest_NeedAuthenticate(ILibWebClient_StateObject state);
char* ILibWebClient_Digest_GetRealm(ILibWebClient_StateObject state);
void ILibWebClient_GenerateAuthenticationHeader(ILibWebClient_StateObject state, ILibHTTPPacket *packet, char* username, char* password);
#ifdef MICROSTACK_PROXY
struct sockaddr_in6* ILibWebClient_SetProxy(ILibWebClient_RequestToken token, char *proxyHost, unsigned short proxyPort, char *username, char *password);
void ILibWebClient_SetProxyEx(ILibWebClient_RequestToken token, struct sockaddr_in6* proxyServer, char *username, char *password);
#endif
// WebSocket Methods
typedef enum ILibWebClient_WebSocket_PingResponse
{
ILibWebClient_WebSocket_PingResponse_Respond = 0,
ILibWebClient_WebSocket_PingResponse_None = 1
}ILibWebClient_WebSocket_PingResponse;
typedef ILibWebClient_WebSocket_PingResponse(*ILibWebClient_WebSocket_PingHandler)(ILibWebClient_StateObject state, void *user);
typedef void(*ILibWebClient_WebSocket_PongHandler)(ILibWebClient_StateObject state, void *user);
void ILibWebClient_AddWebSocketRequestHeaders(ILibHTTPPacket *packet, int FragmentReassemblyMaxBufferSize, ILibWebClient_OnSendOK OnSendOK);
ILibAsyncSocket_SendStatus ILibWebClient_WebSocket_Send(ILibWebClient_StateObject state, ILibWebClient_WebSocket_DataTypes bufferType, char* buffer, int bufferLen, ILibAsyncSocket_MemoryOwnership userFree, ILibWebClient_WebSocket_FragmentFlags bufferFragment);
void ILibWebClient_WebSocket_SetPingPongHandler(ILibWebClient_StateObject state, ILibWebClient_WebSocket_PingHandler pingHandler, ILibWebClient_WebSocket_PongHandler pongHandler, void *user);
#define ILibWebClient_WebSocket_Ping(stateObject) ILibWebClient_WebSocket_Send((stateObject), (ILibWebClient_WebSocket_DataTypes)WEBSOCKET_OPCODE_PING, NULL, 0, ILibAsyncSocket_MemoryOwnership_STATIC, ILibWebServer_WebSocket_FragmentFlag_Complete)
#define ILibWebClient_WebSocket_Pong(stateObject) ILibWebClient_WebSocket_Send((stateObject), (ILibWebClient_WebSocket_DataTypes)WEBSOCKET_OPCODE_PONG, NULL, 0, ILibAsyncSocket_MemoryOwnership_STATIC, ILibWebServer_WebSocket_FragmentFlag_Complete)
typedef void(*ILibWebClient_TimeoutHandler)(ILibWebClient_StateObject state, void *user);
void ILibWebClient_SetTimeout(ILibWebClient_StateObject state, int timeoutSeconds, ILibWebClient_TimeoutHandler handler, void *user);
// OpenSSL supporting code
#ifndef MICROSTACK_NOTLS
X509* ILibWebClient_SslGetCert(void* socketModule);
STACK_OF(X509)* ILibWebClient_SslGetCerts(void* socketModule);
#endif
// Mesh specific code, used to store the NodeID in the web client
char* ILibWebClient_GetCertificateHash(void* socketModule);
char* ILibWebClient_SetCertificateHash(void* socketModule, char* ptr);
char* ILibWebClient_GetCertificateHashEx(void* socketModule);
int ILibWebClient_HasAllocatedClient(ILibWebClient_RequestManager WebClient, struct sockaddr *remoteAddress);
int ILibWebClient_GetActiveClientCount(ILibWebClient_RequestManager WebClient);
#ifdef UPNP_DEBUG
char *ILibWebClient_QueryWCDO(ILibWebClient_RequestManager wcm, char *query);
#endif
#ifdef __cplusplus
}
#endif
#endif

7364
microstack/ILibWebRTC.c Normal file

File diff suppressed because it is too large Load Diff

270
microstack/ILibWebRTC.h Normal file
View File

@@ -0,0 +1,270 @@
/*
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.
*/
#if !defined(___ILIBWEBRTC___) && !defined(MICROSTACK_NOTLS)
#define ___ILIBWEBRTC___
#include "ILibAsyncSocket.h"
#include <openssl/ssl.h>
/*! \file ILibWrapperWebRTC.h
\brief Microstack API for WebRTC Functionality
*/
/*! \defgroup ILibWebRTC ILibWebRTC Module */
/*! @{ */
#define ILibTransports_Raw_WebRTC 0x50
typedef enum ILibWebRTC_SDP_Flags
{
ILibWebRTC_SDP_Flags_DTLS_SERVER = 0x2
} ILibWebRTC_SDP_Flags;
typedef enum ILibStun_Results
{
ILibStun_Results_Unknown = 0, //!< Cannot determine NAT Type
ILibStun_Results_No_NAT = 1, //!< No NAT Detected
ILibStun_Results_Full_Cone_NAT = 2, //!< NAT Type: FULL Cone
ILibStun_Results_Symetric_NAT = 3, //!< NAT Type: Symmetric
ILibStun_Results_Restricted_NAT = 4, //!< NAT Type: Address Restricted
ILibStun_Results_Port_Restricted_NAT = 5, //!< NAT Type: Port Restricted
ILibStun_Results_RFC5780_NOT_IMPLEMENTED = 10, //!< Server does not support RFC5780
ILibStun_Results_Public_Interface = 11, //!< Local interface is publically accessible
} ILibStun_Results;
typedef enum ILibWebRTC_TURN_ConnectFlags
{
ILibWebRTC_TURN_DISABLED = 0, //!< No TURN support
ILibWebRTC_TURN_ENABLED = 1, //!< Always connect the control channel, but only use the server when necessary
ILibWebRTC_TURN_ALWAYS_RELAY = 2 //!< Always relay all connections
} ILibWebRTC_TURN_ConnectFlags;
typedef enum ILibWebRTC_DataChannel_ReliabilityModes
{
ILibWebRTC_DataChannel_ReliabilityMode_RELIABLE = 0x00, //!< Reliable Transport [DEFAULT]
ILibWebRTC_DataChannel_ReliabilityMode_RELIABLE_UNORDERED = 0x80, //!< Unordered Reliable Transport
ILibWebRTC_DataChannel_ReliabilityMode_PARTIAL_RELIABLE_REXMIT = 0x01, //!< Partial Reliable via a Max-Retransmit Attribute
ILibWebRTC_DataChannel_ReliabilityMode_PARTIAL_RELIABLE_REXMIT_UNORDERED = 0x81, //!< Partial Reliable/Unordered via a Max-Retransmit Attribute
ILibWebRTC_DataChannel_ReliabilityMode_PARTIAL_RELIABLE_TIMED = 0x02, //!< Partial Reliable via Timeout for Re-transmits
ILibWebRTC_DataChannel_ReliabilityMode_PARTIAL_RELIABLE_TIMED_UNORDERED = 0x82, //!< Parital Reliable/Unordered via Timeout for Re-transmits
}ILibWebRTC_DataChannel_ReliabilityModes;
#define ILibStun_SlotToChar(val) (val>26?(val+97):(val+65))
#define ILibStun_CharToSlot(val) (val>=97?(val-97):(val-65))
/*! \defgroup STUN_ICE STUN & ICE Related Methods */
/*! @{ */
typedef void(*ILibStunClient_OnResult)(void* StunModule, ILibStun_Results Result, struct sockaddr_in* PublicIP, void *user);
void ILibStunClient_SetOptions(void* StunModule, SSL_CTX* securityContext, char* certThumbprintSha256);
void* ILibStunClient_Start(void *Chain, unsigned short LocalPort, ILibStunClient_OnResult OnResult);
SSL_CTX* ILibStunClient_GetSSLCTX(void *StunModule);
void ILibStunClient_PerformNATBehaviorDiscovery(void* StunModule, struct sockaddr_in* StunServer, void *user);
void ILibStunClient_PerformStun(void* StunModule, struct sockaddr_in* StunServer, void *user);
void ILibStunClient_SendData(void* StunModule, struct sockaddr* target, char* data, int datalen, enum ILibAsyncSocket_MemoryOwnership UserFree);
int ILibStun_SetIceOffer(void* StunModule, char* iceOffer, int iceOfferLen, char** answer);
int ILibStun_SetIceOffer2(void *StunModule, char* iceOffer, int iceOfferLen, char *username, int usernameLength, char* password, int passwordLength, char** answer);
int ILibStun_GenerateIceOffer(void* StunModule, char** offer, char* userName, char* password);
void ILibStun_ClearIceState(void* stunModule, int iceSlot);
int ILibStun_GetExistingIceOfferIndex(void* stunModule, char *iceOffer, int iceOfferLen);
/*! @} */
/*! \defgroup ORTC ORTC Related Methods */
/*! @{ */
void ILibORTC_GetLocalParameters(void *stunModule, char* username, char** password, int *passwordLength, char** certHash, int* certHashLength);
void ILibORTC_SetRemoteParameters(void* stunModule, char *username, int usernameLen, char *password, int passwordLen, char *certHash, int certHashLen, char *localUserName);
void ILibORTC_AddRemoteCandidate(void *stunModule, char* localUsername, struct sockaddr_in6 *candidate);
/*! @} */
/*! \defgroup General General Methods */
/*! @{ */
typedef enum
{
ILibWebRTC_DataChannel_CloseStatus_OK = 0, //!< SCTP/RECONFIG Result: OK
ILibWebRTC_DataChannel_CloseStatus_ALREADY_PENDING = 1, //!< SCTP/RECONFIG Result: Already Pending
ILibWebRTC_DataChannel_CloseStatus_ERROR = 254, //!< SCTP/RECONFIG Result: ERROR
ILibWebRTC_DataChannel_CloseStatus_NOT_SUPPORTED = 255, //!< SCTP/RECONFIG Not supported by Peer
}ILibWebRTC_DataChannel_CloseStatus;
int ILibWebRTC_IsDtlsInitiator(void* dtlsSession);
void ILibWebRTC_OpenDataChannel(void *WebRTCModule, unsigned short streamId, char* channelName, int channelNameLength);
void ILibWebRTC_CloseDataChannel_ALL(void *WebRTCModule);
ILibWebRTC_DataChannel_CloseStatus ILibWebRTC_CloseDataChannel(void *WebRTCModule, unsigned short streamId);
ILibWebRTC_DataChannel_CloseStatus ILibWebRTC_CloseDataChannelEx(void *WebRTCModule, unsigned short *streamIds, int streamIdsCount);
//! Handler for new Data Channel Associations
/*!
\param StunModule Local Stun/ICE Client
\param WebRTCModule Peer Connection Session
\param StreamId Data Channel ID
\param ChannelName Name of the Data Channel
\param ChannelNameLength Length of the Channel Name
\return 0 = Respond with ACK, Non-Zero = DO NOT ACK
*/
typedef int(*ILibWebRTC_OnDataChannel)(void *StunModule, void* WebRTCModule, unsigned short StreamId, char* ChannelName, int ChannelNameLength);
//! Handler for when an Associated Data Channel is closed
/*!
\param StunModule Local Stun/ICE Client
\param WebRTCModule Peer Connection Session
\param StreamId Data Channel Stream ID
*/
typedef void(*ILibWebRTC_OnDataChannelClosed)(void *StunModule, void* WebRTCModule, unsigned short StreamId);
//! Handler for when a Data Channel Creation request was ACK'ed by the peer
/*!
\param StunModule Local Stun/ICE Client
\param WebRTCModule Peer Connection Session
\param StreamId Data Channel Stream ID
*/
typedef void(*ILibWebRTC_OnDataChannelAck)(void *StunModule, void* WebRTCModule, unsigned short StreamId);
typedef void(*ILibWebRTC_OnOfferUpdated)(void* stunModule, char* iceOffer, int iceOfferLen);
void ILibWebRTC_SetCallbacks(void *StunModule, ILibWebRTC_OnDataChannel OnDataChannel, ILibWebRTC_OnDataChannelClosed OnDataChannelClosed, ILibWebRTC_OnDataChannelAck OnDataChannelAck, ILibWebRTC_OnOfferUpdated OnOfferUpdated);
void ILibStun_DTLS_GetIceUserName(void* WebRTCModule, char* username);
void ILibWebRTC_SetTurnServer(void* stunModule, struct sockaddr_in6* turnServer, char* username, int usernameLength, char* password, int passwordLength, ILibWebRTC_TURN_ConnectFlags turnFlags);
void ILibWebRTC_DisableConsentFreshness(void *stunModule);
void ILibWebRTC_SetUserObject(void *stunModule, char* localUsername, void *userObject);
void* ILibWebRTC_GetUserObject(void *stunModule, char* localUsername);
void* ILibWebRTC_GetUserObjectFromDtlsSession(void *webRTCSession);
#ifdef _WEBRTCDEBUG
// SCTP Instrumentation Methods/Helpers
typedef void(*ILibSCTP_OnSenderReceiverCreditsChanged)(void *StunModule, int dtlsSessionId, int senderCredits, int receiverCredits);
typedef void(*ILibSCTP_OnTSNChanged)(void *stunModule, int OutboundTSN, int CumulativeTSNAck);
typedef void (*ILibSCTP_OnSCTPDebug)(void* dtlsSession, char* debugField, int data);
void ILibSCTP_SetSenderReceiverCreditsCallback(void* stunModule, ILibSCTP_OnSenderReceiverCreditsChanged callback);
void ILibSCTP_SetSimulatedInboundLossPercentage(void *stunModule, int lossPercentage);
void ILibSCTP_SetTSNCallback(void *dtlsSession, ILibSCTP_OnTSNChanged tsnHandler);
int ILibSCTP_Debug_SetDebugCallback(void *dtlsSession, char* debugFieldName, ILibSCTP_OnSCTPDebug handler);
#endif
/*! @} */
/*! \defgroup SCTP SCTP Related Methods */
/*! @{ */
typedef void(*ILibSCTP_OnConnect)(void *StunModule, void* SctpSession, int connected);
typedef void(*ILibSCTP_OnData)(void* StunModule, void* SctpSession, unsigned short streamId, int pid, char* buffer, int bufferLen, void** user);
typedef void(*ILibSCTP_OnSendOK)(void* StunModule, void* SctpSession, void* user);
int ILibSCTP_DoesPeerSupportFeature(void* SctpSession, int feature);
void ILibSCTP_Pause(void* SctpSession);
void ILibSCTP_Resume(void* SctpSession);
void ILibSCTP_SetCallbacks(void* StunModule, ILibSCTP_OnConnect onconnect, ILibSCTP_OnData ondata, ILibSCTP_OnSendOK onsendok);
ILibTransport_DoneState ILibSCTP_Send(void* SctpSession, unsigned short streamId, char* data, int datalen);
ILibTransport_DoneState ILibSCTP_SendEx(void* SctpSession, unsigned short streamId, char* data, int datalen, int dataType);
int ILibSCTP_GetPendingBytesToSend(void* SctpSession);
void ILibSCTP_Close(void* SctpSession);
void ILibSCTP_SetUser(void* SctpSession, void* user);
void* ILibSCTP_GetUser(void* SctpSession);
void ILibSCTP_SetUser2(void* SctpSession, void* user);
void* ILibSCTP_GetUser2(void* SctpSession);
void ILibSCTP_SetUser3(void* SctpSession, int user);
int ILibSCTP_GetUser3(void* SctpSession);
void ILibSCTP_SetUser4(void* SctpSession, int user);
int ILibSCTP_GetUser4(void* SctpSession);
/*! @} */
// Debug
void ILib_Stun_SendAttributeChangeRequest(void* StunModule, struct sockaddr* StunServer, int flags);
// Note: In "ILibStunClient_Start" you can pass NULL in the LocalInterface for INADDR_ANY.
/*! \defgroup TURN TURN Related Methods */
/*! @{ */
typedef void* ILibTURN_ClientModule;
ILibTURN_ClientModule ILibStun_GetTurnClient(void *stunModule);
//! Handler for TURN Server Connection Attempts
/*!
\param turnModule TURN Client
\param success 0 = FAIL, 1 = SUCCESS
*/
typedef void(*ILibTURN_OnConnectTurnHandler)(ILibTURN_ClientModule turnModule, int success);
//! Handler for TURN/ALLOCATE Response
/*!
\param turnModule TURN Client
\param Lifetime The cache timeout of the new allocation. If not renewed by this timeout, allocation will expire.
\param RelayedTransportAddress The public IP Address/Port that is relayed
*/
typedef void(*ILibTURN_OnAllocateHandler)(ILibTURN_ClientModule turnModule, int Lifetime, struct sockaddr_in6* RelayedTransportAddress);
typedef void(*ILibTURN_OnRefreshHandler)(ILibTURN_ClientModule turnModule, int Lifetime, void *user);
//! Handler for TURN/PERMISSION Response
/*!
\param turnModule TURN Client
\param success 0 = FAIL, 1 = SUCCESS
\param user Custom user state object
*/
typedef void(*ILibTURN_OnCreatePermissionHandler)(ILibTURN_ClientModule turnModule, int success, void *user);
//! Handler for received TURN/INDICATION
/*!
\param turnModule TURN Client
\param remotePeer Origin of received Indication
\param buffer Data received
\param offset Data Offset Received
\param length Data Length
*/
typedef void(*ILibTURN_OnDataIndicationHandler)(ILibTURN_ClientModule turnModule, struct sockaddr_in6* remotePeer, char* buffer, int offset, int length);
//! Handler for TURN/CHANNELBIND Response
/*!
\param turnModule TURN Client
\param channelNumber Channel Number
\param success 0 = FAIL, 1 = SUCCESS
\param user Custom user state object
*/
typedef void(*ILibTURN_OnCreateChannelBindingHandler)(ILibTURN_ClientModule turnModule, unsigned short channelNumber, int success, void* user);
//! Handler for received TURN/CHANNELDATA
/*!
\param turnModule TURN Client
\param channelNumber Channel Number that received data
\param buffer Received Data
\param offset Received Data Offset
\param length Received Data Length
*/
typedef void(*ILibTURN_OnChannelDataHandler)(ILibTURN_ClientModule turnModule, unsigned short channelNumber, char* buffer, int offset, int length);
typedef enum
{
ILibTURN_TransportTypes_UDP = 17, //!< TURN Transport Type: UDP
ILibTURN_TransportTypes_TCP = 6 //!< TURN Transport Type: TCP
}ILibTURN_TransportTypes;
//! Create a new TURN Client Instance
/*!
\param chain Microstack Chain to add TURN Client to
\param OnCennectTurn Event Handler for CONNECT Response
\param OnAllocate Event Handler for ALLOCATE Response
\param OnData Event Handler for INDICATION reception
\param OnChannelData Event Handler for CHANNEL/DATA reception
\return TURN Client Instance
*/
ILibTURN_ClientModule ILibTURN_CreateTurnClient(void* chain, ILibTURN_OnConnectTurnHandler OnConnectTurn, ILibTURN_OnAllocateHandler OnAllocate, ILibTURN_OnDataIndicationHandler OnData, ILibTURN_OnChannelDataHandler OnChannelData);
void ILibTURN_SetTag(ILibTURN_ClientModule clientModule, void *tag);
void* ILibTURN_GetTag(ILibTURN_ClientModule clientModule);
void ILibTURN_ConnectTurnServer(ILibTURN_ClientModule turnModule, struct sockaddr_in* turnServer, char* username, int usernameLen, char* password, int passwordLen, struct sockaddr_in* proxyServer);
void ILibTURN_Allocate(ILibTURN_ClientModule turnModule, ILibTURN_TransportTypes transportType);
void ILibTURN_RefreshAllocation(ILibTURN_ClientModule turnModule, ILibTURN_OnRefreshHandler handler, void *user);
int ILibTURN_CreateXORMappedAddress(struct sockaddr_in6 *endpoint, char* buffer, char* transactionID);
void ILibTURN_GetXORMappedAddress(char* buffer, int bufferLen, char* transactionID, struct sockaddr_in6 *value);
void ILibTURN_CreatePermission(ILibTURN_ClientModule turnModule, struct sockaddr_in6* permissions, int permissionsLength, ILibTURN_OnCreatePermissionHandler result, void* user);
enum ILibAsyncSocket_SendStatus ILibTURN_SendIndication(ILibTURN_ClientModule turnModule, struct sockaddr_in6* remotePeer, char* buffer, int offset, int length);
void ILibTURN_CreateChannelBinding(ILibTURN_ClientModule turnModule, unsigned short channelNumber, struct sockaddr_in6* remotePeer, ILibTURN_OnCreateChannelBindingHandler result, void* user);
enum ILibAsyncSocket_SendStatus ILibTURN_SendChannelData(ILibTURN_ClientModule turnModule, unsigned short channelNumber, char* buffer, int offset, int length);
int ILibTURN_IsConnectedToServer(ILibTURN_ClientModule clientModule);
unsigned int ILibTURN_GetPendingBytesToSend(ILibTURN_ClientModule turnModule);
/*! @} */
/*! @} */
#endif

2105
microstack/ILibWebServer.c Normal file

File diff suppressed because it is too large Load Diff

270
microstack/ILibWebServer.h Normal file
View File

@@ -0,0 +1,270 @@
/*
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.
*/
/*! \file ILibWebServer.h
\brief MicroStack APIs for HTTP Server functionality
*/
#ifndef __ILibWebServer__
#define __ILibWebServer__
#include "ILibParsers.h"
#include "ILibAsyncServerSocket.h"
#include "ILibCrypto.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ILibTransports_WebServer 0x10
#define ILibTransports_WebSocket 0x20
extern const int ILibMemory_WEBSERVERSESSION_CONTAINERSIZE;
typedef enum
{
ILibWebServer_WebSocket_DataType_UNKNOWN = 0x0,
ILibWebServer_WebSocket_DataType_REQUEST = 0xFF,
ILibWebServer_WebSocket_DataType_BINARY = 0x2,
ILibWebServer_WebSocket_DataType_TEXT = 0x1
}ILibWebServer_WebSocket_DataTypes;
typedef enum
{
ILibWebServer_DoneFlag_NotDone = 0,
ILibWebServer_DoneFlag_Done = 1,
ILibWebServer_DoneFlag_Partial = 10,
ILibWebServer_DoneFlag_LastPartial = 11
}ILibWebServer_DoneFlag;
typedef enum
{
ILibWebServer_WebSocket_FragmentFlag_Incomplete = 0,
ILibWebServer_WebSocket_FragmentFlag_Complete = 1
}ILibWebServer_WebSocket_FragmentFlags;
/*! \defgroup ILibWebServer ILibWebServer Module
\{
*/
typedef enum ILibWebServer_Status
{
ILibWebServer_ALL_DATA_SENT = 1, /*!< All of the data has already been sent */
ILibWebServer_NOT_ALL_DATA_SENT_YET = 0, /*!< Not all of the data could be sent, but is queued to be sent as soon as possible */
ILibWebServer_SEND_RESULTED_IN_DISCONNECT = -2, /*!< A send operation resulted in the socket being closed */
ILibWebServer_INVALID_SESSION = -3, /*!< The specified ILibWebServer_Session was invalid */
ILibWebServer_TRIED_TO_SEND_ON_CLOSED_SOCKET = -4, /*!< A send operation was attmepted on a closed socket */
}ILibWebServer_Status;
/*! \typedef ILibWebServer_ServerToken
\brief The handle for an ILibWebServer module
*/
typedef void* ILibWebServer_ServerToken;
struct ILibWebServer_Session;
/*! \typedef ILibWebServer_Session_OnReceive
\brief OnReceive Handler
\param sender The associate \a ILibWebServer_Session object
\param InterruptFlag boolean indicating if the underlying chain/thread is disposing
\param header The HTTP headers that were received
\param bodyBuffer Pointer to the HTTP body
\param[in,out] beginPointer Starting offset of the body buffer. Advance this pointer when the data is consumed.
\param endPointer Length of available data pointed to by \a bodyBuffer
\param done boolean indicating if the entire packet has been received
*/
typedef void (*ILibWebServer_Session_OnReceive)(struct ILibWebServer_Session *sender, int InterruptFlag, struct packetheader *header, char *bodyBuffer, int *beginPointer, int endPointer, ILibWebServer_DoneFlag done);
/*! \typedef ILibWebServer_Session_OnDisconnect
\brief Handler for when an ILibWebServer_Session object is disconnected
\param sender The \a ILibWebServer_Session object that was disconnected
*/
typedef void (*ILibWebServer_Session_OnDisconnect)(struct ILibWebServer_Session *sender);
/*! \typedef ILibWebServer_Session_OnSendOK
\brief Handler for when pending send operations have completed
\par
<B>Note:</B> This handler will only be called after all pending data from any call(s) to
\a ILibWebServer_Send, \a ILibWebServer_Send_Raw, \a ILibWebServer_StreamBody,
\a ILibWebServer_StreamHeader, and/or \a ILibWebServer_StreamHeader_Raw, have completed. You will need to look at the return values
of those methods, to determine if there is any pending data that still needs to be sent. That will determine if this handler will get called.
\param sender The \a ILibWebServer_Session that has completed sending all of the pending data
*/
typedef void (*ILibWebServer_Session_OnSendOK)(struct ILibWebServer_Session *sender);
/*! \struct ILibWebServer_Session
\brief A structure representing the state of an HTTP Session
*/
typedef struct ILibWebServer_Session
{
ILibTransport Reserved_Transport;
//
// DO NOT MODIFY STRUCTURE DEFINITION ABOVE THIS COMMENT LINE (ILibTransport)
//
/*! \var OnReceive
\brief A Function Pointer that is triggered whenever data is received
*/
ILibWebServer_Session_OnReceive OnReceive;
/*! \var OnDisconnect
\brief A Function Pointer that is triggered when the session is disconnected
*/
ILibWebServer_Session_OnDisconnect OnDisconnect;
/*! \var OnSendOK
\brief A Function Pointer that is triggered when the send buffer is emptied
*/
ILibWebServer_Session_OnSendOK OnSendOK;
void *Parent;
/*! \var User
\brief A reserved pointer that you can use for your own use
*/
void *User;
/*! \var User2
\brief A reserved pointer that you can use for your own use
*/
void *User2;
/*! \var User3
\brief A reserved pointer that you can use for your own use
*/
void *User3;
/*! \var User4
\brief A reserved pointer that you can use for your own use
*/
unsigned int User4;
unsigned int User5;
char* CertificateHashPtr; // Points to the certificate hash (next field) if set
char CertificateHash[32]; // Used by the Mesh to store NodeID of this session
char *buffer;
int bufferLength;
int done;
int SessionInterrupted;
void *ParentExtraMemory;
}ILibWebServer_Session;
void ILibWebServer_AddRef(struct ILibWebServer_Session *session);
void ILibWebServer_Release(struct ILibWebServer_Session *session);
/*! \typedef ILibWebServer_Session_OnSession
\brief New Session Handler
\param SessionToken The new Session
\param User The \a User object specified in \a ILibWebServer_Create
*/
typedef void (*ILibWebServer_Session_OnSession)(struct ILibWebServer_Session *SessionToken, void *User);
/*! \typedef ILibWebServer_VirtualDirectory
\brief Request Handler for a registered Virtual Directory
\param session The session that received the request
\param header The HTTP headers
\param bodyBuffer Pointer to the HTTP body
\param[in,out] beginPointer Starting index of \a bodyBuffer. Advance this pointer as data is consumed
\param endPointer Length of available data in \a bodyBuffer
\param done boolean indicating that the entire packet has been read
\param user The \a user specified in \a ILibWebServer_Create
*/
typedef void (*ILibWebServer_VirtualDirectory)(struct ILibWebServer_Session *session, struct packetheader *header, char *bodyBuffer, int *beginPointer, int endPointer, int done, void *user);
#ifndef MICROSTACK_NOTLS
typedef int(*ILibWebServer_OnHttpsConnection)(ILibWebServer_ServerToken sender, int preverify_ok, STACK_OF(X509) *certs, struct sockaddr_in6* addr);
int ILibWebServer_EnableHTTPS(ILibWebServer_ServerToken object, struct util_cert* leafCert, X509* nonLeafCert, int requestClientCert, ILibWebServer_OnHttpsConnection onHTTPS);
X509 *ILibWebServer_Session_SslGetCert(ILibWebServer_Session* session);
STACK_OF(X509) *ILibWebServer_Session_SslGetCerts(ILibWebServer_Session* session);
#ifdef MICROSTACK_TLS_DETECT
void ILibWebServer_SetTLS(ILibWebServer_ServerToken object, void *ssl_ctx, int enableTLSDetect);
#define ILibWebServer_IsUsingTLS(session) ILibAsyncSocket_IsUsingTls(ILibWebServer_Session_GetConnectionToken(session))
#else
void ILibWebServer_SetTLS(ILibWebServer_ServerToken object, void *ssl_ctx);
#endif
#endif
void ILibWebServer_SetTag(ILibWebServer_ServerToken WebServerToken, void *Tag);
void *ILibWebServer_GetTag(ILibWebServer_ServerToken WebServerToken);
void *ILibWebServer_Session_GetConnectionToken(ILibWebServer_Session *session);
ILibWebServer_ServerToken ILibWebServer_CreateEx(void *Chain, int MaxConnections, unsigned short PortNumber, int loopbackFlag, ILibWebServer_Session_OnSession OnSession, void *User);
ILibExportMethod ILibWebServer_ServerToken ILibWebServer_CreateEx2(void *Chain, int MaxConnections, unsigned short PortNumber, int loopbackFlag, ILibWebServer_Session_OnSession OnSession, int ExtraMemorySize, void *User);
#define ILibWebServer_Create(Chain, MaxConnections, PortNumber, OnSession, User) ILibWebServer_CreateEx(Chain, MaxConnections, PortNumber, INADDR_ANY, OnSession, User)
#define ILibWebServer_Create2(Chain, MaxConnections, PortNumber, OnSession, ExtraMemorySize, User) ILibWebServer_CreateEx2(Chain, MaxConnections, PortNumber, INADDR_ANY, OnSession, ExtraMemorySize, User)
void ILibWebServer_StopListener(ILibWebServer_ServerToken server);
void ILibWebServer_RestartListener(ILibWebServer_ServerToken server);
int ILibWebServer_RegisterVirtualDirectory(ILibWebServer_ServerToken WebServerToken, char *vd, int vdLength, ILibWebServer_VirtualDirectory OnVirtualDirectory, void *user);
int ILibWebServer_UnRegisterVirtualDirectory(ILibWebServer_ServerToken WebServerToken, char *vd, int vdLength);
// Checks if the Web Request is uses digest authentication. Returns non zero if the request is using digest authentication
ILibExportMethod int ILibWebServer_Digest_IsAuthenticated(struct ILibWebServer_Session *session, char* realm, int realmLen);
// Gets the username that the client used to authenticate
ILibExportMethod char* ILibWebServer_Digest_GetUsername(struct ILibWebServer_Session *session);
// Validates the client's digest authentication response. Returns 0 on failure, 1 on success
ILibExportMethod int ILibWebServer_Digest_ValidatePassword(struct ILibWebServer_Session *session, char* password, int passwordLen);
// Send un-autorized response
ILibExportMethod void ILibWebServer_Digest_SendUnauthorized(struct ILibWebServer_Session *session, char* realm, int realmLen, char* html, int htmllen);
// Returns NULL if the request was not CrossSite, otherwise returns the contents of the Origin header
ILibExportMethod char* ILibWebServer_IsCrossSiteRequest(ILibWebServer_Session* session);
ILibExportMethod int ILibWebServer_UpgradeWebSocket(struct ILibWebServer_Session *session, int autoFragmentReassemblyMaxBufferSize);
ILibExportMethod enum ILibWebServer_Status ILibWebServer_WebSocket_Send(struct ILibWebServer_Session *session, char* buffer, int bufferLen, ILibWebServer_WebSocket_DataTypes bufferType, enum ILibAsyncSocket_MemoryOwnership userFree, ILibWebServer_WebSocket_FragmentFlags fragmentStatus);
ILibExportMethod void ILibWebServer_WebSocket_Close(struct ILibWebServer_Session *session);
/* Gets the WebSocket DataFrame type from the ILibWebServer_Session object 'x' */
ILibExportMethod ILibWebServer_WebSocket_DataTypes ILibWebServer_WebSocket_GetDataType(ILibWebServer_Session *session);
ILibExportMethod enum ILibWebServer_Status ILibWebServer_Send(struct ILibWebServer_Session *session, struct packetheader *packet);
ILibExportMethod enum ILibWebServer_Status ILibWebServer_Send_Raw(struct ILibWebServer_Session *session, char *buffer, int bufferSize, enum ILibAsyncSocket_MemoryOwnership userFree, ILibWebServer_DoneFlag done);
/*! \def ILibWebServer_Session_GetPendingBytesToSend
\brief Returns the number of outstanding bytes to be sent
\param session The ILibWebServer_Session object to query
*/
unsigned int ILibWebServer_Session_GetPendingBytesToSend(struct ILibWebServer_Session *session);
/*! \def ILibWebServer_Session_GetTotalBytesSent
\brief Returns the total number of bytes sent
\param session The ILibWebServer_Session object to query
*/
#define ILibWebServer_Session_GetTotalBytesSent(session) ILibAsyncServerSocket_GetTotalBytesSent(session->Reserved1,session->Reserved2)
/*! \def ILibWebServer_Session_ResetTotalBytesSent
\brief Resets the total bytes set counter
\param session The ILibWebServer_Session object to query
*/
#define ILibWebServer_Session_ResetTotalBytesSent(session) ILibAsyncServerSocket_ResetTotalBytesSent(session->Reserved1,session->Reserved2)
unsigned short ILibWebServer_GetPortNumber(ILibWebServer_ServerToken WebServerToken);
int ILibWebServer_GetLocalInterface(struct ILibWebServer_Session *session, struct sockaddr *localAddress);
int ILibWebServer_GetRemoteInterface(struct ILibWebServer_Session *session, struct sockaddr *remoteAddress);
enum ILibWebServer_Status ILibWebServer_StreamHeader(struct ILibWebServer_Session *session, struct packetheader *header);
enum ILibWebServer_Status ILibWebServer_StreamBody(struct ILibWebServer_Session *session, char *buffer, int bufferSize, enum ILibAsyncSocket_MemoryOwnership userFree, ILibWebServer_DoneFlag done);
// ResponseHeaders must start with \r\n. Do not trail with \r\n
enum ILibWebServer_Status ILibWebServer_StreamHeader_Raw(struct ILibWebServer_Session *session, int StatusCode, char *StatusData, char *ResponseHeaders, enum ILibAsyncSocket_MemoryOwnership ResponseHeaders_FREE);
void ILibWebServer_DisconnectSession(struct ILibWebServer_Session *session);
ILibExportMethod void ILibWebServer_Pause(struct ILibWebServer_Session *session);
ILibExportMethod void ILibWebServer_Resume(struct ILibWebServer_Session *session);
void ILibWebServer_OverrideReceiveHandler(struct ILibWebServer_Session *session, ILibWebServer_Session_OnReceive OnReceive);
void ILibWebServer_StreamFile(struct ILibWebServer_Session *session, FILE* pfile);
#ifdef __cplusplus
}
#endif
/* \} */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,389 @@
/*
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.
*/
#ifndef MICROSTACK_NOTLS
#ifndef ___ILibWrapper_WebRTC___
#define ___ILibWrapper_WebRTC___
#include "ILibAsyncSocket.h"
#include "ILibCrypto.h"
#define ILibWebWrapperWebRTC_ConnectionFactory_INIT_CRYPTO_LATER (void*)0x01
/*! \file ILibWrapperWebRTC.h
\brief Microstack API/Abstraction for WebRTC Functionality
*/
/*! \defgroup ILibWrapperWebRTC ILibWrapperWebRTC Module */
/*! @{ */
#define ILibTransports_WebRTC_DataChannel 0x51
extern const int ILibMemory_WebRTC_Connection_CONTAINERSIZE;
/** Factory object that is used to create WebRTC Connections. */
typedef void* ILibWrapper_WebRTC_ConnectionFactory;
/** Object encapsulating WebRTC Peer Connections. */
typedef void* ILibWrapper_WebRTC_Connection;
struct ILibWrapper_WebRTC_DataChannel;
//! Handler for when a remote peer has ACK'ed a Create Data Channel request
/*
\param dataChannel The data channel that the peer has AcK'ed
*/
typedef void(*ILibWrapper_WebRTC_DataChannel_OnDataChannelAck)(struct ILibWrapper_WebRTC_DataChannel* dataChannel);
//! Handler for when data is received on a Data Channel
/*!
\param dataChannel The Data Channel on which data has arrived
\param data Received data
\param dataLen Number of bytes received
*/
typedef void(*ILibWrapper_WebRTC_DataChannel_OnData)(struct ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen);
//! Raw Handler for when data is received on a Data Channel
/*!
\param dataChannel The Data Channel on which data has arrived
\param data Received Data
\param dataLen Number of bytes received
\param dataType Kind of Data received. 51 = String, 53 = Binary, etc.
*/
typedef void(*ILibWrapper_WebRTC_DataChannel_OnRawData)(struct ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen, int dataType);
//! Handler for when a data channel is closed
/*!
\param dataChannel The data channel that was closed
*/
typedef void(*ILibWrapper_WebRTC_DataChannel_OnClosed)(struct ILibWrapper_WebRTC_DataChannel* dataChannel);
/** DataChannel abstraction used to send/receive peer-to-peer data. */
typedef struct ILibWrapper_WebRTC_DataChannel
{
ILibWrapper_WebRTC_DataChannel_OnData OnBinaryData; //!< Binary Data Event Handler
ILibWrapper_WebRTC_DataChannel_OnData OnStringData; //!< String Data Event Handler
ILibWrapper_WebRTC_DataChannel_OnRawData OnRawData; //!< Raw Data Event Handler
void* Chain; //!< Microstack Chain to which this object resides
void* ReservedMemory; //!< RESERVED
ILibTransport_SendPtr SendPtr; //!< RESERVED
ILibTransport_ClosePtr ClosePtr; //!< RESERVED
ILibTransport_PendingBytesToSendPtr PendingBytesPtr; //!< RESERVED
ILibTransport_OnSendOK TransportSendOKPtr; //!< RESERVED
unsigned int IdentifierFlags; //!< RESERVED
/*
*
* DO NOT MODIFY STRUCT DEFINITION ABOVE THIS COMMENT BLOCK
*
*/
unsigned short streamId; //!< Stream Identifier for this Data Channel
char* channelName; //!< Friendly Name for this Data Channel
ILibWrapper_WebRTC_DataChannel_OnDataChannelAck OnAck; //!< Event triggered when Data Channel creation is ACKnowledged by the remote peer.
ILibWrapper_WebRTC_DataChannel_OnClosed OnClosed; //!< Event triggered when the Data Channel has been closed.
ILibWrapper_WebRTC_Connection parent; //!< The Peer Connection object that owns this data channel object
void* userData; //!< User specified state object
}ILibWrapper_WebRTC_DataChannel;
//! Handler for new ICE candidates
/*!
\param connection The RTC Peer Connection object that called
\param candidate The ICE candidate
*/
typedef void(*ILibWrapper_WebRTC_OnConnectionCandidate)(ILibWrapper_WebRTC_Connection connection, struct sockaddr_in6* candidate);
//! Handler for when the connection state of an SCTP session has changed
/*!
\param connection The RTC Peer Connection parent object
\param connected 0 = Disconnected, 1 = Connected
*/
typedef void(*ILibWrapper_WebRTC_Connection_OnConnect)(ILibWrapper_WebRTC_Connection connection, int connected);
//! Handler for when a new Data Channel was established
/*!
\param connection Parent RTC Peer Connection object
\param dataChannel The Data Channel object that was created
*/
typedef void(*ILibWrapper_WebRTC_Connection_OnDataChannel)(ILibWrapper_WebRTC_Connection connection, ILibWrapper_WebRTC_DataChannel *dataChannel);
//! Handler for when all the buffered send operations for a Peer Connection has been flushed
/*!
\param connection The RTC Peer Connection object whose send buffers have been flushed
*/
typedef void(*ILibWrapper_WebRTC_Connection_OnSendOK)(ILibWrapper_WebRTC_Connection connection);
typedef void(*ILibWrapper_WebRTC_Connection_Debug_OnEvent)(ILibWrapper_WebRTC_Connection connection, char* debugFieldName, int debugValue);
/**
* \defgroup WebRTC_ConnectionFactory WebRTC Connection Factory Methods
* @{
*/
//! Creates a Factory object that can create WebRTC Connection objects.
/*!
\paramn chain The microstack chain to associate with this factory
\param localPort The local UDP port to bind, for ICE/DTLS. 0 = Random
\return A new connection factory instance
*/
ILibWrapper_WebRTC_ConnectionFactory ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionFactory(void* chain, unsigned short localPort);
//! Creates a Factory object that can create WebRTC Connection objects, using the specified certs
/*!
\paramn chain The microstack chain to associate with this factory
\param localPort The local UDP port to bind, for ICE/DTLS. 0 = Random
\param tlsCert The certificate to use. ILibWebWrapperWebRTC_ConnectionFactory_INIT_CRYPTO_LATER to init crypto later
\return A new connection factory instance
*/
ILibWrapper_WebRTC_ConnectionFactory ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionFactory2(void* chain, unsigned short localPort, struct util_cert *tlsCert);
//! Initializes the crypto for a ConnectionFactory object. (Note: Only valid if ILibWebWrapperWebRTC_ConnectionFactory_INIT_CRYPTO_LATER was used previously)
/*!
\paramn factory The ConnectionFactory object to initialize crypto on
\param tlsCert The certificate to use, or NULL to generate self certs
*/
void ILibWrapper_WebRTC_ConnectionFactory_InitCrypto(ILibWrapper_WebRTC_ConnectionFactory factory, struct util_cert *tlsCert);
void ILibWrapper_WebRTC_Connection_SetOnSendOK(ILibWrapper_WebRTC_Connection connection, ILibWrapper_WebRTC_Connection_OnSendOK SendOKSink);
SSL_CTX* ILibWrapper_WebRTC_ConnectionFactory_GetCTX(ILibWrapper_WebRTC_ConnectionFactory factory);
void* ILibWrapper_WebRTC_Connection_GetChain(ILibWrapper_WebRTC_Connection connection);
void ILibWrapper_WebRTC_ConnectionFactory_SendRaw(ILibWrapper_WebRTC_ConnectionFactory factory, struct sockaddr* target, char* data, int datalen, enum ILibAsyncSocket_MemoryOwnership UserFree);
//! Sets the TURN server to use for all WebRTC connections.
/*!
\param factory ConnectionFactory to configure
\param turnServer The TURN Server to configure
\param username Username for the TURN Server
\param usernameLength Length of buffer holding username
\param password Password for the TURN Server
\param passwordLength Length of the buffer holding the password
\param turnSetting TURN configuration settings
*/
void ILibWrapper_WebRTC_ConnectionFactory_SetTurnServer(ILibWrapper_WebRTC_ConnectionFactory factory, struct sockaddr_in6* turnServer, char* username, int usernameLength, char* password, int passwordLength, ILibWebRTC_TURN_ConnectFlags turnSetting);
typedef void(*ILibWrapper_WebRTC_ConnectionFactory_STUNHandler)(ILibWrapper_WebRTC_ConnectionFactory sender, ILibStun_Results Result, struct sockaddr_in* PublicIP);
void ILibWrapper_WebRTC_ConnectionFactory_PerformSTUN(ILibWrapper_WebRTC_ConnectionFactory factory, struct sockaddr_in* StunServer);
void ILibWrapper_WebRTC_ConnectionFactory_Set_STUNHandler(ILibWrapper_WebRTC_ConnectionFactory factory, ILibWrapper_WebRTC_ConnectionFactory_STUNHandler handler);
//! Creates an unconnected WebRTC Connection.
/*!
\param factory ConnectionFactory to use to create the RTC Peer Connection
\param OnConnectHandler Callback to trigger when the connection state has changed
\param OnDataChannelHandler Callback to trigger when new Data Channels are established for the new RTC Peer Connection
\param OnConnectionSendOK Callback to trigger when buffered Send data for the Peer Connection is flushed.
\return An unconnected RTC Peer Connection
*/
ILibWrapper_WebRTC_Connection ILibWrapper_WebRTC_ConnectionFactory_CreateConnection(ILibWrapper_WebRTC_ConnectionFactory factory, ILibWrapper_WebRTC_Connection_OnConnect OnConnectHandler, ILibWrapper_WebRTC_Connection_OnDataChannel OnDataChannelHandler, ILibWrapper_WebRTC_Connection_OnSendOK OnConnectionSendOK);
//! Creates an unconnected WebRTC Connection, with ILibMemory
/*!
\param factory ConnectionFactory to use to create the RTC Peer Connection
\param OnConnectHandler Callback to trigger when the connection state has changed
\param OnDataChannelHandler Callback to trigger when new Data Channels are established for the new RTC Peer Connection
\param OnConnectionSendOK Callback to trigger when buffered Send data for the Peer Connection is flushed.
\param extraMemorySize The size of the extra memory partition to allocation
\return An unconnected RTC Peer Connection
*/
ILibWrapper_WebRTC_Connection ILibWrapper_WebRTC_ConnectionFactory_CreateConnection2(ILibWrapper_WebRTC_ConnectionFactory factory, ILibWrapper_WebRTC_Connection_OnConnect OnConnectHandler, ILibWrapper_WebRTC_Connection_OnDataChannel OnDataChannelHandler, ILibWrapper_WebRTC_Connection_OnSendOK OnConnectionSendOK, int extraMemorySize);
//! Fetches the associated WebRTC Connection object from the IceOfferBlock (creating a new one if it doesn't exist), and sets the remote offer
/*!
\param factory ConnectionFactory to use to create the RTC Peer Connection
\param iceOfferBlock The IceOfferBlock from MeshCentral
\param iceOfferBlockLen The length of the IceOfferBlock from MeshCentral
\param OnConnectHandler Callback to trigger when the connection state has changed
\param OnDataChannelHandler Callback to trigger when new Data Channels are established for the new RTC Peer Connection
\param OnConnectionSendOK Callback to trigger when buffered Send data for the Peer Connection is flushed.
\return An unconnected RTC Peer Connection
*/
ILibWrapper_WebRTC_Connection ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionEx(ILibWrapper_WebRTC_ConnectionFactory factory, char *iceOfferBlock, int iceOfferBlockLen, ILibWrapper_WebRTC_Connection_OnConnect OnConnectHandler, ILibWrapper_WebRTC_Connection_OnDataChannel OnDataChannelHandler, ILibWrapper_WebRTC_Connection_OnSendOK OnConnectionSendOK);
ILibWrapper_WebRTC_Connection ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionEx2(ILibWrapper_WebRTC_ConnectionFactory factory, char *iceOfferBlock, int iceOfferBlockLen, ILibWrapper_WebRTC_Connection_OnConnect OnConnectHandler, ILibWrapper_WebRTC_Connection_OnDataChannel OnDataChannelHandler, ILibWrapper_WebRTC_Connection_OnSendOK OnConnectionSendOK, int extraMemorySize);
/** @}*/
/**
* \defgroup WebRTC_Connection WebRTC Connection Methods
* @{
*/
int ILibWrapper_WebRTC_Connection_GetID(ILibWrapper_WebRTC_Connection connection);
char* ILibWrapper_WebRTC_Connection_GetLocalUsername(ILibWrapper_WebRTC_Connection connection);
ILibTransport* ILibWrapper_WebRTC_Connection_GetRawTransport(ILibWrapper_WebRTC_Connection connection);
//! Set the STUN Servers to use with the WebRTC Connection when gathering candidates
/*!
\param connection RTC Peer Connection to configure
\param serverList Array of NULL terminated strings, where each string is a STUN Server Hostname
\param serverLength Size of the serverList array
*/
void ILibWrapper_WebRTC_Connection_SetStunServers(ILibWrapper_WebRTC_Connection connection, char** serverList, int serverLength);
//! Queries the SCTP connection state of an RTC Peer Connection
/*!
\param connection The RTC Peer Connection to query
\return 0 = Disconnected, Non-Zero = Connected
*/
int ILibWrapper_WebRTC_Connection_IsConnected(ILibWrapper_WebRTC_Connection connection);
//! Disconnects the unerlying SCTP session, if it is connected
/*!
\param connection The RTC Peer Connection to disconnect
*/
void ILibWrapper_WebRTC_Connection_Disconnect(ILibWrapper_WebRTC_Connection connection);
//! Gets the underlying Local ICE Offer Block
/*!
\param connection The RTC Peer Connection to query
\param localOfferBlock the Local Offer Block associated with this connection
\return The length of localOfferBlock
*/
int ILibWrapper_WebRTC_Connection_GetLocalOfferBlock(ILibWrapper_WebRTC_Connection connection, char **localOfferBlock);
//! Destroys a WebRTC Connection
/*!
\param connection The RTC Peer Connection to destroy
*/
void ILibWrapper_WebRTC_Connection_DestroyConnection(ILibWrapper_WebRTC_Connection connection);
void ILibWrapper_WebRTC_Connection_CloseAllDataChannels(ILibWrapper_WebRTC_Connection connection);
//! Closes the WebRTC Data Channel.
//! If SCTP/RECONFIG is supported, it will request to close the Data Channel before shutting down DTLS
/*!
\ingroup WebRTC_DataChannel
\param dataChannel The Data Channel to close.
*/
void ILibWrapper_WebRTC_DataChannel_Close(ILibWrapper_WebRTC_DataChannel* dataChannel);
//! Creates a WebRTC Data Channel, using the next available Stream ID
/*!
\ingroup WebRTC_DataChannel
\param connection The RTC Peer Connection on which to create a new data channel
\param channelName Name of the data channel to create
\param channelNameLen Length of channelName
\param OnAckHandler Callback to trigger when the Remote Peer ACK's this request (Can be NULL)
\return An un-Acknowledged Data Channel
*/
ILibWrapper_WebRTC_DataChannel* ILibWrapper_WebRTC_DataChannel_Create(ILibWrapper_WebRTC_Connection connection, char* channelName, int channelNameLen, ILibWrapper_WebRTC_DataChannel_OnDataChannelAck OnAckHandler);
//! Creates a WebRTC Data Channel, using the specified Stream ID
/*!
\ingroup WebRTC_DataChannel
\param connection The RTC Peer Connection on which to create a new data channel
\param channelName Name of the data channel to create
\param channelNameLen Length of channelName
\param streamId The stream identifier to associate with the Data Channel
\param OnAckHandler Callback to trigger when the Remote Peer ACK's this request (Can be NULL)
\return An un-Acknowledged Data Channel
*/
ILibWrapper_WebRTC_DataChannel* ILibWrapper_WebRTC_DataChannel_CreateEx(ILibWrapper_WebRTC_Connection connection, char* channelName, int channelNameLen, unsigned short streamId, ILibWrapper_WebRTC_DataChannel_OnDataChannelAck OnAckHandler);
//! Sets Custom User State Data
/*!
\param connection The RTC Peer Connection to set user data to
\param user1
\param user2
\param user3
*/
void ILibWrapper_WebRTC_Connection_SetUserData(ILibWrapper_WebRTC_Connection connection, void *user1, void *user2, void *user3);
//! Retrieves stored Custom User State Data
/*!
\param connection The RTC Peer Connection to fetch user data from
\param user1
\param user2
\param user3
*/
void ILibWrapper_WebRTC_Connection_GetUserData(ILibWrapper_WebRTC_Connection connection, void **user1, void **user2, void **user3);
int ILibWrapper_WebRTC_Connection_DoesPeerSupportUnreliableMode(ILibWrapper_WebRTC_Connection connection);
int ILibWrapper_WebRTC_Connection_SetReliabilityMode(ILibWrapper_WebRTC_Connection connection, int isOrdered, short maxRetransmits, short maxLifetime);
// WebRTC Connection Management
void ILibWrapper_WebRTC_Connection_CreateLocalParameters_ICE(ILibWrapper_WebRTC_Connection connection);
void ILibWrapper_WebRTC_Connection_GetLocalParameters_ICE(ILibWrapper_WebRTC_Connection connection, char **username, int *usernameLen, char **password, int *passwordLen);
void ILibWrapper_WebRTC_Connection_GetLocalParameters_DTLS(ILibWrapper_WebRTC_Connection connection, char **hash, int *hashLen);
//! Generate an SDP Offer (WebRTC Initiator)
/*!
\param connection The RTC Connection object to act as initiator
\param onCandidates Callback triggered for each discovered ICE candidate
\return SDP offer that contains only local candidates
*/
char* ILibWrapper_WebRTC_Connection_GenerateOffer(ILibWrapper_WebRTC_Connection connection, ILibWrapper_WebRTC_OnConnectionCandidate onCandidates);
//! Set an SDP Answer/Offer
/*!
\param connection The RTC Connection object to set the response to
\param offer The SDP Answer/Offer to set
\param offerLen The size of the buffer holding the SDP
\param onCandidates Callback to trigger when additional ICE candidates are discovered
\return SDP Counter Offer, containing only local candidates, which can be returned to the sender
*/
char* ILibWrapper_WebRTC_Connection_SetOffer(ILibWrapper_WebRTC_Connection connection, char* offer, int offerLen, ILibWrapper_WebRTC_OnConnectionCandidate onCandidates);
//! Generate an udpated SDP offer containing the reflexive candidate specified
/*!
\param connection The RTC Peer Connection that generated the reflexive candidate
\param candidate The reflexive candidate
\return SDP Offer containing the reflexive candidate
*/
char* ILibWrapper_WebRTC_Connection_AddServerReflexiveCandidateToLocalSDP(ILibWrapper_WebRTC_Connection connection, struct sockaddr_in6* candidate);
// Pause processing inbound data, and buffer it
/*!
\param connection The RTC Connection to pause
*/
void ILibWrapper_WebRTC_Connection_Pause(ILibWrapper_WebRTC_Connection connection);
//! Resume processing inbound data
/*!
\param connection The RTC Connection to resume
*/
void ILibWrapper_WebRTC_Connection_Resume(ILibWrapper_WebRTC_Connection connection);
/** @}*/
/**
* \defgroup WebRTC_DataChannel WebRTC Data Channel Methods
* @{
*/
//! Send Binary Data over the specified Data Channel
/*!
\param dataChannel The Data Channel to send the data on
\param data The binary data to send
\param dataLen The size of the binary data buffer
\return The Send status of the send operation
*/
ILibTransport_DoneState ILibWrapper_WebRTC_DataChannel_Send(ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen);
//! Send Arbitrary Data over the specified Data Channel.
/*!
\param dataChannel The Data Channel to send the data on
\param data The data to send
\param dataLen The size of the data buffer
\param dataType The type of data to be sent (51 = String, 53 = Binary, etc)
\return The Send status of the send operation
*/
ILibTransport_DoneState ILibWrapper_WebRTC_DataChannel_SendEx(ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen, int dataType);
//! Send String Data over the specified Data Channel
/*!
\param dataChannel The Data Channel to send the data on
\param data The string data to send
\param dataLen The size of the string data buffer
\return The Send status of the send operation
*/
ILibTransport_DoneState ILibWrapper_WebRTC_DataChannel_SendString(ILibWrapper_WebRTC_DataChannel* dataChannel, char* data, int dataLen);
#ifdef _WEBRTCDEBUG
int ILibWrapper_WebRTC_Connection_Debug_Set(ILibWrapper_WebRTC_Connection connection, char* debugFieldName, ILibWrapper_WebRTC_Connection_Debug_OnEvent eventHandler);
void ILibWrapper_WebRTC_ConnectionFactory_SetSimulatedLossPercentage(ILibWrapper_WebRTC_ConnectionFactory factory, int lossPercentage);
#endif
/** @}*/
/** @}*/
#endif
#endif

310
microstack/SHA256.c Normal file
View File

@@ -0,0 +1,310 @@
/* Functions to compute SHA256 message digest of files or memory blocks.
according to the definition of SHA256 in FIPS 180-2.
Copyright (C) 2007, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <endian.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "sha256.h"
#if __BYTE_ORDER == __LITTLE_ENDIAN
# ifdef _LIBC
# include <byteswap.h>
# define SWAP(n) bswap_32 (n)
# define SWAP64(n) bswap_64 (n)
# else
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
# define SWAP64(n) \
(((n) << 56) \
| (((n) & 0xff00) << 40) \
| (((n) & 0xff0000) << 24) \
| (((n) & 0xff000000) << 8) \
| (((n) >> 8) & 0xff000000) \
| (((n) >> 24) & 0xff0000) \
| (((n) >> 40) & 0xff00) \
| ((n) >> 56))
# endif
#else
# define SWAP(n) (n)
# define SWAP64(n) (n)
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (FIPS 180-2:5.1.1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Constants for SHA256 from FIPS 180-2:4.2.2. */
static const uint32_t K[64] =
{
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
static void
sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx)
{
const uint32_t *words = buffer;
size_t nwords = len / sizeof(uint32_t);
uint32_t a = ctx->H[0];
uint32_t b = ctx->H[1];
uint32_t c = ctx->H[2];
uint32_t d = ctx->H[3];
uint32_t e = ctx->H[4];
uint32_t f = ctx->H[5];
uint32_t g = ctx->H[6];
uint32_t h = ctx->H[7];
/* First increment the byte count. FIPS 180-2 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. */
ctx->total64 += len;
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (nwords > 0)
{
uint32_t W[64];
uint32_t a_save = a;
uint32_t b_save = b;
uint32_t c_save = c;
uint32_t d_save = d;
uint32_t e_save = e;
uint32_t f_save = f;
uint32_t g_save = g;
uint32_t h_save = h;
/* Operators defined in FIPS 180-2:4.1.2. */
#define Ch(x, y, z) ((x & y) ^ (~x & z))
#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
/* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
for (unsigned int t = 0; t < 16; ++t)
{
W[t] = SWAP(*words);
++words;
}
for (unsigned int t = 16; t < 64; ++t)
W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
/* The actual computation according to FIPS 180-2:6.2.2 step 3. */
for (unsigned int t = 0; t < 64; ++t)
{
uint32_t T1 = h + S1(e) + Ch(e, f, g) + K[t] + W[t];
uint32_t T2 = S0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
/* Add the starting values of the context according to FIPS 180-2:6.2.2
step 4. */
a += a_save;
b += b_save;
c += c_save;
d += d_save;
e += e_save;
f += f_save;
g += g_save;
h += h_save;
/* Prepare for the next round. */
nwords -= 16;
}
/* Put checksum in context given as argument. */
ctx->H[0] = a;
ctx->H[1] = b;
ctx->H[2] = c;
ctx->H[3] = d;
ctx->H[4] = e;
ctx->H[5] = f;
ctx->H[6] = g;
ctx->H[7] = h;
}
/* Initialize structure containing state of computation.
(FIPS 180-2:5.3.2) */
void
__sha256_init_ctx(ctx)
struct sha256_ctx *ctx;
{
ctx->H[0] = 0x6a09e667;
ctx->H[1] = 0xbb67ae85;
ctx->H[2] = 0x3c6ef372;
ctx->H[3] = 0xa54ff53a;
ctx->H[4] = 0x510e527f;
ctx->H[5] = 0x9b05688c;
ctx->H[6] = 0x1f83d9ab;
ctx->H[7] = 0x5be0cd19;
ctx->total64 = 0;
ctx->buflen = 0;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
void *
__sha256_finish_ctx(ctx, resbuf)
struct sha256_ctx *ctx;
void *resbuf;
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total64 += bytes;
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy(&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
#ifdef _STRING_ARCH_unaligned
ctx->buffer64[(bytes + pad) / 8] = SWAP64(ctx->total64 << 3);
#else
ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3);
ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3) |
(ctx->total[TOTAL64_low] >> 29));
#endif
/* Process last bytes. */
sha256_process_block(ctx->buffer, bytes + pad + 8, ctx);
/* Put result from CTX in first 32 bytes following RESBUF. */
for (unsigned int i = 0; i < 8; ++i)
((uint32_t *)resbuf)[i] = SWAP(ctx->H[i]);
return resbuf;
}
void
__sha256_process_bytes(buffer, len, ctx)
const void *buffer;
size_t len;
struct sha256_ctx *ctx;
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy(&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *)buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !_STRING_ARCH_unaligned
/* To check alignment gcc has an appropriate operator. Other
compilers don't. */
# if __GNUC__ >= 2
# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint32_t) != 0)
# else
# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint32_t) != 0)
# endif
if (UNALIGNED_P(buffer))
while (len > 64)
{
sha256_process_block(memcpy(ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *)buffer + 64;
len -= 64;
}
else
#endif
{
sha256_process_block(buffer, len & ~63, ctx);
buffer = (const char *)buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes into internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy(&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
sha256_process_block(ctx->buffer, 64, ctx);
left_over -= 64;
memcpy(ctx->buffer, &ctx->buffer[64], left_over);
}
ctx->buflen = left_over;
}
}

65
microstack/SHA256.h Normal file
View File

@@ -0,0 +1,65 @@
/* Declaration of functions and data types used for SHA256 sum computing
library functions.
Copyright (C) 2007, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _SHA256_H
#define _SHA256_H 1
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <endian.h>
/* Structure to save state of computation between the single steps. */
struct sha256_ctx
{
uint32_t H[8];
union
{
uint64_t total64;
#define TOTAL64_low (1 - (BYTE_ORDER == LITTLE_ENDIAN))
#define TOTAL64_high (BYTE_ORDER == LITTLE_ENDIAN)
uint32_t total[2];
};
uint32_t buflen;
union
{
char buffer[128];
uint32_t buffer32[32];
uint64_t buffer64[16];
};
};
/* Initialize structure containing state of computation.
(FIPS 180-2: 5.3.2) */
extern void __sha256_init_ctx(struct sha256_ctx *ctx) __THROW;
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void __sha256_process_bytes(const void *buffer, size_t len,
struct sha256_ctx *ctx) __THROW;
/* Process the remaining bytes in the buffer and put result from CTX
in first 32 bytes following RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *__sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf)
__THROW;
#endif /* sha256.h */

296
microstack/md5.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#if !defined(HAVE_OPENSSL) && defined(MICROSTACK_NOTLS)
#include <string.h>
#include "md5.h"
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) (((x) ^ (y)) ^ (z))
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them
* in a properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned
* memory accesses is just an optimization. Nothing will break if it
* doesn't work.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
(*(MD5_u32plus *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update
* the bit counters. There are no alignment requirements.
*/
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD5_u32plus a, b, c, d;
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
ptr = (const unsigned char *)data;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
void MD5_Init(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
}
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
MD5_u32plus saved_lo;
unsigned long used, available;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
available = 64 - used;
if (size < available) {
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
body(ctx, ctx->buffer, 64);
}
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
unsigned long used, available;
used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
available = 64 - used;
if (available < 8) {
memset(&ctx->buffer[used], 0, available);
body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->buffer[used], 0, available - 8);
ctx->lo <<= 3;
ctx->buffer[56] = (unsigned char)(ctx->lo);
ctx->buffer[57] = (unsigned char)(ctx->lo >> 8);
ctx->buffer[58] = (unsigned char)(ctx->lo >> 16);
ctx->buffer[59] = (unsigned char)(ctx->lo >> 24);
ctx->buffer[60] = (unsigned char)(ctx->hi);
ctx->buffer[61] = (unsigned char)(ctx->hi >> 8);
ctx->buffer[62] = (unsigned char)(ctx->hi >> 16);
ctx->buffer[63] = (unsigned char)(ctx->hi >> 24);
body(ctx, ctx->buffer, 64);
result[0] = (unsigned char)(ctx->a);
result[1] = (unsigned char)(ctx->a >> 8);
result[2] = (unsigned char)(ctx->a >> 16);
result[3] = (unsigned char)(ctx->a >> 24);
result[4] = (unsigned char)(ctx->b);
result[5] = (unsigned char)(ctx->b >> 8);
result[6] = (unsigned char)(ctx->b >> 16);
result[7] = (unsigned char)(ctx->b >> 24);
result[8] = (unsigned char)(ctx->c);
result[9] = (unsigned char)(ctx->c >> 8);
result[10] = (unsigned char)(ctx->c >> 16);
result[11] = (unsigned char)(ctx->c >> 24);
result[12] = (unsigned char)(ctx->d);
result[13] = (unsigned char)(ctx->d >> 8);
result[14] = (unsigned char)(ctx->d >> 16);
result[15] = (unsigned char)(ctx->d >> 24);
memset(ctx, 0, sizeof(*ctx));
}
#endif

45
microstack/md5.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
#ifdef HAVE_OPENSSL
#include <openssl/md5.h>
#elif !defined(_MD5_H)
#define _MD5_H
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;
typedef struct {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
} MD5_CTX;
extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
#endif

325
microstack/sha1.c Normal file
View File

@@ -0,0 +1,325 @@
/* This code is public-domain - it is based on libcrypt
* placed in the public domain by Wei Dai and other contributors.
*
* Obtained from: http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c
* Source Project: http://code.google.com/p/oauth/
*
*/
#ifdef MICROSTACK_NOTLS
#include <stdint.h>
#include <string.h>
#ifdef __BIG_ENDIAN__
# define SHA_BIG_ENDIAN
#elif defined __LITTLE_ENDIAN__
/* override */
#elif defined __BYTE_ORDER
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define SHA_BIG_ENDIAN
# endif
//#else // ! defined __LITTLE_ENDIAN__
//# include <endian.h> // machine/endian.h
//# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
//# define SHA_BIG_ENDIAN
//# endif
#endif
/* header */
#define HASH_LENGTH 20
#define BLOCK_LENGTH 64
#include "sha1.h"
/* public API - prototypes - TODO: doxygen*/
/**
*/
void sha1_writebyte(sha1nfo *s, uint8_t data);
/**
*/
void sha1_write(sha1nfo *s, const char *data, size_t len);
/**
*/
uint8_t* sha1_result(sha1nfo *s);
/**
*/
void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength);
/**
*/
uint8_t* sha1_resultHmac(sha1nfo *s);
/* code */
#define SHA1_K0 0x5a827999
#define SHA1_K20 0x6ed9eba1
#define SHA1_K40 0x8f1bbcdc
#define SHA1_K60 0xca62c1d6
void SHA1_Init(sha1nfo *s)
{
s->state[0] = 0x67452301;
s->state[1] = 0xefcdab89;
s->state[2] = 0x98badcfe;
s->state[3] = 0x10325476;
s->state[4] = 0xc3d2e1f0;
s->byteCount = 0;
s->bufferOffset = 0;
}
uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
return ((number << bits) | (number >> (32-bits)));
}
void sha1_hashBlock(sha1nfo *s) {
uint8_t i;
uint32_t a,b,c,d,e,t;
a=s->state[0];
b=s->state[1];
c=s->state[2];
d=s->state[3];
e=s->state[4];
for (i=0; i<80; i++) {
if (i>=16) {
t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15];
s->buffer[i&15] = sha1_rol32(t,1);
}
if (i<20) {
t = (d ^ (b & (c ^ d))) + SHA1_K0;
} else if (i<40) {
t = (b ^ c ^ d) + SHA1_K20;
} else if (i<60) {
t = ((b & c) | (d & (b | c))) + SHA1_K40;
} else {
t = (b ^ c ^ d) + SHA1_K60;
}
t+=sha1_rol32(a,5) + e + s->buffer[i&15];
e=d;
d=c;
c=sha1_rol32(b,30);
b=a;
a=t;
}
s->state[0] += a;
s->state[1] += b;
s->state[2] += c;
s->state[3] += d;
s->state[4] += e;
}
void sha1_addUncounted(sha1nfo *s, uint8_t data) {
uint8_t * const b = (uint8_t*) s->buffer;
#ifdef SHA_BIG_ENDIAN
b[s->bufferOffset] = data;
#else
b[s->bufferOffset ^ 3] = data;
#endif
s->bufferOffset++;
if (s->bufferOffset == BLOCK_LENGTH) {
sha1_hashBlock(s);
s->bufferOffset = 0;
}
}
void sha1_writebyte(sha1nfo *s, uint8_t data) {
++s->byteCount;
sha1_addUncounted(s, data);
}
void sha1_write(sha1nfo *s, const char *data, size_t len) {
for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
}
void sha1_pad(sha1nfo *s) {
// Implement SHA-1 padding (fips180-2 §5.1.1)
// Pad with 0x80 followed by 0x00 until the end of the block
sha1_addUncounted(s, 0x80);
while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
// Append length in the last 8 bytes
sha1_addUncounted(s, 0); // We're only using 32 bit lengths
sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
sha1_addUncounted(s, 0); // So zero pad the top bits
sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
sha1_addUncounted(s, s->byteCount >> 13); // byte.
sha1_addUncounted(s, s->byteCount >> 5);
sha1_addUncounted(s, s->byteCount << 3);
}
uint8_t* sha1_result(sha1nfo *s) {
int i;
// Pad to complete the last block
sha1_pad(s);
#ifndef SHA_BIG_ENDIAN
// Swap byte order back
for (i=0; i<5; i++) {
s->state[i]=
(((s->state[i])<<24)& 0xff000000)
| (((s->state[i])<<8) & 0x00ff0000)
| (((s->state[i])>>8) & 0x0000ff00)
| (((s->state[i])>>24)& 0x000000ff);
}
#endif
// Return pointer to hash (20 characters)
return (uint8_t*) s->state;
}
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c
void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength) {
uint8_t i;
memset(s->keyBuffer, 0, BLOCK_LENGTH);
if (keyLength > BLOCK_LENGTH) {
// Hash long keys
SHA1_Init(s);
for (;keyLength--;) sha1_writebyte(s, *key++);
memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH);
} else {
// Block length keys are used as is
memcpy(s->keyBuffer, key, keyLength);
}
// Start inner hash
SHA1_Init(s);
for (i=0; i<BLOCK_LENGTH; i++) {
sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD);
}
}
uint8_t* sha1_resultHmac(sha1nfo *s) {
uint8_t i;
// Complete inner hash
memcpy(s->innerHash,sha1_result(s),HASH_LENGTH);
// Calculate outer hash
SHA1_Init(s);
for (i=0; i<BLOCK_LENGTH; i++) sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD);
for (i=0; i<HASH_LENGTH; i++) sha1_writebyte(s, s->innerHash[i]);
return sha1_result(s);
}
/* self-test */
#if SHA1TEST
#include <stdio.h>
uint8_t hmacKey1[]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
};
uint8_t hmacKey2[]={
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43
};
uint8_t hmacKey3[]={
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3
};
uint8_t hmacKey4[]={
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0
};
void printHash(uint8_t* hash) {
int i;
for (i=0; i<20; i++) {
printf("%02x", hash[i]);
}
printf("\n");
}
int main (int argc, char **argv) {
uint32_t a;
sha1nfo s;
// SHA tests
printf("Test: FIPS 180-2 C.1 and RFC3174 7.3 TEST1\n");
printf("Expect:a9993e364706816aba3e25717850c26c9cd0d89d\n");
printf("Result:");
sha1_init(&s);
sha1_write(&s, "abc", 3);
printHash(sha1_result(&s));
printf("\n\n");
printf("Test: FIPS 180-2 C.2 and RFC3174 7.3 TEST2\n");
printf("Expect:84983e441c3bd26ebaae4aa1f95129e5e54670f1\n");
printf("Result:");
sha1_init(&s);
sha1_write(&s, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56);
printHash(sha1_result(&s));
printf("\n\n");
printf("Test: RFC3174 7.3 TEST4\n");
printf("Expect:dea356a2cddd90c7a7ecedc5ebb563934f460452\n");
printf("Result:");
sha1_init(&s);
for (a=0; a<80; a++) sha1_write(&s, "01234567", 8);
printHash(sha1_result(&s));
printf("\n\n");
// HMAC tests
printf("Test: FIPS 198a A.1\n");
printf("Expect:4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a\n");
printf("Result:");
sha1_initHmac(&s, hmacKey1, 64);
sha1_write(&s, "Sample #1",9);
printHash(sha1_resultHmac(&s));
printf("\n\n");
printf("Test: FIPS 198a A.2\n");
printf("Expect:0922d3405faa3d194f82a45830737d5cc6c75d24\n");
printf("Result:");
sha1_initHmac(&s, hmacKey2, 20);
sha1_write(&s, "Sample #2", 9);
printHash(sha1_resultHmac(&s));
printf("\n\n");
printf("Test: FIPS 198a A.3\n");
printf("Expect:bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa\n");
printf("Result:");
sha1_initHmac(&s, hmacKey3,100);
sha1_write(&s, "Sample #3", 9);
printHash(sha1_resultHmac(&s));
printf("\n\n");
printf("Test: FIPS 198a A.4\n");
printf("Expect:9ea886efe268dbecce420c7524df32e0751a2a26\n");
printf("Result:");
sha1_initHmac(&s, hmacKey4,49);
sha1_write(&s, "Sample #4", 9);
printHash(sha1_resultHmac(&s));
printf("\n\n");
// Long tests
printf("Test: FIPS 180-2 C.3 and RFC3174 7.3 TEST3\n");
printf("Expect:34aa973cd4c4daa4f61eeb2bdbad27316534016f\n");
printf("Result:");
sha1_init(&s);
for (a=0; a<1000000; a++) sha1_writebyte(&s, 'a');
printHash(sha1_result(&s));
return 0;
}
#endif /* self-test */
#endif

43
microstack/sha1.h Normal file
View File

@@ -0,0 +1,43 @@
/*
Copyright 2015 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.
*/
#ifndef __SHA1H__
#define __SHA1H__
#include <stdint.h>
#define HASH_LENGTH 20
#define BLOCK_LENGTH 64
typedef struct sha1nfo {
uint32_t buffer[BLOCK_LENGTH / 4];
uint32_t state[HASH_LENGTH / 4];
uint32_t byteCount;
uint8_t bufferOffset;
uint8_t keyBuffer[BLOCK_LENGTH];
uint8_t innerHash[HASH_LENGTH];
} sha1nfo;
typedef sha1nfo SHA_CTX;
void sha1_write(sha1nfo *s, const char *data, size_t len);
uint8_t* sha1_result(sha1nfo *s);
void SHA1_Init(SHA_CTX*);
#define SHA1_Update(pctx, pkeyResult, keyResultLen) sha1_write(pctx, pkeyResult, keyResultLen)
#define SHA1_Final(shavalue, pctx) memcpy(shavalue, sha1_result(pctx), 20);
#endif