Compare commits
	
		
			23 Commits
		
	
	
		
			feature/te
			...
			bsergean-p
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2ddac836ad | ||
| 
						 | 
					69e4bc4c05 | ||
| 
						 | 
					3b66efbb6a | ||
| 
						 | 
					f29906c72f | ||
| 
						 | 
					872f516ede | ||
| 
						 | 
					014d43eb13 | ||
| 
						 | 
					d77067e50f | ||
| 
						 | 
					ed5b1a0895 | ||
| 
						 | 
					ef57e3a2b1 | ||
| 
						 | 
					28832f8732 | ||
| 
						 | 
					0dd284267a | ||
| 
						 | 
					a7019631b7 | ||
| 
						 | 
					632ee31509 | ||
| 
						 | 
					688af99747 | ||
| 
						 | 
					397bb5d18a | ||
| 
						 | 
					f79c64ae97 | ||
| 
						 | 
					bc765e73a3 | ||
| 
						 | 
					dfa10df5ae | ||
| 
						 | 
					eb9a7bed76 | ||
| 
						 | 
					d20864d7d1 | ||
| 
						 | 
					f184a7adef | ||
| 
						 | 
					dc7b986e10 | ||
| 
						 | 
					1e3560014f | 
							
								
								
									
										27
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,27 +0,0 @@
 | 
			
		||||
name: windows
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    paths-ignore:
 | 
			
		||||
    - 'docs/**'
 | 
			
		||||
  pull_request:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  windows:
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
			
		||||
    - uses: seanmiddleditch/gha-setup-ninja@master
 | 
			
		||||
    - run: |
 | 
			
		||||
        mkdir build
 | 
			
		||||
        cd build
 | 
			
		||||
        cmake -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 -DUSE_ZLIB=OFF -DBUILD_SHARED_LIBS=OFF ..
 | 
			
		||||
    - run: |
 | 
			
		||||
        cd build
 | 
			
		||||
        ninja
 | 
			
		||||
    - run: |
 | 
			
		||||
        cd build
 | 
			
		||||
        ninja test
 | 
			
		||||
 | 
			
		||||
#- run: ../build/test/ixwebsocket_unittest.exe
 | 
			
		||||
# working-directory: test
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ jobs:
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - uses: seanmiddleditch/gha-setup-ninja@master
 | 
			
		||||
    - uses: egor-tensin/setup-mingw@v2
 | 
			
		||||
    - uses: bsergean/setup-mingw@d79ce405bac9edef3a1726ef00554a56f0bafe66
 | 
			
		||||
    - run: |
 | 
			
		||||
        mkdir build
 | 
			
		||||
        cd build
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.4.1...3.17.2)
 | 
			
		||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
 | 
			
		||||
 | 
			
		||||
project(ixwebsocket C CXX)
 | 
			
		||||
project(ixwebsocket LANGUAGES C CXX VERSION 11.4.4)
 | 
			
		||||
 | 
			
		||||
set (CMAKE_CXX_STANDARD 11)
 | 
			
		||||
set (CXX_STANDARD_REQUIRED ON)
 | 
			
		||||
@@ -136,6 +136,7 @@ if (USE_TLS)
 | 
			
		||||
    else() # default to OpenSSL on all other platforms
 | 
			
		||||
      if (NOT USE_MBED_TLS) # Unless mbedtls is requested
 | 
			
		||||
        set(USE_OPEN_SSL ON)
 | 
			
		||||
        set(requires "openssl")
 | 
			
		||||
      endif()
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
@@ -167,7 +168,7 @@ if(BUILD_SHARED_LIBS)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Set library version
 | 
			
		||||
    set_target_properties(ixwebsocket PROPERTIES VERSION 11.3.2)
 | 
			
		||||
    set_target_properties(ixwebsocket PROPERTIES VERSION ${CMAKE_PROJECT_VERSION})
 | 
			
		||||
 | 
			
		||||
else()
 | 
			
		||||
    # Static library
 | 
			
		||||
@@ -287,8 +288,12 @@ if (IXWEBSOCKET_INSTALL)
 | 
			
		||||
          PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ixwebsocket/
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-config.cmake.in" "${CMAKE_BINARY_DIR}/ixwebsocket-config.cmake" @ONLY)
 | 
			
		||||
  install(FILES "${CMAKE_BINARY_DIR}/ixwebsocket-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket")
 | 
			
		||||
  configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" @ONLY)
 | 
			
		||||
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket")
 | 
			
		||||
  
 | 
			
		||||
  set(prefix ${CMAKE_INSTALL_PREFIX})
 | 
			
		||||
  configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" @ONLY)
 | 
			
		||||
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
 | 
			
		||||
 | 
			
		||||
  install(EXPORT ixwebsocket
 | 
			
		||||
          FILE ixwebsocket-targets.cmake
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							@@ -99,14 +99,15 @@ Starting with the 11.0.8 release, IXWebSocket should be fully C++11 compatible.
 | 
			
		||||
If your company or project is using this library, feel free to open an issue or PR to amend this list.
 | 
			
		||||
 | 
			
		||||
- [Machine Zone](https://www.mz.com)
 | 
			
		||||
- [Tokio](https://gitlab.com/HCInk/tokio), a discord library focused on audio playback with node bindings.
 | 
			
		||||
- [Tokio](https://github.com/liz3/tokio), a discord library focused on audio playback with node bindings.
 | 
			
		||||
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), an easy to use Discord-bot framework.
 | 
			
		||||
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
 | 
			
		||||
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
 | 
			
		||||
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper (archived as of Oct 8, 2021)
 | 
			
		||||
- [discord.cpp](https://github.com/luccanunes/discord.cpp), a discord library for making bots
 | 
			
		||||
- [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar
 | 
			
		||||
- [Abaddon](https://github.com/uowuo/abaddon), An alternative Discord client made with C++/gtkmm 
 | 
			
		||||
- [NovaCoin](https://github.com/novacoin-project/novacoin), a hybrid scrypt PoW + PoS based cryptocurrency.
 | 
			
		||||
- [Candy](https://github.com/lanthora/candy), A WebSocket and TUN based VPN for Linux 
 | 
			
		||||
 | 
			
		||||
## Alternative libraries
 | 
			
		||||
 | 
			
		||||
@@ -114,8 +115,8 @@ There are plenty of great websocket libraries out there, which might work for yo
 | 
			
		||||
 | 
			
		||||
* [websocketpp](https://github.com/zaphoyd/websocketpp) - C++
 | 
			
		||||
* [beast](https://github.com/boostorg/beast) - C++
 | 
			
		||||
* [µWebSockets](https://github.com/uNetworking/uWebSockets) - C++
 | 
			
		||||
* [libwebsockets](https://libwebsockets.org/) - C
 | 
			
		||||
* [µWebSockets](https://github.com/uNetworking/uWebSockets) - C
 | 
			
		||||
* [wslay](https://github.com/tatsuhiro-t/wslay) - C
 | 
			
		||||
 | 
			
		||||
[uvweb](https://github.com/bsergean/uvweb) is a library written by the IXWebSocket author which is built on top of [uvw](https://github.com/skypjack/uvw), which is a C++ wrapper for [libuv](https://libuv.org/). It has more dependencies and does not support SSL at this point, but it can be used to open multiple connections within a single OS thread thanks to libuv.
 | 
			
		||||
@@ -133,9 +134,7 @@ To check the performance of a websocket library, you can look at the [autoroute]
 | 
			
		||||
| Windows           | Disabled          | None              | [![Build2][5]][0] |
 | 
			
		||||
| UWP               | Disabled          | None              | [![Build2][6]][0] |
 | 
			
		||||
| Linux             | OpenSSL           | Address Sanitizer | [![Build2][7]][0] |
 | 
			
		||||
| Mingw             | Disabled          | None              | [![Build2][8]][0] |
 | 
			
		||||
 | 
			
		||||
* ASAN fails on Linux because of a known problem, we need a 
 | 
			
		||||
* Some tests are disabled on Windows/UWP because of a pathing problem
 | 
			
		||||
* TLS and ZLIB are disabled on Windows/UWP because enabling make the CI run takes a lot of time, for setting up vcpkg.
 | 
			
		||||
 | 
			
		||||
@@ -147,5 +146,4 @@ To check the performance of a websocket library, you can look at the [autoroute]
 | 
			
		||||
[5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg
 | 
			
		||||
[6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/badge.svg
 | 
			
		||||
[7]: https://github.com/machinezone/IXWebSocket/workflows/linux_asan/badge.svg
 | 
			
		||||
[8]: https://github.com/machinezone/IXWebSocket/workflows/unittest_windows_gcc/badge.svg
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
 | 
			
		||||
All changes to this project will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## [11.4.4] - 2023-06-05
 | 
			
		||||
 | 
			
		||||
## [11.4.3] - 2022-05-13
 | 
			
		||||
 | 
			
		||||
Set shorter thread names
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								ixwebsocket.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ixwebsocket.pc.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
prefix=@prefix@
 | 
			
		||||
exec_prefix=${prefix}
 | 
			
		||||
libdir=${exec_prefix}/lib
 | 
			
		||||
includedir=${prefix}/include
 | 
			
		||||
 | 
			
		||||
Name: ixwebsocket
 | 
			
		||||
Description: websocket and http client and server library, with TLS support and very few dependencies
 | 
			
		||||
Version: @CMAKE_PROJECT_VERSION@
 | 
			
		||||
Libs: -L${libdir} -lixwebsocket
 | 
			
		||||
Cflags: -I${includedir}
 | 
			
		||||
Requires: @requires@
 | 
			
		||||
@@ -27,9 +27,13 @@
 | 
			
		||||
 | 
			
		||||
// mingw build quirks
 | 
			
		||||
#if defined(_WIN32) && defined(__GNUC__)
 | 
			
		||||
#ifndef AI_NUMERICSERV
 | 
			
		||||
#define AI_NUMERICSERV NI_NUMERICSERV
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef AI_ADDRCONFIG
 | 
			
		||||
#define AI_ADDRCONFIG LUP_ADDRCONFIG
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -133,16 +133,20 @@ namespace ix
 | 
			
		||||
        if (headers.find("Content-Length") != headers.end())
 | 
			
		||||
        {
 | 
			
		||||
            int contentLength = 0;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                contentLength = std::stoi(headers["Content-Length"]);
 | 
			
		||||
            }
 | 
			
		||||
            catch (const std::exception&)
 | 
			
		||||
            {
 | 
			
		||||
                const char* p = headers["Content-Length"].c_str();
 | 
			
		||||
                char* p_end{};
 | 
			
		||||
                errno = 0;
 | 
			
		||||
                long val = std::strtol(p, &p_end, 10);
 | 
			
		||||
                if (p_end == p            // invalid argument
 | 
			
		||||
                    || errno == ERANGE    // out of range
 | 
			
		||||
                    || val < std::numeric_limits<int>::min()
 | 
			
		||||
                    || val > std::numeric_limits<int>::max()) {
 | 
			
		||||
                    return std::make_tuple(
 | 
			
		||||
                        false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                contentLength = val;
 | 
			
		||||
            }
 | 
			
		||||
            if (contentLength < 0)
 | 
			
		||||
            {
 | 
			
		||||
                return std::make_tuple(
 | 
			
		||||
 
 | 
			
		||||
@@ -209,6 +209,12 @@ namespace ix
 | 
			
		||||
            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set an origin header if missing
 | 
			
		||||
        if (args->extraHeaders.find("Origin") == args->extraHeaders.end())
 | 
			
		||||
        {
 | 
			
		||||
            ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (verb == kPost || verb == kPut || verb == kPatch || _forceBody)
 | 
			
		||||
        {
 | 
			
		||||
            // Set request compression header
 | 
			
		||||
 
 | 
			
		||||
@@ -148,6 +148,7 @@ namespace ix
 | 
			
		||||
                    content = gzipCompress(content);
 | 
			
		||||
                    headers["Content-Encoding"] = "gzip";
 | 
			
		||||
                }
 | 
			
		||||
                headers["Accept-Encoding"] = "gzip";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
                // Log request
 | 
			
		||||
@@ -161,11 +162,6 @@ namespace ix
 | 
			
		||||
                // headers["Content-Type"] = "application/octet-stream";
 | 
			
		||||
                headers["Accept-Ranges"] = "none";
 | 
			
		||||
 | 
			
		||||
                for (auto&& it : request->headers)
 | 
			
		||||
                {
 | 
			
		||||
                    headers[it.first] = it.second;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return std::make_shared<HttpResponse>(
 | 
			
		||||
                    200, "OK", HttpErrorCode::Ok, headers, content);
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ namespace ix
 | 
			
		||||
            {
 | 
			
		||||
                // We must deselect the networkevents from the socket event. Otherwise the
 | 
			
		||||
                // socket will report states that aren't there.
 | 
			
		||||
                if (_fd != nullptr && _fd->fd != -1)
 | 
			
		||||
                if (_fd != nullptr && (int)_fd->fd != -1)
 | 
			
		||||
                    WSAEventSelect(_fd->fd, _event, 0);
 | 
			
		||||
                WSACloseEvent(_event);
 | 
			
		||||
            }
 | 
			
		||||
@@ -171,7 +171,7 @@ namespace ix
 | 
			
		||||
            int count = 0;
 | 
			
		||||
            // WSAWaitForMultipleEvents returns the index of the first signaled event. And to emulate WSAPoll()
 | 
			
		||||
            // all the signaled events must be processed.
 | 
			
		||||
            while (socketIndex < socketEvents.size())
 | 
			
		||||
            while (socketIndex < (int)socketEvents.size())
 | 
			
		||||
            {
 | 
			
		||||
                struct pollfd* fd = socketEvents[socketIndex];
 | 
			
		||||
 | 
			
		||||
@@ -345,7 +345,7 @@ namespace ix
 | 
			
		||||
                    buf[best] = buf[best + 1] = ':';
 | 
			
		||||
                    memmove(buf + best + 2, buf + best + max, i - best - max + 1);
 | 
			
		||||
                }
 | 
			
		||||
                if (strlen(buf) < l)
 | 
			
		||||
                if (strlen(buf) < (size_t)l)
 | 
			
		||||
                {
 | 
			
		||||
                    strcpy(s, buf);
 | 
			
		||||
                    return s;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,10 @@
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#ifdef __FreeBSD__
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ namespace ix
 | 
			
		||||
        mbedtls_pk_init(&_pkey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SocketMbedTLS::loadSystemCertificates(std::string& /* errorMsg */)
 | 
			
		||||
    bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg)
 | 
			
		||||
    {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
// For manipulating the certificate store
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <wincrypt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +50,7 @@ namespace
 | 
			
		||||
        X509_STORE* opensslStore = SSL_CTX_get_cert_store(ssl);
 | 
			
		||||
 | 
			
		||||
        int certificateCount = 0;
 | 
			
		||||
        while (certificateIterator = CertEnumCertificatesInStore(systemStore, certificateIterator))
 | 
			
		||||
        while ((certificateIterator = CertEnumCertificatesInStore(systemStore, certificateIterator)))
 | 
			
		||||
        {
 | 
			
		||||
            X509* x509 = d2i_X509(NULL,
 | 
			
		||||
                                  (const unsigned char**) &certificateIterator->pbCertEncoded,
 | 
			
		||||
@@ -293,10 +294,16 @@ namespace ix
 | 
			
		||||
     */
 | 
			
		||||
    bool SocketOpenSSL::checkHost(const std::string& host, const char* pattern)
 | 
			
		||||
    {
 | 
			
		||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
 | 
			
		||||
        return true;
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        return PathMatchSpecA(host.c_str(), pattern);
 | 
			
		||||
#else
 | 
			
		||||
        return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -219,6 +219,10 @@ namespace ix
 | 
			
		||||
        if (_gcThread.joinable())
 | 
			
		||||
        {
 | 
			
		||||
            _stopGc = true;
 | 
			
		||||
            {
 | 
			
		||||
                std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC };
 | 
			
		||||
                _canContinueGC = true;
 | 
			
		||||
            }
 | 
			
		||||
            _conditionVariableGC.notify_one();
 | 
			
		||||
            _gcThread.join();
 | 
			
		||||
            _stopGc = false;
 | 
			
		||||
@@ -451,7 +455,10 @@ namespace ix
 | 
			
		||||
            if (!_stopGc)
 | 
			
		||||
            {
 | 
			
		||||
                std::unique_lock<std::mutex> lock(_conditionVariableMutexGC);
 | 
			
		||||
                _conditionVariableGC.wait(lock);
 | 
			
		||||
                if(!_canContinueGC) {
 | 
			
		||||
                    _conditionVariableGC.wait(lock, [this]{ return _canContinueGC; });
 | 
			
		||||
                }
 | 
			
		||||
                _canContinueGC = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -465,6 +472,10 @@ namespace ix
 | 
			
		||||
    {
 | 
			
		||||
        // a connection got terminated, we can run the connection thread GC,
 | 
			
		||||
        // so wake up the thread responsible for that
 | 
			
		||||
        {
 | 
			
		||||
            std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC };
 | 
			
		||||
            _canContinueGC = true;
 | 
			
		||||
        }
 | 
			
		||||
        _conditionVariableGC.notify_one();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -126,5 +126,6 @@ namespace ix
 | 
			
		||||
        // as a connection
 | 
			
		||||
        std::condition_variable _conditionVariableGC;
 | 
			
		||||
        std::mutex _conditionVariableMutexGC;
 | 
			
		||||
        bool _canContinueGC{ false };
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@ namespace ix
 | 
			
		||||
        , _enablePong(kDefaultEnablePong)
 | 
			
		||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
			
		||||
        , _pingType(SendMessageKind::Ping)
 | 
			
		||||
        , _autoThreadName(true)
 | 
			
		||||
    {
 | 
			
		||||
        _ws.setOnCloseCallback(
 | 
			
		||||
            [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote)
 | 
			
		||||
@@ -369,8 +370,11 @@ namespace ix
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocket::run()
 | 
			
		||||
    {
 | 
			
		||||
        if (_autoThreadName)
 | 
			
		||||
        {
 | 
			
		||||
            setThreadName(getUrl());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool firstConnectionAttempt = true;
 | 
			
		||||
 | 
			
		||||
@@ -627,4 +631,9 @@ namespace ix
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
			
		||||
        return _subProtocols;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocket::setAutoThreadName(bool enabled)
 | 
			
		||||
    {
 | 
			
		||||
        _autoThreadName = enabled;
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -119,6 +119,8 @@ namespace ix
 | 
			
		||||
        uint32_t getMinWaitBetweenReconnectionRetries() const;
 | 
			
		||||
        const std::vector<std::string>& getSubProtocols();
 | 
			
		||||
 | 
			
		||||
        void setAutoThreadName(bool enabled);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        WebSocketSendInfo sendMessage(const IXWebSocketSendData& message,
 | 
			
		||||
                                      SendMessageKind sendMessageKind,
 | 
			
		||||
@@ -182,6 +184,9 @@ namespace ix
 | 
			
		||||
        // Subprotocols
 | 
			
		||||
        std::vector<std::string> _subProtocols;
 | 
			
		||||
 | 
			
		||||
        // enable or disable auto set thread name
 | 
			
		||||
        bool _autoThreadName;
 | 
			
		||||
 | 
			
		||||
        friend class WebSocketServer;
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,7 @@ namespace ix
 | 
			
		||||
    WebSocketInitResult WebSocketHandshake::clientHandshake(
 | 
			
		||||
        const std::string& url,
 | 
			
		||||
        const WebSocketHttpHeaders& extraHeaders,
 | 
			
		||||
        const std::string& protocol,
 | 
			
		||||
        const std::string& host,
 | 
			
		||||
        const std::string& path,
 | 
			
		||||
        int port,
 | 
			
		||||
@@ -125,6 +126,12 @@ namespace ix
 | 
			
		||||
            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set an origin header if missing
 | 
			
		||||
        if (extraHeaders.find("Origin") == extraHeaders.end())
 | 
			
		||||
        {
 | 
			
		||||
            ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (auto& it : extraHeaders)
 | 
			
		||||
        {
 | 
			
		||||
            ss << it.first << ": " << it.second << "\r\n";
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        WebSocketInitResult clientHandshake(const std::string& url,
 | 
			
		||||
                                            const WebSocketHttpHeaders& extraHeaders,
 | 
			
		||||
                                            const std::string& protocol,
 | 
			
		||||
                                            const std::string& host,
 | 
			
		||||
                                            const std::string& path,
 | 
			
		||||
                                            int port,
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ namespace ix
 | 
			
		||||
        server.setOnConnectionCallback(
 | 
			
		||||
            [remoteUrl, remoteUrlsMapping](std::weak_ptr<ix::WebSocket> webSocket,
 | 
			
		||||
                                           std::shared_ptr<ConnectionState> connectionState) {
 | 
			
		||||
                auto state = std::dynamic_pointer_cast<ProxyConnectionState>(connectionState);
 | 
			
		||||
                auto state = std::static_pointer_cast<ProxyConnectionState>(connectionState);
 | 
			
		||||
                auto remoteIp = connectionState->getRemoteIp();
 | 
			
		||||
 | 
			
		||||
                // Server connection
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,9 @@ namespace ix
 | 
			
		||||
        setThreadName("Srv:ws:" + connectionState->getId());
 | 
			
		||||
 | 
			
		||||
        auto webSocket = std::make_shared<WebSocket>();
 | 
			
		||||
 | 
			
		||||
        webSocket->setAutoThreadName(false);
 | 
			
		||||
 | 
			
		||||
        if (_onConnectionCallback)
 | 
			
		||||
        {
 | 
			
		||||
            _onConnectionCallback(webSocket, connectionState);
 | 
			
		||||
 
 | 
			
		||||
@@ -71,10 +71,10 @@ namespace ix
 | 
			
		||||
        , _closingTimePoint(std::chrono::steady_clock::now())
 | 
			
		||||
        , _enablePong(kDefaultEnablePong)
 | 
			
		||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
			
		||||
        , _pongReceived(false)
 | 
			
		||||
        , _setCustomMessage(false)
 | 
			
		||||
        , _kPingMessage("ixwebsocket::heartbeat")
 | 
			
		||||
        , _pingType(SendMessageKind::Ping)
 | 
			
		||||
        , _pongReceived(false)
 | 
			
		||||
        , _pingCount(0)
 | 
			
		||||
        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
			
		||||
    {
 | 
			
		||||
@@ -140,7 +140,7 @@ namespace ix
 | 
			
		||||
                                                  _enablePerMessageDeflate);
 | 
			
		||||
 | 
			
		||||
            result = webSocketHandshake.clientHandshake(
 | 
			
		||||
                remoteUrl, headers, host, path, port, timeoutSecs);
 | 
			
		||||
                remoteUrl, headers, protocol, host, path, port, timeoutSecs);
 | 
			
		||||
 | 
			
		||||
            if (result.http_status >= 300 && result.http_status < 400)
 | 
			
		||||
            {
 | 
			
		||||
@@ -700,6 +700,7 @@ namespace ix
 | 
			
		||||
                if (_readyState != ReadyState::CLOSING)
 | 
			
		||||
                {
 | 
			
		||||
                    // send back the CLOSE frame
 | 
			
		||||
                    setReadyState(ReadyState::CLOSING);
 | 
			
		||||
                    sendCloseFrame(code, reason);
 | 
			
		||||
 | 
			
		||||
                    wakeUpFromPoll(SelectInterrupt::kCloseRequest);
 | 
			
		||||
@@ -1072,7 +1073,10 @@ namespace ix
 | 
			
		||||
            else if (ret <= 0)
 | 
			
		||||
            {
 | 
			
		||||
                closeSocket();
 | 
			
		||||
                if (_readyState != ReadyState::CLOSING)
 | 
			
		||||
                {
 | 
			
		||||
                    setReadyState(ReadyState::CLOSED);
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@@ -1170,7 +1174,22 @@ namespace ix
 | 
			
		||||
    {
 | 
			
		||||
        _requestInitCancellation = true;
 | 
			
		||||
 | 
			
		||||
        if (_readyState == ReadyState::CLOSING || _readyState == ReadyState::CLOSED) return;
 | 
			
		||||
        if (_readyState == ReadyState::CLOSING || _readyState == ReadyState::CLOSED)
 | 
			
		||||
        {
 | 
			
		||||
            // Wake up the socket polling thread, as
 | 
			
		||||
            // Socket::isReadyToRead() might be still waiting the
 | 
			
		||||
            // interrupt event to happen.
 | 
			
		||||
            bool wakeUpPoll = false;
 | 
			
		||||
            {
 | 
			
		||||
              std::lock_guard<std::mutex> lock(_socketMutex);
 | 
			
		||||
              wakeUpPoll = (_socket && _socket->isWakeUpFromPollSupported());
 | 
			
		||||
            }
 | 
			
		||||
            if (wakeUpPoll)
 | 
			
		||||
            {
 | 
			
		||||
                wakeUpFromPoll(SelectInterrupt::kCloseRequest);
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (closeWireSize == 0)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <deque>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
@@ -157,7 +156,7 @@ namespace ix
 | 
			
		||||
        // Contains all messages that were fetched in the last socket read.
 | 
			
		||||
        // This could be a mix of control messages (Close, Ping, etc...) and
 | 
			
		||||
        // data messages. That buffer is resized
 | 
			
		||||
        std::deque<uint8_t> _rxbuf;
 | 
			
		||||
        std::vector<uint8_t> _rxbuf;
 | 
			
		||||
 | 
			
		||||
        // Contains all messages that are waiting to be sent
 | 
			
		||||
        std::vector<uint8_t> _txbuf;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.4.3"
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.4.4"
 | 
			
		||||
 
 | 
			
		||||
@@ -13,16 +13,24 @@ all: brew
 | 
			
		||||
 | 
			
		||||
install: brew
 | 
			
		||||
 | 
			
		||||
-DCMAKE_INSTALL_PREFIX=/opt/homebrew
 | 
			
		||||
 | 
			
		||||
# Use -DCMAKE_INSTALL_PREFIX= to install into another location
 | 
			
		||||
# on osx it is good practice to make /usr/local user writable
 | 
			
		||||
# sudo chown -R `whoami`/staff /usr/local
 | 
			
		||||
#
 | 
			
		||||
# Those days (since Apple Silicon mac shipped), on macOS homebrew installs in /opt/homebrew, and /usr/local is readonly
 | 
			
		||||
#
 | 
			
		||||
# Release, Debug, MinSizeRel, RelWithDebInfo are the build types
 | 
			
		||||
#
 | 
			
		||||
# Default rule does not use python as that requires first time users to have Python3 installed
 | 
			
		||||
#
 | 
			
		||||
brew:
 | 
			
		||||
ifeq ($(shell uname),Darwin)
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/homebrew -DCMAKE_UNITY_BUILD=OFF -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
			
		||||
else
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=OFF -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Docker default target. We've had problems with OpenSSL and TLS 1.3 (on the
 | 
			
		||||
# server side ?) and I can't work-around it easily, so we're using mbedtls on
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ set (TEST_TARGET_NAMES
 | 
			
		||||
  IXWebSocketServerTest
 | 
			
		||||
  IXWebSocketTestConnectionDisconnection
 | 
			
		||||
  IXUrlParserTest
 | 
			
		||||
  IXHttpClientTest
 | 
			
		||||
  # IXHttpClientTest ## FIXME httpbin.org does not seem normal
 | 
			
		||||
  IXUnityBuildsTest
 | 
			
		||||
  IXHttpTest
 | 
			
		||||
  IXDNSLookupTest
 | 
			
		||||
@@ -24,14 +24,13 @@ set (TEST_TARGET_NAMES
 | 
			
		||||
  # IXWebSocketBroadcastTest ## FIXME was depending on cobra / take a broadcast server from ws
 | 
			
		||||
  IXStrCaseCompareTest
 | 
			
		||||
  IXExponentialBackoffTest
 | 
			
		||||
  IXWebSocketCloseTest
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Some unittest don't work on windows yet
 | 
			
		||||
# Windows without TLS does not have hmac yet
 | 
			
		||||
if (UNIX)
 | 
			
		||||
  list(APPEND TEST_TARGET_NAMES
 | 
			
		||||
    IXWebSocketCloseTest
 | 
			
		||||
 | 
			
		||||
    # Fail on Windows in CI probably because the pathing is wrong and
 | 
			
		||||
    # some resource files cannot be found
 | 
			
		||||
    IXHttpServerTest
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,7 @@ TEST_CASE("http server", "[httpd]")
 | 
			
		||||
        REQUIRE(response->errorCode == HttpErrorCode::Ok);
 | 
			
		||||
        REQUIRE(response->statusCode == 200);
 | 
			
		||||
        REQUIRE(response->headers["Accept-Encoding"] == "gzip");
 | 
			
		||||
        REQUIRE(response->headers["Content-Encoding"] == "gzip");
 | 
			
		||||
 | 
			
		||||
        server.stop();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user