esp8266-std/ESP8266_RTOS_SDK/third_party/nopoll/nopoll.c

1730 lines
54 KiB
C
Raw Normal View History

2018-11-23 01:43:17 +00:00
/*
* 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 10,
* Alcalá de Henares 28802 Madrid
* Spain
*
* Email address:
* info@aspl.es - http://www.aspl.es/nopoll
*/
#include <nopoll.h>
#include <nopoll_private.h>
#include "freertos/FreeRTOS.h"
/**
* \defgroup nopoll_support noPoll Support: core support functions used by the library
*/
/**
* \addtogroup nopoll_support
* @{
*/
/**
* @brief Allows to check if provided strings are equal.
*
* @param string1 The first string to check. The string must be ended by 0.
* @param string2 The second string to check. The string must be ended by 0.
*
* @return nopoll_true if both strings are equal, otherwise
* nopoll_false is returned.
*/
nopoll_bool nopoll_cmp (const char * string1, const char * string2)
{
int iterator;
if (string1 == NULL && string2 == NULL)
return nopoll_true;
if (string1 == NULL || string2 == NULL)
return nopoll_false;
/* next position */
iterator = 0;
while (string1[iterator] && string1[iterator]) {
if (string1[iterator] != string2[iterator])
return nopoll_false;
iterator++;
} /* end while */
/* last check, ensure both ends with 0 */
return string1[iterator] == string2[iterator];
}
/**
* @brief Allows to check if provided strings are equal for the first
* bytes.
*
* @param string1 The first string to check. The string must be ended by 0.
* @param string2 The second string to check. The string must be ended by 0.
* @param bytes Number of bytes to check. The value must be > 0.
*
* @return nopoll_true if both strings are equal, otherwise
* nopoll_false is returned.
*/
nopoll_bool nopoll_ncmp (const char * string1, const char * string2, int bytes)
{
int iterator;
if (bytes <= 0)
return nopoll_false;
if (string1 == NULL && string2 == NULL)
return nopoll_true;
if (string1 == NULL || string2 == NULL)
return nopoll_false;
/* next position */
iterator = 0;
while (string1[iterator] &&
string2[iterator] &&
iterator < bytes) {
if (string1[iterator] != string2[iterator])
return nopoll_false;
iterator++;
} /* end while */
/* last check, ensure both ends with 0 */
return iterator == bytes;
}
/**
* @brief Allows to produce an newly allocated string produced by the
* chunk received plus arguments, using the printf-like format.
*
* @param chunk The chunk to copy.
*
* @return A newly allocated chunk.
*/
char * nopoll_strdup_printf (const char * chunk, ...)
{
char * result = NULL;
va_list args;
if (chunk == NULL)
return NULL;
/* open std args */
va_start (args, chunk);
/* get the string */
result = nopoll_strdup_printfv (chunk, args);
/* close std args */
va_end (args);
return result;
}
/**
* @internal Allows to calculate the amount of memory required to
* store the string that will representing the construction provided
* by the printf-like format received and its arguments.
*
* @param format The printf-like format to be printed.
*
* @param args The set of arguments that the printf applies to.
*
* <i><b>NOTE:</b> not all printf specification is supported. Generally, the
* following is supported: %s, %d, %f, %g, %ld, %lg and all
* combinations that provides precision, number of items inside the
* integer part, etc: %6.2f, %+2d, etc. An especial case not supported
* is %lld, %llu and %llg.</i>
*
* @return Return the number of bytes that must be allocated to hold
* the string (including the string terminator \0). If the format is
* not correct or it is not properly formated according to the value
* found at the argument set, the function will return -1.
*/
int nopoll_vprintf_len (const char * format, va_list args)
{
/** IMPLEMENTATION NOTE: in the case this code is update,
* update exarg_vprintf_len **/
#if defined (NOPOLL_OS_WIN32) && ! defined (__GNUC__)
# if HAVE_VSCPRINTF
if (format == NULL)
return 0;
return _vscprintf (format, args) + 1;
# else
char buffer[8192];
if (format == NULL)
return 0;
return _vsnprintf (buffer, 8191, format, args) + 1;
# endif
#else
/* gnu gcc case */
if (format == NULL)
return 0;
return vsnprintf (NULL, 0, format, args) + 1;
#endif
}
/**
* @brief DEPRECATED: Allows to produce an string representing the
* message hold by chunk with the parameters provided.
*
* @param chunk The message chunk to print.
* @param args The arguments for the chunk.
*
* @return A newly allocated string.
*
* IMPLEMENTATION NOTE: This function may have a fundamental bug due
* to the design of va_list arguments under amd64 platforms. In short,
* a function receiving a va_list argument can't use it twice. In you
* are running amd64, check your nopoll_config.h did find
* NOPOLL_HAVE_VASPRINTF.
*/
char * nopoll_strdup_printfv (const char * chunk, va_list args)
{
/** IMPLEMENTATION NOTE: place update exarg_strdup_printfv
* code in the case this code is updated **/
#if defined(SHOW_DEBUG_LOG) && ! defined(NOPOLL_HAVE_VASPRINTF)
noPollCtx * ctx = NULL;
#endif
#if !defined(NOPOLL_HAVE_VASPRINTF)
int size;
#endif
char * result = NULL;
if (chunk == NULL)
return NULL;
#ifdef NOPOLL_HAVE_VASPRINTF
/* do the operation using the GNU extension */
if (vasprintf (&result, chunk, args) == -1)
return NULL;
#else
/* get the amount of memory to be allocated */
size = nopoll_vprintf_len (chunk, args);
/* check result */
if (size == -1) {
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to calculate the amount of memory for the strdup_printf operation");
return NULL;
} /* end if */
/* allocate memory */
result = nopoll_new (char, size + 2);
/* copy current size */
# if defined(NOPOLL_OS_WIN32) && ! defined (__GNUC__)
size = _vsnprintf_s (result, size + 1, size, chunk, args);
# else
size = vsnprintf (result, size + 1, chunk, args);
# endif
#endif
/* return the result */
return result;
}
/**
* @internal Function used by \ref nopoll_trim.
*/
nopoll_bool nopoll_is_white_space (char * chunk)
{
/* do not complain about receive a null refernce chunk */
if (chunk == NULL)
return nopoll_false;
if (chunk[0] == ' ')
return nopoll_true;
if (chunk[0] == '\n')
return nopoll_true;
if (chunk[0] == '\t')
return nopoll_true;
if (chunk[0] == '\r')
return nopoll_true;
/* no white space was found */
return nopoll_false;
}
/**
* @brief Removes white spaces and new lines characters from the
* string providing the count of bytes trimmed from the string.
*
* @param chunk The chunk to trim.
*
* @param trimmed An optional reference that returns the count of bytes
* trimmed by the operation.
*/
void nopoll_trim (char * chunk, int * trimmed)
{
int iterator;
int iterator2;
int end;
int total;
/* perform some environment check */
if (chunk == NULL)
return;
/* check empty string received */
if (strlen (chunk) == 0) {
if (trimmed)
*trimmed = 0;
return;
}
/* check the amount of white spaces to remove from the
* begin */
iterator = 0;
while (chunk[iterator] != 0) {
/* check that the iterator is not pointing to a white
* space */
if (! nopoll_is_white_space (chunk + iterator))
break;
/* update the iterator */
iterator++;
}
/* check for the really basic case where an empty string is found */
if (iterator == (int) strlen (chunk)) {
/* an empty string, trim it all */
chunk [0] = 0;
if (trimmed)
*trimmed = iterator;
return;
} /* end if */
/* now get the position for the last valid character in the
* chunk */
total = strlen (chunk) -1;
end = total;
while (chunk[end] != 0) {
/* stop if a white space is found */
if (! nopoll_is_white_space (chunk + end)) {
break;
}
/* update the iterator to eat the next white space */
end--;
}
/* the number of items trimmed */
total -= end;
total += iterator;
/* copy the exact amount of non white spaces items */
iterator2 = 0;
while (iterator2 < (end - iterator + 1)) {
/* copy the content */
chunk [iterator2] = chunk [iterator + iterator2];
/* update the iterator */
iterator2++;
}
chunk [ end - iterator + 1] = 0;
if (trimmed != NULL)
*trimmed = total;
/* return the result reference */
return;
}
/**
* @brief Portable subsecond sleep. Suspends the calling thread during
* the provided amount of time.
*
* @param microseconds The amount of time to wait.
*/
void nopoll_sleep (long microseconds)
{
#if defined(NOPOLL_OS_UNIX)
// usleep (microseconds);
vTaskDelay(microseconds / portTICK_RATE_MS);
return;
#elif defined(NOPOLL_OS_WIN32)
Sleep (microseconds / 1000);
return;
#endif
}
noPollMutexCreate __nopoll_mutex_create = NULL;
noPollMutexDestroy __nopoll_mutex_destroy = NULL;
noPollMutexLock __nopoll_mutex_lock = NULL;
noPollMutexUnlock __nopoll_mutex_unlock = NULL;
/**
* @brief Creates a mutex with the defined create mutex handler.
*
* See \ref nopoll_thread_handlers for more information.
*
* @return A mutex reference or NULL if it fails.
*/
noPollPtr nopoll_mutex_create (void)
{
if (! __nopoll_mutex_create)
return NULL;
/* call defined handler */
return __nopoll_mutex_create ();
}
/**
* @brief Implements a mutex lock operation on the provided
* reference. The function just skip when no mutex reference is
* received o no lock handler was defined.
*
* See \ref nopoll_thread_handlers for more information.
*
* @param mutex The mutex where do the lock operation.
*
* The function will just return if the reference isn't defined or the
* lock handler wasn't installed.
*/
void nopoll_mutex_lock (noPollPtr mutex)
{
if (! __nopoll_mutex_lock)
return;
/* call defined handler */
__nopoll_mutex_lock (mutex);
return;
}
/**
* @brief Implements a mutex unlock operation on the provided
* reference. The function just skip when no mutex reference is
* received o no unlock handler was defined.
*
* See \ref nopoll_thread_handlers for more information.
*
* @param mutex The mutex where do the unlock operation.
*
*/
void nopoll_mutex_unlock (noPollPtr mutex)
{
if (! __nopoll_mutex_unlock)
return;
/* call defined handler */
__nopoll_mutex_unlock (mutex);
return;
}
/**
* @brief Implements a mutex destroy operation on the provided
* reference. The function just skip when no mutex reference is
* received o no destroy handler was defined.
*
* See \ref nopoll_thread_handlers for more information.
*
* @param mutex The mutex to destroy operation.
*
*/
void nopoll_mutex_destroy (noPollPtr mutex)
{
if (! __nopoll_mutex_destroy)
return;
/* call defined handler */
__nopoll_mutex_destroy (mutex);
return;
}
/**
* @brief Global optional mutex handlers used by noPoll library to
* create, destroy, lock and unlock mutex.
*
* If you set this handlers, the library will use these functions to
* secure sensitive code paths that mustn't be protected while working
* with threads.
*
* If you don't provide these, the library will work as usual without
* doing any locking.
*
* @param mutex_create The handler used to create mutexes.
*
* @param mutex_destroy The handler used to destroy mutexes.
*
* @param mutex_lock The handler used to lock a particular mutex.
*
* @param mutex_unlock The handler used to unlock a particular mutex.
*
* The function must receive all handlers defined, otherwise no
* configuration will be done.
*/
void nopoll_thread_handlers (noPollMutexCreate mutex_create,
noPollMutexDestroy mutex_destroy,
noPollMutexLock mutex_lock,
noPollMutexUnlock mutex_unlock)
{
/* check handlers before configuring anything */
if (! mutex_create ||
! mutex_destroy ||
! mutex_lock ||
! mutex_unlock)
return;
/* configured received handlers */
__nopoll_mutex_create = mutex_create;
__nopoll_mutex_destroy = mutex_destroy;
__nopoll_mutex_lock = mutex_lock;
__nopoll_mutex_unlock = mutex_unlock;
return;
}
/**
* @brief Allows to encode the provided content, leaving the output on
* the buffer allocated by the caller.
*
* @param content The content to be encoded.
*
* @param length Content byte-length to encode.
*
* @param output Reference to the already allocated buffer where to
* place the output.
*
* @param output_size The buffer size.
*
* @return nopoll_true if the conversion was properly done, otherwise
* nopoll_false is returned. The function also returns nopoll_false in
* the case some parameter is not defined.
*/
nopoll_bool nopoll_base64_encode (const char * content,
int length,
char * output,
int * output_size)
{
base64_encode(output, *output_size, (int*)output_size, (char *)content,length);
return nopoll_true;
#if 0
BIO * b64;
BIO * bmem;
BUF_MEM * bptr;
if (content == NULL || output == NULL || length <= 0 || output_size == NULL)
return nopoll_false;
/* create bio */
b64 = BIO_new (BIO_f_base64());
bmem = BIO_new (BIO_s_mem());
/* push */
b64 = BIO_push(b64, bmem);
if (BIO_write (b64, content, length) != length) {
BIO_free_all (b64);
return nopoll_false;
}
if (BIO_flush (b64) != 1) {
BIO_free_all (b64);
return nopoll_false;
}
/* now get content */
BIO_get_mem_ptr (b64, &bptr);
/* check output size */
if ((*output_size) < bptr->length) {
BIO_free_all (b64);
*output_size = bptr->length;
return nopoll_false;
}
memcpy(output, bptr->data, bptr->length - 1);
output[bptr->length-1] = 0;
BIO_free_all (b64);
return nopoll_true;
#endif
}
/**
* @brief Decodes the provided base64 content into the user provided
* buffer.
*
* @param content The content to be decoded.
*
* @param length Content byte-length to encode.
*
* @param output Reference to the already allocated buffer where to
* place the output.
*
* @param output_size The buffer size.
*
* @return nopoll_true if the conversion was properly done, otherwise
* nopoll_false is returned. The function also returns nopoll_false in
* the case some parameter is not defined.
*/
nopoll_bool nopoll_base64_decode (const char * content,
int length,
char * output,
int * output_size)
{
int ret;
ret = base64_decode(content,length,output,output_size);
return ret;
#if 0
BIO * b64;
BIO * bmem;
if (content == NULL || output == NULL || length <= 0 || output_size == NULL)
return nopoll_false;
/* create bio */
bmem = BIO_new_mem_buf ((void *) content, length);
b64 = BIO_new (BIO_f_base64());
BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL);
/* push */
bmem = BIO_push(b64, bmem);
*output_size = BIO_read (bmem, output, *output_size);
output[*output_size] = 0;
BIO_free_all (bmem);
return nopoll_true;
#endif
}
/**
* @brief Performs a timeval substract leaving the result in
* (result). Subtract the `struct timeval' values a and b, storing the
* result in result.
*
* @param a First parameter to substract
*
* @param b Second parameter to substract
*
* @param result Result variable. Do no used a or b to place the
* result.
*
* @return 1 if the difference is negative, otherwise 0 (operations
* implemented is a - b).
*/
int nopoll_timeval_substract (struct timeval * a,
struct timeval * b,
struct timeval * result)
{
/* Perform the carry for the later subtraction by updating
* y. */
if (a->tv_usec < b->tv_usec) {
int nsec = (b->tv_usec - a->tv_usec) / 1000000 + 1;
b->tv_usec -= 1000000 * nsec;
b->tv_sec += nsec;
}
if (a->tv_usec - b->tv_usec > 1000000) {
int nsec = (a->tv_usec - b->tv_usec) / 1000000;
b->tv_usec += 1000000 * nsec;
b->tv_sec -= nsec;
}
/* get the result */
result->tv_sec = a->tv_sec - b->tv_sec;
result->tv_usec = a->tv_usec - b->tv_usec;
/* return 1 if result is negative. */
return a->tv_sec < b->tv_sec;
}
/**
* @brief Safe strdup () wrapper.
*
* @param buffer The string to copy
*
* @return A reference to the string copied or NULL if it fails.
*/
char * nopoll_strdup (const char * buffer)
{
if (buffer == NULL)
return NULL;
return strdup (buffer);
}
/* internal reference to track if we have to randomly init seed */
nopoll_bool __nopoll_nonce_init = nopoll_false;
/**
* @brief Fills the buffer provided with a random nonce of the
* requested size. The function try to read random bytes from the
* local PRNG to complete the bytes requested on the buffer..
*
* @param buffer The buffer where the output is left
*
* @param nonce_size The size of the requested nonce to written into the caller buffer.
*
* @return nopoll_true if the nonce was created otherwise nopoll_false
* is returned.
*/
nopoll_bool nopoll_nonce (char * buffer, int nonce_size)
{
long int random_value;
int iterator;
struct timeval tv;
if (buffer == NULL || nonce_size <= 0)
return nopoll_false;
if (! __nopoll_nonce_init) {
#if defined(NOPOLL_OS_WIN32)
nopoll_win32_gettimeofday (&tv, NULL);
#else
gettimeofday (&tv, NULL);
#endif
// srand (time(0) * tv.tv_usec);
__nopoll_nonce_init = nopoll_true;
} /* end if */
/* now get the value from random */
iterator = 0;
while (iterator < nonce_size) {
/* gen random value */
#if defined(NOPOLL_OS_WIN32)
random_value = rand ();
#else
random_value = os_random();
#endif
/* copy into the buffer */
memcpy (buffer + iterator, &random_value, sizeof (random_value));
iterator += sizeof (random_value);
} /* end while */
return nopoll_true;
}
/**
* @internal Allows to extract a particular bit from a byte given the
* position.
*
* +------------------------+
* | 7 6 5 4 3 2 1 0 | position
* +------------------------+
*/
int nopoll_get_bit (char byte, int position) {
return ( ( byte & (1 << position) ) >> position);
}
/**
* @internal Allows to set a particular bit on the first position of
* the buffer provided.
*
* +------------------------+
* | 7 6 5 4 3 2 1 0 | position
* +------------------------+
*/
void nopoll_set_bit (char * buffer, int position) {
buffer[0] |= (1 << position);
return;
}
void nopoll_show_byte (noPollCtx * ctx, char byte, const char * label) {
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " byte (%s) = %d %d %d %d %d %d %d %d",
label,
nopoll_get_bit (byte, 7),
nopoll_get_bit (byte, 6),
nopoll_get_bit (byte, 5),
nopoll_get_bit (byte, 4),
nopoll_get_bit (byte, 3),
nopoll_get_bit (byte, 2),
nopoll_get_bit (byte, 1),
nopoll_get_bit (byte, 0));
return;
}
char * nopoll_int2bin (int a, char *buffer, int buf_size) {
int i;
buffer += (buf_size - 1);
for (i = 31; i >= 0; i--) {
*buffer-- = (a & 1) + '0';
a >>= 1;
}
return buffer;
}
#define BUF_SIZE 33
void nopoll_int2bin_print (noPollCtx * ctx, int value) {
char buffer[BUF_SIZE];
buffer[BUF_SIZE - 1] = '\0';
nopoll_int2bin (value, buffer, BUF_SIZE - 1);
nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "%d = %s", value, buffer);
return;
}
/**
* @internal Allows to get the 16 bit integer located at the buffer
* pointer.
*
* @param buffer The buffer pointer to extract the 16bit integer from.
*
* @return The 16 bit integer value found at the buffer pointer.
*/
int nopoll_get_16bit (const char * buffer)
{
int high_part = buffer[0] << 8;
int low_part = buffer[1] & 0x000000ff;
return (high_part | low_part) & 0x000000ffff;
}
/**
* @internal Allows to get the 8bit integer located at the buffer
* pointer.
*
* @param buffer The buffer pointer to extract the 8bit integer from.
*
* @erturn The 8 bit integer value found at the buffer pointer.
*/
int nopoll_get_8bit (const char * buffer)
{
return buffer[0] & 0x00000000ff;
}
/**
* @internal Allows to set the 16 bit integer value into the 2 first
* bytes of the provided buffer.
*
* @param value The value to be configured in the buffer.
*
* @param buffer The buffer where the content will be placed.
*/
void nopoll_set_16bit (int value, char * buffer)
{
buffer[0] = (value & 0x0000ff00) >> 8;
buffer[1] = value & 0x000000ff;
return;
}
/**
* @internal Allows to set the 32 bit integer value into the 4 first
* bytes of the provided buffer.
*
* @param value The value to be configured in the buffer.
*
* @param buffer The buffer where the content will be placed.
*/
void nopoll_set_32bit (int value, char * buffer)
{
buffer[0] = (value & 0x00ff000000) >> 24;
buffer[1] = (value & 0x0000ff0000) >> 16;
buffer[2] = (value & 0x000000ff00) >> 8;
buffer[3] = value & 0x00000000ff;
return;
}
/**
* @brief Allows to get a 32bits integer value from the buffer.
*
* @param buffer The buffer where the integer will be retreived from.
*
* @return The integer value reported by the buffer.
*/
int nopoll_get_32bit (const char * buffer)
{
int part1 = (int)(buffer[0] & 0x0ff) << 24;
int part2 = (int)(buffer[1] & 0x0ff) << 16;
int part3 = (int)(buffer[2] & 0x0ff) << 8;
int part4 = (int)(buffer[3] & 0x0ff);
return part1 | part2 | part3 | part4;
}
extern nopoll_bool __nopoll_tls_was_init;
/**
* @brief Optional function that can be called at the very end of the
* noPoll usage to ensure all memory allocated by the library is
* released so debugging operations are easier.
*
* It is not required to call this function to get proper operation by
* the library. It is provided, especially due to TLS, to release all
* internal memory that may be allocated.
*/
void nopoll_cleanup_library (void)
{
if (__nopoll_tls_was_init) {
EVP_cleanup ();
CRYPTO_cleanup_all_ex_data ();
ERR_free_strings ();
/* notify the library isn't initialized */
__nopoll_tls_was_init = nopoll_false;
} /* end if */
return;
} /* end if */
/* @} */
/**
* \mainpage
*
* \section intro noPoll: a toolkit to add WebSocket support to your project
*
* <b>noPoll</b> is a clean implemetnation of the <b>RFC 6455 : The Websocket protocol</b> definition, written in <b>ANSI C</b>.
*
* Some of its features are:
*
* - Context based API design making the library stateless. Support to run several execution contexts in the same process.
* - Support for stream based API and message based API (handler notified)
* - Robust and well tested implementation checked by a strong regression test to ensure the library keeps on working as new features are added.
* - Flexible design that allows its integration into a external loop or to use its own waiting loop
* - Support for port share which allows running native protocol and WebSocket protocol on the same port.
*
* noPoll has been developed by <b>Advanced Software Production Line,
* S.L.</b> (http://www.aspl.es). It is \ref license "licensed under the LGPL 2.1"
* which allows open source and commercial usage.
*
* noPoll manual is available in the following link:
*
* - \ref nopoll_core_library_manual
* - \ref license
*
* Check out <b>noPoll API documentation</b> in the following links:
*
* 1) Common API definition:
*
* - \ref nopoll_support
* - \ref nopoll_decl_module
* - \ref nopoll_ctx
* - \ref nopoll_handlers
* - \ref nopoll_log
* - \ref nopoll_loop
*
* 2) Function for creating connections and listeners
*
* - \ref nopoll_conn
* - \ref nopoll_listener
* - \ref nopoll_conn_opts
*
* 3) Functions to handle messages (message based API):
*
* - \ref nopoll_msg
*
* \section contact_aspl Contact Us
*
* You can reach us at the <b>noPoll mailing list:</b> at <a href="http://lists.aspl.es/cgi-bin/mailman/listinfo/nopoll">noPoll users</a>
* for any question you may find.
*
* If you are interested on getting commercial support, you can also
* contact us at: info@aspl.es.
*/
/**
* \page nopoll_core_library_manual noPoll core library manual
*
* \section nopoll_core_library_manual_index Index
*
* <b>Section 1: Basic concepts to starting writing with or integrating noPoll:</b>
*
* - \ref installing_nopoll
* - \ref using_nopoll
* - \ref thread_safety
* - \ref creating_a_nopoll_ctx
* - \ref creating_basic_web_socket_server
* - \ref creating_basic_web_socket_client
* - \ref nopoll_manual_reading_content_from_connection
* - \ref nopoll_manual_handling_fragments_with_websocket
*
* <b>Section 2: Advanced concepts to consider: </b>
*
* - \ref nopoll_manual_retrying_write_operations
* - \ref nopoll_implementing_port_sharing
*
* <b>Section 3: using noPoll TLS API: </b>
*
* - \ref nopoll_implementing_mutual_auth
* - \ref nopoll_implementing_tls_extended_validation_post_check
* - \ref nopoll_implementing_tls_context_creator
*
* <b>Section 4: Android platfom notes: </b>
*
* - \ref nopoll_android_usage "4.1 Android noPoll's usage"
*
* \section installing_nopoll 1.1 How to install noPoll
*
* Currently, noPoll has only one dependency, which is OpenSSL
* (libssl) for all those crypto operations required by the protocol
* itself.
*
* After having that library installed in your system (check your OS
* documentation), download lastest tar.gz noPoll library from: http://code.google.com/p/no-poll
*
* Then, to compile the library follow the standard autoconf voodoo:
*
* \code
* >> tar xzvf nopoll-{version}.tar.gz
* >> cd nopoll-{version}
* >> ./configure
* >> make
* \endcode
*
* At this point, if everything went ok, you can check the library by running in one terminal:
*
* \code
* >> cd test/
* >> ./nopoll-regression-listener
* \endcode
*
* And then in another terminal the client regression test:
*
* \code
* >> cd test/
* >> ./nopoll-regression-client
* \endcode
*
* If everything looks fine, you can install nopoll into your system with the standard:
* \code
* >> make install
* \endcode
*
* \section using_nopoll 1.2. How to use noPoll library into your application
*
* After a successful noPoll installation, you should be able to
* include noPoll API functions by including the following header:
*
* \code
* #include <nopoll.h>
* \endcode
*
* Then you can use the following to get nopoll compilation flags:
*
* \code
* >> pkg-config nopoll --cflags
* >> pkg-config nopoll --libs
* \endcode
*
* Or if your project uses autoconf for the building process, just include the following into your configure.ac file:
*
* \code
* dnl check for websocket support (through noPoll)
* AC_ARG_ENABLE(websocket-support, [ --disable-websocket-support Makes the built with WebSocket extension library],
* enable_websocket_support="$enableval",
* enable_websocket_support=yes)
* if test "$enable_websocket_support" != "no" ; then
* PKG_CHECK_MODULES(NOPOLL, nopoll, [enable_websocket_support=yes], [enable_websocket_support=no])
* AC_SUBST(NOPOLL_CFLAGS)
* AC_SUBST(NOPOLL_LIBS)
* fi
* AM_CONDITIONAL(ENABLE_WEBSOCKET_SUPPORT, test "x$enable_websocket_support" = "xyes")
* \endcode
*
* \section thread_safety 1.3. noPoll thread safety considerations
*
* noPoll is designed as a thread agnostic stateless library so it can
* fit in any project configuration (no matter if it uses threads or
* event notification).
*
* In the case you are planning to use noPoll in a project that uses
* threads and you expect to make calls to the noPoll API from
* different threads at the same time, then you must setup four
* callbacks that will help noPoll to create, destroy, lock and unlock
* mutexes. For that, check documentation about \ref
* nopoll_thread_handlers
*
* \section creating_a_nopoll_ctx 1.4. Creating a noPoll context
*
* Before working with noPoll API you must create a
* \ref noPollCtx object, which represents a single library instance
* state. You can create as much \ref noPollCtx objects inside the process as you
* want. To create it you must do something like:
*
* \code
* noPollCtx * ctx = nopoll_ctx_new ();
* if (! ctx) {
* // error some handling code here
* }
*
* // do some WebSocket operations (as client or listener)...
*
* // ...and once you are done and after terminating all messages and
* // connections created you have to release the context by doing the
* // following:
* nopoll_ctx_unref (ctx);
* \endcode
*
*
*
*
* \section creating_basic_web_socket_server 1.5. Creating a basic WebSocket server with noPoll (using noPoll own loop)
*
* \note Remember you can see many of the code already supported by noPoll by checking the nopoll regression listener at: https://dolphin.aspl.es/svn/publico/nopoll/trunk/test/nopoll-regression-listener.c
*
* Now let's see how to create a simple WebSocket server using noPoll own loop:
* \code
* // create a listener to receive connections on port 1234
* noPollConn * listener = nopoll_listener_new (ctx, "0.0.0.0", "1234");
* if (! nopoll_conn_is_ok (listener)) {
* // some error handling here
* }
*
* // now set a handler that will be called when a message (fragment or not) is received
* nopoll_ctx_set_on_msg (ctx, listener_on_message, NULL);
*
* // now call to wait for the loop to notify events
* nopoll_loop_wait (ctx, 0);
* \endcode
*
* Now, every time a frame is received, the handler
* <b>listener_on_message</b> will be called. Here is an example about
* that handler:
*
* \code
* void listener_on_message (noPollCtx * ctx, noPollConn * conn, noPollMsg * msg, noPollPtr * user_data) {
* // print the message (for debugging purposes) and reply
* printf ("Listener received (size: %d, ctx refs: %d): (first %d bytes, fragment: %d) '%s'\n",
* nopoll_msg_get_payload_size (msg),
* nopoll_ctx_ref_count (ctx), shown, nopoll_msg_is_fragment (msg), example);
*
* // reply to the message
* nopoll_conn_send_text (conn, "Message received", 16);
*
* return;
* }
* \endcode
*
* \section creating_basic_web_socket_client 1.6. Creating a basic WebSocket client with noPoll
*
* \note Remember you can see many of the code already supported by noPoll by checking the nopoll regression client at: https://dolphin.aspl.es/svn/publico/nopoll/trunk/test/nopoll-regression-client.c
*
* The process of creating a WebSocket connection is really
* simple. After creating a context (\ref noPollCtx) you connect to
* the listener by using:
*
* \code
* // call to create a connection
* noPollConn * conn = nopoll_conn_new (ctx, "localhost", "1234", NULL, NULL, NULL, NULL);
* if (! nopoll_conn_is_ok (conn)) {
* // some error handling here
* }
*
* \endcode
*
* After that, you can call to \ref nopoll_conn_is_ready to check if
* the connection is ready to send and receive content. If you don't
* have a loop to wait on, you can use the following function to wait
* for the connection to be ready:
*
* \code
* if (! nopoll_conn_wait_until_connection_ready (conn, 5)) {
* // some error handling
* }
* \endcode
*
* In any case, once the connection is ready, either because \ref
* nopoll_conn_is_ready returned \ref nopoll_true or because you used
* \ref nopoll_conn_wait_until_connection_ready, you can send a
* message by using the following:
*
* \code
* // send a message
* if (nopoll_conn_send_text (conn, "Hello there! this is a test", 27) != 27) {
* // send a message
* }
* \endcode
*
* Now, to receive the content from this connection see the following.
*
* \section nopoll_manual_reading_content_from_connection 1.7. How to handle read I/O operations on noPollConn objects (or how it integrates with existing I/O loops).
*
* Now, to receive content from connections (or to handle master listeners requests) you can use the following methods:
*
* - Use noPoll own I/O loop wait (\ref nopoll_loop_wait) and set a onMessage received handler (\ref nopoll_ctx_set_on_msg and \ref nopoll_conn_set_on_msg)
*
* - Use your already working I/O loop to wait for changes on the
* socket associated to the noPollConn object (see \ref
* nopoll_conn_socket). In the case of detecting changes on a master listener connection use to \ref nopoll_conn_accept to accept new incoming connections. In the case of detecting changes in connections with I/O, call to \ref nopoll_conn_get_msg to receive entire messages or \ref nopoll_conn_read (if you want to use streaming API).
*
* \section nopoll_manual_handling_fragments_with_websocket 1.8 Will noPoll automatically integrate fragments into a single message?.
*
* Ok, in general it does, however we would have to look into the
* particular case to give a correct answer. That's because the term
* "fragment" is *really* broad especially for WebSocket.
*
* In general, <b>you shouldn't design in a way that this is important
* for your application to work</b>. All about WebSocket must be designed
* as if you were working with a stream oriented socket.
*
* For example, WebSocket standard states that any intermediary may
* split or join frames. And by any intermediary we mean any WebSocket
* stack in the middle of the transmission including the sender and
* the receiver.
*
* The practical implication is that if your WebSocket peer sends a
* message, it may reach to the other peer consolidated along with
* other smaller messages or it may be received as several "complete"
* WebSocket frames.
*
* In general noPoll tries to consolidate internal frame fragments but
* only for some particular functions like (\ref
* nopoll_conn_get_msg). For example, if a frame fragment is received,
* that is, just the header and part of the body, this particular
* function will "wait" until the entire body is received. And by
* "wait" we mean the function will return NULL, waiting you to call
* again in the future to get the entire message.
*
* In general, even though the standard allows it (as we saw), noPoll
* doesn't do any split or join operation to avoid confusion. However,
* some API calls like \ref nopoll_conn_read, which provides an "stream
* view" of the connection, will serve bytes as they come (so the
* frame concept is not present in this case).
*
* \section nopoll_manual_retrying_write_operations 2.1. Retrying failed write operations
*
* Every time you do a write operation (using for example \ref
* nopoll_conn_send_text or \ref nopoll_conn_send_text_fragment) there
* is a possibility that the write operation <b>failes because the socket
* isn't capable to keep on accepting more data</b>.
*
* In that case, errno == 11 (or \ref NOPOLL_EWOULDBLOCK) is returned
* so you can check this to later retry the write operation.
*
* Because websocket involves sending headers that already includes
* the size of the message sent, <b>you can't just retry by calling again
* to the send operation used</b> (like \ref nopoll_conn_send_text),
* especially because you must "continue" the send operation where it
* was left instead of sending more content with additional
* headers. <b>In short, you must complete the operation.</b>
*
* To this end, you must use the following functions to check and
* complete pending write operations:
*
* - \ref nopoll_conn_pending_write_bytes
* - \ref nopoll_conn_complete_pending_write
*
* Here is a posible complete function considering all points:
*
* \code
* int websocket_write (noPollConn * conn, const char * content, int length) {
* // FIRST PART: normal send operation
* int tries = 0;
* int bytes_written;
*
* // do write operation and check
* bytes_written = nopoll_conn_send_text (conn, content, length);
* if (bytes_written == length) {
* // operation completed, just return bytes written
* return bytes_written;
* }
*
* // SECOND PART: retry in the case of failure
* // some failure found, check errno
* while (tries < 5 && errno == NOPOLL_EWOULDBLOCK && nopoll_conn_pending_write_bytes (conn) > 0) {
* // ok, unable to write all data but that data is waiting to be flushed
* // you can return here and then make your application to retry again or
* // try it right now, but with a little pause before continue
* nopoll_sleep (10000); // lets wait 10ns
*
* // flush and check if write operation completed
* if (nopoll_conn_complete_pending_write (conn) == 0)
* return length;
*
* // limit loop
* tries++;
* }
*
* // failure, return error code reported by the first call or the last retry
* return bytes_written;
* }
* \endcode
*
* As we can see, the example tries to first write the content and
* then check for errors, trying to complete write in the case of
* errno == NOPOLL_EWOULDBLOCK, but, before going ahead retrying, the
* function sleeps a bit.
*
* <b>A very important note to consider is that this</b> isn't by far
* the best way to do this. This example is just to demonstrate the
* concept. The "ideal" implementation would be not to do any retry
* here (second part) but let the engine looping and waiting for this
* WebSocket to retry later, letting the overall application to keep
* on doing other things meanwhile (like writing or handling I/O in other
* connections) rather than locking the caller (as the example do).
*
* Knowing this, if you want a ready to use function that implements
* concept (for the second part), you can directly use:
*
* - \ref nopoll_conn_flush_writes
*
* With it, a fairly complete and efficient write operation would be:
*
* \code
* // do write operation
* bytes_written = nopoll_conn_send_text (conn, content, length);
*
* // complete pending write by flushing and limitting operation for 2 seconds
* // pass to the function bytes_written as returned by nopoll_conn_send_text
* bytes_written = nopoll_conn_flush_writes (conn, 2000000, bytes_written);
*
* \endcode
*
* \section nopoll_implementing_port_sharing 2.2. Implementing protocol port sharing: running WebSocket and legacy protocol on the same port
*
* Current noPoll design allows to implement full WebSocket connection
* accept by calling to \ref nopoll_conn_accept but also it is
* possible to let other application to do the accept connection, try
* to guess if what is comming is a WebSocket connection, to then let
* noPoll to complete the accept socket operation.
*
* As a example, these concepts are being implemented by Vortex
* Library (http://www.aspl.es/vortex) to allow running on the same
* port BEEP and BEEP over WebSocket.
*
* The way each application implements "port sharing concept" is
* really especific to each case, but here are the general steps:
*
* - 1. Let the legacy application to accept the socket by the standard call accept ()
*
* - 2. Then, call to recv (socket, buffer[3], 3, MSG_PEEK); to get just 3 bytes from the socket without removing them from the queue.
*
* - 3. Then check with something like the following to know if the incoming connection seems to be a WebSocket one or not:
*
* \code
* // detect tls conn
* nopoll_bool is_tls_conn = bytes[0] == 22 && bytes[1] == 3 && bytes[2] == 1;
*
* // detect then both values (TLS WebSocket and just WebScoket)
* if (! axl_memcmp ("GET", bytes, 3) && ! is_tls_conn)
* return nopoll_false; // nothing detected here (it doesn't seems
* // to be a websocket connection) continue as normal
*
* // nice, it seems we've found an incoming WebSocket connection
* \endcode
*
* - 4. In the case nothing was detected, stop, and continue with the
* usual accept process that was already in place. In the case you
* detected a posible WebSocket connection, then, you'll have to
* do something like:
*
* \code
* // Create a noPollConn listener object that presents the legacy listener where the connection was
* // received. In general is recommended to reuse these references to avoid creating over and over
* // again new references as new WebSocket connections are received.
* //
* noPollConn * nopoll_listener = nopoll_listener_from_socket (nopoll_ctx, listener_socket);
*
* // Create an accepted listener connection reusing the socket received
* // where nopoll_ctx is a reference to a noPollCtx object created and reused by all
* // connections accepted, and _socket represents the socket file descriptor
* //
* noPollConn * conn = nopoll_listener_from_socket (nopoll_ctx, _socket);
* if (! nopoll_conn_is_ok (conn)) {
* // ok, something failed, release and return
* nopoll_conn_close (conn);
* return;
* }
*
* // Now, initiate the entire WebSocket accept process (including TLS one)
* // where nopoll_ctx is the context we used before, nopoll_listener is a listener where
* // the connection was received, conn is the connection accepted and is_tls_conn
* // is an indication about what to expect about TLS process.
* //
* if (! nopoll_conn_accept_complete (nopoll_ctx, nopoll_listener, conn, _socket, is_tls_conn)) {
* // failed to accept connection, release connection
* nopoll_conn_close (conn);
* // optionally close listener reference if it is not reused
* nopoll_conn_close (nopoll_listener);
* return;
* }
*
* // now process incoming messages as configured (either because you've configured an onMessage handler)
* // or because you are handling directly all incoming content (streaming API).
* \endcode
*
* \section nopoll_implementing_mutual_auth 3.1. Implementing mutual TLS certificate verification
*
* In the case you want to verify provided client certificate at the
* server you can use the following code. It optionally provides the
* CA (as root.pem) which will make the listener to also verify client
* matches that CA. However, if you remove that CA (root.pem) your
* server will just verify peer's certificate:
*
* \code
* // configure server certificates (server.pem) signed by the
* // provided ca (root.pem) also configured in the last
* // parameter
* if (! nopoll_conn_opts_set_ssl_certs (opts,
* "server.pem",
* "server.key",
* NULL,
* "root.pem")) {
* printf ("ERROR: unable to setup certificates...\n");
* return -1;
* }
*
* // configure peer verification
* nopoll_conn_opts_ssl_peer_verify (opts, nopoll_true);
*
* // create listener
* listener2 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1239");
* if (! nopoll_conn_is_ok (listener2)) {
* printf ("ERROR: Expected to find proper listener TLS connection status (:1236, SSLv23), but found..\n");
* return -1;
* }
* \endcode
*
* Here the important part is calling to \ref
* nopoll_conn_opts_ssl_peer_verify. This is because peer verification
* is disabled for servers (that is, servers by default do not verify
* peer's certificate which usually is not provided). However, this is
* not true for clients which is by default enabled (of course, client
* must always verify server's certificate when connecting with
* TLS/SSL, was we have said, this can be controlled by \ref
* nopoll_conn_opts_ssl_peer_verify too).
*
* Now, in the case you want to provide client certificate for a
* WebSocket connecting node, use the following:
*
*
* \code
* // create connection options
* opts = nopoll_conn_opts_new ();
* nopoll_conn_opts_set_ssl_certs (opts,
* // certificate
* "client.pem",
* // private key
* "client.pem",
* NULL,
* // ca certificate
* "root.pem");
*
* // connect to remote WebSocket server
* conn = nopoll_conn_tls_new (ctx, opts, "server-address", "1239", NULL, NULL, NULL, NULL);
* \endcode
*
* \section nopoll_implementing_tls_extended_validation_post_check 3.2. Doing extended validation as a post check task (TLS/SSL)
*
* The idea is to configure the following handler at your server/listener component:
*
* \code
* nopoll_ctx_set_post_ssl_check (ctx, your_post_ssl_check_handler, <some-user-pointer>);
* \endcode
*
* Now, somewhere, that handler will have the following signature and code example:
*
* \code
* nopoll_bool your_post_ssl_check_handler (noPollCtx * ctx,
* noPollConn * conn,
* noPollPtr SSL_CTX,
* noPollPtr SSL,
* noPollPtr user_data)
* {
*
* // Do here some additional checks on the certificate received (using SSL_CTX and SSL).
* // I the case of error, return nopoll_false to ensure the connection is not accepted.
*
* return nopoll_true; // to accept connection
* }
* \endcode
*
* For example, to get the certificate that is proposing the client you could use:
*
* \code
* cert = SSL_get_peer_certificate (SSL);
* \endcode
*
* \section nopoll_implementing_tls_context_creator 3.3. Creating TLS/SSL context to implement especific validation options
*
* In the case you want to create the SSL_CTX/SSL object so it uses
* certain configurations like chain certificates, etc, so that the
* verification will only work when matching these settings.
*
* If this is the case you'll have to use a different handler that
* will help noPoll engine to create the SSL context with the settings
* you want. By default, the SSL context is created with default
* settings if no handler is provided.
*
* In the case you want to provide a ssl context creator, use:
*
* \code
* nopoll_ctx_set_ssl_context_creator (ctx, your_ssl_context_creator, NULL);
* \endcode
*
* And your handler will have the following signature with a very
* basic configuration:
*
* \code
* SSL_CTX * your_ssl_context_creator (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client, noPollPtr user_data)
* {
* // very basic context creation using default settings provided by OpenSSL
* return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ());
* }
* \endcode
*
* As you can see, the function must return an SSL_CTX for every
* connection received and attempting to start TLS session.
*
*
*/
/**
* \page nopoll_android_usage Android noPoll's usage
*
*
* \section nopoll_android_usage Using noPoll's Android install and development kit
*
* Inside http://www.aspl.es/nopoll/downloads/android you'll find two types of downloads.
* One prefixed with <b>-install.zip</b> that provides just those binaries needed and <b>-full.zip</b>
* that provides a ready to use binaries with all the headers, etc needed to produce
* Android solutions using noPoll library.
*
*
* \section nopoll_general_notes General notes
*
* The idea behind these installers is the following. Because there
* are several platforms (android APIs) that you might want to support
* and for each platform there could be several archs (up to 6), these
* installers include all files compiled for each possible
* combination.
*
* That way, you only have to pick desired combinations to compile
* your project with ready to use binaries.
*
*
* \section nopoll_platforms_archs Platforms and archs
*
* In particular the following platforms are supported by the
* NDK. Each of them represents an android particular version:
*
* - android-12
* - android-13
* - android-14
* - android-15
* - android-16
* - android-17
* - android-18
* - android-19
* - android-21
* - android-3
* - android-4
* - android-5
* - android-8
* - android-9
*
* In the following link you have a declaration between each platform
* and each Android version: https://developer.android.com/ndk/guides/stable_apis.html
*
* Now, for each platform you may have different archs supported (cpu
* style):
*
* - arm
* - arm64
* - mips
* - mips64
* - x86
* - x86_64
*
* More information about this at: https://developer.android.com/ndk/guides/abis.html
*
* \section nopoll_using_install_bundle Using the install bundle
*
* Assuming previous information, please, uncompress
* nopoll-VERSION-instal.zip bundle. Inside it, you'll find a
* "install" folder that inside includes the following structure:
*
* \code
* install/<android-platform>/lib/<arch>/{libfiles}.so
* \endcode
*
* That way, if you need ready to use compiled libraries for android-21, arch mips64, the look at:
*
* \code
* install/android-21/<arch>/lib/mips64/{libfiles}.so files.
* \endcode
*
* You might wonder why don't use a <android-platform>/<arch>/lib
* scheme? That's good question. This is because Android
* architectural design. See "Native code in app packages" in the
* following link https://developer.android.com/ndk/guides/abis.html
* to know more about this structure.
*
* The idea is that you have to support all <archs> for a given
* <android-platform> (android-21 i.e.).
*
* In that case, the install.zip is prepared to pick the entire
* directory content of a given android platform (for example
* install/android-21/) so the structure follows the guide lines of
* Android but also provides you full support for all archs, in that
* platform, to all components that noPoll is made of.
*
* \section nopoll_use_development_kit Using development kit bundle (full.zip)
*
* Ok, now for compiling your project for android using this bundle,
* please grab a reference to the full installer and uncompress it.
*
* Inside, you'll find the following structure (more handy for a
* developer using autoconf or cmake):
*
* \code
* full/<arch>/<platform>/{ready to use devel files to compile using noPoll}
* \endcode
*
*
* Now, assuming you are working with an ARM device, running android
* 4.0, then you can use files found at:
*
* \code
* full/arm/android-14/bin/
* include/
* lib/
* share/
* ssl/
* \endcode
*
*
* In your case, you only have to provide the following gcc flags to
* your cmake or autoconf environment as follows:
*
* 1) Compiler flags:
*
* \code
* CFLAGS="-I/full/arm/android-14/include -I/full/arm/android-14/include/vortex -I/full/arm/android-14/include/axl -I/full/arm/android-14/include/nopoll"
* \endcode
*
* 2) Linker flags:
*
* \code
* LDFLAGS=" -L/full/arm/android-14/lib -lvortex -lvortex-tls-1.1 -l axl -lssl -lcrypto -lpthread -pthread -lm"
* \endcode
*
* 3) And your compiler must match the target platform, for example, for ARM:
*
* \code
* CC := $(ANDROID_NDK_BIN)/arm-linux-androideabi-gcc
* CPP := $(ANDROID_NDK_BIN)/arm-linux-androideabi-g++
* AR := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ar
* LD := $(ANDROID_NDK_BIN)/arm-linux-androideabi-ld
* \endcode
*
* After that, according to your compiling tool, have it to use these
* indicatations to compile your source code using noPoll.
*
*
*/
/**
* \page license noPoll License
*
* \section licence_intro noPoll terms of use
* The noPoll is release under the terms of the Lesser General
* Public license (LGPL). You can find it at
* http://www.gnu.org/licenses/licenses.html#LGPL.
*
* The main implication this license has is that you are allowed to
* use the noPoll for commercial application as well on open
* source application using GPL/LGPL compatible licenses.
*
* Restrictions for proprietary development are the following:
*
* - You have to provide back to the main repository or to your
* customers any change, modifications, improvements you may do to the
* noPoll. Of course, we would appreciate to add to the main
* noPoll repository any patch, idea or improvement you send
* us but you are not required to do so.
*
* - You cannot use our company name or image, the noPoll name
* or any trademark associated to that product or any product the
* Advanced Software Production Line company may have in a way that
* they could be damaged. Of course, we would appreciate your project, in
* the case it is a proprietary one, make a reference to us but you are
* not required to do so.
*
* \section license_about_static_linking About statically linking noPoll
*
* Statically linking noPoll or any other component based on GPL/LGPL
* <b>is strictly forbidden by the license</b> unless all components
* taking part into the final products are all of them GPL, LGPL, MIT,
* Bsds, etc, or similar licenses that allow an end user or the
* customer to download the entire product source code and clear
* instructions to rebuild it.
*
* If the library is being used by a proprietary product the only
* allowed option is dynamic linking (so final user is capable of
* updating that dynamic linked part) or a practical procedure where
* the propritary binary object along with the instructions to relink
* the LGPL part (including an update or modification of it) is
* provided.
*
* An end user or customer using a product using LGPL components must
* be able to rebuild those components by introducing updates or
* improvements.
*
* Thus, statically linking a LGPL components without considering
* previous points takes away this user/customer right because he/she
* cannot replace/update that LGPL component anymore unless you can
* have access to the whole solution.
*
* - See more about this at: https://www.gnu.org/licenses/lgpl-2.1.html
* - Also at: http://stackoverflow.com/questions/10130143/gpl-lgpl-and-static-linking
* - LGPL 2.1 Guide: http://copyleft.org/guide/comprehensive-gpl-guidech11.html
*
* \section other Contact us to know more about licenses.
*
* Use the following contact information to reach us about this issue.
*
* \code
* Postal address:
* Advanced Software Production Line, S.L.
* C/ Antonio Suarez 10,
* Edificio Alius A, Despacho 102
* Alcalá de Henares 28802 (Madrid)
* Spain
*
* Email address:
* info@aspl.es - http://www.aspl.es/nopoll
* Fax and Telephones:
* (+34) 91 669 55 32 - (+34) 91 231 44 50
* From outside Spain must use (+34) prefix.
* \endcode
*
*
*/