├── .gitignore ├── LICENSE ├── README.md ├── SConscript ├── examples └── nopoll_client.c └── nopoll ├── nopoll.c ├── nopoll.h ├── nopoll_config.h ├── nopoll_config_win32.h ├── nopoll_config_win64.h ├── nopoll_conn.c ├── nopoll_conn.h ├── nopoll_conn_opts.c ├── nopoll_conn_opts.h ├── nopoll_ctx.c ├── nopoll_ctx.h ├── nopoll_decl.c ├── nopoll_decl.h ├── nopoll_handlers.h ├── nopoll_io.c ├── nopoll_io.h ├── nopoll_listener.c ├── nopoll_listener.h ├── nopoll_log.c ├── nopoll_log.h ├── nopoll_loop.c ├── nopoll_loop.h ├── nopoll_msg.c ├── nopoll_msg.h ├── nopoll_private.h ├── nopoll_rtthread.c ├── nopoll_rtthread.h ├── nopoll_win32.c └── nopoll_win32.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # noPoll 2 | [noPoll](https://github.com/ASPLes/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. 3 | 4 | Here is a simple implementation for RT-Thread based on [noPoll](https://github.com/ASPLes/nopoll) , temporarily only support non-encrypted operation. 5 | 6 | # Quick Start 7 | There is a websocket client example at `examples/nopoll_client.c`. 8 | Test server host : echo.websocket.org 9 | Test server port : 80 10 | 11 | Run the example at `MSH` as follows : 12 | ``` 13 | msh />nopoll_client 14 | web socket connection ready! 15 | sending content.. 16 | recv: Hello RT-Thread! 17 | sendcnt = 1 18 | ... 19 | ... 20 | ``` 21 | 22 | # Notes 23 | ## 1 Not defined `strdup` function 24 | 25 | If your compiler is not offered `strdup` function , you can implement it yourself as shown below : 26 | 27 | ``` 28 | /* _strdup.c */ 29 | #include 30 | 31 | #ifdef RT_USING_HEAP 32 | char *strdup(const char *s) 33 | { 34 | size_t len = strlen(s) + 1; 35 | char *tmp = (char *)rt_malloc(len); 36 | 37 | if(!tmp) return NULL; 38 | 39 | rt_memcpy(tmp, s, len); 40 | return tmp; 41 | } 42 | #endif 43 | ``` 44 | ## 2 `FD_SETSIZE` too small 45 | 46 | Please config the project as shown below : 47 | 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. 48 | 49 | 50 | # Reference 51 | 1 WebSocket Official website : http://websocket.org/ 52 | 2 noPoll Official website : http://www.aspl.es/nopoll/ 53 | 3 noPoll GitHub repository : https://github.com/ASPLes/nopoll 54 | 4 WebSocket test server : http://websocket.org/echo.html 55 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | import os 2 | import rtconfig 3 | from building import * 4 | 5 | cwd = GetCurrentDir() 6 | src = Split(''' 7 | nopoll/nopoll.c 8 | nopoll/nopoll_conn_opts.c 9 | nopoll/nopoll_ctx.c 10 | nopoll/nopoll_decl.c 11 | nopoll/nopoll_io.c 12 | nopoll/nopoll_listener.c 13 | nopoll/nopoll_log.c 14 | nopoll/nopoll_loop.c 15 | nopoll/nopoll_msg.c 16 | nopoll/nopoll_conn.c 17 | nopoll/nopoll_rtthread.c 18 | ''') 19 | 20 | CPPPATH = [cwd + '/nopoll', cwd + '/sha1'] 21 | 22 | LOCAL_CCFLAGS = '' 23 | 24 | if rtconfig.CROSS_TOOL == 'keil': 25 | LOCAL_CCFLAGS += ' --gnu' 26 | 27 | group = DefineGroup('nopoll', src, depend = ['RT_USING_LWIP', 'PKG_USING_NOPOLL', 'PKG_USING_TINYCRYPT'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS) 28 | 29 | examples_src = Split(''' 30 | examples/nopoll_client.c 31 | ''') 32 | 33 | group = group + DefineGroup('nopoll-examples', examples_src, depend = ['PKG_USING_NOPOLL', 'PKG_USING_NOPOLL_EXAMPLE'], LOCAL_CCFLAGS = LOCAL_CCFLAGS) 34 | 35 | Return('group') 36 | -------------------------------------------------------------------------------- /examples/nopoll_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define HOST_NAME "echo.websocket.org" 9 | #define HOST_PORT "80" 10 | 11 | /* eg: "/ws" , used for http handshake request URI */ 12 | #define HOST_URI (NULL) 13 | 14 | static char message[1024] = {'*'}; 15 | static char rev_buffer[1024]; 16 | 17 | static int nopoll_client(int argc, char **argv) 18 | { 19 | noPollConn *conn = RT_NULL; 20 | noPollCtx *ctx = RT_NULL; 21 | 22 | /* initialize context */ 23 | ctx = nopoll_ctx_new(); 24 | 25 | /* create connection */ 26 | conn = nopoll_conn_new(ctx, HOST_NAME, HOST_PORT, HOST_NAME, HOST_URI, NULL, NULL); 27 | if (!nopoll_conn_is_ok(conn)) 28 | { 29 | printf("ERROR: Expected to find proper client connection status, but found error..\n"); 30 | goto __exit; 31 | } /* end if */ 32 | 33 | if (!nopoll_conn_wait_until_connection_ready(conn, 6)) 34 | { 35 | printf("ERROR: websocket connection failed!\n"); 36 | goto __exit; 37 | } /* end if */ 38 | 39 | printf("web socket connection ready!\n"); 40 | 41 | { 42 | int bytes_read; 43 | int retries = 0; 44 | int sendcnt = 0; 45 | 46 | int length = 0; 47 | 48 | /* test blocking mode */ 49 | { 50 | char *block_msg = "Hello RT-Thread!"; 51 | 52 | length = strlen(block_msg); 53 | 54 | /* send content text(utf-8) */ 55 | printf("sending content..\n"); 56 | if (nopoll_conn_send_text(conn, block_msg, length) != length) 57 | { 58 | printf("ERROR: Expected to find proper send operation..\n"); 59 | goto __exit; 60 | } 61 | 62 | /* nopoll_true : blocking, wait for the reply (try to read length, blocking and with a 3 seconds timeout) */ 63 | bytes_read = nopoll_conn_read(conn, rev_buffer, length, nopoll_true, 3000); 64 | if (bytes_read > 0) 65 | rev_buffer[bytes_read] = 0; 66 | 67 | if (bytes_read != length) 68 | { 69 | printf("ERROR: expected to find 14 bytes but found %d..\n", bytes_read); 70 | goto __exit; 71 | } /* end if */ 72 | 73 | printf("recv: %s\n", rev_buffer); 74 | } 75 | 76 | memset(rev_buffer, 0, sizeof(rev_buffer)); 77 | 78 | /* test no-blocking mode */ 79 | { 80 | memset(message, '*', sizeof(message) - 1); 81 | 82 | char *send_message = message; 83 | 84 | while (1) 85 | { 86 | /* send content text(utf-8) */ 87 | if (nopoll_conn_send_text(conn, send_message, strlen(send_message)) != strlen(send_message)) 88 | { 89 | printf("ERROR: Expected to find proper send operation..\n"); 90 | goto __exit; 91 | } /* end if */ 92 | 93 | send_message += sizeof(char) * 10; 94 | sendcnt++; 95 | 96 | printf("sendcnt = %d\n", sendcnt); 97 | 98 | /* nopoll_false : non-blocking */ 99 | bytes_read = nopoll_conn_read(conn, rev_buffer, sizeof(rev_buffer), nopoll_false, 1000); 100 | if (bytes_read < 0) 101 | { 102 | printf("ERROR: expected to find bytes from the connection but found: %d\n", bytes_read); 103 | goto __exit; 104 | } 105 | else if (bytes_read == 0) 106 | { 107 | retries++; 108 | if (retries > 10) 109 | { 110 | printf("Error: nothing found (0 bytes), %d retries\n", retries); 111 | goto __exit; 112 | } /* end if */ 113 | 114 | continue; 115 | } 116 | else 117 | { 118 | rev_buffer[bytes_read] = '\0'; 119 | printf("\nrecv: %s \nlength = %d\n", rev_buffer, strlen(rev_buffer)); 120 | } /* end if */ 121 | 122 | rt_thread_delay(3000); 123 | 124 | if ((send_message - message) / sizeof(char) > sizeof(message)) 125 | goto __exit; 126 | } 127 | } 128 | } 129 | 130 | __exit: 131 | /* close the connection */ 132 | if (conn) 133 | nopoll_conn_close(conn); 134 | 135 | /* release context */ 136 | if (ctx) 137 | nopoll_ctx_unref(ctx); 138 | 139 | return 0; 140 | } /* end nopoll_client */ 141 | MSH_CMD_EXPORT(nopoll_client, websocket client test no input param); 142 | -------------------------------------------------------------------------------- /nopoll/nopoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_H__ 40 | #define __NOPOLL_H__ 41 | 42 | #include 43 | #include 44 | 45 | BEGIN_C_DECLS 46 | 47 | #if defined(NOPOLL_OS_WIN32) 48 | #include 49 | #endif 50 | 51 | #if defined(NOPOLL_OS_RTTHREAD) 52 | #include "nopoll_rtthread.h" 53 | #endif 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | /** 66 | * \addtogroup nopoll_module 67 | * @{ 68 | */ 69 | 70 | nopoll_bool nopoll_cmp (const char * string1, const char * string2); 71 | 72 | nopoll_bool nopoll_ncmp (const char * string1, const char * string2, int bytes); 73 | 74 | char * nopoll_strdup_printf (const char * chunk, ...); 75 | 76 | char * nopoll_strdup_printfv (const char * chunk, va_list args); 77 | 78 | void nopoll_trim (char * chunk, int * trimmed); 79 | 80 | void nopoll_sleep (long microseconds); 81 | 82 | void nopoll_thread_handlers (noPollMutexCreate mutex_create, 83 | noPollMutexDestroy mutex_destroy, 84 | noPollMutexLock mutex_lock, 85 | noPollMutexUnlock mutex_unlock); 86 | 87 | noPollPtr nopoll_mutex_create (void); 88 | 89 | void nopoll_mutex_lock (noPollPtr mutex); 90 | 91 | void nopoll_mutex_unlock (noPollPtr mutex); 92 | 93 | void nopoll_mutex_destroy (noPollPtr mutex); 94 | 95 | nopoll_bool nopoll_base64_encode (const char * content, 96 | int length, 97 | char * output, 98 | int * output_size); 99 | 100 | nopoll_bool nopoll_base64_decode (const char * content, 101 | int length, 102 | char * output, 103 | int * output_size); 104 | 105 | int nopoll_timeval_substract (struct timeval * a, 106 | struct timeval * b, 107 | struct timeval * result); 108 | 109 | char * nopoll_strdup (const char * buffer); 110 | 111 | nopoll_bool nopoll_nonce (char * buffer, int nonce_size); 112 | 113 | void nopoll_cleanup_library (void); 114 | 115 | int nopoll_get_bit (char byte, int position); 116 | 117 | void nopoll_set_bit (char * buffer, int position); 118 | 119 | void nopoll_show_byte (noPollCtx * ctx, char byte, const char * label); 120 | 121 | char * nopoll_int2bin (int a, char *buffer, int buf_size); 122 | 123 | void nopoll_int2bin_print (noPollCtx * ctx, int value); 124 | 125 | int nopoll_get_8bit (const char * buffer); 126 | 127 | int nopoll_get_16bit (const char * buffer); 128 | 129 | void nopoll_set_16bit (int value, char * buffer); 130 | 131 | void nopoll_set_32bit (int value, char * buffer); 132 | 133 | int nopoll_get_32bit (const char * buffer); 134 | 135 | /* @} */ 136 | 137 | END_C_DECLS 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /nopoll/nopoll_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Nopoll Library nopoll_config.h 3 | * Platform dependant definitions. 4 | * 5 | * This is a generated file. Please modify 'configure.in' 6 | */ 7 | 8 | #ifndef __NOPOLL_CONFIG_H__ 9 | #define __NOPOLL_CONFIG_H__ 10 | 11 | /** 12 | * \addtogroup nopoll_decl_module 13 | * @{ 14 | */ 15 | 16 | /** 17 | * @brief Allows to convert integer value (including constant values) 18 | * into a pointer representation. 19 | * 20 | * Use the oposite function to restore the value from a pointer to a 21 | * integer: \ref PTR_TO_INT. 22 | * 23 | * @param integer The integer value to cast to pointer. 24 | * 25 | * @return A \ref noPollPtr reference. 26 | */ 27 | #ifndef INT_TO_PTR 28 | #define INT_TO_PTR(integer) ((noPollPtr) (integer)) 29 | #endif 30 | 31 | /** 32 | * @brief Allows to convert a pointer reference (\ref noPollPtr), 33 | * which stores an integer that was stored using \ref INT_TO_PTR. 34 | * 35 | * Use the oposite function to restore the pointer value stored in the 36 | * integer value. 37 | * 38 | * @param ptr The pointer to cast to a integer value. 39 | * 40 | * @return A int value. 41 | */ 42 | #ifndef PTR_TO_INT 43 | #define PTR_TO_INT(ptr) ((int) (ptr)) 44 | #endif 45 | 46 | /** 47 | * @brief Allows to get current platform configuration. This is used 48 | * by Nopoll library but could be used by applications built on top of 49 | * Nopoll to change its configuration based on the platform information. 50 | */ 51 | // #define NOPOLL_OS_UNIX (1) 52 | #define NOPOLL_OS_RTTHREAD (1) 53 | 54 | /** 55 | * @internal Allows to now if the platform support vasprintf 56 | * function. Do not use this macro as it is supposed to be for 57 | * internal use. 58 | */ 59 | // #define NOPOLL_HAVE_VASPRINTF (0) 60 | 61 | /** 62 | * @brief Indicates that this platform have support for 64bits. 63 | */ 64 | // #define NOPOLL_64BIT_PLATFORM (0) 65 | 66 | #define NOPLL_TLS (0) 67 | #define NOPLL_IPV6 (0) 68 | 69 | /** 70 | * @brief Indicates where we have support for SSL v.3 support. 71 | */ 72 | #define NOPOLL_HAVE_SSLv23_ENABLED (1) 73 | 74 | /** 75 | * @brief Indicates where we have support for SSL v3.0 support. The SSLv3 protocol is deprecated and should not be used. 76 | */ 77 | #define NOPOLL_HAVE_SSLv3_ENABLED (1) 78 | 79 | /** 80 | * @brief Indicates where we have support for TLSv1.0 support. 81 | */ 82 | #define NOPOLL_HAVE_TLSv10_ENABLED (1) 83 | 84 | /** 85 | * @brief Indicates where we have support for TLSv1.1 support. 86 | */ 87 | #define NOPOLL_HAVE_TLSv11_ENABLED (1) 88 | 89 | /** 90 | * @brief Indicates where we have support for TLSv1.2 support. 91 | */ 92 | #define NOPOLL_HAVE_TLSv12_ENABLED (1) 93 | 94 | 95 | /* @} */ 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /nopoll/nopoll_config_win32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * noPoll Library nopoll_config.h 3 | * Platform dependant definitions for Win32 platform. 4 | * 5 | * This file is maintained manually for those people that do not 6 | * compile nopoll using autoconf. It should look really similar to 7 | * nopoll_config.h file created on a i386 linux platform but changing 8 | * NOPOLL_OS_UNIX to NOPOLL_OS_WIN32 (at least for now). 9 | * 10 | * For commercial support on build WebSocket enabled solutions contact us: 11 | * 12 | * Postal address: 13 | * Advanced Software Production Line, S.L. 14 | * Edificio Alius A, Oficina 102, 15 | * C/ Antonio Suarez Nº 10, 16 | * Alcalá de Henares 28802 Madrid 17 | * Spain 18 | * 19 | * Email address: 20 | * info@aspl.es - http://www.aspl.es/nopoll 21 | * 22 | */ 23 | 24 | #ifndef __NOPOLL_CONFIG_H__ 25 | #define __NOPOLL_CONFIG_H__ 26 | 27 | /** 28 | * \addtogroup nopoll_decl_module 29 | * @{ 30 | */ 31 | 32 | /** 33 | * @brief Allows to convert integer value (including constant values) 34 | * into a pointer representation. 35 | * 36 | * Use the oposite function to restore the value from a pointer to a 37 | * integer: \ref PTR_TO_INT. 38 | * 39 | * @param integer The integer value to cast to pointer. 40 | * 41 | * @return A \ref noPollPtr reference. 42 | */ 43 | #ifndef INT_TO_PTR 44 | #define INT_TO_PTR(integer) ((noPollPtr) (integer)) 45 | #endif 46 | 47 | /** 48 | * @brief Allows to convert a pointer reference (\ref noPollPtr), 49 | * which stores an integer that was stored using \ref INT_TO_PTR. 50 | * 51 | * Use the oposite function to restore the pointer value stored in the 52 | * integer value. 53 | * 54 | * @param ptr The pointer to cast to a integer value. 55 | * 56 | * @return A int value. 57 | */ 58 | #ifndef PTR_TO_INT 59 | #define PTR_TO_INT(ptr) ((int) (ptr)) 60 | #endif 61 | 62 | /** 63 | * @brief Allows to get current platform configuration. This is used 64 | * by Nopoll library but could be used by applications built on top of 65 | * Nopoll to change its configuration based on the platform information. 66 | * 67 | * Note when this flag is enabled (set to 1), it means we are 68 | * compiling in a windows platform (no matter if it is 64 or 32 69 | * bits). To check for 64bit see NOPOLL_OS_WIN64. 70 | */ 71 | #define NOPOLL_OS_WIN32 (1) 72 | 73 | 74 | /** 75 | * @brief Indicates where we have support for TLSv1.0 support. 76 | */ 77 | #define NOPOLL_HAVE_TLSv10_ENABLED (1) 78 | 79 | /** 80 | * @brief Indicates where we have support for TLSv1.1 support. 81 | */ 82 | #define NOPOLL_HAVE_TLSv11_ENABLED (1) 83 | 84 | /** 85 | * @brief Indicates where we have support for TLSv1.2 support. 86 | */ 87 | #define NOPOLL_HAVE_TLSv12_ENABLED (1) 88 | 89 | 90 | /* @} */ 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /nopoll/nopoll_config_win64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * noPoll Library nopoll_config.h 3 | * Platform dependant definitions for Win32 platform. 4 | * 5 | * This file is maintained manually for those people that do not 6 | * compile nopoll using autoconf. It should look really similar to 7 | * nopoll_config.h file created on a i386 linux platform but changing 8 | * NOPOLL_OS_UNIX to NOPOLL_OS_WIN32 (at least for now). 9 | * 10 | * For commercial support on build WebSocket enabled solutions contact us: 11 | * 12 | * Postal address: 13 | * Advanced Software Production Line, S.L. 14 | * Edificio Alius A, Oficina 102, 15 | * C/ Antonio Suarez Nº 10, 16 | * Alcalá de Henares 28802 Madrid 17 | * Spain 18 | * 19 | * Email address: 20 | * info@aspl.es - http://www.aspl.es/nopoll 21 | * 22 | */ 23 | 24 | #ifndef __NOPOLL_CONFIG_H__ 25 | #define __NOPOLL_CONFIG_H__ 26 | 27 | #include 28 | 29 | /** 30 | * \addtogroup nopoll_decl_module 31 | * @{ 32 | */ 33 | 34 | /** 35 | * @brief Allows to convert integer value (including constant values) 36 | * into a pointer representation. 37 | * 38 | * Use the oposite function to restore the value from a pointer to a 39 | * integer: \ref PTR_TO_INT. 40 | * 41 | * @param integer The integer value to cast to pointer. 42 | * 43 | * @return A \ref noPollPtr reference. 44 | */ 45 | #ifndef INT_TO_PTR 46 | #define INT_TO_PTR(integer) IntToPtr(integer) 47 | #endif 48 | 49 | /** 50 | * @brief Allows to convert a pointer reference (\ref noPollPtr), 51 | * which stores an integer that was stored using \ref INT_TO_PTR. 52 | * 53 | * Use the oposite function to restore the pointer value stored in the 54 | * integer value. 55 | * 56 | * @param ptr The pointer to cast to a integer value. 57 | * 58 | * @return A int value. 59 | */ 60 | #ifndef PTR_TO_INT 61 | #define PTR_TO_INT(ptr) PtrToInt((const void *) (ptr)) 62 | #endif 63 | 64 | /** 65 | * @brief Allows to get current platform configuration. This is used 66 | * by Nopoll library but could be used by applications built on top of 67 | * Nopoll to change its configuration based on the platform information. 68 | * 69 | * Note when this flag is enabled (set to 1), it means we are 70 | * compiling in a windows platform (no matter if it is 64 or 32 71 | * bits). To check for 64bit see NOPOLL_OS_WIN64. 72 | */ 73 | #define NOPOLL_OS_WIN32 (1) 74 | 75 | /** 76 | * @brief If defined to1, it means we are compiling in a windows 77 | platform running 64 bit version. 78 | */ 79 | #define NOPOLL_OS_WIN64 (1) 80 | 81 | /** 82 | * @brief Indicates where we have support for TLSv1.0 support. 83 | */ 84 | #define NOPOLL_HAVE_TLSv10_ENABLED (1) 85 | 86 | /** 87 | * @brief Indicates where we have support for TLSv1.1 support. 88 | */ 89 | #define NOPOLL_HAVE_TLSv11_ENABLED (1) 90 | 91 | /** 92 | * @brief Indicates where we have support for TLSv1.2 support. 93 | */ 94 | #define NOPOLL_HAVE_TLSv12_ENABLED (1) 95 | 96 | 97 | /* @} */ 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /nopoll/nopoll_conn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_CONN_H__ 40 | #define __NOPOLL_CONN_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | noPollConn * nopoll_conn_new (noPollCtx * ctx, 47 | const char * host_ip, 48 | const char * host_port, 49 | const char * host_name, 50 | const char * get_url, 51 | const char * protocols, 52 | const char * origin); 53 | 54 | noPollConn * nopoll_conn_new6 (noPollCtx * ctx, 55 | const char * host_ip, 56 | const char * host_port, 57 | const char * host_name, 58 | const char * get_url, 59 | const char * protocols, 60 | const char * origin); 61 | 62 | 63 | noPollConn * nopoll_conn_new_opts (noPollCtx * ctx, 64 | noPollConnOpts * opts, 65 | const char * host_ip, 66 | const char * host_port, 67 | const char * host_name, 68 | const char * get_url, 69 | const char * protocols, 70 | const char * origin); 71 | 72 | noPollConn * nopoll_conn_new_with_socket (noPollCtx * ctx, 73 | noPollConnOpts * opts, 74 | int socket, 75 | const char * host_ip, 76 | const char * host_port, 77 | const char * host_name, 78 | const char * get_url, 79 | const char * protocols, 80 | const char * origin); 81 | 82 | noPollConn * nopoll_conn_tls_new (noPollCtx * ctx, 83 | noPollConnOpts * options, 84 | const char * host_ip, 85 | const char * host_port, 86 | const char * host_name, 87 | const char * get_url, 88 | const char * protocols, 89 | const char * origin); 90 | 91 | noPollConn * nopoll_conn_tls_new6 (noPollCtx * ctx, 92 | noPollConnOpts * options, 93 | const char * host_ip, 94 | const char * host_port, 95 | const char * host_name, 96 | const char * get_url, 97 | const char * protocols, 98 | const char * origin); 99 | 100 | noPollConn * nopoll_conn_tls_new_with_socket (noPollCtx * ctx, 101 | noPollConnOpts * options, 102 | int socket, 103 | const char * host_ip, 104 | const char * host_port, 105 | const char * host_name, 106 | const char * get_url, 107 | const char * protocols, 108 | const char * origin); 109 | 110 | noPollConn * nopoll_conn_accept (noPollCtx * ctx, noPollConn * listener); 111 | 112 | noPollConn * nopoll_conn_accept_socket (noPollCtx * ctx, noPollConn * listener, NOPOLL_SOCKET session); 113 | 114 | nopoll_bool nopoll_conn_accept_complete (noPollCtx * ctx, 115 | noPollConn * listener, 116 | noPollConn * conn, 117 | NOPOLL_SOCKET session, 118 | nopoll_bool tls_on); 119 | 120 | nopoll_bool nopoll_conn_ref (noPollConn * conn); 121 | 122 | int nopoll_conn_ref_count (noPollConn * conn); 123 | 124 | void nopoll_conn_unref (noPollConn * conn); 125 | 126 | nopoll_bool nopoll_conn_is_ok (noPollConn * conn); 127 | 128 | nopoll_bool nopoll_conn_is_ready (noPollConn * conn); 129 | 130 | nopoll_bool nopoll_conn_is_tls_on (noPollConn * conn); 131 | 132 | NOPOLL_SOCKET nopoll_conn_socket (noPollConn * conn); 133 | 134 | void nopoll_conn_set_socket (noPollConn * conn, NOPOLL_SOCKET _socket); 135 | 136 | int nopoll_conn_get_id (noPollConn * conn); 137 | 138 | const char * nopoll_conn_get_requested_url (noPollConn * conn); 139 | 140 | noPollCtx * nopoll_conn_ctx (noPollConn * conn); 141 | 142 | noPollRole nopoll_conn_role (noPollConn * conn); 143 | 144 | const char * nopoll_conn_host (noPollConn * conn); 145 | 146 | const char * nopoll_conn_port (noPollConn * conn); 147 | 148 | const char * nopoll_conn_get_origin (noPollConn * conn); 149 | 150 | const char * nopoll_conn_get_host_header (noPollConn * conn); 151 | 152 | const char * nopoll_conn_get_cookie (noPollConn * conn); 153 | 154 | const char * nopoll_conn_get_accepted_protocol (noPollConn * conn); 155 | 156 | const char * nopoll_conn_get_requested_protocol (noPollConn * conn); 157 | 158 | void nopoll_conn_set_accepted_protocol (noPollConn * conn, const char * protocol); 159 | 160 | int nopoll_conn_get_close_status (noPollConn * conn); 161 | 162 | const char * nopoll_conn_get_close_reason (noPollConn * conn); 163 | 164 | void nopoll_conn_shutdown (noPollConn * conn); 165 | 166 | void nopoll_conn_close (noPollConn * conn); 167 | 168 | void nopoll_conn_close_ext (noPollConn * conn, int status, const char * reason, int reason_size); 169 | 170 | void nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr); 171 | 172 | noPollPtr nopoll_conn_get_hook (noPollConn * conn); 173 | 174 | nopoll_bool nopoll_conn_set_sock_block (NOPOLL_SOCKET socket, 175 | nopoll_bool enable); 176 | 177 | noPollMsg * nopoll_conn_get_msg (noPollConn * conn); 178 | 179 | int nopoll_conn_send_text (noPollConn * conn, const char * content, long length); 180 | 181 | int nopoll_conn_send_text_fragment (noPollConn * conn, const char * content, long length); 182 | 183 | int nopoll_conn_send_binary (noPollConn * conn, const char * content, long length); 184 | 185 | int nopoll_conn_send_binary_fragment (noPollConn * conn, const char * content, long length); 186 | 187 | int nopoll_conn_complete_pending_write (noPollConn * conn); 188 | 189 | int nopoll_conn_pending_write_bytes (noPollConn * conn); 190 | 191 | int nopoll_conn_flush_writes (noPollConn * conn, long timeout, int previous_result); 192 | 193 | int nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout); 194 | int aispeech_nopoll_conn_read (noPollConn * conn, char * buffer, int bytes, nopoll_bool block, long int timeout); 195 | 196 | noPollConn * nopoll_conn_get_listener (noPollConn * conn); 197 | 198 | nopoll_bool nopoll_conn_send_ping (noPollConn * conn); 199 | 200 | nopoll_bool nopoll_conn_send_pong (noPollConn * conn, long length, noPollPtr content); 201 | 202 | void nopoll_conn_set_on_msg (noPollConn * conn, 203 | noPollOnMessageHandler on_msg, 204 | noPollPtr user_data); 205 | 206 | void nopoll_conn_set_on_ready (noPollConn * conn, 207 | noPollActionHandler on_ready, 208 | noPollPtr user_data); 209 | 210 | void nopoll_conn_set_on_close (noPollConn * conn, 211 | noPollOnCloseHandler on_close, 212 | noPollPtr user_data); 213 | 214 | int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool masked, 215 | noPollOpCode op_code, long length, noPollPtr content, 216 | long sleep_in_header); 217 | 218 | int __nopoll_conn_send_common (noPollConn * conn, 219 | const char * content, 220 | long length, 221 | nopoll_bool has_fin, 222 | long sleep_in_header, 223 | noPollOpCode frame_type); 224 | 225 | nopoll_bool nopoll_conn_wait_until_connection_ready (noPollConn * conn, 226 | int timeout); 227 | 228 | void nopoll_conn_connect_timeout (noPollCtx * ctx, 229 | long microseconds_to_wait); 230 | 231 | long nopoll_conn_get_connect_timeout (noPollCtx * ctx); 232 | 233 | /** internal api **/ 234 | void nopoll_conn_complete_handshake (noPollConn * conn); 235 | 236 | int nopoll_conn_default_receive (noPollConn * conn, char * buffer, int buffer_size); 237 | 238 | int nopoll_conn_default_send (noPollConn * conn, char * buffer, int buffer_size); 239 | 240 | void nopoll_conn_mask_content (noPollCtx * ctx, char * payload, int payload_size, char * mask, int desp); 241 | 242 | END_C_DECLS 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /nopoll/nopoll_conn_opts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | /** 43 | * \defgroup nopoll_conn_opts noPoll Connection Options: API to change default connection options. 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_conn_opts 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @brief Create a new connection options object. 53 | * 54 | * @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. 55 | */ 56 | noPollConnOpts * nopoll_conn_opts_new (void) 57 | { 58 | noPollConnOpts * result; 59 | 60 | /* create configuration object */ 61 | result = nopoll_new (noPollConnOpts, 1); 62 | if (! result) 63 | return NULL; 64 | 65 | result->reuse = nopoll_false; /* this is not needed, just to clearly state defaults */ 66 | result->ssl_protocol = NOPOLL_METHOD_TLSV1; 67 | 68 | result->mutex = nopoll_mutex_create (); 69 | result->refs = 1; 70 | 71 | /* by default, disable ssl peer verification */ 72 | result->disable_ssl_verify = nopoll_true; 73 | 74 | return result; 75 | } 76 | 77 | /** 78 | * @brief Set ssl protocol method to be used on the API receiving this 79 | * configuration object. 80 | * 81 | * @param opts The connection options object. 82 | * 83 | * @param ssl_protocol SSL protocol to use. See \ref noPollSslProtocol for more information. 84 | */ 85 | void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol) 86 | { 87 | if (opts == NULL) 88 | return; 89 | opts->ssl_protocol = ssl_protocol; 90 | return; 91 | } 92 | 93 | 94 | /** 95 | * @brief Allows to certificate, private key and optional chain 96 | * certificate and ca for on a particular options that can be used for 97 | * a client and a listener connection. 98 | * 99 | * @param opts The connection options where these settings will be 100 | * applied. 101 | * 102 | * @param certificate The certificate to use on the connection. 103 | * 104 | * @param private_key client_certificate private key. 105 | * 106 | * @param chain_certificate Optional chain certificate to use 107 | * 108 | * @param ca_certificate Optional CA certificate to use during the 109 | * process. 110 | * 111 | * @return nopoll_true in the case all certificate files provided are 112 | * reachable. 113 | */ 114 | nopoll_bool nopoll_conn_opts_set_ssl_certs (noPollConnOpts * opts, 115 | const char * certificate, 116 | const char * private_key, 117 | const char * chain_certificate, 118 | const char * ca_certificate) 119 | { 120 | if (opts == NULL) 121 | return nopoll_false; 122 | 123 | /* store certificate settings */ 124 | opts->certificate = nopoll_strdup (certificate); 125 | if (opts->certificate) 126 | if (access (opts->certificate, R_OK) != 0) 127 | return nopoll_false; 128 | opts->private_key = nopoll_strdup (private_key); 129 | if (opts->private_key) 130 | if (access (opts->private_key, R_OK) != 0) 131 | return nopoll_false; 132 | opts->chain_certificate = nopoll_strdup (chain_certificate); 133 | if (opts->chain_certificate) 134 | if (access (opts->chain_certificate, R_OK) != 0) 135 | return nopoll_false; 136 | opts->ca_certificate = nopoll_strdup (ca_certificate); 137 | if (opts->ca_certificate) 138 | if (access (opts->ca_certificate, R_OK) != 0) 139 | return nopoll_false; 140 | 141 | return nopoll_true; 142 | } 143 | 144 | /** 145 | * @brief Allows to disable peer ssl certificate verification. This is 146 | * not recommended for production enviroment. This affects in a 147 | * different manner to a listener connection and a client connection. 148 | * 149 | * For a client connection, by default, peer verification is enabled 150 | * and this function may help to disable it during development or 151 | * other reasons. 152 | * 153 | * In the case of the servers (created by using \ref 154 | * nopoll_listener_new for example) this is not required because by 155 | * default peer verification is disabled by default. 156 | * 157 | * @param opts The connection option to configure. 158 | * 159 | * @param verify nopoll_true to disable verification 160 | * otherwise, nopoll_false should be used. By default SSL verification 161 | * is enabled. 162 | * 163 | */ 164 | void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify) 165 | { 166 | if (opts == NULL) 167 | return; 168 | opts->disable_ssl_verify = ! verify; 169 | return; 170 | } 171 | 172 | /** 173 | * @brief Allows to set Cookie header content to be sent during the 174 | * connection handshake. If configured and the remote side server is a 175 | * noPoll peer, use \ref nopoll_conn_get_cookie to get this value. 176 | * 177 | * @param opts The connection option to configure. 178 | * 179 | * @param cookie_content Content for the cookie. If you pass NULL the 180 | * cookie is unset. 181 | */ 182 | void nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content) 183 | { 184 | if (opts == NULL) 185 | return; 186 | 187 | if (cookie_content) { 188 | /* configure cookie content to be sent */ 189 | opts->cookie = nopoll_strdup (cookie_content); 190 | } else { 191 | nopoll_free (opts->cookie); 192 | opts->cookie = NULL; 193 | } /* end if */ 194 | 195 | return; 196 | } 197 | 198 | /** 199 | * @brief Allows to set arbitrary HTTP headers and content to be sent during 200 | * the connection handshake. 201 | * 202 | * @note String must match the format: "\r\nheader:value\r\nheader2:value2" with 203 | * no trailing \r\n. 204 | * 205 | * @param opts The connection option to configure. 206 | * 207 | * @param header_string Content for the headers. If you pass NULL the 208 | * extra headers are unset. 209 | */ 210 | void nopoll_conn_opts_set_extra_headers (noPollConnOpts * opts, const char * header_string) 211 | { 212 | if (opts == NULL) 213 | return; 214 | 215 | if (header_string) { 216 | /* configure extra_header content to be sent */ 217 | opts->extra_headers = nopoll_strdup (header_string); 218 | } else { 219 | nopoll_free (opts->extra_headers); 220 | opts->extra_headers = NULL; 221 | } /* end if */ 222 | 223 | return; 224 | } 225 | 226 | 227 | /** 228 | * @brief Allows to skip origin check for an incoming connection. 229 | * 230 | * This option is highly not recommended because the Origin header 231 | * must be provided by all WebSocket clients so the the server side 232 | * can check it. 233 | * 234 | * In most environments not doing so will make the connection to not succeed. 235 | * 236 | * Use this option just in development environment. 237 | * 238 | * @param opts The connection options to configure. 239 | * 240 | * @param skip_check nopoll_bool Skip header check 241 | * 242 | */ 243 | void nopoll_conn_opts_skip_origin_check (noPollConnOpts * opts, nopoll_bool skip_check) 244 | { 245 | /* configure skip origin header check */ 246 | if (opts) 247 | opts->skip_origin_header_check = skip_check; 248 | 249 | return; 250 | } 251 | 252 | 253 | /** 254 | * @brief Allows to increase a reference to the connection options 255 | * provided. 256 | * 257 | * @param opts The connection option reference over which a connection 258 | * reference is needed. 259 | * 260 | * @return nopoll_true in the case the operation went ok, otherwise 261 | * nopoll_false is returned. 262 | */ 263 | nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts) 264 | { 265 | if (opts == NULL) 266 | return nopoll_false; 267 | 268 | /* lock the mutex */ 269 | nopoll_mutex_lock (opts->mutex); 270 | if (opts->refs <= 0) { 271 | /* unlock the mutex */ 272 | nopoll_mutex_unlock (opts->mutex); 273 | return nopoll_false; 274 | } 275 | 276 | opts->refs++; 277 | 278 | /* release here the mutex */ 279 | nopoll_mutex_unlock (opts->mutex); 280 | 281 | return nopoll_true; 282 | } 283 | 284 | /** 285 | * @brief Allows to unref a reference acquired by \ref nopoll_conn_opts_ref 286 | * 287 | * @param opts The connection opts to release. 288 | */ 289 | void nopoll_conn_opts_unref (noPollConnOpts * opts) 290 | { 291 | /* call free implementation */ 292 | nopoll_conn_opts_free (opts); 293 | return; 294 | } 295 | 296 | 297 | /** 298 | * @brief Set reuse-flag be used on the API receiving this 299 | * configuration object. By setting nopoll_true will cause the API to 300 | * not release the object when finished. Instead, the caller will be 301 | * able to use this object in additional API calls but, after 302 | * finishing, a call to \ref nopoll_conn_opts_set_reuse function is 303 | * required. 304 | * 305 | * @param opts The connection options object. 306 | * 307 | * @param reuse nopoll_true to reuse the object across calls, 308 | * otherwise nopoll_false to make the API function to release the 309 | * object when done. 310 | */ 311 | void nopoll_conn_opts_set_reuse (noPollConnOpts * opts, nopoll_bool reuse) 312 | { 313 | if (opts == NULL) 314 | return; 315 | opts->reuse = reuse; 316 | return; 317 | } 318 | 319 | 320 | /** 321 | * @brief Allows the user to configure the interface to bind the connection to. 322 | * 323 | * @param opts The connection options object. 324 | * 325 | * @param _interface The interface to bind to, or NULL for system default. 326 | * 327 | */ 328 | void nopoll_conn_opts_set_interface (noPollConnOpts * opts, const char * _interface) 329 | { 330 | if (opts == NULL) 331 | return; 332 | 333 | if (_interface) { 334 | /* configure interface */ 335 | opts->_interface = nopoll_strdup (_interface); 336 | } else { 337 | nopoll_free (opts->_interface); 338 | opts->_interface = NULL; 339 | } /* end if */ 340 | 341 | return; 342 | } 343 | 344 | void __nopoll_conn_opts_free_common (noPollConnOpts * opts) 345 | { 346 | if (opts == NULL) 347 | return; 348 | 349 | /* acquire here the mutex */ 350 | nopoll_mutex_lock (opts->mutex); 351 | 352 | opts->refs--; 353 | if (opts->refs != 0) { 354 | /* release here the mutex */ 355 | nopoll_mutex_unlock (opts->mutex); 356 | return; 357 | } 358 | /* release here the mutex */ 359 | nopoll_mutex_unlock (opts->mutex); 360 | 361 | nopoll_free (opts->certificate); 362 | nopoll_free (opts->private_key); 363 | nopoll_free (opts->chain_certificate); 364 | nopoll_free (opts->ca_certificate); 365 | 366 | /* cookie */ 367 | nopoll_free (opts->cookie); 368 | 369 | /* interface */ 370 | nopoll_free (opts->_interface); 371 | 372 | if (opts->extra_headers) 373 | nopoll_free (opts->extra_headers); 374 | 375 | /* release mutex */ 376 | nopoll_mutex_destroy (opts->mutex); 377 | nopoll_free (opts); 378 | return; 379 | } 380 | 381 | /** 382 | * @brief Allows to release a connection object reported by \ref nopoll_conn_opts_new 383 | * 384 | * 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). 385 | * 386 | * Default behaviour provided by the API implies that every connection 387 | * options object created by \ref nopoll_conn_opts_new is 388 | * automatically released by the API consuming that object. 389 | */ 390 | void nopoll_conn_opts_free (noPollConnOpts * opts) 391 | { 392 | __nopoll_conn_opts_free_common (opts); 393 | return; 394 | } /* end if */ 395 | 396 | /** 397 | * @internal API. Do not use it. It may change at any time without any 398 | * previous indication. 399 | */ 400 | void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options) 401 | { 402 | if (! options) 403 | return; 404 | if (options && options->reuse) 405 | return; 406 | __nopoll_conn_opts_free_common (options); 407 | return; 408 | } 409 | 410 | /* @} */ 411 | -------------------------------------------------------------------------------- /nopoll/nopoll_conn_opts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_CONN_OPTS_H__ 40 | #define __NOPOLL_CONN_OPTS_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | noPollConnOpts * nopoll_conn_opts_new (void); 47 | 48 | void nopoll_conn_opts_set_ssl_protocol (noPollConnOpts * opts, noPollSslProtocol ssl_protocol); 49 | 50 | nopoll_bool nopoll_conn_opts_set_ssl_certs (noPollConnOpts * opts, 51 | const char * client_certificate, 52 | const char * private_key, 53 | const char * chain_certificate, 54 | const char * ca_certificate); 55 | 56 | void nopoll_conn_opts_ssl_peer_verify (noPollConnOpts * opts, nopoll_bool verify); 57 | 58 | void nopoll_conn_opts_set_cookie (noPollConnOpts * opts, const char * cookie_content); 59 | 60 | void nopoll_conn_opts_skip_origin_check (noPollConnOpts * opts, nopoll_bool skip_check); 61 | 62 | nopoll_bool nopoll_conn_opts_ref (noPollConnOpts * opts); 63 | 64 | void nopoll_conn_opts_unref (noPollConnOpts * opts); 65 | 66 | void nopoll_conn_opts_set_reuse (noPollConnOpts * opts, nopoll_bool reuse); 67 | 68 | void nopoll_conn_opts_set_interface (noPollConnOpts * opts, const char * _interface); 69 | 70 | void nopoll_conn_opts_set_extra_headers (noPollConnOpts * opts, const char * extra_headers); 71 | 72 | void nopoll_conn_opts_free (noPollConnOpts * opts); 73 | 74 | /** internal API **/ 75 | void __nopoll_conn_opts_release_if_needed (noPollConnOpts * options); 76 | 77 | END_C_DECLS 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /nopoll/nopoll_ctx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | #include 42 | 43 | /** 44 | * \defgroup nopoll_ctx noPoll Context: context handling functions used by the library 45 | */ 46 | 47 | /** 48 | * \addtogroup nopoll_ctx 49 | * @{ 50 | */ 51 | void __nopoll_ctx_sigpipe_do_nothing (int _signal) 52 | { 53 | #if !defined(NOPOLL_OS_WIN32) && !defined(NOPOLL_OS_RTTHREAD) 54 | /* do nothing sigpipe handler to be able to manage EPIPE error 55 | * returned by write ops. */ 56 | 57 | /* the following line is to ensure ancient glibc version that 58 | * restores to the default handler once the signal handling is 59 | * executed. */ 60 | signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing); 61 | #endif 62 | return; 63 | } 64 | 65 | 66 | /** 67 | * @brief Creates an empty Nopoll context. 68 | */ 69 | noPollCtx * nopoll_ctx_new (void) { 70 | noPollCtx * result = nopoll_new (noPollCtx, 1); 71 | if (result == NULL) 72 | return NULL; 73 | 74 | #if defined(NOPOLL_OS_WIN32) 75 | if (! nopoll_win32_init (result)) 76 | return NULL; 77 | #endif 78 | 79 | /* set initial reference */ 80 | result->conn_id = 1; 81 | result->refs = 1; 82 | result->conn_id = 1; 83 | 84 | /* 20 seconds for connection timeout */ 85 | result->conn_connect_std_timeout = 20000000; 86 | 87 | /* default log initialization */ 88 | result->not_executed = nopoll_true; 89 | result->debug_enabled = nopoll_false; 90 | 91 | /* colored log */ 92 | result->not_executed_color = nopoll_true; 93 | result->debug_color_enabled = nopoll_false; 94 | 95 | /* default back log */ 96 | result->backlog = 5; 97 | 98 | /* current list length */ 99 | result->conn_length = 0; 100 | 101 | /* setup default protocol version */ 102 | result->protocol_version = 13; 103 | 104 | /* create mutexes */ 105 | result->ref_mutex = nopoll_mutex_create (); 106 | 107 | #if !defined(NOPOLL_OS_WIN32) && !defined(NOPOLL_OS_RTTHREAD) 108 | /* install sigpipe handler */ 109 | signal (SIGPIPE, __nopoll_ctx_sigpipe_do_nothing); 110 | #endif 111 | 112 | return result; 113 | } 114 | 115 | /** 116 | * @brief Allows to acquire a reference to the provided context. This 117 | * reference is released by calling to \ref nopoll_ctx_unref. 118 | * 119 | * @param ctx The context to acquire a reference. 120 | * 121 | * @return The function returns nopoll_true in the case the reference 122 | * was acquired, otherwise nopoll_false is returned. 123 | */ 124 | nopoll_bool nopoll_ctx_ref (noPollCtx * ctx) 125 | { 126 | /* return false value */ 127 | nopoll_return_val_if_fail (ctx, ctx, nopoll_false); 128 | 129 | /* acquire mutex here */ 130 | nopoll_mutex_lock (ctx->ref_mutex); 131 | 132 | ctx->refs++; 133 | 134 | /* release mutex here */ 135 | nopoll_mutex_unlock (ctx->ref_mutex); 136 | 137 | return nopoll_true; 138 | } 139 | 140 | 141 | /** 142 | * @brief allows to release a reference acquired to the provided 143 | * noPoll context. 144 | * 145 | * @param ctx The noPoll context reference to release.. 146 | */ 147 | void nopoll_ctx_unref (noPollCtx * ctx) 148 | { 149 | noPollCertificate * cert; 150 | int iterator; 151 | 152 | nopoll_return_if_fail (ctx, ctx); 153 | 154 | /* acquire mutex here */ 155 | nopoll_mutex_lock (ctx->ref_mutex); 156 | 157 | ctx->refs--; 158 | if (ctx->refs != 0) { 159 | /* release mutex here */ 160 | nopoll_mutex_unlock (ctx->ref_mutex); 161 | return; 162 | } 163 | /* release mutex here */ 164 | nopoll_mutex_unlock (ctx->ref_mutex); 165 | 166 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Releasing no poll context %p (%d, conns: %d)", ctx, ctx->refs, ctx->conn_length); 167 | 168 | iterator = 0; 169 | while (iterator < ctx->certificates_length) { 170 | /* get reference */ 171 | cert = &(ctx->certificates[iterator]); 172 | 173 | /* release */ 174 | nopoll_free (cert->serverName); 175 | nopoll_free (cert->certificateFile); 176 | nopoll_free (cert->privateKey); 177 | nopoll_free (cert->optionalChainFile); 178 | 179 | /* next position */ 180 | iterator++; 181 | } /* end while */ 182 | 183 | /* release mutex */ 184 | nopoll_mutex_destroy (ctx->ref_mutex); 185 | 186 | /* release all certificates buckets */ 187 | nopoll_free (ctx->certificates); 188 | 189 | /* release connection */ 190 | nopoll_free (ctx->conn_list); 191 | ctx->conn_length = 0; 192 | nopoll_free (ctx); 193 | return; 194 | } 195 | 196 | /** 197 | * @brief Allows to get current reference counting for the provided 198 | * context. 199 | * 200 | * @param ctx The context the reference counting is being requested. 201 | * 202 | * @return The reference counting or -1 if it fails. 203 | */ 204 | int nopoll_ctx_ref_count (noPollCtx * ctx) 205 | { 206 | int result; 207 | if (! ctx) 208 | return -1; 209 | 210 | /* lock */ 211 | nopoll_mutex_lock (ctx->ref_mutex); 212 | 213 | result = ctx->refs; 214 | 215 | /* unlock */ 216 | nopoll_mutex_unlock (ctx->ref_mutex); 217 | 218 | return result; 219 | } 220 | 221 | /** 222 | * @internal Function used to register the provided connection on the 223 | * provided context. 224 | * 225 | * @param ctx The context where the connection will be registered. 226 | * 227 | * @param conn The connection to be registered. 228 | * 229 | * @return nopoll_true if the connection was registered, otherwise 230 | * nopoll_false is returned. 231 | */ 232 | nopoll_bool nopoll_ctx_register_conn (noPollCtx * ctx, 233 | noPollConn * conn) 234 | { 235 | int iterator; 236 | 237 | nopoll_return_val_if_fail (ctx, ctx && conn, nopoll_false); 238 | 239 | /* acquire mutex here */ 240 | nopoll_mutex_lock (ctx->ref_mutex); 241 | 242 | /* get connection */ 243 | conn->id = ctx->conn_id; 244 | ctx->conn_id ++; 245 | 246 | /* register connection */ 247 | iterator = 0; 248 | while (iterator < ctx->conn_length) { 249 | 250 | /* register reference */ 251 | if (ctx->conn_list[iterator] == 0) { 252 | ctx->conn_list[iterator] = conn; 253 | 254 | /* update connection list number */ 255 | ctx->conn_num++; 256 | 257 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "registered connection id %d, role: %d", conn->id, conn->role); 258 | 259 | /* release */ 260 | nopoll_mutex_unlock (ctx->ref_mutex); 261 | 262 | /* acquire reference */ 263 | nopoll_ctx_ref (ctx); 264 | 265 | /* acquire a reference to the conection */ 266 | nopoll_conn_ref (conn); 267 | 268 | /* release mutex here */ 269 | return nopoll_true; 270 | } 271 | 272 | iterator++; 273 | } /* end while */ 274 | 275 | /* if reached this place it means no more buckets are 276 | * available, acquire more memory (increase 10 by 10) */ 277 | ctx->conn_length += 10; 278 | ctx->conn_list = (noPollConn**) nopoll_realloc (ctx->conn_list, sizeof (noPollConn *) * (ctx->conn_length)); 279 | if (ctx->conn_list == NULL) { 280 | /* release mutex */ 281 | nopoll_mutex_unlock (ctx->ref_mutex); 282 | 283 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "General connection registration error, memory acquisition failed.."); 284 | return nopoll_false; 285 | } /* end if */ 286 | 287 | /* clear new positions */ 288 | iterator = (ctx->conn_length - 10); 289 | while (iterator < ctx->conn_length) { 290 | ctx->conn_list[iterator] = 0; 291 | /* next position */ 292 | iterator++; 293 | } /* end while */ 294 | 295 | /* release mutex here */ 296 | nopoll_mutex_unlock (ctx->ref_mutex); 297 | 298 | /* ok, now register connection because we have memory */ 299 | return nopoll_ctx_register_conn (ctx, conn); 300 | } 301 | 302 | /** 303 | * @internal Function used to register the provided connection on the 304 | * provided context. 305 | * 306 | * @param ctx The context where the connection will be registered. 307 | * 308 | * @param conn The connection to be registered. 309 | */ 310 | void nopoll_ctx_unregister_conn (noPollCtx * ctx, 311 | noPollConn * conn) 312 | { 313 | int iterator; 314 | 315 | nopoll_return_if_fail (ctx, ctx && conn); 316 | 317 | /* acquire mutex here */ 318 | nopoll_mutex_lock (ctx->ref_mutex); 319 | 320 | /* find the connection and remove it from the array */ 321 | iterator = 0; 322 | while (iterator < ctx->conn_length) { 323 | 324 | /* check the connection reference */ 325 | if (ctx->conn_list && ctx->conn_list[iterator] && ctx->conn_list[iterator]->id == conn->id) { 326 | /* remove reference */ 327 | ctx->conn_list[iterator] = NULL; 328 | 329 | /* update connection list number */ 330 | ctx->conn_num--; 331 | 332 | /* release */ 333 | nopoll_mutex_unlock (ctx->ref_mutex); 334 | 335 | /* acquire a reference to the conection */ 336 | nopoll_conn_unref (conn); 337 | 338 | break; 339 | } /* end if */ 340 | 341 | iterator++; 342 | } /* end while */ 343 | 344 | /* release mutex here */ 345 | nopoll_mutex_unlock (ctx->ref_mutex); 346 | 347 | return; 348 | } 349 | 350 | /** 351 | * @brief Allows to get number of connections currently registered. 352 | * 353 | * @param ctx The context where the operation is requested. 354 | * 355 | * @return Number of connections registered on this context or -1 if it fails. 356 | */ 357 | int nopoll_ctx_conns (noPollCtx * ctx) 358 | { 359 | nopoll_return_val_if_fail (ctx, ctx, -1); 360 | return ctx->conn_num; 361 | } 362 | 363 | /** 364 | * @brief Allows to find the certificate associated to the provided serverName. 365 | * 366 | * @param ctx The context where the operation will take place. 367 | * 368 | * @param serverName the servername to use as pattern to find the 369 | * right certificate. If NULL is provided the first certificate not 370 | * refering to any serverName will be returned. 371 | * 372 | * @param certificateFile If provided a reference and the function 373 | * returns nopoll_true, it will contain the certificateFile found. 374 | * 375 | * @param privateKey If provided a reference and the function 376 | * returns nopoll_true, it will contain the privateKey found. 377 | * 378 | * @param optionalChainFile If provided a reference and the function 379 | * returns nopoll_true, it will contain the optionalChainFile found. 380 | * 381 | * @return nopoll_true in the case the certificate was found, 382 | * otherwise nopoll_false is returned. 383 | */ 384 | nopoll_bool nopoll_ctx_find_certificate (noPollCtx * ctx, 385 | const char * serverName, 386 | const char ** certificateFile, 387 | const char ** privateKey, 388 | const char ** optionalChainFile) 389 | { 390 | noPollCertificate * cert; 391 | 392 | int iterator = 0; 393 | nopoll_return_val_if_fail (ctx, ctx, nopoll_false); 394 | 395 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Finding a certificate for serverName=%s", serverName ? serverName : ""); 396 | 397 | while (iterator < ctx->certificates_length) { 398 | /* get cert */ 399 | cert = &(ctx->certificates[iterator]); 400 | if (cert) { 401 | /* found a certificate */ 402 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " certificate stored associated to serverName=%s", cert->serverName ? cert->serverName : ""); 403 | if ((serverName == NULL && cert->serverName == NULL) || 404 | (nopoll_cmp (serverName, cert->serverName))) { 405 | if (certificateFile) 406 | (*certificateFile) = cert->certificateFile; 407 | if (privateKey) 408 | (*privateKey) = cert->privateKey; 409 | if (optionalChainFile) 410 | (*optionalChainFile) = cert->optionalChainFile; 411 | return nopoll_true; 412 | } /* end if */ 413 | } /* end if */ 414 | 415 | /* next position */ 416 | iterator++; 417 | } 418 | 419 | /* check for default certificate when serverName isn't defined */ 420 | if (serverName == NULL) { 421 | /* requested a certificate for an undefined serverName */ 422 | iterator = 0; 423 | while (iterator < ctx->certificates_length) { 424 | /* get cert */ 425 | cert = &(ctx->certificates[iterator]); 426 | if (cert) { 427 | /* found a certificate */ 428 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, " serverName not defined, selecting first certificate from the list"); 429 | if (certificateFile) 430 | (*certificateFile) = cert->certificateFile; 431 | if (privateKey) 432 | (*privateKey) = cert->privateKey; 433 | if (optionalChainFile) 434 | (*optionalChainFile) = cert->optionalChainFile; 435 | return nopoll_true; 436 | } /* end if */ 437 | } /* end if */ 438 | 439 | /* next position */ 440 | iterator++; 441 | } /* end if */ 442 | 443 | return nopoll_false; 444 | } 445 | 446 | /** 447 | * @brief Allows to install a certificate to be used in general by all 448 | * listener connections working under the provided context. 449 | * 450 | * @param ctx The context where the certificate will be installed. 451 | * 452 | * @param serverName The optional server name to to limit the use of 453 | * this certificate to the value provided here. Provide a NULL value 454 | * to make the certificate provide to work under any server notified 455 | * (Host: header) or via SNI (server name identification associated to 456 | * the TLS transport). 457 | * 458 | * @param certificateFile The certificate file to be installed. 459 | * 460 | * @param privateKey The private key file to use used. 461 | * 462 | * @param optionalChainFile Optional chain file with additional 463 | * material to complete the certificate definition. 464 | * 465 | * @return nopoll_true if the certificate was installed otherwise 466 | * nopoll_false. The function returns nopoll_false when ctx, certificateFile or privateKey are NULL. 467 | */ 468 | nopoll_bool nopoll_ctx_set_certificate (noPollCtx * ctx, 469 | const char * serverName, 470 | const char * certificateFile, 471 | const char * privateKey, 472 | const char * optionalChainFile) 473 | { 474 | int length; 475 | noPollCertificate * cert; 476 | 477 | /* check values before proceed */ 478 | nopoll_return_val_if_fail (ctx, ctx && certificateFile && privateKey, nopoll_false); 479 | 480 | /* check if the certificate is already installed */ 481 | if (nopoll_ctx_find_certificate (ctx, serverName, NULL, NULL, NULL)) 482 | return nopoll_true; 483 | 484 | /* update certificate storage to hold all values */ 485 | ctx->certificates_length++; 486 | length = ctx->certificates_length; 487 | if (length == 1) 488 | ctx->certificates = nopoll_new (noPollCertificate, 1); 489 | else 490 | ctx->certificates = (noPollCertificate *) nopoll_realloc (ctx->certificates, sizeof (noPollCertificate) * (length)); 491 | 492 | /* hold certificate */ 493 | cert = &(ctx->certificates[length - 1]); 494 | 495 | cert->serverName = NULL; 496 | if (serverName) 497 | cert->serverName = nopoll_strdup (serverName); 498 | 499 | cert->certificateFile = NULL; 500 | if (certificateFile) 501 | cert->certificateFile = nopoll_strdup (certificateFile); 502 | 503 | cert->privateKey = NULL; 504 | if (privateKey) 505 | cert->privateKey = nopoll_strdup (privateKey); 506 | 507 | cert->optionalChainFile = NULL; 508 | if (optionalChainFile) 509 | cert->optionalChainFile = nopoll_strdup (optionalChainFile); 510 | 511 | return nopoll_true; 512 | } 513 | 514 | /** 515 | * @brief Allows to configure the on open handler, the handler that is 516 | * called when it is received an incoming websocket connection and all 517 | * websocket client handshake data was received (but still not required). 518 | * 519 | * This handler differs from \ref nopoll_ctx_set_on_accept this 520 | * handler is called after all client handshake data was received. 521 | * 522 | * Note the connection is still not fully working at this point 523 | * because the handshake hasn't been sent to the remote peer yet. This 524 | * means that attempting to send any content inside this handler (for 525 | * example by using \ref nopoll_conn_send_text) will cause a protocol 526 | * violation (because remote side is expecting a handshake reply but 527 | * received something different). 528 | * 529 | * In the case you want to sent content right away after receiving a 530 | * connection (on a listener), you can use \ref 531 | * nopoll_ctx_set_on_ready "On Ready" handler which is called just 532 | * after the connection has been fully accepted and handshake reply is 533 | * fully written. 534 | * 535 | * @param ctx The context that will be configured. 536 | * 537 | * @param on_open The handler to be configured on this context. 538 | * 539 | * @param user_data User defined pointer to be passed to the on open 540 | * handler 541 | */ 542 | void nopoll_ctx_set_on_open (noPollCtx * ctx, 543 | noPollActionHandler on_open, 544 | noPollPtr user_data) 545 | { 546 | nopoll_return_if_fail (ctx, ctx && on_open); 547 | 548 | /* set the handler */ 549 | ctx->on_open = on_open; 550 | if (ctx->on_open == NULL) 551 | ctx->on_open_data = NULL; 552 | else 553 | ctx->on_open_data = user_data; 554 | return; 555 | } 556 | 557 | /** 558 | * @brief Allows to configure a handler that is called when a 559 | * connection is received and it is ready to send and receive because 560 | * all WebSocket handshake protocol finished OK. 561 | * 562 | * Unlike handlers configured at \ref nopoll_ctx_set_on_open and \ref 563 | * nopoll_ctx_set_on_accept which get notified when the connection 564 | * isn't still working (because WebSocket handshake wasn't finished 565 | * yet), on read handlers configured here will get called just after 566 | * the WebSocket handshake has taken place. 567 | * 568 | * @param ctx The context that will be configured. 569 | * 570 | * @param on_ready The handler to be called when a connection is fully 571 | * ready to send and receive content because WebSocket handshake has 572 | * finished. The function must return nopoll_true to accept the 573 | * connection. By returning nopoll_false the handler is signalling to 574 | * terminate the connection. 575 | * 576 | * @param user_data Optional user data pointer passed to the on ready 577 | * handler. 578 | * 579 | */ 580 | void nopoll_ctx_set_on_ready (noPollCtx * ctx, 581 | noPollActionHandler on_ready, 582 | noPollPtr user_data) 583 | { 584 | nopoll_return_if_fail (ctx, ctx && on_ready); 585 | 586 | /* set the handler */ 587 | ctx->on_ready = on_ready; 588 | if (ctx->on_ready == NULL) 589 | ctx->on_ready_data = NULL; 590 | else 591 | ctx->on_ready_data = user_data; 592 | return; 593 | } 594 | 595 | /** 596 | * @brief Allows to configure the accept handler that will be called 597 | * when a connection is received but before any handshake takes place. 598 | * 599 | * @param ctx The context that will be configured. 600 | * 601 | * @param on_accept The handler to be called when a connection is 602 | * received. Here the handler must return nopoll_true to accept the 603 | * connection, otherwise nopoll_false should be returned. 604 | * 605 | * @param user_data Optional user data pointer passed to the on accept 606 | * handler. 607 | * 608 | */ 609 | void nopoll_ctx_set_on_accept (noPollCtx * ctx, 610 | noPollActionHandler on_accept, 611 | noPollPtr user_data) 612 | { 613 | nopoll_return_if_fail (ctx, ctx && on_accept); 614 | 615 | /* set the handler */ 616 | ctx->on_accept = on_accept; 617 | if (ctx->on_accept == NULL) 618 | ctx->on_accept_data = NULL; 619 | else 620 | ctx->on_accept_data = user_data; 621 | return; 622 | } 623 | 624 | /** 625 | * @brief Allows to set a general handler to get notifications about a 626 | * message received over any connection that is running under the 627 | * provided context (noPollCtx). 628 | * 629 | * @param ctx The context where the notification will happen 630 | * 631 | * @param on_msg The handler to be called when an incoming message is 632 | * received. 633 | * 634 | * @param user_data User defined pointer that is passed in into the 635 | * handler when called. 636 | * 637 | * Note that the handler configured here will be overriden by the handler configured by \ref nopoll_conn_set_on_msg 638 | * 639 | */ 640 | void nopoll_ctx_set_on_msg (noPollCtx * ctx, 641 | noPollOnMessageHandler on_msg, 642 | noPollPtr user_data) 643 | { 644 | nopoll_return_if_fail (ctx, ctx); 645 | 646 | /* set new handler */ 647 | ctx->on_msg = on_msg; 648 | ctx->on_msg_data = user_data; 649 | 650 | return; 651 | } 652 | 653 | /** 654 | * @brief Allows to configure the handler that will be used to let 655 | * user land code to define OpenSSL SSL_CTX object. 656 | * 657 | * By default, SSL_CTX (SSL Context) object is created by default 658 | * settings that works for most of the cases. In the case you want to 659 | * configure particular configurations that should be enabled on the 660 | * provided SSL_CTX that is going to be used by the client ---while 661 | * connecting--- or server ---while receiving a connection--- then use 662 | * this function to setup your creator handler. 663 | * 664 | * See \ref noPollSslContextCreator for more information about this 665 | * handler. 666 | * 667 | */ 668 | void nopoll_ctx_set_ssl_context_creator (noPollCtx * ctx, 669 | noPollSslContextCreator context_creator, 670 | noPollPtr user_data) 671 | { 672 | if (ctx == NULL) 673 | return; 674 | 675 | /* set handlers as indicated by the caller */ 676 | ctx->context_creator = context_creator; 677 | ctx->context_creator_data = user_data; 678 | return; 679 | } 680 | 681 | /** 682 | * @brief Allows to configure a function that will implement an post SSL/TLS check. 683 | * 684 | * See the following function to get more information: \ref noPollSslPostCheck 685 | * 686 | * @param ctx The context where the operation is taking place. 687 | * 688 | * @param post_ssl_check The handler that is going to be called 689 | * everything a new connection with SSL is established by a client or 690 | * received by a server. The handler is executed right after the SSL 691 | * handshake finishes without error. 692 | * 693 | * @param user_data A reference to user defined pointer that will be 694 | * passed in to the handler. 695 | */ 696 | void nopoll_ctx_set_post_ssl_check (noPollCtx * ctx, 697 | noPollSslPostCheck post_ssl_check, 698 | noPollPtr user_data) 699 | { 700 | if (ctx == NULL) 701 | return; 702 | 703 | /* set handlers as indicated by the caller */ 704 | ctx->post_ssl_check = post_ssl_check; 705 | ctx->post_ssl_check_data = user_data; 706 | return; 707 | } 708 | 709 | /** 710 | * @brief Allows to iterate over all connections currently registered 711 | * on the provided context, optionally stopping the foreach process, 712 | * returning the connection reference selected if the foreach handler 713 | * returns nopoll_true. 714 | * 715 | * @param ctx The nopoll context where the foreach operation will take 716 | * place. 717 | * 718 | * @param foreach The foreach handler to be called for each connection 719 | * registered. 720 | * 721 | * @param user_data An optional reference to a pointer that will be 722 | * passed to the handler. 723 | * 724 | * @return Returns the connection selected (in the case the foreach 725 | * function returns nopoll_false) or NULL in the case all foreach 726 | * executions returned nopoll_true. Keep in mind the function also 727 | * returns NULL if ctx or foreach parameter is NULL. 728 | * 729 | * See \ref noPollForeachConn for a signature example. 730 | */ 731 | noPollConn * nopoll_ctx_foreach_conn (noPollCtx * ctx, 732 | noPollForeachConn foreach, 733 | noPollPtr user_data) 734 | { 735 | noPollConn * result; 736 | int iterator; 737 | nopoll_return_val_if_fail (ctx, ctx && foreach, NULL); 738 | 739 | /* acquire here the mutex to protect connection list */ 740 | nopoll_mutex_lock (ctx->ref_mutex); 741 | 742 | /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Doing foreach over conn_length array (%p): %d", ctx, ctx->conn_length); */ 743 | 744 | /* find the connection and remove it from the array */ 745 | iterator = 0; 746 | while (iterator < ctx->conn_length) { 747 | 748 | /* check the connection reference */ 749 | if (ctx->conn_list[iterator]) { 750 | 751 | result = ctx->conn_list[iterator]; 752 | 753 | nopoll_mutex_unlock (ctx->ref_mutex); 754 | 755 | /* call to notify connection */ 756 | if (foreach (ctx, result, user_data)) { 757 | 758 | /* release here the mutex to protect connection list */ 759 | return result; 760 | } /* end if */ 761 | 762 | /* realloc again */ 763 | nopoll_mutex_lock (ctx->ref_mutex); 764 | 765 | } /* end if */ 766 | 767 | iterator++; 768 | } /* end while */ 769 | 770 | /* release here the mutex to protect connection list */ 771 | nopoll_mutex_unlock (ctx->ref_mutex); 772 | 773 | return NULL; 774 | } 775 | 776 | 777 | /** 778 | * @brief Allows to change the protocol version that is send in all 779 | * client connections created under the provided context and the 780 | * protocol version accepted by listener created under this context 781 | * too. 782 | * 783 | * This is a really basic (mostly fake) protocol version support 784 | * because it only allows to change the version string sent (but 785 | * nothing more for now). It is useful for testing purposes. 786 | * 787 | * @param ctx The noPoll context where the protocol version change 788 | * will be applied. 789 | * 790 | * @param version The value representing the protocol version. By 791 | * default this function isn't required to be called because it 792 | * already has the right protocol value configured (13). 793 | */ 794 | void nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version) 795 | { 796 | /* check input data */ 797 | nopoll_return_if_fail (ctx, ctx || version); 798 | 799 | /* setup the new protocol version */ 800 | ctx->protocol_version = version; 801 | 802 | return; 803 | } 804 | 805 | /* @} */ 806 | -------------------------------------------------------------------------------- /nopoll/nopoll_ctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_CTX_H__ 40 | #define __NOPOLL_CTX_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | noPollCtx * nopoll_ctx_new (void); 47 | 48 | nopoll_bool nopoll_ctx_ref (noPollCtx * ctx); 49 | 50 | void nopoll_ctx_unref (noPollCtx * ctx); 51 | 52 | int nopoll_ctx_ref_count (noPollCtx * ctx); 53 | 54 | nopoll_bool nopoll_ctx_register_conn (noPollCtx * ctx, 55 | noPollConn * conn); 56 | 57 | void nopoll_ctx_unregister_conn (noPollCtx * ctx, 58 | noPollConn * conn); 59 | 60 | int nopoll_ctx_conns (noPollCtx * ctx); 61 | 62 | nopoll_bool nopoll_ctx_set_certificate (noPollCtx * ctx, 63 | const char * serverName, 64 | const char * certificateFile, 65 | const char * privateKey, 66 | const char * optionalChainFile); 67 | 68 | nopoll_bool nopoll_ctx_find_certificate (noPollCtx * ctx, 69 | const char * serverName, 70 | const char ** certificateFile, 71 | const char ** privateKey, 72 | const char ** optionalChainFile); 73 | 74 | void nopoll_ctx_set_on_accept (noPollCtx * ctx, 75 | noPollActionHandler on_accept, 76 | noPollPtr user_data); 77 | 78 | void nopoll_ctx_set_on_open (noPollCtx * ctx, 79 | noPollActionHandler on_open, 80 | noPollPtr user_data); 81 | 82 | void nopoll_ctx_set_on_ready (noPollCtx * ctx, 83 | noPollActionHandler on_ready, 84 | noPollPtr user_data); 85 | 86 | void nopoll_ctx_set_on_msg (noPollCtx * ctx, 87 | noPollOnMessageHandler on_msg, 88 | noPollPtr user_data); 89 | 90 | void nopoll_ctx_set_ssl_context_creator (noPollCtx * ctx, 91 | noPollSslContextCreator context_creator, 92 | noPollPtr user_data); 93 | 94 | void nopoll_ctx_set_post_ssl_check (noPollCtx * ctx, 95 | noPollSslPostCheck post_ssl_check, 96 | noPollPtr user_data); 97 | 98 | noPollConn * nopoll_ctx_foreach_conn (noPollCtx * ctx, noPollForeachConn foreach, noPollPtr user_data); 99 | 100 | void nopoll_ctx_set_protocol_version (noPollCtx * ctx, int version); 101 | 102 | void nopoll_ctx_free (noPollCtx * ctx); 103 | 104 | END_C_DECLS 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /nopoll/nopoll_decl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | 41 | /** 42 | * \addtogroup nopoll_decl_module 43 | * @{ 44 | */ 45 | 46 | #if !(NOPOLL_OS_RTTHREAD) 47 | /** 48 | * @brief Calloc helper for nopoll library. 49 | * 50 | * @param count How many items to allocate. 51 | * @param size Size of one item. 52 | * 53 | * @return A newly allocated pointer. 54 | * @see nopoll_free 55 | */ 56 | noPollPtr nopoll_calloc(size_t count, size_t size) 57 | { 58 | return calloc (count, size); 59 | } 60 | 61 | /** 62 | * @brief Realloc helper for nopoll library. 63 | * 64 | * @param ref the reference to reallocate. 65 | * @param size Size of the new reference. 66 | * 67 | * @return A newly allocated pointer. 68 | * @see nopoll_free 69 | */ 70 | noPollPtr nopoll_realloc(noPollPtr ref, size_t size) 71 | { 72 | return realloc (ref, size); 73 | } 74 | 75 | /** 76 | * @brief Allows to deallocate memory referenced by ref but 77 | * checking before that the reference is different from null. 78 | * 79 | * @param ref The reference to clear. 80 | */ 81 | void nopoll_free (noPollPtr ref) 82 | { 83 | free (ref); 84 | return; 85 | } 86 | #endif 87 | 88 | /** 89 | * @} 90 | */ 91 | 92 | -------------------------------------------------------------------------------- /nopoll/nopoll_decl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_DECL_H__ 40 | #define __NOPOLL_DECL_H__ 41 | 42 | /** 43 | * \defgroup nopoll_decl_module Nopoll Declarations: Common Nopoll declarations, Types, macros, and support functions. 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_decl_module 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @brief Set a default I/O wait limit from the default, which is 64 53 | * sockets to 4096. Note that this affects \ref nopoll_loop_wait (when 54 | * using select() API). If you change this value, you'll have to 55 | * recompile noPoll so internal structures will be updated. See the 56 | * following document: 57 | * 58 | * - https://tangentsoft.net/wskfaq/advanced.html 59 | * (What are the "64 sockets" limitations?) 60 | * 61 | * For Windows platforms, there are two 64-socket limitations: 62 | * 63 | * The Windows event mechanism (e.g. WaitForMultipleObjects()) can 64 | * only wait on 64 event objects at a time. Winsock 2 provides the 65 | * WSAEventSelect() function which lets you use Windows’ event 66 | * mechanism to wait for events on sockets. Because it uses Windows’ 67 | * event mechanism, you can only wait for events on 64 sockets at a 68 | * time. If you want to wait on more than 64 Winsock event objects at 69 | * a time, you need to use multiple threads, each waiting on no more 70 | * than 64 of the sockets. 71 | * 72 | * The select() function is also limited in certain situations to 73 | * waiting on 64 sockets at a time. The FD_SETSIZE constant defined in 74 | * the Winsock header determines the size of the fd_set structures you 75 | * pass to select(). The default value is 64, but if you define this 76 | * constant to a different value before including the Winsock header, 77 | * it accepts that value instead: 78 | * 79 | * \code 80 | * // define in your code new limit 81 | * #define FD_SETSIZE 1024 82 | * // then include nopoll.h (you need to recompile noPoll) 83 | * #include 84 | * \endcode 85 | * 86 | * The problem is that modern network stacks are complex, with many 87 | * parts coming from various sources, including third parties via 88 | * things like Layered Service Providers. When you change this 89 | * constant, you’re depending on all these components to play by the 90 | * new rules. They’re supposed to, but not all do. The typical symptom 91 | * is that they ignore sockets beyond the 64th in larger fd_set 92 | * structures. You can get around this limitation with threads, just 93 | * as in the event object case. 94 | */ 95 | #ifndef FD_SETSIZE 96 | #define FD_SETSIZE 4096 97 | #endif 98 | 99 | /* include platform specific configuration */ 100 | #include 101 | 102 | /* max buffer size to process incoming handshake */ 103 | #define NOPOLL_HANDSHAKE_BUFFER_SIZE 8192 104 | 105 | /* include this at this place to load GNU extensions */ 106 | #if defined(__GNUC__) 107 | # ifndef _GNU_SOURCE 108 | # define _GNU_SOURCE 109 | # endif 110 | # define __NOPOLL_PRETTY_FUNCTION__ __PRETTY_FUNCTION__ 111 | # define __NOPOLL_LINE__ __LINE__ 112 | # define __NOPOLL_FILE__ __FILE__ 113 | #elif defined(_MSC_VER) 114 | # define __NOPOLL_PRETTY_FUNCTION__ __FUNCDNAME__ 115 | # define __NOPOLL_LINE__ __LINE__ 116 | # define __NOPOLL_FILE__ __FILE__ 117 | #else 118 | /* unknown compiler */ 119 | #define __NOPOLL_PRETTY_FUNCTION__ "" 120 | #define __NOPOLL_LINE__ 0 121 | #define __NOPOLL_FILE__ "" 122 | #endif 123 | 124 | #include 125 | #include 126 | #include 127 | 128 | #include 129 | 130 | /* only include unistd.h if unix platform is found or gnu gcc compiler 131 | * is found */ 132 | #if defined(__GNUC__) || defined(NOPOLL_OS_UNIX) 133 | # include 134 | #endif 135 | 136 | // #include 137 | // #include 138 | // #include 139 | #include 140 | 141 | /* Direct portable mapping definitions */ 142 | #if defined(NOPOLL_OS_UNIX) 143 | 144 | /* Portable definitions while using noPoll Library */ 145 | #define NOPOLL_EINTR EINTR 146 | /** 147 | * @brief Portable definition for EWOULDBLOCK errno code. 148 | */ 149 | #define NOPOLL_EWOULDBLOCK EWOULDBLOCK 150 | #define NOPOLL_EINPROGRESS EINPROGRESS 151 | #define NOPOLL_ENOTCONN ENOTCONN 152 | #define NOPOLL_EAGAIN EAGAIN 153 | #define NOPOLL_SOCKET int 154 | #define NOPOLL_INVALID_SOCKET -1 155 | #define NOPOLL_SOCKET_ERROR -1 156 | #define nopoll_close_socket(s) do {if ( s >= 0) {close (s);}} while (0) 157 | #define nopoll_is_disconnected (errno == EPIPE) 158 | 159 | #endif /* end defined(AXL_OS_UNIX) */ 160 | 161 | #if defined(NOPOLL_OS_RTTHREAD) 162 | 163 | #include 164 | 165 | /** let's have support for R_OK if it is not defined **/ 166 | # ifndef R_OK 167 | # define R_OK 4 168 | # endif 169 | 170 | /* Portable definitions while using noPoll Library */ 171 | #define NOPOLL_EINTR EINTR 172 | /** 173 | * @brief Portable definition for EWOULDBLOCK errno code. 174 | */ 175 | #define NOPOLL_EWOULDBLOCK EWOULDBLOCK 176 | #define NOPOLL_EINPROGRESS EINPROGRESS 177 | #define NOPOLL_ENOTCONN ENOTCONN 178 | #define NOPOLL_EAGAIN EAGAIN 179 | #define NOPOLL_SOCKET int 180 | #define NOPOLL_INVALID_SOCKET -1 181 | #define NOPOLL_SOCKET_ERROR -1 182 | #define nopoll_close_socket(s) do {if ( s >= 0) {closesocket (s);}} while (0) 183 | 184 | #endif /* end defined(AXL_OS_UNIX) */ 185 | 186 | #if defined(NOPOLL_OS_WIN32) 187 | 188 | /** let's have support for R_OK if it is not defined **/ 189 | # ifndef R_OK 190 | # define R_OK 4 191 | # endif 192 | 193 | 194 | /* additional includes for the windows platform */ 195 | 196 | /* _WIN32_WINNT note: If the application including the header defines 197 | * the _WIN32_WINNT, it must include the bits defined by the value 198 | * 0x501. */ 199 | #ifndef _WIN32_WINNT 200 | # define _WIN32_WINNT 0x501 201 | #elif _WIN32_WINNT < 0x501 202 | # undef _WIN32_WINNT 203 | # define _WIN32_WINNT 0x501 204 | #endif 205 | #include 206 | #include 207 | #include 208 | #include 209 | #include 210 | #include 211 | #include 212 | 213 | #ifdef _MSC_FULL_VER 214 | #define strcasecmp(string1, string2) _stricmp(string1, string2) 215 | #endif 216 | 217 | #define NOPOLL_EINTR WSAEINTR 218 | #define NOPOLL_EWOULDBLOCK WSAEWOULDBLOCK 219 | #define NOPOLL_EINPROGRESS WSAEINPROGRESS 220 | #define NOPOLL_ENOTCONN WSAENOTCONN 221 | #define NOPOLL_EAGAIN WSAEWOULDBLOCK 222 | #define SHUT_RDWR SD_BOTH 223 | #define SHUT_WR SD_SEND 224 | #define NOPOLL_SOCKET SOCKET 225 | #define NOPOLL_INVALID_SOCKET INVALID_SOCKET 226 | #define NOPOLL_SOCKET_ERROR SOCKET_ERROR 227 | #define nopoll_close_socket(s) do {if ( s >= 0) {closesocket (s);}} while (0) 228 | #define uint16_t u_short 229 | #define nopoll_is_disconnected ((errno == WSAESHUTDOWN) || (errno == WSAECONNABORTED) || (errno == WSAECONNRESET)) 230 | 231 | /* a definition to avoid warnings */ 232 | #define strlen (int) strlen 233 | 234 | /* no link support windows */ 235 | #define S_ISLNK(m) (0) 236 | 237 | #endif /* end defined(NOPOLL_OS_WINDOWS) */ 238 | 239 | #if defined(NOPOLL_OS_UNIX) 240 | #include 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | #include 249 | #include 250 | #include 251 | #endif 252 | 253 | #if defined(NOPOLL_OS_RTTHREAD) 254 | #include 255 | #include 256 | #include 257 | 258 | // #include 259 | // #include 260 | #include 261 | #include 262 | #include 263 | // #include 264 | 265 | #ifdef send 266 | #undef send 267 | #endif 268 | 269 | #endif 270 | 271 | 272 | /* additional headers for poll support */ 273 | #if defined(NOPOLL_HAVE_POLL) 274 | #include 275 | #endif 276 | 277 | /* additional headers for linux epoll support */ 278 | #if defined(NOPOLL_HAVE_EPOLL) 279 | #include 280 | #endif 281 | 282 | #include 283 | 284 | #if defined(NOPOLL_OS_WIN32) 285 | /* errno redefinition for windows platform. this declaration must 286 | * follow the previous include. */ 287 | #ifdef errno 288 | #undef errno 289 | #endif 290 | #define errno (WSAGetLastError()) 291 | #endif 292 | 293 | #if defined(NOPOLL_OS_RTTHREAD) 294 | #ifdef errno 295 | #undef errno 296 | #endif 297 | #define errno (*_rt_errno()) 298 | #endif 299 | 300 | /** 301 | * @brief Common definition to have false (\ref nopoll_false) value (which is defined to 0 integer value). 302 | */ 303 | #define nopoll_false ((int)0) 304 | /** 305 | * @brief Common definition to have true (\ref nopoll_true) value (which is defined to 1 integer value). 306 | */ 307 | #define nopoll_true ((int)1) 308 | 309 | /** 310 | * @brief Bool definition for the Nopoll toolkit. This type built on 311 | * top of int is used along with \ref nopoll_false and \ref 312 | * nopoll_true to model those API functions and attributes that 313 | * returns or receive a boolean state. 314 | */ 315 | typedef int nopoll_bool; 316 | 317 | /** 318 | * @brief Pointer to any structure definition. It should be required 319 | * to use this definition, however, some platforms doesn't support the 320 | * void * making it necessary to use the char * 321 | * definition as a general way to represent references. 322 | */ 323 | typedef void * noPollPtr; 324 | 325 | /** 326 | * @brief Execution context object used by the API to provide default 327 | * settings. 328 | */ 329 | typedef struct _noPollCtx noPollCtx; 330 | 331 | /** 332 | * @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 333 | * 334 | * See noPoll API because there are other methods to create connections (not only previous mentioned functions). 335 | */ 336 | typedef struct _noPollConn noPollConn; 337 | 338 | /** 339 | * @brief Optional connection options to change default behaviour. 340 | */ 341 | typedef struct _noPollConnOpts noPollConnOpts; 342 | 343 | /** 344 | * @brief Abstraction that represents a selected IO wait mechanism. 345 | */ 346 | typedef struct _noPollIoEngine noPollIoEngine; 347 | 348 | /** 349 | * @brief Abstraction that represents a single websocket message 350 | * received. 351 | */ 352 | typedef struct _noPollMsg noPollMsg; 353 | 354 | /** 355 | * @brief Abstraction that represents the status and data exchanged 356 | * during the handshake. 357 | */ 358 | typedef struct _noPollHandshake noPollHandShake; 359 | 360 | /** 361 | * @brief Nopoll debug levels. 362 | * 363 | * While reporting log to the console, these levels are used to report 364 | * the severity for such log. 365 | */ 366 | typedef enum { 367 | /** 368 | * @brief Debug level. Only used to report common 369 | * circumstances that represent the proper functionality. 370 | */ 371 | NOPOLL_LEVEL_DEBUG, 372 | /** 373 | * @brief Warning level. Only used to report that an internal 374 | * issue have happend that could be interesting while 375 | * reporting error, but it could also mean common situations. 376 | */ 377 | NOPOLL_LEVEL_WARNING, 378 | /** 379 | * @brief Critical level. Only used to report critical 380 | * situations where some that have happened shouldn't. 381 | * 382 | * This level should only be used while reporting critical 383 | * situations. 384 | */ 385 | NOPOLL_LEVEL_CRITICAL} 386 | noPollDebugLevel; 387 | 388 | /** 389 | * @brief Describes the connection role (how it was initiated). 390 | */ 391 | typedef enum { 392 | /** 393 | * @brief Unknown role, returned/used when the connection isn't defined. 394 | */ 395 | NOPOLL_ROLE_UNKNOWN, 396 | /** 397 | * @brief When the connection was created connecting to a web 398 | * socket server (see \ref nopoll_conn_new). 399 | */ 400 | NOPOLL_ROLE_CLIENT, 401 | /** 402 | * @brief When the connection was accepted being a listener 403 | * process. 404 | */ 405 | NOPOLL_ROLE_LISTENER, 406 | /** 407 | * @brief When the connection was created by \ref 408 | * nopoll_listener_new to accept incoming connections. 409 | */ 410 | NOPOLL_ROLE_MAIN_LISTENER 411 | } noPollRole; 412 | 413 | /** 414 | * @brief List of supported IO waiting mechanism available. 415 | */ 416 | typedef enum { 417 | /** 418 | * @brief Selects the default (best) IO mechanism found on the 419 | * system. 420 | */ 421 | NOPOLL_IO_ENGINE_DEFAULT, 422 | /** 423 | * @brief Selects the select(2) based IO wait mechanism. 424 | */ 425 | NOPOLL_IO_ENGINE_SELECT, 426 | /** 427 | * @brief Selects the poll(2) based IO wait mechanism. 428 | */ 429 | NOPOLL_IO_ENGINE_POLL, 430 | /** 431 | * @brief Selects the epoll(2) based IO wait mechanism. 432 | */ 433 | NOPOLL_IO_ENGINE_EPOLL 434 | } noPollIoEngineType; 435 | 436 | /** 437 | * @brief Support macro to allocate memory using nopoll_calloc function, 438 | * making a casting and using the sizeof keyword. 439 | * 440 | * @param type The type to allocate 441 | * @param count How many items to allocate. 442 | * 443 | * @return A newly allocated pointer. 444 | */ 445 | #define nopoll_new(type, count) (type *) nopoll_calloc (count, sizeof (type)) 446 | 447 | /** 448 | * @brief Allows to check a condition and return if it is not meet. 449 | * 450 | * @param ctx The context where the operation will take place. 451 | * @param expr The expresion to check. 452 | */ 453 | #define nopoll_return_if_fail(ctx, expr) \ 454 | 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;} 455 | 456 | /** 457 | * @brief Allows to check a condition and return the given value if it 458 | * is not meet. 459 | * 460 | * @param ctx The context where the operation will take place. 461 | * 462 | * @param expr The expresion to check. 463 | * 464 | * @param val The value to return if the expression is not meet. 465 | */ 466 | #define nopoll_return_val_if_fail(ctx, expr, val) \ 467 | 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;} 468 | 469 | 470 | /** 471 | * @internal 472 | * 473 | * C++ support declarations borrowed from the libtool webpage. Thanks 474 | * you guys for this information. 475 | * 476 | * BEGIN_C_DECLS should be used at the beginning of your declarations, 477 | * so that C++ compilers don't mangle their names. Use END_C_DECLS at 478 | * the end of C declarations. 479 | */ 480 | #undef BEGIN_C_DECLS 481 | #undef END_C_DECLS 482 | #ifdef __cplusplus 483 | # define BEGIN_C_DECLS extern "C" { 484 | # define END_C_DECLS } 485 | #else 486 | # define BEGIN_C_DECLS /* empty */ 487 | # define END_C_DECLS /* empty */ 488 | #endif 489 | 490 | 491 | /** 492 | * @brief Type of frames and opcodes supported by noPoll. 493 | */ 494 | typedef enum { 495 | /** 496 | * @brief Support to model unknown op code. 497 | */ 498 | NOPOLL_UNKNOWN_OP_CODE = -1, 499 | /** 500 | * @brief Denotes a continuation frame. 501 | */ 502 | NOPOLL_CONTINUATION_FRAME = 0, 503 | /** 504 | * @brief Denotes a text frame (utf-8 content) and the first 505 | * frame of the message. 506 | */ 507 | NOPOLL_TEXT_FRAME = 1, 508 | /** 509 | * @brief Denotes a binary frame and the first frame of the 510 | * message. 511 | */ 512 | NOPOLL_BINARY_FRAME = 2, 513 | /** 514 | * @brief Denotes a close frame request. 515 | */ 516 | NOPOLL_CLOSE_FRAME = 8, 517 | /** 518 | * @brief Denotes a ping frame (used to ring test the circuit 519 | * and to keep alive the connection). 520 | */ 521 | NOPOLL_PING_FRAME = 9, 522 | /** 523 | * @brief Denotes a pong frame (reply to ping request). 524 | */ 525 | NOPOLL_PONG_FRAME = 10 526 | } noPollOpCode; 527 | 528 | /** 529 | * @brief SSL/TLS protocol type to use for the client or listener 530 | * connection. 531 | */ 532 | typedef enum { 533 | #if defined(NOPOLL_HAVE_SSLv23_ENABLED) 534 | /** 535 | * @brief Allows to define SSLv23 as SSL protocol used by the 536 | * client or server connection. A TLS/SSL connection 537 | * established with these methods may understand SSLv3, TLSv1, 538 | * TLSv1.1 and TLSv1.2 protocols (\ref NOPOLL_METHOD_SSLV3, \ref NOPOLL_METHOD_TLSV1, ...) 539 | */ 540 | NOPOLL_METHOD_SSLV23 = 2, 541 | #endif 542 | #if defined(NOPOLL_HAVE_SSLv3_ENABLED) 543 | /** 544 | * @brief Allows to define SSLv3 as SSL protocol used by the 545 | * client or server connection. A connection/listener 546 | * established with this method will only understand this 547 | * method. 548 | */ 549 | NOPOLL_METHOD_SSLV3 = 3, 550 | #endif 551 | #if defined(NOPOLL_HAVE_TLSv10_ENABLED) 552 | /** 553 | * @brief Allows to define TLSv1 as SSL protocol used by the 554 | * client or server connection. A connection/listener 555 | * established with this method will only understand this 556 | * method. 557 | */ 558 | NOPOLL_METHOD_TLSV1 = 4, 559 | #endif 560 | #if defined(NOPOLL_HAVE_TLSv11_ENABLED) 561 | /** 562 | * @brief Allows to define TLSv1.1 as SSL protocol used by the 563 | * client or server connection. A connection/listener 564 | * established with this method will only understand this 565 | * method. 566 | */ 567 | NOPOLL_METHOD_TLSV1_1 = 5 568 | #endif 569 | #if defined(NOPOLL_HAVE_TLSv12_ENABLED) 570 | , 571 | /** 572 | * @brief Allows to define TLSv1.2 as SSL protocol used by the 573 | * client or server connection. A connection/listener 574 | * established with this method will only understand this 575 | * method. 576 | */ 577 | NOPOLL_METHOD_TLSV1_2 = 6 578 | #endif 579 | #if defined(NOPOLL_HAVE_TLS_FLEXIBLE_ENABLED) 580 | , 581 | /** 582 | * @brief Allows to define TLS flexible negotiation where the 583 | * highest version available will be negotiated by both 584 | * ends. If you want a particular TLS version, do not use this 585 | * method. 586 | * 587 | * Security consideration: by using this method you are 588 | * accepting that the remote peer can downgrade to the lowest 589 | * version of the protocol. In the case you want to use a 590 | * particular version do not use this flexible method. 591 | */ 592 | NOPOLL_METHOD_TLS_FLEXIBLE = 7 593 | #endif 594 | } noPollSslProtocol ; 595 | 596 | /** 597 | * @brief Transport indication to be used by various internal and 598 | * public APIs 599 | */ 600 | typedef enum { 601 | /** 602 | * Use IPv4 transport 603 | */ 604 | NOPOLL_TRANSPORT_IPV4 = 1, 605 | /** 606 | * Use IPv6 transport 607 | */ 608 | NOPOLL_TRANSPORT_IPV6 = 2 609 | } noPollTransport; 610 | 611 | BEGIN_C_DECLS 612 | 613 | noPollPtr nopoll_calloc (size_t count, size_t size); 614 | 615 | noPollPtr nopoll_realloc (noPollPtr ref, size_t size); 616 | 617 | void nopoll_free (noPollPtr ref); 618 | 619 | END_C_DECLS 620 | 621 | #endif 622 | 623 | /* @} */ 624 | -------------------------------------------------------------------------------- /nopoll/nopoll_handlers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_HANDLERS_H__ 40 | #define __NOPOLL_HANDLERS_H__ 41 | 42 | /** 43 | * \defgroup nopoll_handlers noPoll Handlers: Handler definitions used by the library to du async notifications 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_handlers 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @brief General async handler definition used to notify generic 53 | * events associated to a connection. 54 | * 55 | * Currently this handler is used by: 56 | * - \ref nopoll_ctx_set_on_accept 57 | * - \ref nopoll_ctx_set_on_open 58 | * 59 | * @param ctx The context where the wait is happening. 60 | * 61 | * @param conn The connection where the data or something meaningful 62 | * was detected. 63 | * 64 | * @param user_data Optional user data pointer passed in into the handler. 65 | * 66 | * @return The function returns a boolean value which is interpreted 67 | * in an especific form according to the event. 68 | */ 69 | typedef nopoll_bool (*noPollActionHandler) (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data); 70 | 71 | /** 72 | * @brief Handler used to define the create function for an IO mechanism. 73 | * 74 | * @param ctx The context where the io mechanism will be created. 75 | */ 76 | typedef noPollPtr (*noPollIoMechCreate) (noPollCtx * ctx); 77 | 78 | /** 79 | * @brief Handler used to define the IO wait set destroy function for 80 | * an IO mechanism. 81 | * 82 | * @param ctx The context where the io mechanism will be destroyed. 83 | * 84 | * @param io_object The io object to be destroyed as created by \ref 85 | * noPollIoMechCreate handler. 86 | */ 87 | typedef void (*noPollIoMechDestroy) (noPollCtx * ctx, noPollPtr io_object); 88 | 89 | /** 90 | * @brief Handler used to define the IO wait set clear function for an 91 | * IO mechanism. 92 | * 93 | * @param ctx The context where the io mechanism will be cleared. 94 | * 95 | * @param io_object The io object to be created as created by \ref 96 | * noPollIoMechCreate handler. 97 | */ 98 | typedef void (*noPollIoMechClear) (noPollCtx * ctx, noPollPtr io_object); 99 | 100 | 101 | /** 102 | * @brief Handler used to define the IO wait function for an IO 103 | * mechanism. 104 | * 105 | * @param ctx The context where the io mechanism was created. 106 | * 107 | * @param io_object The io object to be created as created by \ref 108 | * noPollIoMechCreate handler where the wait will be implemented. 109 | */ 110 | typedef int (*noPollIoMechWait) (noPollCtx * ctx, noPollPtr io_object); 111 | 112 | 113 | /** 114 | * @brief Handler used to define the IO add to set function for an IO 115 | * mechanism. 116 | * 117 | * @param ctx The context where the io mechanism was created. 118 | * 119 | * @param conn The noPollConn to be added to the working set. 120 | * 121 | * @param io_object The io object to be created as created by \ref 122 | * noPollIoMechCreate handler where the wait will be implemented. 123 | */ 124 | typedef nopoll_bool (*noPollIoMechAddTo) (int fds, 125 | noPollCtx * ctx, 126 | noPollConn * conn, 127 | noPollPtr io_object); 128 | 129 | 130 | /** 131 | * @brief Handler used to define the IO is set function for an IO 132 | * mechanism. 133 | * 134 | * @param ctx The context where the io mechanism was created. 135 | * 136 | * @param conn The noPollConn to be added to the working set. 137 | * 138 | * @param io_object The io object to be created as created by \ref 139 | * noPollIoMechCreate handler where the wait will be implemented. 140 | */ 141 | typedef nopoll_bool (*noPollIoMechIsSet) (noPollCtx * ctx, 142 | int fds, 143 | noPollPtr io_object); 144 | 145 | /** 146 | * @brief Handler used to define the foreach function that is used by 147 | * \ref nopoll_ctx_foreach_conn 148 | * 149 | * @param ctx The context where the foreach operation is taking place. 150 | * 151 | * @param conn The connection notified 152 | * 153 | * @param user_data Optional user defined pointer received at \ref 154 | * nopoll_ctx_foreach_conn. 155 | * 156 | * @return nopoll_true to stop the foreach process, otherwise 157 | * nopoll_false to keep checking the next connection until all 158 | * connections are notified. 159 | */ 160 | typedef nopoll_bool (*noPollForeachConn) (noPollCtx * ctx, 161 | noPollConn * conn, 162 | noPollPtr user_data); 163 | 164 | /** 165 | * @brief Handler definition used to describe read functions used by \ref noPollConn. 166 | * 167 | * @param conn The connection where the readOperation will take place. 168 | * 169 | * @param buffer The buffer where data read from socket will be placed. 170 | * 171 | * @param buffer_size The buffer size that is receiving the function. 172 | */ 173 | typedef int (*noPollRead) (noPollConn * conn, 174 | char * buffer, 175 | int buffer_size); 176 | 177 | /** 178 | * @brief Handler definition used to notify websocket messages 179 | * received. 180 | * 181 | * This handler will be called when a websocket message is 182 | * received. Keep in mind the reference received on this handler will 183 | * be finished when the handler ends. If you need to have a reference 184 | * to the message after handler execution, acquire a reference via 185 | * \ref nopoll_msg_ref. 186 | * 187 | * @param ctx The context where the messagewas received. 188 | * 189 | * @param conn The connection where the message was received. 190 | * 191 | * @param msg The websocket message was received. 192 | * 193 | * @param user_data An optional user defined pointer. 194 | */ 195 | typedef void (*noPollOnMessageHandler) (noPollCtx * ctx, 196 | noPollConn * conn, 197 | noPollMsg * msg, 198 | noPollPtr user_data); 199 | 200 | /** 201 | * @brief Handler definition used by \ref nopoll_conn_set_on_close. 202 | * 203 | * Handler definition for the function that is called when the 204 | * connection is closed but just before shutting down the socket 205 | * associated to the connection. 206 | * 207 | * @param ctx The context where the operation will take place. 208 | * 209 | * @param conn The connection where the operation will take place. 210 | * 211 | * @param user_data The reference that was configured to be passed in 212 | * into the handler. 213 | */ 214 | typedef void (*noPollOnCloseHandler) (noPollCtx * ctx, 215 | noPollConn * conn, 216 | noPollPtr user_data); 217 | 218 | /** 219 | * @brief Mutex creation handler used by the library. 220 | * 221 | * @return A reference to the mutex created (already initialized). 222 | */ 223 | typedef noPollPtr (*noPollMutexCreate) (void); 224 | 225 | /** 226 | * @brief Mutex destroy handler used by the library. 227 | * 228 | * @param The mutex to destroy. 229 | */ 230 | typedef void (*noPollMutexDestroy) (noPollPtr mutex); 231 | 232 | /** 233 | * @brief Mutex lock handler used by the library. 234 | * 235 | * @param The mutex where to implement the lock operation. 236 | */ 237 | typedef void (*noPollMutexLock) (noPollPtr mutex); 238 | 239 | /** 240 | * @brief Mutex unlock handler used by the library. 241 | * 242 | * @param The mutex where to implement the unlock operation. 243 | */ 244 | typedef void (*noPollMutexUnlock) (noPollPtr mutex); 245 | 246 | /** 247 | * @brief Handler used by nopoll_log_set_handler to receive all log 248 | * notifications produced by the library on this function. 249 | * 250 | * @param ctx The context where the operation is happening. 251 | * 252 | * @param level The log level 253 | * 254 | * @param log_msg The actual log message reported. 255 | * 256 | * @param user_data A reference to user defined pointer passed in into the function. 257 | */ 258 | typedef void (*noPollLogHandler) (noPollCtx * ctx, noPollDebugLevel level, const char * log_msg, noPollPtr user_data); 259 | 260 | /** 261 | * @brief An optional handler that allows user land code to define how 262 | * is SSL_CTX (SSL context) created and which are the settings it 263 | * should have before taking place SSL/TLS handshake. 264 | * 265 | * NOTE: that the function should return one context for every 266 | * connection created. Do not reuse unless you know what you are 267 | * doing. 268 | * 269 | * A very bare implementation for this context creation will be: 270 | * 271 | * \code 272 | * SSL_CTX * my_ssl_ctx_creator (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client, noPollPtr user_data) 273 | * { 274 | * // very basic context creation using default settings provided by OpenSSL 275 | * return SSL_CTX_new (is_client ? TLSv1_client_method () : TLSv1_server_method ()); 276 | * } 277 | * \endcode 278 | * 279 | * @param ctx The context where the operation is taking place. 280 | * 281 | * @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. 282 | * 283 | * @param opts Optional reference to the connection object created for this connection. 284 | * 285 | * @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. 286 | * 287 | * @param user_data User defined pointer that received on this function as defined at \ref nopoll_ctx_set_ssl_context_creator. 288 | * 289 | * @return The function must return a valid SSL_CTX object (see OpenSSL documentation to know more about this) or NULL if it fails. 290 | */ 291 | typedef noPollPtr (*noPollSslContextCreator) (noPollCtx * ctx, 292 | noPollConn * conn, 293 | noPollConnOpts * opts, 294 | nopoll_bool is_client, 295 | noPollPtr user_data); 296 | 297 | /** 298 | * @brief Optional user defined handler that allows to execute SSL 299 | * post checks code before proceed. 300 | * 301 | * This handler is configured at \ref nopoll_ctx_set_post_ssl_check 302 | * and allows to implement custom actions while additional 303 | * verifications about certificate received, validation based on 304 | * certain attributes, etc. 305 | * 306 | * Note that when this handler is called, the SSL handshake has 307 | * finished without error. In case of SSL handshake failure, this 308 | * handler is not executed. 309 | * 310 | * @param ctx The context where the operation happens. 311 | * 312 | * @param conn The connection where the operation takes place and for which the post SSL check is being done. 313 | * 314 | * @param SSL_CTX The OpenSSL SSL_CTX object created for this connection. 315 | * 316 | * @param SSL The OpenSSL SSL object created for this connection. 317 | * 318 | * @param user_data User defined data that is received on this handler as configured at \ref nopoll_ctx_set_post_ssl_check 319 | */ 320 | typedef nopoll_bool (*noPollSslPostCheck) (noPollCtx * ctx, 321 | noPollConn * conn, 322 | noPollPtr SSL_CTX, 323 | noPollPtr SSL, 324 | noPollPtr user_data); 325 | 326 | 327 | #endif 328 | 329 | /* @} */ 330 | -------------------------------------------------------------------------------- /nopoll/nopoll_io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | typedef struct _noPollSelect { 43 | noPollCtx * ctx; 44 | fd_set set; 45 | int length; 46 | int max_fds; 47 | } noPollSelect; 48 | 49 | /** 50 | * @internal nopoll implementation to create a compatible "select" IO 51 | * call fd set reference. 52 | * 53 | * @return A newly allocated fd_set reference. 54 | */ 55 | noPollPtr nopoll_io_wait_select_create (noPollCtx * ctx) 56 | { 57 | noPollSelect * select = nopoll_new (noPollSelect, 1); 58 | 59 | /* set default behaviour expected for the set */ 60 | select->ctx = ctx; 61 | 62 | /* clear the set */ 63 | FD_ZERO (&(select->set)); 64 | 65 | return select; 66 | } 67 | 68 | /** 69 | * @internal noPoll implementation to destroy the "select" IO call 70 | * created by the default create. 71 | * 72 | * @param fd_group The fd group to be deallocated. 73 | */ 74 | void nopoll_io_wait_select_destroy (noPollCtx * ctx, noPollPtr fd_group) 75 | { 76 | fd_set * __fd_set = (fd_set *) fd_group; 77 | 78 | /* release memory allocated */ 79 | nopoll_free (__fd_set); 80 | 81 | /* nothing more to do */ 82 | return; 83 | } 84 | 85 | /** 86 | * @internal noPoll implementation to clear the "select" IO call 87 | * created by the default create. 88 | * 89 | * @param fd_group The fd group to be deallocated. 90 | */ 91 | void nopoll_io_wait_select_clear (noPollCtx * ctx, noPollPtr __fd_group) 92 | { 93 | noPollSelect * select = (noPollSelect *) __fd_group; 94 | 95 | /* clear the fd set */ 96 | select->length = 0; 97 | FD_ZERO (&(select->set)); 98 | 99 | /* nothing more to do */ 100 | return; 101 | } 102 | 103 | /** 104 | * @internal Default internal implementation for the wait operation to 105 | * change its status at least one socket description inside the fd set 106 | * provided. 107 | * 108 | * @param __fd_group The fd set having all sockets to be watched. 109 | * @param wait_to The operation requested. 110 | * 111 | * @return Number of connections that changed or -1 if something wailed 112 | */ 113 | int nopoll_io_wait_select_wait (noPollCtx * ctx, noPollPtr __fd_group) 114 | { 115 | int result = -1; 116 | struct timeval tv; 117 | noPollSelect * _select = (noPollSelect *) __fd_group; 118 | 119 | /* init wait */ 120 | tv.tv_sec = 0; 121 | tv.tv_usec = 500000; 122 | result = select (_select->max_fds + 1, &(_select->set), NULL, NULL, &tv); 123 | 124 | /* check result */ 125 | if ((result == NOPOLL_SOCKET_ERROR) && (errno == NOPOLL_EINTR)) 126 | return -1; 127 | 128 | return result; 129 | } 130 | 131 | /** 132 | * @internal noPoll select implementation for the "add to" on fd set 133 | * operation. 134 | * 135 | * @param fds The socket descriptor to be added. 136 | * 137 | * @param fd_set The fd set where the socket descriptor will be added. 138 | */ 139 | nopoll_bool nopoll_io_wait_select_add_to (int fds, 140 | noPollCtx * ctx, 141 | noPollConn * conn, 142 | noPollPtr __fd_set) 143 | { 144 | noPollSelect * select = (noPollSelect *) __fd_set; 145 | 146 | if (fds < 0) { 147 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 148 | "received a non valid socket (%d), unable to add to the set", fds); 149 | return nopoll_false; 150 | } 151 | 152 | /* set the value */ 153 | FD_SET (fds, &(select->set)); 154 | 155 | /* update length */ 156 | select->length++; 157 | 158 | /* update max fds */ 159 | if (fds > select->max_fds) 160 | select->max_fds = fds; 161 | 162 | return nopoll_true; 163 | } 164 | 165 | /** 166 | * @internal 167 | * 168 | * @brief Default noPoll implementation for the "is set" on fd 169 | * set operation. 170 | * 171 | * @param fds The socket descriptor to be checked to be active on the 172 | * given fd group. 173 | * 174 | * @param fd_set The fd set where the socket descriptor will be checked. 175 | */ 176 | nopoll_bool nopoll_io_wait_select_is_set (noPollCtx * ctx, 177 | int fds, 178 | noPollPtr __fd_set) 179 | { 180 | noPollSelect * select = (noPollSelect *) __fd_set; 181 | 182 | return FD_ISSET (fds, &(select->set)); 183 | } 184 | 185 | 186 | /** 187 | * @brief Creates an object that represents the best IO wait mechanism 188 | * found on the current system. 189 | * 190 | * @param ctx The context where the engine will be created/associated. 191 | * 192 | * @param engine Use \ref NOPOLL_IO_ENGINE_DEFAULT or the engine you 193 | * want to use. 194 | * 195 | * @return The selected IO wait mechanism or NULL if it fails. 196 | */ 197 | noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type) 198 | { 199 | noPollIoEngine * engine = nopoll_new (noPollIoEngine, 1); 200 | if (engine == NULL) 201 | return NULL; 202 | 203 | /* configure default implementation */ 204 | engine->create = nopoll_io_wait_select_create; 205 | engine->destroy = nopoll_io_wait_select_destroy; 206 | engine->clear = nopoll_io_wait_select_clear; 207 | engine->wait = nopoll_io_wait_select_wait; 208 | engine->addto = nopoll_io_wait_select_add_to; 209 | engine->isset = nopoll_io_wait_select_is_set; 210 | 211 | /* call to create the object */ 212 | engine->ctx = ctx; 213 | engine->io_object = engine->create (ctx); 214 | 215 | /* return the engine that was created */ 216 | return engine; 217 | } 218 | 219 | /** 220 | * @brief Release the io engine created by \ref nopoll_io_get_engine. 221 | * 222 | * @param engine The engine to be released. 223 | */ 224 | void nopoll_io_release_engine (noPollIoEngine * engine) 225 | { 226 | if (engine == NULL) 227 | return; 228 | engine->destroy (engine->ctx, engine->io_object); 229 | nopoll_free (engine); 230 | return; 231 | } 232 | 233 | 234 | -------------------------------------------------------------------------------- /nopoll/nopoll_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_IO_H__ 40 | #define __NOPOLL_IO_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | noPollIoEngine * nopoll_io_get_engine (noPollCtx * ctx, noPollIoEngineType engine_type); 47 | 48 | void nopoll_io_release_engine (noPollIoEngine * engine); 49 | 50 | END_C_DECLS 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /nopoll/nopoll_listener.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | /** 45 | * \defgroup nopoll_listener noPoll Listener: functions required to create WebSocket listener connections. 46 | */ 47 | 48 | /** 49 | * \addtogroup nopoll_listener 50 | * @{ 51 | */ 52 | 53 | /* 54 | * @internal Implementation used by all sock listener functions. 55 | */ 56 | NOPOLL_SOCKET __nopoll_listener_sock_listen_internal (noPollCtx * ctx, 57 | noPollTransport transport, 58 | const char * host, 59 | const char * port) 60 | { 61 | struct hostent * he; 62 | struct in_addr * haddr; 63 | struct sockaddr_in saddr; 64 | struct sockaddr_in sin; 65 | NOPOLL_SOCKET fd; 66 | int tries; 67 | 68 | #if defined(NOPOLL_OS_WIN32) 69 | int sin_size = sizeof (sin); 70 | #else 71 | int unit = 1; 72 | socklen_t sin_size = sizeof (sin); 73 | #endif 74 | uint16_t int_port; 75 | int bind_res; 76 | 77 | nopoll_return_val_if_fail (ctx, ctx, -2); 78 | nopoll_return_val_if_fail (ctx, host, -2); 79 | nopoll_return_val_if_fail (ctx, port || strlen (port) == 0, -2); 80 | 81 | /* resolve hostname */ 82 | switch (transport) { 83 | case NOPOLL_TRANSPORT_IPV4: 84 | he = gethostbyname (host); 85 | if (he == NULL) { 86 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get hostname by calling gethostbyname"); 87 | return -1; 88 | } /* end if */ 89 | 90 | haddr = ((struct in_addr *) (he->h_addr_list)[0]); 91 | break; 92 | #if NOPLL_IPV6 93 | case NOPOLL_TRANSPORT_IPV6: 94 | /* configure hints */ 95 | hints.ai_family = AF_INET6; 96 | hints.ai_socktype = SOCK_STREAM; 97 | hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 98 | 99 | /* check value received */ 100 | if (memcmp (host, "0.0.0.0", 7) == 0) { 101 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received an address (%s) that is not a valid IPv6 address..", host); 102 | return -1; 103 | } /* end if */ 104 | 105 | /* resolve hosting name */ 106 | if (getaddrinfo (host, port, &hints, &res) != 0) { 107 | nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "unable to resolve host name %s, errno=%d", host, errno); 108 | return -1; 109 | } /* end if */ 110 | break; 111 | #endif 112 | } /* end switch */ 113 | 114 | /* get integer port */ 115 | int_port = (uint16_t) atoi (port); 116 | 117 | memset(&saddr, 0, sizeof(struct sockaddr_in)); 118 | saddr.sin_family = AF_INET; 119 | saddr.sin_port = htons(int_port); 120 | memcpy(&saddr.sin_addr, haddr, sizeof(struct in_addr)); 121 | 122 | /* create socket */ 123 | fd = socket (AF_INET, SOCK_STREAM, 0); 124 | if (fd <= 2) { 125 | /* do not allow creating sockets reusing stdin (0), 126 | stdout (1), stderr (2) */ 127 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "failed to create listener socket: %d (errno=%d)", fd, errno); 128 | return -1; 129 | } /* end if */ 130 | 131 | #if defined(NOPOLL_OS_WIN32) 132 | /* Do not issue a reuse addr which causes on windows to reuse 133 | * the same address:port for the same process. Under linux, 134 | * reusing the address means that consecutive process can 135 | * reuse the address without being blocked by a wait 136 | * state. */ 137 | /* setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&unit, sizeof(BOOL)); */ 138 | #else 139 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &unit, sizeof (unit)); 140 | #endif 141 | 142 | 143 | /* call to bind */ 144 | tries = 0; 145 | while (1) { 146 | /* call bind */ 147 | bind_res = bind(fd, (struct sockaddr *)&saddr, sizeof (struct sockaddr_in)); 148 | if (bind_res == NOPOLL_SOCKET_ERROR) { 149 | /* check if we can retry */ 150 | tries++; 151 | if (tries < 25) { 152 | nopoll_log (ctx, NOPOLL_LEVEL_WARNING, 153 | "unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s), retrying=%d on socket: %d", 154 | int_port, errno, strerror (errno), tries, fd); 155 | nopoll_sleep (100000); 156 | continue; 157 | } /* end if */ 158 | 159 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, 160 | "unable to bind address (port:%u already in use or insufficient permissions, errno=%d : %s). Closing socket: %d", 161 | int_port, errno, strerror (errno), fd); 162 | nopoll_close_socket (fd); 163 | return -1; 164 | } /* end if */ 165 | 166 | /* reached this point, bind was ok */ 167 | break; 168 | } /* end while */ 169 | 170 | if (listen(fd, ctx->backlog) == NOPOLL_SOCKET_ERROR) { 171 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "an error have occur while executing listen"); 172 | return -1; 173 | } /* end if */ 174 | 175 | /* notify listener */ 176 | if (getsockname (fd, (struct sockaddr *) &sin, &sin_size) < -1) { 177 | return -1; 178 | } /* end if */ 179 | 180 | /* report and return fd */ 181 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "running listener at %s:%d (socket: %d)", inet_ntoa(sin.sin_addr), ntohs (sin.sin_port), fd); 182 | return fd; 183 | } 184 | 185 | /** 186 | * @internal Function to create a WebSocket listener 187 | */ 188 | noPollConn * __nopoll_listener_new_opts_internal (noPollCtx * ctx, 189 | noPollTransport transport, 190 | noPollConnOpts * opts, 191 | const char * host, 192 | const char * port) 193 | { 194 | NOPOLL_SOCKET session; 195 | noPollConn * listener; 196 | 197 | nopoll_return_val_if_fail (ctx, ctx && host, NULL); 198 | 199 | /* call to create the socket */ 200 | session = __nopoll_listener_sock_listen_internal (ctx, transport, host, port); 201 | if (session == NOPOLL_INVALID_SOCKET) { 202 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to start listener error was: errno=%d", errno); 203 | return NULL; 204 | } /* end if */ 205 | 206 | /* create noPollConn ection object */ 207 | listener = nopoll_new (noPollConn, 1); 208 | listener->refs = 1; 209 | /* create mutex */ 210 | listener->ref_mutex = nopoll_mutex_create (); 211 | listener->session = session; 212 | listener->ctx = ctx; 213 | listener->role = NOPOLL_ROLE_MAIN_LISTENER; 214 | 215 | /* record host and port */ 216 | listener->host = nopoll_strdup (host); 217 | listener->port = nopoll_strdup (port); 218 | 219 | /* register connection into context */ 220 | nopoll_ctx_register_conn (ctx, listener); 221 | 222 | /* configure default handlers */ 223 | listener->receive = nopoll_conn_default_receive; 224 | listener->send = nopoll_conn_default_send; 225 | 226 | /* configure connection options */ 227 | listener->opts = opts; 228 | 229 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d, transport: %s)", 230 | listener->host, listener->port, listener->session, (transport == NOPOLL_TRANSPORT_IPV4 ? "IPv4" : "IPv6")); 231 | 232 | return listener; 233 | } 234 | 235 | 236 | /** 237 | * @internal Creates a listener socket on the provided port. 238 | */ 239 | NOPOLL_SOCKET nopoll_listener_sock_listen (noPollCtx * ctx, 240 | const char * host, 241 | const char * port) 242 | { 243 | return __nopoll_listener_sock_listen_internal (ctx, NOPOLL_TRANSPORT_IPV4, host, port); 244 | } 245 | 246 | /** 247 | * @brief Creates a new websocket server listener on the provided host 248 | * name and port (IPv4) 249 | * 250 | * @param ctx The context where the operation will take place. 251 | * 252 | * @param host The hostname or address interface to bind on. 253 | * 254 | * @param port The port where to listen, or NULL to use default port: 80. 255 | * 256 | * @return A reference to a \ref noPollConn object representing the 257 | * listener or NULL if it fails. 258 | */ 259 | noPollConn * nopoll_listener_new (noPollCtx * ctx, 260 | const char * host, 261 | const char * port) 262 | { 263 | return nopoll_listener_new_opts (ctx, NULL, host, port); 264 | } 265 | 266 | #if NOPLL_IPV6 267 | /** 268 | * @brief Creates a new websocket server listener on the provided host 269 | * name and port (IPv6). 270 | * 271 | * See \ref nopoll_listener_new for more information. 272 | * 273 | * @param ctx See \ref nopoll_listener_new for more information. 274 | * 275 | * @param host See \ref nopoll_listener_new for more information. 276 | * 277 | * @param port See \ref nopoll_listener_new for more information. 278 | * 279 | * @return See \ref nopoll_listener_new for more information. 280 | */ 281 | noPollConn * nopoll_listener_new6 (noPollCtx * ctx, 282 | const char * host, 283 | const char * port) 284 | { 285 | return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, NULL, host, port); 286 | } 287 | #endif 288 | 289 | /** 290 | * @brief Creates a new websocket server listener on the provided host 291 | * name and port (IPv4). 292 | * 293 | * @param ctx The context where the operation will take place. 294 | * 295 | * @param opts Optional connection options to configure this listener. 296 | * 297 | * @param host The hostname or address interface to bind on. 298 | * 299 | * @param port The port where to listen, or NULL to use default port: 80. 300 | * 301 | * @return A reference to a \ref noPollConn object representing the 302 | * listener or NULL if it fails. 303 | */ 304 | noPollConn * nopoll_listener_new_opts (noPollCtx * ctx, 305 | noPollConnOpts * opts, 306 | const char * host, 307 | const char * port) 308 | { 309 | /* call common implementation */ 310 | return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV4, opts, host, port); 311 | } 312 | 313 | #if NOPLL_IPV6 314 | /** 315 | * @brief Creates a new websocket server listener on the provided host 316 | * name and port (IPv6). 317 | * 318 | * See \ref nopoll_listener_new_opts for more information. 319 | * 320 | * @param ctx See \ref nopoll_listener_new_opts 321 | * 322 | * @param opts See \ref nopoll_listener_new_opts 323 | * 324 | * @param host See \ref nopoll_listener_new_opts 325 | * 326 | * @param port See \ref nopoll_listener_new_opts 327 | * 328 | * @return See \ref nopoll_listener_new_opts 329 | */ 330 | noPollConn * nopoll_listener_new_opts6 (noPollCtx * ctx, 331 | noPollConnOpts * opts, 332 | const char * host, 333 | const char * port) 334 | { 335 | /* call common implementation */ 336 | return __nopoll_listener_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, opts, host, port); 337 | } 338 | #endif 339 | 340 | /** 341 | * @brief Allows to create a new WebSocket listener but expecting the 342 | * incoming connection to be under TLS supervision. The function works 343 | * like \ref nopoll_listener_new (providing wss:// services) (IPv4 version). 344 | * 345 | * @param ctx The context where the operation will take place. 346 | * 347 | * @param host The hostname or address interface to bind on. 348 | * 349 | * @param port The port where to listen, or NULL to use default port: 80. 350 | * 351 | * @return A reference to a \ref noPollConn object representing the 352 | * listener or NULL if it fails. 353 | */ 354 | noPollConn * nopoll_listener_tls_new (noPollCtx * ctx, 355 | const char * host, 356 | const char * port) 357 | { 358 | return nopoll_listener_tls_new_opts (ctx, NULL, host, port); 359 | } 360 | 361 | #if NOPLL_IPV6 362 | /** 363 | * @brief Allows to create a new WebSocket listener but expecting the 364 | * incoming connection to be under TLS supervision. The function works 365 | * like \ref nopoll_listener_new (providing wss:// services) (IPv6 version). 366 | * 367 | * See \ref nopoll_listener_tls_new for more information. 368 | * 369 | * @param ctx See \ref nopoll_listener_tls_new for more information. 370 | * 371 | * @param host See \ref nopoll_listener_tls_new for more information. 372 | * 373 | * @param port See \ref nopoll_listener_tls_new for more information. 374 | * 375 | * @return See \ref nopoll_listener_tls_new for more information. 376 | */ 377 | noPollConn * nopoll_listener_tls_new6 (noPollCtx * ctx, 378 | const char * host, 379 | const char * port) 380 | { 381 | return nopoll_listener_tls_new_opts6 (ctx, NULL, host, port); 382 | } 383 | #endif 384 | 385 | /** 386 | * @internal Common implementation 387 | */ 388 | noPollConn * __nopoll_listener_tls_new_opts_internal (noPollCtx * ctx, 389 | noPollTransport transport, 390 | noPollConnOpts * opts, 391 | const char * host, 392 | const char * port) 393 | { 394 | noPollConn * listener; 395 | 396 | /* call to get listener from base function */ 397 | listener = __nopoll_listener_new_opts_internal (ctx, transport, opts, host, port); 398 | if (! listener) 399 | return listener; 400 | 401 | /* setup TLS support */ 402 | listener->tls_on = nopoll_true; 403 | listener->opts = opts; 404 | 405 | return listener; 406 | } 407 | 408 | /** 409 | * @brief Allows to create a new WebSocket listener but expecting the 410 | * incoming connection to be under TLS supervision. The function works 411 | * like \ref nopoll_listener_new (providing wss:// services) (IPv4 version). 412 | * 413 | * @param ctx The context where the operation will take place. 414 | * 415 | * @param opts The connection options to configure this particular 416 | * listener. 417 | * 418 | * @param host The hostname or address interface to bind on. 419 | * 420 | * @param port The port where to listen, or NULL to use default port: 80. 421 | * 422 | * @return A reference to a \ref noPollConn object representing the 423 | * listener or NULL if it fails. 424 | */ 425 | noPollConn * nopoll_listener_tls_new_opts (noPollCtx * ctx, 426 | noPollConnOpts * opts, 427 | const char * host, 428 | const char * port) 429 | { 430 | return __nopoll_listener_tls_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV4, opts, host, port); 431 | } 432 | 433 | #if NOPLL_IPV6 434 | /** 435 | * @brief Allows to create a new WebSocket listener but expecting the 436 | * incoming connection to be under TLS supervision. The function works 437 | * like \ref nopoll_listener_new (providing wss:// services) (IPv6 version). 438 | * 439 | * See \ref nopoll_listener_tls_new_opts for more information. 440 | * 441 | * @param ctx See \ref nopoll_listener_tls_new_opts for more information. 442 | * 443 | * @param opts See \ref nopoll_listener_tls_new_opts for more information. 444 | * 445 | * @param host See \ref nopoll_listener_tls_new_opts for more information. 446 | * 447 | * @param port See \ref nopoll_listener_tls_new_opts for more information. 448 | * 449 | * @return See \ref nopoll_listener_tls_new_opts for more information. 450 | */ 451 | noPollConn * nopoll_listener_tls_new_opts6 (noPollCtx * ctx, 452 | noPollConnOpts * opts, 453 | const char * host, 454 | const char * port) 455 | { 456 | return __nopoll_listener_tls_new_opts_internal (ctx, NOPOLL_TRANSPORT_IPV6, opts, host, port); 457 | } 458 | #endif 459 | 460 | /** 461 | * @brief Allows to configure the TLS certificate and key to be used 462 | * on the provided connection. 463 | * 464 | * @param listener The listener that is going to be configured with the providing certificate and key. 465 | * 466 | * @param certificate The path to the public certificate file (PEM 467 | * format) to be used for every TLS connection received under the 468 | * provided listener. 469 | * 470 | * @param private_key The path to the key file (PEM format) to be used for 471 | * every TLS connection received under the provided listener. 472 | * 473 | * @param chain_file The path to additional chain certificates (PEM 474 | * format). You can safely pass here a NULL value. 475 | * 476 | * @return nopoll_true if the certificates were configured, otherwise 477 | * nopoll_false is returned. 478 | */ 479 | nopoll_bool nopoll_listener_set_certificate (noPollConn * listener, 480 | const char * certificate, 481 | const char * private_key, 482 | const char * chain_file) 483 | { 484 | FILE * handle; 485 | 486 | if (! listener || ! certificate || ! private_key) 487 | return nopoll_false; 488 | 489 | /* check certificate file */ 490 | handle = fopen (certificate, "r"); 491 | if (! handle) { 492 | nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open certificate file from %s", certificate); 493 | return nopoll_false; 494 | } /* end if */ 495 | fclose (handle); 496 | 497 | /* check private file */ 498 | handle = fopen (private_key, "r"); 499 | if (! handle) { 500 | nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open private key file from %s", private_key); 501 | return nopoll_false; 502 | } /* end if */ 503 | fclose (handle); 504 | 505 | if (chain_file) { 506 | /* check private file */ 507 | handle = fopen (chain_file, "r"); 508 | if (! handle) { 509 | nopoll_log (listener->ctx, NOPOLL_LEVEL_CRITICAL, "Failed to open chain certificate file from %s", private_key); 510 | return nopoll_false; 511 | } /* end if */ 512 | fclose (handle); 513 | } /* end if */ 514 | 515 | #if NOPOLL_TLS 516 | /* copy certificates to be used */ 517 | listener->certificate = nopoll_strdup (certificate); 518 | listener->private_key = nopoll_strdup (private_key); 519 | if (chain_file) 520 | listener->chain_certificate = nopoll_strdup (chain_file); 521 | 522 | nopoll_log (listener->ctx, NOPOLL_LEVEL_DEBUG, "Configured certificate: %s, key: %s, for conn id: %d", 523 | listener->certificate, listener->private_key, listener->id); 524 | #endif 525 | 526 | /* certificates configured */ 527 | return nopoll_true; 528 | } 529 | 530 | /** 531 | * @brief Creates a websocket listener from the socket provided. 532 | * 533 | * @param ctx The context where the listener will be associated. 534 | * 535 | * @param session The session to associate to the listener. 536 | * 537 | * @return A reference to a listener connection object or NULL if it 538 | * fails. 539 | */ 540 | noPollConn * nopoll_listener_from_socket (noPollCtx * ctx, 541 | NOPOLL_SOCKET session) 542 | { 543 | noPollConn * listener; 544 | struct sockaddr_in sin; 545 | #if defined(NOPOLL_OS_WIN32) 546 | /* windows flavors */ 547 | int sin_size = sizeof (sin); 548 | #else 549 | /* unix flavors */ 550 | socklen_t sin_size = sizeof (sin); 551 | #endif 552 | 553 | nopoll_return_val_if_fail (ctx, ctx && session > 0, NULL); 554 | 555 | /* create noPollConn ection object */ 556 | listener = nopoll_new (noPollConn, 1); 557 | listener->refs = 1; 558 | /* create mutex */ 559 | listener->ref_mutex = nopoll_mutex_create (); 560 | listener->session = session; 561 | listener->ctx = ctx; 562 | listener->role = NOPOLL_ROLE_LISTENER; 563 | 564 | /* get peer value */ 565 | memset (&sin, 0, sizeof (struct sockaddr_in)); 566 | if (getpeername (session, (struct sockaddr *) &sin, &sin_size) < -1) { 567 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to get remote hostname and port"); 568 | return NULL; 569 | } /* end if */ 570 | 571 | /* record host and port */ 572 | /* lock mutex here to protect inet_ntoa */ 573 | listener->host = nopoll_strdup (inet_ntoa (sin.sin_addr)); 574 | /* release mutex here to protect inet_ntoa */ 575 | listener->port = nopoll_strdup_printf ("%d", ntohs (sin.sin_port)); 576 | 577 | /* configure default handlers */ 578 | listener->receive = nopoll_conn_default_receive; 579 | listener->send = nopoll_conn_default_send; 580 | 581 | /* register connection into context */ 582 | if (! nopoll_ctx_register_conn (ctx, listener)) { 583 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to register connection into the context, unable to create connection"); 584 | nopoll_conn_ref (listener); 585 | return NULL; 586 | } /* end if */ 587 | 588 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Listener created, started: %s:%s (socket: %d)", listener->host, listener->port, listener->session); 589 | 590 | /* reduce reference counting here because ctx_register_conn 591 | * already acquired a reference */ 592 | nopoll_conn_unref (listener); 593 | 594 | return listener; 595 | } 596 | 597 | /** 598 | * @internal Public function that performs a TCP listener accept. 599 | * 600 | * @param server_socket The listener socket where the accept() 601 | * operation will be called. 602 | * 603 | * @return Returns a connected socket descriptor or -1 if it fails. 604 | */ 605 | NOPOLL_SOCKET nopoll_listener_accept (NOPOLL_SOCKET server_socket) 606 | { 607 | struct sockaddr_in inet_addr; 608 | #if defined(NOPOLL_OS_WIN32) 609 | int addrlen; 610 | #else 611 | socklen_t addrlen; 612 | #endif 613 | addrlen = sizeof(struct sockaddr_in); 614 | 615 | /* accept the connection new connection */ 616 | return accept (server_socket, (struct sockaddr *)&inet_addr, &addrlen); 617 | } 618 | 619 | /* @} */ 620 | -------------------------------------------------------------------------------- /nopoll/nopoll_listener.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_LISTENER_H__ 40 | #define __NOPOLL_LISTENER_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | NOPOLL_SOCKET nopoll_listener_sock_listen (noPollCtx * ctx, 47 | const char * host, 48 | const char * port); 49 | 50 | noPollConn * nopoll_listener_new (noPollCtx * ctx, 51 | const char * host, 52 | const char * port); 53 | 54 | noPollConn * nopoll_listener_new6 (noPollCtx * ctx, 55 | const char * host, 56 | const char * port); 57 | 58 | noPollConn * nopoll_listener_new_opts (noPollCtx * ctx, 59 | noPollConnOpts * opts, 60 | const char * host, 61 | const char * port); 62 | 63 | noPollConn * nopoll_listener_new_opts6 (noPollCtx * ctx, 64 | noPollConnOpts * opts, 65 | const char * host, 66 | const char * port); 67 | 68 | noPollConn * nopoll_listener_tls_new (noPollCtx * ctx, 69 | const char * host, 70 | const char * port); 71 | 72 | noPollConn * nopoll_listener_tls_new6 (noPollCtx * ctx, 73 | const char * host, 74 | const char * port); 75 | 76 | noPollConn * nopoll_listener_tls_new_opts (noPollCtx * ctx, 77 | noPollConnOpts * opts, 78 | const char * host, 79 | const char * port); 80 | 81 | noPollConn * nopoll_listener_tls_new_opts6 (noPollCtx * ctx, 82 | noPollConnOpts * opts, 83 | const char * host, 84 | const char * port); 85 | 86 | nopoll_bool nopoll_listener_set_certificate (noPollConn * listener, 87 | const char * certificate, 88 | const char * private_key, 89 | const char * chain_file); 90 | 91 | noPollConn * nopoll_listener_from_socket (noPollCtx * ctx, 92 | NOPOLL_SOCKET session); 93 | 94 | NOPOLL_SOCKET nopoll_listener_accept (NOPOLL_SOCKET server_socket); 95 | 96 | END_C_DECLS 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /nopoll/nopoll_log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | /** 43 | * \defgroup nopoll_log noPoll Log: Console log reporting for noPoll library 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_log 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @brief Allows to check if the log reporting inside the system is 53 | * enabled. 54 | * 55 | * @return nopoll_true if the log is enabled or nopoll_false 56 | */ 57 | nopoll_bool nopoll_log_is_enabled (noPollCtx * ctx) 58 | { 59 | if (ctx == NULL) 60 | return nopoll_false; 61 | 62 | /* return current value */ 63 | return ctx->debug_enabled; 64 | } 65 | 66 | /** 67 | * 68 | * @brief Allows to get current log configuration, to use colors. 69 | * 70 | * @return nopoll_true if the color log is enabled or nopoll_false 71 | */ 72 | nopoll_bool nopoll_log_color_is_enabled (noPollCtx * ctx) 73 | { 74 | 75 | if (ctx == NULL) 76 | return nopoll_false; 77 | 78 | /* return current value */ 79 | return ctx->debug_color_enabled; 80 | } 81 | 82 | /** 83 | * @brief Allows to control how to activate the log reporting to the 84 | * console from the nopoll core library. 85 | * 86 | * @param ctx The context where the operation will take place. 87 | * 88 | * @param value nopoll_true to enable log to console, otherwise nopoll_false is 89 | * returned. 90 | */ 91 | void nopoll_log_enable (noPollCtx * ctx, nopoll_bool value) 92 | { 93 | if (ctx == NULL) 94 | return; 95 | 96 | /* activate debuging according to the variable */ 97 | ctx->debug_enabled = value; 98 | return; 99 | } 100 | 101 | /** 102 | * @brief Allows to control how to activate the colog log reporting to 103 | * the console from the nopoll core library. 104 | * 105 | * @param ctx The context where the operation will take place. 106 | * 107 | * @param value nopoll_true to enable log to console, otherwise nopoll_false is 108 | * returned. 109 | */ 110 | void nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value) 111 | { 112 | if (ctx == NULL) 113 | return; 114 | 115 | /* activate color debuging according to the variable */ 116 | ctx->debug_color_enabled = value; 117 | return; 118 | } 119 | 120 | /** 121 | * @brief Allows to define a log handler that will receive all logs 122 | * produced under the provided content. 123 | * 124 | * @param ctx The context that is going to be configured. 125 | * 126 | * @param handler The handler to be called for each log to be 127 | * notified. Passing in NULL is allowed to remove any previously 128 | * configured handler. 129 | * 130 | * @param user_data User defined pointer to be passed in into the 131 | * handler configured along with the log notified. 132 | */ 133 | void nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data) 134 | { 135 | nopoll_return_if_fail (ctx, ctx); 136 | 137 | ctx->log_handler = handler; 138 | ctx->log_user_data = user_data; 139 | 140 | return; 141 | } 142 | 143 | /** 144 | * @internal Allows to drop a log to the console. 145 | * 146 | * This function allow to drop a log to the console using the given 147 | * domain, as an identification of which subsystem have reported the 148 | * information, and report level. This report level is used to notify 149 | * the consideration of the log reported. 150 | * 151 | * The function allows to provide a printf like interface to report 152 | * messages. Here are some examples: 153 | * 154 | * \code 155 | * // drop a log about current library initialization 156 | * nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "library properly initialized status=%d", status); 157 | * \endcode 158 | * 159 | * 160 | * @param ctx The context where the operation will take place. 161 | * 162 | * @param level The level that this message is classificed. 163 | * 164 | * @param message The message to report. The message to report must be 165 | * not NULL. 166 | */ 167 | void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...) 168 | { 169 | 170 | #ifdef SHOW_DEBUG_LOG 171 | va_list args; 172 | char * log_msg; 173 | char * log_msg2; 174 | 175 | if (ctx && ctx->log_handler) { 176 | /* print the message */ 177 | va_start (args, message); 178 | log_msg = nopoll_strdup_printfv (message, args); 179 | va_end (args); 180 | 181 | log_msg2 = log_msg; 182 | log_msg = nopoll_strdup_printf ("%s:%d %s ", file, line, log_msg); 183 | nopoll_free (log_msg2); 184 | 185 | ctx->log_handler (ctx, level, log_msg, ctx->log_user_data); 186 | nopoll_free (log_msg); 187 | return; 188 | } 189 | 190 | /* check if the log is enabled */ 191 | if (! nopoll_log_is_enabled (ctx)) 192 | return; 193 | 194 | /* printout the process pid */ 195 | //if (nopoll_log_color_is_enabled (ctx)) 196 | // printf ("\e[1;36m(proc %d)\e[0m: ", getpid ()); 197 | //else 198 | // printf ("(proc %d): ", getpid ()); 199 | 200 | /* drop a log according to the level */ 201 | if (nopoll_log_color_is_enabled (ctx)) { 202 | switch (level) { 203 | case NOPOLL_LEVEL_DEBUG: 204 | printf ("(\e[1;32mdebug\e[0m) "); 205 | break; 206 | case NOPOLL_LEVEL_WARNING: 207 | printf ("(\e[1;33mwarning\e[0m) "); 208 | break; 209 | case NOPOLL_LEVEL_CRITICAL: 210 | printf ("(\e[1;31mcritical\e[0m) "); 211 | break; 212 | } 213 | } else { 214 | switch (level) { 215 | case NOPOLL_LEVEL_DEBUG: 216 | printf ("(debug)"); 217 | break; 218 | case NOPOLL_LEVEL_WARNING: 219 | printf ("(warning)"); 220 | break; 221 | case NOPOLL_LEVEL_CRITICAL: 222 | printf ("(critical) "); 223 | break; 224 | } 225 | } 226 | 227 | /* drop a log according to the domain */ 228 | printf ("%s:%d ", file, line); 229 | 230 | /* print the message */ 231 | va_start (args, message); 232 | vprintf (message, args); 233 | va_end (args); 234 | 235 | printf ("\n"); 236 | 237 | /* ensure that the log is droped to the console */ 238 | fflush (stdout); 239 | #endif 240 | 241 | /* return */ 242 | return; 243 | } 244 | 245 | /* @} */ 246 | -------------------------------------------------------------------------------- /nopoll/nopoll_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_LOG_H__ 40 | #define __NOPOLL_LOG_H__ 41 | 42 | #include 43 | #include 44 | 45 | BEGIN_C_DECLS 46 | 47 | /** 48 | * \addtogroup nopoll_log_module 49 | * @{ 50 | */ 51 | 52 | nopoll_bool nopoll_log_is_enabled (noPollCtx * ctx); 53 | 54 | nopoll_bool nopoll_log_color_is_enabled (noPollCtx * ctx); 55 | 56 | void nopoll_log_enable (noPollCtx * ctx, nopoll_bool value); 57 | 58 | void nopoll_log_color_enable (noPollCtx * ctx, nopoll_bool value); 59 | 60 | void nopoll_log_set_handler (noPollCtx * ctx, noPollLogHandler handler, noPollPtr user_data); 61 | 62 | /* include this at this place to load GNU extensions */ 63 | #if defined(__GNUC__) 64 | # ifndef _GNU_SOURCE 65 | # define _GNU_SOURCE 66 | # endif 67 | # define __function_name__ __PRETTY_FUNCTION__ 68 | # define __line__ __LINE__ 69 | # define __file__ __FILE__ 70 | #elif defined(_MSC_VER) 71 | # define __function_name__ __FUNCDNAME__ 72 | # define __line__ __LINE__ 73 | # define __file__ __FILE__ 74 | #else 75 | /* unknown compiler */ 76 | #define __function_name__ "" 77 | #define __line__ 0 78 | #define __file__ "" 79 | #endif 80 | 81 | 82 | #if defined(SHOW_DEBUG_LOG) 83 | # define nopoll_log(ctx,level,message, ...) do{__nopoll_log(ctx, __function_name__, __file__, __line__, level, message, ##__VA_ARGS__);}while(0) 84 | #else 85 | # if defined(NOPOLL_OS_WIN32) && !( defined (__GNUC__) || _MSC_VER >= 1400) 86 | /* default case where '...' is not supported but log is still 87 | * disabled */ 88 | # define nopoll_log __nopoll_log 89 | # else 90 | # define nopoll_log(ctx, level, message, ...) /* nothing */ 91 | # endif 92 | #endif 93 | 94 | /** 95 | * @internal The following definition allows to find printf like wrong 96 | * argument passing to nopoll_log function. To activate the depuration 97 | * just add the following to local nopoll_config.h file: 98 | * 99 | * #define SHOW_FORMAT_BUGS (1) 100 | */ 101 | #if defined(SHOW_FORMAT_BUGS) 102 | # undef nopoll_log 103 | # define nopoll_log(ctx,level,message, ...) do{printf (message, ##__VA_ARGS__);}while(0) 104 | #endif 105 | 106 | void __nopoll_log (noPollCtx * ctx, const char * function_name, const char * file, int line, noPollDebugLevel level, const char * message, ...); 107 | 108 | /* @} */ 109 | 110 | END_C_DECLS 111 | 112 | #endif 113 | 114 | -------------------------------------------------------------------------------- /nopoll/nopoll_loop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | /** 43 | * \defgroup nopoll_loop noPoll Loop: basic support to create a watching loop for WebSocket listeners 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_loop 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @internal Function used by nopoll_loop_wait to register all 53 | * connections into the io waiting object. 54 | */ 55 | nopoll_bool nopoll_loop_register (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) 56 | { 57 | /* do not add connections that aren't working */ 58 | if (! nopoll_conn_is_ok (conn)) { 59 | 60 | /* remove this connection from registry */ 61 | nopoll_ctx_unregister_conn (ctx, conn); 62 | 63 | return nopoll_false; /* keep foreach, don't stop */ 64 | } 65 | 66 | /* register the connection socket */ 67 | /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding socket id: %d", conn->session);*/ 68 | if (! ctx->io_engine->addto (conn->session, ctx, conn, ctx->io_engine->io_object)) { 69 | 70 | /* remove this connection from registry */ 71 | nopoll_ctx_unregister_conn (ctx, conn); 72 | nopoll_log (ctx, NOPOLL_LEVEL_WARNING, "Failed to add socket %d to the watching set", conn->session); 73 | 74 | } 75 | 76 | return nopoll_false; /* keep foreach, don't stop */ 77 | } 78 | 79 | /** 80 | * @internal Function used to handle incoming data from from the 81 | * connection and to notify this data on the connection. 82 | */ 83 | void nopoll_loop_process_data (noPollCtx * ctx, noPollConn * conn) 84 | { 85 | noPollMsg * msg; 86 | 87 | /* call to get messages from the connection */ 88 | msg = nopoll_conn_get_msg (conn); 89 | if (msg == NULL) 90 | return; 91 | 92 | /* found message, notify it */ 93 | if (conn->on_msg) 94 | conn->on_msg (ctx, conn, msg, conn->on_msg_data); 95 | else if (ctx->on_msg) 96 | ctx->on_msg (ctx, conn, msg, ctx->on_msg_data); 97 | 98 | /* release message */ 99 | nopoll_msg_unref (msg); 100 | return; 101 | } 102 | 103 | /** 104 | * @internal Function used to detected which connections has something 105 | * interesting to be notified. 106 | * 107 | */ 108 | nopoll_bool nopoll_loop_process (noPollCtx * ctx, noPollConn * conn, noPollPtr user_data) 109 | { 110 | int * conn_changed = (int *) user_data; 111 | 112 | /* check if the connection have something to notify */ 113 | if (ctx->io_engine->isset (ctx, conn->session, ctx->io_engine->io_object)) { 114 | 115 | /* call to notify action according to role */ 116 | switch (conn->role) { 117 | case NOPOLL_ROLE_CLIENT: 118 | case NOPOLL_ROLE_LISTENER: 119 | /* received data, notify */ 120 | nopoll_loop_process_data (ctx, conn); 121 | break; 122 | case NOPOLL_ROLE_MAIN_LISTENER: 123 | /* call to handle */ 124 | nopoll_conn_accept (ctx, conn); 125 | break; 126 | default: 127 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found connection with unknown role, closing and dropping"); 128 | nopoll_conn_shutdown (conn); 129 | break; 130 | } 131 | 132 | /* reduce connection changed */ 133 | (*conn_changed)--; 134 | } /* end if */ 135 | 136 | return (*conn_changed) == 0; 137 | } 138 | 139 | /** 140 | * @internal Function used to init internal io wait mechanism... 141 | * 142 | * @param ctx The noPoll context to be initialized if it wasn't 143 | */ 144 | void nopoll_loop_init (noPollCtx * ctx) 145 | { 146 | if (ctx == NULL) 147 | return; 148 | 149 | /* grab the mutex for the following check */ 150 | if (ctx->io_engine == NULL) { 151 | ctx->io_engine = nopoll_io_get_engine (ctx, NOPOLL_IO_ENGINE_DEFAULT); 152 | if (ctx->io_engine == NULL) { 153 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Failed to create IO wait engine, unable to implement wait call"); 154 | return; 155 | } 156 | } /* end if */ 157 | /* release the mutex */ 158 | 159 | return; 160 | } 161 | 162 | /** 163 | * @brief Flag to stop the current loop implemented (if any) on the provided context. 164 | * 165 | * @param ctx The context where the loop is being done, and wanted to 166 | * be stopped. 167 | * 168 | */ 169 | void nopoll_loop_stop (noPollCtx * ctx) 170 | { 171 | if (! ctx) 172 | return; 173 | ctx->keep_looping = nopoll_false; 174 | return; 175 | } /* end if */ 176 | 177 | /** 178 | * @brief Allows to implement a wait over all connections registered 179 | * under the provided context during the provided timeout until 180 | * something is detected meaningful to the user, calling to the action 181 | * handler defined, optionally receving the user data pointer. 182 | * 183 | * @param ctx The context object where the wait will be implemented. 184 | * 185 | * @param timeout The timeout to wait for changes. If no changes 186 | * happens, the function returns. The function will block the caller 187 | * until a call to \ref nopoll_loop_stop is done in the case timeout 188 | * passed is 0. 189 | * 190 | * @return The function returns 0 when finished or -2 in the case ctx 191 | * is NULL or timeout is negative. 192 | */ 193 | int nopoll_loop_wait (noPollCtx * ctx, long timeout) 194 | { 195 | struct timeval start; 196 | struct timeval stop; 197 | struct timeval diff; 198 | long ellapsed; 199 | int wait_status; 200 | 201 | nopoll_return_val_if_fail (ctx, ctx, -2); 202 | nopoll_return_val_if_fail (ctx, timeout >= 0, -2); 203 | 204 | /* call to init io engine */ 205 | nopoll_loop_init (ctx); 206 | 207 | /* get as reference current time */ 208 | if (timeout > 0) 209 | #if defined(NOPOLL_OS_WIN32) 210 | nopoll_win32_gettimeofday (&start, NULL); 211 | #else 212 | gettimeofday (&start, NULL); 213 | #endif 214 | 215 | /* set to keep looping everything this function is called */ 216 | ctx->keep_looping = nopoll_true; 217 | 218 | while (ctx->keep_looping) { 219 | /* ok, now implement wait operation */ 220 | ctx->io_engine->clear (ctx, ctx->io_engine->io_object); 221 | 222 | /* add all connections */ 223 | /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Adding connections to watch: %d", ctx->conn_num); */ 224 | nopoll_ctx_foreach_conn (ctx, nopoll_loop_register, NULL); 225 | 226 | /* if (errno == EBADF) { */ 227 | /* detected some descriptor not properly 228 | * working, try to check them */ 229 | /* nopoll_ctx_foreach_conn (ctx, nopoll_loop_clean_descriptors, NULL); */ 230 | /* nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Found some descriptor is not valid (errno==%d)", errno); 231 | continue; */ 232 | /* } */ /* end if */ 233 | 234 | /* implement wait operation */ 235 | /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting for changes into %d connections", ctx->conn_num); */ 236 | wait_status = ctx->io_engine->wait (ctx, ctx->io_engine->io_object); 237 | /* nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "Waiting finished with result %d", wait_status); */ 238 | if (wait_status == -1) { 239 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Received error from wait operation, error code was: %d", errno); 240 | break; 241 | } /* end if */ 242 | 243 | /* check how many connections changed and restart */ 244 | if (wait_status > 0) { 245 | /* check and call for connections with something 246 | * interesting */ 247 | nopoll_ctx_foreach_conn (ctx, nopoll_loop_process, &wait_status); 248 | } 249 | 250 | /* check to stop wait operation */ 251 | if (timeout > 0) { 252 | #if defined(NOPOLL_OS_WIN32) 253 | nopoll_win32_gettimeofday (&stop, NULL); 254 | #else 255 | gettimeofday (&stop, NULL); 256 | #endif 257 | nopoll_timeval_substract (&stop, &start, &diff); 258 | ellapsed = (diff.tv_sec * 1000000) + diff.tv_usec; 259 | if (ellapsed > timeout) 260 | break; 261 | } /* end if */ 262 | } /* end while */ 263 | 264 | /* release engine */ 265 | nopoll_io_release_engine (ctx->io_engine); 266 | ctx->io_engine = NULL; 267 | 268 | return 0; 269 | } 270 | 271 | /* @} */ 272 | 273 | 274 | -------------------------------------------------------------------------------- /nopoll/nopoll_loop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_LOOP_H__ 40 | #define __NOPOLL_LOOP_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | int nopoll_loop_wait (noPollCtx * ctx, long timeout); 47 | 48 | void nopoll_loop_stop (noPollCtx * ctx); 49 | 50 | END_C_DECLS 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /nopoll/nopoll_msg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #include 40 | #include 41 | 42 | /** 43 | * \defgroup nopoll_msg noPoll Message: functions for handling and using noPoll messages (websocket messages) 44 | */ 45 | 46 | /** 47 | * \addtogroup nopoll_msg 48 | * @{ 49 | */ 50 | 51 | /** 52 | * @internal function that creates an empty message holder. 53 | * @return A newly created reference or NULL if it fails. 54 | */ 55 | noPollMsg * nopoll_msg_new (void) 56 | { 57 | noPollMsg * msg = nopoll_new (noPollMsg, 1); 58 | if (msg == NULL) 59 | return NULL; 60 | 61 | msg->refs = 1; 62 | msg->ref_mutex = nopoll_mutex_create (); 63 | 64 | return msg; 65 | } 66 | 67 | /** 68 | * @brief Allows to get a reference to the payload content inside the 69 | * provided websocket message. 70 | * 71 | * @param msg The websocket message to get the payload from. 72 | * 73 | * @return A reference to the payload or NULL if it fails. See \ref 74 | * nopoll_msg_get_payload_size to get payload size. 75 | */ 76 | const unsigned char * nopoll_msg_get_payload (noPollMsg * msg) 77 | { 78 | if (msg == NULL) 79 | return NULL; 80 | return msg->payload; 81 | } 82 | 83 | /** 84 | * @brief Allows to get the payload byte length stored on the provided 85 | * message. 86 | * 87 | * @param msg The websocket message to get the payload from. 88 | * 89 | * @return The payload size or -1 if it fails (only when msg is NULL). 90 | */ 91 | int nopoll_msg_get_payload_size (noPollMsg * msg) 92 | { 93 | if (msg == NULL) 94 | return -1; 95 | return msg->payload_size; 96 | } 97 | 98 | /** 99 | * @brief Allows to acquire a reference to the provided websocket 100 | * message. 101 | * 102 | * @param msg The websocket message to acquire a reference. 103 | * 104 | * @return nopoll_true if the reference was acquired, otherwise 105 | * nopoll_false is returned. 106 | */ 107 | nopoll_bool nopoll_msg_ref (noPollMsg * msg) 108 | { 109 | /* check recieved reference */ 110 | if (msg == NULL) 111 | return nopoll_false; 112 | 113 | /* acquire mutex here */ 114 | nopoll_mutex_lock (msg->ref_mutex); 115 | 116 | msg->refs++; 117 | 118 | /* release mutex here */ 119 | nopoll_mutex_unlock (msg->ref_mutex); 120 | 121 | return nopoll_true; 122 | } 123 | 124 | /** 125 | * @brief Allows to get current reference counting for the provided 126 | * message. 127 | * 128 | * @param msg The message for which we are requesting for the 129 | * reference counting. 130 | * 131 | * @return Reference counting or -1 if it fails (returned when msg 132 | * reference received is NULL). 133 | */ 134 | int nopoll_msg_ref_count (noPollMsg * msg) 135 | { 136 | int result; 137 | 138 | /* check recieved reference */ 139 | if (msg == NULL) 140 | return -1; 141 | 142 | /* acquire mutex here */ 143 | nopoll_mutex_lock (msg->ref_mutex); 144 | 145 | result = msg->refs; 146 | 147 | /* release mutex here */ 148 | nopoll_mutex_unlock (msg->ref_mutex); 149 | 150 | return result; 151 | } 152 | 153 | /** 154 | * @brief Allows to get if the provided message reference has FIN flag 155 | * on (or off) to indicate if it is a final frame. 156 | * 157 | * When a series of messages are received and they conform together a 158 | * single message, the last message is flagged with FIN = 1 while the 159 | * rest before go with FIN = 0. 160 | * 161 | * For example, if a user level application is splitted into 4 frame 162 | * fragments, then the WebSocket peer will receive 3 fragments with 163 | * FIN = 0 and the last fragment with FIN = 1. 164 | * 165 | * You can use \ref nopoll_msg_is_fragment to know if a particular 166 | * message was produced due to a fragmentation found at the network 167 | * level. This happens when the entire frame wasn't sent or it 168 | * couldn't be read entirely. In the example before, the four frames 169 | * will be also flagged as fragments too. 170 | * 171 | * @param msg The message that is being checked for FIN flag. 172 | * 173 | * @return nopoll_true if the message is a final one, otherwise 174 | * nopoll_false is returned. The function returns nopoll_false when 175 | * message reference received is NULL. 176 | * 177 | */ 178 | nopoll_bool nopoll_msg_is_final (noPollMsg * msg) 179 | { 180 | if (msg == NULL) 181 | return nopoll_false; 182 | 183 | return msg->has_fin; 184 | } 185 | 186 | /** 187 | * @brief Allows to check if the message represents a frame fragment. 188 | * 189 | * The function allows to check if the provided noPollMsg is a 190 | * fragment from a bigger frame or message that was splitted as a 191 | * consequence of not being able to read the entire frame or because 192 | * it wasn't sent complete from the other side. See \ref 193 | * nopoll_msg_is_final for more information. 194 | * 195 | * The function also returns that the message is a fragment when the frame has FIN = 0. 196 | * 197 | * @param msg The message checked to be a fragment or not. 198 | * 199 | * @return nopoll_true if the message is a fragment, otherwise 200 | * nopoll_false is returned. 201 | */ 202 | nopoll_bool nopoll_msg_is_fragment (noPollMsg * msg) 203 | { 204 | if (msg == NULL) 205 | return nopoll_false; 206 | return msg->is_fragment || msg->has_fin == 0; 207 | } 208 | 209 | /** 210 | * @brief Get message OpCode to get the type of message that was 211 | * received. 212 | * 213 | * @param msg The message that is being checked for its OpCode 214 | * 215 | * @return The op code or -1 in the case NULL reference is received. 216 | */ 217 | noPollOpCode nopoll_msg_opcode (noPollMsg * msg) 218 | { 219 | if (msg == NULL) 220 | return NOPOLL_UNKNOWN_OP_CODE; 221 | return (noPollOpCode) msg->op_code; 222 | } 223 | 224 | /** 225 | * @brief Allows to join the provided noPollMsg references to create a 226 | * newly allocated message (or reusing same reference but increasing reference 227 | * counting) that contains both content. 228 | * 229 | * @param msg The message to be join to the next message. Headers from 230 | * this message will be used as reference for the headers to be 231 | * used. In the case this is NULL, the second argument will be used as 232 | * argument and reference counting will be updated. 233 | * 234 | * @param msg2 The message to be join as a second part for the first 235 | * argument. 236 | * 237 | * Here are some examples showing how the function works. The notation 238 | * along the argument indicates the reference counting at the end of 239 | * the function. 240 | * 241 | * msgA (2) = nopoll_msg_join (msgA (1), NULL); 242 | * msgB (2) = nopoll_msg_join (NULL, msgB (1)); 243 | * msgC (1) = nopoll_msg_join (msgA (1), msgB (1)); 244 | * NULL = nopoll_msg_join (NULL, NULL); 245 | * 246 | * @return The function returns the newly allocated or reused 247 | * reference with increased reference counting or NULL if it fails. 248 | */ 249 | noPollMsg * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2) 250 | { 251 | noPollMsg * result; 252 | 253 | /* check for basic cases */ 254 | if (msg == NULL && msg2 == NULL) 255 | return NULL; 256 | if (msg == NULL && msg2) { 257 | nopoll_msg_ref (msg2); 258 | return msg2; 259 | } /* ned if */ 260 | if (msg && msg2 == NULL) { 261 | nopoll_msg_ref (msg); 262 | return msg; 263 | } /* end if */ 264 | 265 | /* now, join content */ 266 | result = nopoll_msg_new (); 267 | result->has_fin = msg->has_fin; 268 | result->op_code = msg->op_code; 269 | result->is_masked = msg->is_masked; 270 | if (result->is_masked) 271 | memcpy (result->mask, msg->mask, 4); 272 | 273 | /* copy payload size and content */ 274 | result->payload_size = msg->payload_size + msg2->payload_size; 275 | result->payload = nopoll_new (char, result->payload_size + 1); 276 | 277 | /* copy content from first message */ 278 | memcpy (result->payload, msg->payload, msg->payload_size); 279 | 280 | /* copy content from second message */ 281 | memcpy (((unsigned char *) result->payload) + msg->payload_size , msg2->payload, msg2->payload_size); 282 | 283 | /* return joined message */ 284 | return result; 285 | } 286 | 287 | /** 288 | * @brief Allows to release the reference acquired, finished the 289 | * object if all references are terminated. 290 | * 291 | * @param msg The websocket message to be finished. 292 | */ 293 | void nopoll_msg_unref (noPollMsg * msg) 294 | { 295 | if (msg == NULL) 296 | return; 297 | 298 | /* acquire mutex here */ 299 | nopoll_mutex_lock (msg->ref_mutex); 300 | 301 | msg->refs--; 302 | if (msg->refs != 0) { 303 | /* release mutex here */ 304 | nopoll_mutex_unlock (msg->ref_mutex); 305 | return; 306 | } 307 | /* release mutex */ 308 | nopoll_mutex_unlock (msg->ref_mutex); 309 | nopoll_mutex_destroy (msg->ref_mutex); 310 | 311 | /* free websocket message */ 312 | nopoll_free (msg->payload); 313 | nopoll_free (msg); 314 | 315 | /* release mutex here */ 316 | return; 317 | } 318 | 319 | 320 | /* @} */ 321 | -------------------------------------------------------------------------------- /nopoll/nopoll_msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_MSG_H__ 40 | #define __NOPOLL_MSG_H__ 41 | 42 | #include 43 | 44 | BEGIN_C_DECLS 45 | 46 | const unsigned char * nopoll_msg_get_payload (noPollMsg * msg); 47 | 48 | int nopoll_msg_get_payload_size (noPollMsg * msg); 49 | 50 | noPollMsg * nopoll_msg_new (void); 51 | 52 | nopoll_bool nopoll_msg_ref (noPollMsg * msg); 53 | 54 | int nopoll_msg_ref_count (noPollMsg * msg); 55 | 56 | nopoll_bool nopoll_msg_is_final (noPollMsg * msg); 57 | 58 | nopoll_bool nopoll_msg_is_fragment (noPollMsg * msg); 59 | 60 | noPollOpCode nopoll_msg_opcode (noPollMsg * msg); 61 | 62 | noPollMsg * nopoll_msg_join (noPollMsg * msg, noPollMsg * msg2); 63 | 64 | void nopoll_msg_unref (noPollMsg * msg); 65 | 66 | END_C_DECLS 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /nopoll/nopoll_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | #ifndef __NOPOLL_PRIVATE_H__ 40 | #define __NOPOLL_PRIVATE_H__ 41 | 42 | #if NOPLL_TLS 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #endif 50 | 51 | #include 52 | 53 | typedef struct _noPollCertificate { 54 | 55 | char * serverName; 56 | char * certificateFile; 57 | char * privateKey; 58 | char * optionalChainFile; 59 | 60 | } noPollCertificate; 61 | 62 | struct _noPollCtx { 63 | /** 64 | * @internal Controls logs output.. 65 | */ 66 | /* context reference counting */ 67 | int refs; 68 | 69 | /* console log */ 70 | nopoll_bool not_executed; 71 | nopoll_bool debug_enabled; 72 | 73 | /* colored log */ 74 | nopoll_bool not_executed_color; 75 | nopoll_bool debug_color_enabled; 76 | 77 | nopoll_bool keep_looping; 78 | 79 | /** 80 | * @internal noPollConn connection timeout. 81 | */ 82 | long conn_connect_std_timeout; 83 | 84 | /** 85 | * @internal Default listener connection backlog 86 | */ 87 | int backlog; 88 | 89 | /** 90 | * @internal Currently selected io engine on this context. 91 | */ 92 | noPollIoEngine * io_engine; 93 | 94 | /** 95 | * @internal Connection array list and its length. 96 | */ 97 | int conn_id; 98 | noPollConn ** conn_list; 99 | int conn_length; 100 | /** 101 | * @internal Number of connections registered on this context. 102 | */ 103 | int conn_num; 104 | 105 | /** 106 | * @internal Reference to defined on accept handling. 107 | */ 108 | noPollActionHandler on_accept; 109 | noPollPtr on_accept_data; 110 | 111 | /** 112 | * @internal Reference to defined on ready handling. 113 | */ 114 | noPollActionHandler on_ready; 115 | noPollPtr on_ready_data; 116 | 117 | /** 118 | * @internal Reference to defined on open handling. 119 | */ 120 | noPollActionHandler on_open; 121 | noPollPtr on_open_data; 122 | 123 | /** 124 | * @internal Reference to the defined on message handling. 125 | */ 126 | noPollOnMessageHandler on_msg; 127 | noPollPtr on_msg_data; 128 | 129 | /** 130 | * @internal Basic fake support for protocol version, by 131 | * default: 13, due to RFC6455 standard 132 | */ 133 | int protocol_version; 134 | 135 | /** 136 | * @internal Certificates added.. 137 | */ 138 | noPollCertificate * certificates; 139 | int certificates_length; 140 | 141 | /* mutex */ 142 | noPollPtr ref_mutex; 143 | 144 | /* log handling */ 145 | noPollLogHandler log_handler; 146 | noPollPtr log_user_data; 147 | 148 | /* context creator */ 149 | noPollSslContextCreator context_creator; 150 | noPollPtr context_creator_data; 151 | 152 | /* SSL postcheck */ 153 | noPollSslPostCheck post_ssl_check; 154 | noPollPtr post_ssl_check_data; 155 | }; 156 | 157 | struct _noPollConn { 158 | /** 159 | * @internal Connection id. 160 | */ 161 | int id; 162 | 163 | /** 164 | * @internal The context associated to this connection. 165 | */ 166 | noPollCtx * ctx; 167 | 168 | /** 169 | * @internal This is the actual socket handler associated to 170 | * the noPollConn object. 171 | */ 172 | NOPOLL_SOCKET session; 173 | /** 174 | * @internal Flag to signal this connection has finished its 175 | * handshake. 176 | */ 177 | nopoll_bool handshake_ok; 178 | 179 | /** 180 | * @internal Current connection receive function. 181 | */ 182 | noPollRead receive; 183 | 184 | /** 185 | * @internal Current connection receive function. 186 | */ 187 | noPollRead send; 188 | 189 | /** 190 | * @internal The connection role. 191 | */ 192 | noPollRole role; 193 | 194 | /** 195 | * @internal Conection host ip location (connecting or listening). 196 | */ 197 | char * host; 198 | 199 | /** 200 | * @internal Connection port location (connecting or 201 | * listening). 202 | */ 203 | char * port; 204 | 205 | /** 206 | * @internal Host name requested on the connection. 207 | */ 208 | char * host_name; 209 | 210 | /** 211 | * @internal Origin requested on the connection. 212 | */ 213 | char * origin; 214 | 215 | /** 216 | * @internal reference to the get url. 217 | */ 218 | char * get_url; 219 | 220 | /** 221 | * @internal Reference to protocols requested to be opened on 222 | * this connection. 223 | */ 224 | char * protocols; 225 | /* @internal reference to the protocol that was replied by the server */ 226 | char * accepted_protocol; 227 | 228 | /* close status and reason */ 229 | int peer_close_status; 230 | char * peer_close_reason; 231 | 232 | /** 233 | * @internal Reference to the defined on message handling. 234 | */ 235 | noPollOnMessageHandler on_msg; 236 | noPollPtr on_msg_data; 237 | 238 | /** 239 | * @internal Reference to defined on ready handling. 240 | */ 241 | noPollActionHandler on_ready; 242 | noPollPtr on_ready_data; 243 | 244 | /** 245 | * @internal Reference to the defined on close handling. 246 | */ 247 | noPollOnCloseHandler on_close; 248 | noPollPtr on_close_data; 249 | 250 | /* reference to the handshake */ 251 | noPollHandShake * handshake; 252 | 253 | /* reference to a buffer with pending content */ 254 | char * pending_line; 255 | 256 | /** 257 | * @internal connection reference counting. 258 | */ 259 | int refs; 260 | 261 | /** 262 | * @internal References to pending content to be read 263 | */ 264 | noPollMsg * pending_msg; 265 | long int pending_diff; 266 | long int pending_desp; 267 | 268 | /** 269 | * @internal Flag to handle TLS support upon connection 270 | * reception. 271 | */ 272 | nopoll_bool tls_on; 273 | #if NOPLL_TLS 274 | /** 275 | * @internal Flag that indicates that the provided session 276 | * must call to accept the TLS session before proceeding. 277 | */ 278 | nopoll_bool pending_ssl_accept; 279 | 280 | /* SSL support */ 281 | SSL_CTX * ssl_ctx; 282 | SSL * ssl; 283 | 284 | /* certificates */ 285 | char * certificate; 286 | char * private_key; 287 | char * chain_certificate; 288 | #endif 289 | 290 | /* pending buffer */ 291 | char pending_buf[100]; 292 | int pending_buf_bytes; 293 | 294 | /** 295 | * @internal Support for an user defined pointer. 296 | */ 297 | noPollPtr hook; 298 | 299 | /** 300 | * @internal Mutex 301 | */ 302 | noPollPtr ref_mutex; 303 | 304 | /** 305 | * @internal Variable to track pending bytes from previous 306 | * read that must be completed. 307 | */ 308 | noPollMsg * previous_msg; 309 | /* allows to track if previous message was a fragment to flag 310 | * next message, even having FIN enabled as a fragment. */ 311 | nopoll_bool previous_was_fragment; 312 | 313 | char * pending_write; 314 | int pending_write_bytes; 315 | int pending_write_desp; 316 | 317 | /** 318 | * @internal Internal reference to the connection options. 319 | */ 320 | noPollConnOpts * opts; 321 | 322 | /** 323 | * @internal Reference to the listener in the case this is a 324 | * connection that was created due to a listener running. 325 | */ 326 | noPollConn * listener; 327 | 328 | /** 329 | * @internal Flag to track internal header pending 330 | */ 331 | nopoll_bool read_pending_header; 332 | 333 | 334 | /**** debug values ****/ 335 | /* force stop after header: do not use this, it is just for 336 | testing purposes */ 337 | nopoll_bool __force_stop_after_header; 338 | }; 339 | 340 | struct _noPollIoEngine { 341 | noPollPtr io_object; 342 | noPollCtx * ctx; 343 | noPollIoMechCreate create; 344 | noPollIoMechDestroy destroy; 345 | noPollIoMechClear clear; 346 | noPollIoMechWait wait; 347 | noPollIoMechAddTo addto; 348 | noPollIoMechIsSet isset; 349 | }; 350 | 351 | struct _noPollMsg { 352 | nopoll_bool has_fin; 353 | short op_code; 354 | nopoll_bool is_masked; 355 | 356 | noPollPtr payload; 357 | long int payload_size; 358 | 359 | int refs; 360 | noPollPtr ref_mutex; 361 | 362 | char mask[4]; 363 | int remain_bytes; 364 | 365 | nopoll_bool is_fragment; 366 | int unmask_desp; 367 | }; 368 | 369 | struct _noPollHandshake { 370 | /** 371 | * @internal Reference to the to the GET url HTTP/1.1 header 372 | * part. 373 | */ 374 | nopoll_bool upgrade_websocket; 375 | nopoll_bool connection_upgrade; 376 | nopoll_bool received_101; 377 | char * websocket_key; 378 | char * websocket_version; 379 | char * websocket_accept; 380 | char * expected_accept; 381 | 382 | /* reference to cookie header */ 383 | char * cookie; 384 | }; 385 | 386 | struct _noPollConnOpts { 387 | /* If the connection options object should be reused across calls */ 388 | nopoll_bool reuse; 389 | 390 | /* mutex */ 391 | noPollPtr mutex; 392 | int refs; 393 | 394 | /* What ssl protocol should be used */ 395 | noPollSslProtocol ssl_protocol; 396 | 397 | /* SSL options */ 398 | char * certificate; 399 | char * private_key; 400 | char * chain_certificate; 401 | char * ca_certificate; 402 | 403 | nopoll_bool disable_ssl_verify; 404 | 405 | /* cookie support */ 406 | char * cookie; 407 | 408 | /* skip origin check flag */ 409 | nopoll_bool skip_origin_header_check; 410 | 411 | /* network interface to bind to */ 412 | char * _interface; 413 | 414 | /* extra HTTP headers to send during the connection */ 415 | char * extra_headers; 416 | }; 417 | 418 | #endif 419 | -------------------------------------------------------------------------------- /nopoll/nopoll_rtthread.c: -------------------------------------------------------------------------------- 1 | #include "nopoll_rtthread.h" 2 | #include 3 | #include 4 | 5 | /* 6 | * os mutex routine 7 | */ 8 | static noPollPtr nopoll_rtt_mutex_create (void) 9 | { 10 | noPollPtr ptr; 11 | ptr = rt_mutex_create("nopoll", RT_IPC_FLAG_FIFO); 12 | 13 | return ptr; 14 | } 15 | 16 | static void nopoll_rtt_mutex_lock (noPollPtr mutex) 17 | { 18 | rt_mutex_t m = (rt_mutex_t) mutex; 19 | 20 | rt_mutex_take(m, RT_WAITING_FOREVER); 21 | return; 22 | } 23 | 24 | static void nopoll_rtt_mutex_unlock (noPollPtr mutex) 25 | { 26 | rt_mutex_t m = (rt_mutex_t) mutex; 27 | 28 | rt_mutex_release(m); 29 | return; 30 | } 31 | 32 | static void nopoll_rtt_mutex_destroy (noPollPtr mutex) 33 | { 34 | rt_mutex_t m = (rt_mutex_t) mutex; 35 | 36 | rt_mutex_delete(m); 37 | return; 38 | } 39 | 40 | /* 41 | * socket send/recv, because these two routines was defined by lwIP macro. 42 | */ 43 | #ifndef SAL_USING_POSIX 44 | 45 | #ifdef send 46 | #undef send 47 | #endif 48 | 49 | int send(int s, const void *dataptr, size_t size, int flags) 50 | { 51 | return lwip_send(s, dataptr, size, flags); 52 | } 53 | 54 | #ifdef recv 55 | #undef recv 56 | #endif 57 | 58 | int recv(int s, void *mem, size_t len, int flags) 59 | { 60 | return lwip_recv(s, mem, len, flags); 61 | } 62 | #endif 63 | 64 | /* 65 | * random routine, just to use os_tick 66 | */ 67 | unsigned int nopoll_rtt_random(void) 68 | { 69 | return rt_tick_get(); 70 | } 71 | 72 | /* 73 | * base64 routines 74 | */ 75 | static const unsigned char base64_enc_map[64] = 76 | { 77 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 78 | 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 79 | 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 80 | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 81 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 82 | 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 83 | '8', '9', '+', '/' 84 | }; 85 | 86 | static const unsigned char base64_dec_map[128] = 87 | { 88 | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 89 | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 90 | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 91 | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 92 | 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, 93 | 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 94 | 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, 95 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 96 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 97 | 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 98 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 99 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 100 | 49, 50, 51, 127, 127, 127, 127, 127 101 | }; 102 | 103 | /* 104 | * Encode a buffer into base64 format 105 | */ 106 | int _base64_encode( unsigned char *dst, size_t *dlen, 107 | const unsigned char *src, size_t slen ) 108 | { 109 | size_t i, n; 110 | int C1, C2, C3; 111 | unsigned char *p; 112 | 113 | if( slen == 0 ) 114 | return( 0 ); 115 | 116 | n = ( slen << 3 ) / 6; 117 | 118 | switch( ( slen << 3 ) - ( n * 6 ) ) 119 | { 120 | case 2: n += 3; break; 121 | case 4: n += 2; break; 122 | default: break; 123 | } 124 | 125 | if( *dlen < n + 1 ) 126 | { 127 | *dlen = n + 1; 128 | return( -1 ); 129 | } 130 | 131 | n = ( slen / 3 ) * 3; 132 | 133 | for( i = 0, p = dst; i < n; i += 3 ) 134 | { 135 | C1 = *src++; 136 | C2 = *src++; 137 | C3 = *src++; 138 | 139 | *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; 140 | *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; 141 | *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; 142 | *p++ = base64_enc_map[C3 & 0x3F]; 143 | } 144 | 145 | if( i < slen ) 146 | { 147 | C1 = *src++; 148 | C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; 149 | 150 | *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; 151 | *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; 152 | 153 | if( ( i + 1 ) < slen ) 154 | *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; 155 | else *p++ = '='; 156 | 157 | *p++ = '='; 158 | } 159 | 160 | *dlen = p - dst; 161 | *p = 0; 162 | 163 | return( 0 ); 164 | } 165 | 166 | /* 167 | * Decode a base64-formatted buffer 168 | */ 169 | int _base64_decode( unsigned char *dst, size_t *dlen, 170 | const unsigned char *src, size_t slen ) 171 | { 172 | size_t i, n; 173 | uint32_t j, x; 174 | unsigned char *p; 175 | 176 | for( i = n = j = 0; i < slen; i++ ) 177 | { 178 | if( ( slen - i ) >= 2 && 179 | src[i] == '\r' && src[i + 1] == '\n' ) 180 | continue; 181 | 182 | if( src[i] == '\n' ) 183 | continue; 184 | 185 | if( src[i] == '=' && ++j > 2 ) 186 | return( -1 ); 187 | 188 | if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) 189 | return( -1 ); 190 | 191 | if( base64_dec_map[src[i]] < 64 && j != 0 ) 192 | return( -1 ); 193 | 194 | n++; 195 | } 196 | 197 | if( n == 0 ) 198 | return( 0 ); 199 | 200 | n = ( ( n * 6 ) + 7 ) >> 3; 201 | n -= j; 202 | 203 | if( dst == NULL || *dlen < n ) 204 | { 205 | *dlen = n; 206 | return( -1 ); 207 | } 208 | 209 | for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) 210 | { 211 | if( *src == '\r' || *src == '\n' ) 212 | continue; 213 | 214 | j -= ( base64_dec_map[*src] == 64 ); 215 | x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); 216 | 217 | if( ++n == 4 ) 218 | { 219 | n = 0; 220 | if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); 221 | if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); 222 | if( j > 2 ) *p++ = (unsigned char)( x ); 223 | } 224 | } 225 | 226 | *dlen = p - dst; 227 | 228 | return( 0 ); 229 | } 230 | 231 | nopoll_bool nopoll_rtt_base64_encode (const char * content, 232 | int length, 233 | char * output, 234 | int * output_size) 235 | { 236 | nopoll_bool result = nopoll_false; 237 | 238 | if (_base64_encode(output, output_size, content, length) == 0) 239 | result = nopoll_true; 240 | 241 | return result; 242 | } 243 | 244 | nopoll_bool nopoll_rtt_base64_decode (const char * content, 245 | int length, 246 | char * output, 247 | int * output_size) 248 | { 249 | nopoll_bool result = nopoll_false; 250 | 251 | if (_base64_decode(output, output_size, content, length) == 0) 252 | result = nopoll_true; 253 | 254 | return result; 255 | } 256 | 257 | /* 258 | * memory related routines 259 | */ 260 | noPollPtr nopoll_calloc(size_t count, size_t size) 261 | { 262 | noPollPtr ptr; 263 | 264 | ptr = rt_malloc(count * size); 265 | if (ptr) memset(ptr, 0x0, count * size); 266 | 267 | return ptr; 268 | } 269 | 270 | noPollPtr nopoll_realloc(noPollPtr ref, size_t size) 271 | { 272 | return rt_realloc(ref, size); 273 | } 274 | 275 | void nopoll_free (noPollPtr ref) 276 | { 277 | rt_free (ref); 278 | return; 279 | } 280 | 281 | #ifdef __IAR_SYSTEMS_ICC__ 282 | #define MICROSECOND_PER_SECOND 1000000UL 283 | #define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND) 284 | 285 | /* POSIX thread provides clock_gettime function */ 286 | #include 287 | int gettimeofday(struct timeval *__tp, void *__tzp) 288 | { 289 | if (__tp) 290 | { 291 | rt_tick_t tick; 292 | 293 | /* get tick */ 294 | tick = rt_tick_get(); 295 | 296 | __tp->tv_sec = tick / RT_TICK_PER_SECOND; 297 | __tp->tv_usec = ((tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK); 298 | } 299 | 300 | return 0; 301 | } 302 | #endif 303 | 304 | /* 305 | * Initialization routine 306 | */ 307 | int nopoll_rtt_init(void) 308 | { 309 | nopoll_thread_handlers(nopoll_rtt_mutex_create, 310 | nopoll_rtt_mutex_destroy, 311 | nopoll_rtt_mutex_lock, 312 | nopoll_rtt_mutex_unlock); 313 | 314 | return 0; 315 | } 316 | INIT_COMPONENT_EXPORT(nopoll_rtt_init); 317 | -------------------------------------------------------------------------------- /nopoll/nopoll_rtthread.h: -------------------------------------------------------------------------------- 1 | #ifndef NOPOLL_RTTHREAD_H__ 2 | #define NOPOLL_RTTHREAD_H__ 3 | 4 | #include "nopoll.h" 5 | #include 6 | 7 | unsigned int nopoll_rtt_random(void); 8 | 9 | nopoll_bool nopoll_rtt_base64_encode (const char * content, 10 | int length, 11 | char * output, 12 | int * output_size); 13 | 14 | nopoll_bool nopoll_rtt_base64_decode (const char * content, 15 | int length, 16 | char * output, 17 | int * output_size); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /nopoll/nopoll_win32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | 40 | #include 41 | 42 | #define LOG_DOMAIN "nopoll-win32" 43 | 44 | #if defined(NOPOLL_OS_WIN32) 45 | 46 | nopoll_bool __nopoll_win32_was_init = nopoll_false; 47 | 48 | int nopoll_win32_init (noPollCtx * ctx) 49 | { 50 | WORD wVersionRequested; 51 | WSADATA wsaData; 52 | int error; 53 | 54 | if (__nopoll_win32_was_init) 55 | return nopoll_true; 56 | 57 | wVersionRequested = MAKEWORD( 2, 2 ); 58 | 59 | error = WSAStartup( wVersionRequested, &wsaData ); 60 | if (error != NO_ERROR) { 61 | nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "unable to init winsock api, exiting.."); 62 | return nopoll_false; 63 | } 64 | nopoll_log (ctx, NOPOLL_LEVEL_DEBUG, "winsock initialization ok"); 65 | /* flag the library as initialized */ 66 | __nopoll_win32_was_init = nopoll_true; 67 | return nopoll_true; 68 | } 69 | 70 | BOOL APIENTRY DllMain (HINSTANCE hInst, 71 | DWORD reason, 72 | LPVOID reserved) 73 | { 74 | 75 | /* always returns true because nopoll init is done through 76 | * nopoll_init */ 77 | return nopoll_true; 78 | } 79 | 80 | int __nopoll_win32_blocking_socket_set (NOPOLL_SOCKET socket, 81 | int status) 82 | { 83 | unsigned long enable = status; 84 | 85 | return (ioctlsocket (socket, FIONBIO, &enable) == 0); 86 | } 87 | 88 | int nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket) 89 | { 90 | return __nopoll_win32_blocking_socket_set (socket, 1); 91 | } 92 | 93 | int nopoll_win32_blocking_enable (NOPOLL_SOCKET socket) 94 | { 95 | return __nopoll_win32_blocking_socket_set (socket, 0); 96 | } 97 | 98 | #if ! defined(HAVE_GETTIMEOFDAY) 99 | 100 | 101 | /** 102 | * @brief The function obtains the current time, expressed as seconds 103 | * and microseconds since the Epoch, and store it in the timeval 104 | * structure pointed to by tv. As posix says gettimeoday should return 105 | * zero and should not reserve any value for error, this function 106 | * returns zero. 107 | * 108 | * The timeval struct have the following members: 109 | * 110 | * \code 111 | * struct timeval { 112 | * long tv_sec; 113 | * long tv_usec; 114 | * } timeval; 115 | * \endcode 116 | * 117 | * @param tv Timeval struct. 118 | * @param notUsed Not defined. 119 | * 120 | * @return The function allways return 0. 121 | */ 122 | int nopoll_win32_gettimeofday(struct timeval *tv, noPollPtr notUsed) 123 | { 124 | union { 125 | long long ns100; 126 | FILETIME fileTime; 127 | } now; 128 | 129 | GetSystemTimeAsFileTime (&now.fileTime); 130 | tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); 131 | tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); 132 | return (0); 133 | } /* end gettimeofday */ 134 | #endif /* end ! defined(HAVE_GETTIMEOFDAY) */ 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /nopoll/nopoll_win32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibNoPoll: A websocket library 3 | * Copyright (C) 2015 Advanced Software Production Line, S.L. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public License 7 | * as published by the Free Software Foundation; either version 2.1 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program; if not, write to the Free 17 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | * 02111-1307 USA 19 | * 20 | * You may find a copy of the license under this software is released 21 | * at COPYING file. This is LGPL software: you are welcome to develop 22 | * proprietary applications using this library without any royalty or 23 | * fee but returning back any change, improvement or addition in the 24 | * form of source code, project image, documentation patches, etc. 25 | * 26 | * For commercial support on build Websocket enabled solutions 27 | * contact us: 28 | * 29 | * Postal address: 30 | * Advanced Software Production Line, S.L. 31 | * Edificio Alius A, Oficina 102, 32 | * C/ Antonio Suarez Nº 10, 33 | * Alcalá de Henares 28802 Madrid 34 | * Spain 35 | * 36 | * Email address: 37 | * info@aspl.es - http://www.aspl.es/nopoll 38 | */ 39 | 40 | #ifndef __NOPOLL_WIN32_H__ 41 | #define __NOPOLL_WIN32_H__ 42 | 43 | #include 44 | 45 | BEGIN_C_DECLS 46 | 47 | int nopoll_win32_init (noPollCtx * ctx); 48 | 49 | int nopoll_win32_nonblocking_enable (NOPOLL_SOCKET socket); 50 | 51 | int nopoll_win32_blocking_enable (NOPOLL_SOCKET socket); 52 | 53 | /* gettimeofday support on windows */ 54 | int nopoll_win32_gettimeofday (struct timeval *tv, noPollPtr notUsed); 55 | 56 | BOOL APIENTRY DllMain (HINSTANCE hInst, 57 | DWORD reason, 58 | LPVOID reserved); 59 | 60 | #if !defined(EINPROGRESS) 61 | #define EINPROGRESS (WSAEINPROGRESS) 62 | #endif 63 | 64 | END_C_DECLS 65 | 66 | #endif 67 | --------------------------------------------------------------------------------