Ver código fonte

Merge pull request #1 from zhaojuntao/Add-source

[nopoll] Add source code and examples
Bernard Xiong 8 anos atrás
pai
commit
c6ed33e146

+ 54 - 2
README.md

@@ -1,2 +1,54 @@
-# nopoll
-ASPLes/nopoll - OpenSource WebSocket toolkit for RT-Thread
+# noPoll  
+[noPoll]() is a OpenSource WebSocket implementation (RFC 6455) , written in ansi C , that allows building pure WebSocket solutions or to provide WebSocket support to existing TCP oriented applications.   
+
+Here is a simple implementation for RT-Thread based on [noPoll]() , temporarily only support non-encrypted operation.  
+
+# Quick Start  
+There is a websocket client example at `examples/nopoll_client.c`.  
+Test server host : echo.websocket.org  
+Test server port : 80 
+
+Run the example at `MSH` as follows :
+```
+msh />nopoll_client
+web socket connection ready!
+sending content..
+recv: Hello RT-Thread!
+sendcnt = 1
+...
+...
+```
+
+# Notes  
+## 1 Not defined `strdup` function   
+
+If your compiler is not offered `strdup` function , you can implement it yourself as shown below :   
+
+```
+/* _strdup.c  */   
+#include <rtthread.h>
+
+#ifdef RT_USING_HEAP
+char *strdup(const char *s)
+{
+	size_t len = strlen(s) + 1;
+	char *tmp = (char *)rt_malloc(len);
+
+	if(!tmp) return NULL;
+
+	rt_memcpy(tmp, s, len);
+	return tmp;
+}
+#endif
+```
+## 2 `FD_SETSIZE` too small  
+
+Please config the project as shown below :   
+The `RT-Thread Component/Device virtual file system/The maximal number of opened files` value need to  greater or equal to `RT-Thread Component/Network stack/light weight TCP/IP stack/The number of raw connection` value.  
+
+
+# Reference  
+1 WebSocket Official website : http://websocket.org/  
+2 noPoll Official website : http://www.aspl.es/nopoll/  
+3 noPoll GitHub repository : https://github.com/ASPLes/nopoll  
+4 WebSocket test server : http://websocket.org/echo.html  

+ 36 - 0
SConscript

@@ -0,0 +1,36 @@
+import os
+import rtconfig
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Split('''
+nopoll/nopoll.c
+nopoll/nopoll_conn_opts.c
+nopoll/nopoll_ctx.c
+nopoll/nopoll_decl.c
+nopoll/nopoll_io.c
+nopoll/nopoll_listener.c
+nopoll/nopoll_log.c
+nopoll/nopoll_loop.c
+nopoll/nopoll_msg.c
+nopoll/nopoll_conn.c
+nopoll/nopoll_rtthread.c
+sha1/sha1.c
+''')
+
+CPPPATH = [cwd + '/nopoll', cwd + '/sha1']
+
+LOCAL_CCFLAGS = ''
+
+if rtconfig.CROSS_TOOL == 'keil':
+    LOCAL_CCFLAGS += ' --gnu'
+
+group = DefineGroup('nopoll', src, depend = ['RT_USING_LWIP', 'PKG_USING_NOPOLL'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
+
+examples_src = Split('''
+examples/nopoll_client.c
+''')
+
+group = group + DefineGroup('nopoll-examples', examples_src, depend = ['PKG_USING_NOPOLL', 'PKG_USING_NOPOLL_EXAMPLE'], LOCAL_CCFLAGS = LOCAL_CCFLAGS)
+
+Return('group')

+ 141 - 0
examples/nopoll_client.c

@@ -0,0 +1,141 @@
+#include <rtthread.h>
+#include <finsh.h>
+
+#include <nopoll.h>
+#include <nopoll_decl.h>
+#include <nopoll_private.h>
+
+#define HOST_NAME "echo.websocket.org"
+#define HOST_PORT "80"
+
+/* eg: "/ws" , used for http handshake request URI */
+#define HOST_URI (NULL)
+
+static char message[1024] = {'*'};
+static char rev_buffer[1024];
+
+static int nopoll_client(int argc, char **argv)
+{
+	noPollConn *conn = RT_NULL;
+	noPollCtx *ctx = RT_NULL;
+
+	/* initialize context */
+	ctx = nopoll_ctx_new();
+
+	/* create connection */
+	conn = nopoll_conn_new(ctx, HOST_NAME, HOST_PORT, HOST_NAME, HOST_URI, NULL, NULL);
+	if (!nopoll_conn_is_ok(conn))
+	{
+		printf("ERROR: Expected to find proper client connection status, but found error..\n");
+		goto __exit;
+	} /* end if */
+
+	if (!nopoll_conn_wait_until_connection_ready(conn, 6))
+	{
+		printf("ERROR: websocket connection failed!\n");
+		goto __exit;
+	} /* end if */
+
+	printf("web socket connection ready!\n");
+
+	{
+		int bytes_read;
+		int retries = 0;
+		int sendcnt = 0;
+
+		int length = 0;
+
+		/* test blocking mode */
+		{
+			char *block_msg = "Hello RT-Thread!";
+
+			length = strlen(block_msg);
+
+			/* send content text(utf-8) */
+			printf("sending content..\n");
+			if (nopoll_conn_send_text(conn, block_msg, length) != length)
+			{
+				printf("ERROR: Expected to find proper send operation..\n");
+				goto __exit;
+			}
+
+			/* nopoll_true : blocking, wait for the reply (try to read length, blocking and with a 3 seconds timeout) */
+			bytes_read = nopoll_conn_read(conn, rev_buffer, length, nopoll_true, 3000);
+			if (bytes_read > 0)
+				rev_buffer[bytes_read] = 0;
+
+			if (bytes_read != length)
+			{
+				printf("ERROR: expected to find 14 bytes but found %d..\n", bytes_read);
+				goto __exit;
+			} /* end if */
+
+			printf("recv: %s\n", rev_buffer);
+		}
+
+		memset(rev_buffer, 0, sizeof(rev_buffer));
+
+		/* test no-blocking mode */
+		{
+			memset(message, '*', sizeof(message) - 1);
+
+			char *send_message = message;
+
+			while (1)
+			{
+				/* send content text(utf-8) */
+				if (nopoll_conn_send_text(conn, send_message, strlen(send_message)) != strlen(send_message))
+				{
+					printf("ERROR: Expected to find proper send operation..\n");
+					goto __exit;
+				} /* end if */
+
+				send_message += sizeof(char) * 10;
+				sendcnt++;
+
+				printf("sendcnt = %d\n", sendcnt);
+
+				/* nopoll_false : non-blocking */
+				bytes_read = nopoll_conn_read(conn, rev_buffer, sizeof(rev_buffer), nopoll_false, 1000);
+				if (bytes_read < 0)
+				{
+					printf("ERROR: expected to find bytes from the connection but found: %d\n", bytes_read);
+					goto __exit;
+				}
+				else if (bytes_read == 0)
+				{
+					retries++;
+					if (retries > 10)
+					{
+						printf("Error: nothing found (0 bytes), %d retries\n", retries);
+						goto __exit;
+					} /* end if */
+
+					continue;
+				}
+				else
+				{
+					rev_buffer[bytes_read] = '\0';
+					printf("\nrecv: %s \nlength = %d\n", rev_buffer, strlen(rev_buffer));
+				} /* end if */
+
+				rt_thread_delay(3000);
+
+				if ((send_message - message) / sizeof(char) > sizeof(message))
+					goto __exit;
+			}
+		}
+	}
+
+__exit:
+	/* close the connection */
+	if (conn)
+		nopoll_conn_close(conn);
+
+	/* release context */
+	if (ctx)
+		nopoll_ctx_unref(ctx);
+
+	return 0;
+} /* end nopoll_client */
+MSH_CMD_EXPORT(nopoll_client, websocket client test no input param);

+ 1744 - 0
nopoll/nopoll.c

@@ -0,0 +1,1744 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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_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);
+	return;
+#elif defined(NOPOLL_OS_RTTHREAD)
+	rt_tick_t tick;
+
+	tick = rt_tick_from_millisecond(microseconds/1000);
+	if (tick == 0) tick = 1;
+
+	rt_thread_delay(tick);
+#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. In the case NULL
+ * values are provided, they will be uninstalled.
+ */
+void        nopoll_thread_handlers (noPollMutexCreate  mutex_create,
+				    noPollMutexDestroy mutex_destroy,
+				    noPollMutexLock    mutex_lock,
+				    noPollMutexUnlock  mutex_unlock)
+{
+	/* 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)
+{
+#if NOPOLL_TLS
+	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;
+#else
+#if NOPOLL_OS_RTTHREAD
+	return nopoll_rtt_base64_encode(content, length, output, output_size);
+#else
+	return nopoll_true;
+#endif
+#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)
+{
+#if NOPOLL_TLS
+	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;
+#else
+#if NOPOLL_OS_RTTHREAD
+	return nopoll_rtt_base64_decode(content, length, output, output_size);
+#else
+	return nopoll_true;
+#endif
+#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 ();
+#elif defined(NOPOLL_OS_RTTHREAD)
+		random_value = nopoll_rtt_random();
+#else
+		random_value = 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
+	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 */
+#endif
+	
+	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://www.aspl.es/nopoll/downloads
+ *
+ * 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
+ *
+ * <b>Notes about preparing sources if you use SVN/GIT from https://github.com/asples/nopoll</b>
+ *
+ * In the case you want to work directly using SVN latest sources,
+ * just download them from githubt as usual from: https://github.com/asples/nopoll
+ *
+ * After that, run the following command to prepare all compilation files:
+ *
+ * \code
+ * >> ./autogen.sh
+ * \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/&lt;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/&lt;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 Nº 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
+ * 
+ *
+ */

+ 139 - 0
nopoll/nopoll.h

@@ -0,0 +1,139 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_H__
+#define __NOPOLL_H__
+
+#include <nopoll_decl.h>
+#include <nopoll_handlers.h>
+
+BEGIN_C_DECLS
+
+#if defined(NOPOLL_OS_WIN32)
+#include <nopoll_win32.h>
+#endif
+
+#if defined(NOPOLL_OS_RTTHREAD)
+#include "nopoll_rtthread.h"
+#endif
+
+#include <nopoll_ctx.h>
+#include <nopoll_io.h>
+#include <nopoll_conn_opts.h>
+#include <nopoll_conn.h>
+#include <nopoll_msg.h>
+#include <nopoll_log.h>
+#include <nopoll_listener.h>
+#include <nopoll_io.h>
+#include <nopoll_loop.h>
+
+/** 
+ * \addtogroup nopoll_module
+ * @{
+ */
+
+nopoll_bool nopoll_cmp (const char * string1, const char * string2);
+
+nopoll_bool nopoll_ncmp (const char * string1, const char * string2, int bytes);
+
+char      * nopoll_strdup_printf   (const char * chunk, ...);
+
+char      * nopoll_strdup_printfv  (const char * chunk, va_list args);
+
+void        nopoll_trim  (char * chunk, int * trimmed);
+
+void        nopoll_sleep (long microseconds);
+
+void        nopoll_thread_handlers (noPollMutexCreate  mutex_create,
+				    noPollMutexDestroy mutex_destroy,
+				    noPollMutexLock    mutex_lock,
+				    noPollMutexUnlock  mutex_unlock);
+
+noPollPtr   nopoll_mutex_create (void);
+
+void        nopoll_mutex_lock    (noPollPtr mutex);
+
+void        nopoll_mutex_unlock  (noPollPtr mutex);
+
+void        nopoll_mutex_destroy (noPollPtr mutex);
+
+nopoll_bool nopoll_base64_encode (const char * content, 
+				  int          length, 
+				  char       * output, 
+				  int        * output_size);
+
+nopoll_bool nopoll_base64_decode (const char * content, 
+				  int          length, 
+				  char       * output, 
+				  int        * output_size);
+
+int         nopoll_timeval_substract  (struct timeval * a, 
+				       struct timeval * b,
+				       struct timeval * result);
+
+char      * nopoll_strdup (const char * buffer);
+
+nopoll_bool nopoll_nonce (char * buffer, int nonce_size);
+
+void        nopoll_cleanup_library (void);
+
+int    nopoll_get_bit (char byte, int position);
+
+void   nopoll_set_bit     (char * buffer, int position);
+
+void   nopoll_show_byte (noPollCtx * ctx, char byte, const char * label);
+
+char * nopoll_int2bin (int a, char *buffer, int buf_size);
+
+void   nopoll_int2bin_print (noPollCtx * ctx, int value);
+
+int    nopoll_get_8bit  (const char * buffer);
+
+int    nopoll_get_16bit (const char * buffer);
+
+void   nopoll_set_16bit (int value, char * buffer);
+
+void   nopoll_set_32bit (int value, char * buffer);
+
+int    nopoll_get_32bit (const char * buffer);
+
+/* @} */
+
+END_C_DECLS
+
+#endif

+ 97 - 0
nopoll/nopoll_config.h

@@ -0,0 +1,97 @@
+/*
+ * Nopoll Library nopoll_config.h
+ * Platform dependant definitions.
+ *
+ * This is a generated file.  Please modify 'configure.in'
+ */
+
+#ifndef __NOPOLL_CONFIG_H__
+#define __NOPOLL_CONFIG_H__
+
+/**
+ * \addtogroup nopoll_decl_module
+ * @{
+ */
+
+/**
+ * @brief Allows to convert integer value (including constant values)
+ * into a pointer representation.
+ *
+ * Use the oposite function to restore the value from a pointer to a
+ * integer: \ref PTR_TO_INT.
+ *
+ * @param integer The integer value to cast to pointer.
+ *
+ * @return A \ref noPollPtr reference.
+ */
+#ifndef INT_TO_PTR
+#define INT_TO_PTR(integer) ((noPollPtr) (integer))
+#endif
+
+/**
+ * @brief Allows to convert a pointer reference (\ref noPollPtr),
+ * which stores an integer that was stored using \ref INT_TO_PTR.
+ *
+ * Use the oposite function to restore the pointer value stored in the
+ * integer value.
+ *
+ * @param ptr The pointer to cast to a integer value.
+ *
+ * @return A int value.
+ */
+#ifndef PTR_TO_INT
+#define PTR_TO_INT(ptr) ((int) (ptr))
+#endif
+
+/**
+ * @brief Allows to get current platform configuration. This is used
+ * by Nopoll library but could be used by applications built on top of
+ * Nopoll to change its configuration based on the platform information.
+ */
+// #define NOPOLL_OS_UNIX (1)
+#define NOPOLL_OS_RTTHREAD  (1)
+
+/**
+ * @internal Allows to now if the platform support vasprintf
+ * function. Do not use this macro as it is supposed to be for
+ * internal use.
+ */
+// #define NOPOLL_HAVE_VASPRINTF (0)
+
+/**
+ * @brief Indicates that this platform have support for 64bits.
+ */
+// #define NOPOLL_64BIT_PLATFORM (0)
+
+#define NOPLL_TLS             (0)
+#define NOPLL_IPV6            (0)
+
+/**
+ * @brief Indicates where we have support for SSL v.3 support.
+ */
+#define NOPOLL_HAVE_SSLv23_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for SSL v3.0 support. The SSLv3 protocol is deprecated and should not be used.
+ */
+#define NOPOLL_HAVE_SSLv3_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.0 support.
+ */
+#define NOPOLL_HAVE_TLSv10_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.1 support.
+ */
+#define NOPOLL_HAVE_TLSv11_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.2 support.
+ */
+#define NOPOLL_HAVE_TLSv12_ENABLED (1)
+
+
+/* @} */
+
+#endif

+ 92 - 0
nopoll/nopoll_config_win32.h

@@ -0,0 +1,92 @@
+/*
+ * noPoll Library nopoll_config.h
+ * Platform dependant definitions for Win32 platform.
+ *
+ * This file is maintained manually for those people that do not
+ * compile nopoll using autoconf. It should look really similar to
+ * nopoll_config.h file created on a i386 linux platform but changing
+ * NOPOLL_OS_UNIX to NOPOLL_OS_WIN32 (at least for now).
+ *
+ *  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
+ *
+ */
+
+#ifndef __NOPOLL_CONFIG_H__
+#define __NOPOLL_CONFIG_H__
+
+/**
+ * \addtogroup nopoll_decl_module
+ * @{
+ */
+
+/**
+ * @brief Allows to convert integer value (including constant values)
+ * into a pointer representation.
+ *
+ * Use the oposite function to restore the value from a pointer to a
+ * integer: \ref PTR_TO_INT.
+ *
+ * @param integer The integer value to cast to pointer.
+ *
+ * @return A \ref noPollPtr reference.
+ */
+#ifndef INT_TO_PTR
+#define INT_TO_PTR(integer) ((noPollPtr) (integer))
+#endif
+
+/**
+ * @brief Allows to convert a pointer reference (\ref noPollPtr),
+ * which stores an integer that was stored using \ref INT_TO_PTR.
+ *
+ * Use the oposite function to restore the pointer value stored in the
+ * integer value.
+ *
+ * @param ptr The pointer to cast to a integer value.
+ *
+ * @return A int value.
+ */
+#ifndef PTR_TO_INT
+#define PTR_TO_INT(ptr) ((int) (ptr))
+#endif
+
+/**
+ * @brief Allows to get current platform configuration. This is used
+ * by Nopoll library but could be used by applications built on top of
+ * Nopoll to change its configuration based on the platform information.
+ *
+ * Note when this flag is enabled (set to 1), it means we are
+ * compiling in a windows platform (no matter if it is 64 or 32
+ * bits). To check for 64bit see NOPOLL_OS_WIN64.
+ */
+#define NOPOLL_OS_WIN32 (1)
+
+
+/**
+ * @brief Indicates where we have support for TLSv1.0 support.
+ */
+#define NOPOLL_HAVE_TLSv10_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.1 support.
+ */
+#define NOPOLL_HAVE_TLSv11_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.2 support.
+ */
+#define NOPOLL_HAVE_TLSv12_ENABLED (1)
+
+
+/* @} */
+
+#endif

+ 99 - 0
nopoll/nopoll_config_win64.h

@@ -0,0 +1,99 @@
+/*
+ * noPoll Library nopoll_config.h
+ * Platform dependant definitions for Win32 platform.
+ *
+ * This file is maintained manually for those people that do not
+ * compile nopoll using autoconf. It should look really similar to
+ * nopoll_config.h file created on a i386 linux platform but changing
+ * NOPOLL_OS_UNIX to NOPOLL_OS_WIN32 (at least for now).
+ *
+ *  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
+ *
+ */
+
+#ifndef __NOPOLL_CONFIG_H__
+#define __NOPOLL_CONFIG_H__
+
+#include <basetsd.h>
+
+/**
+ * \addtogroup nopoll_decl_module
+ * @{
+ */
+
+/**
+ * @brief Allows to convert integer value (including constant values)
+ * into a pointer representation.
+ *
+ * Use the oposite function to restore the value from a pointer to a
+ * integer: \ref PTR_TO_INT.
+ *
+ * @param integer The integer value to cast to pointer.
+ *
+ * @return A \ref noPollPtr reference.
+ */
+#ifndef INT_TO_PTR
+#define INT_TO_PTR(integer) IntToPtr(integer)
+#endif
+
+/**
+ * @brief Allows to convert a pointer reference (\ref noPollPtr),
+ * which stores an integer that was stored using \ref INT_TO_PTR.
+ *
+ * Use the oposite function to restore the pointer value stored in the
+ * integer value.
+ *
+ * @param ptr The pointer to cast to a integer value.
+ *
+ * @return A int value.
+ */
+#ifndef PTR_TO_INT
+#define PTR_TO_INT(ptr) PtrToInt((const void *) (ptr))
+#endif
+
+/**
+ * @brief Allows to get current platform configuration. This is used
+ * by Nopoll library but could be used by applications built on top of
+ * Nopoll to change its configuration based on the platform information.
+ *
+ * Note when this flag is enabled (set to 1), it means we are
+ * compiling in a windows platform (no matter if it is 64 or 32
+ * bits). To check for 64bit see NOPOLL_OS_WIN64.
+ */
+#define NOPOLL_OS_WIN32 (1)
+
+/**
+ * @brief If defined to1, it means we are compiling in a windows
+ platform running 64 bit version.
+ */
+#define NOPOLL_OS_WIN64 (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.0 support.
+ */
+#define NOPOLL_HAVE_TLSv10_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.1 support.
+ */
+#define NOPOLL_HAVE_TLSv11_ENABLED (1)
+
+/**
+ * @brief Indicates where we have support for TLSv1.2 support.
+ */
+#define NOPOLL_HAVE_TLSv12_ENABLED (1)
+
+
+/* @} */
+
+#endif

+ 4884 - 0
nopoll/nopoll_conn.c

@@ -0,0 +1,4884 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+
+/** 
+ * \defgroup nopoll_conn noPoll Connection: functions required to create WebSocket client connections.
+ */
+
+/** 
+ * \addtogroup nopoll_conn
+ * @{
+ */
+
+#include <nopoll_conn.h>
+#include <nopoll_private.h>
+
+#if defined(NOPOLL_OS_UNIX)
+# include <netinet/tcp.h>
+#endif
+
+
+/** 
+ * @brief Allows to enable/disable non-blocking/blocking behavior on
+ * the provided socket.
+ * 
+ * @param socket The socket to be configured.
+ *
+ * @param enable nopoll_true to enable blocking I/O, otherwise use
+ * nopoll_false to enable non blocking I/O.
+ * 
+ * @return nopoll_true if the operation was properly done, otherwise
+ * nopoll_false is returned.
+ */
+nopoll_bool                 nopoll_conn_set_sock_block         (NOPOLL_SOCKET socket,
+								nopoll_bool   enable)
+{
+#if defined(NOPOLL_OS_UNIX) || defined(NOPOLL_OS_RTTHREAD)
+	int flags = 0;
+#endif
+
+	if (enable) {
+		/* enable blocking mode */
+#if defined(NOPOLL_OS_WIN32)
+		if (!nopoll_win32_blocking_enable (socket)) {
+			return nopoll_false;
+		}
+#elif defined(NOPOLL_OS_RTTHREAD)
+		if ((flags = lwip_fcntl (socket, F_GETFL, 0)) < -1) {
+			return nopoll_false;
+		} /* end if */
+
+		flags &= ~O_NONBLOCK;
+		if (lwip_fcntl (socket, F_SETFL, flags) < -1) {
+			return nopoll_false;
+		} /* end if */
+#else
+		if ((flags = fcntl (socket, F_GETFL, 0)) < -1) {
+			return nopoll_false;
+		} /* end if */
+
+		flags &= ~O_NONBLOCK;
+		if (fcntl (socket, F_SETFL, flags) < -1) {
+			return nopoll_false;
+		} /* end if */
+#endif
+	} else {
+		/* enable nonblocking mode */
+#if defined(NOPOLL_OS_WIN32)
+		/* win32 case */
+		if (!nopoll_win32_nonblocking_enable (socket)) {
+			return nopoll_false;
+		}
+#elif defined(NOPOLL_OS_RTTHREAD)
+		if ((flags = lwip_fcntl (socket, F_GETFL, 0)) < -1) {
+			return nopoll_false;
+		}
+		
+		flags |= O_NONBLOCK;
+		if (lwip_fcntl (socket, F_SETFL, flags) < -1) {
+			return nopoll_false;
+		}
+#else
+		/* unix case */
+		if ((flags = fcntl (socket, F_GETFL, 0)) < -1) {
+			return nopoll_false;
+		}
+		
+		flags |= O_NONBLOCK;
+		if (fcntl (socket, F_SETFL, flags) < -1) {
+			return nopoll_false;
+		}
+#endif
+	} /* end if */
+
+	return nopoll_true;
+}
+
+
+/** 
+ * @brief Allows to get current timeout set for \ref noPollConn
+ * connect operation.
+ *
+ * See also \ref nopoll_conn_connect_timeout.
+ *
+ * @return Current timeout configured. Returned value is measured in
+ * microseconds (1 second = 1000000 microseconds). If a null value is
+ * received, 0 is return and no timeout is implemented.
+ */
+long              nopoll_conn_get_connect_timeout (noPollCtx * ctx)
+{
+	/* check context recevied */
+	if (ctx == NULL) {
+		/* get the the default connect */
+		return (0);
+	} /* end if */
+		
+	/* return current value */
+	return ctx->conn_connect_std_timeout;
+}
+
+/** 
+ * @brief Allows to configure nopoll connect timeout.
+ * 
+ * This function allows to set the TCP connect timeout used by \ref
+ * nopoll_conn_new.
+ *
+ * @param ctx The context where the operation will be performed.
+ *
+ * @param microseconds_to_wait Timeout value to be used. The value
+ * provided is measured in microseconds. Use 0 to restore the connect
+ * timeout to the default value.
+ */
+void               nopoll_conn_connect_timeout (noPollCtx * ctx,
+						long        microseconds_to_wait)
+{
+	/* check reference received */
+	if (ctx == NULL)
+		return;
+	
+	/* configure new value */
+	ctx->conn_connect_std_timeout = microseconds_to_wait;
+
+	return;
+}
+
+
+/** 
+ * @brief Allows to configure tcp no delay flag (enable/disable Nagle
+ * algorithm).
+ * 
+ * @param socket The socket to be configured.
+ *
+ * @param enable The value to be configured, nopoll_true to enable tcp no
+ * delay.
+ * 
+ * @return nopoll_true if the operation is completed.
+ */
+nopoll_bool                 nopoll_conn_set_sock_tcp_nodelay   (NOPOLL_SOCKET socket,
+								nopoll_bool      enable)
+{
+	/* local variables */
+	int result;
+
+#if defined(NOPOLL_OS_WIN32)
+	BOOL   flag = enable ? TRUE : FALSE;
+	result      = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char  *)&flag, sizeof(BOOL));
+#else
+	int    flag = enable;
+	result      = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag));
+#endif
+	if (result == NOPOLL_INVALID_SOCKET) {
+		return nopoll_false;
+	}
+
+	/* properly configured */
+	return nopoll_true;
+} /* end */
+
+
+/** 
+ * @brief Allows to configure which network interface to bind to.
+ * 
+ * @param socket The socket to be configured.
+ *
+ * @param options The options defining the interface value to be configured.
+ * 
+ * @return nopoll_true if the operation is completed.
+ */
+nopoll_bool                 nopoll_conn_set_bind_interface (NOPOLL_SOCKET socket,
+							    noPollConnOpts  * options)
+{
+	/* no local variable here please */
+
+	if ((NULL != options) && (NULL != options->_interface)) {
+#if defined(NOPOLL_OS_WIN32) || defined(NOPOLL_OS_WIN64)
+		/* Windows still not supported: send us a patch! */ 
+		return nopoll_false;
+#elif defined(NOPOLL_OS_RTTHREAD)
+		return nopoll_false;
+#elif defined(__APPLE__)
+		/* Mac/OSX: that supports  */
+		/* bind to the interface */
+		return setsockopt (socket, SOL_SOCKET, IP_RECVIF,
+				   options->_interface, strlen(options->_interface) ) == 0;
+#else
+		/* Linux/Unix case: that supports SO_BINDTODEVICE */
+		/* bind to the interface */
+		return setsockopt (socket, SOL_SOCKET, SO_BINDTODEVICE,
+				   options->_interface, strlen (options->_interface) ) == 0;
+#endif
+	}
+
+	/* properly configured */
+	return nopoll_true;
+} /* end */
+
+NOPOLL_SOCKET __nopoll_conn_sock_connect_opts_internal (noPollCtx       * ctx,
+							noPollTransport   transport,
+							const char      * host,
+							const char      * port,
+							noPollConnOpts  * options)
+{
+	struct hostent     * hostent;
+	struct sockaddr_in   saddr;
+	NOPOLL_SOCKET        session     = NOPOLL_INVALID_SOCKET;
+
+	switch (transport) {
+	case NOPOLL_TRANSPORT_IPV4:
+    	/* resolve hosting name */
+    	hostent = gethostbyname (host);
+    	if (hostent == NULL) {
+    		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "unable to resolve host name %s", host);
+    		return -1;
+    	} /* end if */
+
+		/* create the socket and check if it */
+		session      = socket (AF_INET, SOCK_STREAM, 0);
+		break;
+#if NOPLL_IPV6
+	case NOPOLL_TRANSPORT_IPV6:
+		/* configure hints */
+		hints.ai_family   = AF_INET6;
+		hints.ai_socktype = SOCK_STREAM;
+		
+		/* resolve hosting name */
+		if (getaddrinfo (host, port, &hints, &res) != 0) {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "unable to resolve host name %s, errno=%d", host, errno);
+			return -1;
+		} /* end if */
+
+		/* create the socket and check if it */
+		session      = socket (AF_INET6, SOCK_STREAM, 0);
+		break;
+#endif        
+	} /* end switch */
+	
+	if (session == NOPOLL_INVALID_SOCKET) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to create socket");
+		return -1;
+	} /* end if */
+
+	/* disable nagle */
+	nopoll_conn_set_sock_tcp_nodelay (session, nopoll_true);
+
+	/* bind to specified interface */
+	if( nopoll_true != nopoll_conn_set_bind_interface (session, options) ) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to bind to specified interface");
+		nopoll_close_socket (session);
+		return -1;
+	} /* end if */
+
+	/* prepare socket configuration to operate using TCP/IP
+	 * socket */
+    memset(&saddr, 0, sizeof(saddr));
+    saddr.sin_addr.s_addr = ((struct in_addr *)(hostent->h_addr))->s_addr;
+    saddr.sin_family    = AF_INET;
+    saddr.sin_port      = htons((uint16_t) strtod (port, NULL));
+
+	/* set non blocking status */
+	nopoll_conn_set_sock_block (session, nopoll_false);
+	
+	/* do a tcp connect */
+        if (connect (session, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+		if(errno != NOPOLL_EINPROGRESS && errno != NOPOLL_EWOULDBLOCK && errno != NOPOLL_ENOTCONN) { 
+		        shutdown (session, SHUT_RDWR);
+                        nopoll_close_socket (session);
+
+			nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to connect to remote host %s:%s errno=%d",
+				    host, port, errno);
+			return -1;
+		} /* end if */
+	} /* end if */
+
+	/* return socket created */
+	return session;
+}
+
+/** 
+ * @internal Allows to create a plain socket connection against the
+ * host and port provided.
+ *
+ * @param ctx The context where the connection happens.
+ *
+ * @param host The host server to connect to.
+ *
+ * @param port The port server to connect to.
+ *
+ * @param options The connection options to apply.
+ *
+ * @return A connected socket or -1 if it fails. 
+ */
+NOPOLL_SOCKET nopoll_conn_sock_connect_opts (noPollCtx       * ctx,
+					     const char      * host,
+					     const char      * port,
+					     noPollConnOpts  * options)
+{
+
+	return __nopoll_conn_sock_connect_opts_internal (ctx, NOPOLL_TRANSPORT_IPV4, host, port, options);
+}
+
+
+/** 
+ * @internal Allows to create a plain socket connection against the
+ * host and port provided.
+ *
+ * @param ctx The context where the connection happens.
+ *
+ * @param host The host server to connect to.
+ *
+ * @param port The port server to connect to.
+ *
+ * @return A connected socket or -1 if it fails. 
+ */
+NOPOLL_SOCKET nopoll_conn_sock_connect (noPollCtx       * ctx,
+					const char      * host,
+					const char      * port)
+{
+	return nopoll_conn_sock_connect_opts (ctx, host, port, NULL);
+}
+
+
+/** 
+ * @internal Function that builds the client init greetings that will
+ * be send to the server according to registered implementation.
+ */ 
+char * __nopoll_conn_get_client_init (noPollConn * conn, noPollConnOpts * opts)
+{
+	/* build sec-websocket-key */
+	char key[50];
+	int  key_size = 50;
+	char nonce[17];
+
+	/* get the nonce */
+	if (! nopoll_nonce (nonce, 16)) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to get nonce, unable to produce Sec-WebSocket-Key.");
+		return NULL;
+	} /* end if */
+
+	/* now base 64 */
+	if (! nopoll_base64_encode (nonce, 16, key, &key_size)) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to base 64 encode characters for Sec-WebSocket-Key");
+		return NULL;
+	}
+	
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Created Sec-WebSocket-Key nonce: %s", key);
+
+	/* create accept and store */
+	conn->handshake = nopoll_new (noPollHandShake, 1);
+	conn->handshake->expected_accept = nopoll_strdup (key);
+
+	/* send initial handshake */
+	return nopoll_strdup_printf ("GET %s HTTP/1.1"
+				     "\r\nHost: %s"
+				     "\r\nUpgrade: websocket"
+				     "\r\nConnection: Upgrade"
+				     "\r\nSec-WebSocket-Key: %s"
+				     "\r\nSec-WebSocket-Version: %d"
+				     "\r\nOrigin: %s"
+				     "%s%s"  /* Cookie */
+				     "%s%s"  /* protocol part */
+				     "%s"    /* extra arbitrary headers */
+				     "\r\n\r\n",
+				     conn->get_url,
+				     conn->host_name,
+				     /* sec-websocket-key */
+				     key,
+				     /* sec-websocket-version */
+				     conn->ctx->protocol_version,
+				     /* Origin */
+				     conn->origin,
+				     /* Cookie */
+				     (opts && opts->cookie) ? "\r\nCookie: " : "",
+				     (opts && opts->cookie) ? opts->cookie : "",
+				     /* protocol part */
+				     conn->protocols ? "\r\nSec-WebSocket-Protocol: " : "",
+				     conn->protocols ? conn->protocols : "",
+				     /* extra arbitrary headers */
+				     (opts && opts->extra_headers) ? opts->extra_headers : "");
+}
+
+#if NOPOLL_TLS
+/**
+ * @internal Function that dumps all errors found on current ssl context.
+ */
+int nopoll_conn_log_ssl (noPollConn * conn)
+{
+#if defined(SHOW_DEBUG_LOG)
+        noPollCtx      * ctx = conn->ctx;
+#endif
+	char             log_buffer [512];
+	unsigned long    err;
+	int              error_position;
+	int              aux_position;
+	
+	while ((err = ERR_get_error()) != 0) {
+		ERR_error_string_n (err, log_buffer, sizeof (log_buffer));
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "tls stack: %s (find reason(code) at openssl/ssl.h)", log_buffer); 
+
+		/* find error code position */
+		error_position = 0;
+		while (log_buffer[error_position] != ':' && log_buffer[error_position] != 0 && error_position < 511)
+			error_position++;
+		error_position++;
+		aux_position = error_position;
+		while (log_buffer[aux_position] != 0) {
+			if (log_buffer[aux_position] == ':') {
+				log_buffer[aux_position] = 0;
+				break;
+			}
+			aux_position++;
+		} /* end while */
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "    details, run: openssl errstr %s", log_buffer + error_position);
+	}
+
+	recv (conn->session, log_buffer, 1, MSG_PEEK);
+	nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "    noPoll id=%d, socket: %d (after testing errno: %d)",
+		    conn->id, conn->session, errno);
+	
+	
+	return (0);
+}
+
+int __nopoll_conn_tls_handle_error (noPollConn * conn, int res, const char * label, nopoll_bool * needs_retry)
+{
+	int ssl_err;
+
+	(*needs_retry) = nopoll_false;
+
+	/* get error returned */
+	ssl_err = SSL_get_error (conn->ssl, res);
+	switch (ssl_err) {
+	case SSL_ERROR_NONE:
+		/* no error, return the number of bytes read */
+	        /* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s, ssl_err=%d, perfect, no error reported, bytes read=%d", 
+		   label, ssl_err, res); */
+		return res;
+	case SSL_ERROR_WANT_WRITE:
+	case SSL_ERROR_WANT_READ:
+	case SSL_ERROR_WANT_X509_LOOKUP:
+	        nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s, ssl_err=%d returned that isn't ready to read/write: you should retry", 
+			    label, ssl_err);
+		(*needs_retry) = nopoll_true;
+		return -2;
+	case SSL_ERROR_SYSCALL:
+		if(res < 0) { /* not EOF */
+			if(errno == NOPOLL_EINTR) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "%s interrupted by a signal: retrying", label);
+				/* report to retry */
+				return -2;
+			}
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "SSL_read (SSL_ERROR_SYSCALL)");
+			return -1;
+		}
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "SSL socket closed on %s (res=%d, ssl_err=%d, errno=%d)",
+			    label, res, ssl_err, errno);
+		nopoll_conn_log_ssl (conn);
+
+		return res;
+	case SSL_ERROR_ZERO_RETURN: /* close_notify received */
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL closed on %s", label);
+		return res;
+	case SSL_ERROR_SSL:
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "%s function error (received SSL_ERROR_SSL) (res=%d, ssl_err=%d, errno=%d)",
+			    label, res, ssl_err, errno);
+		nopoll_conn_log_ssl (conn);
+		return -1;
+	default:
+		/* nothing to handle */
+		break;
+	}
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "%s/SSL_get_error returned %d", label, res);
+	return -1;
+	
+}
+
+/** 
+ * @internal Default connection receive until handshake is complete.
+ */
+int nopoll_conn_tls_receive (noPollConn * conn, char * buffer, int buffer_size)
+{
+	int res;
+	nopoll_bool needs_retry;
+	int         tries = 0;
+
+	/* call to read content */
+	while (tries < 50) {
+	        res = SSL_read (conn->ssl, buffer, buffer_size);
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL: received %d bytes..", res); */
+
+		/* call to handle error */
+		res = __nopoll_conn_tls_handle_error (conn, res, "SSL_read", &needs_retry);
+		
+		if (! needs_retry)
+		        break;
+
+		/* next operation */
+		tries++;
+	}
+	/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "  SSL: after procesing error %d bytes..", res); */
+	return res;
+}
+
+/** 
+ * @internal Default connection send until handshake is complete.
+ */
+int nopoll_conn_tls_send (noPollConn * conn, char * buffer, int buffer_size)
+{
+	int         res;
+	nopoll_bool needs_retry;
+	int         tries = 0;
+
+	/* call to read content */
+	while (tries < 50) {
+	        res = SSL_write (conn->ssl, buffer, buffer_size);
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "SSL: sent %d bytes (requested: %d)..", res, buffer_size); 
+
+		/* call to handle error */
+		res = __nopoll_conn_tls_handle_error (conn, res, "SSL_write", &needs_retry);
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "   SSL: after processing error, sent %d bytes (requested: %d)..",  res, buffer_size); */
+
+		if (! needs_retry)
+		        break;
+
+		/* next operation */
+		nopoll_sleep (tries * 10000);
+		tries++;
+	}
+	return res;
+}
+
+
+SSL_CTX * __nopoll_conn_get_ssl_context (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client)
+{
+	/* call to user defined function if the context creator is defined */
+	if (ctx && ctx->context_creator) 
+		return ctx->context_creator (ctx, conn, opts, is_client, ctx->context_creator_data);
+
+	if (opts == NULL) {
+		/* select a default mechanism according to what's
+		 * available, starting from the most common accepted
+		 * solution, which is TLSv1.0 */
+#if defined(NOPOLL_HAVE_TLSv10_ENABLED)
+		/* by default use TLSv1.0 */
+		return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ());
+#elif defined(NOPOLL_HAVE_TLSv11_ENABLED)
+		/* if not use TLSv1.1 */
+		return SSL_CTX_new (is_client ? TLSv1_1_client_method () : TLSv1_1_server_method ());
+#elif defined(NOPOLL_HAVE_TLSv12_ENABLED)
+		/* if not use TLSv1.2 */
+		return SSL_CTX_new (is_client ? TLSv1_2_client_method () : TLSv1_2_server_method ());
+#elif defined(NOPOLL_HAVE_SSLv23_ENABLED)
+		/* if not use SSLv23 */
+		return SSL_CTX_new (is_client ? SSLv23_client_method () : SSLv23_server_method ()); 
+#elif defined(NOPOLL_HAVE_SSLv3_ENABLED)
+		/* if not use SSLv3 */
+		return SSL_CTX_new (is_client ? SSLv3_client_method () : SSLv3_server_method ()); 
+#else
+		/* no default method found */
+		return NULL;
+#endif
+		
+	} /* end if */
+
+	switch (opts->ssl_protocol) {
+
+#if defined(NOPOLL_HAVE_TLS_FLEXIBLE_ENABLED)
+	case NOPOLL_METHOD_TLS_FLEXIBLE:
+		return SSL_CTX_new (is_client ? TLS_client_method () : TLS_server_method ());
+#endif		
+		
+#if defined(NOPOLL_HAVE_TLSv10_ENABLED)
+	case NOPOLL_METHOD_TLSV1:
+		return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ());
+#endif
+		
+#if defined(NOPOLL_HAVE_TLSv11_ENABLED)
+	case NOPOLL_METHOD_TLSV1_1:
+		return SSL_CTX_new (is_client ? TLSv1_1_client_method () : TLSv1_1_server_method ()); 
+#endif
+		
+#if defined(NOPOLL_HAVE_TLSv12_ENABLED)
+	case NOPOLL_METHOD_TLSV1_2:
+		return SSL_CTX_new (is_client ? TLSv1_2_client_method () : TLSv1_2_server_method ()); 
+#endif
+		
+#if defined(NOPOLL_HAVE_SSLv3_ENABLED)
+	case NOPOLL_METHOD_SSLV3:
+		/* printf ("**** REPORTING SSLv3 ****\n"); */
+		return SSL_CTX_new (is_client ? SSLv3_client_method () : SSLv3_server_method ()); 
+#endif
+#if defined(NOPOLL_HAVE_SSLv23_ENABLED)
+	case NOPOLL_METHOD_SSLV23:
+		/* printf ("**** REPORTING SSLv23 ****\n"); */
+		return SSL_CTX_new (is_client ? SSLv23_client_method () : SSLv23_server_method ());
+#endif		
+	}
+
+#if defined(NOPOLL_HAVE_TLSv10_ENABLED)
+	/* reached this point, report default TLSv1 method */
+	return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ());
+#else
+	return NULL;
+#endif
+}
+
+noPollCtx * __nopoll_conn_ssl_ctx_debug = NULL;
+
+int __nopoll_conn_ssl_verify_callback (int ok, X509_STORE_CTX * store) {
+	char   data[256];
+	X509 * cert;
+#if defined(SHOW_DEBUG_LOG)
+	int    depth;
+	int    err;
+#endif
+
+	if (! ok) {
+		cert  = X509_STORE_CTX_get_current_cert (store);
+#if defined(SHOW_DEBUG_LOG)
+		depth = X509_STORE_CTX_get_error_depth (store);
+		err   = X509_STORE_CTX_get_error (store);
+#endif
+
+		nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: error=%d at depth: %d", err, depth);
+
+		X509_NAME_oneline (X509_get_issuer_name (cert), data, 256);
+		nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: issuer: %s", data);
+
+		X509_NAME_oneline (X509_get_subject_name (cert), data, 256);
+		nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: subject: %s", data);
+
+		nopoll_log (__nopoll_conn_ssl_ctx_debug, NOPOLL_LEVEL_CRITICAL, "CERTIFICATE: error %d:%s", err, X509_verify_cert_error_string (err));
+			    
+	}
+	return ok; /* return same value */
+}
+
+nopoll_bool __nopoll_conn_set_ssl_client_options (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * options)
+{
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking to establish SSL options (%p)", options);
+
+	if (options && options->ca_certificate) {
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting CA certificate: %s", options->ca_certificate);
+		if (SSL_CTX_load_verify_locations (conn->ssl_ctx, options->ca_certificate, NULL) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure CA certificate (%s), SSL_CTX_load_verify_locations () failed", options->ca_certificate);
+			return nopoll_false;
+		} /* end if */
+		
+	} /* end if */
+
+	/* enable default verification paths */
+	/* printf ("conn = %p, conn->ssl_ctx = %p\n", conn, conn->ssl_ctx); */
+	if (SSL_CTX_set_default_verify_paths (conn->ssl_ctx) != 1) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure default verification paths, SSL_CTX_set_default_verify_paths () failed");
+		return nopoll_false;
+	} /* end if */
+
+	if (options && options->chain_certificate) {
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting chain certificate: %s", options->chain_certificate);
+		if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, options->chain_certificate) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure chain certificate (%s), SSL_CTX_use_certificate_chain_file () failed", options->chain_certificate);
+			return nopoll_false;
+		} /* end if */
+	} /* end if */
+
+	if (options && options->certificate) {
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting certificate: %s", options->certificate);
+		if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, options->certificate) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure client certificate (%s), SSL_CTX_use_certificate_file () failed", options->certificate);
+			return nopoll_false;
+		} /* end if */
+	} /* end if */
+
+	if (options && options->private_key) {
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting private key: %s", options->private_key);
+		if (SSL_CTX_use_PrivateKey_file (conn->ssl_ctx, options->private_key, SSL_FILETYPE_PEM) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure private key (%s), SSL_CTX_use_PrivateKey_file () failed", options->private_key);
+			return nopoll_false;
+		} /* end if */
+	} /* end if */
+
+	if (options && options->private_key && options->certificate) {
+		if (!SSL_CTX_check_private_key (conn->ssl_ctx)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Certificate and private key do not matches, verification fails, SSL_CTX_check_private_key ()");
+			return nopoll_false;
+		} /* end if */
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Certificate (%s) and private key (%s) matches", options->certificate, options->private_key);
+	} /* end if */
+
+	/* if no option and it is not disabled */
+	if (options == NULL || ! options->disable_ssl_verify) {
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Enabling certificate peer verification");
+		/** really, really ugly hack to let
+		 * __nopoll_conn_ssl_verify_callback to be able to get
+		 * access to the context required to drop some logs */
+		__nopoll_conn_ssl_ctx_debug = ctx;
+		SSL_CTX_set_verify (conn->ssl_ctx, SSL_VERIFY_PEER, __nopoll_conn_ssl_verify_callback); 
+		SSL_CTX_set_verify_depth (conn->ssl_ctx, 10); 
+	} /* end if */
+
+	return nopoll_true;
+}
+#endif
+
+/** 
+ * @internal Internal implementation used to do a connect.
+ */
+noPollConn * __nopoll_conn_new_common (noPollCtx       * ctx,
+				       noPollConnOpts  * options,
+				       noPollTransport   transport,
+				       nopoll_bool       enable_tls,
+				       int               socket,
+				       const char      * host_ip, 
+				       const char      * host_port, 
+				       const char      * host_name,
+				       const char      * get_url, 
+				       const char      * protocols,
+				       const char      * origin)
+{
+	noPollConn     * conn;
+	NOPOLL_SOCKET    session;
+	char           * content;
+	int              size;
+#if NOPOLL_TLS
+	int              ssl_error;
+	X509           * server_cert;
+#endif
+	int              iterator;
+	long             remaining_timeout;
+
+	if (! ctx || ! host_ip) {
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+		return NULL;
+	} /* end if */
+
+	/* set default connection port */
+	if (host_port == NULL)
+		host_port = "80";
+
+	session = socket;
+	/* create socket connection in a non block manner */
+	if (session == NOPOLL_INVALID_SOCKET)
+		session = __nopoll_conn_sock_connect_opts_internal (ctx, transport, host_ip, host_port, options);
+	if (session == NOPOLL_INVALID_SOCKET) {
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to connect to remote host %s:%s", host_ip, host_port);
+		return NULL;
+	} /* end if */
+
+	/* create the connection */
+	conn = nopoll_new (noPollConn, 1);
+	if (conn == NULL) {
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+		return NULL;
+	} /* end if */
+
+	conn->refs = 1;
+
+	/* create mutex */
+	conn->ref_mutex = nopoll_mutex_create ();
+
+	/* register connection into context */
+	if (! nopoll_ctx_register_conn (ctx, conn)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to register connection into the context, unable to create connection");
+		nopoll_free (conn);
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+
+		return NULL;
+	}
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Created noPoll conn-id=%d (ptr: %p, context: %p, socket: %d)",
+		    conn->id, conn, ctx, session);
+	
+	/* configure context */
+	conn->ctx     = ctx;
+	conn->session = session;
+	conn->role    = NOPOLL_ROLE_CLIENT;
+
+	/* record host and port */
+	conn->host    = nopoll_strdup (host_ip);
+	conn->port    = nopoll_strdup (host_port);
+
+	/* configure default handlers */
+	conn->receive = nopoll_conn_default_receive;
+	conn->send    = nopoll_conn_default_send;
+
+	/* build host name */
+	if (host_name == NULL)
+		conn->host_name = nopoll_strdup (host_ip);
+	else
+		conn->host_name = nopoll_strdup (host_name);
+
+	/* build origin */
+	if (origin == NULL)
+		conn->origin = nopoll_strdup_printf ("http://%s", conn->host_name);
+	else
+		conn->origin = nopoll_strdup (origin);
+
+	/* get url */
+	if (get_url == NULL)
+		conn->get_url = nopoll_strdup ("/");
+	else
+		conn->get_url = nopoll_strdup (get_url);
+
+	/* protocols */
+	if (protocols != NULL)
+		conn->protocols = nopoll_strdup (protocols);
+
+
+	/* get client init payload */
+	content = __nopoll_conn_get_client_init (conn, options);
+
+	if (content == NULL) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to build client init message, unable to connect");
+		nopoll_conn_shutdown (conn);
+
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+
+		return NULL;
+	} /* end if */
+
+#if NOPOLL_TLS
+	/* check for TLS support */
+	if (enable_tls) {
+		/* found TLS connection request, enable it */
+		conn->ssl_ctx  = __nopoll_conn_get_ssl_context (ctx, conn, options, nopoll_true);
+		if (conn->ssl_ctx == NULL) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to enable TLS, internal __nopoll_conn_get_ssl_context (ctx=%p, conn=%p, options=%p, nopoll_true) failed",
+				    ctx, conn, options);
+			goto fail_ssl_connection;
+		} /* end if */
+
+		/* check for client side SSL configuration */
+		if (! __nopoll_conn_set_ssl_client_options (ctx, conn, options)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure additional SSL options, unable to continue, conn->ssl_ctx=%p, conn->ssl=%p",
+				    conn->ssl_ctx, conn->ssl);
+			goto fail_ssl_connection;
+		} /* end if */
+
+		/* create context and check for result */
+		conn->ssl      = SSL_new (conn->ssl_ctx);       
+		if (conn->ssl_ctx == NULL || conn->ssl == NULL) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to create SSL context internal references are null (conn->ssl_ctx=%p, conn->ssl=%p)",
+				    conn->ssl_ctx, conn->ssl);
+		fail_ssl_connection:
+
+			nopoll_free (content);
+			nopoll_conn_shutdown (conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return conn;
+		} /* end if */
+		
+		/* set socket */
+		SSL_set_fd (conn->ssl, conn->session);
+
+		/* do the initial connect connect */
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "connecting to remote TLS site %s:%s", conn->host, conn->port);
+		iterator = 0;
+		while (SSL_connect (conn->ssl) <= 0) {
+		
+			/* get ssl error */
+			ssl_error = SSL_get_error (conn->ssl, -1);
+ 
+			switch (ssl_error) {
+			case SSL_ERROR_WANT_READ:
+			        nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because read wanted, conn-id=%d (%p, session: %d), errno=%d",
+					    conn->id, conn, conn->session, errno);
+				break;
+			case SSL_ERROR_WANT_WRITE:
+			        nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because write wanted, conn-id=%d (%p)",
+					    conn->id, conn);
+				break;
+			case SSL_ERROR_SYSCALL:
+				/* Check ENOTCONN on SSL_connect error (only happening on windows). See:
+				 * https://github.com/ASPLes/nopoll/pull/19
+				 */
+				if (errno == NOPOLL_ENOTCONN) {
+					nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "the socket is not yet connected, retrying, conn-id=%d (%p)",
+					            conn->id, conn);
+					break;
+				}
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "syscall error while doing TLS handshake, ssl error (code:%d), conn-id: %d (%p), errno: %d, session: %d",
+					    ssl_error, conn->id, conn, errno, conn->session);
+				nopoll_conn_log_ssl (conn);
+				nopoll_conn_shutdown (conn);
+				nopoll_free (content);
+
+				/* release connection options */
+				__nopoll_conn_opts_release_if_needed (options);
+
+				return conn;
+			default:
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "there was an error with the TLS negotiation, ssl error (code:%d) : %s",
+					    ssl_error, ERR_error_string (ssl_error, NULL));
+				nopoll_conn_log_ssl (conn);
+				nopoll_conn_shutdown (conn);
+				nopoll_free (content);
+
+				/* release connection options */
+				__nopoll_conn_opts_release_if_needed (options);
+
+				return conn;
+			} /* end switch */
+
+			/* try and limit max reconnect allowed */
+			iterator++;
+
+			if (iterator > 1000) {
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Max retry calls=%d to SSL_connect reached, shutting down connection id=%d, errno=%d",
+					    iterator, conn->id, errno);
+				nopoll_free (content);
+
+				/* release connection options */
+				__nopoll_conn_opts_release_if_needed (options);
+
+				return conn;
+			} /* end if */
+
+			/* wait a bit before retry */
+			nopoll_sleep (10000);
+
+		} /* end while */
+
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Client TLS handshake finished, configuring I/O handlers");
+
+		/* check remote certificate (if it is present) */
+		server_cert = SSL_get_peer_certificate (conn->ssl);
+		if (server_cert == NULL) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "server side didn't set a certificate for this session, these are bad news");
+
+			/* release connection options */
+			nopoll_free (content);
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return conn;
+		}
+		X509_free (server_cert);
+
+		/* call to check post ssl checks after SSL finalization */
+		if (conn->ctx && conn->ctx->post_ssl_check) {
+			if (! conn->ctx->post_ssl_check (conn->ctx, conn, conn->ssl_ctx, conn->ssl, conn->ctx->post_ssl_check_data)) {
+				/* TLS post check failed */
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "TLS/SSL post check function failed, dropping connection");
+				nopoll_conn_shutdown (conn);
+				return NULL;
+			} /* end if */
+		} /* end if */
+
+		/* configure default handlers */
+		conn->receive = nopoll_conn_tls_receive;
+		conn->send    = nopoll_conn_tls_send;
+
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "TLS I/O handlers configured");
+		conn->tls_on = nopoll_true;
+	} /* end if */
+#endif
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sending websocket client init: %s", content);
+	size = strlen (content);
+
+	/* call to send content */
+	remaining_timeout = ctx->conn_connect_std_timeout;
+	while (remaining_timeout > 0) {
+		if (size != conn->send (conn, content, size)) {
+		        /* for some reason, under FreeBSD, a ENOTCONN is reported when they should be returning EINPROGRESS and/or EWOULDBLOCK */
+			if (errno == NOPOLL_EWOULDBLOCK || errno == NOPOLL_EINPROGRESS || errno == NOPOLL_ENOTCONN) {
+				/* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Connection in progress (errno=%d), session: %d", errno, session); */
+				nopoll_sleep (10000);
+				remaining_timeout -= 10000;
+				continue;
+			} /* end if */
+
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to send websocket init message, error code was: %d (2), closing session", errno);
+			nopoll_conn_shutdown (conn);
+		} /* end if */
+
+		break;
+	}
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Web socket initial client handshake sent");
+
+	/* release content */
+	nopoll_free (content);
+
+	/* release connection options */
+	__nopoll_conn_opts_release_if_needed (options);
+
+	/* return connection created */
+	return conn;
+}
+
+
+/** 
+ * @brief Creates a new Websocket connection to the provided
+ * destination, physically located at host_ip and host_port (IPv4 version).
+ *
+ * @param ctx The noPoll context to which this new connection will be associated.
+ *
+ * @param host_ip The websocket server address to connect to.
+ *
+ * @param host_port The websocket server port to connect to. If NULL
+ * is provided, port 80 is used.
+ *
+ * @param host_name This is the Host: header value that will be
+ * sent. This header is used by the websocket server to activate the
+ * right virtual host configuration. If null is provided, Host: will
+ * use host_ip value.
+ *
+ * @param get_url As part of the websocket handshake, an url is passed
+ * to the remote server inside a GET method. This parameter allows to
+ * configure this. If NULL is provided, then / will be used.
+ *
+ * @param origin Websocket origin to be notified to the server.
+ *
+ * @param protocols Optional protocols requested to be activated for
+ * this connection (an string of list of strings separated by a white
+ * space). If the server accepts the connection you can use \ref
+ * nopoll_conn_get_accepted_protocol to get the protocol accepted by
+ * the server.
+ *
+ * @return A reference to the connection created or NULL if it
+ * fails. Keep in mind the connection reported may not be connected at
+ * the time is returned by this function. You can use \ref
+ * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be
+ * used. There is also a helper function (NOTE it is blocking) that
+ * can help you implement a very simple wait until ready operation:
+ * \ref nopoll_conn_wait_until_connection_ready (however, it is not
+ * recommended for any serious, non-command line programming).
+ *
+ * <b>Note 1: Is \ref nopoll_conn_new blocking?</b>
+ *
+ * Partially. It is blocking with a timeout but just for sending the
+ * client init (the initial packet that a WebSocket client must send),
+ * but the function does not block the caller until a reply from the
+ * server is received and the handshake is completed (which is where
+ * the blocking it is likely to happen).
+ *
+ * So, it essence, \ref nopoll_conn_new (and all its variants) is not
+ * blocking (unless you have a problem with network connection causing
+ * send() API to fail to send the WebSocket init message by returning
+ * EWOULD_BLOCK, which is very likely to not happen),
+ * 
+ * Because of that, the connection (\ref noPollConn) reported by this function have big
+ * chances to be not ready (that's why you have to use \ref nopoll_conn_is_ready
+ * or the blocking one \ref nopoll_conn_wait_until_connection_ready to ensure
+ * you successfully connected),
+ *
+ * <b>Note 2: Controll connect timeout</b>
+ *
+ * To control timeout for sending the initial message (and to ensure
+ * the engine sends it), you can use the following functions:
+ *
+ *  - \ref nopoll_conn_connect_timeout
+ *  - \ref nopoll_conn_get_connect_timeout
+ */
+noPollConn * nopoll_conn_new (noPollCtx  * ctx,
+			      const char * host_ip, 
+			      const char * host_port, 
+			      const char * host_name,
+			      const char * get_url, 
+			      const char * protocols,
+			      const char * origin)
+{
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, NULL, NOPOLL_TRANSPORT_IPV4, nopoll_false, 
+					 NOPOLL_INVALID_SOCKET,
+					 host_ip, host_port, host_name, 
+					 get_url, protocols, origin);
+}
+
+/** 
+ * @brief Creates a new Websocket connection to the provided
+ * destination, physically located at host_ip and host_port (IPv6 version).
+ *
+ * See \ref nopoll_conn_new for more information about this
+ * function. Both shares same core.
+ *
+ * @param ctx See \ref nopoll_conn_new
+ *
+ * @param host_ip See \ref nopoll_conn_new
+ *
+ * @param host_port See \ref nopoll_conn_new
+ *
+ * @param host_name See \ref nopoll_conn_new
+ *
+ * @param get_url See \ref nopoll_conn_new
+ *
+ * @param origin See \ref nopoll_conn_new
+ *
+ * @param protocols See \ref nopoll_conn_new
+ *
+ * @return See \ref nopoll_conn_new
+ *
+ * See \ref nopoll_conn_new for more information about this
+ * function. Both shares same core.
+ *
+ */
+noPollConn * nopoll_conn_new6 (noPollCtx  * ctx,
+			       const char * host_ip, 
+			       const char * host_port, 
+			       const char * host_name,
+			       const char * get_url, 
+			       const char * protocols,
+			       const char * origin)
+{
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, NULL, NOPOLL_TRANSPORT_IPV6, nopoll_false, 
+					 NOPOLL_INVALID_SOCKET,
+					 host_ip, host_port, host_name, 
+					 get_url, protocols, origin);
+}
+
+/** 
+ * @brief Creates a new Websocket connection to the provided
+ * destination, physically located at host_ip and host_port and
+ * allowing to provide a noPollConnOpts object.
+ *
+ * See \ref nopoll_conn_new for more information.
+ *
+ * @param ctx The noPoll context to which this new connection will be associated.
+ *
+ * @param opts The connection options to use during the connection and
+ * the usage of this connection.
+ *
+ * @param host_ip The websocket server address to connect to.
+ *
+ * @param host_port The websocket server port to connect to. If NULL
+ * is provided, port 80 is used.
+ *
+ * @param host_name This is the Host: header value that will be
+ * sent. This header is used by the websocket server to activate the
+ * right virtual host configuration. If null is provided, Host: will
+ * use host_ip value.
+ *
+ * @param get_url As part of the websocket handshake, an url is passed
+ * to the remote server inside a GET method. This parameter allows to
+ * configure this. If NULL is provided, then / will be used.
+ *
+ * @param origin Websocket origin to be notified to the server.
+ *
+ * @param protocols Optional protocols requested to be activated for
+ * this connection (an string of list of strings separated by a white
+ * space). If the server accepts the connection you can use \ref
+ * nopoll_conn_get_accepted_protocol to get the protocol accepted by
+ * the server.
+ *
+ * @return A reference to the connection created or NULL if it
+ * fails. Keep in mind the connection reported may not be connected at
+ * the time is returned by this function. You can use \ref
+ * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be
+ * used. There is also a helper function (NOTE it is blocking) that
+ * can help you implement a very simple wait until ready operation:
+ * \ref nopoll_conn_wait_until_connection_ready (however, it is not
+ * recommended for any serious, non-command line programming).
+ */
+noPollConn * nopoll_conn_new_opts (noPollCtx       * ctx,
+				   noPollConnOpts  * opts,
+				   const char      * host_ip, 
+				   const char      * host_port, 
+				   const char      * host_name,
+				   const char      * get_url, 
+				   const char      * protocols,
+				   const char      * origin)
+{
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, opts, NOPOLL_TRANSPORT_IPV4, nopoll_false, 
+					 NOPOLL_INVALID_SOCKET,
+					 host_ip, host_port, host_name, 
+					 get_url, protocols, origin);
+}
+
+/**
+ * @brief Creates a new Websocket connection using a socket
+ * with a preestablished connection.
+ *
+ * @param ctx The noPoll context to which this new connection will be associated.
+ *
+ * @param options Optional configuration object. See \ref nopoll_conn_opts_new and \ref nopoll_conn_opts_set_ssl_protocol (for example).
+ *
+ * @param socket Socket FD with an already established connection.
+ *
+ * @param host_ip The websocket server address to connect to.
+ *
+ * @param host_port The websocket server port to connect to. If NULL
+ * is provided, port 80 is used.
+ *
+ * @param host_name This is the Host: header value that will be
+ * sent. This header is used by the websocket server to activate the
+ * right virtual host configuration. If null is provided, Host: will
+ * use host_ip value.
+ *
+ * @param get_url As part of the websocket handshake, an url is passed
+ * to the remote server inside a GET method. This parameter allows to
+ * configure this. If NULL is provided, then / will be used.
+ *
+ * @param origin Websocket origin to be notified to the server.
+ *
+ * @param protocols Optional protocols requested to be activated for
+ * this connection (an string of list of strings separated by a white
+ * space).
+ */
+noPollConn * nopoll_conn_new_with_socket (noPollCtx  * ctx,
+				   noPollConnOpts  * options,
+				   int             socket,
+				   const char      * host_ip,
+				   const char      * host_port,
+				   const char      * host_name,
+				   const char      * get_url,
+				   const char      * protocols,
+				   const char      * origin)
+{
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, options, NOPOLL_TRANSPORT_IPV4, nopoll_false,
+					 socket, host_ip, host_port, host_name,
+					 get_url, protocols, origin);
+}
+
+nopoll_bool __nopoll_tls_was_init = nopoll_false;
+#if NOPOLL_TLS
+/** 
+ * @brief Allows to create a client WebSocket connection over TLS (IPv4 version).
+ *
+ * The function works like \ref nopoll_conn_new with the same
+ * semantics but providing a way to create a WebSocket session under
+ * TLS supervision. See \ref nopoll_conn_new for more information.
+ *
+ * @param ctx The context where the operation will take place.
+ *
+ * @param options Optional configuration object. See \ref nopoll_conn_opts_new and \ref nopoll_conn_opts_set_ssl_protocol (for example).
+ *
+ * @param host_ip The websocket server address to connect to.
+ *
+ * @param host_port The websocket server port to connect to. If NULL
+ * is provided, port 443 is used.
+ *
+ * @param host_name This is the Host: header value that will be
+ * sent. This header is used by the websocket server to activate the
+ * right virtual host configuration. If null is provided, Host: will
+ * use host_ip value.
+ *
+ * @param get_url As part of the websocket handshake, an url is passed
+ * to the remote server inside a GET method. This parameter allows to
+ * configure this. If NULL is provided, then / will be used.
+ *
+ * @param origin Websocket origin to be notified to the server.
+ *
+ * @param protocols Optional protocols requested to be activated for
+ * this connection (an string of list of strings separated by a white
+ * space). If the server accepts the connection you can use \ref
+ * nopoll_conn_get_accepted_protocol to get the protocol accepted by
+ * the server.
+ *
+ * @return A reference to the connection created or NULL if it
+ * fails. Keep in mind the connection reported may not be connected at
+ * the time is returned by this function. You can use \ref
+ * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be
+ * used. There is also a helper function (NOTE it is blocking) that
+ * can help you implement a very simple wait until ready operation:
+ * \ref nopoll_conn_wait_until_connection_ready (however, it is not
+ * recommended for any serious, non-command line programming).
+ * 
+ */
+noPollConn * nopoll_conn_tls_new (noPollCtx  * ctx,
+				  noPollConnOpts  * options,
+				  const char * host_ip, 
+				  const char * host_port, 
+				  const char * host_name,
+				  const char * get_url, 
+				  const char * protocols,
+				  const char * origin)
+{
+	/* init ssl ciphers and engines */
+	if (! __nopoll_tls_was_init) {
+		__nopoll_tls_was_init = nopoll_true;
+		SSL_library_init ();
+	} /* end if */
+
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, options, NOPOLL_TRANSPORT_IPV4, nopoll_true, 
+					 NOPOLL_INVALID_SOCKET,
+					 host_ip, host_port, host_name, 
+					 get_url, protocols, origin);
+}
+
+/** 
+ * @brief Allows to create a client WebSocket connection over TLS (IPv6 version).
+ *
+ * See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param ctx See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param options See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param host_ip See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param host_port See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param host_name See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param get_url See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param origin See \ref nopoll_conn_tls_new for more information.
+ *
+ * @param protocols See \ref nopoll_conn_tls_new for more information.
+ *
+ * @return See \ref nopoll_conn_tls_new for more information.
+ * 
+ */
+noPollConn * nopoll_conn_tls_new6 (noPollCtx  * ctx,
+				   noPollConnOpts  * options,
+				   const char * host_ip, 
+				   const char * host_port, 
+				   const char * host_name,
+				   const char * get_url, 
+				   const char * protocols,
+				   const char * origin)
+{
+	/* init ssl ciphers and engines */
+	if (! __nopoll_tls_was_init) {
+		__nopoll_tls_was_init = nopoll_true;
+		SSL_library_init ();
+	} /* end if */
+
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, options, NOPOLL_TRANSPORT_IPV6, nopoll_true, 
+					 NOPOLL_INVALID_SOCKET,
+					 host_ip, host_port, host_name, 
+					 get_url, protocols, origin);
+}
+
+/**
+ * @brief Allows to create a client WebSocket connection over TLS using a preestablished socket.
+ *
+ * The function works like \ref nopoll_conn_tls_new with the same
+ * semantics but providing a way to create a WebSocket session under
+ * TLS supervision with a preestablished socket. See \ref nopoll_conn_tls_new
+ * and \ref nopoll_conn_new_with_socket for more information.
+ *
+ * @param ctx The context where the operation will take place.
+ *
+ * @param options Optional configuration object. See \ref nopoll_conn_opts_new and \ref nopoll_conn_opts_set_ssl_protocol (for example).
+ *
+ * @param socket Socket FD with an already established connection.
+ *
+ * @param host_ip The websocket server address to connect to.
+ *
+ * @param host_port The websocket server port to connect to. If NULL
+ * is provided, port 443 is used.
+ *
+ * @param host_name This is the Host: header value that will be
+ * sent. This header is used by the websocket server to activate the
+ * right virtual host configuration. If null is provided, Host: will
+ * use host_ip value.
+ *
+ * @param get_url As part of the websocket handshake, an url is passed
+ * to the remote server inside a GET method. This parameter allows to
+ * configure this. If NULL is provided, then / will be used.
+ *
+ * @param origin Websocket origin to be notified to the server.
+ *
+ * @param protocols Optional protocols requested to be activated for
+ * this connection (an string of list of strings separated by a white
+ * space). If the server accepts the connection you can use \ref
+ * nopoll_conn_get_accepted_protocol to get the protocol accepted by
+ * the server.
+ *
+ * @return A reference to the connection created or NULL if it
+ * fails. Keep in mind the connection reported may not be connected at
+ * the time is returned by this function. You can use \ref
+ * nopoll_conn_is_ready and \ref nopoll_conn_is_ok to ensure it can be
+ * used. There is also a helper function (NOTE it is blocking) that
+ * can help you implement a very simple wait until ready operation:
+ * \ref nopoll_conn_wait_until_connection_ready (however, it is not
+ * recommended for any serious, non-command line programming).
+ *
+ */
+noPollConn * nopoll_conn_tls_new_with_socket (noPollCtx  * ctx,
+				  noPollConnOpts  * options,
+				  int          socket,
+				  const char * host_ip,
+				  const char * host_port,
+				  const char * host_name,
+				  const char * get_url,
+				  const char * protocols,
+				  const char * origin)
+{
+	/* init ssl ciphers and engines */
+	if (! __nopoll_tls_was_init) {
+		__nopoll_tls_was_init = nopoll_true;
+		SSL_library_init ();
+	} /* end if */
+
+	/* call common implementation */
+	return __nopoll_conn_new_common (ctx, options, NOPOLL_TRANSPORT_IPV4, nopoll_true,
+					 socket, host_ip, host_port, host_name,
+					 get_url, protocols, origin);
+}
+#endif
+
+/** 
+ * @brief Allows to acquire a reference to the provided connection.
+ *
+ * @param conn The conection to be referenced
+ *
+ * @return nopoll_true In the case the function acquired a reference
+ * otherwise nopoll_false is returned.
+ */
+nopoll_bool    nopoll_conn_ref (noPollConn * conn)
+{
+	if (conn == NULL)
+		return nopoll_false;
+
+	/* lock the mutex */
+	nopoll_mutex_lock (conn->ref_mutex);
+	conn->refs++;
+	nopoll_mutex_unlock (conn->ref_mutex);
+		
+	/* report */
+	return conn->refs > 1;
+}
+
+/** 
+ * @brief Allows to get current reference counting state for the
+ * provided connection.
+ *
+ * @param conn The connection queried for its reference counting.
+ *
+ * @return The reference counting or -1 if it fails.
+ */
+int            nopoll_conn_ref_count (noPollConn * conn)
+{
+	if (! conn)
+		return -1;
+	return conn->refs;
+}
+
+/** 
+ * @brief Allows to check if the provided connection is in connected
+ * state (just to the connection). This is different to be ready to send and receive content
+ * because the session needs to be first established. 
+ *
+ * You can use \ref nopoll_conn_is_ready to ensure the connection is
+ * ready to be used (read or write operation can be done because
+ * handshake has finished).
+ *
+ * For example, you might connect to a raw socket server and
+ * nopoll_conn_is_ok will report that everything is ok because the
+ * socket is indeed connected but because you are connecting to a
+ * non-websocket server, it will not work because the WebSocket
+ * session establishment didn't take place and hence
+ * nopoll_conn_is_ready will fail.
+ *
+ * Please, see the following link for a complete example that connects
+ * and ensure the connection is ready (for a client):  http://www.aspl.es/nopoll/html/nopoll_core_library_manual.html#creating_basic_web_socket_client
+ *
+ * @param conn The websocket connection to be checked.
+ *
+ * @return nopoll_true in the case the connection is working otherwise
+ * nopoll_false is returned.
+ */
+nopoll_bool    nopoll_conn_is_ok (noPollConn * conn)
+{
+	if (conn == NULL)
+		return nopoll_false;
+
+	/* return current socket status */
+	return conn->session != NOPOLL_INVALID_SOCKET;
+}
+
+/** 
+ * @brief Allows to check if the connection is ready to be used
+ * (handshake completed).
+ *
+ * Note this function may block the caller in the case the hanshake is
+ * not completed.
+ *
+ * @param conn The connection to be checked.
+ *
+ * @return nopoll_true in the case the handshake was completed
+ * otherwise nopoll_false is returned. The function also returns
+ * nopoll_false in case \ref nopoll_conn_is_ok is failing.
+ */
+nopoll_bool    nopoll_conn_is_ready (noPollConn * conn)
+{
+	if (conn == NULL)
+		return nopoll_false;
+	if (conn->session == NOPOLL_INVALID_SOCKET)
+		return nopoll_false;
+	if (! conn->handshake_ok) {
+		/* acquire here handshake mutex */
+		nopoll_mutex_lock (conn->ref_mutex);
+
+		/* complete handshake */
+		nopoll_conn_complete_handshake (conn);
+
+		/* release here handshake mutex */
+		nopoll_mutex_unlock (conn->ref_mutex);
+	}
+	return conn->handshake_ok;
+}
+
+/** 
+ * @brief Allows to check if the provided connection is working under a TLS session.
+ *
+ * @param conn The connection where the TLS is being queired to be enabled.
+ *
+ * @return nopoll_true in the case TLS is enabled, otherwise* nopoll_false is returned. Note the function also returns* nopoll_false when the reference received is NULL.
+ */
+nopoll_bool    nopoll_conn_is_tls_on (noPollConn * conn)
+{
+	if (! conn)
+		return nopoll_false;
+
+#if NOPOLL_TLS
+	return nopoll_false;
+#else
+	/* return TLS on */
+	return conn->tls_on;
+#endif
+}
+
+/** 
+ * @brief Allows to get the socket associated to this nopoll
+ * connection.
+ *
+ * @return The socket reference or -1 if it fails.
+ */
+NOPOLL_SOCKET nopoll_conn_socket (noPollConn * conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->session;
+}
+
+/** 
+ * @brief Allows to set up the socket reference to be used by this
+ * noPollConn.
+ *
+ * @param conn The connection to setup with a new socket.
+ *
+ * @param _socket The socket that will be configured.
+ */
+void           nopoll_conn_set_socket (noPollConn * conn, NOPOLL_SOCKET _socket)
+{
+	if (conn == NULL)
+		return;
+	conn->session = _socket;
+	return;
+}
+
+/** 
+ * @brief Allows to get the connection id from the provided
+ * connection.
+ *
+ * @param conn The connection from where the unique identifier will be
+ * returned.
+ *
+ * @return The identifier or -1 if it fails.
+ */
+int           nopoll_conn_get_id (noPollConn * conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->id;
+}
+
+/**
+ * @brief Allows to get the get_url from the connection
+ *
+ * @param conn The connection from where the url will be obtained
+ *
+ * @return The get_url or NULL
+ */
+const char * nopoll_conn_get_requested_url (noPollConn * conn)
+{
+        if (!conn)
+            return NULL;
+        return (conn->get_url == NULL ? "/" : conn->get_url);
+}
+
+
+/** 
+ * @brief Allows to get the noPollCtx context object associated to the
+ * connection (or where the connection is working).
+ *
+ * @param conn The connection that is requested to return its context.
+ *
+ * @return A reference to the context or NULL if it fails.
+ */
+noPollCtx   * nopoll_conn_ctx    (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->ctx;
+}
+
+/** 
+ * @brief Allows to get the connection role.
+ *
+ * @return The connection role, see \ref noPollRole for details.
+ */
+noPollRole    nopoll_conn_role   (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NOPOLL_ROLE_UNKNOWN;
+	return conn->role;
+}
+
+/** 
+ * @brief Returns the host location this connection connects to or it is
+ * listening (according to the connection role \ref noPollRole).
+ *
+ * If you are looking for a way to get the Host: header value received
+ * for this connection during the handshake, use: \ref
+ * nopoll_conn_get_host_header.
+ *
+ * @param conn The connection to check for the host value.
+ *
+ * @return The host location value or NULL if it fails.
+ */
+const char  * nopoll_conn_host   (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->host;
+}
+
+/** 
+ * @brief Allows to get the connection Origin header content received.
+ *
+ * @param conn The websocket connection where the operation takes place.
+ *
+ * @return The Origin value received during the handshake for this
+ * connection or NULL if it fails to get this value.
+ */
+const char  * nopoll_conn_get_origin (noPollConn * conn)
+{
+	if (conn == NULL || conn->handshake == NULL)
+		return NULL;
+	return conn->origin;
+} /* end if */
+
+/** 
+ * @brief Allows to get the Host: header value that was received for
+ * this connection during the handshake.
+ *
+ * @param conn The websocket connection where the operation takes place.
+ *
+ * @return The Host value received during the handshake for this
+ * connection or NULL if it fails to get this value (or it wasn't
+ * defined).
+ */
+const char  * nopoll_conn_get_host_header (noPollConn * conn)
+{
+	if (conn == NULL || conn->host_name == NULL)
+		return NULL;
+	return conn->host_name;
+}
+
+/** 
+ * @brief Allows to get cookie header content received during
+ * handshake (if received).
+ *
+ * @param conn The websocket connection where the operation takes place.
+ *
+ * @return A reference to the cookie value or NULL if nothing is
+ * configured or if failed to get it.
+ */
+const char  * nopoll_conn_get_cookie (noPollConn * conn)
+{
+	
+        if (conn == NULL || conn->handshake == NULL)
+                return NULL;
+        return conn->handshake->cookie;
+}
+
+/** 
+ * @brief Allows to get accepted protocol in the case a protocol was
+ * requested during connection.
+ *
+ * @param conn The connection where the operation is taking place.
+ *
+ * @return A reference to the protocol accepted or NULL if no protocol
+ * was mentioned during the handshake.
+ */
+const char  * nopoll_conn_get_accepted_protocol (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->accepted_protocol; /* report accepted protocol */
+}
+
+/** 
+ * @brief Allows to get requested protocols for the provided
+ * connection
+ *
+ * @param conn The connection where the operation is taking place.
+ *
+ * @return A reference to the protocol or list of protocols requested
+ * by this connection.
+ */
+const char  * nopoll_conn_get_requested_protocol (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->protocols; /* report requested protocol */
+}
+
+/** 
+ * @brief Allows to configure accepted protocol on the provided
+ * connection.
+ *
+ * @param conn The connection where the accepted protocol will be
+ * notified. This function is only useful at server side to notify
+ * accepted protocol to the connecting client. Caller is entirely
+ * responsible on setting an appropriate value that is understood by
+ * the client. No especial check is done on the value provided to this function.
+ *
+ * @param protocol The protocol to configure in the reply, that is,
+ * the protocol accepted by the server. 
+ *
+ * If no protocol is configured and the client requests a protocol,
+ * the server will reply by default the same accepting it.
+ */
+void          nopoll_conn_set_accepted_protocol (noPollConn * conn, const char * protocol)
+{
+	if (conn == NULL || protocol == NULL)
+		return;
+
+	/* set accepted protocol */
+	conn->accepted_protocol = nopoll_strdup (protocol);
+	return;
+}
+
+/** 
+ * @brief Returns the port location this connection connects to or it
+ * is listening (according to the connection role \ref noPollRole).
+ *
+ * @param conn The connection to check for the port value.
+ *
+ * @return The port location value or NULL if it fails.
+ */
+const char  * nopoll_conn_port   (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->port;
+}
+
+/** 
+ * @brief Optionally, remote peer can close the connection providing an
+ * error code (\ref nopoll_conn_get_close_status) and a reason (\ref nopoll_conn_get_close_reason).
+ *
+ * These functions are used to get those values.
+ *
+ * @param conn The connection where the peer reported close status is being asked.
+ *
+ * @return Status code reported by the remote peer or 0 if nothing was reported.
+ */ 
+int           nopoll_conn_get_close_status (noPollConn * conn)
+{
+	if (conn == NULL)
+		return 0;
+	return conn->peer_close_status;
+}
+
+/** 
+ * @brief Optionally, remote peer can close the connection providing an
+ * error code (\ref nopoll_conn_get_close_status) and a reason (\ref nopoll_conn_get_close_reason).
+ *
+ * These functions are used to get those values.
+ *
+ * @param conn The connection where the peer reported close reason is being asked.
+ *
+ * @return Status close reason reported by the remote peer or NULL if nothing was reported.
+ */ 
+const char *  nopoll_conn_get_close_reason (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->peer_close_reason;
+}
+
+/** 
+ * @brief Call to close the connection immediately without going
+ * through websocket close negotiation.
+ *
+ * @param conn The connection to be shutted down.
+ */
+void          nopoll_conn_shutdown (noPollConn * conn)
+{
+#if defined(SHOW_DEBUG_LOG)
+	const char * role = NULL;
+#endif
+
+	if (conn == NULL)
+		return;
+
+	/* report connection close */
+#if defined(SHOW_DEBUG_LOG)
+	if (conn->role == NOPOLL_ROLE_LISTENER)
+		role = "listener";
+	else if (conn->role == NOPOLL_ROLE_MAIN_LISTENER)
+		role = "master-listener";
+	else if (conn->role == NOPOLL_ROLE_UNKNOWN)
+		role = "unknown";
+	else if (conn->role == NOPOLL_ROLE_CLIENT)
+		role = "client";
+	else
+		role = "unknown";
+
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "shutting down connection id=%d (session: %d, role: %s)", 
+		    conn->id, conn->session, role);
+#endif
+
+	/* call to on close handler if defined */
+	if (conn->session != NOPOLL_INVALID_SOCKET && conn->on_close)
+	        conn->on_close (conn->ctx, conn, conn->on_close_data);
+
+	/* shutdown connection here */
+	if (conn->session != NOPOLL_INVALID_SOCKET) {
+	        shutdown (conn->session, SHUT_RDWR);
+		nopoll_close_socket (conn->session);
+	}
+	conn->session = NOPOLL_INVALID_SOCKET;
+
+	return;
+}
+
+/** 
+ * @brief Allows to close an opened \ref noPollConn no matter its role
+ * (\ref noPollRole).
+ *
+ * @param conn The connection to close.
+ *
+ * @param status Optional status code to send to remote side. If
+ * status is < 0, no status code is sent.
+ *
+ * @param reason Pointer to the content to be sent.
+ *
+ * @param reason_size The amount of bytes that should be used from content pointer.
+ */ 
+void          nopoll_conn_close_ext  (noPollConn  * conn, int status, const char * reason, int reason_size)
+{
+	int    refs;
+	char * content;
+#if defined(SHOW_DEBUG_LOG)
+	const char * role = "unknown";
+#endif
+
+	/* check input data */
+	if (conn == NULL)
+		return;
+
+#if defined(SHOW_DEBUG_LOG)
+	if (conn->role == NOPOLL_ROLE_LISTENER)
+		role = "listener";
+	else if (conn->role == NOPOLL_ROLE_MAIN_LISTENER)
+		role = "master-listener";
+	else if (conn->role == NOPOLL_ROLE_UNKNOWN)
+		role = "unknown";
+	else if (conn->role == NOPOLL_ROLE_CLIENT)
+		role = "client";
+	
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Calling to close close id=%d (session %d, refs: %d, role: %s)", 
+		    conn->id, conn->session, conn->refs, role);
+#endif
+	if (conn->session != NOPOLL_INVALID_SOCKET) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "requested proper connection close id=%d (session %d)", conn->id, conn->session);
+
+		/* build reason indication */
+		content = NULL;
+		if (reason && reason_size > 0) {
+			/* send content */
+			content = nopoll_new (char, reason_size + 3);
+			if (content) {
+				nopoll_set_16bit (status, content);
+				memcpy (content + 2, reason, reason_size);
+			} /* end if */
+		} /* end if */
+
+		/* send close without reason */
+		nopoll_conn_send_frame (conn, nopoll_true /* has_fin */, 
+					/* masked */
+					conn->role == NOPOLL_ROLE_CLIENT, NOPOLL_CLOSE_FRAME, 
+					/* content size and content */
+					reason_size > 0 ? reason_size + 2 : 0, content, 
+					/* sleep in header */
+					0);
+
+		/* release content (if defined) */
+		nopoll_free (content);
+
+		/* call to shutdown connection */
+		nopoll_conn_shutdown (conn);
+	} /* end if */
+
+	/* unregister connection from context */
+	refs = nopoll_conn_ref_count (conn);
+	nopoll_ctx_unregister_conn (conn->ctx, conn);
+
+	/* avoid calling next unref in the case not enough references
+	 * are found */
+	if (refs <= 1)
+		return;
+
+	/* call to unref connection */
+	nopoll_conn_unref (conn);
+
+	return;	
+}
+
+/** 
+ * @brief Allows to close an opened \ref noPollConn no matter its role
+ * (\ref noPollRole).
+ *
+ * @param conn The connection to close.
+ *
+ * There is available an alternative extended version that allows to
+ * send the status code and the error message: \ref
+ * nopoll_conn_close_ext
+ */ 
+void          nopoll_conn_close  (noPollConn  * conn)
+{
+	/* call to close without providing a reason */
+	nopoll_conn_close_ext (conn, 0, NULL, 0);
+	return;
+}
+
+/** 
+ * @brief Allows to define a user level pointer associated to this
+ * connection. This pointer can be later be retrieved using \ref
+ * nopoll_conn_get_hook.
+ *
+ * @param conn The connection where the pointer will be associated.
+ *
+ * @param ptr The pointer to associate to the connection.
+ */
+void          nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr)
+{
+	if (conn == NULL)
+		return;
+	conn->hook = ptr;
+	return;
+}
+
+
+/** 
+ * @brief Allows to get the user level pointer defined by \ref
+ * nopoll_conn_get_hook.
+ *
+ * @param conn The connection where the uesr level pointer was stored.
+ *
+ * @return A reference to the pointer stored.
+ */
+noPollPtr     nopoll_conn_get_hook (noPollConn * conn)
+{
+	if (conn == NULL)
+		return NULL;
+	return conn->hook;
+}
+
+/** 
+ * @brief Allows to unref connection reference acquired via \ref
+ * nopoll_conn_ref.
+ *
+ * @param conn The connection to be unrefered.
+ */
+void nopoll_conn_unref (noPollConn * conn)
+{
+	int value;
+	
+	if (conn == NULL)
+		return;
+
+	/* acquire here the mutex */
+	nopoll_mutex_lock (conn->ref_mutex);
+
+	conn->refs--;
+	value = conn->refs;
+	
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Releasing connection id %d reference, current ref count status is: %d", 
+		    conn->id, value);
+	/* release here the mutex */
+	nopoll_mutex_unlock (conn->ref_mutex);
+	
+	if (value != 0) 
+		return;
+
+	/* release message */
+	if (conn->pending_msg)
+		nopoll_msg_unref (conn->pending_msg);
+
+	/* release ctx */
+	if (conn->ctx) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Released context refs, now: %d", conn->ctx->refs);
+		nopoll_ctx_unref (conn->ctx);
+	} /* end if */
+	conn->ctx = NULL;
+
+	/* free all internal strings */
+	nopoll_free (conn->host);
+	nopoll_free (conn->port);
+	nopoll_free (conn->host_name);
+	nopoll_free (conn->origin);
+	nopoll_free (conn->protocols);
+	nopoll_free (conn->accepted_protocol);
+	nopoll_free (conn->get_url);
+
+	/* close reason if any */
+	nopoll_free (conn->peer_close_reason);
+
+#if NOPOLL_TLS
+	/* release TLS certificates */
+	nopoll_free (conn->certificate);
+	nopoll_free (conn->private_key);
+	nopoll_free (conn->chain_certificate);
+#endif
+
+	/* release uncomplete message */
+	if (conn->previous_msg) 
+		nopoll_msg_unref (conn->previous_msg);
+
+#if NOPOLL_TLS
+	if (conn->ssl)
+		SSL_free (conn->ssl);
+	if (conn->ssl_ctx)
+		SSL_CTX_free (conn->ssl_ctx);
+#endif
+
+	/* release handshake internal data */
+	if (conn->handshake) {
+		nopoll_free (conn->handshake->websocket_key);
+		nopoll_free (conn->handshake->websocket_version);
+		nopoll_free (conn->handshake->websocket_accept);
+		nopoll_free (conn->handshake->expected_accept);
+		nopoll_free (conn->handshake->cookie);
+		nopoll_free (conn->handshake);
+	} /* end if */
+
+	/* release connection options if defined and reuse flag is not defined */
+	if (conn->opts && ! conn->opts->reuse)
+		nopoll_conn_opts_free (conn->opts);
+
+	/* release pending write buffer */
+	nopoll_free (conn->pending_write);
+
+	/* release mutex */
+	nopoll_mutex_destroy (conn->ref_mutex);
+
+	nopoll_free (conn);	
+
+	return;
+}
+
+/** 
+ * @internal Default connection receive until handshake is complete.
+ */
+int nopoll_conn_default_receive (noPollConn * conn, char * buffer, int buffer_size)
+{
+	return recv (conn->session, buffer, buffer_size, 0);
+}
+
+/** 
+ * @internal Default connection send until handshake is complete.
+ */
+int nopoll_conn_default_send (noPollConn * conn, char * buffer, int buffer_size)
+{
+	return send (conn->session, buffer, buffer_size, 0);
+}
+
+/** 
+ * @internal Read the next line, byte by byte until it gets a \n or
+ * maxlen is reached. Some code errors are used to manage exceptions
+ * (see return values)
+ * 
+ * @param connection The connection where the read operation will be done.
+ *
+ * @param buffer A buffer to store content read from the network.
+ *
+ * @param maxlen max content to read from the network.
+ * 
+ * @return  values returned by this function follows:
+ *  0 - remote peer have closed the connection
+ * -1 - an error have happened while reading
+ * -2 - could read because this connection is on non-blocking mode and there is no data.
+ *  n - some data was read.
+ * 
+ **/
+int          nopoll_conn_readline (noPollConn * conn, char  * buffer, int  maxlen)
+{
+	int         n, rc;
+	int         desp;
+	char        c, *ptr;
+#if defined(SHOW_DEBUG_LOG)
+# if !defined(SHOW_FORMAT_BUGS)
+	noPollCtx * ctx = conn->ctx;
+# endif
+#endif
+
+	/* clear the buffer received */
+	/* memset (buffer, 0, maxlen * sizeof (char ));  */
+
+	/* check for pending line read */
+	desp         = 0;
+	if (conn->pending_line) {
+		/* get size and check exceeded values */
+		desp = strlen (conn->pending_line);
+		if (desp >= maxlen) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 
+				    "found fragmented frame line header but allowed size was exceeded (desp:%d >= maxlen:%d)",
+				    desp, maxlen);
+			nopoll_conn_shutdown (conn);
+			return -1;
+		} /* end if */
+
+		/* now store content into the buffer */
+		memcpy (buffer, conn->pending_line, desp);
+
+		/* clear from the conn the line */
+		nopoll_free (conn->pending_line);
+		conn->pending_line = NULL;
+	}
+
+	/* read current next line */
+	ptr = (buffer + desp);
+	for (n = 1; n < (maxlen - desp); n++) {
+	nopoll_readline_again:
+		if (( rc = conn->receive (conn, &c, 1)) == 1) {
+			*ptr++ = c;
+			if (c == '\x0A')
+				break;
+		}else if (rc == 0) {
+			if (n == 1)
+				return 0;
+			else
+				break;
+		} else {
+			if (errno == NOPOLL_EINTR) 
+				goto nopoll_readline_again;
+			if ((errno == NOPOLL_EWOULDBLOCK) || (errno == NOPOLL_EAGAIN) || (rc == -2)) {
+				if (n > 0) {
+					/* store content read until now */
+					if ((n + desp - 1) > 0) {
+						buffer[n+desp - 1] = 0;
+						conn->pending_line = nopoll_strdup (buffer);
+					} /* end if */
+				} /* end if */
+				return -2;
+			}
+
+			if (nopoll_conn_is_ok (conn) && errno == 0 && rc == 0) {
+				nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to read line, but errno is 0, and connection is ok, return to keep on trying..");
+				return -2;
+			}
+			
+			/* if the conn is closed, just return
+			 * without logging a message */
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to read line, error code errno: %d, rc: %d (%s)", 
+				    errno, rc, strerror (errno));
+			return (-1);
+		}
+	}
+	*ptr = 0;
+	return (n + desp);
+
+}
+
+/** 
+ * @brief Allows to get the master listener that was used to accept
+ * the provided connection that represents a listener connection.
+ *
+ * @param conn A listener connection that was accepted for which we
+ * want to get the master listener connection. The connection must be
+ * a \ref NOPOLL_ROLE_LISTENER (as reported by \ref nopoll_conn_role).
+ *
+ * @return A reference to the master listener connection or NULL if it
+ * fails. It can only fail when NULL reference is received or the
+ * connection is not a \ref NOPOLL_ROLE_LISTENER.
+ */
+noPollConn  * nopoll_conn_get_listener (noPollConn * conn)
+{
+	/* check if the incoming connection is a NOPOLL_ROLE_LISTENER
+	 * that is an accepted connection */
+	if (conn == NULL || conn->role != NOPOLL_ROLE_LISTENER)
+		return NULL;
+
+	return conn->listener;
+}
+
+void __nopoll_pack_content (char * buffer, int start, int bytes)
+{
+	int iterator = 0;
+	while (iterator < bytes) {
+		/* copy bytes to the begining of the array */
+		buffer[iterator] = buffer[start + iterator];
+		
+		/* next position */
+		iterator++;
+	} /* end while */
+
+	return;
+}
+
+/** 
+ * @internal Function used to read bytes from the wire. 
+ *
+ * @return The function returns the number of bytes read, 0 when no
+ * bytes were available and -1 when it fails.
+ */
+int         __nopoll_conn_receive  (noPollConn * conn, char  * buffer, int  maxlen)
+{
+	int         nread;
+
+	if (conn->pending_buf_bytes > 0) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Calling with bytes we can reuse (%d), requested: %d",
+			    conn->pending_buf_bytes, maxlen);
+
+		if (conn->pending_buf_bytes >= maxlen) {
+			/* we have more in the buffer to serve than
+			 * requested, ok, copy into the buffer and
+			 * pack */
+
+			memcpy (buffer, conn->pending_buf, maxlen);
+			__nopoll_pack_content (conn->pending_buf, maxlen, conn->pending_buf_bytes - maxlen);
+			conn->pending_buf_bytes -= maxlen;
+			return maxlen;
+		} 
+
+		/* ok, we don't have enough bytes to serve
+		 * directly, so copy what we have */
+		memcpy (buffer, conn->pending_buf, conn->pending_buf_bytes);
+
+		/* copy number of bytes served to reduce next request */
+		nread = conn->pending_buf_bytes;
+		conn->pending_buf_bytes = 0;
+
+		/* call again to get bytes reducing the request in the
+		 * amount of bytes served */
+		return __nopoll_conn_receive (conn, buffer + nread, maxlen - nread) + nread;
+		
+	} /* end if */
+
+ keep_reading:
+	/* clear buffer */
+	/* memset (buffer, 0, maxlen * sizeof (char )); */
+#if defined(NOPOLL_OS_UNIX)
+	errno = 0;
+#endif
+	if ((nread = conn->receive (conn, buffer, maxlen)) == NOPOLL_SOCKET_ERROR) {
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " returning errno=%d (%s)", errno, strerror (errno)); */
+		if (errno == NOPOLL_EAGAIN) 
+			return 0;
+		if (errno == NOPOLL_EWOULDBLOCK) 
+			return 0;
+		if (errno == NOPOLL_EINTR) 
+			goto keep_reading;
+		
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "unable to readn=%d, error code was: %d (%s) (shutting down connection)", maxlen, errno, strerror (errno));
+		nopoll_conn_shutdown (conn);
+		return -1;
+	}
+
+	/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, " returning bytes read = %d", nread); */
+	if (nread == 0) {
+		/* check for blocking operations */
+		if (errno == NOPOLL_EAGAIN || errno == NOPOLL_EWOULDBLOCK) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "unable to read from conn-id=%d (%s:%s), connection is not ready (errno: %d : %s)",
+				    conn->id, conn->host, conn->port, errno, strerror (errno));
+			return 0;
+		} /* end if */
+
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "received connection close while reading from conn id %d (errno=%d : %s) (%d, %d, %d), shutting down connection..", 
+			    conn->id, errno, strerror (errno),
+			    NOPOLL_EAGAIN, NOPOLL_EWOULDBLOCK, NOPOLL_EINTR);
+		nopoll_conn_shutdown (conn);
+	} /* end if */
+
+	/* ensure we don't access outside the array */
+	if (nread < 0) 
+		nread = 0;
+
+	buffer[nread] = 0;
+	return nread;
+}
+
+nopoll_bool nopoll_conn_get_http_url (noPollConn * conn, const char * buffer, int buffer_size, const char * method, char ** url)
+{
+	int          iterator;
+	int          iterator2;
+#if defined(SHOW_DEBUG_LOG)
+# if ! defined(SHOW_FORMAT_BUGS)
+	noPollCtx  * ctx = conn->ctx;
+# endif
+#endif
+
+	/* check if we already received method */
+	if (conn->get_url) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received GET method declartion when it was already received during handshake..closing session");
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	} /* end if */
+	
+	/* the get url must have a minimum size: GET / HTTP/1.1\r\n 16 (15 if only \n) */
+	if (buffer_size < 15) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received uncomplete GET method during handshake, closing session");
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	} /* end if */
+	
+	/* skip white spaces */
+	iterator = 4;
+	while (iterator <  buffer_size && buffer[iterator] == ' ') 
+		iterator++;
+	if (buffer_size == iterator) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method without an starting request url, closing session", method);
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	} /* end if */
+
+	/* now check url format */
+	if (buffer[iterator] != '/') {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with a request url that do not start with /, closing session", method);
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	}
+	
+	/* ok now find the rest of the url content util the next white space */
+	iterator2 = (iterator + 1);
+	while (iterator2 <  buffer_size && buffer[iterator2] != ' ') 
+		iterator2++;
+	if (buffer_size == iterator2) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with an uncomplate request url, closing session", method);
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	} /* end if */
+	
+	(*url) = nopoll_new (char, iterator2 - iterator + 1);
+	memcpy (*url, buffer + iterator, iterator2 - iterator);
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Found url method: '%s'", *url);
+
+	/* now check final HTTP header */
+	iterator = iterator2 + 1;
+	while (iterator <  buffer_size && buffer[iterator] == ' ') 
+		iterator++;
+	if (buffer_size == iterator) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received a %s method with an uncomplate request url, closing session", method);
+		nopoll_conn_shutdown (conn);
+		return nopoll_false;
+	} /* end if */
+
+	/* now check trailing content */
+	return nopoll_cmp (buffer + iterator, "HTTP/1.1\r\n") || nopoll_cmp (buffer + iterator, "HTTP/1.1\n");
+}
+
+/** 
+ * @internal Function that parses the mime header found on the
+ * provided buffer.
+ */
+nopoll_bool nopoll_conn_get_mime_header (noPollCtx * ctx, noPollConn * conn, const char * buffer, int buffer_size, char ** header, char ** value)
+{
+	int iterator = 0;
+	int iterator2 = 0;
+
+	if (buffer_size < 3) {
+	        nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Expected to find mime header content (but buffer size %d was found)", buffer_size);
+		return nopoll_false;
+	}
+
+	/* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Processing content: %s", buffer); */
+	
+	/* ok, find the first : */
+	while (iterator < buffer_size && buffer[iterator] && buffer[iterator] != ':')
+		iterator++;
+	if (buffer[iterator] != ':') {
+	        /* ensure print always ends */
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Expected to find mime header separator : but it wasn't found, buffer_size=%d, iterator=%d..",
+			    buffer_size, iterator);
+		return nopoll_false;
+	} 
+
+	/* copy the header value */
+	(*header) = nopoll_new (char, iterator + 1);
+	memcpy (*header, buffer, iterator);
+	
+	/* now get the mime header value */
+	iterator2 = iterator + 1;
+	while (iterator2 < buffer_size && buffer[iterator2] && buffer[iterator2] != '\n')
+		iterator2++;
+	if (buffer[iterator2] != '\n') {
+	        nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 
+			    "Expected to find mime header value end (13) but it wasn't found (iterator=%d, iterator2=%d, buffer_size=%d, for header: [%s], found value: [%d])..",
+			    iterator, iterator2, buffer_size, (*header), (int)buffer[iterator2]);
+		nopoll_free (*header);
+		(*header) = NULL;
+		(*value)  = NULL;
+		return nopoll_false;
+	} 
+
+	/* copy the value */
+	(*value) = nopoll_new (char, (iterator2 - iterator) + 1);
+	memcpy (*value, buffer + iterator + 1, iterator2 - iterator);
+
+	/* trim content */
+	nopoll_trim (*value, NULL);
+	nopoll_trim (*header, NULL);
+	
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Found MIME header: '%s' -> '%s'", *header, *value);
+	return nopoll_true;
+}
+
+/** 
+ * @internal Function that ensures we don't receive any 
+ */ 
+nopoll_bool nopoll_conn_check_mime_header_repeated (noPollConn   * conn, 
+						    char         * header, 
+						    char         * value, 
+						    const char   * ref_header, 
+						    noPollPtr      check)
+{
+	if (strcasecmp (ref_header, header) == 0) {
+		if (check) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Provided header %s twice, closing connection", header);
+			nopoll_free (header);
+			nopoll_free (value);
+			nopoll_conn_shutdown (conn);
+			return nopoll_true;
+		} /* end if */
+	} /* end if */
+	return nopoll_false;
+}
+
+char * nopoll_conn_produce_accept_key (noPollCtx * ctx, const char * websocket_key)
+{
+	const char    * static_guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";	
+	char          * accept_key;	
+	int             accept_key_size;
+	int             key_length;
+
+#if NOPOLL_OS_RTTHREAD
+#define SHA_BUF_SZ	20
+	unsigned char   buffer[SHA_BUF_SZ];
+	sha1_context sha1_ctx;
+	unsigned int    md_len = SHA_BUF_SZ;
+
+	if (websocket_key == NULL)
+		return NULL;
+
+	key_length  = strlen (websocket_key);
+
+	accept_key_size = key_length + 36 + 1;
+	accept_key      = nopoll_new (char, accept_key_size);
+
+	memcpy (accept_key, websocket_key, key_length);
+	memcpy (accept_key + key_length, static_guid, 36);
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "base key value: %s", accept_key);
+
+	/* now sha-1 */
+    sha1_starts( &sha1_ctx );
+    sha1_update( &sha1_ctx, accept_key, strlen (accept_key) );
+    sha1_finish( &sha1_ctx, buffer );
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sha-1 length is: %u", md_len);
+	/* now convert into base64 */
+	if (! nopoll_base64_encode ((const char *) buffer, md_len, (char *) accept_key, &accept_key_size)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to base64 sec-websocket-key value..");
+		return NULL;
+	}
+#else
+	unsigned char   buffer[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX      mdctx;
+	const EVP_MD  * md = NULL;
+	unsigned int    md_len = EVP_MAX_MD_SIZE;
+
+	if (websocket_key == NULL)
+		return NULL;
+
+	key_length  = strlen (websocket_key);
+
+	accept_key_size = key_length + 36 + 1;
+	accept_key      = nopoll_new (char, accept_key_size);
+
+	memcpy (accept_key, websocket_key, key_length);
+	memcpy (accept_key + key_length, static_guid, 36);
+	
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "base key value: %s", accept_key);
+
+	/* now sha-1 */
+	md = EVP_sha1 ();
+	EVP_DigestInit (&mdctx, md);
+	EVP_DigestUpdate (&mdctx, accept_key, strlen (accept_key));
+	EVP_DigestFinal (&mdctx, buffer, &md_len);
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sha-1 length is: %u", md_len);
+	/* now convert into base64 */
+	if (! nopoll_base64_encode ((const char *) buffer, md_len, (char *) accept_key, &accept_key_size)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to base64 sec-websocket-key value..");
+		return NULL;
+	}
+#endif
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Returning Sec-Websocket-Accept: %s", accept_key);
+	
+	return accept_key;
+	
+}
+
+nopoll_bool __nopoll_conn_call_on_ready_if_defined (noPollCtx * ctx, noPollConn * conn)
+{
+	noPollActionHandler    on_ready;
+	noPollPtr              on_ready_data;
+
+	if (ctx == NULL || conn == NULL)
+		return nopoll_false; /* this should never happen */
+
+	if (ctx->on_ready || conn->on_ready) {
+		/* set on ready handler, first considering conn->on_ready and then ctx->on_ready */
+		on_ready      = conn->on_ready;
+		on_ready_data = conn->on_ready_data;
+		if (! on_ready) {
+			on_ready      = ctx->on_ready;
+			on_ready_data = ctx->on_ready_data;
+		} /* end if */
+
+		if (on_ready &&  ! on_ready (ctx, conn, on_ready_data)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Peer from %s:%s was denied by application level (on ready handler: %p), clossing session", 
+				    conn->host, conn->port, on_ready);
+			nopoll_conn_shutdown (conn);
+			return nopoll_false;
+		}
+	} /* end if */
+
+	/* reached this point, return ok status (even if we have or no
+	   on ready function defined) */
+	return nopoll_true;
+
+}
+
+nopoll_bool nopoll_conn_complete_handshake_check_listener (noPollCtx * ctx, noPollConn * conn)
+{
+	char                 * reply;
+	int                    reply_size;
+	char                 * accept_key;
+	const char           * protocol;
+	nopoll_bool            origin_check;
+
+	/* call to check listener handshake */
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking client handshake data..");
+
+	/* update default origin check (Origin: header must be
+	 * defined, event though RFC says SHOULD it should have been
+	 * MUST because other wise, server side cannot check this
+	 * value which is crucial for security reasons */
+	origin_check = conn->origin != NULL;
+
+	/* now, update this origin_check in the case it is not defined
+	 * and origin header skip was enabled */
+	if ( conn->listener && conn->listener->opts && conn->listener->opts->skip_origin_header_check && conn->origin == NULL)
+		origin_check = nopoll_true;
+	
+
+	/* ensure we have all minumum data */
+	if (! conn->handshake->upgrade_websocket ||
+	    ! conn->handshake->connection_upgrade ||
+	    ! conn->handshake->websocket_key ||
+	    ! origin_check ||  /* see above */
+	    ! conn->handshake->websocket_version) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Client from %s:%s didn't provide all websocket handshake values required, closing session (Upgraded: websocket %d, Connection: upgrade%d, Sec-WebSocket-Key: %p, Origin: %p, Sec-WebSocket-Version: %p)",
+			    conn->host, conn->port,
+			    conn->handshake->upgrade_websocket,
+			    conn->handshake->connection_upgrade,
+			    conn->handshake->websocket_key,
+			    conn->origin,
+			    conn->handshake->websocket_version);
+		return nopoll_false;
+	} /* end if */
+
+	/* check protocol support */
+	if (strtod (conn->handshake->websocket_version, NULL) != ctx->protocol_version) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received request for an unsupported protocol version: %s, expected: %d",
+			    conn->handshake->websocket_version, ctx->protocol_version);
+		return nopoll_false;
+	} /* end if */
+	
+	/* now call the user app level to accept the websocket
+	   connection */
+	if (ctx->on_open) {
+		if (! ctx->on_open (ctx, conn, ctx->on_open_data)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Client from %s:%s was denied by application level (on open handler %p), clossing session", 
+				    conn->host, conn->port, ctx->on_open);
+			nopoll_conn_shutdown (conn);
+			return nopoll_false;
+		}
+	} /* end if */
+	
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Client from %s:%s was accepted, replying accept",
+		    conn->host, conn->port);
+
+	/* produce accept key */
+	accept_key = nopoll_conn_produce_accept_key (ctx, conn->handshake->websocket_key);
+	
+	/* ok, send handshake reply */
+	if (conn->protocols || conn->accepted_protocol) {
+		/* set protocol in the reply taking preference by the
+		   value configured at conn->accepted_protocol */
+		protocol = conn->accepted_protocol;
+		if (! protocol)
+			protocol = conn->protocols;
+
+		/* send accept header accepting protocol requested by the user */
+		reply = nopoll_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\nSec-WebSocket-Protocol: %s\r\n\r\n", 
+					      accept_key, protocol);
+	} else {
+		/* send accept header without telling anything about protocols */
+		reply = nopoll_strdup_printf ("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n", 
+					      accept_key);
+	}
+		
+	nopoll_free (accept_key);
+	if (reply == NULL) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to build reply, closing session");
+		return nopoll_false;
+	} /* end if */
+	
+	reply_size = strlen (reply);
+	if (reply_size != conn->send (conn, reply, reply_size)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to send reply, there was a failure, error code was: %d", errno);
+		nopoll_free (reply);
+		return nopoll_false;
+	} /* end if */
+	
+	/* free reply */
+	nopoll_free (reply);
+
+	/* now call the user app level to accept the websocket
+	   connection */
+	if (! __nopoll_conn_call_on_ready_if_defined (ctx, conn))
+		return nopoll_false;
+	
+	return nopoll_true; /* signal handshake was completed */
+}
+
+nopoll_bool nopoll_conn_complete_handshake_check_client (noPollCtx * ctx, noPollConn * conn)
+{
+	char         * accept;
+	nopoll_bool    result;
+
+	/* check all data received */
+	if (! conn->handshake->websocket_accept ||
+	    ! conn->handshake->upgrade_websocket ||
+	    ! conn->handshake->connection_upgrade) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received uncomplete listener handshake reply (%p %d %d)",
+			    conn->handshake->websocket_accept, conn->handshake->upgrade_websocket, conn->handshake->connection_upgrade);
+		return nopoll_false;
+	} /* end if */
+
+	/* check accept value here */
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Checking accept key from listener..");
+	accept = nopoll_conn_produce_accept_key (ctx, conn->handshake->websocket_key);
+	
+	result = nopoll_cmp (accept, conn->handshake->websocket_key);
+	if (! result) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept connection Sec-Websocket-Accept %s is not expected %s, closing session",
+			    accept, conn->handshake->websocket_key);
+		nopoll_conn_shutdown (conn);
+	}
+	nopoll_free (accept);
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Sec-Websocket-Accept matches expected value..nopoll_conn_complete_handshake_check_client (%p, %p)=%d",
+		    ctx, conn, result);
+
+	/* now call the user app level to accept the websocket
+	   connection */
+	if (! __nopoll_conn_call_on_ready_if_defined (ctx, conn))
+		return nopoll_false;
+
+	return result;
+}
+
+
+/** 
+ * @internal Function used to validate all handshake received until
+ * now.
+ */
+void nopoll_conn_complete_handshake_check (noPollConn * conn)
+{
+	noPollCtx    * ctx    = conn->ctx;
+	nopoll_bool    result = nopoll_false;
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "calling to check handshake received on connection id %d role %d..",
+		    conn->id, conn->role);
+
+	if (conn->role == NOPOLL_ROLE_LISTENER) {
+		result = nopoll_conn_complete_handshake_check_listener (ctx, conn);
+	} else if (conn->role == NOPOLL_ROLE_CLIENT) {
+		result = nopoll_conn_complete_handshake_check_client (ctx, conn);
+	} /* end if */
+
+	/* flag connection as ready: now we can get messages */
+	if (result) {
+		conn->handshake_ok = nopoll_true;
+	} else {
+		nopoll_conn_shutdown (conn);
+	} /* end if */
+
+	return;
+}
+
+/** 
+ * @internal Handler that implements one step of the websocket
+ * listener handshake received from client, until it is completed.
+ *
+ * @return Returns 0 to return (because error or because no data is
+ * available) or 1 to signal the caller continue reading if it is
+ * possible.
+ */
+int nopoll_conn_complete_handshake_listener (noPollCtx * ctx, noPollConn * conn, char * buffer, int buffer_size)
+{
+	char * header;
+	char * value;
+
+	/* handle content */
+	if (nopoll_ncmp (buffer, "GET ", 4)) {
+		/* get url method */
+		nopoll_conn_get_http_url (conn, buffer, buffer_size, "GET", &conn->get_url);
+		return 1;
+	} /* end if */
+
+	/* get mime header */
+	if (! nopoll_conn_get_mime_header (ctx, conn, buffer, buffer_size, &header, &value)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to acquire mime header from remote peer during handshake, closing connection");
+		nopoll_conn_shutdown (conn);
+		return 0;
+	}
+		
+	/* ok, process here predefined headers */
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Host", conn->host_name))
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Upgrade", INT_TO_PTR (conn->handshake->upgrade_websocket))) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Connection", INT_TO_PTR (conn->handshake->connection_upgrade))) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Key", conn->handshake->websocket_key)) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Origin", conn->origin)) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Protocol", conn->protocols)) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Version", conn->handshake->websocket_version)) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Cookie", conn->handshake->cookie)) 
+		return 0;
+	
+	/* set the value if required */
+	if (strcasecmp (header, "Host") == 0)
+		conn->host_name = value;
+	else if (strcasecmp (header, "Sec-Websocket-Key") == 0)
+		conn->handshake->websocket_key = value;
+	else if (strcasecmp (header, "Origin") == 0)
+		conn->origin = value;
+	else if (strcasecmp (header, "Sec-Websocket-Protocol") == 0)
+		conn->protocols = value;
+	else if (strcasecmp (header, "Sec-Websocket-Version") == 0)
+		conn->handshake->websocket_version = value;
+	else if (strcasecmp (header, "Upgrade") == 0) {
+		conn->handshake->upgrade_websocket = 1;
+		nopoll_free (value);
+	} else if (strcasecmp (header, "Connection") == 0) {
+		conn->handshake->connection_upgrade = 1;
+		nopoll_free (value);
+	} else if (strcasecmp (header, "Cookie") == 0) {
+		/* record cookie so it can be used by the application level */
+		conn->handshake->cookie = value;
+	} else {
+		/* release value, no body claimed it */
+		nopoll_free (value);
+	} /* end if */
+	
+	/* release the header */
+	nopoll_free (header);
+
+	return 1; /* continue reading lines */
+}
+
+/** 
+ * @internal Handler that implements one step of the websocket
+ * client handshake received from the server, until it is completed. 
+ *
+ * @return Returns 0 to return (because error or because no data is
+ * available) or 1 to signal the caller continue reading if it is
+ * possible.
+ */
+int nopoll_conn_complete_handshake_client (noPollCtx * ctx, noPollConn * conn, char * buffer, int buffer_size)
+{
+	char * header;
+	char * value;
+	int    iterator;
+
+	/* handle content */
+	if (! conn->handshake->received_101 && nopoll_ncmp (buffer, "HTTP/1.1 ", 9)) {
+		iterator = 9;
+		while (iterator < buffer_size && buffer[iterator] && buffer[iterator] == ' ')
+			iterator++;
+		if (! nopoll_ncmp (buffer + iterator, "101", 3)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "websocket server denied connection with: %s", buffer + iterator);
+			return 0; /* do not continue */
+		} /* end if */
+
+		/* flag that we have received HTTP/1.1 101 indication */
+		conn->handshake->received_101 = nopoll_true;
+
+		return 1;
+	} /* end if */
+
+	/* get mime header */
+	if (! nopoll_conn_get_mime_header (ctx, conn, buffer, buffer_size, &header, &value)) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to acquire mime header from remote peer during handshake, closing connection");
+		nopoll_conn_shutdown (conn);
+		return 0;
+	}
+		
+	/* ok, process here predefined headers */
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Upgrade", INT_TO_PTR (conn->handshake->upgrade_websocket))) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Connection", INT_TO_PTR (conn->handshake->connection_upgrade))) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Accept", conn->handshake->websocket_accept)) 
+		return 0;
+	if (nopoll_conn_check_mime_header_repeated (conn, header, value, "Sec-WebSocket-Protocol", conn->accepted_protocol)) 
+		return 0;
+	
+	/* set the value if required */
+	if (strcasecmp (header, "Sec-Websocket-Accept") == 0)
+		conn->handshake->websocket_accept = value;
+	else if (strcasecmp (header, "Sec-Websocket-Protocol") == 0)
+		conn->accepted_protocol = value;
+	else if (strcasecmp (header, "Upgrade") == 0) {
+		conn->handshake->upgrade_websocket = 1;
+		nopoll_free (value);
+	} else if (strcasecmp (header, "Connection") == 0) {
+		conn->handshake->connection_upgrade = 1;
+		nopoll_free (value);
+	} else {
+		/* release value, no body claimed it */
+		nopoll_free (value);
+	} /* end if */
+	
+	/* release the header */
+	nopoll_free (header);
+
+	return 1; /* continue reading lines */
+}
+
+/** 
+ * @internal Function that completes the handshake in an non-blocking
+ * manner taking into consideration the connection type (listener or
+ * client).
+ */
+void nopoll_conn_complete_handshake (noPollConn * conn)
+{
+	/* for NOPOLL_HANDSHAKE_BUFFER_SIZE definition, see
+	   nopoll_decl.h */
+	char        *buffer = 0;
+	int         buffer_size;
+	noPollCtx * ctx = conn->ctx;
+
+	/* ensure we didn't complete handshake */
+	if (conn->handshake_ok)
+		return;
+
+	buffer = nopoll_calloc(1, NOPOLL_HANDSHAKE_BUFFER_SIZE);
+	if (!buffer)
+		return;
+	
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Checking to complete conn-id=%d WebSocket handshake, role %d", conn->id, conn->role);
+
+	/* ensure handshake object is created */
+	if (conn->handshake == NULL)
+		conn->handshake = nopoll_new (noPollHandShake, 1);
+
+	/* get lines and complete the handshake data */
+	while (nopoll_true) {
+		/* clear buffer for debugging functions */
+		buffer[0] = 0;
+
+		/* get next line to process: for
+		   NOPOLL_HANDSHAKE_BUFFER_SIZE definition, see
+		   nopoll_decl.h */
+		buffer_size = nopoll_conn_readline (conn, buffer, NOPOLL_HANDSHAKE_BUFFER_SIZE);
+		if (buffer_size == 0 || buffer_size == -1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unexpected connection close during handshake..closing connection");
+			nopoll_conn_shutdown (conn);
+			nopoll_free(buffer);
+			return;
+		} /* end if */
+
+		/* no data at this moment, return to avoid consuming data */
+		if (buffer_size == -2) {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "No more data available on connection id %d", conn->id);
+			nopoll_free(buffer);
+			return;
+		}
+
+		/* drop a debug line */
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Bytes read %d from connection id %d: %s", buffer_size, conn->id, buffer);  
+			
+		/* check if we have received the end of the
+		   websocket client handshake */
+		if (buffer_size == 2 && nopoll_ncmp (buffer, "\r\n", 2)) {
+			nopoll_conn_complete_handshake_check (conn);
+			nopoll_free(buffer);
+			return;
+		}
+
+		if (conn->role == NOPOLL_ROLE_LISTENER) {
+			/* call to complete listener handshake */
+			if (nopoll_conn_complete_handshake_listener (ctx, conn, buffer, buffer_size) == 1)
+				continue;
+		} else if (conn->role == NOPOLL_ROLE_CLIENT) {
+			/* call to complete listener handshake */
+			if (nopoll_conn_complete_handshake_client (ctx, conn, buffer, buffer_size) == 1)
+				continue;
+		} else {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Called to handle connection handshake on a connection with an unexpected role: %d, closing session",
+				    conn->role);
+			nopoll_conn_shutdown (conn);
+			nopoll_free(buffer);
+			return;
+		}
+	} /* end while */
+
+	nopoll_free(buffer);
+	
+	return;
+}
+
+void nopoll_conn_mask_content (noPollCtx * ctx, char * payload, int payload_size, char * mask, int desp)
+{
+	int iter       = 0;
+	int mask_index = 0;
+
+	while (iter < payload_size) {
+		/* rotate mask and apply it */
+		mask_index = (iter + desp) % 4;
+		payload[iter] ^= mask[mask_index];
+		iter++;
+	} /* end while */
+
+	return;
+} 
+
+
+/** 
+ * @brief Allows to get the next message available on the provided
+ * connection. The function returns NULL in the case no message is
+ * still ready to be returned. 
+ *
+ * The function do not block. 
+ *
+ * @param conn The connection where the read operation will take
+ * place.
+ * 
+ * @return A reference to a noPollMsg object or NULL if there is
+ * nothing available. In case the function returns NULL, check
+ * connection status with \ref nopoll_conn_is_ok.
+ */
+noPollMsg   * nopoll_conn_get_msg (noPollConn * conn)
+{
+	char        buffer[20];
+	int         bytes;
+	noPollMsg * msg;
+	int         ssl_error;
+	int         header_size;
+#if defined(SHOW_DEBUG_LOG)
+	long        result;
+#endif
+	unsigned char *len;
+
+	if (conn == NULL)
+		return NULL;
+
+#if NOPOLL_TLS
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, 
+		    "=== START: conn-id=%d (errno=%d, session: %d, conn->handshake_ok: %d, conn->pending_ssl_accept: %d) ===", 
+		    conn->id, errno, conn->session, conn->handshake_ok, conn->pending_ssl_accept);
+	
+	/* check for accept SSL connection */
+	if (conn->pending_ssl_accept) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received connect over a connection (id %d) with TLS handshake pending to be finished, processing..",
+			    conn->id);
+
+		/* get ssl error */
+		ssl_error = SSL_accept (conn->ssl);
+		if (ssl_error == -1) {
+			/* get error */
+			ssl_error = SSL_get_error (conn->ssl, -1);
+ 
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "accept function have failed (for listener side) ssl_error=%d : dumping error stack..", ssl_error);
+ 
+			switch (ssl_error) {
+			case SSL_ERROR_WANT_READ:
+			        nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because read wanted conn-id=%d (%p, session %d)",
+					    conn->id, conn, conn->session);
+				return NULL;
+			case SSL_ERROR_WANT_WRITE:
+			        nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "still not prepared to continue because write wanted conn-id=%d (%p)",
+					    conn->id, conn);
+				return NULL;
+			default:
+				break;
+			} /* end switch */
+
+			/* TLS-fication process have failed */
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "there was an error while accepting TLS connection");
+			nopoll_conn_log_ssl (conn);
+			nopoll_conn_shutdown (conn);
+			return NULL;
+		} /* end if */
+
+		/* ssl accept */
+		conn->pending_ssl_accept = nopoll_false;
+		nopoll_conn_set_sock_block (conn->session, nopoll_false);
+
+#if defined(SHOW_DEBUG_LOG)
+		result = SSL_get_verify_result (conn->ssl);
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Completed TLS operation from %s:%s (conn id %d, ssl veriry result: %d)",
+			    conn->host, conn->port, conn->id, (int) result);
+#endif
+
+		/* configure default handlers */
+		conn->receive = nopoll_conn_tls_receive;
+		conn->send    = nopoll_conn_tls_send;
+
+		/* call to check post ssl checks after SSL finalization */
+		if (conn->ctx && conn->ctx->post_ssl_check) {
+			if (! conn->ctx->post_ssl_check (conn->ctx, conn, conn->ssl_ctx, conn->ssl, conn->ctx->post_ssl_check_data)) {
+				/* TLS post check failed */
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "TLS/SSL post check function failed, dropping connection");
+				nopoll_conn_shutdown (conn);
+				return NULL;
+			} /* end if */
+		} /* end if */
+
+		/* set this connection has TLS ok */
+		conn->tls_on  = nopoll_true;
+
+#if defined(NOPOLL_OS_UNIX)
+		/* report NULL because this was a call to complete TLS */
+		errno = NOPOLL_EWOULDBLOCK; /* simulate there is no data available to stop
+					       here. If there is no data indeed, on next
+					       call it will not fail */
+#endif
+		return NULL;
+		
+	} /* end if */
+#endif
+
+	/* check connection status */
+	if (! conn->handshake_ok) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Connection id %d handshake is not complete, running..", conn->id);
+		/* acquire here handshake mutex */
+		nopoll_mutex_lock (conn->ref_mutex);
+
+		/* complete handshake */
+		nopoll_conn_complete_handshake (conn);
+
+		/* release here handshake mutex */
+		nopoll_mutex_unlock (conn->ref_mutex);
+
+		if (! conn->handshake_ok) 
+			return NULL;
+	} /* end if */
+
+	if (conn->previous_msg) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Reading bytes (previously read %d) from a previous unfinished frame (pending: %d) over conn-id=%d",
+			    conn->previous_msg->payload_size, conn->previous_msg->remain_bytes, conn->id);
+
+		if (conn->read_pending_header) {
+			/* detected pending read header, continue from here */
+			msg                       = conn->previous_msg;
+			conn->previous_msg        = NULL;
+			conn->read_pending_header = nopoll_false;
+			goto read_pending_header;
+		} /* end if */
+		
+		/* build next message holder to continue with this content */
+		if (conn->previous_msg->payload_size > 0) {
+			msg = nopoll_msg_new ();
+			if (msg == NULL) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to allocate memory for received message, closing session id: %d", 
+					    conn->id);
+				nopoll_conn_shutdown (conn);
+				return NULL;
+			} /* end if */
+
+			/* flag this message as a fragment */
+			msg->is_fragment = nopoll_true;
+
+			/* get fin bytes */
+			msg->has_fin      = 1; /* for now final message */
+			msg->op_code      = 0; /* continuation frame */
+
+			/* copy initial mask indication */
+			msg->is_masked    = conn->previous_msg->is_masked;
+			msg->payload_size = conn->previous_msg->remain_bytes;
+			msg->unmask_desp  = conn->previous_msg->unmask_desp;
+
+			/* copy mask */
+			memcpy (msg->mask, conn->previous_msg->mask, 4);
+			
+			if (msg->is_masked) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Reusing mask value = %d from previous frame (%d)", nopoll_get_32bit (msg->mask));
+				nopoll_show_byte (conn->ctx, msg->mask[0], "mask[0]");
+				nopoll_show_byte (conn->ctx, msg->mask[1], "mask[1]");
+				nopoll_show_byte (conn->ctx, msg->mask[2], "mask[2]");
+				nopoll_show_byte (conn->ctx, msg->mask[3], "mask[3]");
+			}
+
+			/* release previous reference because de don't need it anymore */
+			nopoll_msg_unref (conn->previous_msg);
+		} else {
+			/* reuse reference */
+			msg = conn->previous_msg;
+
+			/* update remaining bytes */
+			msg->payload_size = msg->remain_bytes;
+			nopoll_free (msg->payload);
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "reusing noPollMsg reference (%p) since last payload read was 0, remaining: %d", msg,
+				    msg->payload_size);
+		}
+
+		/* nullify references */
+		conn->previous_msg      = NULL;
+
+		goto read_payload;
+		
+	} /* end if */
+
+	/*
+	  0                   1                   2                   3
+	  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+	  +-+-+-+-+-------+-+-------------+-------------------------------+
+	  |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
+	  |I|S|S|S|  (4)  |A|     (7)     |             (16/63)           |
+	  |N|V|V|V|       |S|             |   (if payload len==126/127)   |
+	  | |1|2|3|       |K|             |                               |
+	  +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+	  |     Extended payload length continued, if payload len == 127  |
+	  + - - - - - - - - - - - - - - - +-------------------------------+
+	  |                               |Masking-key, if MASK set to 1  |
+	  +-------------------------------+-------------------------------+
+	  | Masking-key (continued)       |          Payload Data         |
+	  +-------------------------------- - - - - - - - - - - - - - - - +
+	  :                     Payload Data continued ...                :
+	  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+	  |                     Payload Data continued ...                |
+	  +---------------------------------------------------------------+
+	*/
+	/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Found data in opened connection id %d..", conn->id);*/ 
+
+	/* get the first 2 bytes from the websocket header */
+	bytes = __nopoll_conn_receive (conn, buffer, 2);
+	if (bytes == 0) {
+		/* connection not ready */
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Connection id=%d without data, errno=%d : %s, returning no message", 
+			    conn->id, errno, strerror (errno));
+		return NULL;
+	}
+
+	if (bytes <= 0) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received connection close, finishing connection session");
+		nopoll_conn_shutdown (conn);
+		return NULL;
+	} /* end if */
+
+	if (bytes != 2) { 
+		/* ok, store content read into the pending buffer for next call */
+		memcpy (conn->pending_buf + conn->pending_buf_bytes, buffer, bytes);
+		conn->pending_buf_bytes += bytes;
+		
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, 
+			    "Expected to receive complete websocket frame header but found only %d bytes over conn-id=%d, saving to reuse later",
+			    bytes, conn->id);
+		return NULL;
+	} /* end if */
+
+	/* record header size */
+	header_size = 2;
+
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received %d bytes for websocket header", bytes);
+	nopoll_show_byte (conn->ctx, buffer[0], "header[0]");
+	nopoll_show_byte (conn->ctx, buffer[1], "header[1]");
+
+	/* build next message */
+	msg = nopoll_msg_new ();
+	if (msg == NULL) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to allocate memory for received message, closing session id: %d", 
+			    conn->id);
+		nopoll_conn_shutdown (conn);
+		return NULL;
+	} /* end if */
+
+	/* get fin bytes */
+	msg->has_fin      = nopoll_get_bit (buffer[0], 7);
+	msg->op_code      = buffer[0] & 0x0F;
+	msg->is_masked    = nopoll_get_bit (buffer[1], 7);
+	msg->payload_size = buffer[1] & 0x7F;
+
+	/* ensure FIN = 1 in case we are listener */
+	if (conn->role == NOPOLL_ROLE_LISTENER && ! msg->is_masked) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received websocket frame with mask bit set to zero, closing session id: %d", 
+			    conn->id);
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL;
+	} /* end if */
+
+	/* check payload size value */
+	if (msg->payload_size < 0) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received wrong payload size at first 7 bits, closing session id: %d", 
+			    conn->id);
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL;
+	} /* end if */
+
+ read_pending_header:
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "interim payload size received: %d", (int) msg->payload_size);
+
+	/* read the rest */
+	if (msg->payload_size < 126) {
+		/* nothing to declare here */
+
+	} else if (msg->payload_size == 126) {
+		/* get extended 2 bytes length as unsigned 16 bit
+		   unsigned integer */
+		bytes = __nopoll_conn_receive (conn, buffer + 2, 2);
+		if (bytes != 2) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Failed to get next 2 bytes to read header from the wire, but received=%d, failed to received content, shutting down id=%d the connection, errno=%d (%s)",
+				    bytes, conn->id, errno, strerror (errno));
+			if (errno == NOPOLL_EWOULDBLOCK || errno == 0) { 
+				/* connection is not ready at this point */
+				conn->previous_msg = msg;
+				conn->read_pending_header = nopoll_true;
+
+				/* check amount of bytes to reuse them */
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Detected broken WebSocket peer sending header content using different frames, trying to save and resume later");
+				if (bytes > 0) {
+					/* ok, store content read into the pending buffer for next call */
+					memcpy (conn->pending_buf + conn->pending_buf_bytes, buffer + 2, bytes);
+					conn->pending_buf_bytes += bytes;
+				}
+				
+				return NULL;
+			}
+
+			nopoll_msg_unref (msg);
+			nopoll_conn_shutdown (conn);
+			return NULL; 	
+		} /* end if */
+
+		/* add to the header bytes read */
+		header_size += bytes;
+			
+		msg->payload_size = nopoll_get_16bit (buffer + 2);
+
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received (%d) bytes in header (size %d) for payload size indication, which finally is: %d", bytes, header_size,(int) msg->payload_size);
+		
+	} else if (msg->payload_size == 127) {
+		/* read more content (next 8 bytes) */
+		if ((bytes = __nopoll_conn_receive (conn, buffer, 8)) != 8) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, 
+				    "Expected to receive next 6 bytes for websocket frame header but found only %d bytes, closing session: %d",
+				    bytes, conn->id);
+			nopoll_conn_shutdown (conn);
+			return NULL;
+		} /* end if */
+
+		len = (unsigned char*)buffer;
+		msg->payload_size = 0;
+#if defined(NOPOLL_64BIT_PLATFORM)
+		msg->payload_size |= ((long)(len[0]) << 56);
+		msg->payload_size |= ((long)(len[1]) << 48);
+		msg->payload_size |= ((long)(len[2]) << 40);
+		msg->payload_size |= ((long)(len[3]) << 32);
+#else
+		if (len[0] || len[1] || len[2] || len[3]) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "noPoll doesn't support messages bigger than 2GB on this plataform (support for 64bit not found)");
+			nopoll_msg_unref (msg);
+			nopoll_conn_shutdown (conn);
+			return NULL;
+		}
+#endif
+		msg->payload_size |= ((long)(len[4]) << 24);
+		msg->payload_size |= ((long)(len[5]) << 16);
+		msg->payload_size |= ((long)(len[6]) << 8);
+		msg->payload_size |= len[7];
+	} /* end if */
+
+	if (msg->op_code == NOPOLL_PONG_FRAME) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "PONG received over connection id=%d", conn->id);
+		nopoll_msg_unref (msg);
+		return NULL;
+	} /* end if */
+
+	if (msg->op_code == NOPOLL_CLOSE_FRAME) {
+		if (msg->payload_size == 0) {
+			/* nothing more to add here, close frame
+			   without content received, so we have no
+			   reason to keep on reading */
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Proper connection close frame received id=%d, shutting down", conn->id);
+			nopoll_msg_unref (msg);
+			nopoll_conn_shutdown (conn);
+			return NULL;
+		} /* end if */
+
+		/* received close frame with content, try to read the content */
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Proper connection close frame received id=%d with content bytes=%d, reading reason..", 
+			    conn->id, msg->payload_size);
+	} /* end if */
+
+	/* get more bytes */
+	if (msg->is_masked) {
+		bytes = __nopoll_conn_receive (conn, (char *) msg->mask, 4);
+		if (bytes != 4) {
+			/* record header read so far */
+			memcpy (conn->pending_buf, buffer, header_size);
+			conn->pending_buf_bytes = header_size;
+			/* record mask read so far if required */
+			if (bytes > 0) {
+				memcpy (conn->pending_buf + header_size, msg->mask, bytes);
+				conn->pending_buf_bytes += bytes;
+			} /* end if */
+
+			/* release message because it not available here */
+			nopoll_msg_unref (msg);
+			if (bytes >= 0 && nopoll_conn_is_ok (conn)) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, 
+					    "Expected to receive incoming mask after header (4 bytes) but found %d bytes on conn-id=%d, saving %d for future operations ", 
+					    bytes, conn->id, conn->pending_buf_bytes);
+				return NULL;
+			} /* end if */
+
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Expected to receive incoming mask after header (4 bytes) but found %d bytes, shutting down id=%d the connection", 
+				    bytes, conn->id);
+			nopoll_conn_shutdown (conn);
+			return NULL; 
+		} /* end if */
+		
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received mask value = %d", nopoll_get_32bit (msg->mask));
+		nopoll_show_byte (conn->ctx, msg->mask[0], "mask[0]");
+		nopoll_show_byte (conn->ctx, msg->mask[1], "mask[1]");
+		nopoll_show_byte (conn->ctx, msg->mask[2], "mask[2]");
+		nopoll_show_byte (conn->ctx, msg->mask[3], "mask[3]");
+	} /* end if */
+
+	/* check payload size */
+	if (msg->payload_size == 0) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found incoming frame with payload size 0, shutting down id=%d the connection", conn->id);
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL; 	
+	} /* end if */
+
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Detected incoming websocket frame: fin(%d), op_code(%d), is_masked(%d), payload size(%ld), mask=%d", 
+		    msg->has_fin, msg->op_code, msg->is_masked, msg->payload_size, nopoll_get_32bit (msg->mask));
+
+	/* check here for the limit of message we are willing to accept */
+	/* FIX SECURITY ISSUE */
+
+read_payload:
+
+	/* copy payload received */
+	msg->payload = nopoll_new (char, msg->payload_size + 1);
+	if (msg->payload == NULL) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to acquire memory to read the incoming frame, dropping connection id=%d", conn->id);
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL;		
+	} /* end if */
+
+	bytes = __nopoll_conn_receive (conn, (char *) msg->payload, msg->payload_size);
+	if (bytes < 0) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Connection lost during message reception, dropping connection id=%d, bytes=%d, errno=%d : %s", 
+			    conn->id, bytes, errno, strerror (errno));
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL;		
+	} /* end if */
+
+	if (bytes != msg->payload_size) {
+		/* record we've got content pending to be read */
+		msg->remain_bytes = msg->payload_size - bytes;
+
+		/* set connection in remaining data to read */
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Received fewer bytes than expected (bytes: %d < payload size: %d)", 
+			    bytes, (int) msg->payload_size);
+		msg->payload_size = bytes;
+
+		/* grab a reference to previous message to reuse itsdata but only when bytes > 0 
+		   because when bytes == 0, the reference is reused since it is not returned
+		   to the caller (see next lines) */
+		if (bytes > 0)
+			nopoll_msg_ref (msg);
+		conn->previous_msg = msg;
+
+		/* flag this message as a fragment */
+		msg->is_fragment = nopoll_true;
+
+		/* flag that this message doesn't have FIN = 0 because
+		 * we wasn't able to read it entirely */
+		/* msg->has_fin = 0; */
+	} /* end if */
+
+	/* flag the message was being a fragment according to previous flag */
+	msg->is_fragment = msg->is_fragment || conn->previous_was_fragment || msg->has_fin == 0;
+
+	/* update was a fragment */
+	conn->previous_was_fragment = msg->is_fragment && msg->has_fin == 0;
+
+	/* do not notify any frame since no content was found */
+	if (bytes == 0 && msg == conn->previous_msg) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "bytes == %d, msg (%p) == conn->previous_msg (%p)",
+			    bytes, msg, conn->previous_msg);
+		return NULL;
+	} /* end if */
+
+	/* now unmask content (if required) */
+	if (msg->is_masked) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Unmasking (payload size %d, mask: %d, msg: %p, desp: %d)", 
+			    msg->payload_size, nopoll_get_32bit (msg->mask), msg, msg->unmask_desp);
+		nopoll_conn_mask_content (conn->ctx, (char*) msg->payload, msg->payload_size, (char*) msg->mask, msg->unmask_desp);
+
+		/* flag what was unmasked */
+		msg->unmask_desp += msg->payload_size;
+	} /* end if */
+
+	/* check here close frame with reason */
+	if (msg->op_code == NOPOLL_CLOSE_FRAME) {
+		/* try to read reason and report those values */
+		if (msg->payload_size >= 2) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Close frame received id=%d with content bytes=%d, peer status=%d, peer reason=%s, reading reason..", 
+				    conn->id, msg->payload_size, nopoll_get_16bit (msg->payload), msg->payload + 2);
+
+			/* get values so the user can get them */
+			conn->peer_close_status = nopoll_get_16bit ((const char *) msg->payload);
+			conn->peer_close_reason = nopoll_strdup ((const char *) msg->payload + 2);
+		} /* end if */
+
+		/* release message, close the connection and return
+		   NULL to notify caller nothing to read for the
+		   application */
+		nopoll_msg_unref (msg);
+		nopoll_conn_shutdown (conn);
+		return NULL;
+	}
+
+	return msg;
+}
+
+/** 
+ * @internal Implementation to send Frames according to various
+ * parameters passed in into the function. This is the core function
+ * used to send frames in noPoll.
+ *
+ * @param conn The connection where the content will be sent.
+ *
+ * @param content The content that will be sent (user level content)
+ *
+ * @param length The length of such content to be sent.
+ *
+ * @param has_fin nopoll_true/nopoll_false to signal FIN header flag 
+ *
+ * @param sleep_in_header Optional hacking option that allows to
+ * include a pause between sending the header and the rest of the
+ * content.
+ */
+int           __nopoll_conn_send_common (noPollConn * conn, const char * content, long length, nopoll_bool has_fin, long sleep_in_header, noPollOpCode frame_type)
+{
+	if (conn == NULL || content == NULL || length == 0 || length < -1)
+		return -1;
+
+	if (conn->role == NOPOLL_ROLE_MAIN_LISTENER) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Trying to send content over a master listener connection");
+		return -1;
+	} /* end if */
+
+	if (length == -1) {
+		if (NOPOLL_BINARY_FRAME == frame_type) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received length == -1 for binary frame. Unable to guess length");
+			return -1;
+		} /* end if */
+
+		length = strlen (content);
+	}
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_send_text: Attempting to send %d bytes", (int) length);
+
+	/* sending content as client */
+	if (conn->role == NOPOLL_ROLE_CLIENT) {
+		return nopoll_conn_send_frame (conn, /* fin */ has_fin, /* masked */ nopoll_true, 
+					       frame_type, length, (noPollPtr) content, sleep_in_header);
+	} /* end if */
+
+	/* sending content as listener */
+	return nopoll_conn_send_frame (conn, /* fin */ has_fin, /* masked */ nopoll_false, 
+				       frame_type, length, (noPollPtr) content, sleep_in_header);	
+}
+
+/** 
+ * @brief Allows to send an UTF-8 text (op code 1) message over the
+ * provided connection with the provided length.
+ *
+ * @param conn The connection where the message will be sent.
+ *
+ * @param content The content to be sent (it should be utf-8 content
+ * or the function will fail).
+ *
+ * @param length Amount of bytes to take from the content to be
+ * sent. If provided -1, it is assumed you are passing in a C-like
+ * string nul terminated, so, that's the content to be sent.
+ *
+ * @return The number of bytes written otherwise < 0 is returned in
+ * case of failure. The function will fail if some parameter is NULL
+ * or undefined, or the content provided is not UTF-8. In the case of
+ * failure, also check errno variable to know more what went wrong.
+ *
+ * See \ref nopoll_manual_retrying_write_operations to know more about error codes and when it is possible to retry write operations.
+ */
+int           nopoll_conn_send_text (noPollConn * conn, const char * content, long length)
+{
+	/* do a send common operation with FIN = 1 */
+	return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_TEXT_FRAME);
+}
+
+/** 
+ * @brief Allows to send an UTF-8 text (op code 1) message over the
+ * provided connection with the provided length but flagging the frame
+ * sent as not complete (more frames to come, that is, FIN = 0).
+ *
+ * @param conn The connection where the message will be sent.
+ *
+ * @param content The content to be sent (it should be utf-8 content
+ * or the function will fail).
+ *
+ * @param length Amount of bytes to take from the content to be
+ * sent. If provided -1, it is assumed you are passing in a C-like
+ * string nul terminated, so, that's the content to be sent.
+ *
+ * @return The number of bytes written otherwise < 0 is returned in
+ * case of failure. The function will fail if some parameter is NULL
+ * or undefined, or the content provided is not UTF-8. In the case of
+ * failure, also check errno variable to know more what went wrong.
+ *
+ * See \ref nopoll_manual_retrying_write_operations to know more about
+ * error codes and when it is possible to retry write operations.
+ */
+int           nopoll_conn_send_text_fragment (noPollConn * conn, const char * content, long length)
+{
+	/* do a send common operation with FIN = 0 */
+	return __nopoll_conn_send_common (conn, content, length, nopoll_false, 0, NOPOLL_TEXT_FRAME);
+}
+
+/** 
+ * @brief Allows to send a binary (op code 2) message over the
+ * provided connection with the provided length.
+ *
+ * @param conn The connection where the message will be sent.
+ *
+ * @param content The content to be sent (it should be utf-8 content
+ * or the function will fail).
+ *
+ * @param length Amount of bytes to take from the content to be
+ * sent. Note you cannot pass in -1 (unlike \ref nopoll_conn_send_text).
+ *
+ * @return The number of bytes written otherwise < 0 is returned in
+ * case of failure. The function will fail if some parameter is NULL
+ * or undefined. In the case of failure, also check errno variable to
+ * know more what went wrong.
+ *
+ * See \ref nopoll_manual_retrying_write_operations to know more about error codes and when it is possible to retry write operations.
+ */
+int           nopoll_conn_send_binary (noPollConn * conn, const char * content, long length)
+{
+	return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_BINARY_FRAME);
+}
+
+
+/** 
+ * @brief Allows to send a binary (op code 2) message over the
+ * provided connection with the provided length but flagging the frame
+ * sent as not complete (more frames to come, that is, FIN = 0).
+ *
+ * @param conn The connection where the message will be sent.
+ *
+ * @param content The content to be sent (it should be utf-8 content
+ * or the function will fail).
+ *
+ * @param length Amount of bytes to take from the content to be
+ * sent. Note you cannot pass in -1 (unlike \ref
+ * nopoll_conn_send_text).
+ *
+ * @return The number of bytes written otherwise < 0 is returned in
+ * case of failure. The function will fail if some parameter is NULL
+ * or undefined. In the case of failure, also check errno variable to
+ * know more what went wrong.
+ *
+ * See \ref nopoll_manual_retrying_write_operations to know more about
+ * error codes and when it is possible to retry write operations.
+ */
+int           nopoll_conn_send_binary_fragment (noPollConn * conn, const char * content, long length)
+{
+	return __nopoll_conn_send_common (conn, content, length, nopoll_true, 0, NOPOLL_BINARY_FRAME);
+}
+
+
+/** 
+ * @brief Allows to read the provided amount of bytes from the
+ * provided connection, leaving the content read on the buffer
+ * provided.
+ *
+ * Optionally, the function allows blocking the caller until the
+ * amount of bytes requested are satisfied. Also, the function allows
+ * to timeout the operation after provided amount of time.
+ *
+ * @param conn The connection where the read operation will take place.
+ *
+ * @param buffer The buffer where the result is returned. Memory
+ * buffer must be enough to hold bytes requested and must be acquired
+ * by the caller. 
+ *
+ * @param bytes Number of bytes to be read from the connection.
+ *
+ * @param block If nopoll_true, the caller will be blocked until the
+ * amount of bytes requested are satisfied or until the timeout is
+ * reached (if enabled). If nopoll_false is provided, the function
+ * won't block and will return all bytes available at this moment.
+ *
+ * @param timeout (milliseconds 1sec = 1000ms) If provided a value
+ * higher than 0, a timeout will be enabled to complete the
+ * operation. If the timeout is reached, the function will return the
+ * bytes read so far. Please note that the function has a precision of
+ * 10ms.
+ *
+ * @return Number of bytes read or -1 if it fails. The function
+ * returns -1 when no content is available to be read and you pass
+ * block == nopoll_false
+ *
+ * Note that the function doesn't clear the buffer received. Only
+ * memory (bytes) notified by the value returned by this function
+ * should be accessed by the caller. In the same direction you can't
+ * use the buffer as a nul-terminated string because the function
+ * doesn't add the final \0 to the content read.
+ *
+ */
+int           nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout)
+{
+	long int           wait_slice = 0;
+	noPollMsg        * msg        = NULL;
+	struct  timeval    start;
+	struct  timeval    stop;
+	struct  timeval    diff;
+	long               ellapsed   = 0;
+	int                desp       = 0;
+	int                amount;
+	int                total_read = 0;
+	int                total_pending = 0;
+
+	/* report error value */
+	if (conn == NULL || buffer == NULL || bytes <= 0)
+		return -1;
+	
+	if (timeout > 1000)
+		wait_slice = 100;
+	else if (timeout > 100)
+		wait_slice = 50;
+	else if (timeout > 10)
+		wait_slice = 10;
+
+	if (timeout > 0)
+#if defined(NOPOLL_OS_WIN32)
+		nopoll_win32_gettimeofday (&start, NULL);
+#else
+		gettimeofday (&start, NULL);
+#endif
+
+	/* clear the buffer */
+	memset (buffer, 0, bytes);
+
+	/* check here if we have a pending message to read */
+	if (conn->pending_msg)  {
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read (found pending content: %d, requested %d)", conn->pending_diff, bytes); */
+		/* get references to pending data */
+		amount = conn->pending_diff;
+		msg    = conn->pending_msg;
+		if (amount > bytes) {
+			/* check if bytes requested are bigger the
+			 * conn->pending_diff */
+			if (bytes < conn->pending_diff) {
+				conn->pending_diff -= bytes;
+			} else {
+				/* update values */
+				bytes = conn->pending_diff;
+				conn->pending_diff = 0;
+			} /* end if */
+
+			amount = bytes;
+		} else {
+			conn->pending_diff = 0;
+		}
+
+		/* read content */
+		memcpy (buffer, ((unsigned char *) nopoll_msg_get_payload (msg)) + conn->pending_desp, amount);
+		total_read += amount;
+		desp        = amount;
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read total amount satisfied is not %d, requested %d", total_read, bytes); */
+		
+		/* increase pending desp */
+		conn->pending_desp += amount;
+
+		/* now release internally the content if consumed the message */
+		if (conn->pending_diff == 0) {
+			nopoll_msg_unref (conn->pending_msg);
+			conn->pending_msg = NULL;
+		} /* end if */
+
+		/* see if we have finished */
+		if (total_read == bytes || ! block) {
+			if (total_read == 0 && ! block) 
+				return -1;
+
+			return total_read;
+		}
+		
+		/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "### ====> Read %d bytes from previous pending frame, requested %d. Pending diff %d", total_read, bytes, conn->pending_diff); */
+	} /* end if */
+
+
+	/* for for the content */
+	while (nopoll_true) {
+		/* call to get next message */
+		msg = nopoll_conn_get_msg (conn);
+		if (msg == NULL) {
+			if (! nopoll_conn_is_ok (conn)) {
+			        nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received websocket conn-id=%d close during wait reply..",
+					    conn->id);
+				if (total_read == 0 && ! block)
+					return -1;
+				return total_read;
+			} /* end if */
+
+			if (! block) {
+				if (total_read == 0 && ! block) 
+					return -1;
+				return total_read;
+			} /* end if */
+			
+		} /* end if */
+
+		/* get the message content into the buffer */
+		if (msg) {
+			if (msg->op_code == NOPOLL_PING_FRAME) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "PING received over connection id=%d, replying PONG", conn->id);
+				/* call to send pong */
+				nopoll_conn_send_pong (conn, nopoll_msg_get_payload_size (msg), (noPollPtr)nopoll_msg_get_payload (msg));
+				nopoll_msg_unref (msg);
+				continue;
+			} /* end if */
+
+			/* get the amount of bytes we can read */
+			amount = nopoll_msg_get_payload_size (msg);
+			total_pending = bytes - total_read;
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "(New Frame) received %d bytes (pending requested %d bytes, desp: %d)", amount, total_pending, desp);
+			if (amount > total_pending) {
+				/* save here the difference between
+				 * what we have read and remaining data */
+				conn->pending_desp = total_pending;
+				conn->pending_diff = amount - total_pending;
+				conn->pending_msg  = msg;
+				amount = total_pending;
+
+				/* acquire a reference to the message */
+				nopoll_msg_ref (msg);
+			} /* end if */
+			/* copy data */
+			memcpy (buffer + desp, nopoll_msg_get_payload (msg), amount);
+			total_read += amount;
+			desp       += amount;
+			/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read total amount satisfied is not %d, requested %d, desp: %d",
+			   total_read, bytes, desp); */
+
+			/* release message */
+			nopoll_msg_unref (msg);
+
+			/* return amount read */
+			if (total_read == bytes || ! block) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read because block=%d or total bytes requested=%d satisfied=%d ", 
+					    block, bytes, total_read);
+
+				if (total_read == 0 && ! block) 
+					return -1;
+				return total_read;
+			}
+		}
+
+		/* check to stop due to timeout */
+		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 * 1000) + (diff.tv_usec / 1000);
+			if (ellapsed > (timeout)) 
+				break;
+		} /* end if */
+		
+		nopoll_sleep (wait_slice);
+	} /* end while */
+
+	/* reached this point, return that timeout was reached */
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read timeout reached=%ld ms , returning total bytes requested=%d satisfied=%d ", 
+		    timeout, bytes, total_read);
+
+	if (total_read == 0 && ! block)
+		return -1;
+	return total_read;
+}
+
+int	aispeech_nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout)
+{
+	long int           wait_slice = 0;
+	noPollMsg        * msg        = NULL;
+	struct  timeval    start;
+	struct  timeval    stop;
+	struct  timeval    diff;
+	long               ellapsed   = 0;
+	int                desp       = 0;
+	int                amount;
+	int                total_bytes = bytes, total_read = 0;
+	int                total_pending = 0;
+
+	/* report error value */
+	if (conn == NULL || buffer == NULL || total_bytes <= 0)
+		return -1;
+	
+	if (timeout > 1000)
+		wait_slice = 100;
+	else if (timeout > 100)
+		wait_slice = 50;
+	else if (timeout > 10)
+		wait_slice = 10;
+
+	if (timeout > 0)
+#if defined(NOPOLL_OS_WIN32)
+		nopoll_win32_gettimeofday (&start, NULL);
+#else
+		gettimeofday (&start, NULL);
+#endif
+
+	/* clear the buffer */
+	memset (buffer, 0, total_bytes);
+
+	/* for for the content */
+	while (nopoll_true) {
+		/* call to get next message */
+		msg = nopoll_conn_get_msg (conn);
+		if (msg == NULL) {
+			if (! nopoll_conn_is_ok (conn)) {
+			        nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Received websocket conn-id=%d close during wait reply..",
+					    conn->id);
+				if (total_read == 0 && ! block)
+					return -1;
+				return total_read;
+			} /* end if */
+
+			if (! block) {
+				if (total_read == 0 && ! block) 
+					return -1;
+				return total_read;
+			} /* end if */
+			
+		} /* end if */
+
+		/* get the message content into the buffer */
+		if (msg) {
+			if (total_read == 0)
+			{
+				total_bytes = msg->remain_bytes + msg->payload_size;
+			}
+		  	
+			/* get the amount of total_bytes we can read */
+			amount = nopoll_msg_get_payload_size (msg);
+			total_pending = total_bytes - total_read;
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "(New Frame) received %d total_bytes (pending requested %d total_bytes, desp: %d)", amount, total_pending, desp);
+			if (amount > total_pending) {
+				/* save here the difference between
+				 * what we have read and remaining data */
+				conn->pending_desp = total_pending;
+				conn->pending_diff = amount - total_pending;
+				conn->pending_msg  = msg;
+				amount = total_pending;
+
+				/* acquire a reference to the message */
+				nopoll_msg_ref (msg);
+			} /* end if */
+			/* copy data */
+			memcpy (buffer + desp, nopoll_msg_get_payload (msg), amount);
+			total_read += amount;
+			desp       += amount;
+			/* nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "nopoll_conn_read total amount satisfied is not %d, requested %d, desp: %d",
+			   total_read, total_bytes, desp); */
+
+			/* release message */
+			nopoll_msg_unref (msg);
+
+			/* return amount read */
+			if (total_read == total_bytes || ! block) {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read because block=%d or total total_bytes requested=%d satisfied=%d ", 
+					    block, total_bytes, total_read);
+
+				if (total_read == 0 && ! block) 
+					return -1;
+				return total_read;
+			}
+		}
+
+		/* check to stop due to timeout */
+		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 * 1000) + (diff.tv_usec / 1000);
+			if (ellapsed > (timeout)) 
+				break;
+		} /* end if */
+		
+		nopoll_sleep (wait_slice);
+	} /* end while */
+
+	/* reached this point, return that timeout was reached */
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Finishing nopoll_conn_read timeout reached=%ld ms , returning total total_bytes requested=%d satisfied=%d ", 
+		    timeout, total_bytes, total_read);
+
+	if (total_read == 0 && ! block)
+		return -1;
+	return total_read;
+}
+
+/** 
+ * @brief Allows to send a ping message over the Websocket connection
+ * provided. The function will not block the caller.
+ *
+ * @param conn The connection where the PING operation will be sent.
+ *
+ * @return nopoll_true if the operation was sent without any error,
+ * otherwise nopoll_false is returned.
+ */
+nopoll_bool      nopoll_conn_send_ping (noPollConn * conn)
+{
+	return nopoll_conn_send_frame (conn, nopoll_true, nopoll_false, NOPOLL_PING_FRAME, 0, NULL, 0) > 0;
+}
+
+/** 
+ * @brief Allows to configure an on message handler on the provided
+ * connection that overrides the one configured at \ref noPollCtx.
+ *
+ * @param conn The connection to be configured with a particular on message handler.
+ *
+ * @param on_msg The on message handler configured.
+ *
+ * @param user_data User defined pointer to be passed in into the on message handler when it is called.
+ * 
+ */
+void          nopoll_conn_set_on_msg (noPollConn              * conn,
+				      noPollOnMessageHandler    on_msg,
+				      noPollPtr                 user_data)
+{
+	if (conn == NULL)
+		return;
+
+	/* configure on message handler */
+	conn->on_msg      = on_msg;
+	conn->on_msg_data = user_data;
+
+	return;
+}
+
+/** 
+ * @brief Allows to configure a handler that is called when the
+ * connection provided 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 conn The connection to configure.
+ *
+ * @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_conn_set_on_ready (noPollConn            * conn,
+					 noPollActionHandler     on_ready,
+					 noPollPtr               user_data)
+{
+	if (conn == NULL)
+		return;
+
+	/* set the handler */
+	conn->on_ready = on_ready;
+	if (conn->on_ready == NULL)
+		conn->on_ready_data = NULL;
+	else
+		conn->on_ready_data = user_data;
+	return;
+}
+
+/** 
+ * @brief Allows to configure an OnClose handler that will be called
+ * when the connection is closed.
+ *
+ * @param conn The connection to configure with the on close handle.
+ *
+ * @param on_close The handler to be configured.
+ *
+ * @param user_data A reference pointer to be passed in into the handler.
+ */
+void          nopoll_conn_set_on_close (noPollConn            * conn,
+					noPollOnCloseHandler    on_close,
+					noPollPtr               user_data)
+{
+	if (conn == NULL)
+		return;
+
+	/* configure on close handler */
+	conn->on_close      = on_close;
+	conn->on_close_data = user_data;
+
+        return;
+}
+
+/** 
+ * @internal Allows to send a pong message over the Websocket
+ * connection provided. The function will not block the caller. This
+ * function is not intended to be used by normal API consumer.
+ *
+ * @param conn The connection where the PING operation will be sent.
+ *
+ * @param nopoll_true if the operation was sent without any error,
+ * otherwise nopoll_false is returned.
+ */
+nopoll_bool      nopoll_conn_send_pong (noPollConn * conn, long length, noPollPtr content)
+{
+	if (conn == NULL)
+		return nopoll_false; /* do not pong if wrong reference received */
+
+	return nopoll_conn_send_frame (conn, nopoll_true, conn->role == NOPOLL_ROLE_CLIENT, NOPOLL_PONG_FRAME, length, content, 0);
+}
+
+/** 
+ * @brief Allows to call to complete last pending write process that may be
+ * pending from a previous uncompleted write operation. The function
+ * returns the number of bytes that were written.
+ *
+ * @param conn The connection where the pending write operation
+ * operation will take place. In the case conn == NULL is received, 0
+ * is returned. Keep in mind this.
+ *
+ * @return In the case no pending write is in place, the function
+ * returns 0. Otherwise, the function returns the pending bytes that
+ * were written. The function returns -1 in the case of failure.
+ *
+ * You can call this function as many times as you want until you get
+ * a 0. You can view it as a flush operation.
+ */
+int nopoll_conn_complete_pending_write (noPollConn * conn)
+{
+	int    bytes_written = 0;
+
+	if (conn == NULL || conn->pending_write == NULL)
+		return 0;
+
+	/* simple implementation */
+	bytes_written = conn->send (conn, conn->pending_write + conn->pending_write_desp, conn->pending_write_bytes);
+	if (bytes_written == conn->pending_write_bytes) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Completed pending write operation with bytes=%d", bytes_written);
+		nopoll_free (conn->pending_write);
+		conn->pending_write = NULL;
+		return bytes_written;
+	} /* end if */
+
+	if (bytes_written > 0) {
+		/* bytes written but not everything */
+		conn->pending_write_bytes -= bytes_written;
+		conn->pending_write_desp += bytes_written;
+		return bytes_written;
+	}
+
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found complete write operation didn't finish well, result=%d, errno=%d, conn-id=%d",
+		    bytes_written, errno, conn->id);
+	return bytes_written;
+}
+
+/** 
+ * @brief Allows to check if there are pending write bytes. The
+ * function returns the number of pending write bytes that are waiting
+ * to be flushed. To do so you must call \ref nopoll_conn_complete_pending_write.
+ *
+ * @param conn The connection to be checked to have pending bytes to be written.
+ *
+ * @return The number of bytes pending to be written. The function
+ * also returns 0 when conn reference received is NULL.
+ */
+int           nopoll_conn_pending_write_bytes (noPollConn * conn)
+{
+	if (conn == NULL || conn->pending_write == NULL)
+		return 0;
+
+	return conn->pending_write_bytes;
+}
+
+/** 
+ * @brief Ready to use function that checks for pending write
+ * operations and flush them waiting until they are done or until the
+ * timeout provided by the user is reached.
+ *
+ * This function uses \ref nopoll_conn_pending_write_bytes and \ref
+ * nopoll_conn_complete_pending_write to check and complete pending
+ * write operations. 
+ *
+ * Because writing pending bytes is a common operation, this function
+ * is provided as a ready to use function to call after a write operation (for
+ * example \ref nopoll_conn_send_text).
+ *
+ * @param conn The connection where pending bytes must be written. 
+ *
+ * @param timeout Timeout in milliseconds to limit the flush operation.
+ *
+ * @param previous_result Optional parameter that can receive the
+ * number of bytes optionally read before this call. The value
+ * received on this function will be added to the result, checking
+ * first it contains a value higher than 0. This is an option to
+ * clarify the interface. If you don't have the value to be passed to
+ * this function at the time needed, just pass 0.
+ *
+ * @return Bytes that were written. If no pending bytes must be written, the function returns 0.
+ */
+int nopoll_conn_flush_writes (noPollConn * conn, long timeout, int previous_result)
+{
+	int iterator = 0;
+	int bytes_written;
+	int total = 0;
+	int multiplier = 1;
+	long wait_implemented = 0;
+
+	/* check for errno and pending write operations */
+	if (errno != NOPOLL_EWOULDBLOCK || nopoll_conn_pending_write_bytes (conn) == 0) {
+	        nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "called flush but nothing is pending=%d or errno=%d isn't %d",
+		            nopoll_conn_pending_write_bytes (conn), errno, NOPOLL_EWOULDBLOCK);
+		return previous_result > 0 ? previous_result : 0;
+	}
+		
+	while (iterator < 100 && nopoll_conn_pending_write_bytes (conn) > 0) {
+
+		/* stop operation if timeout reached */
+		if (wait_implemented >= timeout)
+			break;
+
+		nopoll_sleep (100000 * multiplier);
+		wait_implemented += (100000 * multiplier);
+
+		/* write content pending */
+		bytes_written = nopoll_conn_complete_pending_write (conn);
+
+		if (bytes_written > 0)
+			total += bytes_written;
+
+		/* next position */
+		iterator++;
+		multiplier++;
+	} /* end while */
+
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "finishing flush operation, total written=%d, added to previous result=%d",
+		    total, previous_result);
+
+	/* add value received */
+	if (previous_result > 0) 
+		return total + previous_result;
+
+	/* just bytes written */
+	return total;
+}
+
+
+/** 
+ * @internal Function used to send a frame over the provided
+ * connection.
+ *
+ * @param conn The connection where the send operation will hapen.
+ *
+ * @param fin If the frame to be sent must be flagged as a fin frame.
+ *
+ * @param masked The frame to be sent is masked or not.
+ *
+ * @param op_code The frame op code to be configured.
+ *
+ * @param length The frame payload length.
+ *
+ * @param content Pointer to the data to be sent in the frame.
+ */
+int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool masked,
+			    noPollOpCode op_code, long length, noPollPtr content, long sleep_in_header)
+
+{
+	char               header[14];
+	int                header_size;
+	char             * send_buffer;
+	int                bytes_written = 0;
+	char               mask[4];
+	unsigned int       mask_value = 0;
+	int                desp = 0;
+	int                tries, result;
+#if defined(SHOW_DEBUG_LOG)
+	noPollDebugLevel   level;
+#endif
+
+    /* check for pending send operation */
+    result = nopoll_conn_complete_pending_write (conn);
+	if (result > 0)
+	{
+	    if (conn->pending_write != NULL)
+	    	return length + 1;
+		else
+		  	return length;
+	}
+	else if (result < 0)
+	{
+		return result;
+	}
+
+	/* clear header */
+	memset (header, 0, 14);
+
+	/* set header codes */
+	if (fin) 
+		nopoll_set_bit (header, 7);
+	
+	if (masked) {
+		nopoll_set_bit (header + 1, 7);
+		
+		/* define a random mask */
+#if defined(NOPOLL_OS_WIN32)
+		mask_value = (unsigned int) rand ();
+#elif defined(NOPOLL_OS_RTTHREAD)
+		mask_value = nopoll_rtt_random();
+#else
+		mask_value = (unsigned int) random ();
+#endif
+		memset (mask, 0, 4);
+		nopoll_set_32bit (mask_value, mask);
+	} /* end if */
+
+	if (op_code) {
+		/* set initial 4 bits */
+		header[0]   |= op_code & 0x0f;
+	}
+
+	/* set default header size */
+	header_size  = 2;
+
+	/* according to message length */
+	if (length < 126) {
+		header[1] |= length;
+	} else if (length <= 65535) {
+		/* set the next header length is at least 65535 */
+		header[1] |= 126;
+		header_size += 2;
+		/* set length into the next bytes */
+		nopoll_set_16bit (length, header + 2);
+#if defined(NOPOLL_64BIT_PLATFORM)
+	} else if (length < 0x8000000000000000) {
+		header[2] = (length & 0xFF00000000000000) >> 56;
+		header[3] = (length & 0x00FF000000000000) >> 48;
+		header[4] = (length & 0x0000FF0000000000) >> 40;
+		header[5] = (length & 0x000000FF00000000) >> 32;
+#else
+	} else if (length < 0x80000000) {
+		header[2] = header[3] = header[4] = header[5] = 0;
+#endif
+		header[1] |= 127;
+		header_size += 8;
+		header[6] = (length & 0x00000000FF000000) >> 24;
+		header[7] = (length & 0x0000000000FF0000) >> 16;
+		header[8] = (length & 0x000000000000FF00) >> 8;
+		header[9] = (length & 0x00000000000000FF);
+	} else {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to send the requested message, this requested is bigger than the value that can be supported by this platform");
+		return -1;
+	}
+
+	/* place mask */
+	if (masked) {
+		nopoll_set_32bit (mask_value, header + header_size);
+		header_size += 4;
+	} /* end if */
+
+	/* allocate enough memory to send content */
+	send_buffer = nopoll_new (char, length + header_size + 2);
+	if (send_buffer == NULL) {
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_CRITICAL, "Unable to allocate memory to implement send operation");
+		return -1;
+	} /* end if */
+	
+	/* copy content to be sent */
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Copying into the buffer %d bytes of header (total memory allocated: %d)", 
+		    header_size, (int) length + header_size + 1);
+	memcpy (send_buffer, header, header_size);
+	if (length > 0) {
+		memcpy (send_buffer + header_size, content, length);
+
+		/* mask content before sending if requested */
+		if (masked) {
+			nopoll_conn_mask_content (conn->ctx, send_buffer + header_size, length, mask, 0);
+		}
+	} /* end if */
+
+	
+	/* send content */
+	nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Mask used for this delivery: %d (about to send %d bytes)",
+		    nopoll_get_32bit (send_buffer + header_size - 2), (int) length + header_size);
+
+	/* clear errno status before writting */
+	desp  = 0;
+	tries = 0;
+
+	/***** BEGIN INTERNAL debug code for test_30, test_31, test_32, test_33, test_34, test_35 : nopoll-regression-client.c ******/
+	if ((conn->__force_stop_after_header > 0) && (conn->__force_stop_after_header < (length + header_size))) {
+		
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Sending broken header (just %d bytes) and implement a pause on purpose...", conn->__force_stop_after_header);
+
+		/* send just 2 bytes for the header and then implement a very long pause */
+		bytes_written = conn->send (conn, send_buffer, conn->__force_stop_after_header);
+		desp          = conn->__force_stop_after_header;
+		if (bytes_written != conn->__force_stop_after_header) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Requested to write %d bytes for the header but %d were written",
+				    conn->__force_stop_after_header, bytes_written);
+			desp  = 0;
+		} /* end if */
+
+		/* sleep after header ... */
+		nopoll_sleep (5000000); /* 5 seconds */
+
+	} /* end if */
+	/****** END INTERNAL debug code for test_30 : nopoll-regression-client.c ******/
+
+	while (nopoll_true) {
+		/* try to write bytes */
+		if (sleep_in_header == 0) {
+			bytes_written = conn->send (conn, send_buffer + desp, length + header_size - desp);
+		} else {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Found sleep in header indication, sending header: %d bytes (waiting %ld)", header_size, sleep_in_header);
+			bytes_written = conn->send (conn, send_buffer, header_size);
+			if (bytes_written == header_size) {
+				/* sleep after header ... */
+				nopoll_sleep (sleep_in_header);
+				
+				/* now send the rest of the content (without the header) */
+				bytes_written = conn->send (conn, send_buffer + header_size, length);
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Rest of content written %d (header size: %d, length: %d)", 
+					    bytes_written, header_size, length);
+				bytes_written = length + header_size;
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "final bytes_written %d", bytes_written);
+			} else {
+				nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Requested to write %d bytes for the header but %d were written",
+					    header_size, bytes_written);
+				return -1;
+			} /* end if */
+		} /* end if */
+		
+		if ((bytes_written + desp) != (length + header_size)) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, 
+				    "Requested to write %d bytes but found %d written (masked? %d, mask: %u, header size: %d, length: %d), errno = %d : %s", 
+				    (int) length + header_size - desp, bytes_written, masked, mask_value, header_size, (int) length, errno, strerror (errno));
+		} else {
+			/* accomulate bytes written to continue */
+			if (bytes_written > 0)
+				desp += bytes_written;
+
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Bytes written to the wire %d (masked? %d, mask: %u, header size: %d, length: %d)", 
+				    bytes_written, masked, mask_value, header_size, (int) length);
+			break;
+		} /* end if */
+
+		/* accomulate bytes written to continue */
+		if (bytes_written > 0)
+			desp += bytes_written;
+
+		/* increase tries */
+		tries++;
+
+		if ((errno != 0) || tries > 50) {
+			nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Found errno=%d (%s) value while trying to bytes to the WebSocket conn-id=%d or max tries reached=%d",
+				    errno, strerror (errno), conn->id, tries);
+			break;
+		} /* end if */
+
+		/* wait a bit */
+		nopoll_sleep (100000);
+
+	} /* end while */
+
+	/* record pending write bytes */
+	conn->pending_write_bytes = length + header_size - desp;
+
+#if defined(SHOW_DEBUG_LOG)
+	level = NOPOLL_LEVEL_DEBUG;
+	if (desp != (length + header_size))
+		level = NOPOLL_LEVEL_CRITICAL;
+	else if (errno == NOPOLL_EWOULDBLOCK && conn->pending_write_bytes > 0)
+		level = NOPOLL_LEVEL_WARNING;
+
+	nopoll_log (conn->ctx, level, 
+		    "Write operation finished with with last result=%d, bytes_written=%d, requested=%d, remaining=%d (conn-id=%d)",
+		    /* report want we are going to report: result */
+		    bytes_written <= 0 ? bytes_written : desp - header_size,
+		    /* bytes written */
+		    desp - header_size, 
+		    length, conn->pending_write_bytes, conn->id);
+#endif
+
+	/* check pending bytes for the next operation */
+	if (conn->pending_write_bytes > 0) {
+		conn->pending_write = send_buffer;
+		conn->pending_write_desp = desp;
+		nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Stored %d bytes starting from %d out of %d bytes (header size: %d)", 
+			    conn->pending_write_bytes, desp, length + header_size, header_size);
+	} else {
+		/* release memory */
+		nopoll_free (send_buffer);
+	} /* end if */
+
+    /* report that everything was written */
+	if (conn->pending_write != NULL)
+    	return length + 1;
+	else
+	  	return length;
+}
+
+/** 
+ * @brief Allows to accept a new incoming WebSocket connection on the
+ * provided listener.
+ *
+ * @param ctx The context where the operation will take place.
+ *
+ * @param listener The WebSocket listener that is receiving a new incoming connection.
+ *
+ * @return A newly created \ref noPollConn reference or NULL if it
+ * fails.
+ */
+noPollConn * nopoll_conn_accept (noPollCtx * ctx, noPollConn * listener)
+{
+	NOPOLL_SOCKET   session;
+
+	nopoll_return_val_if_fail (ctx, ctx && listener, NULL);
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Calling to accept web socket connection over master id=%d, socket=%d",
+		    listener->id, listener->session);
+
+	/* recevied a new connection: accept the
+	 * connection and ask the app level to accept
+	 * or not */
+	session = nopoll_listener_accept (listener->session);
+	if (session == NOPOLL_INVALID_SOCKET) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received invalid socket value from accept(2): %d, error code errno=: %d", 
+			    session, errno);
+		return NULL;
+	} /* end if */
+
+	return nopoll_conn_accept_socket (ctx, listener, session);
+}
+
+
+/** 
+ * @brief Allows to accept a new incoming WebSocket connection on the
+ * provided listener but with a socket already accepted.
+ *
+ * @param ctx The context where the operation will take place.
+ *
+ * @param listener The WebSocket listener that is receiving a new incoming connection.
+ *
+ * @param session An already accepted socket from the provided
+ * listener.
+ *
+ * @return A newly created \ref noPollConn reference or NULL if it
+ * fails.
+ */
+noPollConn * nopoll_conn_accept_socket (noPollCtx * ctx, noPollConn * listener, NOPOLL_SOCKET session)
+{
+	noPollConn * conn;
+
+	nopoll_return_val_if_fail (ctx, ctx && listener, NULL);
+
+	/* create the connection */
+	conn = nopoll_listener_from_socket (ctx, session);
+	if (conn == NULL) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received NULL pointer after calling to create listener from session..");
+		return NULL;
+	} /* end if */
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Accepted new WebSocket conn-id=%d, socket=%d, over master id=%d, socket=%d",
+		    conn->id, conn->session, listener->id, listener->session);
+
+	/* configure the listener reference that accepted this
+	 * connection */
+	conn->listener = listener;
+
+	if (! nopoll_conn_accept_complete (ctx, listener, conn, session, listener->tls_on))
+		return NULL;
+
+	/* report listener created */
+	return conn;
+}
+
+/**
+ * @internal Function to support accept listener operations.
+ */
+nopoll_bool __nopoll_conn_accept_complete_common (noPollCtx * ctx, noPollConnOpts * options, noPollConn * listener, noPollConn * conn, NOPOLL_SOCKET session, nopoll_bool tls_on) {
+
+	const char          * certificateFile  = NULL;
+	const char          * privateKey       = NULL;
+	const char          * chainCertificate = NULL;
+	const char          * serverName       = NULL;
+
+	/* check input parameters */
+	if (! (ctx && listener && conn && session != NOPOLL_INVALID_SOCKET)) {
+		nopoll_conn_shutdown (conn);
+		nopoll_ctx_unregister_conn (ctx, conn);
+
+		/* release connection options */
+		__nopoll_conn_opts_release_if_needed (options);
+
+		return nopoll_false;
+	} /* end if */
+
+	/* configure non blocking mode */
+	nopoll_conn_set_sock_block (session, nopoll_true);
+	
+	/* now check for accept handler */
+	if (ctx->on_accept) {
+		/* call to on accept */
+		if (! ctx->on_accept (ctx, conn, ctx->on_accept_data)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Application level denied accepting connection from %s:%s, closing", 
+				    conn->host, conn->port);
+			nopoll_conn_shutdown (conn);
+			nopoll_ctx_unregister_conn (ctx, conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		} /* end if */
+	} /* end if */
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Connection received and accepted from %s:%s (conn refs: %d, ctx refs: %d)", 
+		    listener->host, listener->port, listener->refs, ctx->refs);
+
+#if NOPOLL_TLS
+	if (listener->tls_on || tls_on) {
+		/* reached this point, ensure tls is enabled on this
+		 * session */
+		conn->tls_on = nopoll_true;
+
+		/* get here SNI to query about the serverName */
+
+		/* 1) GET FROM OPTIONS: detect here if we have
+		 * certificates provided through options */
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Starting TLS process, options=%p, listener=%p", options, listener);
+
+		if (options) {
+			certificateFile = options->certificate;
+			privateKey      = options->private_key;
+		} /* end if */
+		if (certificateFile == NULL || privateKey == NULL) {
+
+			/* 2) GET FROM LISTENER: get references to currently configured certificate file */
+			certificateFile = listener->certificate;
+			privateKey      = listener->private_key;
+			if (certificateFile == NULL || privateKey == NULL) {
+				/* 3) GET FROM STORE: check if the
+				 * certificate is already installed */
+				nopoll_ctx_find_certificate (ctx, serverName, &certificateFile, &privateKey, &chainCertificate);
+			}
+		} /* end if */
+
+		/* check certificates and private key */
+		if (certificateFile == NULL || privateKey == NULL) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept secure web socket connection, certificate file %s and/or key file %s isn't defined",
+				    certificateFile ? certificateFile : "<not defined>", 
+				    privateKey ? privateKey : "<not defined>");
+			nopoll_conn_shutdown (conn);
+			nopoll_ctx_unregister_conn (ctx, conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		} /* end if */
+
+		/* init ssl ciphers and engines */
+		if (! __nopoll_tls_was_init) {
+			__nopoll_tls_was_init = nopoll_true;
+			SSL_library_init ();
+		} /* end if */
+
+		/* now configure chainCertificate */
+		if (listener->chain_certificate) 
+			chainCertificate = listener->chain_certificate;
+		else if (options && options->chain_certificate)
+			chainCertificate = options->chain_certificate;
+
+		/* create ssl context */
+		conn->ssl_ctx  = __nopoll_conn_get_ssl_context (ctx, conn, listener->opts, nopoll_false);
+
+		/* Configure ca certificate in the case it is defined */
+		if (options && options->ca_certificate) {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting up CA certificate: %s", options->ca_certificate);
+			if (SSL_CTX_load_verify_locations (conn->ssl_ctx, options->ca_certificate, NULL) != 1) {
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure CA certificate (%s), SSL_CTX_load_verify_locations () failed", options->ca_certificate);
+				return nopoll_false;
+			} /* end if */
+
+		} /* end if */
+
+		/* enable default verification paths */
+		if (SSL_CTX_set_default_verify_paths (conn->ssl_ctx) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure default verification paths, SSL_CTX_set_default_verify_paths () failed");
+			return nopoll_false;
+		} /* end if */
+
+		/* configure chain certificate */
+		if (chainCertificate) {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Setting up chain certificate: %s", chainCertificate);
+			if (SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, chainCertificate) != 1) {
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to configure chain certificate (%s), SSL_CTX_use_certificate_chain_file () failed", chainCertificate);
+				return nopoll_false;
+			} /* end if */
+		} /* end if */
+
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Using certificate file: %s (with ssl context ref: %p)", certificateFile, conn->ssl_ctx);
+		if (conn->ssl_ctx == NULL || SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, certificateFile) != 1) {
+			/* drop an error log */
+			if (conn->ssl_ctx == NULL)
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to accept incoming connection, failed to create SSL context. Context creator returned NULL pointer");
+			else 
+				nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "there was an error while setting certificate file into the SSl context, unable to start TLS profile. Failure found at SSL_CTX_use_certificate_file function. Tried certificate file: %s", 
+					    certificateFile);
+
+			/* dump error stack */
+			nopoll_conn_shutdown (conn);
+			nopoll_ctx_unregister_conn (ctx, conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		} /* end if */
+
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Using certificate key: %s", privateKey);
+		if (SSL_CTX_use_PrivateKey_file (conn->ssl_ctx, privateKey, SSL_FILETYPE_PEM) != 1) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 
+				    "there was an error while setting private file into the SSl context, unable to start TLS profile. Failure found at SSL_CTX_use_PrivateKey_file function. Tried private file: %s", 
+				    privateKey);
+			/* dump error stack */
+			nopoll_conn_shutdown (conn);
+			nopoll_ctx_unregister_conn (ctx, conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		}
+
+		/* check for private key and certificate file to match. */
+		if (! SSL_CTX_check_private_key (conn->ssl_ctx)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 
+				    "seems that certificate file and private key doesn't match!, unable to start TLS profile. Failure found at SSL_CTX_check_private_key function. Used certificate %s, and key: %s",
+				    certificateFile, privateKey);
+			/* dump error stack */
+			nopoll_conn_shutdown (conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		} /* end if */
+
+		if (options != NULL && ! options->disable_ssl_verify) {
+			nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Enabling certificate client peer verification from server");
+			/** really, really ugly hack to let
+			 * __nopoll_conn_ssl_verify_callback to be able to get
+			 * access to the context required to drop some logs */
+			__nopoll_conn_ssl_ctx_debug = ctx;
+			SSL_CTX_set_verify (conn->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, __nopoll_conn_ssl_verify_callback); 
+			SSL_CTX_set_verify_depth (conn->ssl_ctx, 5);
+		} /* end if */
+
+
+		/* create SSL context */
+		conn->ssl = SSL_new (conn->ssl_ctx);       
+		if (conn->ssl == NULL) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "error while creating TLS transport, SSL_new (%p) returned NULL", conn->ssl_ctx);
+			nopoll_conn_shutdown (conn);
+			nopoll_ctx_unregister_conn (ctx, conn);
+
+			/* release connection options */
+			__nopoll_conn_opts_release_if_needed (options);
+
+			return nopoll_false;
+		} /* end if */
+
+		/* set the file descriptor */
+		SSL_set_fd (conn->ssl, conn->session);
+
+		/* don't complete here the operation but flag it as
+		 * pending */
+		conn->pending_ssl_accept = nopoll_true;
+		nopoll_conn_set_sock_block (conn->session, nopoll_false);
+
+		nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Prepared TLS session to be activated on next reads (conn id %d)", conn->id);
+		
+	} /* end if */
+#endif
+
+	/* release connection options */
+	__nopoll_conn_opts_release_if_needed (options);
+
+	return nopoll_true;
+}
+
+/** 
+ * @brief Allows to complete accept operation by setting up all I/O
+ * handlers required to make the WebSocket connection to work.
+ *
+ * @param ctx The context where the operation takes place.
+ *
+ * @param listener The listener where the connection was accepted.
+ *
+ * @param conn The connection that was accepted.
+ *
+ * @param session The socket associated to the listener accepted.
+ *
+ * @param tls_on A boolean indication if the TLS interface should be
+ * enabled or not.
+ *
+ * @return nopoll_true if the listener was accepted otherwise nopoll_false is returned.
+ */
+nopoll_bool nopoll_conn_accept_complete (noPollCtx * ctx, noPollConn * listener, noPollConn * conn, NOPOLL_SOCKET session, nopoll_bool tls_on) {
+
+	if (listener->opts) {
+		if (! nopoll_conn_opts_ref (listener->opts)) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to acquire a reference to the connection option at nopoll_conn_accept_complete() function nopoll_conn_opts_ref () failed..");
+			return nopoll_false;
+		} /* end if */
+	} /* end if */
+
+	return __nopoll_conn_accept_complete_common (ctx, listener->opts, listener, conn, session, tls_on);
+}
+
+/** 
+ * @brief Allows to implement a wait operation until the provided
+ * connection is ready or the provided timeout is reached.
+ *
+ * @param conn The connection that is being waited to be created.
+ *
+ * @param timeout The timeout operation to limit the wait
+ * operation. Timeout is provided in seconds.
+ *
+ * @return The function returns when the timeout was reached or the
+ * connection is ready. In the case the connection is ready when the
+ * function finished nopoll_true is returned, otherwise nopoll_false.
+ */
+nopoll_bool      nopoll_conn_wait_until_connection_ready (noPollConn * conn,
+							  int          timeout)
+{
+	long int total_timeout = timeout * 1000000;
+
+	/* check if the connection already finished its connection
+	   handshake */
+	while (! nopoll_conn_is_ready (conn) && total_timeout > 0) {
+
+		/* check if the connection is ok */
+		if (! nopoll_conn_is_ok (conn)) 
+			return nopoll_false;
+
+		/* wait a bit 0,5ms */
+		nopoll_sleep (500);
+
+		/* reduce the amount of time we have to wait */
+		total_timeout = total_timeout - 500;
+	} /* end if */
+
+	/* report if the connection is ok */
+	return nopoll_conn_is_ok (conn) && nopoll_conn_is_ready (conn);
+}
+
+/* @} */

+ 244 - 0
nopoll/nopoll_conn.h

@@ -0,0 +1,244 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_CONN_H__
+#define __NOPOLL_CONN_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+noPollConn * nopoll_conn_new (noPollCtx  * ctx,
+			      const char * host_ip, 
+			      const char * host_port, 
+			      const char * host_name,
+			      const char * get_url, 
+			      const char * protocols,
+			      const char * origin);
+
+noPollConn * nopoll_conn_new6 (noPollCtx  * ctx,
+			       const char * host_ip, 
+			       const char * host_port, 
+			       const char * host_name,
+			       const char * get_url, 
+			       const char * protocols,
+			       const char * origin);
+
+
+noPollConn * nopoll_conn_new_opts (noPollCtx       * ctx,
+				   noPollConnOpts  * opts,
+				   const char      * host_ip, 
+				   const char      * host_port, 
+				   const char      * host_name,
+				   const char      * get_url, 
+				   const char      * protocols,
+				   const char      * origin);
+
+noPollConn * nopoll_conn_new_with_socket (noPollCtx  * ctx,
+			      noPollConnOpts  * opts,
+			      int          socket,
+			      const char * host_ip,
+			      const char * host_port,
+			      const char * host_name,
+			      const char * get_url,
+			      const char * protocols,
+			      const char * origin);
+
+noPollConn * nopoll_conn_tls_new (noPollCtx  * ctx,
+				  noPollConnOpts * options,
+				  const char * host_ip, 
+				  const char * host_port, 
+				  const char * host_name,
+				  const char * get_url, 
+				  const char * protocols,
+				  const char * origin);
+
+noPollConn * nopoll_conn_tls_new6 (noPollCtx  * ctx,
+				   noPollConnOpts * options,
+				   const char * host_ip, 
+				   const char * host_port, 
+				   const char * host_name,
+				   const char * get_url, 
+				   const char * protocols,
+				   const char * origin);
+
+noPollConn * nopoll_conn_tls_new_with_socket (noPollCtx  * ctx,
+				  noPollConnOpts * options,
+				  int          socket,
+				  const char * host_ip,
+				  const char * host_port,
+				  const char * host_name,
+				  const char * get_url,
+				  const char * protocols,
+				  const char * origin);
+
+noPollConn   * nopoll_conn_accept (noPollCtx * ctx, noPollConn * listener);
+
+noPollConn   * nopoll_conn_accept_socket (noPollCtx * ctx, noPollConn * listener, NOPOLL_SOCKET session);
+
+nopoll_bool    nopoll_conn_accept_complete (noPollCtx      * ctx, 
+					    noPollConn     * listener, 
+					    noPollConn     * conn, 
+					    NOPOLL_SOCKET    session,
+					    nopoll_bool      tls_on);
+
+nopoll_bool    nopoll_conn_ref (noPollConn * conn);
+
+int            nopoll_conn_ref_count (noPollConn * conn);
+
+void           nopoll_conn_unref (noPollConn * conn);
+
+nopoll_bool    nopoll_conn_is_ok (noPollConn * conn);
+
+nopoll_bool    nopoll_conn_is_ready (noPollConn * conn);
+
+nopoll_bool    nopoll_conn_is_tls_on (noPollConn * conn);
+
+NOPOLL_SOCKET nopoll_conn_socket (noPollConn * conn);
+
+void           nopoll_conn_set_socket (noPollConn * conn, NOPOLL_SOCKET _socket);
+
+int           nopoll_conn_get_id (noPollConn * conn);
+
+const char * nopoll_conn_get_requested_url (noPollConn * conn);
+
+noPollCtx   * nopoll_conn_ctx    (noPollConn * conn);
+
+noPollRole    nopoll_conn_role   (noPollConn * conn);
+
+const char  * nopoll_conn_host   (noPollConn * conn);
+
+const char  * nopoll_conn_port   (noPollConn * conn);
+
+const char  * nopoll_conn_get_origin (noPollConn * conn);
+
+const char  * nopoll_conn_get_host_header (noPollConn * conn);
+
+const char  * nopoll_conn_get_cookie (noPollConn * conn);
+
+const char  * nopoll_conn_get_accepted_protocol (noPollConn * conn);
+
+const char  * nopoll_conn_get_requested_protocol (noPollConn * conn);
+
+void          nopoll_conn_set_accepted_protocol (noPollConn * conn, const char * protocol);
+
+int           nopoll_conn_get_close_status (noPollConn * conn);
+
+const char *  nopoll_conn_get_close_reason (noPollConn * conn);
+
+void          nopoll_conn_shutdown (noPollConn * conn);
+
+void          nopoll_conn_close  (noPollConn  * conn);
+
+void          nopoll_conn_close_ext  (noPollConn  * conn, int status, const char * reason, int reason_size);
+
+void          nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr);
+
+noPollPtr     nopoll_conn_get_hook (noPollConn * conn);
+
+nopoll_bool   nopoll_conn_set_sock_block         (NOPOLL_SOCKET socket,
+						  nopoll_bool   enable);
+
+noPollMsg   * nopoll_conn_get_msg (noPollConn * conn);
+
+int           nopoll_conn_send_text (noPollConn * conn, const char * content, long length);
+
+int           nopoll_conn_send_text_fragment (noPollConn * conn, const char * content, long length);
+
+int           nopoll_conn_send_binary (noPollConn * conn, const char * content, long length);
+
+int           nopoll_conn_send_binary_fragment (noPollConn * conn, const char * content, long length);
+
+int           nopoll_conn_complete_pending_write (noPollConn * conn);
+
+int           nopoll_conn_pending_write_bytes    (noPollConn * conn);
+
+int           nopoll_conn_flush_writes           (noPollConn * conn, long timeout, int previous_result);
+
+int           nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout);
+int           aispeech_nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout);
+
+noPollConn  * nopoll_conn_get_listener (noPollConn * conn);
+
+nopoll_bool      nopoll_conn_send_ping (noPollConn * conn);
+
+nopoll_bool      nopoll_conn_send_pong (noPollConn * conn, long length, noPollPtr content);
+
+void          nopoll_conn_set_on_msg (noPollConn              * conn,
+				      noPollOnMessageHandler    on_msg,
+				      noPollPtr                 user_data);
+
+void          nopoll_conn_set_on_ready (noPollConn            * conn,
+					noPollActionHandler     on_ready,
+					noPollPtr               user_data);
+
+void          nopoll_conn_set_on_close (noPollConn            * conn,
+					noPollOnCloseHandler    on_close,
+					noPollPtr               user_data);
+
+int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool masked,
+			    noPollOpCode op_code, long length, noPollPtr content,
+			    long sleep_in_header);
+
+int           __nopoll_conn_send_common (noPollConn * conn, 
+					 const char * content, 
+					 long         length, 
+					 nopoll_bool  has_fin, 
+					 long         sleep_in_header,
+					 noPollOpCode frame_type);
+
+nopoll_bool      nopoll_conn_wait_until_connection_ready (noPollConn * conn,
+							  int          timeout);
+
+void               nopoll_conn_connect_timeout (noPollCtx * ctx,
+						long        microseconds_to_wait);
+
+long               nopoll_conn_get_connect_timeout (noPollCtx * ctx);
+
+/** internal api **/
+void nopoll_conn_complete_handshake (noPollConn * conn);
+
+int nopoll_conn_default_receive (noPollConn * conn, char * buffer, int buffer_size);
+
+int nopoll_conn_default_send (noPollConn * conn, char * buffer, int buffer_size);
+
+void nopoll_conn_mask_content (noPollCtx * ctx, char * payload, int payload_size, char * mask, int desp);
+
+END_C_DECLS
+
+#endif

+ 410 - 0
nopoll/nopoll_conn_opts.c

@@ -0,0 +1,410 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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);
+	if (opts->certificate)
+		if (access (opts->certificate, R_OK) != 0)
+			return nopoll_false;
+	opts->private_key        = nopoll_strdup (private_key);
+	if (opts->private_key)
+		if (access (opts->private_key, R_OK) != 0)
+			return nopoll_false;
+	opts->chain_certificate  = nopoll_strdup (chain_certificate);
+	if (opts->chain_certificate)
+		if (access (opts->chain_certificate, R_OK) != 0)
+			return nopoll_false;
+	opts->ca_certificate     = nopoll_strdup (ca_certificate);
+	if (opts->ca_certificate)
+		if (access (opts->ca_certificate, R_OK) != 0)
+			return nopoll_false;
+
+	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 set arbitrary HTTP headers and content to be sent during
+ * the connection handshake.
+ *
+ * @note String must match the format: "\r\nheader:value\r\nheader2:value2" with
+ * no trailing \r\n.
+ *
+ * @param opts The connection option to configure.
+ *
+ * @param header_string Content for the headers. If you pass NULL the
+ * extra headers are unset.
+ */
+void        nopoll_conn_opts_set_extra_headers (noPollConnOpts * opts, const char * header_string)
+{
+	if (opts == NULL)
+		return;
+
+	if (header_string) {
+		/* configure extra_header content to be sent */
+		opts->extra_headers = nopoll_strdup (header_string);
+	} else {
+		nopoll_free (opts->extra_headers);
+		opts->extra_headers = NULL;
+	} /* end if */
+
+	return;
+}
+
+
+/** 
+ * @brief Allows to skip origin check for an incoming connection.
+ *
+ * This option is highly not recommended because the Origin header
+ * must be provided by all WebSocket clients so the the server side
+ * can check it.
+ *
+ * In most environments not doing so will make the connection to not succeed.
+ *
+ * Use this option just in development environment.
+ *
+ * @param opts The connection options to configure.
+ *
+ * @param skip_check nopoll_bool Skip header check 
+ *
+ */
+void        nopoll_conn_opts_skip_origin_check (noPollConnOpts * opts, nopoll_bool skip_check)
+{
+	/* configure skip origin header check */
+	if (opts) 
+		opts->skip_origin_header_check = skip_check;
+
+	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;
+}
+
+
+/** 
+ * @brief Allows the user to configure the interface to bind the connection to.
+ *
+ * @param opts The connection options object. 
+ *
+ * @param _interface The interface to bind to, or NULL for system default.
+ *
+ */
+void nopoll_conn_opts_set_interface    (noPollConnOpts * opts, const char * _interface)
+{
+	if (opts == NULL)
+		return;
+
+	if (_interface) {
+		/* configure interface */
+		opts->_interface = nopoll_strdup (_interface);
+	} else {
+		nopoll_free (opts->_interface);
+		opts->_interface = NULL;
+	} /* end if */
+
+	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);
+
+	/* interface */
+	nopoll_free (opts->_interface);
+
+	if (opts->extra_headers)
+		nopoll_free (opts->extra_headers);
+
+	/* 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;
+}
+
+/* @} */

+ 79 - 0
nopoll/nopoll_conn_opts.h

@@ -0,0 +1,79 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_CONN_OPTS_H__
+#define __NOPOLL_CONN_OPTS_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+noPollConnOpts * nopoll_conn_opts_new (void);
+
+void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol);
+
+nopoll_bool  nopoll_conn_opts_set_ssl_certs    (noPollConnOpts * opts, 
+						const char     * client_certificate,
+						const char     * private_key,
+						const char     * chain_certificate,
+						const char     * ca_certificate);
+
+void        nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify);
+
+void        nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content);
+
+void        nopoll_conn_opts_skip_origin_check (noPollConnOpts * opts, nopoll_bool skip_check);
+
+nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts);
+
+void        nopoll_conn_opts_unref (noPollConnOpts * opts);
+
+void nopoll_conn_opts_set_reuse        (noPollConnOpts * opts, nopoll_bool reuse);
+
+void nopoll_conn_opts_set_interface    (noPollConnOpts * opts, const char * _interface);
+
+void nopoll_conn_opts_set_extra_headers (noPollConnOpts * opts, const char * extra_headers);
+
+void nopoll_conn_opts_free (noPollConnOpts * opts);
+
+/** internal API **/
+void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options);
+
+END_C_DECLS
+
+#endif

+ 805 - 0
nopoll/nopoll_ctx.c

@@ -0,0 +1,805 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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) && !defined(NOPOLL_OS_RTTHREAD)
+	/* 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;
+
+	/* setup default protocol version */
+	result->protocol_version = 13;
+
+	/* create mutexes */
+	result->ref_mutex = nopoll_mutex_create ();
+
+#if !defined(NOPOLL_OS_WIN32) && !defined(NOPOLL_OS_RTTHREAD)
+	/* install sigpipe handler */
+	signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing);
+#endif
+
+	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]) {
+
+			result = ctx->conn_list[iterator];
+			
+			nopoll_mutex_unlock (ctx->ref_mutex);
+			
+			/* call to notify connection */
+			if (foreach (ctx, result, user_data)) {
+				
+				/* release here the mutex to protect connection list */
+				return result;
+			} /* end if */
+
+			/* realloc again */
+			nopoll_mutex_lock (ctx->ref_mutex);
+
+		} /* 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;
+}
+
+/* @} */

+ 106 - 0
nopoll/nopoll_ctx.h

@@ -0,0 +1,106 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_CTX_H__
+#define __NOPOLL_CTX_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+noPollCtx    * nopoll_ctx_new (void);
+
+nopoll_bool    nopoll_ctx_ref (noPollCtx * ctx);
+
+void           nopoll_ctx_unref (noPollCtx * ctx);
+
+int            nopoll_ctx_ref_count (noPollCtx * ctx);
+
+nopoll_bool    nopoll_ctx_register_conn (noPollCtx  * ctx, 
+					 noPollConn * conn);
+
+void           nopoll_ctx_unregister_conn (noPollCtx  * ctx, 
+					   noPollConn * conn);
+
+int            nopoll_ctx_conns (noPollCtx * ctx);
+
+nopoll_bool    nopoll_ctx_set_certificate (noPollCtx  * ctx, 
+					   const char * serverName, 
+					   const char * certificateFile, 
+					   const char * privateKey, 
+					   const char * optionalChainFile);
+
+nopoll_bool    nopoll_ctx_find_certificate (noPollCtx   * ctx, 
+					    const char  * serverName, 
+					    const char ** certificateFile, 
+					    const char ** privateKey, 
+					    const char ** optionalChainFile);
+
+void           nopoll_ctx_set_on_accept (noPollCtx           * ctx,
+					 noPollActionHandler   on_accept,
+					 noPollPtr             user_data);
+
+void           nopoll_ctx_set_on_open (noPollCtx            * ctx,
+				       noPollActionHandler    on_open,
+				       noPollPtr              user_data);
+
+void           nopoll_ctx_set_on_ready (noPollCtx          * ctx,
+					noPollActionHandler  on_ready,
+					noPollPtr            user_data);
+
+void           nopoll_ctx_set_on_msg    (noPollCtx              * ctx,
+					 noPollOnMessageHandler   on_msg,
+					 noPollPtr                user_data);
+
+void           nopoll_ctx_set_ssl_context_creator (noPollCtx                * ctx,
+						   noPollSslContextCreator    context_creator,
+						   noPollPtr                  user_data);
+
+void           nopoll_ctx_set_post_ssl_check (noPollCtx          * ctx,
+					      noPollSslPostCheck   post_ssl_check,
+					      noPollPtr            user_data);
+
+noPollConn   * nopoll_ctx_foreach_conn (noPollCtx * ctx, noPollForeachConn foreach, noPollPtr user_data);
+
+void           nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version);
+
+void           nopoll_ctx_free (noPollCtx * ctx);
+
+END_C_DECLS
+
+#endif

+ 91 - 0
nopoll/nopoll_decl.c

@@ -0,0 +1,91 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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>
+
+/** 
+ * \addtogroup nopoll_decl_module
+ * @{
+ */
+
+#if !(NOPOLL_OS_RTTHREAD)
+/** 
+ * @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 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 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)
+{
+	free (ref);
+	return;
+}
+#endif
+
+/** 
+ * @}
+ */
+

+ 622 - 0
nopoll/nopoll_decl.h

@@ -0,0 +1,622 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_DECL_H__
+#define __NOPOLL_DECL_H__
+
+/** 
+ * \defgroup nopoll_decl_module Nopoll Declarations: Common Nopoll declarations, Types, macros, and support functions.
+ */
+
+/** 
+ * \addtogroup nopoll_decl_module
+ * @{
+ */
+
+/** 
+ * @brief Set a default I/O wait limit from the default, which is 64
+ * sockets to 4096. Note that this affects \ref nopoll_loop_wait (when
+ * using select() API). If you change this value, you'll have to
+ * recompile noPoll so internal structures will be updated. See the
+ * following document:
+ *
+ *   - https://tangentsoft.net/wskfaq/advanced.html
+ *   (What are the "64 sockets" limitations?)
+ *
+ * For Windows platforms, there are two 64-socket limitations:
+ * 
+ * The Windows event mechanism (e.g. WaitForMultipleObjects()) can
+ * only wait on 64 event objects at a time. Winsock 2 provides the
+ * WSAEventSelect() function which lets you use Windows’ event
+ * mechanism to wait for events on sockets. Because it uses Windows’
+ * event mechanism, you can only wait for events on 64 sockets at a
+ * time. If you want to wait on more than 64 Winsock event objects at
+ * a time, you need to use multiple threads, each waiting on no more
+ * than 64 of the sockets.
+ * 
+ * The select() function is also limited in certain situations to
+ * waiting on 64 sockets at a time. The FD_SETSIZE constant defined in
+ * the Winsock header determines the size of the fd_set structures you
+ * pass to select(). The default value is 64, but if you define this
+ * constant to a different value before including the Winsock header,
+ * it accepts that value instead:
+ *
+ * \code
+ *   // define in your code new limit
+ *   #define FD_SETSIZE 1024
+ *   // then include nopoll.h  (you need to recompile noPoll)
+ *   #include <nopoll.n>
+ * \endcode
+ *
+ * The problem is that modern network stacks are complex, with many
+ * parts coming from various sources, including third parties via
+ * things like Layered Service Providers. When you change this
+ * constant, you’re depending on all these components to play by the
+ * new rules. They’re supposed to, but not all do. The typical symptom
+ * is that they ignore sockets beyond the 64th in larger fd_set
+ * structures. You can get around this limitation with threads, just
+ * as in the event object case.
+ */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 4096
+#endif
+
+/* include platform specific configuration */
+#include <nopoll_config.h>
+
+/* max buffer size to process incoming handshake */
+#define NOPOLL_HANDSHAKE_BUFFER_SIZE 8192
+
+/* include this at this place to load GNU extensions */
+#if defined(__GNUC__)
+#  ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+#  endif
+#  define __NOPOLL_PRETTY_FUNCTION__ __PRETTY_FUNCTION__
+#  define __NOPOLL_LINE__            __LINE__
+#  define __NOPOLL_FILE__            __FILE__
+#elif defined(_MSC_VER)
+#  define __NOPOLL_PRETTY_FUNCTION__ __FUNCDNAME__
+#  define __NOPOLL_LINE__            __LINE__
+#  define __NOPOLL_FILE__            __FILE__
+#else
+/* unknown compiler */
+#define __NOPOLL_PRETTY_FUNCTION__ ""
+#define __NOPOLL_LINE__            0
+#define __NOPOLL_FILE__            ""
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* only include unistd.h if unix platform is found or gnu gcc compiler
+ * is found */
+#if defined(__GNUC__) || defined(NOPOLL_OS_UNIX)
+# include <unistd.h>
+#endif
+
+// #include <sys/types.h>
+// #include <sys/stat.h>
+// #include <fcntl.h>
+#include <ctype.h>
+
+/* Direct portable mapping definitions */
+#if defined(NOPOLL_OS_UNIX)
+
+/* Portable definitions while using noPoll Library */
+#define NOPOLL_EINTR           EINTR
+/** 
+ * @brief Portable definition for EWOULDBLOCK errno code.
+ */
+#define NOPOLL_EWOULDBLOCK     EWOULDBLOCK
+#define NOPOLL_EINPROGRESS     EINPROGRESS
+#define NOPOLL_ENOTCONN        ENOTCONN
+#define NOPOLL_EAGAIN          EAGAIN
+#define NOPOLL_SOCKET          int
+#define NOPOLL_INVALID_SOCKET  -1
+#define NOPOLL_SOCKET_ERROR    -1
+#define nopoll_close_socket(s) do {if ( s >= 0) {close (s);}} while (0)
+#define nopoll_is_disconnected (errno == EPIPE)
+
+#endif /* end defined(AXL_OS_UNIX) */
+
+#if defined(NOPOLL_OS_RTTHREAD)
+
+#include <rtthread.h>
+
+/** let's have support for R_OK if it is not defined **/
+#  ifndef R_OK
+#   define R_OK        4
+#  endif
+
+/* Portable definitions while using noPoll Library */
+#define NOPOLL_EINTR           EINTR
+/**
+ * @brief Portable definition for EWOULDBLOCK errno code.
+ */
+#define NOPOLL_EWOULDBLOCK     EWOULDBLOCK
+#define NOPOLL_EINPROGRESS     EINPROGRESS
+#define NOPOLL_ENOTCONN        ENOTCONN
+#define NOPOLL_EAGAIN          EAGAIN
+#define NOPOLL_SOCKET          int
+#define NOPOLL_INVALID_SOCKET  -1
+#define NOPOLL_SOCKET_ERROR    -1
+#define nopoll_close_socket(s) do {if ( s >= 0) {lwip_close (s);}} while (0)
+
+#endif /* end defined(AXL_OS_UNIX) */
+
+#if defined(NOPOLL_OS_WIN32)
+
+/** let's have support for R_OK if it is not defined **/
+#  ifndef R_OK
+#   define R_OK        4
+#  endif
+
+
+/* additional includes for the windows platform */
+
+/* _WIN32_WINNT note: If the application including the header defines
+ * the _WIN32_WINNT, it must include the bits defined by the value
+ * 0x501. */
+#ifndef _WIN32_WINNT
+#  define _WIN32_WINNT 0x501
+#elif _WIN32_WINNT < 0x501
+#  undef _WIN32_WINNT
+#  define _WIN32_WINNT 0x501
+#endif
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <fcntl.h>
+#include <io.h>
+#include <process.h>
+#include <time.h>
+
+#ifdef _MSC_FULL_VER
+#define strcasecmp(string1, string2) _stricmp(string1, string2)
+#endif
+
+#define NOPOLL_EINTR           WSAEINTR
+#define NOPOLL_EWOULDBLOCK     WSAEWOULDBLOCK
+#define NOPOLL_EINPROGRESS     WSAEINPROGRESS
+#define NOPOLL_ENOTCONN        WSAENOTCONN
+#define NOPOLL_EAGAIN          WSAEWOULDBLOCK
+#define SHUT_RDWR              SD_BOTH
+#define SHUT_WR                SD_SEND
+#define NOPOLL_SOCKET          SOCKET
+#define NOPOLL_INVALID_SOCKET  INVALID_SOCKET
+#define NOPOLL_SOCKET_ERROR    SOCKET_ERROR
+#define nopoll_close_socket(s) do {if ( s >= 0) {closesocket (s);}} while (0)
+#define uint16_t               u_short
+#define nopoll_is_disconnected ((errno == WSAESHUTDOWN) || (errno == WSAECONNABORTED) || (errno == WSAECONNRESET))
+
+/* a definition to avoid warnings */
+#define strlen (int) strlen
+
+/* no link support windows */
+#define S_ISLNK(m) (0)
+
+#endif /* end defined(NOPOLL_OS_WINDOWS) */
+
+#if defined(NOPOLL_OS_UNIX)
+#include <sys/types.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <time.h>
+#include <unistd.h>
+#endif
+
+#if defined(NOPOLL_OS_RTTHREAD)
+#include <stdint.h>
+#include <string.h>
+#include <rtthread.h>
+
+// #include <sys/types.h>
+// #include <fcntl.h>
+#include <lwip/netdb.h>
+#include <lwip/sockets.h>
+#include <time.h>
+// #include <unistd.h>
+
+#ifdef send
+#undef send
+#endif
+
+#endif
+
+
+/* additional headers for poll support */
+#if defined(NOPOLL_HAVE_POLL)
+#include <sys/poll.h>
+#endif
+
+/* additional headers for linux epoll support */
+#if defined(NOPOLL_HAVE_EPOLL)
+#include <sys/epoll.h>
+#endif
+
+#include <errno.h>
+
+#if defined(NOPOLL_OS_WIN32)
+/* errno redefinition for windows platform. this declaration must
+ * follow the previous include. */
+#ifdef  errno
+#undef  errno
+#endif
+#define errno (WSAGetLastError())
+#endif
+
+#if defined(NOPOLL_OS_RTTHREAD)
+#ifdef  errno
+#undef  errno
+#endif
+#define errno (*_rt_errno())
+#endif
+
+/**
+ * @brief Common definition to have false (\ref nopoll_false) value (which is defined to 0 integer value).
+ */
+#define nopoll_false ((int)0)
+/** 
+ * @brief Common definition to have true (\ref nopoll_true) value (which is defined to 1 integer value).
+ */
+#define nopoll_true  ((int)1)
+
+/** 
+ * @brief Bool definition for the Nopoll toolkit. This type built on
+ * top of <b>int</b> is used along with \ref nopoll_false and \ref
+ * nopoll_true to model those API functions and attributes that
+ * returns or receive a boolean state.
+ */
+typedef int nopoll_bool;
+
+/** 
+ * @brief Pointer to any structure definition. It should be required
+ * to use this definition, however, some platforms doesn't support the
+ * <b>void *</b> making it necessary to use the <b>char *</b>
+ * definition as a general way to represent references.
+ */
+typedef void * noPollPtr;
+
+/** 
+ * @brief Execution context object used by the API to provide default
+ * settings.
+ */
+typedef struct _noPollCtx noPollCtx;
+
+/** 
+ * @brief Abstraction that represents a connection that maybe be a listener created by \ref nopoll_listener_new or because the connection was received as a consequence of that call, or because it is a client connection created by \ref nopoll_conn_new 
+ *
+ * See noPoll API because there are other methods to create connections (not only previous mentioned functions).
+ */
+typedef struct _noPollConn noPollConn;
+
+/** 
+ * @brief Optional connection options to change default behaviour.
+ */
+typedef struct _noPollConnOpts noPollConnOpts;
+
+/** 
+ * @brief Abstraction that represents a selected IO wait mechanism.
+ */
+typedef struct _noPollIoEngine noPollIoEngine;
+
+/** 
+ * @brief Abstraction that represents a single websocket message
+ * received.
+ */
+typedef struct _noPollMsg noPollMsg;
+
+/** 
+ * @brief Abstraction that represents the status and data exchanged
+ * during the handshake.
+ */
+typedef struct _noPollHandshake noPollHandShake;
+
+/** 
+ * @brief Nopoll debug levels.
+ * 
+ * While reporting log to the console, these levels are used to report
+ * the severity for such log.
+ */
+typedef enum {
+	/** 
+	 * @brief Debug level. Only used to report common
+	 * circumstances that represent the proper functionality.
+	 */
+	NOPOLL_LEVEL_DEBUG, 
+	/** 
+	 * @brief Warning level. Only used to report that an internal
+	 * issue have happend that could be interesting while
+	 * reporting error, but it could also mean common situations.
+	 */
+	NOPOLL_LEVEL_WARNING, 
+	/** 
+	 * @brief Critical level. Only used to report critical
+	 * situations where some that have happened shouldn't. 
+	 *
+	 * This level should only be used while reporting critical
+	 * situations.
+	 */
+	NOPOLL_LEVEL_CRITICAL}  
+noPollDebugLevel;
+
+/** 
+ * @brief Describes the connection role (how it was initiated).
+ */
+typedef enum {
+	/** 
+	 * @brief Unknown role, returned/used when the connection isn't defined.
+	 */
+	NOPOLL_ROLE_UNKNOWN,
+	/** 
+	 * @brief When the connection was created connecting to a web
+	 * socket server (see \ref nopoll_conn_new).
+	 */
+	NOPOLL_ROLE_CLIENT,
+	/** 
+	 * @brief When the connection was accepted being a listener
+	 * process.
+	 */
+	NOPOLL_ROLE_LISTENER,
+	/** 
+	 * @brief When the connection was created by \ref
+	 * nopoll_listener_new to accept incoming connections.
+	 */
+	NOPOLL_ROLE_MAIN_LISTENER
+} noPollRole;
+
+/** 
+ * @brief List of supported IO waiting mechanism available.
+ */
+typedef enum {
+	/** 
+	 * @brief Selects the default (best) IO mechanism found on the
+	 * system.
+	 */
+	NOPOLL_IO_ENGINE_DEFAULT,
+	/** 
+	 * @brief Selects the select(2) based IO wait mechanism.
+	 */
+	NOPOLL_IO_ENGINE_SELECT,
+	/** 
+	 * @brief Selects the poll(2) based IO wait mechanism.
+	 */
+	NOPOLL_IO_ENGINE_POLL,
+	/** 
+	 * @brief Selects the epoll(2) based IO wait mechanism.
+	 */
+	NOPOLL_IO_ENGINE_EPOLL
+} noPollIoEngineType;
+
+/** 
+ * @brief Support macro to allocate memory using nopoll_calloc function,
+ * making a casting and using the sizeof keyword.
+ *
+ * @param type The type to allocate
+ * @param count How many items to allocate.
+ * 
+ * @return A newly allocated pointer.
+ */
+#define nopoll_new(type, count) (type *) nopoll_calloc (count, sizeof (type))
+
+/** 
+ * @brief Allows to check a condition and return if it is not meet.
+ * 
+ * @param ctx The context where the operation will take place.
+ * @param expr The expresion to check.
+ */
+#define nopoll_return_if_fail(ctx, expr)					\
+	if (!(expr)) {__nopoll_log (ctx, __function_name__, __file__, __line__, NOPOLL_LEVEL_CRITICAL, "Expresion '%s' have failed at %s (%s:%d)", #expr, __NOPOLL_PRETTY_FUNCTION__, __NOPOLL_FILE__, __NOPOLL_LINE__); return;}
+
+/** 
+ * @brief Allows to check a condition and return the given value if it
+ * is not meet.
+ *
+ * @param ctx The context where the operation will take place.
+ * 
+ * @param expr The expresion to check.
+ *
+ * @param val The value to return if the expression is not meet.
+ */
+#define nopoll_return_val_if_fail(ctx, expr, val)			\
+	if (!(expr)) { __nopoll_log (ctx, __function_name__, __file__, __line__, NOPOLL_LEVEL_CRITICAL, "Expresion '%s' have failed, returning: %s at %s (%s:%d)", #expr, #val, __NOPOLL_PRETTY_FUNCTION__, __NOPOLL_FILE__, __NOPOLL_LINE__); return val;}
+
+
+/** 
+ * @internal
+ *
+ * C++ support declarations borrowed from the libtool webpage. Thanks
+ * you guys for this information. 
+ *
+ * BEGIN_C_DECLS should be used at the beginning of your declarations,
+ * so that C++ compilers don't mangle their names.  Use END_C_DECLS at
+ * the end of C declarations.
+ */
+#undef BEGIN_C_DECLS
+#undef END_C_DECLS
+#ifdef __cplusplus
+# define BEGIN_C_DECLS extern "C" {
+# define END_C_DECLS }
+#else
+# define BEGIN_C_DECLS /* empty */
+# define END_C_DECLS /* empty */
+#endif
+
+
+/** 
+ * @brief Type of frames and opcodes supported by noPoll.
+ */
+typedef enum {
+	/** 
+	 * @brief Support to model unknown op code.
+	 */
+	NOPOLL_UNKNOWN_OP_CODE = -1,
+	/** 
+	 * @brief Denotes a continuation frame.
+	 */
+	NOPOLL_CONTINUATION_FRAME = 0,
+	/** 
+	 * @brief Denotes a text frame (utf-8 content) and the first
+	 * frame of the message.
+	 */
+	NOPOLL_TEXT_FRAME         = 1,
+	/** 
+	 * @brief Denotes a binary frame and the first frame of the
+	 * message.
+	 */
+	NOPOLL_BINARY_FRAME       = 2,
+	/** 
+	 * @brief Denotes a close frame request.
+	 */
+	NOPOLL_CLOSE_FRAME        = 8,
+	/** 
+	 * @brief Denotes a ping frame (used to ring test the circuit
+	 * and to keep alive the connection).
+	 */
+	NOPOLL_PING_FRAME         = 9,
+	/** 
+	 * @brief Denotes a pong frame (reply to ping request).
+	 */
+	NOPOLL_PONG_FRAME         = 10
+} noPollOpCode;
+
+/** 
+ * @brief SSL/TLS protocol type to use for the client or listener
+ * connection. 
+ */
+typedef enum {
+#if defined(NOPOLL_HAVE_SSLv23_ENABLED)	
+	/** 
+	 * @brief Allows to define SSLv23 as SSL protocol used by the
+	 * client or server connection. A TLS/SSL connection
+	 * established with these methods may understand SSLv3, TLSv1,
+	 * TLSv1.1 and TLSv1.2 protocols (\ref NOPOLL_METHOD_SSLV3, \ref NOPOLL_METHOD_TLSV1, ...)
+	 */
+	NOPOLL_METHOD_SSLV23      = 2,
+#endif
+#if defined(NOPOLL_HAVE_SSLv3_ENABLED)	
+	/** 
+	 * @brief Allows to define SSLv3 as SSL protocol used by the
+	 * client or server connection. A connection/listener
+	 * established with this method will only understand this
+	 * method.
+	 */
+	NOPOLL_METHOD_SSLV3       = 3,
+#endif
+#if defined(NOPOLL_HAVE_TLSv10_ENABLED)
+	/** 
+	 * @brief Allows to define TLSv1 as SSL protocol used by the
+	 * client or server connection. A connection/listener
+	 * established with this method will only understand this
+	 * method.
+	 */
+	NOPOLL_METHOD_TLSV1       = 4,
+#endif	
+#if defined(NOPOLL_HAVE_TLSv11_ENABLED)
+	/** 
+	 * @brief Allows to define TLSv1.1 as SSL protocol used by the
+	 * client or server connection. A connection/listener
+	 * established with this method will only understand this
+	 * method.
+	 */
+	NOPOLL_METHOD_TLSV1_1     = 5
+#endif
+#if defined(NOPOLL_HAVE_TLSv12_ENABLED)
+	,
+	/** 
+	 * @brief Allows to define TLSv1.2 as SSL protocol used by the
+	 * client or server connection. A connection/listener
+	 * established with this method will only understand this
+	 * method.
+	 */
+	NOPOLL_METHOD_TLSV1_2     = 6
+#endif
+#if defined(NOPOLL_HAVE_TLS_FLEXIBLE_ENABLED)
+	,
+	/** 
+	 * @brief Allows to define TLS flexible negotiation where the
+	 * highest version available will be negotiated by both
+	 * ends. If you want a particular TLS version, do not use this
+	 * method. 
+	 *
+	 * Security consideration: by using this method you are
+	 * accepting that the remote peer can downgrade to the lowest
+	 * version of the protocol. In the case you want to use a
+	 * particular version do not use this flexible method.
+	 */
+	NOPOLL_METHOD_TLS_FLEXIBLE     = 7
+#endif		
+} noPollSslProtocol ;
+
+/** 
+ * @brief Transport indication to be used by various internal and
+ * public APIs
+ */
+typedef enum {
+	/** 
+	 * Use IPv4 transport
+	 */
+	NOPOLL_TRANSPORT_IPV4 = 1,
+	/** 
+	 * Use IPv6 transport
+	 */
+	NOPOLL_TRANSPORT_IPV6 = 2
+} noPollTransport;
+
+BEGIN_C_DECLS
+
+noPollPtr  nopoll_calloc  (size_t count, size_t size);
+
+noPollPtr  nopoll_realloc (noPollPtr ref, size_t size);
+
+void       nopoll_free    (noPollPtr ref);
+
+END_C_DECLS
+
+#endif
+
+/* @} */

+ 329 - 0
nopoll/nopoll_handlers.h

@@ -0,0 +1,329 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_HANDLERS_H__
+#define __NOPOLL_HANDLERS_H__
+
+/** 
+ * \defgroup nopoll_handlers noPoll Handlers: Handler definitions used by the library to du async notifications
+ */
+
+/** 
+ * \addtogroup nopoll_handlers
+ * @{
+ */
+
+/** 
+ * @brief General async handler definition used to notify generic
+ * events associated to a connection.
+ *
+ * Currently this handler is used by:
+ * - \ref nopoll_ctx_set_on_accept
+ * - \ref nopoll_ctx_set_on_open
+ *
+ * @param ctx The context where the wait is happening.
+ *
+ * @param conn The connection where the data or something meaningful
+ * was detected.
+ *
+ * @param user_data Optional user data pointer passed in into the handler.
+ *
+ * @return The function returns a boolean value which is interpreted
+ * in an especific form according to the event.
+ */
+typedef nopoll_bool (*noPollActionHandler) (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data);
+
+/** 
+ * @brief Handler used to define the create function for an IO mechanism.
+ *
+ * @param ctx The context where the io mechanism will be created.
+ */
+typedef noPollPtr (*noPollIoMechCreate)  (noPollCtx * ctx);
+
+/** 
+ * @brief Handler used to define the IO wait set destroy function for
+ * an IO mechanism.
+ *
+ * @param ctx The context where the io mechanism will be destroyed.
+ *
+ * @param io_object The io object to be destroyed as created by \ref
+ * noPollIoMechCreate handler.
+ */
+typedef void (*noPollIoMechDestroy)  (noPollCtx * ctx, noPollPtr io_object);
+
+/** 
+ * @brief Handler used to define the IO wait set clear function for an
+ * IO mechanism.
+ *
+ * @param ctx The context where the io mechanism will be cleared.
+ *
+ * @param io_object The io object to be created as created by \ref
+ * noPollIoMechCreate handler.
+ */
+typedef void (*noPollIoMechClear)  (noPollCtx * ctx, noPollPtr io_object);
+
+
+/** 
+ * @brief Handler used to define the IO wait function for an IO
+ * mechanism.
+ *
+ * @param ctx The context where the io mechanism was created.
+ *
+ * @param io_object The io object to be created as created by \ref
+ * noPollIoMechCreate handler where the wait will be implemented.
+ */
+typedef int (*noPollIoMechWait)  (noPollCtx * ctx, noPollPtr io_object);
+
+
+/** 
+ * @brief Handler used to define the IO add to set function for an IO
+ * mechanism.
+ *
+ * @param ctx The context where the io mechanism was created.
+ *
+ * @param conn The noPollConn to be added to the working set.
+ *
+ * @param io_object The io object to be created as created by \ref
+ * noPollIoMechCreate handler where the wait will be implemented.
+ */
+typedef nopoll_bool (*noPollIoMechAddTo)  (int               fds, 
+					   noPollCtx       * ctx,
+					   noPollConn      * conn,
+					   noPollPtr         io_object);
+
+
+/** 
+ * @brief Handler used to define the IO is set function for an IO
+ * mechanism.
+ *
+ * @param ctx The context where the io mechanism was created.
+ *
+ * @param conn The noPollConn to be added to the working set.
+ *
+ * @param io_object The io object to be created as created by \ref
+ * noPollIoMechCreate handler where the wait will be implemented.
+ */
+typedef nopoll_bool (*noPollIoMechIsSet)  (noPollCtx       * ctx,
+					   int               fds, 
+					   noPollPtr         io_object);
+
+/** 
+ * @brief Handler used to define the foreach function that is used by
+ * \ref nopoll_ctx_foreach_conn
+ *
+ * @param ctx The context where the foreach operation is taking place.
+ *
+ * @param conn The connection notified
+ *
+ * @param user_data Optional user defined pointer received at \ref
+ * nopoll_ctx_foreach_conn.
+ *
+ * @return nopoll_true to stop the foreach process, otherwise
+ * nopoll_false to keep checking the next connection until all
+ * connections are notified.
+ */
+typedef nopoll_bool (*noPollForeachConn)  (noPollCtx  * ctx,
+					   noPollConn * conn,
+					   noPollPtr    user_data);
+
+/** 
+ * @brief Handler definition used to describe read functions used by \ref noPollConn.
+ *
+ * @param conn The connection where the readOperation will take place.
+ *
+ * @param buffer The buffer where data read from socket will be placed.
+ *
+ * @param buffer_size The buffer size that is receiving the function.
+ */
+typedef int (*noPollRead) (noPollConn * conn,
+			   char       * buffer,
+			   int          buffer_size);
+
+/** 
+ * @brief Handler definition used to notify websocket messages
+ * received.
+ *
+ * This handler will be called when a websocket message is
+ * received. Keep in mind the reference received on this handler will
+ * be finished when the handler ends. If you need to have a reference
+ * to the message after handler execution, acquire a reference via
+ * \ref nopoll_msg_ref.
+ *
+ * @param ctx The context where the messagewas received.
+ *
+ * @param conn The connection where the message was received.
+ *
+ * @param msg The websocket message was received.
+ *
+ * @param user_data An optional user defined pointer.
+ */
+typedef void (*noPollOnMessageHandler) (noPollCtx  * ctx,
+					noPollConn * conn,
+					noPollMsg  * msg,
+					noPollPtr    user_data);
+
+/** 
+ * @brief Handler definition used by \ref nopoll_conn_set_on_close.
+ *
+ * Handler definition for the function that is called when the
+ * connection is closed but just before shutting down the socket
+ * associated to the connection.
+ *
+ * @param ctx The context where the operation will take place.
+ *
+ * @param conn The connection where the operation will take place.
+ *
+ * @param user_data The reference that was configured to be passed in
+ * into the handler.
+ */
+typedef void (*noPollOnCloseHandler)    (noPollCtx  * ctx,
+					 noPollConn * conn, 
+					 noPollPtr    user_data);
+
+/** 
+ * @brief Mutex creation handler used by the library.
+ *
+ * @return A reference to the mutex created (already initialized).
+ */
+typedef noPollPtr (*noPollMutexCreate) (void);
+
+/** 
+ * @brief Mutex destroy handler used by the library.
+ *
+ * @param The mutex to destroy.
+ */
+typedef void (*noPollMutexDestroy) (noPollPtr mutex);
+
+/** 
+ * @brief Mutex lock handler used by the library.
+ *
+ * @param The mutex where to implement the lock operation.
+ */
+typedef void (*noPollMutexLock) (noPollPtr mutex);
+
+/** 
+ * @brief Mutex unlock handler used by the library.
+ *
+ * @param The mutex where to implement the unlock operation.
+ */
+typedef void (*noPollMutexUnlock) (noPollPtr mutex);
+
+/** 
+ * @brief Handler used by nopoll_log_set_handler to receive all log
+ * notifications produced by the library on this function.
+ *
+ * @param ctx The context where the operation is happening.
+ *
+ * @param level The log level 
+ *
+ * @param log_msg The actual log message reported.
+ *
+ * @param user_data A reference to user defined pointer passed in into  the function.
+ */
+typedef void (*noPollLogHandler) (noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data);
+
+/** 
+ * @brief An optional handler that allows user land code to define how
+ * is SSL_CTX (SSL context) created and which are the settings it
+ * should have before taking place SSL/TLS handshake.
+ *
+ * NOTE: that the function should return one context for every
+ * connection created. Do not reuse unless you know what you are
+ * doing.
+ *
+ * A very bare implementation for this context creation will be:
+ *
+ * \code 
+ * SSL_CTX * my_ssl_ctx_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
+ *
+ * @param ctx The context where the operation is taking place.
+ *
+ * @param conn The connection that is being requested for a new context (SSL_CTX). Use is_client to know if this is a connecting client or a listener connection.
+ *
+ * @param opts Optional reference to the connection object created for this connection.
+ *
+ * @param is_client nopoll_true to signal that this is a request for a context for a client connection. Otherwise, it is for a listener connection.
+ *
+ * @param user_data User defined pointer that received on this function as defined at \ref nopoll_ctx_set_ssl_context_creator.
+ *
+ * @return The function must return a valid SSL_CTX object (see OpenSSL documentation to know more about this) or NULL if it fails.
+ */
+typedef noPollPtr (*noPollSslContextCreator) (noPollCtx       * ctx, 
+					      noPollConn      * conn, 
+					      noPollConnOpts  * opts, 
+					      nopoll_bool       is_client, 
+					      noPollPtr         user_data);
+
+/** 
+ * @brief Optional user defined handler that allows to execute SSL
+ * post checks code before proceed.
+ *
+ * This handler is configured at \ref nopoll_ctx_set_post_ssl_check
+ * and allows to implement custom actions while additional
+ * verifications about certificate received, validation based on
+ * certain attributes, etc.
+ *
+ * Note that when this handler is called, the SSL handshake has
+ * finished without error. In case of SSL handshake failure, this
+ * handler is not executed.
+ *
+ * @param ctx The context where the operation happens.
+ *
+ * @param conn The connection where the operation takes place and for which the post SSL check is being done.
+ *
+ * @param SSL_CTX The OpenSSL SSL_CTX object created for this connection.
+ *
+ * @param SSL The OpenSSL SSL object created for this connection.
+ *
+ * @param user_data User defined data that is received on this handler as configured at \ref nopoll_ctx_set_post_ssl_check
+ */
+typedef nopoll_bool (*noPollSslPostCheck) (noPollCtx      * ctx,
+					   noPollConn     * conn,
+					   noPollPtr        SSL_CTX,
+					   noPollPtr        SSL,
+					   noPollPtr        user_data);
+
+
+#endif
+
+/* @} */

+ 233 - 0
nopoll/nopoll_io.c

@@ -0,0 +1,233 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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;
+}
+
+

+ 52 - 0
nopoll/nopoll_io.h

@@ -0,0 +1,52 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_IO_H__
+#define __NOPOLL_IO_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type);
+
+void             nopoll_io_release_engine (noPollIoEngine * engine);
+
+END_C_DECLS
+
+#endif 

+ 616 - 0
nopoll/nopoll_listener.c

@@ -0,0 +1,616 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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 Implementation used by all sock listener functions.
+ */
+NOPOLL_SOCKET     __nopoll_listener_sock_listen_internal      (noPollCtx        * ctx,
+							       noPollTransport    transport,
+							       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 */
+	switch (transport) {
+	case NOPOLL_TRANSPORT_IPV4:
+    	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]);
+		break;
+#if NOPLL_IPV6
+	case NOPOLL_TRANSPORT_IPV6:
+		/* configure hints */
+		hints.ai_family   = AF_INET6;
+		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_flags    = AI_PASSIVE | AI_NUMERICHOST;
+
+		/* check value received */
+		if (memcmp (host, "0.0.0.0", 7) == 0) {
+			nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received an address (%s) that is not a valid IPv6 address..", host);
+			return -1;
+		} /* end if */
+		
+		/* resolve hosting name */
+		if (getaddrinfo (host, port, &hints, &res) != 0) {
+			nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to resolve host name %s, errno=%d", host, errno);
+			return -1;
+		} /* end if */
+		break;
+#endif
+	} /* end switch */
+
+	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));
+
+	/* create socket */
+	fd = socket (AF_INET, SOCK_STREAM, 0);
+	if (fd <= 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);
+
+	/* call to bind */
+	tries    = 0;
+	while (1) {
+		/* call bind */
+		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;
+}
+
+/** 
+ * @internal Function to create a WebSocket listener
+ */
+noPollConn      * __nopoll_listener_new_opts_internal (noPollCtx      * ctx,
+						       noPollTransport  transport,
+						       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_internal (ctx, transport, host, port);
+	if (session == NOPOLL_INVALID_SOCKET) {
+		nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to start listener error was: errno=%d", errno);
+		return NULL;
+	} /* end if */
+
+	/* create noPollConn ection object */
+	listener           = nopoll_new (noPollConn, 1);
+	listener->refs     = 1;
+	/* create mutex */
+	listener->ref_mutex = nopoll_mutex_create ();
+	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->send      = nopoll_conn_default_send;
+
+	/* configure connection options */
+	listener->opts      = opts;
+
+	nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d, transport: %s)",
+		    listener->host, listener->port, listener->session, (transport == NOPOLL_TRANSPORT_IPV4 ? "IPv4" : "IPv6"));
+
+	return listener;
+}
+
+
+/** 
+ * @internal Creates a listener socket on the provided port.
+ */
+NOPOLL_SOCKET     nopoll_listener_sock_listen      (noPollCtx   * ctx,
+						    const char  * host,
+						    const char  * port)
+{
+	return __nopoll_listener_sock_listen_internal (ctx, NOPOLL_TRANSPORT_IPV4, host, port);
+}
+
+/** 
+ * @brief Creates a new websocket server listener on the provided host
+ * name and port (IPv4)
+ *
+ * @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);
+}
+
+#if NOPLL_IPV6
+/** 
+ * @brief Creates a new websocket server listener on the provided host
+ * name and port (IPv6).
+ *
+ * See \ref nopoll_listener_new for more information.
+ *
+ * @param ctx See \ref nopoll_listener_new for more information.
+ *
+ * @param host See \ref nopoll_listener_new for more information.
+ *
+ * @param port See \ref nopoll_listener_new for more information.
+ *
+ * @return See \ref nopoll_listener_new for more information.
+ */
+noPollConn      * nopoll_listener_new6 (noPollCtx  * ctx,
+					const char * host,
+					const char * port)
+{
+	return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, NULL, host, port);
+}
+#endif
+
+/** 
+ * @brief Creates a new websocket server listener on the provided host
+ * name and port (IPv4).
+ *
+ * @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)
+{
+	/* call common implementation */
+	return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV4, opts, host, port);
+}
+
+#if NOPLL_IPV6
+/** 
+ * @brief Creates a new websocket server listener on the provided host
+ * name and port (IPv6).
+ *
+ * See \ref nopoll_listener_new_opts for more information.
+ *
+ * @param ctx See \ref nopoll_listener_new_opts
+ *
+ * @param opts See \ref nopoll_listener_new_opts
+ *
+ * @param host See \ref nopoll_listener_new_opts
+ *
+ * @param port See \ref nopoll_listener_new_opts
+ *
+ * @return See \ref nopoll_listener_new_opts
+ */
+noPollConn      * nopoll_listener_new_opts6 (noPollCtx      * ctx,
+					     noPollConnOpts * opts,
+					     const char     * host,
+					     const char     * port)
+{
+	/* call common implementation */
+	return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, opts, host, port);
+}
+#endif
+
+/** 
+ * @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) (IPv4 version).
+ *
+ * @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);
+}
+
+#if NOPLL_IPV6
+/** 
+ * @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) (IPv6 version).
+ *
+ * See \ref nopoll_listener_tls_new for more information.
+ *
+ * @param ctx See \ref nopoll_listener_tls_new for more information.
+ *
+ * @param host See \ref nopoll_listener_tls_new for more information.
+ *
+ * @param port See \ref nopoll_listener_tls_new for more information.
+ *
+ * @return See \ref nopoll_listener_tls_new for more information.
+ */
+noPollConn      * nopoll_listener_tls_new6 (noPollCtx  * ctx,
+					    const char * host,
+					    const char * port)
+{
+	return nopoll_listener_tls_new_opts6 (ctx, NULL, host, port);
+}
+#endif
+
+/** 
+ * @internal Common implementation 
+ */
+noPollConn      * __nopoll_listener_tls_new_opts_internal (noPollCtx      * ctx,
+							   noPollTransport  transport,
+							   noPollConnOpts * opts,
+							   const char     * host,
+							   const char     * port)
+{
+	noPollConn * listener;
+
+	/* call to get listener from base function */
+	listener = __nopoll_listener_new_opts_internal (ctx, transport, opts, host, port);
+	if (! listener)
+		return listener;
+
+	/* setup TLS support */
+	listener->tls_on = nopoll_true;
+	listener->opts   = opts;
+
+	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) (IPv4 version).
+ *
+ * @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)
+{
+	return __nopoll_listener_tls_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV4, opts, host, port);
+}
+
+#if NOPLL_IPV6
+/** 
+ * @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) (IPv6 version).
+ *
+ * See \ref nopoll_listener_tls_new_opts for more information.
+ *
+ * @param ctx See \ref nopoll_listener_tls_new_opts for more information.
+ *
+ * @param opts See \ref nopoll_listener_tls_new_opts for more information.
+ *
+ * @param host See \ref nopoll_listener_tls_new_opts for more information.
+ *
+ * @param port See \ref nopoll_listener_tls_new_opts for more information.
+ *
+ * @return See \ref nopoll_listener_tls_new_opts for more information.
+ */
+noPollConn      * nopoll_listener_tls_new_opts6 (noPollCtx      * ctx,
+						 noPollConnOpts * opts,
+						 const char     * host,
+						 const char     * port)
+{
+	return __nopoll_listener_tls_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, opts, host, port);
+}
+#endif
+
+/** 
+ * @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 */
+
+#if NOPOLL_TLS
+	/* 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);
+#endif
+	
+	/* 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;
+	/* create mutex */
+	listener->ref_mutex = nopoll_mutex_create ();
+	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->send    = 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);
+}
+
+/* @} */

+ 98 - 0
nopoll/nopoll_listener.h

@@ -0,0 +1,98 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_LISTENER_H__
+#define __NOPOLL_LISTENER_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+NOPOLL_SOCKET     nopoll_listener_sock_listen      (noPollCtx   * ctx,
+						    const char  * host,
+						    const char  * port);
+
+noPollConn      * nopoll_listener_new (noPollCtx  * ctx,
+				       const char * host,
+				       const char * port);
+
+noPollConn      * nopoll_listener_new6 (noPollCtx  * ctx,
+					const char * host,
+					const char * port);
+
+noPollConn      * nopoll_listener_new_opts (noPollCtx      * ctx,
+					    noPollConnOpts * opts,
+					    const char     * host,
+					    const char     * port);
+
+noPollConn      * nopoll_listener_new_opts6 (noPollCtx      * ctx,
+					     noPollConnOpts * opts,
+					     const char     * host,
+					     const char     * port);
+
+noPollConn      * nopoll_listener_tls_new (noPollCtx  * ctx,
+					   const char * host,
+					   const char * port);
+
+noPollConn      * nopoll_listener_tls_new6 (noPollCtx  * ctx,
+					    const char * host,
+					    const char * port);
+
+noPollConn      * nopoll_listener_tls_new_opts (noPollCtx      * ctx,
+						noPollConnOpts * opts,
+						const char     * host,
+						const char     * port);
+
+noPollConn      * nopoll_listener_tls_new_opts6 (noPollCtx      * ctx,
+						 noPollConnOpts * opts,
+						 const char     * host,
+						 const char     * port);
+
+nopoll_bool       nopoll_listener_set_certificate (noPollConn * listener,
+						   const char * certificate,
+						   const char * private_key,
+						   const char * chain_file);
+
+noPollConn      * nopoll_listener_from_socket (noPollCtx      * ctx,
+					       NOPOLL_SOCKET    session);
+
+NOPOLL_SOCKET     nopoll_listener_accept (NOPOLL_SOCKET server_socket);
+
+END_C_DECLS
+
+#endif

+ 245 - 0
nopoll/nopoll_log.c

@@ -0,0 +1,245 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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;
+}
+
+/* @} */

+ 113 - 0
nopoll/nopoll_log.h

@@ -0,0 +1,113 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_LOG_H__
+#define __NOPOLL_LOG_H__
+
+#include <nopoll_decl.h>
+#include <nopoll_handlers.h>
+
+BEGIN_C_DECLS
+
+/** 
+ * \addtogroup nopoll_log_module
+ * @{
+ */
+
+nopoll_bool     nopoll_log_is_enabled (noPollCtx * ctx);
+
+nopoll_bool     nopoll_log_color_is_enabled (noPollCtx * ctx);
+
+void            nopoll_log_enable (noPollCtx * ctx, nopoll_bool value);
+ 
+void            nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value);
+
+void            nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data);
+
+/* include this at this place to load GNU extensions */
+#if defined(__GNUC__)
+#  ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+#  endif
+#  define __function_name__   __PRETTY_FUNCTION__
+#  define __line__            __LINE__
+#  define __file__            __FILE__
+#elif defined(_MSC_VER)
+#  define __function_name__   __FUNCDNAME__
+#  define __line__            __LINE__
+#  define __file__            __FILE__
+#else
+/* unknown compiler */
+#define __function_name__ ""
+#define __line__            0
+#define __file__            ""
+#endif
+
+
+#if defined(SHOW_DEBUG_LOG)
+# define nopoll_log(ctx,level,message, ...) do{__nopoll_log(ctx, __function_name__, __file__, __line__, level, message, ##__VA_ARGS__);}while(0)
+#else
+# if defined(NOPOLL_OS_WIN32) && !( defined (__GNUC__) || _MSC_VER >= 1400)
+/* default case where '...' is not supported but log is still
+ * disabled */
+#   define nopoll_log __nopoll_log 
+# else
+#   define nopoll_log(ctx, level, message, ...) /* nothing */
+# endif
+#endif
+
+/** 
+ * @internal The following definition allows to find printf like wrong
+ * argument passing to nopoll_log function. To activate the depuration
+ * just add the following to local nopoll_config.h file:
+ *
+ * #define SHOW_FORMAT_BUGS (1)
+ */
+#if defined(SHOW_FORMAT_BUGS)
+# undef  nopoll_log
+# define nopoll_log(ctx,level,message, ...) do{printf (message, ##__VA_ARGS__);}while(0)
+#endif
+
+void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...);
+
+/* @} */
+
+END_C_DECLS
+
+#endif
+

+ 273 - 0
nopoll/nopoll_loop.c

@@ -0,0 +1,273 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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;
+}
+
+/* @} */
+
+

+ 52 - 0
nopoll/nopoll_loop.h

@@ -0,0 +1,52 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_LOOP_H__
+#define __NOPOLL_LOOP_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+int  nopoll_loop_wait (noPollCtx * ctx, long timeout);
+ 
+void nopoll_loop_stop (noPollCtx * ctx);
+
+END_C_DECLS
+
+#endif

+ 320 - 0
nopoll/nopoll_msg.c

@@ -0,0 +1,320 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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;
+}
+
+
+/* @} */

+ 68 - 0
nopoll/nopoll_msg.h

@@ -0,0 +1,68 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_MSG_H__
+#define __NOPOLL_MSG_H__
+
+#include <nopoll.h>
+
+BEGIN_C_DECLS
+
+const unsigned char *  nopoll_msg_get_payload (noPollMsg * msg);
+
+int          nopoll_msg_get_payload_size (noPollMsg * msg);
+
+noPollMsg  * nopoll_msg_new (void);
+
+nopoll_bool  nopoll_msg_ref (noPollMsg * msg);
+
+int          nopoll_msg_ref_count (noPollMsg * msg);
+
+nopoll_bool  nopoll_msg_is_final (noPollMsg * msg);
+
+nopoll_bool  nopoll_msg_is_fragment (noPollMsg * msg);
+
+noPollOpCode nopoll_msg_opcode (noPollMsg * msg);
+
+noPollMsg  * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2);
+
+void         nopoll_msg_unref (noPollMsg * msg);
+
+END_C_DECLS
+
+#endif

+ 418 - 0
nopoll/nopoll_private.h

@@ -0,0 +1,418 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+#ifndef __NOPOLL_PRIVATE_H__
+#define __NOPOLL_PRIVATE_H__
+
+#if NOPLL_TLS
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+#include <nopoll_handlers.h>
+
+typedef struct _noPollCertificate {
+
+	char * serverName;
+	char * certificateFile;
+	char * privateKey;
+	char * optionalChainFile;
+
+} noPollCertificate;
+
+struct _noPollCtx {
+	/**
+	 * @internal Controls logs output..
+	 */
+	/* context reference counting */
+	int             refs;
+
+	/* console log */
+	nopoll_bool     not_executed;
+	nopoll_bool     debug_enabled;
+	
+	/* colored log */
+	nopoll_bool     not_executed_color;
+	nopoll_bool     debug_color_enabled;
+
+	nopoll_bool     keep_looping;
+
+	/** 
+	 * @internal noPollConn connection timeout.
+	 */
+	long        conn_connect_std_timeout;
+
+	/** 
+	 * @internal Default listener connection backlog
+	 */
+	int         backlog;
+
+	/** 
+	 * @internal Currently selected io engine on this context.
+	 */
+	noPollIoEngine * io_engine;
+
+	/** 
+	 * @internal Connection array list and its length.
+	 */
+        int               conn_id;
+	noPollConn     ** conn_list;
+	int               conn_length;
+	/** 
+	 * @internal Number of connections registered on this context.
+	 */
+	int               conn_num;
+
+	/** 
+	 * @internal Reference to defined on accept handling.
+	 */
+	noPollActionHandler on_accept;
+	noPollPtr           on_accept_data;
+
+	/** 
+	 * @internal Reference to defined on ready handling.
+	 */
+	noPollActionHandler on_ready;
+	noPollPtr           on_ready_data;
+
+	/** 
+	 * @internal Reference to defined on open handling.
+	 */
+	noPollActionHandler on_open;
+	noPollPtr           on_open_data;
+
+	/** 
+	 * @internal Reference to the defined on message handling.
+	 */
+	noPollOnMessageHandler on_msg;
+	noPollPtr              on_msg_data;
+
+	/** 
+	 * @internal Basic fake support for protocol version, by
+	 * default: 13, due to RFC6455 standard
+	 */
+	int protocol_version;
+
+	/** 
+	 * @internal Certificates added..
+	 */ 
+	noPollCertificate *  certificates;
+	int                  certificates_length;
+
+	/* mutex */
+	noPollPtr            ref_mutex;
+
+	/* log handling */
+	noPollLogHandler     log_handler;
+	noPollPtr            log_user_data;
+
+	/* context creator */
+	noPollSslContextCreator context_creator;
+	noPollPtr               context_creator_data;
+
+	/* SSL postcheck */
+	noPollSslPostCheck      post_ssl_check;
+	noPollPtr               post_ssl_check_data;
+};
+
+struct _noPollConn {
+	/** 
+	 * @internal Connection id.
+	 */
+	int              id;
+
+	/** 
+	 * @internal The context associated to this connection.
+	 */
+	noPollCtx      * ctx;
+
+	/** 
+	 * @internal This is the actual socket handler associated to
+	 * the noPollConn object.
+	 */
+	NOPOLL_SOCKET    session;
+	/** 
+	 * @internal Flag to signal this connection has finished its
+	 * handshake.
+	 */
+	nopoll_bool      handshake_ok;
+
+	/** 
+	 * @internal Current connection receive function.
+	 */
+	noPollRead       receive;
+
+	/** 
+	 * @internal Current connection receive function.
+	 */
+	noPollRead       send;
+
+	/** 
+	 * @internal The connection role.
+	 */
+	noPollRole       role;
+
+	/** 
+	 * @internal Conection host ip location (connecting or listening).
+	 */
+	char           * host;
+
+	/** 
+	 * @internal Connection port location (connecting or
+	 * listening).
+	 */ 
+	char           * port;
+
+	/** 
+	 * @internal Host name requested on the connection.
+	 */
+	char           * host_name;
+
+	/** 
+	 * @internal Origin requested on the connection.
+	 */
+	char           * origin;
+
+	/** 
+	 * @internal reference to the get url.
+	 */
+	char           * get_url;
+	
+	/** 
+	 * @internal Reference to protocols requested to be opened on
+	 * this connection.
+	 */
+	char           * protocols;
+	/* @internal reference to the protocol that was replied by the server */
+	char           * accepted_protocol;
+
+	/* close status and reason */
+	int              peer_close_status;
+	char           * peer_close_reason;
+	
+	/** 
+	 * @internal Reference to the defined on message handling.
+	 */
+	noPollOnMessageHandler on_msg;
+	noPollPtr              on_msg_data;
+
+	/** 
+	 * @internal Reference to defined on ready handling.
+	 */
+	noPollActionHandler on_ready;
+	noPollPtr           on_ready_data;
+
+	/** 
+	 * @internal Reference to the defined on close handling.
+	 */
+	noPollOnCloseHandler   on_close;
+	noPollPtr              on_close_data;
+
+	/* reference to the handshake */
+	noPollHandShake  * handshake;
+
+	/* reference to a buffer with pending content */
+	char * pending_line;
+
+	/** 
+	 * @internal connection reference counting.
+	 */
+	int    refs;
+
+	/** 
+	 * @internal References to pending content to be read 
+	 */
+	noPollMsg   * pending_msg;
+	long int      pending_diff;
+	long int      pending_desp;
+
+	/** 
+	 * @internal Flag to handle TLS support upon connection
+	 * reception.
+	 */
+	nopoll_bool   tls_on;
+#if NOPLL_TLS
+	/** 
+	 * @internal Flag that indicates that the provided session
+	 * must call to accept the TLS session before proceeding.
+	 */
+	nopoll_bool   pending_ssl_accept;
+
+	/* SSL support */
+	SSL_CTX        * ssl_ctx;
+	SSL            * ssl;
+
+	/* certificates */
+	char           * certificate;
+	char           * private_key;
+	char           * chain_certificate;
+#endif
+
+	/* pending buffer */
+	char             pending_buf[100];
+	int              pending_buf_bytes;
+
+	/** 
+	 * @internal Support for an user defined pointer.
+	 */
+	noPollPtr             hook;
+
+	/** 
+	 * @internal Mutex 
+	 */
+	noPollPtr             ref_mutex;
+
+	/** 
+	 * @internal Variable to track pending bytes from previous
+	 * read that must be completed.
+	 */
+	noPollMsg           * previous_msg;
+	/* allows to track if previous message was a fragment to flag
+	 * next message, even having FIN enabled as a fragment. */
+	nopoll_bool           previous_was_fragment;
+
+	char                * pending_write;
+	int                   pending_write_bytes;
+	int                   pending_write_desp;
+
+	/** 
+	 * @internal Internal reference to the connection options.
+	 */
+	noPollConnOpts      * opts;
+
+	/** 
+	 * @internal Reference to the listener in the case this is a
+	 * connection that was created due to a listener running.
+	 */
+	noPollConn          * listener;
+
+	/** 
+	 * @internal Flag to track internal header pending 
+	 */
+	nopoll_bool           read_pending_header;
+
+	
+	/**** debug values ****/
+	/* force stop after header: do not use this, it is just for
+	   testing purposes */
+	nopoll_bool  __force_stop_after_header;
+};
+
+struct _noPollIoEngine {
+	noPollPtr              io_object;
+	noPollCtx            * ctx;
+	noPollIoMechCreate     create;
+	noPollIoMechDestroy    destroy;
+	noPollIoMechClear      clear;
+	noPollIoMechWait       wait;
+	noPollIoMechAddTo      addto;
+	noPollIoMechIsSet      isset;
+};
+
+struct _noPollMsg {
+	nopoll_bool    has_fin;
+	short          op_code;
+	nopoll_bool    is_masked;
+
+	noPollPtr      payload;
+	long int       payload_size;
+
+	int            refs;
+	noPollPtr      ref_mutex;
+
+	char           mask[4];
+	int            remain_bytes;
+
+	nopoll_bool    is_fragment;
+	int            unmask_desp;
+};
+
+struct _noPollHandshake {
+	/** 
+	 * @internal Reference to the to the GET url HTTP/1.1 header
+	 * part.
+	 */
+	nopoll_bool     upgrade_websocket;
+	nopoll_bool     connection_upgrade;
+	nopoll_bool     received_101; 
+	char          * websocket_key;
+	char          * websocket_version;
+	char          * websocket_accept;
+	char          * expected_accept;
+
+	/* reference to cookie header */
+	char          * cookie;
+};
+
+struct _noPollConnOpts {
+	/* If the connection options object should be reused across calls */
+	nopoll_bool          reuse;
+
+	/* mutex */
+	noPollPtr            mutex;
+	int                  refs;
+
+	/* What ssl protocol should be used */
+	noPollSslProtocol    ssl_protocol;
+
+	/* SSL options */
+	char * certificate;
+	char * private_key;
+	char * chain_certificate;
+	char * ca_certificate;
+
+	nopoll_bool  disable_ssl_verify;
+
+	/* cookie support */
+	char * cookie;
+
+	/* skip origin check flag */
+	nopoll_bool skip_origin_header_check;
+
+	/* network interface to bind to */
+	char * _interface;
+
+	/* extra HTTP headers to send during the connection */
+	char * extra_headers;
+};
+
+#endif

+ 316 - 0
nopoll/nopoll_rtthread.c

@@ -0,0 +1,316 @@
+#include "nopoll_rtthread.h"
+#include <rtthread.h>
+#include <lwip/sockets.h>
+
+/*
+ * os mutex routine
+ */
+static noPollPtr   nopoll_rtt_mutex_create (void)
+{
+	noPollPtr ptr;
+    ptr = rt_mutex_create("nopoll", RT_IPC_FLAG_FIFO);
+
+    return ptr;
+}
+
+static void        nopoll_rtt_mutex_lock    (noPollPtr mutex)
+{
+    rt_mutex_t m = (rt_mutex_t) mutex;
+
+    rt_mutex_take(m, RT_WAITING_FOREVER);
+    return;
+}
+
+static void        nopoll_rtt_mutex_unlock  (noPollPtr mutex)
+{
+    rt_mutex_t m = (rt_mutex_t) mutex;
+
+    rt_mutex_release(m);
+    return;
+}
+
+static void        nopoll_rtt_mutex_destroy (noPollPtr mutex)
+{
+    rt_mutex_t m = (rt_mutex_t) mutex;
+
+    rt_mutex_delete(m);
+    return;
+}
+
+/*
+ * socket send/recv, because these two routines was defined by lwIP macro.
+ */
+#ifndef RT_USING_DFS_NET
+
+#ifdef send
+#undef send
+#endif
+
+int send(int s, const void *dataptr, size_t size, int flags)
+{
+    return lwip_send(s, dataptr, size, flags);
+}
+
+#ifdef recv
+#undef recv
+#endif
+
+int recv(int s, void *mem, size_t len, int flags)
+{
+    return lwip_recv(s, mem, len, flags);
+}
+#endif
+
+/*
+ * random routine, just to use os_tick
+ */
+unsigned int nopoll_rtt_random(void)
+{
+	return rt_tick_get();
+}
+
+/*
+ * base64 routines
+ */
+static const unsigned char base64_enc_map[64] =
+{
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+    'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+    'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+    '8', '9', '+', '/'
+};
+
+static const unsigned char base64_dec_map[128] =
+{
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
+     54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
+    127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
+      5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
+     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
+     25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
+     29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
+     39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+     49,  50,  51, 127, 127, 127, 127, 127
+};
+
+/*
+ * Encode a buffer into base64 format
+ */
+int _base64_encode( unsigned char *dst, size_t *dlen,
+                   const unsigned char *src, size_t slen )
+{
+    size_t i, n;
+    int C1, C2, C3;
+    unsigned char *p;
+
+    if( slen == 0 )
+        return( 0 );
+
+    n = ( slen << 3 ) / 6;
+
+    switch( ( slen << 3 ) - ( n * 6 ) )
+    {
+        case  2: n += 3; break;
+        case  4: n += 2; break;
+        default: break;
+    }
+
+    if( *dlen < n + 1 )
+    {
+        *dlen = n + 1;
+        return( -1 );
+    }
+
+    n = ( slen / 3 ) * 3;
+
+    for( i = 0, p = dst; i < n; i += 3 )
+    {
+        C1 = *src++;
+        C2 = *src++;
+        C3 = *src++;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
+        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+        *p++ = base64_enc_map[C3 & 0x3F];
+    }
+
+    if( i < slen )
+    {
+        C1 = *src++;
+        C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+        if( ( i + 1 ) < slen )
+             *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+        else *p++ = '=';
+
+        *p++ = '=';
+    }
+
+    *dlen = p - dst;
+    *p = 0;
+
+    return( 0 );
+}
+
+/*
+ * Decode a base64-formatted buffer
+ */
+int _base64_decode( unsigned char *dst, size_t *dlen,
+                   const unsigned char *src, size_t slen )
+{
+    size_t i, n;
+    uint32_t j, x;
+    unsigned char *p;
+
+    for( i = n = j = 0; i < slen; i++ )
+    {
+        if( ( slen - i ) >= 2 &&
+            src[i] == '\r' && src[i + 1] == '\n' )
+            continue;
+
+        if( src[i] == '\n' )
+            continue;
+
+        if( src[i] == '=' && ++j > 2 )
+            return( -1 );
+
+        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+            return( -1 );
+
+        if( base64_dec_map[src[i]] < 64 && j != 0 )
+            return( -1 );
+
+        n++;
+    }
+
+    if( n == 0 )
+        return( 0 );
+
+    n = ( ( n * 6 ) + 7 ) >> 3;
+    n -= j;
+
+    if( dst == NULL || *dlen < n )
+    {
+        *dlen = n;
+        return( -1 );
+    }
+
+   for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
+   {
+        if( *src == '\r' || *src == '\n' )
+            continue;
+
+        j -= ( base64_dec_map[*src] == 64 );
+        x  = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
+
+        if( ++n == 4 )
+        {
+            n = 0;
+            if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
+            if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
+            if( j > 2 ) *p++ = (unsigned char)( x       );
+        }
+    }
+
+    *dlen = p - dst;
+
+    return( 0 );
+}
+
+nopoll_bool nopoll_rtt_base64_encode (const char  * content,
+				  int           length,
+				  char        * output,
+				  int         * output_size)
+{
+	nopoll_bool result = nopoll_false;
+
+	if (_base64_encode(output, output_size, content, length) == 0)
+		result = nopoll_true;
+
+	return result;
+}
+
+nopoll_bool nopoll_rtt_base64_decode (const char * content,
+				  int          length,
+				  char       * output,
+				  int        * output_size)
+{
+	nopoll_bool result = nopoll_false;
+
+	if (_base64_decode(output, output_size, content, length) == 0)
+		result = nopoll_true;
+
+	return result;
+}
+
+/*
+ * memory related routines
+ */
+noPollPtr nopoll_calloc(size_t count, size_t size)
+{
+	noPollPtr ptr;
+
+	ptr = rt_malloc(count * size);
+	if (ptr) memset(ptr, 0x0, count * size);
+
+	return ptr;
+}
+
+noPollPtr nopoll_realloc(noPollPtr ref, size_t size)
+{
+	return rt_realloc(ref, size);
+}
+
+void nopoll_free (noPollPtr ref)
+{
+	rt_free (ref);
+	return;
+}
+
+#ifdef __IAR_SYSTEMS_ICC__
+#define MICROSECOND_PER_SECOND  1000000UL
+#define MICROSECOND_PER_TICK    (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND)
+
+/* POSIX thread provides clock_gettime function */
+#include <time.h>
+int gettimeofday(struct timeval *__tp, void *__tzp)
+{
+    if (__tp)
+    {
+        rt_tick_t tick;
+
+        /* get tick */
+        tick = rt_tick_get();
+
+        __tp->tv_sec = tick / RT_TICK_PER_SECOND;
+        __tp->tv_usec = ((tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK);
+    }
+
+    return 0;
+}
+#endif
+
+/*
+ * Initialization routine
+ */
+int nopoll_rtt_init(void)
+{
+	nopoll_thread_handlers(nopoll_rtt_mutex_create,
+			nopoll_rtt_mutex_destroy,
+			nopoll_rtt_mutex_lock,
+			nopoll_rtt_mutex_unlock);
+
+	return 0;
+}
+INIT_COMPONENT_EXPORT(nopoll_rtt_init);

+ 19 - 0
nopoll/nopoll_rtthread.h

@@ -0,0 +1,19 @@
+#ifndef NOPOLL_RTTHREAD_H__
+#define NOPOLL_RTTHREAD_H__
+
+#include "nopoll.h"
+#include <sha1.h>
+
+unsigned int nopoll_rtt_random(void);
+
+nopoll_bool nopoll_rtt_base64_encode (const char  * content,
+				  int           length,
+				  char        * output,
+				  int         * output_size);
+
+nopoll_bool nopoll_rtt_base64_decode (const char * content,
+				  int          length,
+				  char       * output,
+				  int        * output_size);
+
+#endif

+ 136 - 0
nopoll/nopoll_win32.c

@@ -0,0 +1,136 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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 

+ 66 - 0
nopoll/nopoll_win32.h

@@ -0,0 +1,66 @@
+/*
+ *  LibNoPoll: A websocket library
+ *  Copyright (C) 2015 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
+ */
+
+#ifndef __NOPOLL_WIN32_H__
+#define __NOPOLL_WIN32_H__
+
+#include <nopoll_ctx.h>
+
+BEGIN_C_DECLS
+
+int           nopoll_win32_init (noPollCtx * ctx);
+
+int           nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket);
+
+int           nopoll_win32_blocking_enable    (NOPOLL_SOCKET socket);
+
+/* gettimeofday support on windows */
+int           nopoll_win32_gettimeofday (struct timeval *tv, noPollPtr notUsed);
+
+BOOL APIENTRY DllMain                         (HINSTANCE hInst,
+					            DWORD reason,
+					            LPVOID reserved);
+
+#if !defined(EINPROGRESS)
+#define EINPROGRESS (WSAEINPROGRESS)
+#endif
+
+END_C_DECLS
+
+#endif

+ 651 - 0
sha1/sha1.c

@@ -0,0 +1,651 @@
+/*
+ *    FIPS-180-1 compliant SHA-1 implementation
+ *
+ *    Based on XySSL: Copyright (C) 2006-2008     Christophe Devine
+ *
+ *    Copyright (C) 2009    Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *    All rights reserved.
+ *
+ *    Redistribution and use in source and binary forms, with or without
+ *    modification, are permitted provided that the following conditions
+ *    are met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ *      * Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ *      * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ *    The SHA-1 standard was published by NIST in 1993.
+ *
+ *    http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "sha1.h"
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+    {                                                   \
+        (n) = ( (uint32_t) (b)[(i)    ] << 24 )    \
+            | ( (uint32_t) (b)[(i) + 1] << 16 )    \
+            | ( (uint32_t) (b)[(i) + 2] <<  8 )    \
+            | ( (uint32_t) (b)[(i) + 3]       );   \
+    }
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                              \
+    {                                                    \
+        (b)[(i)    ] = (unsigned char) ( (n) >> 24 );    \
+        (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );    \
+        (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );    \
+        (b)[(i) + 3] = (unsigned char) ( (n)       );    \
+    }
+#endif
+
+
+
+/* Rotate an integer value to the left */
+#define ROL( input_value, number_of_bits ) ((input_value << number_of_bits) | ((input_value & 0xFFFFFFFF) >> (32 - number_of_bits)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = ROL(temp,1) )                       \
+)
+
+#define P(a,b,c,d,e,x,func,k)                           \
+{                                                       \
+    e += ROL(a,5) + func(b,c,d) + k + x; b = ROL(b,30); \
+}
+
+#define P2(a,b,c,d,e,x, func, k)                        \
+{                                                       \
+    P(a,b,c,d,e,x, func, k)                             \
+    temp = e;                                           \
+    e = d;                                              \
+    d = c;                                              \
+    c = b;                                              \
+    b = a;                                              \
+    a = temp;                                           \
+}
+
+static inline uint32_t sha1_0_20( uint32_t x, uint32_t y, uint32_t z )
+{
+    return (z ^ (x & (y ^ z)));
+}
+
+static inline uint32_t sha1_20_40_and_60_80( uint32_t x, uint32_t y, uint32_t z )
+{
+    return (x ^ y ^ z);
+}
+
+static inline uint32_t sha1_40_60( uint32_t x, uint32_t y, uint32_t z )
+{
+    return ((x & y) | (z & (x | y)));
+}
+/*
+ * SHA-1 context setup
+ */
+void sha1_starts(sha1_context *ctx)
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_process(sha1_context *ctx, const unsigned char data[64])
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    GET_ULONG_BE(W[0], data, 0);
+    GET_ULONG_BE(W[1], data, 4);
+    GET_ULONG_BE(W[2], data, 8);
+    GET_ULONG_BE(W[3], data, 12);
+    GET_ULONG_BE(W[4], data, 16);
+    GET_ULONG_BE(W[5], data, 20);
+    GET_ULONG_BE(W[6], data, 24);
+    GET_ULONG_BE(W[7], data, 28);
+    GET_ULONG_BE(W[8], data, 32);
+    GET_ULONG_BE(W[9], data, 36);
+    GET_ULONG_BE(W[10], data, 40);
+    GET_ULONG_BE(W[11], data, 44);
+    GET_ULONG_BE(W[12], data, 48);
+    GET_ULONG_BE(W[13], data, 52);
+    GET_ULONG_BE(W[14], data, 56);
+    GET_ULONG_BE(W[15], data, 60);
+
+
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    P( A, B, C, D, E, W[0] , sha1_0_20,            0x5A827999 );
+    P( E, A, B, C, D, W[1] , sha1_0_20,            0x5A827999 );
+    P( D, E, A, B, C, W[2] , sha1_0_20,            0x5A827999 );
+    P( C, D, E, A, B, W[3] , sha1_0_20,            0x5A827999 );
+    P( B, C, D, E, A, W[4] , sha1_0_20,            0x5A827999 );
+    P( A, B, C, D, E, W[5] , sha1_0_20,            0x5A827999 );
+    P( E, A, B, C, D, W[6] , sha1_0_20,            0x5A827999 );
+    P( D, E, A, B, C, W[7] , sha1_0_20,            0x5A827999 );
+    P( C, D, E, A, B, W[8] , sha1_0_20,            0x5A827999 );
+    P( B, C, D, E, A, W[9] , sha1_0_20,            0x5A827999 );
+    P( A, B, C, D, E, W[10], sha1_0_20,            0x5A827999 );
+    P( E, A, B, C, D, W[11], sha1_0_20,            0x5A827999 );
+    P( D, E, A, B, C, W[12], sha1_0_20,            0x5A827999 );
+    P( C, D, E, A, B, W[13], sha1_0_20,            0x5A827999 );
+    P( B, C, D, E, A, W[14], sha1_0_20,            0x5A827999 );
+    P( A, B, C, D, E, W[15], sha1_0_20,            0x5A827999 );
+    P( E, A, B, C, D, R(16), sha1_0_20,            0x5A827999 );
+    P( D, E, A, B, C, R(17), sha1_0_20,            0x5A827999 );
+    P( C, D, E, A, B, R(18), sha1_0_20,            0x5A827999 );
+    P( B, C, D, E, A, R(19), sha1_0_20,            0x5A827999 );
+    P( A, B, C, D, E, R(20), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( E, A, B, C, D, R(21), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( D, E, A, B, C, R(22), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( C, D, E, A, B, R(23), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( B, C, D, E, A, R(24), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( A, B, C, D, E, R(25), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( E, A, B, C, D, R(26), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( D, E, A, B, C, R(27), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( C, D, E, A, B, R(28), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( B, C, D, E, A, R(29), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( A, B, C, D, E, R(30), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( E, A, B, C, D, R(31), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( D, E, A, B, C, R(32), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( C, D, E, A, B, R(33), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( B, C, D, E, A, R(34), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( A, B, C, D, E, R(35), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( E, A, B, C, D, R(36), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( D, E, A, B, C, R(37), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( C, D, E, A, B, R(38), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( B, C, D, E, A, R(39), sha1_20_40_and_60_80, 0x6ED9EBA1 );
+    P( A, B, C, D, E, R(40), sha1_40_60,           0x8F1BBCDC );
+    P( E, A, B, C, D, R(41), sha1_40_60,           0x8F1BBCDC );
+    P( D, E, A, B, C, R(42), sha1_40_60,           0x8F1BBCDC );
+    P( C, D, E, A, B, R(43), sha1_40_60,           0x8F1BBCDC );
+    P( B, C, D, E, A, R(44), sha1_40_60,           0x8F1BBCDC );
+    P( A, B, C, D, E, R(45), sha1_40_60,           0x8F1BBCDC );
+    P( E, A, B, C, D, R(46), sha1_40_60,           0x8F1BBCDC );
+    P( D, E, A, B, C, R(47), sha1_40_60,           0x8F1BBCDC );
+    P( C, D, E, A, B, R(48), sha1_40_60,           0x8F1BBCDC );
+    P( B, C, D, E, A, R(49), sha1_40_60,           0x8F1BBCDC );
+    P( A, B, C, D, E, R(50), sha1_40_60,           0x8F1BBCDC );
+    P( E, A, B, C, D, R(51), sha1_40_60,           0x8F1BBCDC );
+    P( D, E, A, B, C, R(52), sha1_40_60,           0x8F1BBCDC );
+    P( C, D, E, A, B, R(53), sha1_40_60,           0x8F1BBCDC );
+    P( B, C, D, E, A, R(54), sha1_40_60,           0x8F1BBCDC );
+    P( A, B, C, D, E, R(55), sha1_40_60,           0x8F1BBCDC );
+    P( E, A, B, C, D, R(56), sha1_40_60,           0x8F1BBCDC );
+    P( D, E, A, B, C, R(57), sha1_40_60,           0x8F1BBCDC );
+    P( C, D, E, A, B, R(58), sha1_40_60,           0x8F1BBCDC );
+    P( B, C, D, E, A, R(59), sha1_40_60,           0x8F1BBCDC );
+    P( A, B, C, D, E, R(60), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( E, A, B, C, D, R(61), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( D, E, A, B, C, R(62), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( C, D, E, A, B, R(63), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( B, C, D, E, A, R(64), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( A, B, C, D, E, R(65), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( E, A, B, C, D, R(66), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( D, E, A, B, C, R(67), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( C, D, E, A, B, R(68), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( B, C, D, E, A, R(69), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( A, B, C, D, E, R(70), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( E, A, B, C, D, R(71), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( D, E, A, B, C, R(72), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( C, D, E, A, B, R(73), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( B, C, D, E, A, R(74), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( A, B, C, D, E, R(75), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( E, A, B, C, D, R(76), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( D, E, A, B, C, R(77), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( C, D, E, A, B, R(78), sha1_20_40_and_60_80, 0xCA62C1D6 );
+    P( B, C, D, E, A, R(79), sha1_20_40_and_60_80, 0xCA62C1D6 );
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+
+
+
+void sha1_process_small(sha1_context *ctx, const unsigned char data[64])
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    char round = 0;
+
+    while (round < 80)
+    {
+        if (round >= 16)
+        {
+            R( round );
+        }
+        if (round < 20)
+        {
+            P2(A,B,C,D,E, W[round & 0x0F],  sha1_0_20,             0x5A827999);
+        }
+        else if (round < 40)
+        {
+            P2(A,B,C,D,E, W[round & 0x0F],  sha1_20_40_and_60_80,  0x6ED9EBA1);
+        }
+        else if (round < 60)
+        {
+            P2(A,B,C,D,E, W[round & 0x0F],  sha1_40_60,            0x8F1BBCDC);
+        }
+        else
+        {
+            P2(A,B,C,D,E, W[round & 0x0F],  sha1_20_40_and_60_80,  0xCA62C1D6);
+        }
+
+        ++round;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void sha1_update(sha1_context *ctx, const unsigned char *input, int32_t ilen)
+{
+    int32_t fill;
+    uint32_t left;
+
+    if (ilen <= 0)
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if (ctx->total[0] < (uint32_t)ilen)
+        ctx->total[1]++;
+
+    if (left && ilen >= fill) {
+        memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
+        sha1_process(ctx, ctx->buffer);
+        input += fill;
+        ilen -= fill;
+        left = 0;
+    }
+
+    while (ilen >= 64) {
+        sha1_process(ctx, input);
+        input += 64;
+        ilen -= 64;
+    }
+
+    if (ilen > 0) {
+        memcpy((void *)(ctx->buffer + left), (const void *)input, ilen);
+    }
+}
+
+static const unsigned char sha1_padding[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void sha1_finish(sha1_context *ctx, unsigned char output[20])
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    unsigned char msglen[8];
+
+    high = (ctx->total[0] >> 29)
+        | (ctx->total[1] << 3);
+    low = (ctx->total[0] << 3);
+
+    PUT_ULONG_BE(high, msglen, 0);
+    PUT_ULONG_BE(low, msglen, 4);
+
+    last = ctx->total[0] & 0x3F;
+    padn = (last < 56) ? (56 - last) : (120 - last);
+
+    sha1_update(ctx, sha1_padding, padn);
+    sha1_update(ctx, msglen, 8);
+
+    PUT_ULONG_BE(ctx->state[0], output, 0);
+    PUT_ULONG_BE(ctx->state[1], output, 4);
+    PUT_ULONG_BE(ctx->state[2], output, 8);
+    PUT_ULONG_BE(ctx->state[3], output, 12);
+    PUT_ULONG_BE(ctx->state[4], output, 16);
+}
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void sha1(const unsigned char *input, int32_t ilen, unsigned char output[20])
+{
+    sha1_context ctx;
+
+    sha1_starts(&ctx);
+    sha1_update(&ctx, input, ilen);
+    sha1_finish(&ctx, output);
+
+    memset(&ctx, 0, sizeof(sha1_context));
+}
+
+
+
+/*
+ * SHA-1 HMAC context setup
+ */
+void sha1_hmac_starts(sha1_context *ctx, const unsigned char *key, uint32_t keylen)
+{
+    int32_t i;
+    unsigned char sum[20];
+
+    if (keylen > 64) {
+        sha1(key, keylen, sum);
+        keylen = 20;
+        key = sum;
+    }
+
+    memset(ctx->ipad, 0x36, 64);
+    memset(ctx->opad, 0x5C, 64);
+
+    for (i = 0; i < keylen; i++) {
+        ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]);
+        ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]);
+    }
+
+    sha1_starts(ctx);
+    sha1_update(ctx, ctx->ipad, 64);
+
+    memset(sum, 0, sizeof(sum));
+}
+
+/*
+ * SHA-1 HMAC process buffer
+ */
+void sha1_hmac_update(sha1_context *ctx, const unsigned char *input, uint32_t ilen)
+{
+    sha1_update(ctx, input, ilen);
+}
+
+/*
+ * SHA-1 HMAC final digest
+ */
+void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20])
+{
+    unsigned char tmpbuf[20];
+
+    sha1_finish(ctx, tmpbuf);
+    sha1_starts(ctx);
+    sha1_update(ctx, ctx->opad, 64);
+    sha1_update(ctx, tmpbuf, 20);
+    sha1_finish(ctx, output);
+
+    memset(tmpbuf, 0, sizeof(tmpbuf));
+}
+
+/*
+ * output = HMAC-SHA-1( hmac key, input buffer )
+ */
+void sha1_hmac(const unsigned char *key, int32_t keylen,
+           const unsigned char *input, int32_t ilen,
+           unsigned char output[20])
+{
+    sha1_context ctx;
+
+    sha1_hmac_starts(&ctx, key, keylen);
+    sha1_hmac_update(&ctx, input, ilen);
+    sha1_hmac_finish(&ctx, output);
+
+    memset(&ctx, 0, sizeof(sha1_context));
+}
+
+#if defined(TROPICSSL_SELF_TEST)
+
+#include <stdio.h>
+
+/*
+ * FIPS-180-1 test vectors
+ */
+static const unsigned char sha1_test_buf[3][57] = {
+    {"abc"},
+    {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+    {""}
+};
+
+static const int32_t sha1_test_buflen[3] = {
+    3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] = {
+    {
+     0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+     0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D},
+    {
+     0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+     0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1},
+    {
+     0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+     0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F}
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static const unsigned char sha1_hmac_test_key[7][26] = {
+    {
+     "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+     "\x0B\x0B\x0B\x0B"},
+    {"Jefe"},
+    {
+     "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+     "\xAA\xAA\xAA\xAA"},
+    {
+     "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+     "\x11\x12\x13\x14\x15\x16\x17\x18\x19"},
+    {
+     "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+     "\x0C\x0C\x0C\x0C"},
+    {""},            /* 0xAA 80 times */
+    {""}
+};
+
+static const int32_t sha1_hmac_test_keylen[7] = {
+    20, 4, 20, 25, 20, 80, 80
+};
+
+static const unsigned char sha1_hmac_test_buf[7][74] = {
+    {"Hi There"},
+    {"what do ya want for nothing?"},
+    {
+     "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+     "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+     "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+     "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+     "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"},
+    {
+     "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+     "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+     "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+     "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+     "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"},
+    {"Test With Truncation"},
+    {"Test Using Larger Than Block-Size Key - Hash Key First"},
+    {
+     "Test Using Larger Than Block-Size Key and Larger"
+     " Than One Block-Size Data"}
+};
+
+static const int32_t sha1_hmac_test_buflen[7] = {
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char sha1_hmac_test_sum[7][20] = {
+    {
+     0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
+     0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00},
+    {
+     0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
+     0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79},
+    {
+     0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
+     0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3},
+    {
+     0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
+     0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA},
+    {
+     0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
+     0x7B, 0xE1},
+    {
+     0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
+     0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12},
+    {
+     0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
+     0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91}
+};
+
+/*
+ * Checkup routine
+ */
+int32_t sha1_self_test(int32_t verbose)
+{
+    int32_t i, j, buflen;
+    unsigned char buf[1024];
+    unsigned char sha1sum[20];
+    sha1_context ctx;
+
+    /*
+     * SHA-1
+     */
+    for (i = 0; i < 3; i++) {
+        if (verbose != 0)
+            printf("  SHA-1 test #%ld: ", (long int)( i + 1 ));
+
+        sha1_starts(&ctx);
+
+        if (i == 2) {
+            memset(buf, 'a', buflen = 1000);
+
+            for (j = 0; j < 1000; j++)
+                sha1_update(&ctx, buf, buflen);
+        } else
+            sha1_update(&ctx, sha1_test_buf[i],
+                    sha1_test_buflen[i]);
+
+        sha1_finish(&ctx, sha1sum);
+
+        if (memcmp(sha1sum, sha1_test_sum[i], 20) != 0) {
+            if (verbose != 0)
+                printf("failed\n");
+
+            return (1);
+        }
+
+        if (verbose != 0)
+            printf("passed\n");
+    }
+
+    if (verbose != 0)
+        printf("\n");
+
+    for (i = 0; i < 7; i++) {
+        if (verbose != 0)
+            printf("  HMAC-SHA-1 test #%ld: ", (long int)( i + 1 ));
+
+        if (i == 5 || i == 6) {
+            memset(buf, '\xAA', buflen = 80);
+            sha1_hmac_starts(&ctx, buf, buflen);
+        } else
+            sha1_hmac_starts(&ctx, sha1_hmac_test_key[i],
+                     sha1_hmac_test_keylen[i]);
+
+        sha1_hmac_update(&ctx, sha1_hmac_test_buf[i],
+                 sha1_hmac_test_buflen[i]);
+
+        sha1_hmac_finish(&ctx, sha1sum);
+
+        buflen = (i == 4) ? 12 : 20;
+
+        if (memcmp(sha1sum, sha1_hmac_test_sum[i], buflen) != 0) {
+            if (verbose != 0)
+                printf("failed\n");
+
+            return (1);
+        }
+
+        if (verbose != 0)
+            printf("passed\n");
+    }
+
+    if (verbose != 0)
+        printf("\n");
+
+    return (0);
+}
+
+#endif

+ 154 - 0
sha1/sha1.h

@@ -0,0 +1,154 @@
+/**
+ * \file sha1.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TROPICSSL_SHA1_H
+#define TROPICSSL_SHA1_H
+
+#include <stdint.h>
+
+/**
+ * \brief          SHA-1 context structure
+ */
+/* Prevent redefinition of types from crypto_structures.h */
+#ifndef CRYPTO_STRUCTURE
+typedef struct {
+    uint32_t total[2];     /*!< number of bytes processed  */
+    uint32_t state[5];     /*!< intermediate digest state  */
+    unsigned char buffer[64];    /*!< data block being processed */
+
+    unsigned char ipad[64];    /*!< HMAC: inner padding        */
+    unsigned char opad[64];    /*!< HMAC: outer padding        */
+} sha1_context;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    /**
+     * \brief          SHA-1 context setup
+     *
+     * \param ctx      context to be initialized
+     */
+    void sha1_starts(sha1_context * ctx);
+
+    /**
+     * \brief          SHA-1 process buffer
+     *
+     * \param ctx      SHA-1 context
+     * \param input    buffer holding the  data
+     * \param ilen     length of the input data
+     */
+    void sha1_update(sha1_context *ctx, const unsigned char *input, int32_t ilen);
+
+    /**
+     * \brief          SHA-1 final digest
+     *
+     * \param ctx      SHA-1 context
+     * \param output   SHA-1 checksum result
+     */
+    void sha1_finish(sha1_context * ctx, unsigned char output[20]);
+
+    /**
+     * \brief          Output = SHA-1( input buffer )
+     *
+     * \param input    buffer holding the  data
+     * \param ilen     length of the input data
+     * \param output   SHA-1 checksum result
+     */
+    void sha1(const unsigned char *input, int32_t ilen, unsigned char output[20]);
+
+    /**
+     * \brief          Output = SHA-1( file contents )
+     *
+     * \param path     input file name
+     * \param output   SHA-1 checksum result
+     *
+     * \return         0 if successful, 1 if fopen failed,
+     *                 or 2 if fread failed
+     */
+    int32_t sha1_file(const char *path, unsigned char output[20]);
+
+    /**
+     * \brief          SHA-1 HMAC context setup
+     *
+     * \param ctx      HMAC context to be initialized
+     * \param key      HMAC secret key
+     * \param keylen   length of the HMAC key
+     */
+    void sha1_hmac_starts(sha1_context * ctx, const unsigned char *key,
+                  uint32_t keylen);
+
+    /**
+     * \brief          SHA-1 HMAC process buffer
+     *
+     * \param ctx      HMAC context
+     * \param input    buffer holding the  data
+     * \param ilen     length of the input data
+     */
+    void sha1_hmac_update(sha1_context * ctx, const unsigned char *input,
+                  uint32_t ilen);
+
+    /**
+     * \brief          SHA-1 HMAC final digest
+     *
+     * \param ctx      HMAC context
+     * \param output   SHA-1 HMAC checksum result
+     */
+    void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20]);
+
+    /**
+     * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
+     *
+     * \param key      HMAC secret key
+     * \param keylen   length of the HMAC key
+     * \param input    buffer holding the  data
+     * \param ilen     length of the input data
+     * \param output   HMAC-SHA-1 result
+     */
+    void sha1_hmac(const unsigned char *key, int32_t keylen,
+               const unsigned char *input, int32_t ilen,
+               unsigned char output[20]);
+
+    /**
+     * \brief          Checkup routine
+     *
+     * \return         0 if successful, or 1 if the test failed
+     */
+    int32_t sha1_self_test(int32_t verbose);
+
+#ifdef __cplusplus
+}
+#endif
+#endif                /* sha1.h */