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