mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-06-27 04:09:59 +08:00
feat(nopoll): Move nopoll to components
This commit is contained in:
44
components/nopoll/library/Makefile
Normal file
44
components/nopoll/library/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
#############################################################
|
||||
# Required variables for each makefile
|
||||
# Discard this section from all parent makefiles
|
||||
# Expected variables (with automatic defaults):
|
||||
# CSRCS (all "C" files in the dir)
|
||||
# SUBDIRS (all subdirs with a Makefile)
|
||||
# GEN_LIBS - list of libs to be generated ()
|
||||
# GEN_IMAGES - list of images to be generated ()
|
||||
# COMPONENTS_xxx - a list of libs/objs in the form
|
||||
# subdir/lib to be extracted and rolled up into
|
||||
# a generated lib/image xxx.a ()
|
||||
#
|
||||
ifndef PDIR
|
||||
GEN_LIBS = libnopoll.a
|
||||
endif
|
||||
|
||||
|
||||
#############################################################
|
||||
# Configuration i.e. compile options etc.
|
||||
# Target specific stuff (defines etc.) goes in here!
|
||||
# Generally values applying to a tree are captured in the
|
||||
# makefile at its root level - these are then overridden
|
||||
# for a subtree within the makefile rooted therein
|
||||
#
|
||||
#DEFINES +=
|
||||
|
||||
#############################################################
|
||||
# Recursion Magic - Don't touch this!!
|
||||
#
|
||||
# Each subtree potentially has an include directory
|
||||
# corresponding to the common APIs applicable to modules
|
||||
# rooted at that subtree. Accordingly, the INCLUDE PATH
|
||||
# of a module can only contain the include directories up
|
||||
# its parent path, and not its siblings
|
||||
#
|
||||
# Required for each makefile to inherit from the parent
|
||||
#
|
||||
|
||||
INCLUDES := $(INCLUDES) -I $(PDIR)include
|
||||
INCLUDES += -I ./
|
||||
PDIR := ../$(PDIR)
|
||||
sinclude $(PDIR)Makefile
|
||||
|
3080
components/nopoll/library/nopoll-regression-client.c
Normal file
3080
components/nopoll/library/nopoll-regression-client.c
Normal file
File diff suppressed because it is too large
Load Diff
1729
components/nopoll/library/nopoll.c
Normal file
1729
components/nopoll/library/nopoll.c
Normal file
File diff suppressed because it is too large
Load Diff
4156
components/nopoll/library/nopoll_conn.c
Normal file
4156
components/nopoll/library/nopoll_conn.c
Normal file
File diff suppressed because it is too large
Load Diff
313
components/nopoll/library/nopoll_conn_opts.c
Normal file
313
components/nopoll/library/nopoll_conn_opts.c
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_conn_opts.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_conn_opts noPoll Connection Options: API to change default connection options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_conn_opts
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Create a new connection options object.
|
||||
*
|
||||
* @return A newly created connection options object. In general you don't have to worry about releasing this object because this is automatically done by functions using this object. However, if you call to \ref nopoll_conn_opts_set_reuse (opts, nopoll_true), then you'll have to use \ref nopoll_conn_opts_free to release the object after it is no longer used. The function may return NULL in case of memory allocation problems. Creating an object without setting anything will cause the library to provide same default behaviour as not providing it.
|
||||
*/
|
||||
noPollConnOpts * nopoll_conn_opts_new (void)
|
||||
{
|
||||
noPollConnOpts * result;
|
||||
|
||||
/* create configuration object */
|
||||
result = nopoll_new (noPollConnOpts, 1);
|
||||
if (! result)
|
||||
return NULL;
|
||||
|
||||
result->reuse = nopoll_false; /* this is not needed, just to clearly state defaults */
|
||||
result->ssl_protocol = NOPOLL_METHOD_TLSV1;
|
||||
|
||||
result->mutex = nopoll_mutex_create ();
|
||||
result->refs = 1;
|
||||
|
||||
/* by default, disable ssl peer verification */
|
||||
result->disable_ssl_verify = nopoll_true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ssl protocol method to be used on the API receiving this
|
||||
* configuration object.
|
||||
*
|
||||
* @param opts The connection options object.
|
||||
*
|
||||
* @param ssl_protocol SSL protocol to use. See \ref noPollSslProtocol for more information.
|
||||
*/
|
||||
void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return;
|
||||
opts->ssl_protocol = ssl_protocol;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allows to certificate, private key and optional chain
|
||||
* certificate and ca for on a particular options that can be used for
|
||||
* a client and a listener connection.
|
||||
*
|
||||
* @param opts The connection options where these settings will be
|
||||
* applied.
|
||||
*
|
||||
* @param certificate The certificate to use on the connection.
|
||||
*
|
||||
* @param private_key client_certificate private key.
|
||||
*
|
||||
* @param chain_certificate Optional chain certificate to use
|
||||
*
|
||||
* @param ca_certificate Optional CA certificate to use during the
|
||||
* process.
|
||||
*
|
||||
* @return nopoll_true in the case all certificate files provided are
|
||||
* reachable.
|
||||
*/
|
||||
nopoll_bool nopoll_conn_opts_set_ssl_certs (noPollConnOpts * opts,
|
||||
const char * certificate,
|
||||
const char * private_key,
|
||||
const char * chain_certificate,
|
||||
const char * ca_certificate)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
/* store certificate settings */
|
||||
opts->certificate = nopoll_strdup (certificate);
|
||||
opts->private_key = nopoll_strdup (private_key);
|
||||
opts->chain_certificate = nopoll_strdup (chain_certificate);
|
||||
opts->ca_certificate = nopoll_strdup (ca_certificate);
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to disable peer ssl certificate verification. This is
|
||||
* not recommended for production enviroment. This affects in a
|
||||
* different manner to a listener connection and a client connection.
|
||||
*
|
||||
* For a client connection, by default, peer verification is enabled
|
||||
* and this function may help to disable it during development or
|
||||
* other reasons.
|
||||
*
|
||||
* In the case of the servers (created by using \ref
|
||||
* nopoll_listener_new for example) this is not required because by
|
||||
* default peer verification is disabled by default.
|
||||
*
|
||||
* @param opts The connection option to configure.
|
||||
*
|
||||
* @param verify nopoll_true to disable verification
|
||||
* otherwise, nopoll_false should be used. By default SSL verification
|
||||
* is enabled.
|
||||
*
|
||||
*/
|
||||
void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return;
|
||||
opts->disable_ssl_verify = ! verify;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to set Cookie header content to be sent during the
|
||||
* connection handshake. If configured and the remote side server is a
|
||||
* noPoll peer, use \ref nopoll_conn_get_cookie to get this value.
|
||||
*
|
||||
* @param opts The connection option to configure.
|
||||
*
|
||||
* @param cookie_content Content for the cookie. If you pass NULL the
|
||||
* cookie is unset.
|
||||
*/
|
||||
void nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return;
|
||||
|
||||
if (cookie_content) {
|
||||
/* configure cookie content to be sent */
|
||||
opts->cookie = nopoll_strdup (cookie_content);
|
||||
} else {
|
||||
nopoll_free (opts->cookie);
|
||||
opts->cookie = NULL;
|
||||
} /* end if */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allows to increase a reference to the connection options
|
||||
* provided.
|
||||
*
|
||||
* @param opts The connection option reference over which a connection
|
||||
* reference is needed.
|
||||
*
|
||||
* @return nopoll_true in the case the operation went ok, otherwise
|
||||
* nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
/* lock the mutex */
|
||||
nopoll_mutex_lock (opts->mutex);
|
||||
if (opts->refs <= 0) {
|
||||
/* unlock the mutex */
|
||||
nopoll_mutex_unlock (opts->mutex);
|
||||
return nopoll_false;
|
||||
}
|
||||
|
||||
opts->refs++;
|
||||
|
||||
/* release here the mutex */
|
||||
nopoll_mutex_unlock (opts->mutex);
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to unref a reference acquired by \ref nopoll_conn_opts_ref
|
||||
*
|
||||
* @param opts The connection opts to release.
|
||||
*/
|
||||
void nopoll_conn_opts_unref (noPollConnOpts * opts)
|
||||
{
|
||||
/* call free implementation */
|
||||
nopoll_conn_opts_free (opts);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set reuse-flag be used on the API receiving this
|
||||
* configuration object. By setting nopoll_true will cause the API to
|
||||
* not release the object when finished. Instead, the caller will be
|
||||
* able to use this object in additional API calls but, after
|
||||
* finishing, a call to \ref nopoll_conn_opts_set_reuse function is
|
||||
* required.
|
||||
*
|
||||
* @param opts The connection options object.
|
||||
*
|
||||
* @param reuse nopoll_true to reuse the object across calls,
|
||||
* otherwise nopoll_false to make the API function to release the
|
||||
* object when done.
|
||||
*/
|
||||
void nopoll_conn_opts_set_reuse (noPollConnOpts * opts, nopoll_bool reuse)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return;
|
||||
opts->reuse = reuse;
|
||||
return;
|
||||
}
|
||||
|
||||
void __nopoll_conn_opts_free_common (noPollConnOpts * opts)
|
||||
{
|
||||
if (opts == NULL)
|
||||
return;
|
||||
|
||||
/* acquire here the mutex */
|
||||
nopoll_mutex_lock (opts->mutex);
|
||||
|
||||
opts->refs--;
|
||||
if (opts->refs != 0) {
|
||||
/* release here the mutex */
|
||||
nopoll_mutex_unlock (opts->mutex);
|
||||
return;
|
||||
}
|
||||
/* release here the mutex */
|
||||
nopoll_mutex_unlock (opts->mutex);
|
||||
|
||||
nopoll_free (opts->certificate);
|
||||
nopoll_free (opts->private_key);
|
||||
nopoll_free (opts->chain_certificate);
|
||||
nopoll_free (opts->ca_certificate);
|
||||
|
||||
/* cookie */
|
||||
nopoll_free (opts->cookie);
|
||||
|
||||
/* release mutex */
|
||||
nopoll_mutex_destroy (opts->mutex);
|
||||
nopoll_free (opts);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to release a connection object reported by \ref nopoll_conn_opts_new
|
||||
*
|
||||
* IMPORTANT NOTE: do not use this function over a \ref noPollConnOpts if it is not flagged with \ref nopoll_conn_opts_set_reuse (opts, nopoll_true).
|
||||
*
|
||||
* Default behaviour provided by the API implies that every connection
|
||||
* options object created by \ref nopoll_conn_opts_new is
|
||||
* automatically released by the API consuming that object.
|
||||
*/
|
||||
void nopoll_conn_opts_free (noPollConnOpts * opts)
|
||||
{
|
||||
__nopoll_conn_opts_free_common (opts);
|
||||
return;
|
||||
} /* end if */
|
||||
|
||||
/**
|
||||
* @internal API. Do not use it. It may change at any time without any
|
||||
* previous indication.
|
||||
*/
|
||||
void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options)
|
||||
{
|
||||
if (! options)
|
||||
return;
|
||||
if (options && options->reuse)
|
||||
return;
|
||||
__nopoll_conn_opts_free_common (options);
|
||||
return;
|
||||
}
|
||||
|
||||
/* @} */
|
802
components/nopoll/library/nopoll_ctx.c
Normal file
802
components/nopoll/library/nopoll_ctx.c
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_ctx.h>
|
||||
#include <nopoll_private.h>
|
||||
//#include <signal.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_ctx noPoll Context: context handling functions used by the library
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_ctx
|
||||
* @{
|
||||
*/
|
||||
void __nopoll_ctx_sigpipe_do_nothing (int _signal)
|
||||
{
|
||||
#if !defined(NOPOLL_OS_WIN32)
|
||||
/* do nothing sigpipe handler to be able to manage EPIPE error
|
||||
* returned by write ops. */
|
||||
|
||||
/* the following line is to ensure ancient glibc version that
|
||||
* restores to the default handler once the signal handling is
|
||||
* executed. */
|
||||
// signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates an empty Nopoll context.
|
||||
*/
|
||||
noPollCtx * nopoll_ctx_new (void) {
|
||||
noPollCtx * result = nopoll_new (noPollCtx, 1);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
if (! nopoll_win32_init (result))
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* set initial reference */
|
||||
result->conn_id = 1;
|
||||
result->refs = 1;
|
||||
result->conn_id = 1;
|
||||
|
||||
/* 20 seconds for connection timeout */
|
||||
result->conn_connect_std_timeout = 20000000;
|
||||
|
||||
/* default log initialization */
|
||||
result->not_executed = nopoll_true;
|
||||
result->debug_enabled = nopoll_false;
|
||||
|
||||
/* colored log */
|
||||
result->not_executed_color = nopoll_true;
|
||||
result->debug_color_enabled = nopoll_false;
|
||||
|
||||
/* default back log */
|
||||
result->backlog = 5;
|
||||
|
||||
/* current list length */
|
||||
result->conn_length = 0;
|
||||
|
||||
#if !defined(NOPOLL_OS_WIN32)
|
||||
/* install sigpipe handler */
|
||||
// signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing);
|
||||
#endif
|
||||
|
||||
/* setup default protocol version */
|
||||
result->protocol_version = 13;
|
||||
|
||||
/* create mutexes */
|
||||
result->ref_mutex = nopoll_mutex_create ();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to acquire a reference to the provided context. This
|
||||
* reference is released by calling to \ref nopoll_ctx_unref.
|
||||
*
|
||||
* @param ctx The context to acquire a reference.
|
||||
*
|
||||
* @return The function returns nopoll_true in the case the reference
|
||||
* was acquired, otherwise nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_ctx_ref (noPollCtx * ctx)
|
||||
{
|
||||
/* return false value */
|
||||
nopoll_return_val_if_fail (ctx, ctx, nopoll_false);
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
ctx->refs++;
|
||||
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief allows to release a reference acquired to the provided
|
||||
* noPoll context.
|
||||
*
|
||||
* @param ctx The noPoll context reference to release..
|
||||
*/
|
||||
void nopoll_ctx_unref (noPollCtx * ctx)
|
||||
{
|
||||
noPollCertificate * cert;
|
||||
int iterator;
|
||||
|
||||
nopoll_return_if_fail (ctx, ctx);
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
ctx->refs--;
|
||||
if (ctx->refs != 0) {
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
return;
|
||||
}
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Releasing no poll context %p (%d, conns: %d)", ctx, ctx->refs, ctx->conn_length);
|
||||
|
||||
iterator = 0;
|
||||
while (iterator < ctx->certificates_length) {
|
||||
/* get reference */
|
||||
cert = &(ctx->certificates[iterator]);
|
||||
|
||||
/* release */
|
||||
nopoll_free (cert->serverName);
|
||||
nopoll_free (cert->certificateFile);
|
||||
nopoll_free (cert->privateKey);
|
||||
nopoll_free (cert->optionalChainFile);
|
||||
|
||||
/* next position */
|
||||
iterator++;
|
||||
} /* end while */
|
||||
|
||||
/* release mutex */
|
||||
nopoll_mutex_destroy (ctx->ref_mutex);
|
||||
|
||||
/* release all certificates buckets */
|
||||
nopoll_free (ctx->certificates);
|
||||
|
||||
/* release connection */
|
||||
nopoll_free (ctx->conn_list);
|
||||
ctx->conn_length = 0;
|
||||
nopoll_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get current reference counting for the provided
|
||||
* context.
|
||||
*
|
||||
* @param ctx The context the reference counting is being requested.
|
||||
*
|
||||
* @return The reference counting or -1 if it fails.
|
||||
*/
|
||||
int nopoll_ctx_ref_count (noPollCtx * ctx)
|
||||
{
|
||||
int result;
|
||||
if (! ctx)
|
||||
return -1;
|
||||
|
||||
/* lock */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
result = ctx->refs;
|
||||
|
||||
/* unlock */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to register the provided connection on the
|
||||
* provided context.
|
||||
*
|
||||
* @param ctx The context where the connection will be registered.
|
||||
*
|
||||
* @param conn The connection to be registered.
|
||||
*
|
||||
* @return nopoll_true if the connection was registered, otherwise
|
||||
* nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_ctx_register_conn (noPollCtx * ctx,
|
||||
noPollConn * conn)
|
||||
{
|
||||
int iterator;
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx && conn, nopoll_false);
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
/* get connection */
|
||||
conn->id = ctx->conn_id;
|
||||
ctx->conn_id ++;
|
||||
|
||||
/* register connection */
|
||||
iterator = 0;
|
||||
while (iterator < ctx->conn_length) {
|
||||
|
||||
/* register reference */
|
||||
if (ctx->conn_list[iterator] == 0) {
|
||||
ctx->conn_list[iterator] = conn;
|
||||
|
||||
/* update connection list number */
|
||||
ctx->conn_num++;
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "registered connection id %d, role: %d", conn->id, conn->role);
|
||||
|
||||
/* release */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
/* acquire reference */
|
||||
nopoll_ctx_ref (ctx);
|
||||
|
||||
/* acquire a reference to the conection */
|
||||
nopoll_conn_ref (conn);
|
||||
|
||||
/* release mutex here */
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
iterator++;
|
||||
} /* end while */
|
||||
|
||||
/* if reached this place it means no more buckets are
|
||||
* available, acquire more memory (increase 10 by 10) */
|
||||
ctx->conn_length += 10;
|
||||
ctx->conn_list = (noPollConn**) nopoll_realloc (ctx->conn_list, sizeof (noPollConn *) * (ctx->conn_length));
|
||||
if (ctx->conn_list == NULL) {
|
||||
/* release mutex */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "General connection registration error, memory acquisition failed..");
|
||||
return nopoll_false;
|
||||
} /* end if */
|
||||
|
||||
/* clear new positions */
|
||||
iterator = (ctx->conn_length - 10);
|
||||
while (iterator < ctx->conn_length) {
|
||||
ctx->conn_list[iterator] = 0;
|
||||
/* next position */
|
||||
iterator++;
|
||||
} /* end while */
|
||||
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
/* ok, now register connection because we have memory */
|
||||
return nopoll_ctx_register_conn (ctx, conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to register the provided connection on the
|
||||
* provided context.
|
||||
*
|
||||
* @param ctx The context where the connection will be registered.
|
||||
*
|
||||
* @param conn The connection to be registered.
|
||||
*/
|
||||
void nopoll_ctx_unregister_conn (noPollCtx * ctx,
|
||||
noPollConn * conn)
|
||||
{
|
||||
int iterator;
|
||||
|
||||
nopoll_return_if_fail (ctx, ctx && conn);
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
/* find the connection and remove it from the array */
|
||||
iterator = 0;
|
||||
while (iterator < ctx->conn_length) {
|
||||
|
||||
/* check the connection reference */
|
||||
if (ctx->conn_list && ctx->conn_list[iterator] && ctx->conn_list[iterator]->id == conn->id) {
|
||||
/* remove reference */
|
||||
ctx->conn_list[iterator] = NULL;
|
||||
|
||||
/* update connection list number */
|
||||
ctx->conn_num--;
|
||||
|
||||
/* release */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
/* acquire a reference to the conection */
|
||||
nopoll_conn_unref (conn);
|
||||
|
||||
break;
|
||||
} /* end if */
|
||||
|
||||
iterator++;
|
||||
} /* end while */
|
||||
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get number of connections currently registered.
|
||||
*
|
||||
* @param ctx The context where the operation is requested.
|
||||
*
|
||||
* @return Number of connections registered on this context or -1 if it fails.
|
||||
*/
|
||||
int nopoll_ctx_conns (noPollCtx * ctx)
|
||||
{
|
||||
nopoll_return_val_if_fail (ctx, ctx, -1);
|
||||
return ctx->conn_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to find the certificate associated to the provided serverName.
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param serverName the servername to use as pattern to find the
|
||||
* right certificate. If NULL is provided the first certificate not
|
||||
* refering to any serverName will be returned.
|
||||
*
|
||||
* @param certificateFile If provided a reference and the function
|
||||
* returns nopoll_true, it will contain the certificateFile found.
|
||||
*
|
||||
* @param privateKey If provided a reference and the function
|
||||
* returns nopoll_true, it will contain the privateKey found.
|
||||
*
|
||||
* @param optionalChainFile If provided a reference and the function
|
||||
* returns nopoll_true, it will contain the optionalChainFile found.
|
||||
*
|
||||
* @return nopoll_true in the case the certificate was found,
|
||||
* otherwise nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_ctx_find_certificate (noPollCtx * ctx,
|
||||
const char * serverName,
|
||||
const char ** certificateFile,
|
||||
const char ** privateKey,
|
||||
const char ** optionalChainFile)
|
||||
{
|
||||
noPollCertificate * cert;
|
||||
|
||||
int iterator = 0;
|
||||
nopoll_return_val_if_fail (ctx, ctx, nopoll_false);
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Finding a certificate for serverName=%s", serverName ? serverName : "<not defined>");
|
||||
|
||||
while (iterator < ctx->certificates_length) {
|
||||
/* get cert */
|
||||
cert = &(ctx->certificates[iterator]);
|
||||
if (cert) {
|
||||
/* found a certificate */
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " certificate stored associated to serverName=%s", cert->serverName ? cert->serverName : "<not defined>");
|
||||
if ((serverName == NULL && cert->serverName == NULL) ||
|
||||
(nopoll_cmp (serverName, cert->serverName))) {
|
||||
if (certificateFile)
|
||||
(*certificateFile) = cert->certificateFile;
|
||||
if (privateKey)
|
||||
(*privateKey) = cert->privateKey;
|
||||
if (optionalChainFile)
|
||||
(*optionalChainFile) = cert->optionalChainFile;
|
||||
return nopoll_true;
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
|
||||
/* next position */
|
||||
iterator++;
|
||||
}
|
||||
|
||||
/* check for default certificate when serverName isn't defined */
|
||||
if (serverName == NULL) {
|
||||
/* requested a certificate for an undefined serverName */
|
||||
iterator = 0;
|
||||
while (iterator < ctx->certificates_length) {
|
||||
/* get cert */
|
||||
cert = &(ctx->certificates[iterator]);
|
||||
if (cert) {
|
||||
/* found a certificate */
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " serverName not defined, selecting first certificate from the list");
|
||||
if (certificateFile)
|
||||
(*certificateFile) = cert->certificateFile;
|
||||
if (privateKey)
|
||||
(*privateKey) = cert->privateKey;
|
||||
if (optionalChainFile)
|
||||
(*optionalChainFile) = cert->optionalChainFile;
|
||||
return nopoll_true;
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
|
||||
/* next position */
|
||||
iterator++;
|
||||
} /* end if */
|
||||
|
||||
return nopoll_false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to install a certificate to be used in general by all
|
||||
* listener connections working under the provided context.
|
||||
*
|
||||
* @param ctx The context where the certificate will be installed.
|
||||
*
|
||||
* @param serverName The optional server name to to limit the use of
|
||||
* this certificate to the value provided here. Provide a NULL value
|
||||
* to make the certificate provide to work under any server notified
|
||||
* (Host: header) or via SNI (server name identification associated to
|
||||
* the TLS transport).
|
||||
*
|
||||
* @param certificateFile The certificate file to be installed.
|
||||
*
|
||||
* @param privateKey The private key file to use used.
|
||||
*
|
||||
* @param optionalChainFile Optional chain file with additional
|
||||
* material to complete the certificate definition.
|
||||
*
|
||||
* @return nopoll_true if the certificate was installed otherwise
|
||||
* nopoll_false. The function returns nopoll_false when ctx, certificateFile or privateKey are NULL.
|
||||
*/
|
||||
nopoll_bool nopoll_ctx_set_certificate (noPollCtx * ctx,
|
||||
const char * serverName,
|
||||
const char * certificateFile,
|
||||
const char * privateKey,
|
||||
const char * optionalChainFile)
|
||||
{
|
||||
int length;
|
||||
noPollCertificate * cert;
|
||||
|
||||
/* check values before proceed */
|
||||
nopoll_return_val_if_fail (ctx, ctx && certificateFile && privateKey, nopoll_false);
|
||||
|
||||
/* check if the certificate is already installed */
|
||||
if (nopoll_ctx_find_certificate (ctx, serverName, NULL, NULL, NULL))
|
||||
return nopoll_true;
|
||||
|
||||
/* update certificate storage to hold all values */
|
||||
ctx->certificates_length++;
|
||||
length = ctx->certificates_length;
|
||||
if (length == 1)
|
||||
ctx->certificates = nopoll_new (noPollCertificate, 1);
|
||||
else
|
||||
ctx->certificates = (noPollCertificate *) nopoll_realloc (ctx->certificates, sizeof (noPollCertificate) * (length));
|
||||
|
||||
/* hold certificate */
|
||||
cert = &(ctx->certificates[length - 1]);
|
||||
|
||||
cert->serverName = NULL;
|
||||
if (serverName)
|
||||
cert->serverName = nopoll_strdup (serverName);
|
||||
|
||||
cert->certificateFile = NULL;
|
||||
if (certificateFile)
|
||||
cert->certificateFile = nopoll_strdup (certificateFile);
|
||||
|
||||
cert->privateKey = NULL;
|
||||
if (privateKey)
|
||||
cert->privateKey = nopoll_strdup (privateKey);
|
||||
|
||||
cert->optionalChainFile = NULL;
|
||||
if (optionalChainFile)
|
||||
cert->optionalChainFile = nopoll_strdup (optionalChainFile);
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure the on open handler, the handler that is
|
||||
* called when it is received an incoming websocket connection and all
|
||||
* websocket client handshake data was received (but still not required).
|
||||
*
|
||||
* This handler differs from \ref nopoll_ctx_set_on_accept this
|
||||
* handler is called after all client handshake data was received.
|
||||
*
|
||||
* Note the connection is still not fully working at this point
|
||||
* because the handshake hasn't been sent to the remote peer yet. This
|
||||
* means that attempting to send any content inside this handler (for
|
||||
* example by using \ref nopoll_conn_send_text) will cause a protocol
|
||||
* violation (because remote side is expecting a handshake reply but
|
||||
* received something different).
|
||||
*
|
||||
* In the case you want to sent content right away after receiving a
|
||||
* connection (on a listener), you can use \ref
|
||||
* nopoll_ctx_set_on_ready "On Ready" handler which is called just
|
||||
* after the connection has been fully accepted and handshake reply is
|
||||
* fully written.
|
||||
*
|
||||
* @param ctx The context that will be configured.
|
||||
*
|
||||
* @param on_open The handler to be configured on this context.
|
||||
*
|
||||
* @param user_data User defined pointer to be passed to the on open
|
||||
* handler
|
||||
*/
|
||||
void nopoll_ctx_set_on_open (noPollCtx * ctx,
|
||||
noPollActionHandler on_open,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
nopoll_return_if_fail (ctx, ctx && on_open);
|
||||
|
||||
/* set the handler */
|
||||
ctx->on_open = on_open;
|
||||
if (ctx->on_open == NULL)
|
||||
ctx->on_open_data = NULL;
|
||||
else
|
||||
ctx->on_open_data = user_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure a handler that is called when a
|
||||
* connection is received and it is ready to send and receive because
|
||||
* all WebSocket handshake protocol finished OK.
|
||||
*
|
||||
* Unlike handlers configured at \ref nopoll_ctx_set_on_open and \ref
|
||||
* nopoll_ctx_set_on_accept which get notified when the connection
|
||||
* isn't still working (because WebSocket handshake wasn't finished
|
||||
* yet), on read handlers configured here will get called just after
|
||||
* the WebSocket handshake has taken place.
|
||||
*
|
||||
* @param ctx The context that will be configured.
|
||||
*
|
||||
* @param on_ready The handler to be called when a connection is fully
|
||||
* ready to send and receive content because WebSocket handshake has
|
||||
* finished. The function must return nopoll_true to accept the
|
||||
* connection. By returning nopoll_false the handler is signalling to
|
||||
* terminate the connection.
|
||||
*
|
||||
* @param user_data Optional user data pointer passed to the on ready
|
||||
* handler.
|
||||
*
|
||||
*/
|
||||
void nopoll_ctx_set_on_ready (noPollCtx * ctx,
|
||||
noPollActionHandler on_ready,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
nopoll_return_if_fail (ctx, ctx && on_ready);
|
||||
|
||||
/* set the handler */
|
||||
ctx->on_ready = on_ready;
|
||||
if (ctx->on_ready == NULL)
|
||||
ctx->on_ready_data = NULL;
|
||||
else
|
||||
ctx->on_ready_data = user_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure the accept handler that will be called
|
||||
* when a connection is received but before any handshake takes place.
|
||||
*
|
||||
* @param ctx The context that will be configured.
|
||||
*
|
||||
* @param on_accept The handler to be called when a connection is
|
||||
* received. Here the handler must return nopoll_true to accept the
|
||||
* connection, otherwise nopoll_false should be returned.
|
||||
*
|
||||
* @param user_data Optional user data pointer passed to the on accept
|
||||
* handler.
|
||||
*
|
||||
*/
|
||||
void nopoll_ctx_set_on_accept (noPollCtx * ctx,
|
||||
noPollActionHandler on_accept,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
nopoll_return_if_fail (ctx, ctx && on_accept);
|
||||
|
||||
/* set the handler */
|
||||
ctx->on_accept = on_accept;
|
||||
if (ctx->on_accept == NULL)
|
||||
ctx->on_accept_data = NULL;
|
||||
else
|
||||
ctx->on_accept_data = user_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to set a general handler to get notifications about a
|
||||
* message received over any connection that is running under the
|
||||
* provided context (noPollCtx).
|
||||
*
|
||||
* @param ctx The context where the notification will happen
|
||||
*
|
||||
* @param on_msg The handler to be called when an incoming message is
|
||||
* received.
|
||||
*
|
||||
* @param user_data User defined pointer that is passed in into the
|
||||
* handler when called.
|
||||
*
|
||||
* Note that the handler configured here will be overriden by the handler configured by \ref nopoll_conn_set_on_msg
|
||||
*
|
||||
*/
|
||||
void nopoll_ctx_set_on_msg (noPollCtx * ctx,
|
||||
noPollOnMessageHandler on_msg,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
nopoll_return_if_fail (ctx, ctx);
|
||||
|
||||
/* set new handler */
|
||||
ctx->on_msg = on_msg;
|
||||
ctx->on_msg_data = user_data;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure the handler that will be used to let
|
||||
* user land code to define OpenSSL SSL_CTX object.
|
||||
*
|
||||
* By default, SSL_CTX (SSL Context) object is created by default
|
||||
* settings that works for most of the cases. In the case you want to
|
||||
* configure particular configurations that should be enabled on the
|
||||
* provided SSL_CTX that is going to be used by the client ---while
|
||||
* connecting--- or server ---while receiving a connection--- then use
|
||||
* this function to setup your creator handler.
|
||||
*
|
||||
* See \ref noPollSslContextCreator for more information about this
|
||||
* handler.
|
||||
*
|
||||
*/
|
||||
void nopoll_ctx_set_ssl_context_creator (noPollCtx * ctx,
|
||||
noPollSslContextCreator context_creator,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* set handlers as indicated by the caller */
|
||||
ctx->context_creator = context_creator;
|
||||
ctx->context_creator_data = user_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure a function that will implement an post SSL/TLS check.
|
||||
*
|
||||
* See the following function to get more information: \ref noPollSslPostCheck
|
||||
*
|
||||
* @param ctx The context where the operation is taking place.
|
||||
*
|
||||
* @param post_ssl_check The handler that is going to be called
|
||||
* everything a new connection with SSL is established by a client or
|
||||
* received by a server. The handler is executed right after the SSL
|
||||
* handshake finishes without error.
|
||||
*
|
||||
* @param user_data A reference to user defined pointer that will be
|
||||
* passed in to the handler.
|
||||
*/
|
||||
void nopoll_ctx_set_post_ssl_check (noPollCtx * ctx,
|
||||
noPollSslPostCheck post_ssl_check,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* set handlers as indicated by the caller */
|
||||
ctx->post_ssl_check = post_ssl_check;
|
||||
ctx->post_ssl_check_data = user_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to iterate over all connections currently registered
|
||||
* on the provided context, optionally stopping the foreach process,
|
||||
* returning the connection reference selected if the foreach handler
|
||||
* returns nopoll_true.
|
||||
*
|
||||
* @param ctx The nopoll context where the foreach operation will take
|
||||
* place.
|
||||
*
|
||||
* @param foreach The foreach handler to be called for each connection
|
||||
* registered.
|
||||
*
|
||||
* @param user_data An optional reference to a pointer that will be
|
||||
* passed to the handler.
|
||||
*
|
||||
* @return Returns the connection selected (in the case the foreach
|
||||
* function returns nopoll_false) or NULL in the case all foreach
|
||||
* executions returned nopoll_true. Keep in mind the function also
|
||||
* returns NULL if ctx or foreach parameter is NULL.
|
||||
*
|
||||
* See \ref noPollForeachConn for a signature example.
|
||||
*/
|
||||
noPollConn * nopoll_ctx_foreach_conn (noPollCtx * ctx,
|
||||
noPollForeachConn foreach,
|
||||
noPollPtr user_data)
|
||||
{
|
||||
noPollConn * result;
|
||||
int iterator;
|
||||
nopoll_return_val_if_fail (ctx, ctx && foreach, NULL);
|
||||
|
||||
/* acquire here the mutex to protect connection list */
|
||||
nopoll_mutex_lock (ctx->ref_mutex);
|
||||
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Doing foreach over conn_length array (%p): %d", ctx, ctx->conn_length); */
|
||||
|
||||
/* find the connection and remove it from the array */
|
||||
iterator = 0;
|
||||
while (iterator < ctx->conn_length) {
|
||||
|
||||
/* check the connection reference */
|
||||
if (ctx->conn_list[iterator]) {
|
||||
/* call to notify connection */
|
||||
if (foreach (ctx, ctx->conn_list[iterator], user_data)) {
|
||||
/* get a reference to avoid races
|
||||
* after releasing the mutex */
|
||||
result = ctx->conn_list[iterator];
|
||||
|
||||
/* release */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
/* release here the mutex to protect connection list */
|
||||
return result;
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
|
||||
iterator++;
|
||||
} /* end while */
|
||||
|
||||
/* release here the mutex to protect connection list */
|
||||
nopoll_mutex_unlock (ctx->ref_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allows to change the protocol version that is send in all
|
||||
* client connections created under the provided context and the
|
||||
* protocol version accepted by listener created under this context
|
||||
* too.
|
||||
*
|
||||
* This is a really basic (mostly fake) protocol version support
|
||||
* because it only allows to change the version string sent (but
|
||||
* nothing more for now). It is useful for testing purposes.
|
||||
*
|
||||
* @param ctx The noPoll context where the protocol version change
|
||||
* will be applied.
|
||||
*
|
||||
* @param version The value representing the protocol version. By
|
||||
* default this function isn't required to be called because it
|
||||
* already has the right protocol value configured (13).
|
||||
*/
|
||||
void nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version)
|
||||
{
|
||||
/* check input data */
|
||||
nopoll_return_if_fail (ctx, ctx || version);
|
||||
|
||||
/* setup the new protocol version */
|
||||
ctx->protocol_version = version;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* @} */
|
94
components/nopoll/library/nopoll_decl.c
Normal file
94
components/nopoll/library/nopoll_decl.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_decl.h>
|
||||
|
||||
#ifdef MEMLEAK_DEBUG
|
||||
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_decl_module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Calloc helper for nopoll library.
|
||||
*
|
||||
* @param count How many items to allocate.
|
||||
* @param size Size of one item.
|
||||
*
|
||||
* @return A newly allocated pointer.
|
||||
* @see nopoll_free
|
||||
*/
|
||||
noPollPtr nopoll_calloc(size_t count, size_t size)
|
||||
{
|
||||
return (void *)os_calloc (count, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Realloc helper for nopoll library.
|
||||
*
|
||||
* @param ref the reference to reallocate.
|
||||
* @param size Size of the new reference.
|
||||
*
|
||||
* @return A newly allocated pointer.
|
||||
* @see nopoll_free
|
||||
*/
|
||||
noPollPtr nopoll_realloc(noPollPtr ref, size_t size)
|
||||
{
|
||||
return (void *)os_realloc (ref, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to deallocate memory referenced by <i>ref</i> but
|
||||
* checking before that the reference is different from null.
|
||||
*
|
||||
* @param ref The reference to clear.
|
||||
*/
|
||||
void nopoll_free (noPollPtr ref)
|
||||
{
|
||||
os_free (ref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
233
components/nopoll/library/nopoll_io.c
Normal file
233
components/nopoll/library/nopoll_io.c
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_io.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
typedef struct _noPollSelect {
|
||||
noPollCtx * ctx;
|
||||
fd_set set;
|
||||
int length;
|
||||
int max_fds;
|
||||
} noPollSelect;
|
||||
|
||||
/**
|
||||
* @internal nopoll implementation to create a compatible "select" IO
|
||||
* call fd set reference.
|
||||
*
|
||||
* @return A newly allocated fd_set reference.
|
||||
*/
|
||||
noPollPtr nopoll_io_wait_select_create (noPollCtx * ctx)
|
||||
{
|
||||
noPollSelect * select = nopoll_new (noPollSelect, 1);
|
||||
|
||||
/* set default behaviour expected for the set */
|
||||
select->ctx = ctx;
|
||||
|
||||
/* clear the set */
|
||||
FD_ZERO (&(select->set));
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal noPoll implementation to destroy the "select" IO call
|
||||
* created by the default create.
|
||||
*
|
||||
* @param fd_group The fd group to be deallocated.
|
||||
*/
|
||||
void nopoll_io_wait_select_destroy (noPollCtx * ctx, noPollPtr fd_group)
|
||||
{
|
||||
fd_set * __fd_set = (fd_set *) fd_group;
|
||||
|
||||
/* release memory allocated */
|
||||
nopoll_free (__fd_set);
|
||||
|
||||
/* nothing more to do */
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal noPoll implementation to clear the "select" IO call
|
||||
* created by the default create.
|
||||
*
|
||||
* @param fd_group The fd group to be deallocated.
|
||||
*/
|
||||
void nopoll_io_wait_select_clear (noPollCtx * ctx, noPollPtr __fd_group)
|
||||
{
|
||||
noPollSelect * select = (noPollSelect *) __fd_group;
|
||||
|
||||
/* clear the fd set */
|
||||
select->length = 0;
|
||||
FD_ZERO (&(select->set));
|
||||
|
||||
/* nothing more to do */
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Default internal implementation for the wait operation to
|
||||
* change its status at least one socket description inside the fd set
|
||||
* provided.
|
||||
*
|
||||
* @param __fd_group The fd set having all sockets to be watched.
|
||||
* @param wait_to The operation requested.
|
||||
*
|
||||
* @return Number of connections that changed or -1 if something wailed
|
||||
*/
|
||||
int nopoll_io_wait_select_wait (noPollCtx * ctx, noPollPtr __fd_group)
|
||||
{
|
||||
int result = -1;
|
||||
struct timeval tv;
|
||||
noPollSelect * _select = (noPollSelect *) __fd_group;
|
||||
|
||||
/* init wait */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 500000;
|
||||
result = select (_select->max_fds + 1, &(_select->set), NULL, NULL, &tv);
|
||||
|
||||
/* check result */
|
||||
if ((result == NOPOLL_SOCKET_ERROR) && (errno == NOPOLL_EINTR))
|
||||
return -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal noPoll select implementation for the "add to" on fd set
|
||||
* operation.
|
||||
*
|
||||
* @param fds The socket descriptor to be added.
|
||||
*
|
||||
* @param fd_set The fd set where the socket descriptor will be added.
|
||||
*/
|
||||
nopoll_bool nopoll_io_wait_select_add_to (int fds,
|
||||
noPollCtx * ctx,
|
||||
noPollConn * conn,
|
||||
noPollPtr __fd_set)
|
||||
{
|
||||
noPollSelect * select = (noPollSelect *) __fd_set;
|
||||
|
||||
if (fds < 0) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL,
|
||||
"received a non valid socket (%d), unable to add to the set", fds);
|
||||
return nopoll_false;
|
||||
}
|
||||
|
||||
/* set the value */
|
||||
FD_SET (fds, &(select->set));
|
||||
|
||||
/* update length */
|
||||
select->length++;
|
||||
|
||||
/* update max fds */
|
||||
if (fds > select->max_fds)
|
||||
select->max_fds = fds;
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Default noPoll implementation for the "is set" on fd
|
||||
* set operation.
|
||||
*
|
||||
* @param fds The socket descriptor to be checked to be active on the
|
||||
* given fd group.
|
||||
*
|
||||
* @param fd_set The fd set where the socket descriptor will be checked.
|
||||
*/
|
||||
nopoll_bool nopoll_io_wait_select_is_set (noPollCtx * ctx,
|
||||
int fds,
|
||||
noPollPtr __fd_set)
|
||||
{
|
||||
noPollSelect * select = (noPollSelect *) __fd_set;
|
||||
|
||||
return FD_ISSET (fds, &(select->set));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates an object that represents the best IO wait mechanism
|
||||
* found on the current system.
|
||||
*
|
||||
* @param ctx The context where the engine will be created/associated.
|
||||
*
|
||||
* @param engine Use \ref NOPOLL_IO_ENGINE_DEFAULT or the engine you
|
||||
* want to use.
|
||||
*
|
||||
* @return The selected IO wait mechanism or NULL if it fails.
|
||||
*/
|
||||
noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type)
|
||||
{
|
||||
noPollIoEngine * engine = nopoll_new (noPollIoEngine, 1);
|
||||
if (engine == NULL)
|
||||
return NULL;
|
||||
|
||||
/* configure default implementation */
|
||||
engine->create = nopoll_io_wait_select_create;
|
||||
engine->destroy = nopoll_io_wait_select_destroy;
|
||||
engine->clear = nopoll_io_wait_select_clear;
|
||||
engine->wait = nopoll_io_wait_select_wait;
|
||||
engine->addto = nopoll_io_wait_select_add_to;
|
||||
engine->isset = nopoll_io_wait_select_is_set;
|
||||
|
||||
/* call to create the object */
|
||||
engine->ctx = ctx;
|
||||
engine->io_object = engine->create (ctx);
|
||||
|
||||
/* return the engine that was created */
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release the io engine created by \ref nopoll_io_get_engine.
|
||||
*
|
||||
* @param engine The engine to be released.
|
||||
*/
|
||||
void nopoll_io_release_engine (noPollIoEngine * engine)
|
||||
{
|
||||
if (engine == NULL)
|
||||
return;
|
||||
engine->destroy (engine->ctx, engine->io_object);
|
||||
nopoll_free (engine);
|
||||
return;
|
||||
}
|
||||
|
||||
|
441
components/nopoll/library/nopoll_listener.c
Normal file
441
components/nopoll/library/nopoll_listener.c
Normal file
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_listener.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_listener noPoll Listener: functions required to create WebSocket listener connections.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_listener
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal Creates a listener socket on the provided port.
|
||||
*/
|
||||
NOPOLL_SOCKET nopoll_listener_sock_listen (noPollCtx * ctx,
|
||||
const char * host,
|
||||
const char * port)
|
||||
{
|
||||
struct hostent * he;
|
||||
struct in_addr * haddr;
|
||||
struct sockaddr_in saddr;
|
||||
struct sockaddr_in sin;
|
||||
NOPOLL_SOCKET fd;
|
||||
int tries;
|
||||
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
int sin_size = sizeof (sin);
|
||||
#else
|
||||
int unit = 1;
|
||||
socklen_t sin_size = sizeof (sin);
|
||||
#endif
|
||||
uint16_t int_port;
|
||||
int bind_res;
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx, -2);
|
||||
nopoll_return_val_if_fail (ctx, host, -2);
|
||||
nopoll_return_val_if_fail (ctx, port || strlen (port) == 0, -2);
|
||||
|
||||
/* resolve hostname */
|
||||
he = gethostbyname (host);
|
||||
if (he == NULL) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get hostname by calling gethostbyname");
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
haddr = ((struct in_addr *) (he->h_addr_list)[0]);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 2) {
|
||||
/* do not allow creating sockets reusing stdin (0),
|
||||
stdout (1), stderr (2) */
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "failed to create listener socket: %d (errno=%d)", fd, errno);
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
/* Do not issue a reuse addr which causes on windows to reuse
|
||||
* the same address:port for the same process. Under linux,
|
||||
* reusing the address means that consecutive process can
|
||||
* reuse the address without being blocked by a wait
|
||||
* state. */
|
||||
/* setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&unit, sizeof(BOOL)); */
|
||||
#else
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &unit, sizeof (unit));
|
||||
#endif
|
||||
|
||||
/* get integer port */
|
||||
int_port = (uint16_t) atoi (port);
|
||||
|
||||
memset(&saddr, 0, sizeof(struct sockaddr_in));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(int_port);
|
||||
memcpy(&saddr.sin_addr, haddr, sizeof(struct in_addr));
|
||||
|
||||
/* call to bind */
|
||||
tries = 0;
|
||||
while (1) {
|
||||
bind_res = bind(fd, (struct sockaddr *)&saddr, sizeof (struct sockaddr_in));
|
||||
if (bind_res == NOPOLL_SOCKET_ERROR) {
|
||||
/* check if we can retry */
|
||||
tries++;
|
||||
if (tries < 25) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_WARNING,
|
||||
"unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s), retrying=%d on socket: %d",
|
||||
int_port, errno, strerror (errno), tries, fd);
|
||||
nopoll_sleep (100000);
|
||||
continue;
|
||||
} /* end if */
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL,
|
||||
"unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s). Closing socket: %d",
|
||||
int_port, errno, strerror (errno), fd);
|
||||
nopoll_close_socket (fd);
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
/* reached this point, bind was ok */
|
||||
break;
|
||||
} /* end while */
|
||||
|
||||
if (listen(fd, ctx->backlog) == NOPOLL_SOCKET_ERROR) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "an error have occur while executing listen");
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
/* notify listener */
|
||||
if (getsockname (fd, (struct sockaddr *) &sin, &sin_size) < -1) {
|
||||
return -1;
|
||||
} /* end if */
|
||||
|
||||
/* report and return fd */
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "running listener at %s:%d (socket: %d)", inet_ntoa(sin.sin_addr), ntohs (sin.sin_port), fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new websocket server listener on the provided host
|
||||
* name and port.
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param host The hostname or address interface to bind on.
|
||||
*
|
||||
* @param port The port where to listen, or NULL to use default port: 80.
|
||||
*
|
||||
* @return A reference to a \ref noPollConn object representing the
|
||||
* listener or NULL if it fails.
|
||||
*/
|
||||
noPollConn * nopoll_listener_new (noPollCtx * ctx,
|
||||
const char * host,
|
||||
const char * port)
|
||||
{
|
||||
return nopoll_listener_new_opts (ctx, NULL, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new websocket server listener on the provided host
|
||||
* name and port.
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param opts Optional connection options to configure this listener.
|
||||
*
|
||||
* @param host The hostname or address interface to bind on.
|
||||
*
|
||||
* @param port The port where to listen, or NULL to use default port: 80.
|
||||
*
|
||||
* @return A reference to a \ref noPollConn object representing the
|
||||
* listener or NULL if it fails.
|
||||
*/
|
||||
noPollConn * nopoll_listener_new_opts (noPollCtx * ctx,
|
||||
noPollConnOpts * opts,
|
||||
const char * host,
|
||||
const char * port)
|
||||
{
|
||||
NOPOLL_SOCKET session;
|
||||
noPollConn * listener;
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx && host, NULL);
|
||||
|
||||
/* call to create the socket */
|
||||
session = nopoll_listener_sock_listen (ctx, host, port);
|
||||
if (session == NOPOLL_INVALID_SOCKET) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to start listener error was: %d", errno);
|
||||
return NULL;
|
||||
} /* end if */
|
||||
|
||||
/* create noPollConn ection object */
|
||||
listener = nopoll_new (noPollConn, 1);
|
||||
listener->refs = 1;
|
||||
listener->session = session;
|
||||
listener->ctx = ctx;
|
||||
listener->role = NOPOLL_ROLE_MAIN_LISTENER;
|
||||
|
||||
/* record host and port */
|
||||
listener->host = nopoll_strdup (host);
|
||||
listener->port = nopoll_strdup (port);
|
||||
|
||||
/* register connection into context */
|
||||
nopoll_ctx_register_conn (ctx, listener);
|
||||
|
||||
/* configure default handlers */
|
||||
listener->receive = nopoll_conn_default_receive;
|
||||
listener->sends = nopoll_conn_default_send;
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d)", listener->host, listener->port, listener->session);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to create a new WebSocket listener but expecting the
|
||||
* incoming connection to be under TLS supervision. The function works
|
||||
* like \ref nopoll_listener_new (providing wss:// services).
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param host The hostname or address interface to bind on.
|
||||
*
|
||||
* @param port The port where to listen, or NULL to use default port: 80.
|
||||
*
|
||||
* @return A reference to a \ref noPollConn object representing the
|
||||
* listener or NULL if it fails.
|
||||
*/
|
||||
noPollConn * nopoll_listener_tls_new (noPollCtx * ctx,
|
||||
const char * host,
|
||||
const char * port)
|
||||
{
|
||||
return nopoll_listener_tls_new_opts (ctx, NULL, host, port);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allows to create a new WebSocket listener but expecting the
|
||||
* incoming connection to be under TLS supervision. The function works
|
||||
* like \ref nopoll_listener_new (providing wss:// services).
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param opts The connection options to configure this particular
|
||||
* listener.
|
||||
*
|
||||
* @param host The hostname or address interface to bind on.
|
||||
*
|
||||
* @param port The port where to listen, or NULL to use default port: 80.
|
||||
*
|
||||
* @return A reference to a \ref noPollConn object representing the
|
||||
* listener or NULL if it fails.
|
||||
*/
|
||||
noPollConn * nopoll_listener_tls_new_opts (noPollCtx * ctx,
|
||||
noPollConnOpts * opts,
|
||||
const char * host,
|
||||
const char * port)
|
||||
{
|
||||
noPollConn * listener;
|
||||
|
||||
/* call to get listener from base function */
|
||||
listener = nopoll_listener_new (ctx, host, port);
|
||||
if (! listener)
|
||||
return listener;
|
||||
|
||||
/* setup TLS support */
|
||||
listener->tls_on = nopoll_true;
|
||||
listener->opts = opts;
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to configure the TLS certificate and key to be used
|
||||
* on the provided connection.
|
||||
*
|
||||
* @param listener The listener that is going to be configured with the providing certificate and key.
|
||||
*
|
||||
* @param certificate The path to the public certificate file (PEM
|
||||
* format) to be used for every TLS connection received under the
|
||||
* provided listener.
|
||||
*
|
||||
* @param private_key The path to the key file (PEM format) to be used for
|
||||
* every TLS connection received under the provided listener.
|
||||
*
|
||||
* @param chain_file The path to additional chain certificates (PEM
|
||||
* format). You can safely pass here a NULL value.
|
||||
*
|
||||
* @return nopoll_true if the certificates were configured, otherwise
|
||||
* nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_listener_set_certificate (noPollConn * listener,
|
||||
const char * certificate,
|
||||
const char * private_key,
|
||||
const char * chain_file)
|
||||
{
|
||||
// FILE * handle;
|
||||
//
|
||||
// if (! listener || ! certificate || ! private_key)
|
||||
// return nopoll_false;
|
||||
//
|
||||
// /* check certificate file */
|
||||
// handle = fopen (certificate, "r");
|
||||
// if (! handle) {
|
||||
// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open certificate file from %s", certificate);
|
||||
// return nopoll_false;
|
||||
// } /* end if */
|
||||
// fclose (handle);
|
||||
//
|
||||
// /* check private file */
|
||||
// handle = fopen (private_key, "r");
|
||||
// if (! handle) {
|
||||
// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open private key file from %s", private_key);
|
||||
// return nopoll_false;
|
||||
// } /* end if */
|
||||
// fclose (handle);
|
||||
//
|
||||
// if (chain_file) {
|
||||
// /* check private file */
|
||||
// handle = fopen (chain_file, "r");
|
||||
// if (! handle) {
|
||||
// nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open chain certificate file from %s", private_key);
|
||||
// return nopoll_false;
|
||||
// } /* end if */
|
||||
// fclose (handle);
|
||||
// } /* end if */
|
||||
//
|
||||
// /* copy certificates to be used */
|
||||
// listener->certificate = nopoll_strdup (certificate);
|
||||
// listener->private_key = nopoll_strdup (private_key);
|
||||
// if (chain_file)
|
||||
// listener->chain_certificate = nopoll_strdup (chain_file);
|
||||
//
|
||||
// nopoll_log (listener->ctx, NOPOLL_LEVEL_DEBUG, "Configured certificate: %s, key: %s, for conn id: %d",
|
||||
// listener->certificate, listener->private_key, listener->id);
|
||||
|
||||
/* certificates configured */
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a websocket listener from the socket provided.
|
||||
*
|
||||
* @param ctx The context where the listener will be associated.
|
||||
*
|
||||
* @param session The session to associate to the listener.
|
||||
*
|
||||
* @return A reference to a listener connection object or NULL if it
|
||||
* fails.
|
||||
*/
|
||||
noPollConn * nopoll_listener_from_socket (noPollCtx * ctx,
|
||||
NOPOLL_SOCKET session)
|
||||
{
|
||||
noPollConn * listener;
|
||||
struct sockaddr_in sin;
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
/* windows flavors */
|
||||
int sin_size = sizeof (sin);
|
||||
#else
|
||||
/* unix flavors */
|
||||
socklen_t sin_size = sizeof (sin);
|
||||
#endif
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx && session > 0, NULL);
|
||||
|
||||
/* create noPollConn ection object */
|
||||
listener = nopoll_new (noPollConn, 1);
|
||||
listener->refs = 1;
|
||||
listener->session = session;
|
||||
listener->ctx = ctx;
|
||||
listener->role = NOPOLL_ROLE_LISTENER;
|
||||
|
||||
/* get peer value */
|
||||
memset (&sin, 0, sizeof (struct sockaddr_in));
|
||||
if (getpeername (session, (struct sockaddr *) &sin, &sin_size) < -1) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get remote hostname and port");
|
||||
return NULL;
|
||||
} /* end if */
|
||||
|
||||
/* record host and port */
|
||||
/* lock mutex here to protect inet_ntoa */
|
||||
listener->host = nopoll_strdup (inet_ntoa (sin.sin_addr));
|
||||
/* release mutex here to protect inet_ntoa */
|
||||
listener->port = nopoll_strdup_printf ("%d", ntohs (sin.sin_port));
|
||||
|
||||
/* configure default handlers */
|
||||
listener->receive = nopoll_conn_default_receive;
|
||||
listener->sends = nopoll_conn_default_send;
|
||||
|
||||
/* register connection into context */
|
||||
if (! nopoll_ctx_register_conn (ctx, listener)) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to register connection into the context, unable to create connection");
|
||||
nopoll_conn_ref (listener);
|
||||
return NULL;
|
||||
} /* end if */
|
||||
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d)", listener->host, listener->port, listener->session);
|
||||
|
||||
/* reduce reference counting here because ctx_register_conn
|
||||
* already acquired a reference */
|
||||
nopoll_conn_unref (listener);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Public function that performs a TCP listener accept.
|
||||
*
|
||||
* @param server_socket The listener socket where the accept()
|
||||
* operation will be called.
|
||||
*
|
||||
* @return Returns a connected socket descriptor or -1 if it fails.
|
||||
*/
|
||||
NOPOLL_SOCKET nopoll_listener_accept (NOPOLL_SOCKET server_socket)
|
||||
{
|
||||
struct sockaddr_in inet_addr;
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
int addrlen;
|
||||
#else
|
||||
socklen_t addrlen;
|
||||
#endif
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
/* accept the connection new connection */
|
||||
return accept (server_socket, (struct sockaddr *)&inet_addr, &addrlen);
|
||||
}
|
||||
|
||||
/* @} */
|
245
components/nopoll/library/nopoll_log.c
Normal file
245
components/nopoll/library/nopoll_log.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_log noPoll Log: Console log reporting for noPoll library
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_log
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Allows to check if the log reporting inside the system is
|
||||
* enabled.
|
||||
*
|
||||
* @return nopoll_true if the log is enabled or nopoll_false
|
||||
*/
|
||||
nopoll_bool nopoll_log_is_enabled (noPollCtx * ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
/* return current value */
|
||||
return ctx->debug_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Allows to get current log configuration, to use colors.
|
||||
*
|
||||
* @return nopoll_true if the color log is enabled or nopoll_false
|
||||
*/
|
||||
nopoll_bool nopoll_log_color_is_enabled (noPollCtx * ctx)
|
||||
{
|
||||
|
||||
if (ctx == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
/* return current value */
|
||||
return ctx->debug_color_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to control how to activate the log reporting to the
|
||||
* console from the nopoll core library.
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param value nopoll_true to enable log to console, otherwise nopoll_false is
|
||||
* returned.
|
||||
*/
|
||||
void nopoll_log_enable (noPollCtx * ctx, nopoll_bool value)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* activate debuging according to the variable */
|
||||
ctx->debug_enabled = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to control how to activate the colog log reporting to
|
||||
* the console from the nopoll core library.
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param value nopoll_true to enable log to console, otherwise nopoll_false is
|
||||
* returned.
|
||||
*/
|
||||
void nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* activate color debuging according to the variable */
|
||||
ctx->debug_color_enabled = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to define a log handler that will receive all logs
|
||||
* produced under the provided content.
|
||||
*
|
||||
* @param ctx The context that is going to be configured.
|
||||
*
|
||||
* @param handler The handler to be called for each log to be
|
||||
* notified. Passing in NULL is allowed to remove any previously
|
||||
* configured handler.
|
||||
*
|
||||
* @param user_data User defined pointer to be passed in into the
|
||||
* handler configured along with the log notified.
|
||||
*/
|
||||
void nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data)
|
||||
{
|
||||
nopoll_return_if_fail (ctx, ctx);
|
||||
|
||||
ctx->log_handler = handler;
|
||||
ctx->log_user_data = user_data;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Allows to drop a log to the console.
|
||||
*
|
||||
* This function allow to drop a log to the console using the given
|
||||
* domain, as an identification of which subsystem have reported the
|
||||
* information, and report level. This report level is used to notify
|
||||
* the consideration of the log reported.
|
||||
*
|
||||
* The function allows to provide a printf like interface to report
|
||||
* messages. Here are some examples:
|
||||
*
|
||||
* \code
|
||||
* // drop a log about current library initialization
|
||||
* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "library properly initialized status=%d", status);
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* @param ctx The context where the operation will take place.
|
||||
*
|
||||
* @param level The level that this message is classificed.
|
||||
*
|
||||
* @param message The message to report. The message to report must be
|
||||
* not NULL.
|
||||
*/
|
||||
void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...)
|
||||
{
|
||||
|
||||
#ifdef SHOW_DEBUG_LOG
|
||||
va_list args;
|
||||
char * log_msg;
|
||||
char * log_msg2;
|
||||
|
||||
if (ctx && ctx->log_handler) {
|
||||
/* print the message */
|
||||
va_start (args, message);
|
||||
log_msg = nopoll_strdup_printfv (message, args);
|
||||
va_end (args);
|
||||
|
||||
log_msg2 = log_msg;
|
||||
log_msg = nopoll_strdup_printf ("%s:%d %s ", file, line, log_msg);
|
||||
nopoll_free (log_msg2);
|
||||
|
||||
ctx->log_handler (ctx, level, log_msg, ctx->log_user_data);
|
||||
nopoll_free (log_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if the log is enabled */
|
||||
if (! nopoll_log_is_enabled (ctx))
|
||||
return;
|
||||
|
||||
// /* printout the process pid */
|
||||
// if (nopoll_log_color_is_enabled (ctx))
|
||||
// printf ("\e[1;36m(proc %d)\e[0m: ", getpid ());
|
||||
// else
|
||||
// printf ("(proc %d): ", getpid ());
|
||||
|
||||
/* drop a log according to the level */
|
||||
if (nopoll_log_color_is_enabled (ctx)) {
|
||||
switch (level) {
|
||||
case NOPOLL_LEVEL_DEBUG:
|
||||
printf ("(\e[1;32mdebug\e[0m) ");
|
||||
break;
|
||||
case NOPOLL_LEVEL_WARNING:
|
||||
printf ("(\e[1;33mwarning\e[0m) ");
|
||||
break;
|
||||
case NOPOLL_LEVEL_CRITICAL:
|
||||
printf ("(\e[1;31mcritical\e[0m) ");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (level) {
|
||||
case NOPOLL_LEVEL_DEBUG:
|
||||
printf ("(debug)");
|
||||
break;
|
||||
case NOPOLL_LEVEL_WARNING:
|
||||
printf ("(warning)");
|
||||
break;
|
||||
case NOPOLL_LEVEL_CRITICAL:
|
||||
printf ("(critical) ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* drop a log according to the domain */
|
||||
printf ("%s:%d ", file, line);
|
||||
|
||||
/* print the message */
|
||||
va_start (args, message);
|
||||
// vprintf (message, args);
|
||||
va_end (args);
|
||||
|
||||
printf ("\n");
|
||||
|
||||
/* ensure that the log is droped to the console */
|
||||
// fflush (stdout);
|
||||
#endif
|
||||
|
||||
/* return */
|
||||
return;
|
||||
}
|
||||
|
||||
/* @} */
|
269
components/nopoll/library/nopoll_loop.c
Normal file
269
components/nopoll/library/nopoll_loop.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_loop.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_loop noPoll Loop: basic support to create a watching loop for WebSocket listeners
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_loop
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal Function used by nopoll_loop_wait to register all
|
||||
* connections into the io waiting object.
|
||||
*/
|
||||
nopoll_bool nopoll_loop_register (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data)
|
||||
{
|
||||
/* do not add connections that aren't working */
|
||||
if (! nopoll_conn_is_ok (conn)) {
|
||||
/* remove this connection from registry */
|
||||
nopoll_ctx_unregister_conn (ctx, conn);
|
||||
return nopoll_false; /* keep foreach, don't stop */
|
||||
}
|
||||
|
||||
/* register the connection socket */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding socket id: %d", conn->session);*/
|
||||
if (! ctx->io_engine->addto (conn->session, ctx, conn, ctx->io_engine->io_object)) {
|
||||
/* remove this connection from registry */
|
||||
nopoll_ctx_unregister_conn (ctx, conn);
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Failed to add socket %d to the watching set", conn->session);
|
||||
}
|
||||
|
||||
return nopoll_false; /* keep foreach, don't stop */
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to handle incoming data from from the
|
||||
* connection and to notify this data on the connection.
|
||||
*/
|
||||
void nopoll_loop_process_data (noPollCtx * ctx, noPollConn * conn)
|
||||
{
|
||||
noPollMsg * msg;
|
||||
|
||||
/* call to get messages from the connection */
|
||||
msg = nopoll_conn_get_msg (conn);
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
/* found message, notify it */
|
||||
if (conn->on_msg)
|
||||
conn->on_msg (ctx, conn, msg, conn->on_msg_data);
|
||||
else if (ctx->on_msg)
|
||||
ctx->on_msg (ctx, conn, msg, ctx->on_msg_data);
|
||||
|
||||
/* release message */
|
||||
nopoll_msg_unref (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to detected which connections has something
|
||||
* interesting to be notified.
|
||||
*
|
||||
*/
|
||||
nopoll_bool nopoll_loop_process (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data)
|
||||
{
|
||||
int * conn_changed = (int *) user_data;
|
||||
|
||||
/* check if the connection have something to notify */
|
||||
if (ctx->io_engine->isset (ctx, conn->session, ctx->io_engine->io_object)) {
|
||||
|
||||
/* call to notify action according to role */
|
||||
switch (conn->role) {
|
||||
case NOPOLL_ROLE_CLIENT:
|
||||
case NOPOLL_ROLE_LISTENER:
|
||||
/* received data, notify */
|
||||
nopoll_loop_process_data (ctx, conn);
|
||||
break;
|
||||
case NOPOLL_ROLE_MAIN_LISTENER:
|
||||
/* call to handle */
|
||||
nopoll_conn_accept (ctx, conn);
|
||||
break;
|
||||
default:
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found connection with unknown role, closing and dropping");
|
||||
nopoll_conn_shutdown (conn);
|
||||
break;
|
||||
}
|
||||
|
||||
/* reduce connection changed */
|
||||
(*conn_changed)--;
|
||||
} /* end if */
|
||||
|
||||
return (*conn_changed) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Function used to init internal io wait mechanism...
|
||||
*
|
||||
* @param ctx The noPoll context to be initialized if it wasn't
|
||||
*/
|
||||
void nopoll_loop_init (noPollCtx * ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
/* grab the mutex for the following check */
|
||||
if (ctx->io_engine == NULL) {
|
||||
ctx->io_engine = nopoll_io_get_engine (ctx, NOPOLL_IO_ENGINE_DEFAULT);
|
||||
if (ctx->io_engine == NULL) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to create IO wait engine, unable to implement wait call");
|
||||
return;
|
||||
}
|
||||
} /* end if */
|
||||
/* release the mutex */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flag to stop the current loop implemented (if any) on the provided context.
|
||||
*
|
||||
* @param ctx The context where the loop is being done, and wanted to
|
||||
* be stopped.
|
||||
*
|
||||
*/
|
||||
void nopoll_loop_stop (noPollCtx * ctx)
|
||||
{
|
||||
if (! ctx)
|
||||
return;
|
||||
ctx->keep_looping = nopoll_false;
|
||||
return;
|
||||
} /* end if */
|
||||
|
||||
/**
|
||||
* @brief Allows to implement a wait over all connections registered
|
||||
* under the provided context during the provided timeout until
|
||||
* something is detected meaningful to the user, calling to the action
|
||||
* handler defined, optionally receving the user data pointer.
|
||||
*
|
||||
* @param ctx The context object where the wait will be implemented.
|
||||
*
|
||||
* @param timeout The timeout to wait for changes. If no changes
|
||||
* happens, the function returns. The function will block the caller
|
||||
* until a call to \ref nopoll_loop_stop is done in the case timeout
|
||||
* passed is 0.
|
||||
*
|
||||
* @return The function returns 0 when finished or -2 in the case ctx
|
||||
* is NULL or timeout is negative.
|
||||
*/
|
||||
int nopoll_loop_wait (noPollCtx * ctx, long timeout)
|
||||
{
|
||||
struct timeval start;
|
||||
struct timeval stop;
|
||||
struct timeval diff;
|
||||
long ellapsed;
|
||||
int wait_status;
|
||||
|
||||
nopoll_return_val_if_fail (ctx, ctx, -2);
|
||||
nopoll_return_val_if_fail (ctx, timeout >= 0, -2);
|
||||
|
||||
/* call to init io engine */
|
||||
nopoll_loop_init (ctx);
|
||||
|
||||
/* get as reference current time */
|
||||
if (timeout > 0)
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
nopoll_win32_gettimeofday (&start, NULL);
|
||||
#else
|
||||
gettimeofday (&start, NULL);
|
||||
#endif
|
||||
|
||||
/* set to keep looping everything this function is called */
|
||||
ctx->keep_looping = nopoll_true;
|
||||
|
||||
while (ctx->keep_looping) {
|
||||
/* ok, now implement wait operation */
|
||||
ctx->io_engine->clear (ctx, ctx->io_engine->io_object);
|
||||
|
||||
/* add all connections */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding connections to watch: %d", ctx->conn_num); */
|
||||
nopoll_ctx_foreach_conn (ctx, nopoll_loop_register, NULL);
|
||||
|
||||
/* if (errno == EBADF) { */
|
||||
/* detected some descriptor not properly
|
||||
* working, try to check them */
|
||||
/* nopoll_ctx_foreach_conn (ctx, nopoll_loop_clean_descriptors, NULL); */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found some descriptor is not valid (errno==%d)", errno);
|
||||
continue; */
|
||||
/* } */ /* end if */
|
||||
|
||||
/* implement wait operation */
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting for changes into %d connections", ctx->conn_num); */
|
||||
wait_status = ctx->io_engine->wait (ctx, ctx->io_engine->io_object);
|
||||
/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting finished with result %d", wait_status); */
|
||||
if (wait_status == -1) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received error from wait operation, error code was: %d", errno);
|
||||
break;
|
||||
} /* end if */
|
||||
|
||||
/* check how many connections changed and restart */
|
||||
if (wait_status > 0) {
|
||||
/* check and call for connections with something
|
||||
* interesting */
|
||||
nopoll_ctx_foreach_conn (ctx, nopoll_loop_process, &wait_status);
|
||||
}
|
||||
|
||||
/* check to stop wait operation */
|
||||
if (timeout > 0) {
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
nopoll_win32_gettimeofday (&stop, NULL);
|
||||
#else
|
||||
gettimeofday (&stop, NULL);
|
||||
#endif
|
||||
nopoll_timeval_substract (&stop, &start, &diff);
|
||||
ellapsed = (diff.tv_sec * 1000000) + diff.tv_usec;
|
||||
if (ellapsed > timeout)
|
||||
break;
|
||||
} /* end if */
|
||||
} /* end while */
|
||||
|
||||
/* release engine */
|
||||
nopoll_io_release_engine (ctx->io_engine);
|
||||
ctx->io_engine = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
|
320
components/nopoll/library/nopoll_msg.c
Normal file
320
components/nopoll/library/nopoll_msg.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
#include <nopoll_msg.h>
|
||||
#include <nopoll_private.h>
|
||||
|
||||
/**
|
||||
* \defgroup nopoll_msg noPoll Message: functions for handling and using noPoll messages (websocket messages)
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup nopoll_msg
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal function that creates an empty message holder.
|
||||
* @return A newly created reference or NULL if it fails.
|
||||
*/
|
||||
noPollMsg * nopoll_msg_new (void)
|
||||
{
|
||||
noPollMsg * msg = nopoll_new (noPollMsg, 1);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
msg->refs = 1;
|
||||
msg->ref_mutex = nopoll_mutex_create ();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get a reference to the payload content inside the
|
||||
* provided websocket message.
|
||||
*
|
||||
* @param msg The websocket message to get the payload from.
|
||||
*
|
||||
* @return A reference to the payload or NULL if it fails. See \ref
|
||||
* nopoll_msg_get_payload_size to get payload size.
|
||||
*/
|
||||
const unsigned char * nopoll_msg_get_payload (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
return msg->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get the payload byte length stored on the provided
|
||||
* message.
|
||||
*
|
||||
* @param msg The websocket message to get the payload from.
|
||||
*
|
||||
* @return The payload size or -1 if it fails (only when msg is NULL).
|
||||
*/
|
||||
int nopoll_msg_get_payload_size (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
return msg->payload_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to acquire a reference to the provided websocket
|
||||
* message.
|
||||
*
|
||||
* @param msg The websocket message to acquire a reference.
|
||||
*
|
||||
* @return nopoll_true if the reference was acquired, otherwise
|
||||
* nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_msg_ref (noPollMsg * msg)
|
||||
{
|
||||
/* check recieved reference */
|
||||
if (msg == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (msg->ref_mutex);
|
||||
|
||||
msg->refs++;
|
||||
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (msg->ref_mutex);
|
||||
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get current reference counting for the provided
|
||||
* message.
|
||||
*
|
||||
* @param msg The message for which we are requesting for the
|
||||
* reference counting.
|
||||
*
|
||||
* @return Reference counting or -1 if it fails (returned when msg
|
||||
* reference received is NULL).
|
||||
*/
|
||||
int nopoll_msg_ref_count (noPollMsg * msg)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* check recieved reference */
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (msg->ref_mutex);
|
||||
|
||||
result = msg->refs;
|
||||
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (msg->ref_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to get if the provided message reference has FIN flag
|
||||
* on (or off) to indicate if it is a final frame.
|
||||
*
|
||||
* When a series of messages are received and they conform together a
|
||||
* single message, the last message is flagged with FIN = 1 while the
|
||||
* rest before go with FIN = 0.
|
||||
*
|
||||
* For example, if a user level application is splitted into 4 frame
|
||||
* fragments, then the WebSocket peer will receive 3 fragments with
|
||||
* FIN = 0 and the last fragment with FIN = 1.
|
||||
*
|
||||
* You can use \ref nopoll_msg_is_fragment to know if a particular
|
||||
* message was produced due to a fragmentation found at the network
|
||||
* level. This happens when the entire frame wasn't sent or it
|
||||
* couldn't be read entirely. In the example before, the four frames
|
||||
* will be also flagged as fragments too.
|
||||
*
|
||||
* @param msg The message that is being checked for FIN flag.
|
||||
*
|
||||
* @return nopoll_true if the message is a final one, otherwise
|
||||
* nopoll_false is returned. The function returns nopoll_false when
|
||||
* message reference received is NULL.
|
||||
*
|
||||
*/
|
||||
nopoll_bool nopoll_msg_is_final (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return nopoll_false;
|
||||
|
||||
return msg->has_fin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to check if the message represents a frame fragment.
|
||||
*
|
||||
* The function allows to check if the provided noPollMsg is a
|
||||
* fragment from a bigger frame or message that was splitted as a
|
||||
* consequence of not being able to read the entire frame or because
|
||||
* it wasn't sent complete from the other side. See \ref
|
||||
* nopoll_msg_is_final for more information.
|
||||
*
|
||||
* The function also returns that the message is a fragment when the frame has FIN = 0.
|
||||
*
|
||||
* @param msg The message checked to be a fragment or not.
|
||||
*
|
||||
* @return nopoll_true if the message is a fragment, otherwise
|
||||
* nopoll_false is returned.
|
||||
*/
|
||||
nopoll_bool nopoll_msg_is_fragment (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return nopoll_false;
|
||||
return msg->is_fragment || msg->has_fin == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get message OpCode to get the type of message that was
|
||||
* received.
|
||||
*
|
||||
* @param msg The message that is being checked for its OpCode
|
||||
*
|
||||
* @return The op code or -1 in the case NULL reference is received.
|
||||
*/
|
||||
noPollOpCode nopoll_msg_opcode (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return NOPOLL_UNKNOWN_OP_CODE;
|
||||
return (noPollOpCode) msg->op_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to join the provided noPollMsg references to create a
|
||||
* newly allocated message (or reusing same reference but increasing reference
|
||||
* counting) that contains both content.
|
||||
*
|
||||
* @param msg The message to be join to the next message. Headers from
|
||||
* this message will be used as reference for the headers to be
|
||||
* used. In the case this is NULL, the second argument will be used as
|
||||
* argument and reference counting will be updated.
|
||||
*
|
||||
* @param msg2 The message to be join as a second part for the first
|
||||
* argument.
|
||||
*
|
||||
* Here are some examples showing how the function works. The notation
|
||||
* along the argument indicates the reference counting at the end of
|
||||
* the function.
|
||||
*
|
||||
* msgA (2) = nopoll_msg_join (msgA (1), NULL);
|
||||
* msgB (2) = nopoll_msg_join (NULL, msgB (1));
|
||||
* msgC (1) = nopoll_msg_join (msgA (1), msgB (1));
|
||||
* NULL = nopoll_msg_join (NULL, NULL);
|
||||
*
|
||||
* @return The function returns the newly allocated or reused
|
||||
* reference with increased reference counting or NULL if it fails.
|
||||
*/
|
||||
noPollMsg * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2)
|
||||
{
|
||||
noPollMsg * result;
|
||||
|
||||
/* check for basic cases */
|
||||
if (msg == NULL && msg2 == NULL)
|
||||
return NULL;
|
||||
if (msg == NULL && msg2) {
|
||||
nopoll_msg_ref (msg2);
|
||||
return msg2;
|
||||
} /* ned if */
|
||||
if (msg && msg2 == NULL) {
|
||||
nopoll_msg_ref (msg);
|
||||
return msg;
|
||||
} /* end if */
|
||||
|
||||
/* now, join content */
|
||||
result = nopoll_msg_new ();
|
||||
result->has_fin = msg->has_fin;
|
||||
result->op_code = msg->op_code;
|
||||
result->is_masked = msg->is_masked;
|
||||
if (result->is_masked)
|
||||
memcpy (result->mask, msg->mask, 4);
|
||||
|
||||
/* copy payload size and content */
|
||||
result->payload_size = msg->payload_size + msg2->payload_size;
|
||||
result->payload = nopoll_new (char, result->payload_size + 1);
|
||||
|
||||
/* copy content from first message */
|
||||
memcpy (result->payload, msg->payload, msg->payload_size);
|
||||
|
||||
/* copy content from second message */
|
||||
memcpy (((unsigned char *) result->payload) + msg->payload_size , msg2->payload, msg2->payload_size);
|
||||
|
||||
/* return joined message */
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allows to release the reference acquired, finished the
|
||||
* object if all references are terminated.
|
||||
*
|
||||
* @param msg The websocket message to be finished.
|
||||
*/
|
||||
void nopoll_msg_unref (noPollMsg * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
/* acquire mutex here */
|
||||
nopoll_mutex_lock (msg->ref_mutex);
|
||||
|
||||
msg->refs--;
|
||||
if (msg->refs != 0) {
|
||||
/* release mutex here */
|
||||
nopoll_mutex_unlock (msg->ref_mutex);
|
||||
return;
|
||||
}
|
||||
/* release mutex */
|
||||
nopoll_mutex_unlock (msg->ref_mutex);
|
||||
nopoll_mutex_destroy (msg->ref_mutex);
|
||||
|
||||
/* free websocket message */
|
||||
nopoll_free (msg->payload);
|
||||
nopoll_free (msg);
|
||||
|
||||
/* release mutex here */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* @} */
|
136
components/nopoll/library/nopoll_win32.c
Normal file
136
components/nopoll/library/nopoll_win32.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* LibNoPoll: A websocket library
|
||||
* Copyright (C) 2013 Advanced Software Production Line, S.L.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*
|
||||
* You may find a copy of the license under this software is released
|
||||
* at COPYING file. This is LGPL software: you are welcome to develop
|
||||
* proprietary applications using this library without any royalty or
|
||||
* fee but returning back any change, improvement or addition in the
|
||||
* form of source code, project image, documentation patches, etc.
|
||||
*
|
||||
* For commercial support on build Websocket enabled solutions
|
||||
* contact us:
|
||||
*
|
||||
* Postal address:
|
||||
* Advanced Software Production Line, S.L.
|
||||
* Edificio Alius A, Oficina 102,
|
||||
* C/ Antonio Suarez Nº 10,
|
||||
* Alcalá de Henares 28802 Madrid
|
||||
* Spain
|
||||
*
|
||||
* Email address:
|
||||
* info@aspl.es - http://www.aspl.es/nopoll
|
||||
*/
|
||||
|
||||
#include <nopoll.h>
|
||||
|
||||
#define LOG_DOMAIN "nopoll-win32"
|
||||
|
||||
#if defined(NOPOLL_OS_WIN32)
|
||||
|
||||
nopoll_bool __nopoll_win32_was_init = nopoll_false;
|
||||
|
||||
int nopoll_win32_init (noPollCtx * ctx)
|
||||
{
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int error;
|
||||
|
||||
if (__nopoll_win32_was_init)
|
||||
return nopoll_true;
|
||||
|
||||
wVersionRequested = MAKEWORD( 2, 2 );
|
||||
|
||||
error = WSAStartup( wVersionRequested, &wsaData );
|
||||
if (error != NO_ERROR) {
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to init winsock api, exiting..");
|
||||
return nopoll_false;
|
||||
}
|
||||
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "winsock initialization ok");
|
||||
/* flag the library as initialized */
|
||||
__nopoll_win32_was_init = nopoll_true;
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain (HINSTANCE hInst,
|
||||
DWORD reason,
|
||||
LPVOID reserved)
|
||||
{
|
||||
|
||||
/* always returns true because nopoll init is done through
|
||||
* nopoll_init */
|
||||
return nopoll_true;
|
||||
}
|
||||
|
||||
int __nopoll_win32_blocking_socket_set (NOPOLL_SOCKET socket,
|
||||
int status)
|
||||
{
|
||||
unsigned long enable = status;
|
||||
|
||||
return (ioctlsocket (socket, FIONBIO, &enable) == 0);
|
||||
}
|
||||
|
||||
int nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket)
|
||||
{
|
||||
return __nopoll_win32_blocking_socket_set (socket, 1);
|
||||
}
|
||||
|
||||
int nopoll_win32_blocking_enable (NOPOLL_SOCKET socket)
|
||||
{
|
||||
return __nopoll_win32_blocking_socket_set (socket, 0);
|
||||
}
|
||||
|
||||
#if ! defined(HAVE_GETTIMEOFDAY)
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function obtains the current time, expressed as seconds
|
||||
* and microseconds since the Epoch, and store it in the timeval
|
||||
* structure pointed to by tv. As posix says gettimeoday should return
|
||||
* zero and should not reserve any value for error, this function
|
||||
* returns zero.
|
||||
*
|
||||
* The timeval struct have the following members:
|
||||
*
|
||||
* \code
|
||||
* struct timeval {
|
||||
* long tv_sec;
|
||||
* long tv_usec;
|
||||
* } timeval;
|
||||
* \endcode
|
||||
*
|
||||
* @param tv Timeval struct.
|
||||
* @param notUsed Not defined.
|
||||
*
|
||||
* @return The function allways return 0.
|
||||
*/
|
||||
int nopoll_win32_gettimeofday(struct timeval *tv, noPollPtr notUsed)
|
||||
{
|
||||
union {
|
||||
long long ns100;
|
||||
FILETIME fileTime;
|
||||
} now;
|
||||
|
||||
GetSystemTimeAsFileTime (&now.fileTime);
|
||||
tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
|
||||
tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
|
||||
return (0);
|
||||
} /* end gettimeofday */
|
||||
#endif /* end ! defined(HAVE_GETTIMEOFDAY) */
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user