Compare commits
	
		
			1 Commits
		
	
	
		
			feature/te
			...
			bsergean-p
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					56f5527726 | 
							
								
								
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
name: Mark stale issues and pull requests
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  schedule:
 | 
			
		||||
  - cron: "0 0 * * *"
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  stale:
 | 
			
		||||
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/stale@v1
 | 
			
		||||
      with:
 | 
			
		||||
        repo-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
        stale-issue-message: 'Stale issue message'
 | 
			
		||||
        stale-pr-message: 'Stale pull request message'
 | 
			
		||||
        stale-issue-label: 'no-issue-activity'
 | 
			
		||||
        stale-pr-label: 'no-pr-activity'
 | 
			
		||||
@@ -11,7 +11,6 @@ project(ixwebsocket C CXX)
 | 
			
		||||
set (CMAKE_CXX_STANDARD 11)
 | 
			
		||||
set (CXX_STANDARD_REQUIRED ON)
 | 
			
		||||
set (CMAKE_CXX_EXTENSIONS OFF)
 | 
			
		||||
set (CMAKE_EXPORT_COMPILE_COMMANDS yes)
 | 
			
		||||
 | 
			
		||||
option (BUILD_DEMO OFF)
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +66,6 @@ set( IXWEBSOCKET_SOURCES
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set( IXWEBSOCKET_HEADERS
 | 
			
		||||
    ixwebsocket/IXBase64.h
 | 
			
		||||
    ixwebsocket/IXBench.h
 | 
			
		||||
    ixwebsocket/IXCancellationRequest.h
 | 
			
		||||
    ixwebsocket/IXConnectionState.h
 | 
			
		||||
@@ -251,7 +249,7 @@ if (WIN32)
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (UNIX AND NOT APPLE)
 | 
			
		||||
if (UNIX)
 | 
			
		||||
  set(THREADS_PREFER_PTHREAD_FLAG TRUE)
 | 
			
		||||
  find_package(Threads)
 | 
			
		||||
  target_link_libraries(ixwebsocket PRIVATE Threads::Threads)
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,6 @@ int main()
 | 
			
		||||
 | 
			
		||||
    // Connect to a server with encryption
 | 
			
		||||
    // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration
 | 
			
		||||
    //     https://github.com/machinezone/IXWebSocket/issues/386#issuecomment-1105235227 (self signed certificates)
 | 
			
		||||
    std::string url("wss://echo.websocket.org");
 | 
			
		||||
    webSocket.setUrl(url);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,6 @@
 | 
			
		||||
 | 
			
		||||
All changes to this project will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## [11.4.3] - 2022-05-13
 | 
			
		||||
 | 
			
		||||
Set shorter thread names
 | 
			
		||||
BoringSSL fix with SNI
 | 
			
		||||
Websocket computed header is valid Base64
 | 
			
		||||
 | 
			
		||||
## [11.4.1] - 2022-04-23
 | 
			
		||||
 | 
			
		||||
vckpg + cmake fix, to handle zlib as a dependency better
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ To use the installed package within a cmake project, use the following:
 | 
			
		||||
 # include headers
 | 
			
		||||
 include_directories(${IXWEBSOCKET_INCLUDE_DIR})
 | 
			
		||||
 # ...
 | 
			
		||||
 target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUND
 | 
			
		||||
 target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUNS
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -301,9 +301,7 @@ This api was actually changed to take a weak_ptr<WebSocket> as the first argumen
 | 
			
		||||
 | 
			
		||||
// Run a server on localhost at a given port.
 | 
			
		||||
// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
			
		||||
int port = 8008;
 | 
			
		||||
std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0"
 | 
			
		||||
ix::WebSocketServer server(port, host);
 | 
			
		||||
ix::WebSocketServer server(port);
 | 
			
		||||
 | 
			
		||||
server.setOnConnectionCallback(
 | 
			
		||||
    [&server](std::weak_ptr<WebSocket> webSocket,
 | 
			
		||||
@@ -386,9 +384,7 @@ The webSocket reference is guaranteed to be always valid ; by design the callbac
 | 
			
		||||
 | 
			
		||||
// Run a server on localhost at a given port.
 | 
			
		||||
// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
			
		||||
int port = 8008;
 | 
			
		||||
std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0"
 | 
			
		||||
ix::WebSocketServer server(port, host);
 | 
			
		||||
ix::WebSocketServer server(port);
 | 
			
		||||
 | 
			
		||||
server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) {
 | 
			
		||||
    // The ConnectionState object contains information about the connection,
 | 
			
		||||
@@ -628,5 +624,3 @@ For a client, specifying `caFile` can be used if connecting to a server that use
 | 
			
		||||
For a server, specifying `caFile` implies that:
 | 
			
		||||
1. You require clients to present a certificate
 | 
			
		||||
1. It must be signed by one of the trusted roots in the file
 | 
			
		||||
 | 
			
		||||
By default, a destination's hostname is always validated against the certificate that it presents. To accept certificates with any hostname, set `ix::SocketTLSOptions::disable_hostname_validation` to `true`.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,125 +0,0 @@
 | 
			
		||||
#ifndef _MACARON_BASE64_H_
 | 
			
		||||
#define _MACARON_BASE64_H_
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License (MIT)
 | 
			
		||||
 * Copyright (c) 2016 tomykaira
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
 * a copy of this software and associated documentation files (the
 | 
			
		||||
 * "Software"), to deal in the Software without restriction, including
 | 
			
		||||
 * without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
 * distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
 * permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
 * the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be
 | 
			
		||||
 * included in all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
			
		||||
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
			
		||||
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
			
		||||
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace macaron {
 | 
			
		||||
 | 
			
		||||
class Base64 {
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  static std::string Encode(const std::string data) {
 | 
			
		||||
    static constexpr char sEncodingTable[] = {
 | 
			
		||||
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
 | 
			
		||||
      'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
 | 
			
		||||
      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
 | 
			
		||||
      'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
 | 
			
		||||
      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
 | 
			
		||||
      'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 | 
			
		||||
      'w', 'x', 'y', 'z', '0', '1', '2', '3',
 | 
			
		||||
      '4', '5', '6', '7', '8', '9', '+', '/'
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    size_t in_len = data.size();
 | 
			
		||||
    size_t out_len = 4 * ((in_len + 2) / 3);
 | 
			
		||||
    std::string ret(out_len, '\0');
 | 
			
		||||
    size_t i;
 | 
			
		||||
    char *p = const_cast<char*>(ret.c_str());
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < in_len - 2; i += 3) {
 | 
			
		||||
      *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
 | 
			
		||||
      *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
 | 
			
		||||
      *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)];
 | 
			
		||||
      *p++ = sEncodingTable[data[i + 2] & 0x3F];
 | 
			
		||||
    }
 | 
			
		||||
    if (i < in_len) {
 | 
			
		||||
      *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
 | 
			
		||||
      if (i == (in_len - 1)) {
 | 
			
		||||
        *p++ = sEncodingTable[((data[i] & 0x3) << 4)];
 | 
			
		||||
        *p++ = '=';
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
 | 
			
		||||
        *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
 | 
			
		||||
      }
 | 
			
		||||
      *p++ = '=';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static std::string Decode(const std::string& input, std::string& out) {
 | 
			
		||||
    static constexpr unsigned char kDecodingTable[] = {
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
 | 
			
		||||
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
 | 
			
		||||
      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 | 
			
		||||
      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 | 
			
		||||
      64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    size_t in_len = input.size();
 | 
			
		||||
    if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
 | 
			
		||||
 | 
			
		||||
    size_t out_len = in_len / 4 * 3;
 | 
			
		||||
    if (input[in_len - 1] == '=') out_len--;
 | 
			
		||||
    if (input[in_len - 2] == '=') out_len--;
 | 
			
		||||
 | 
			
		||||
    out.resize(out_len);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0, j = 0; i < in_len;) {
 | 
			
		||||
      uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
 | 
			
		||||
      uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
 | 
			
		||||
      uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
 | 
			
		||||
      uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
 | 
			
		||||
 | 
			
		||||
      uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
 | 
			
		||||
 | 
			
		||||
      if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
 | 
			
		||||
      if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
 | 
			
		||||
      if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _MACARON_BASE64_H_ */
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
// mingw build quirks
 | 
			
		||||
#if defined(_WIN32) && defined(__GNUC__)
 | 
			
		||||
@@ -45,7 +44,7 @@ namespace ix
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DNSLookup::AddrInfoPtr DNSLookup::getAddrInfo(const std::string& hostname,
 | 
			
		||||
    struct addrinfo* DNSLookup::getAddrInfo(const std::string& hostname,
 | 
			
		||||
                                            int port,
 | 
			
		||||
                                            std::string& errMsg)
 | 
			
		||||
    {
 | 
			
		||||
@@ -64,10 +63,10 @@ namespace ix
 | 
			
		||||
            errMsg = gai_strerror(getaddrinfo_result);
 | 
			
		||||
            res = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
        return AddrInfoPtr{ res, freeaddrinfo };
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DNSLookup::AddrInfoPtr DNSLookup::resolve(std::string& errMsg,
 | 
			
		||||
    struct addrinfo* DNSLookup::resolve(std::string& errMsg,
 | 
			
		||||
                                        const CancellationRequest& isCancellationRequested,
 | 
			
		||||
                                        bool cancellable)
 | 
			
		||||
    {
 | 
			
		||||
@@ -75,7 +74,12 @@ namespace ix
 | 
			
		||||
                           : resolveUnCancellable(errMsg, isCancellationRequested);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DNSLookup::AddrInfoPtr DNSLookup::resolveUnCancellable(
 | 
			
		||||
    void DNSLookup::release(struct addrinfo* addr)
 | 
			
		||||
    {
 | 
			
		||||
        freeaddrinfo(addr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct addrinfo* DNSLookup::resolveUnCancellable(
 | 
			
		||||
        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
			
		||||
    {
 | 
			
		||||
        errMsg = "no error";
 | 
			
		||||
@@ -90,7 +94,7 @@ namespace ix
 | 
			
		||||
        return getAddrInfo(_hostname, _port, errMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DNSLookup::AddrInfoPtr DNSLookup::resolveCancellable(
 | 
			
		||||
    struct addrinfo* DNSLookup::resolveCancellable(
 | 
			
		||||
        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
			
		||||
    {
 | 
			
		||||
        errMsg = "no error";
 | 
			
		||||
@@ -153,7 +157,7 @@ namespace ix
 | 
			
		||||
        // gone, so we use temporary variables (res) or we pass in by copy everything that
 | 
			
		||||
        // getAddrInfo needs to work.
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        auto res = getAddrInfo(hostname, port, errMsg);
 | 
			
		||||
        struct addrinfo* res = getAddrInfo(hostname, port, errMsg);
 | 
			
		||||
 | 
			
		||||
        if (auto lock = self.lock())
 | 
			
		||||
        {
 | 
			
		||||
@@ -177,13 +181,13 @@ namespace ix
 | 
			
		||||
        return _errMsg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void DNSLookup::setRes(DNSLookup::AddrInfoPtr addr)
 | 
			
		||||
    void DNSLookup::setRes(struct addrinfo* addr)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_resMutex);
 | 
			
		||||
        _res = std::move(addr);
 | 
			
		||||
        _res = addr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DNSLookup::AddrInfoPtr DNSLookup::getRes()
 | 
			
		||||
    struct addrinfo* DNSLookup::getRes()
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_resMutex);
 | 
			
		||||
        return _res;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
 | 
			
		||||
#include "IXCancellationRequest.h"
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <set>
 | 
			
		||||
@@ -25,21 +24,22 @@ namespace ix
 | 
			
		||||
    class DNSLookup : public std::enable_shared_from_this<DNSLookup>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        using AddrInfoPtr = std::shared_ptr<addrinfo>;
 | 
			
		||||
        DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait);
 | 
			
		||||
        ~DNSLookup() = default;
 | 
			
		||||
 | 
			
		||||
        AddrInfoPtr resolve(std::string& errMsg,
 | 
			
		||||
        struct addrinfo* resolve(std::string& errMsg,
 | 
			
		||||
                                 const CancellationRequest& isCancellationRequested,
 | 
			
		||||
                                 bool cancellable = true);
 | 
			
		||||
 | 
			
		||||
        void release(struct addrinfo* addr);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        AddrInfoPtr resolveCancellable(std::string& errMsg,
 | 
			
		||||
        struct addrinfo* resolveCancellable(std::string& errMsg,
 | 
			
		||||
                                            const CancellationRequest& isCancellationRequested);
 | 
			
		||||
        AddrInfoPtr resolveUnCancellable(std::string& errMsg,
 | 
			
		||||
        struct addrinfo* resolveUnCancellable(std::string& errMsg,
 | 
			
		||||
                                              const CancellationRequest& isCancellationRequested);
 | 
			
		||||
 | 
			
		||||
        AddrInfoPtr getAddrInfo(const std::string& hostname,
 | 
			
		||||
        static struct addrinfo* getAddrInfo(const std::string& hostname,
 | 
			
		||||
                                            int port,
 | 
			
		||||
                                            std::string& errMsg);
 | 
			
		||||
 | 
			
		||||
@@ -48,15 +48,15 @@ namespace ix
 | 
			
		||||
        void setErrMsg(const std::string& errMsg);
 | 
			
		||||
        const std::string& getErrMsg();
 | 
			
		||||
 | 
			
		||||
        void setRes(AddrInfoPtr addr);
 | 
			
		||||
        AddrInfoPtr getRes();
 | 
			
		||||
        void setRes(struct addrinfo* addr);
 | 
			
		||||
        struct addrinfo* getRes();
 | 
			
		||||
 | 
			
		||||
        std::string _hostname;
 | 
			
		||||
        int _port;
 | 
			
		||||
        int64_t _wait;
 | 
			
		||||
        const static int64_t kDefaultWait;
 | 
			
		||||
 | 
			
		||||
        AddrInfoPtr _res;
 | 
			
		||||
        struct addrinfo* _res;
 | 
			
		||||
        std::mutex _resMutex;
 | 
			
		||||
 | 
			
		||||
        std::string _errMsg;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
#include "IXProgressCallback.h"
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
#include "IXUserAgent.h"
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <random>
 | 
			
		||||
@@ -140,9 +139,8 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        std::string protocol, host, path, query;
 | 
			
		||||
        int port;
 | 
			
		||||
        bool isProtocolDefaultPort;
 | 
			
		||||
 | 
			
		||||
        if (!UrlParser::parse(url, protocol, host, path, query, port, isProtocolDefaultPort))
 | 
			
		||||
        if (!UrlParser::parse(url, protocol, host, path, query, port))
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream ss;
 | 
			
		||||
            ss << "Cannot parse url: " << url;
 | 
			
		||||
@@ -175,12 +173,7 @@ namespace ix
 | 
			
		||||
        // Build request string
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        ss << verb << " " << path << " HTTP/1.1\r\n";
 | 
			
		||||
        ss << "Host: " << host;
 | 
			
		||||
        if (!isProtocolDefaultPort)
 | 
			
		||||
        {
 | 
			
		||||
            ss << ":" << port;
 | 
			
		||||
        }
 | 
			
		||||
        ss << "\r\n";
 | 
			
		||||
        ss << "Host: " << host << "\r\n";
 | 
			
		||||
 | 
			
		||||
#ifdef IXWEBSOCKET_USE_ZLIB
 | 
			
		||||
        if (args->compress && !args->onChunkCallback)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@
 | 
			
		||||
#include "IXNetSystem.h"
 | 
			
		||||
#include "IXSocketConnect.h"
 | 
			
		||||
#include "IXUserAgent.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
@@ -41,29 +40,6 @@ namespace
 | 
			
		||||
        auto vec = res.second;
 | 
			
		||||
        return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string response_head_file(const std::string& file_name){
 | 
			
		||||
 | 
			
		||||
        if (std::string::npos != file_name.find(".html") || std::string::npos != file_name.find(".htm"))
 | 
			
		||||
            return "text/html";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".css"))
 | 
			
		||||
            return "text/css";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".js") || std::string::npos != file_name.find(".mjs"))
 | 
			
		||||
            return "application/x-javascript";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".ico"))
 | 
			
		||||
            return "image/x-icon";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".png"))
 | 
			
		||||
            return "image/png";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".jpg") || std::string::npos != file_name.find(".jpeg"))
 | 
			
		||||
            return "image/jpeg";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".gif"))
 | 
			
		||||
            return "image/gif";
 | 
			
		||||
        else if (std::string::npos != file_name.find(".svg"))
 | 
			
		||||
            return "image/svg+xml";
 | 
			
		||||
        else
 | 
			
		||||
            return "application/octet-stream";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
@@ -75,14 +51,28 @@ namespace ix
 | 
			
		||||
                           int backlog,
 | 
			
		||||
                           size_t maxConnections,
 | 
			
		||||
                           int addressFamily,
 | 
			
		||||
                           int timeoutSecs,
 | 
			
		||||
                           int handshakeTimeoutSecs)
 | 
			
		||||
        : WebSocketServer(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily)
 | 
			
		||||
                           int timeoutSecs)
 | 
			
		||||
        : SocketServer(port, host, backlog, maxConnections, addressFamily)
 | 
			
		||||
        , _connectedClientsCount(0)
 | 
			
		||||
        , _timeoutSecs(timeoutSecs)
 | 
			
		||||
    {
 | 
			
		||||
        setDefaultConnectionCallback();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HttpServer::~HttpServer()
 | 
			
		||||
    {
 | 
			
		||||
        stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void HttpServer::stop()
 | 
			
		||||
    {
 | 
			
		||||
        stopAcceptingConnections();
 | 
			
		||||
 | 
			
		||||
        // FIXME: cancelling / closing active clients ...
 | 
			
		||||
 | 
			
		||||
        SocketServer::stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback)
 | 
			
		||||
    {
 | 
			
		||||
        _onConnectionCallback = callback;
 | 
			
		||||
@@ -91,35 +81,34 @@ namespace ix
 | 
			
		||||
    void HttpServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                      std::shared_ptr<ConnectionState> connectionState)
 | 
			
		||||
    {
 | 
			
		||||
        _connectedClientsCount++;
 | 
			
		||||
 | 
			
		||||
        auto ret = Http::parseRequest(socket, _timeoutSecs);
 | 
			
		||||
        // FIXME: handle errors in parseRequest
 | 
			
		||||
 | 
			
		||||
        if (std::get<0>(ret))
 | 
			
		||||
        {
 | 
			
		||||
            auto request = std::get<2>(ret);
 | 
			
		||||
            std::shared_ptr<ix::HttpResponse> response;
 | 
			
		||||
            if (request->headers["Upgrade"] == "websocket")
 | 
			
		||||
            auto response = _onConnectionCallback(std::get<2>(ret), connectionState);
 | 
			
		||||
            if (!Http::sendResponse(response, socket))
 | 
			
		||||
            {
 | 
			
		||||
                WebSocketServer::handleUpgrade(std::move(socket), connectionState, request);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto response = _onConnectionCallback(request, connectionState);
 | 
			
		||||
                if (!Http::sendResponse(response, socket))
 | 
			
		||||
                {
 | 
			
		||||
                    logError("Cannot send response");
 | 
			
		||||
                }
 | 
			
		||||
                logError("Cannot send response");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        connectionState->setTerminated();
 | 
			
		||||
 | 
			
		||||
        _connectedClientsCount--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t HttpServer::getConnectedClientsCount()
 | 
			
		||||
    {
 | 
			
		||||
        return _connectedClientsCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void HttpServer::setDefaultConnectionCallback()
 | 
			
		||||
    {
 | 
			
		||||
        setOnConnectionCallback(
 | 
			
		||||
            [this](HttpRequestPtr request,
 | 
			
		||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
			
		||||
            {
 | 
			
		||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
			
		||||
                std::string uri(request->uri);
 | 
			
		||||
                if (uri.empty() || uri == "/")
 | 
			
		||||
                {
 | 
			
		||||
@@ -128,7 +117,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
                WebSocketHttpHeaders headers;
 | 
			
		||||
                headers["Server"] = userAgent();
 | 
			
		||||
                headers["Content-Type"] = response_head_file(uri);
 | 
			
		||||
 | 
			
		||||
                std::string path("." + uri);
 | 
			
		||||
                auto res = readAsString(path);
 | 
			
		||||
@@ -177,9 +165,9 @@ namespace ix
 | 
			
		||||
        // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
 | 
			
		||||
        //
 | 
			
		||||
        setOnConnectionCallback(
 | 
			
		||||
            [this, redirectUrl](HttpRequestPtr request,
 | 
			
		||||
                                std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
			
		||||
            {
 | 
			
		||||
            [this,
 | 
			
		||||
             redirectUrl](HttpRequestPtr request,
 | 
			
		||||
                          std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
			
		||||
                WebSocketHttpHeaders headers;
 | 
			
		||||
                headers["Server"] = userAgent();
 | 
			
		||||
 | 
			
		||||
@@ -210,8 +198,7 @@ namespace ix
 | 
			
		||||
    {
 | 
			
		||||
        setOnConnectionCallback(
 | 
			
		||||
            [this](HttpRequestPtr request,
 | 
			
		||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
			
		||||
            {
 | 
			
		||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
			
		||||
                WebSocketHttpHeaders headers;
 | 
			
		||||
                headers["Server"] = userAgent();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,8 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include "IXSocketServer.h"
 | 
			
		||||
#include "IXWebSocket.h"
 | 
			
		||||
#include "IXWebSocketServer.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    class HttpServer final : public WebSocketServer
 | 
			
		||||
    class HttpServer final : public SocketServer
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        using OnConnectionCallback =
 | 
			
		||||
@@ -30,8 +30,9 @@ namespace ix
 | 
			
		||||
                   int backlog = SocketServer::kDefaultTcpBacklog,
 | 
			
		||||
                   size_t maxConnections = SocketServer::kDefaultMaxConnections,
 | 
			
		||||
                   int addressFamily = SocketServer::kDefaultAddressFamily,
 | 
			
		||||
                   int timeoutSecs = HttpServer::kDefaultTimeoutSecs,
 | 
			
		||||
                   int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs);
 | 
			
		||||
                   int timeoutSecs = HttpServer::kDefaultTimeoutSecs);
 | 
			
		||||
        virtual ~HttpServer();
 | 
			
		||||
        virtual void stop() final;
 | 
			
		||||
 | 
			
		||||
        void setOnConnectionCallback(const OnConnectionCallback& callback);
 | 
			
		||||
 | 
			
		||||
@@ -40,10 +41,10 @@ namespace ix
 | 
			
		||||
        void makeDebugServer();
 | 
			
		||||
 | 
			
		||||
        int getTimeoutSecs();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        // Member variables
 | 
			
		||||
        OnConnectionCallback _onConnectionCallback;
 | 
			
		||||
        std::atomic<int> _connectedClientsCount;
 | 
			
		||||
 | 
			
		||||
        const static int kDefaultTimeoutSecs;
 | 
			
		||||
        int _timeoutSecs;
 | 
			
		||||
@@ -51,6 +52,7 @@ namespace ix
 | 
			
		||||
        // Methods
 | 
			
		||||
        virtual void handleConnection(std::unique_ptr<Socket>,
 | 
			
		||||
                                      std::shared_ptr<ConnectionState> connectionState) final;
 | 
			
		||||
        virtual size_t getConnectedClientsCount() final;
 | 
			
		||||
 | 
			
		||||
        void setDefaultConnectionCallback();
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IXSelectInterrupt.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IXSelectInterrupt.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
 
 | 
			
		||||
@@ -205,9 +205,7 @@ namespace ix
 | 
			
		||||
                _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
 | 
			
		||||
            SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
 | 
			
		||||
            SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
 | 
			
		||||
 | 
			
		||||
            if (!_tlsOptions.disable_hostname_validation)
 | 
			
		||||
                SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
			
		||||
            SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
			
		||||
 | 
			
		||||
            if (_tlsOptions.isPeerVerifyDisabled())
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -102,7 +102,7 @@ namespace ix
 | 
			
		||||
        // First do DNS resolution
 | 
			
		||||
        //
 | 
			
		||||
        auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
 | 
			
		||||
        auto res = dnsLookup->resolve(errMsg, isCancellationRequested);
 | 
			
		||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested);
 | 
			
		||||
        if (res == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            return -1;
 | 
			
		||||
@@ -112,7 +112,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        // iterate through the records to find a working peer
 | 
			
		||||
        struct addrinfo* address;
 | 
			
		||||
        for (address = res.get(); address != nullptr; address = address->ai_next)
 | 
			
		||||
        for (address = res; address != nullptr; address = address->ai_next)
 | 
			
		||||
        {
 | 
			
		||||
            //
 | 
			
		||||
            // Second try to connect to the remote host
 | 
			
		||||
@@ -124,6 +124,7 @@ namespace ix
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        freeaddrinfo(res);
 | 
			
		||||
        return sockfd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@
 | 
			
		||||
#include "IXNetSystem.h"
 | 
			
		||||
#include "IXSocket.h"
 | 
			
		||||
#include "IXSocketConnect.h"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
@@ -49,7 +48,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 |
 | 
			
		||||
@@ -196,13 +195,10 @@ namespace ix
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!_tlsOptions.disable_hostname_validation)
 | 
			
		||||
        if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                errMsg = "SNI setup failed";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            errMsg = "SNI setup failed";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -301,11 +301,7 @@ namespace ix
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl,
 | 
			
		||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
 | 
			
		||||
                                               const std::string& hostname,
 | 
			
		||||
#else
 | 
			
		||||
                                               const std::string& /* hostname */,
 | 
			
		||||
#endif
 | 
			
		||||
                                               std::string& errMsg)
 | 
			
		||||
    {
 | 
			
		||||
        X509* server_cert = SSL_get_peer_certificate(ssl);
 | 
			
		||||
@@ -394,11 +390,6 @@ namespace ix
 | 
			
		||||
            int connect_result = SSL_connect(_ssl_connection);
 | 
			
		||||
            if (connect_result == 1)
 | 
			
		||||
            {
 | 
			
		||||
                if (_tlsOptions.disable_hostname_validation)
 | 
			
		||||
                {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return openSSLCheckServerCert(_ssl_connection, host, errMsg);
 | 
			
		||||
            }
 | 
			
		||||
            int reason = SSL_get_error(_ssl_connection, connect_result);
 | 
			
		||||
@@ -763,11 +754,8 @@ namespace ix
 | 
			
		||||
            // (The docs say that this should work from 1.0.2, and is the default from
 | 
			
		||||
            // 1.1.0, but it does not. To be on the safe side, the manual test
 | 
			
		||||
            // below is enabled for all versions prior to 1.1.0.)
 | 
			
		||||
            if (!_tlsOptions.disable_hostname_validation)
 | 
			
		||||
            {
 | 
			
		||||
                X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
			
		||||
                X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size());
 | 
			
		||||
            }
 | 
			
		||||
            X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
			
		||||
            X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
 | 
			
		||||
#endif
 | 
			
		||||
            handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -268,10 +268,7 @@ namespace ix
 | 
			
		||||
        // Set the socket to non blocking mode, so that accept calls are not blocking
 | 
			
		||||
        SocketConnect::configure(_serverFd);
 | 
			
		||||
 | 
			
		||||
        // Use a cryptic name to stay within the 16 bytes limit thread name limitation
 | 
			
		||||
        // $ echo Srv:gc:64000 | wc -c
 | 
			
		||||
        // 13
 | 
			
		||||
        setThreadName("Srv:ac:" + std::to_string(_port));
 | 
			
		||||
        setThreadName("SocketServer::accept");
 | 
			
		||||
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
@@ -428,10 +425,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
    void SocketServer::runGC()
 | 
			
		||||
    {
 | 
			
		||||
        // Use a cryptic name to stay within the 16 bytes limit thread name limitation
 | 
			
		||||
        // $ echo Srv:gc:64000 | wc -c
 | 
			
		||||
        // 13
 | 
			
		||||
        setThreadName("Srv:gc:" + std::to_string(_port));
 | 
			
		||||
        setThreadName("SocketServer::GC");
 | 
			
		||||
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -33,9 +33,6 @@ namespace ix
 | 
			
		||||
        // whether tls is enabled, used for server code
 | 
			
		||||
        bool tls = false;
 | 
			
		||||
 | 
			
		||||
        // whether to skip validating the peer's hostname against the certificate presented
 | 
			
		||||
        bool disable_hostname_validation = false;
 | 
			
		||||
 | 
			
		||||
        bool hasCertAndKey() const;
 | 
			
		||||
 | 
			
		||||
        bool isUsingSystemDefaults() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -333,19 +333,6 @@ namespace
 | 
			
		||||
 | 
			
		||||
        return Result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int getProtocolPort(const std::string& protocol)
 | 
			
		||||
    {
 | 
			
		||||
        if (protocol == "ws" || protocol == "http")
 | 
			
		||||
        {
 | 
			
		||||
            return 80;
 | 
			
		||||
        }
 | 
			
		||||
        else if (protocol == "wss" || protocol == "https")
 | 
			
		||||
        {
 | 
			
		||||
            return 443;
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
@@ -356,18 +343,6 @@ namespace ix
 | 
			
		||||
                          std::string& path,
 | 
			
		||||
                          std::string& query,
 | 
			
		||||
                          int& port)
 | 
			
		||||
    {
 | 
			
		||||
        bool isProtocolDefaultPort;
 | 
			
		||||
        return parse(url, protocol, host, path, query, port, isProtocolDefaultPort);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool UrlParser::parse(const std::string& url,
 | 
			
		||||
                              std::string& protocol,
 | 
			
		||||
                              std::string& host,
 | 
			
		||||
                              std::string& path,
 | 
			
		||||
                              std::string& query,
 | 
			
		||||
                              int& port,
 | 
			
		||||
                              bool& isProtocolDefaultPort)
 | 
			
		||||
    {
 | 
			
		||||
        clParseURL res = clParseURL::ParseURL(url);
 | 
			
		||||
 | 
			
		||||
@@ -381,12 +356,23 @@ namespace ix
 | 
			
		||||
        path = res.m_Path;
 | 
			
		||||
        query = res.m_Query;
 | 
			
		||||
 | 
			
		||||
        const auto protocolPort = getProtocolPort(protocol);
 | 
			
		||||
        if (!res.GetPort(&port))
 | 
			
		||||
        {
 | 
			
		||||
            port = protocolPort;
 | 
			
		||||
            if (protocol == "ws" || protocol == "http")
 | 
			
		||||
            {
 | 
			
		||||
                port = 80;
 | 
			
		||||
            }
 | 
			
		||||
            else if (protocol == "wss" || protocol == "https")
 | 
			
		||||
            {
 | 
			
		||||
                port = 443;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Invalid protocol. Should be caught by regex check
 | 
			
		||||
                // but this missing branch trigger cpplint linter.
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        isProtocolDefaultPort = port == protocolPort;
 | 
			
		||||
 | 
			
		||||
        if (path.empty())
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,13 +19,5 @@ namespace ix
 | 
			
		||||
                          std::string& path,
 | 
			
		||||
                          std::string& query,
 | 
			
		||||
                          int& port);
 | 
			
		||||
 | 
			
		||||
        static bool parse(const std::string& url,
 | 
			
		||||
                          std::string& protocol,
 | 
			
		||||
                          std::string& host,
 | 
			
		||||
                          std::string& path,
 | 
			
		||||
                          std::string& query,
 | 
			
		||||
                          int& port,
 | 
			
		||||
                          bool& isProtocolDefaultPort);
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@
 | 
			
		||||
 | 
			
		||||
#include "IXUuid.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@
 | 
			
		||||
#include "IXWebSocketHandshake.h"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
@@ -40,11 +39,9 @@ namespace ix
 | 
			
		||||
        , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
 | 
			
		||||
        , _enablePong(kDefaultEnablePong)
 | 
			
		||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
			
		||||
        , _pingType(SendMessageKind::Ping)
 | 
			
		||||
    {
 | 
			
		||||
        _ws.setOnCloseCallback(
 | 
			
		||||
            [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote)
 | 
			
		||||
            {
 | 
			
		||||
            [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) {
 | 
			
		||||
                _onMessageCallback(
 | 
			
		||||
                    ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
			
		||||
                                                      emptyMsg,
 | 
			
		||||
@@ -103,17 +100,6 @@ namespace ix
 | 
			
		||||
        return _perMessageDeflateOptions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocket::setPingMessage(const std::string& sendMessage, SendMessageKind pingType)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
			
		||||
        _pingMessage = sendMessage;
 | 
			
		||||
        _ws.setPingMessage(_pingMessage, pingType);
 | 
			
		||||
    }
 | 
			
		||||
    const std::string WebSocket::getPingMessage() const
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
			
		||||
        return _pingMessage;
 | 
			
		||||
    }
 | 
			
		||||
    void WebSocket::setPingInterval(int pingIntervalSecs)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
			
		||||
@@ -246,7 +232,7 @@ namespace ix
 | 
			
		||||
        if (_pingIntervalSecs > 0)
 | 
			
		||||
        {
 | 
			
		||||
            // Send a heart beat right away
 | 
			
		||||
            _ws.sendHeartBeat(_pingType);
 | 
			
		||||
            _ws.sendHeartBeat();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return status;
 | 
			
		||||
@@ -254,8 +240,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
    WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                                   int timeoutSecs,
 | 
			
		||||
                                                   bool enablePerMessageDeflate,
 | 
			
		||||
                                                   HttpRequestPtr request)
 | 
			
		||||
                                                   bool enablePerMessageDeflate)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            std::lock_guard<std::mutex> lock(_configMutex);
 | 
			
		||||
@@ -264,7 +249,7 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WebSocketInitResult status =
 | 
			
		||||
            _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate, request);
 | 
			
		||||
            _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate);
 | 
			
		||||
        if (!status.success)
 | 
			
		||||
        {
 | 
			
		||||
            return status;
 | 
			
		||||
@@ -281,7 +266,7 @@ namespace ix
 | 
			
		||||
        if (_pingIntervalSecs > 0)
 | 
			
		||||
        {
 | 
			
		||||
            // Send a heart beat right away
 | 
			
		||||
            _ws.sendHeartBeat(_pingType);
 | 
			
		||||
            _ws.sendHeartBeat();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return status;
 | 
			
		||||
@@ -399,9 +384,8 @@ namespace ix
 | 
			
		||||
                [this](const std::string& msg,
 | 
			
		||||
                       size_t wireSize,
 | 
			
		||||
                       bool decompressionError,
 | 
			
		||||
                       WebSocketTransport::MessageKind messageKind)
 | 
			
		||||
                {
 | 
			
		||||
                    WebSocketMessageType webSocketMessageType {WebSocketMessageType::Error};
 | 
			
		||||
                       WebSocketTransport::MessageKind messageKind) {
 | 
			
		||||
                    WebSocketMessageType webSocketMessageType{WebSocketMessageType::Error};
 | 
			
		||||
                    switch (messageKind)
 | 
			
		||||
                    {
 | 
			
		||||
                        case WebSocketTransport::MessageKind::MSG_TEXT:
 | 
			
		||||
@@ -519,13 +503,13 @@ namespace ix
 | 
			
		||||
        return sendMessage(text, SendMessageKind::Text, onProgressCallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WebSocketSendInfo WebSocket::ping(const std::string& text, SendMessageKind pingType)
 | 
			
		||||
    WebSocketSendInfo WebSocket::ping(const std::string& text)
 | 
			
		||||
    {
 | 
			
		||||
        // Standard limit ping message size
 | 
			
		||||
        constexpr size_t pingMaxPayloadSize = 125;
 | 
			
		||||
        if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false);
 | 
			
		||||
 | 
			
		||||
        return sendMessage(text, pingType);
 | 
			
		||||
        return sendMessage(text, SendMessageKind::Ping);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message,
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,11 @@
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include "IXWebSocketMessage.h"
 | 
			
		||||
#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
			
		||||
#include "IXWebSocketSendData.h"
 | 
			
		||||
#include "IXWebSocketSendInfo.h"
 | 
			
		||||
#include "IXWebSocketSendData.h"
 | 
			
		||||
#include "IXWebSocketTransport.h"
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
@@ -54,8 +53,6 @@ namespace ix
 | 
			
		||||
        void setPerMessageDeflateOptions(
 | 
			
		||||
            const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions);
 | 
			
		||||
        void setTLSOptions(const SocketTLSOptions& socketTLSOptions);
 | 
			
		||||
        void setPingMessage(const std::string& sendMessage,
 | 
			
		||||
                            SendMessageKind pingType = SendMessageKind::Ping);
 | 
			
		||||
        void setPingInterval(int pingIntervalSecs);
 | 
			
		||||
        void enablePong();
 | 
			
		||||
        void disablePong();
 | 
			
		||||
@@ -91,7 +88,7 @@ namespace ix
 | 
			
		||||
                                       const OnProgressCallback& onProgressCallback = nullptr);
 | 
			
		||||
        WebSocketSendInfo sendText(const std::string& text,
 | 
			
		||||
                                   const OnProgressCallback& onProgressCallback = nullptr);
 | 
			
		||||
        WebSocketSendInfo ping(const std::string& text,SendMessageKind pingType = SendMessageKind::Ping);
 | 
			
		||||
        WebSocketSendInfo ping(const std::string& text);
 | 
			
		||||
 | 
			
		||||
        void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode,
 | 
			
		||||
                   const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage);
 | 
			
		||||
@@ -106,7 +103,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        const std::string getUrl() const;
 | 
			
		||||
        const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const;
 | 
			
		||||
        const std::string getPingMessage() const;
 | 
			
		||||
        int getPingInterval() const;
 | 
			
		||||
        size_t bufferedAmount() const;
 | 
			
		||||
 | 
			
		||||
@@ -132,8 +128,7 @@ namespace ix
 | 
			
		||||
        // Server
 | 
			
		||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket>,
 | 
			
		||||
                                            int timeoutSecs,
 | 
			
		||||
                                            bool enablePerMessageDeflate,
 | 
			
		||||
                                            HttpRequestPtr request = nullptr);
 | 
			
		||||
                                            bool enablePerMessageDeflate);
 | 
			
		||||
 | 
			
		||||
        WebSocketTransport _ws;
 | 
			
		||||
 | 
			
		||||
@@ -174,8 +169,6 @@ namespace ix
 | 
			
		||||
        // Optional ping and pong timeout
 | 
			
		||||
        int _pingIntervalSecs;
 | 
			
		||||
        int _pingTimeoutSecs;
 | 
			
		||||
        std::string _pingMessage;
 | 
			
		||||
        SendMessageKind _pingType;
 | 
			
		||||
        static const int kDefaultPingIntervalSecs;
 | 
			
		||||
        static const int kDefaultPingTimeoutSecs;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#include "IXWebSocketHandshake.h"
 | 
			
		||||
 | 
			
		||||
#include "IXBase64.h"
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include "IXSocketConnect.h"
 | 
			
		||||
#include "IXStrCaseCompare.h"
 | 
			
		||||
@@ -18,6 +17,7 @@
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    WebSocketHandshake::WebSocketHandshake(
 | 
			
		||||
@@ -106,10 +106,15 @@ namespace ix
 | 
			
		||||
            return WebSocketInitResult(false, 0, ss.str());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate a random 16 bytes string and base64 encode it.
 | 
			
		||||
        //
 | 
			
		||||
        // Generate a random 24 bytes string which looks like it is base64 encoded
 | 
			
		||||
        // y3JJHMbDL1EzLkh9GBhXDw==
 | 
			
		||||
        // 0cb3Vd9HkbpVVumoS3Noka==
 | 
			
		||||
        //
 | 
			
		||||
        // See https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for
 | 
			
		||||
        std::string secWebSocketKey = macaron::Base64::Encode(genRandomString(16));
 | 
			
		||||
        //
 | 
			
		||||
        std::string secWebSocketKey = genRandomString(22);
 | 
			
		||||
        secWebSocketKey += "==";
 | 
			
		||||
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        ss << "GET " << path << " HTTP/1.1\r\n";
 | 
			
		||||
@@ -240,42 +245,28 @@ namespace ix
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs,
 | 
			
		||||
                                                            bool enablePerMessageDeflate,
 | 
			
		||||
                                                            HttpRequestPtr request)
 | 
			
		||||
                                                            bool enablePerMessageDeflate)
 | 
			
		||||
    {
 | 
			
		||||
        _requestInitCancellation = false;
 | 
			
		||||
 | 
			
		||||
        auto isCancellationRequested =
 | 
			
		||||
            makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
 | 
			
		||||
 | 
			
		||||
        std::string method;
 | 
			
		||||
        std::string uri;
 | 
			
		||||
        std::string httpVersion;
 | 
			
		||||
        // Read first line
 | 
			
		||||
        auto lineResult = _socket->readLine(isCancellationRequested);
 | 
			
		||||
        auto lineValid = lineResult.first;
 | 
			
		||||
        auto line = lineResult.second;
 | 
			
		||||
 | 
			
		||||
        if (request)
 | 
			
		||||
        if (!lineValid)
 | 
			
		||||
        {
 | 
			
		||||
            method = request->method;
 | 
			
		||||
            uri = request->uri;
 | 
			
		||||
            httpVersion = request->version;
 | 
			
		||||
            return sendErrorResponse(400, "Error reading HTTP request line");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Read first line
 | 
			
		||||
            auto lineResult = _socket->readLine(isCancellationRequested);
 | 
			
		||||
            auto lineValid = lineResult.first;
 | 
			
		||||
            auto line = lineResult.second;
 | 
			
		||||
 | 
			
		||||
            if (!lineValid)
 | 
			
		||||
            {
 | 
			
		||||
                return sendErrorResponse(400, "Error reading HTTP request line");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Validate request line (GET /foo HTTP/1.1\r\n)
 | 
			
		||||
            auto requestLine = Http::parseRequestLine(line);
 | 
			
		||||
            method = std::get<0>(requestLine);
 | 
			
		||||
            uri = std::get<1>(requestLine);
 | 
			
		||||
            httpVersion = std::get<2>(requestLine);
 | 
			
		||||
        }
 | 
			
		||||
        // Validate request line (GET /foo HTTP/1.1\r\n)
 | 
			
		||||
        auto requestLine = Http::parseRequestLine(line);
 | 
			
		||||
        auto method = std::get<0>(requestLine);
 | 
			
		||||
        auto uri = std::get<1>(requestLine);
 | 
			
		||||
        auto httpVersion = std::get<2>(requestLine);
 | 
			
		||||
 | 
			
		||||
        if (method != "GET")
 | 
			
		||||
        {
 | 
			
		||||
@@ -288,22 +279,14 @@ namespace ix
 | 
			
		||||
                                     "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WebSocketHttpHeaders headers;
 | 
			
		||||
        if (request)
 | 
			
		||||
        {
 | 
			
		||||
            headers = request->headers;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Retrieve and validate HTTP headers
 | 
			
		||||
            auto result = parseHttpHeaders(_socket, isCancellationRequested);
 | 
			
		||||
            auto headersValid = result.first;
 | 
			
		||||
            headers = result.second;
 | 
			
		||||
        // Retrieve and validate HTTP headers
 | 
			
		||||
        auto result = parseHttpHeaders(_socket, isCancellationRequested);
 | 
			
		||||
        auto headersValid = result.first;
 | 
			
		||||
        auto headers = result.second;
 | 
			
		||||
 | 
			
		||||
            if (!headersValid)
 | 
			
		||||
            {
 | 
			
		||||
                return sendErrorResponse(400, "Error parsing HTTP headers");
 | 
			
		||||
            }
 | 
			
		||||
        if (!headersValid)
 | 
			
		||||
        {
 | 
			
		||||
            return sendErrorResponse(400, "Error parsing HTTP headers");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (headers.find("sec-websocket-key") == headers.end())
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IXCancellationRequest.h"
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include "IXSocket.h"
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include "IXWebSocketInitResult.h"
 | 
			
		||||
@@ -36,9 +35,7 @@ namespace ix
 | 
			
		||||
                                            int port,
 | 
			
		||||
                                            int timeoutSecs);
 | 
			
		||||
 | 
			
		||||
        WebSocketInitResult serverHandshake(int timeoutSecs,
 | 
			
		||||
                                            bool enablePerMessageDeflate,
 | 
			
		||||
                                            HttpRequestPtr request = nullptr);
 | 
			
		||||
        WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::string genRandomString(const int len);
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,6 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
#include "IXWebSocketPerMessageDeflate.h"
 | 
			
		||||
 | 
			
		||||
#include "IXUniquePtr.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@
 | 
			
		||||
#include "zlib.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "IXWebSocketSendData.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -1,129 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  IXWebSocketSendData.h
 | 
			
		||||
 *
 | 
			
		||||
 *  WebSocket (Binary/Text) send data buffer
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
    * IXWebSocketSendData implements a wrapper for std::string, std:vector<char/uint8_t> and char*.
 | 
			
		||||
    * It removes the necessarity to copy the data or string into a std::string 
 | 
			
		||||
    */
 | 
			
		||||
    class IXWebSocketSendData {
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        template<typename T>
 | 
			
		||||
        struct IXWebSocketSendData_const_iterator
 | 
			
		||||
            //: public std::iterator<std::forward_iterator_tag, T>
 | 
			
		||||
        {
 | 
			
		||||
            typedef IXWebSocketSendData_const_iterator<T> const_iterator;
 | 
			
		||||
 | 
			
		||||
            using iterator_category = std::forward_iterator_tag;
 | 
			
		||||
            using difference_type = std::ptrdiff_t;
 | 
			
		||||
            using value_type = T;
 | 
			
		||||
            using pointer = value_type*;
 | 
			
		||||
            using reference = const value_type&;
 | 
			
		||||
 | 
			
		||||
            pointer _ptr;
 | 
			
		||||
        public:
 | 
			
		||||
            IXWebSocketSendData_const_iterator() : _ptr(nullptr) {}
 | 
			
		||||
            IXWebSocketSendData_const_iterator(pointer ptr) : _ptr(ptr) {}
 | 
			
		||||
            ~IXWebSocketSendData_const_iterator() {}
 | 
			
		||||
 | 
			
		||||
            const_iterator  operator++(int) { return const_iterator(_ptr++); }
 | 
			
		||||
            const_iterator& operator++() { ++_ptr; return *this; }
 | 
			
		||||
            reference       operator* () const { return *_ptr; }
 | 
			
		||||
            pointer         operator->() const { return _ptr; }
 | 
			
		||||
            const_iterator  operator+ (const difference_type offset) const { return const_iterator(_ptr + offset); }
 | 
			
		||||
            const_iterator  operator- (const difference_type offset) const { return const_iterator(_ptr - offset); }
 | 
			
		||||
            difference_type operator- (const const_iterator& rhs) const { return _ptr - rhs._ptr; }
 | 
			
		||||
            bool            operator==(const const_iterator& rhs) const { return _ptr == rhs._ptr; }
 | 
			
		||||
            bool            operator!=(const const_iterator& rhs) const { return _ptr != rhs._ptr; }
 | 
			
		||||
            const_iterator& operator+=(const difference_type offset) { _ptr += offset; return *this; }
 | 
			
		||||
            const_iterator& operator-=(const difference_type offset) { _ptr -= offset; return *this; }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        using const_iterator = IXWebSocketSendData_const_iterator<char>;
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::string must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::string& str)
 | 
			
		||||
            : _data(str.data())
 | 
			
		||||
            , _size(str.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::vector must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::vector<char>& v)
 | 
			
		||||
            : _data(v.data())
 | 
			
		||||
            , _size(v.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::vector must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::vector<uint8_t>& v)
 | 
			
		||||
            : _data(reinterpret_cast<const char*>(v.data()))
 | 
			
		||||
            , _size(v.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned memory must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const char* data, size_t size)
 | 
			
		||||
            : _data(data)
 | 
			
		||||
            , _size(data == nullptr ? 0 : size)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool empty() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data == nullptr || _size == 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const char* c_str() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const char* data() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size_t size() const
 | 
			
		||||
        {
 | 
			
		||||
            return _size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator begin() const
 | 
			
		||||
        {
 | 
			
		||||
            return const_iterator(const_cast<char*>(_data));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator end() const
 | 
			
		||||
        {
 | 
			
		||||
            return const_iterator(const_cast<char*>(_data) + _size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator cbegin() const
 | 
			
		||||
        {
 | 
			
		||||
            return begin();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator cend() const
 | 
			
		||||
        {
 | 
			
		||||
            return end();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const char* _data;
 | 
			
		||||
        const size_t _size;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  IXWebSocketSendData.h
 | 
			
		||||
 *
 | 
			
		||||
 *  WebSocket (Binary/Text) send data buffer
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
    * IXWebSocketSendData implements a wrapper for std::string, std:vector<char/uint8_t> and char*.
 | 
			
		||||
    * It removes the necessarity to copy the data or string into a std::string 
 | 
			
		||||
    */
 | 
			
		||||
    class IXWebSocketSendData {
 | 
			
		||||
    public:
 | 
			
		||||
 | 
			
		||||
        template<typename T>
 | 
			
		||||
        struct IXWebSocketSendData_const_iterator
 | 
			
		||||
            //: public std::iterator<std::forward_iterator_tag, T>
 | 
			
		||||
        {
 | 
			
		||||
            typedef IXWebSocketSendData_const_iterator<T> const_iterator;
 | 
			
		||||
 | 
			
		||||
            using iterator_category = std::forward_iterator_tag;
 | 
			
		||||
            using difference_type = std::ptrdiff_t;
 | 
			
		||||
            using value_type = T;
 | 
			
		||||
            using pointer = value_type*;
 | 
			
		||||
            using reference = const value_type&;
 | 
			
		||||
 | 
			
		||||
            pointer _ptr;
 | 
			
		||||
        public:
 | 
			
		||||
            IXWebSocketSendData_const_iterator() : _ptr(nullptr) {}
 | 
			
		||||
            IXWebSocketSendData_const_iterator(pointer ptr) : _ptr(ptr) {}
 | 
			
		||||
            ~IXWebSocketSendData_const_iterator() {}
 | 
			
		||||
 | 
			
		||||
            const_iterator  operator++(int) { return const_iterator(_ptr++); }
 | 
			
		||||
            const_iterator& operator++() { ++_ptr; return *this; }
 | 
			
		||||
            reference       operator* () const { return *_ptr; }
 | 
			
		||||
            pointer         operator->() const { return _ptr; }
 | 
			
		||||
            const_iterator  operator+ (const difference_type offset) const { return const_iterator(_ptr + offset); }
 | 
			
		||||
            const_iterator  operator- (const difference_type offset) const { return const_iterator(_ptr - offset); }
 | 
			
		||||
            difference_type operator- (const const_iterator& rhs) const { return _ptr - rhs._ptr; }
 | 
			
		||||
            bool            operator==(const const_iterator& rhs) const { return _ptr == rhs._ptr; }
 | 
			
		||||
            bool            operator!=(const const_iterator& rhs) const { return _ptr != rhs._ptr; }
 | 
			
		||||
            const_iterator& operator+=(const difference_type offset) { _ptr += offset; return *this; }
 | 
			
		||||
            const_iterator& operator-=(const difference_type offset) { _ptr -= offset; return *this; }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        using const_iterator = IXWebSocketSendData_const_iterator<char>;
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::string must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::string& str)
 | 
			
		||||
            : _data(str.data())
 | 
			
		||||
            , _size(str.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::vector must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::vector<char>& v)
 | 
			
		||||
            : _data(v.data())
 | 
			
		||||
            , _size(v.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned std::vector must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const std::vector<uint8_t>& v)
 | 
			
		||||
            : _data(reinterpret_cast<const char*>(v.data()))
 | 
			
		||||
            , _size(v.size())
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* The assigned memory must be kept alive for the lifetime of the input buffer */
 | 
			
		||||
        IXWebSocketSendData(const char* data, size_t size)
 | 
			
		||||
            : _data(data)
 | 
			
		||||
            , _size(data == nullptr ? 0 : size)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool empty() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data == nullptr || _size == 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const char* c_str() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const char* data() const
 | 
			
		||||
        {
 | 
			
		||||
            return _data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size_t size() const
 | 
			
		||||
        {
 | 
			
		||||
            return _size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator begin() const
 | 
			
		||||
        {
 | 
			
		||||
            return const_iterator(const_cast<char*>(_data));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator end() const
 | 
			
		||||
        {
 | 
			
		||||
            return const_iterator(const_cast<char*>(_data) + _size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator cbegin() const
 | 
			
		||||
        {
 | 
			
		||||
            return begin();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const_iterator cend() const
 | 
			
		||||
        {
 | 
			
		||||
            return end();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const char* _data;
 | 
			
		||||
        const size_t _size;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -79,16 +79,7 @@ namespace ix
 | 
			
		||||
    void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                           std::shared_ptr<ConnectionState> connectionState)
 | 
			
		||||
    {
 | 
			
		||||
        handleUpgrade(std::move(socket), connectionState);
 | 
			
		||||
 | 
			
		||||
        connectionState->setTerminated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketServer::handleUpgrade(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                        std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                                        HttpRequestPtr request)
 | 
			
		||||
    {
 | 
			
		||||
        setThreadName("Srv:ws:" + connectionState->getId());
 | 
			
		||||
        setThreadName("WebSocketServer::" + connectionState->getId());
 | 
			
		||||
 | 
			
		||||
        auto webSocket = std::make_shared<WebSocket>();
 | 
			
		||||
        if (_onConnectionCallback)
 | 
			
		||||
@@ -98,7 +89,7 @@ namespace ix
 | 
			
		||||
            if (!webSocket->isOnMessageCallbackRegistered())
 | 
			
		||||
            {
 | 
			
		||||
                logError("WebSocketServer Application developer error: Server callback improperly "
 | 
			
		||||
                         "registered.");
 | 
			
		||||
                         "registerered.");
 | 
			
		||||
                logError("Missing call to setOnMessageCallback inside setOnConnectionCallback.");
 | 
			
		||||
                connectionState->setTerminated();
 | 
			
		||||
                return;
 | 
			
		||||
@@ -108,8 +99,9 @@ namespace ix
 | 
			
		||||
        {
 | 
			
		||||
            WebSocket* webSocketRawPtr = webSocket.get();
 | 
			
		||||
            webSocket->setOnMessageCallback(
 | 
			
		||||
                [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg)
 | 
			
		||||
                { _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); });
 | 
			
		||||
                [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) {
 | 
			
		||||
                    _onClientMessageCallback(connectionState, *webSocketRawPtr, msg);
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
@@ -138,7 +130,7 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto status = webSocket->connectToSocket(
 | 
			
		||||
            std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate, request);
 | 
			
		||||
            std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate);
 | 
			
		||||
        if (status.success)
 | 
			
		||||
        {
 | 
			
		||||
            // Process incoming messages and execute callbacks
 | 
			
		||||
@@ -163,6 +155,8 @@ namespace ix
 | 
			
		||||
                logError("Cannot delete client");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        connectionState->setTerminated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients()
 | 
			
		||||
@@ -182,30 +176,28 @@ namespace ix
 | 
			
		||||
    //
 | 
			
		||||
    void WebSocketServer::makeBroadcastServer()
 | 
			
		||||
    {
 | 
			
		||||
        setOnClientMessageCallback(
 | 
			
		||||
            [this](std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                   WebSocket& webSocket,
 | 
			
		||||
                   const WebSocketMessagePtr& msg)
 | 
			
		||||
        setOnClientMessageCallback([this](std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                                          WebSocket& webSocket,
 | 
			
		||||
                                          const WebSocketMessagePtr& msg) {
 | 
			
		||||
            auto remoteIp = connectionState->getRemoteIp();
 | 
			
		||||
            if (msg->type == ix::WebSocketMessageType::Message)
 | 
			
		||||
            {
 | 
			
		||||
                auto remoteIp = connectionState->getRemoteIp();
 | 
			
		||||
                if (msg->type == ix::WebSocketMessageType::Message)
 | 
			
		||||
                for (auto&& client : getClients())
 | 
			
		||||
                {
 | 
			
		||||
                    for (auto&& client : getClients())
 | 
			
		||||
                    if (client.get() != &webSocket)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (client.get() != &webSocket)
 | 
			
		||||
                        {
 | 
			
		||||
                            client->send(msg->str, msg->binary);
 | 
			
		||||
                        client->send(msg->str, msg->binary);
 | 
			
		||||
 | 
			
		||||
                            // Make sure the OS send buffer is flushed before moving on
 | 
			
		||||
                            do
 | 
			
		||||
                            {
 | 
			
		||||
                                std::chrono::duration<double, std::milli> duration(500);
 | 
			
		||||
                                std::this_thread::sleep_for(duration);
 | 
			
		||||
                            } while (client->bufferedAmount() != 0);
 | 
			
		||||
                        }
 | 
			
		||||
                        // Make sure the OS send buffer is flushed before moving on
 | 
			
		||||
                        do
 | 
			
		||||
                        {
 | 
			
		||||
                            std::chrono::duration<double, std::milli> duration(500);
 | 
			
		||||
                            std::this_thread::sleep_for(duration);
 | 
			
		||||
                        } while (client->bufferedAmount() != 0);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocketServer::listenAndStart()
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,6 @@ namespace ix
 | 
			
		||||
        int getHandshakeTimeoutSecs();
 | 
			
		||||
        bool isPongEnabled();
 | 
			
		||||
        bool isPerMessageDeflateEnabled();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        // Member variables
 | 
			
		||||
        int _handshakeTimeoutSecs;
 | 
			
		||||
@@ -74,10 +73,5 @@ namespace ix
 | 
			
		||||
        virtual void handleConnection(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                      std::shared_ptr<ConnectionState> connectionState);
 | 
			
		||||
        virtual size_t getConnectedClientsCount() final;
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        void handleUpgrade(std::unique_ptr<Socket> socket,
 | 
			
		||||
                           std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                           HttpRequestPtr request = nullptr);
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@
 | 
			
		||||
#include <cstdarg>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
@@ -53,6 +54,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    const std::string WebSocketTransport::kPingMessage("ixwebsocket::heartbeat");
 | 
			
		||||
    const int WebSocketTransport::kDefaultPingIntervalSecs(-1);
 | 
			
		||||
    const bool WebSocketTransport::kDefaultEnablePong(true);
 | 
			
		||||
    const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300);
 | 
			
		||||
@@ -71,9 +73,6 @@ namespace ix
 | 
			
		||||
        , _closingTimePoint(std::chrono::steady_clock::now())
 | 
			
		||||
        , _enablePong(kDefaultEnablePong)
 | 
			
		||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
			
		||||
        , _setCustomMessage(false)
 | 
			
		||||
        , _kPingMessage("ixwebsocket::heartbeat")
 | 
			
		||||
        , _pingType(SendMessageKind::Ping)
 | 
			
		||||
        , _pongReceived(false)
 | 
			
		||||
        , _pingCount(0)
 | 
			
		||||
        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
			
		||||
@@ -171,8 +170,7 @@ namespace ix
 | 
			
		||||
    // Server
 | 
			
		||||
    WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                                            int timeoutSecs,
 | 
			
		||||
                                                            bool enablePerMessageDeflate,
 | 
			
		||||
                                                            HttpRequestPtr request)
 | 
			
		||||
                                                            bool enablePerMessageDeflate)
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
			
		||||
 | 
			
		||||
@@ -189,8 +187,7 @@ namespace ix
 | 
			
		||||
                                              _perMessageDeflateOptions,
 | 
			
		||||
                                              _enablePerMessageDeflate);
 | 
			
		||||
 | 
			
		||||
        auto result =
 | 
			
		||||
            webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate, request);
 | 
			
		||||
        auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate);
 | 
			
		||||
        if (result.success)
 | 
			
		||||
        {
 | 
			
		||||
            setReadyState(ReadyState::OPEN);
 | 
			
		||||
@@ -251,51 +248,13 @@ namespace ix
 | 
			
		||||
        return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketTransport::setPingMessage(const std::string& message, SendMessageKind pingType)
 | 
			
		||||
    {
 | 
			
		||||
        _setCustomMessage = true;
 | 
			
		||||
        _kPingMessage = message;
 | 
			
		||||
        _pingType = pingType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WebSocketSendInfo WebSocketTransport::sendHeartBeat(SendMessageKind pingMessage)
 | 
			
		||||
    WebSocketSendInfo WebSocketTransport::sendHeartBeat()
 | 
			
		||||
    {
 | 
			
		||||
        _pongReceived = false;
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
 | 
			
		||||
        ss << _kPingMessage;
 | 
			
		||||
        if (!_setCustomMessage)
 | 
			
		||||
        {
 | 
			
		||||
            ss << "::" << _pingIntervalSecs << "s"
 | 
			
		||||
               << "::" << _pingCount++;
 | 
			
		||||
        }
 | 
			
		||||
        if (pingMessage == SendMessageKind::Ping)
 | 
			
		||||
        {
 | 
			
		||||
            return sendPing(ss.str());
 | 
			
		||||
        }
 | 
			
		||||
        else if (pingMessage == SendMessageKind::Binary)
 | 
			
		||||
        {
 | 
			
		||||
            WebSocketSendInfo info = sendBinary(ss.str(), nullptr);
 | 
			
		||||
            if (info.success)
 | 
			
		||||
            {
 | 
			
		||||
                std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex);
 | 
			
		||||
                _lastSendPingTimePoint = std::chrono::steady_clock::now();
 | 
			
		||||
            }
 | 
			
		||||
            return info;
 | 
			
		||||
        }
 | 
			
		||||
        else if (pingMessage == SendMessageKind::Text)
 | 
			
		||||
        {
 | 
			
		||||
            WebSocketSendInfo info = sendText(ss.str(), nullptr);
 | 
			
		||||
            if (info.success)
 | 
			
		||||
            {
 | 
			
		||||
                std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex);
 | 
			
		||||
                _lastSendPingTimePoint = std::chrono::steady_clock::now();
 | 
			
		||||
            }
 | 
			
		||||
            return info;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // unknow type ping message
 | 
			
		||||
        return {};
 | 
			
		||||
        ss << kPingMessage << "::" << _pingIntervalSecs << "s"
 | 
			
		||||
           << "::" << _pingCount++;
 | 
			
		||||
        return sendPing(ss.str());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocketTransport::closingDelayExceeded()
 | 
			
		||||
@@ -311,9 +270,7 @@ namespace ix
 | 
			
		||||
        {
 | 
			
		||||
            if (pingIntervalExceeded())
 | 
			
		||||
            {
 | 
			
		||||
                // If it is not a 'ping' message of ping type, there is no need to judge whether
 | 
			
		||||
                // pong will receive it
 | 
			
		||||
                if (_pingType == SendMessageKind::Ping && !_pongReceived)
 | 
			
		||||
                if (!_pongReceived)
 | 
			
		||||
                {
 | 
			
		||||
                    // ping response (PONG) exceeds the maximum delay, close the connection
 | 
			
		||||
                    close(WebSocketCloseConstants::kInternalErrorCode,
 | 
			
		||||
@@ -321,7 +278,7 @@ namespace ix
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    sendHeartBeat(_pingType);
 | 
			
		||||
                    sendHeartBeat();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,17 +18,15 @@
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include "IXWebSocketPerMessageDeflate.h"
 | 
			
		||||
#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
			
		||||
#include "IXWebSocketSendData.h"
 | 
			
		||||
#include "IXWebSocketSendInfo.h"
 | 
			
		||||
#include "IXWebSocketSendData.h"
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <deque>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
@@ -88,8 +86,7 @@ namespace ix
 | 
			
		||||
        // Server
 | 
			
		||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket,
 | 
			
		||||
                                            int timeoutSecs,
 | 
			
		||||
                                            bool enablePerMessageDeflate,
 | 
			
		||||
                                            HttpRequestPtr request = nullptr);
 | 
			
		||||
                                            bool enablePerMessageDeflate);
 | 
			
		||||
 | 
			
		||||
        PollResult poll();
 | 
			
		||||
        WebSocketSendInfo sendBinary(const IXWebSocketSendData& message,
 | 
			
		||||
@@ -111,12 +108,8 @@ namespace ix
 | 
			
		||||
        void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback);
 | 
			
		||||
        size_t bufferedAmount() const;
 | 
			
		||||
 | 
			
		||||
        // set ping heartbeat message
 | 
			
		||||
        void setPingMessage(const std::string& message, SendMessageKind pingType);
 | 
			
		||||
 | 
			
		||||
        // internal
 | 
			
		||||
        // send any type of ping packet, not only 'ping' type
 | 
			
		||||
        WebSocketSendInfo sendHeartBeat(SendMessageKind pingType);
 | 
			
		||||
        WebSocketSendInfo sendHeartBeat();
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::string _url;
 | 
			
		||||
@@ -157,7 +150,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;
 | 
			
		||||
@@ -221,10 +214,7 @@ namespace ix
 | 
			
		||||
        std::atomic<bool> _pongReceived;
 | 
			
		||||
 | 
			
		||||
        static const int kDefaultPingIntervalSecs;
 | 
			
		||||
 | 
			
		||||
        bool _setCustomMessage;
 | 
			
		||||
        std::string _kPingMessage;
 | 
			
		||||
        SendMessageKind _pingType;
 | 
			
		||||
        static const std::string kPingMessage;
 | 
			
		||||
        std::atomic<uint64_t> _pingCount;
 | 
			
		||||
 | 
			
		||||
        // We record when ping are being sent so that we can know when to send the next one
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.4.3"
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.4.1"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDNDCCAhwCFCl+O/rR8flqYKKvD0iwkucFwMaLMA0GCSqGSIb3DQEBCwUAMEEx
 | 
			
		||||
FDASBgNVBAoMC21hY2hpbmV6b25lMRQwEgYDVQQKDAtJWFdlYlNvY2tldDETMBEG
 | 
			
		||||
A1UEAwwKdHJ1c3RlZC1jYTAgFw0yMjA4MjMyMDM2MjVaGA80MjgxMDYwMTIwMzYy
 | 
			
		||||
NVowajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhCZXJrZWxl
 | 
			
		||||
eTEbMBkGA1UECgwSRHVtbXkgT3JnYW5pemF0aW9uMR4wHAYDVQQDDBVub3QuYS52
 | 
			
		||||
YWxpZC5ob3N0Lm5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
 | 
			
		||||
9N806IjCvA82zfk9CPNwaEHOygNDJSXaZ38YDSI4C+Wf2imnMxrLQKaoccHUi+9L
 | 
			
		||||
4rQN/hSCg+uTULQUZ0iyssGDaIh4IcAeoEcNlXYHTrgP+aAaby3q5zeZ80K3+6e4
 | 
			
		||||
rqcuBPV2lLszJu3XXwEKbDSxW3De0gc2N8m9DN8Lx7i70DRf0F4m6RIMFF/kHXwa
 | 
			
		||||
zZLeG7rZb4xL684lmmQsWtk5Z600CvrBtUE7fQ7bhy0QhSt66kdTSL8IKQrbWcGj
 | 
			
		||||
q0tggFlOqeyZSi73gqUiAIuGO8/tRgmp4HygNyC24jpOB5nObOPPJTUEf5Mk1Bum
 | 
			
		||||
kD5a+yL6YbVdhiaK17wbAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKsLXGLfO1IZ
 | 
			
		||||
LbofGc7/TCQwRayR3RdG4864PBy97KfJWyizg7Wm4X4yPFRG+6q3X5NKW32Ew9lI
 | 
			
		||||
jXulXCTjWOiSxiG4Pk20uczkOhWVHFdnS9gZvykPC/ElxBKPalT6MMstZWxpElsk
 | 
			
		||||
rCDKXj4LkD0po8bZrjlgSZQQQk6XMRkoRai2GWLJqIjaNCSF8nqb1wM/1OE1tAwi
 | 
			
		||||
polO1eFMA24yypvlXcNrNXjqcQ7LaoQFQltmi/RV+uTk7EK2F2jgYVzJ/pe2ET0i
 | 
			
		||||
RIMbGZTlAiemDGL9SpMsxftG6fSmP6QqDqYExmmPlZMLprb2da/2kelWFA+VkvdG
 | 
			
		||||
zFrnIcyfMY4=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEpAIBAAKCAQEAtvTfNOiIwrwPNs35PQjzcGhBzsoDQyUl2md/GA0iOAvln9op
 | 
			
		||||
pzMay0CmqHHB1IvvS+K0Df4UgoPrk1C0FGdIsrLBg2iIeCHAHqBHDZV2B064D/mg
 | 
			
		||||
Gm8t6uc3mfNCt/unuK6nLgT1dpS7Mybt118BCmw0sVtw3tIHNjfJvQzfC8e4u9A0
 | 
			
		||||
X9BeJukSDBRf5B18Gs2S3hu62W+MS+vOJZpkLFrZOWetNAr6wbVBO30O24ctEIUr
 | 
			
		||||
eupHU0i/CCkK21nBo6tLYIBZTqnsmUou94KlIgCLhjvP7UYJqeB8oDcgtuI6TgeZ
 | 
			
		||||
zmzjzyU1BH+TJNQbppA+Wvsi+mG1XYYmite8GwIDAQABAoIBAGRzAXG9EglI01mV
 | 
			
		||||
sPfvyCi5NRhiFXRyGtxU4pTD8TuwXHxtfV0NU/KwJlBpVLBrvBCAAbeE/qHB6D9T
 | 
			
		||||
metx4ZorRs/tPrAmZ6LpANnWa50LfUdYGK0qyZ0lIYPm6YS2KJnfWm6LznEyq60j
 | 
			
		||||
/IW45YthaXTO7aOI0OjVrG+dd4CxU1g1NtCQ9bdDMDjfXFVnoOifXIl8W22eRMoZ
 | 
			
		||||
LzCz+0sI0R0LenXCPT566de21F0NDkIK7NaQ1l5BMX4PA+RsN3cZlzyruA1woPKI
 | 
			
		||||
aBR2LQGNrBfDVGMATtUm89RpWAftb8FmXqYUsM7zAzTO6dViitiB7OFlw7Ax15YH
 | 
			
		||||
MTj5zGECgYEA35ocEEMfyahBN70bjyiqOHlzKwFjDl9DsUf8xqHsNhYAL+GrOK9A
 | 
			
		||||
8lN5ByzcnbV3TJtU4WYbPgQJld8gXFx4h3eS+SkA/ASkAdtgHfdMImZ1v7k3TIPf
 | 
			
		||||
DXOCsHzELsQY6OgiI572Nwzx/Tl+0dFwaOfLjU9iEmmqL667j1Y4NiMCgYEA0Xch
 | 
			
		||||
9K/vwZ1I9gM3ySvG40R2TRriC9Bf8jwrEWeRsWNvBcqtMMrgwAMsMCKDugSZR7n6
 | 
			
		||||
o3WZV6mpvYVLFx0b93v07i7EpFP27kMw3gLNBKX62snR9JbqwAMK7tktgLds5pKM
 | 
			
		||||
DvLHuAQ9XMMXMLX7WlSyhmtFeU7IDulTSHHqdakCgYEAywITCpy2xpKRK7bwx4gH
 | 
			
		||||
C6EQc/IdahYJ0nHmSL0IRY6x+sbrelp7H8ezcVVEs5bmylGYvc/DWgm2XjCnI9P8
 | 
			
		||||
xhlFAhw9PZJFCT6QRISaxfy6WSgi0cBEieTeubd9MmxtpT/khuyy5AZHyj0iLAL4
 | 
			
		||||
CPayMwjopIj0r7f3p8qC3HsCgYBmq2kmYVI4aZrIkv02CtIatYTy+DlSJxnQRvOp
 | 
			
		||||
PUWpWB6kDRrk7pxJIYT4NwKwG+7xvFQA6PR3hn7fmUUcGDWMEeMVGDFkho9ja+W4
 | 
			
		||||
/FB3dc/Gi+PwakS4RwWF20e1brLfNXeXICMKrHFTVYC5bIm+VgOHZW8RLa9bt7wN
 | 
			
		||||
p2CPuQKBgQCjW+rCODmMzEues/I143mYMDdZ1IschtWGiXBNrpkHm/DcZSutbacm
 | 
			
		||||
5C7Kwv44pfA90NHDTjuaIgRgfeUTawkrl8uPXEuj80mW72agf5oS8lJzD+2jibCj
 | 
			
		||||
Q4K52G+0LaTxHLZxufil28Rgja01c0mTcuLbhKtCgHl5EHP19wOKEg==
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
@@ -19,9 +19,13 @@ TEST_CASE("dns", "[net]")
 | 
			
		||||
        auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80);
 | 
			
		||||
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
        struct addrinfo* res;
 | 
			
		||||
 | 
			
		||||
        res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
			
		||||
        REQUIRE(res != nullptr);
 | 
			
		||||
 | 
			
		||||
        dnsLookup->release(res);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SECTION("Test resolving a non-existing hostname")
 | 
			
		||||
@@ -29,7 +33,7 @@ TEST_CASE("dns", "[net]")
 | 
			
		||||
        auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
 | 
			
		||||
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
			
		||||
        REQUIRE(res == nullptr);
 | 
			
		||||
    }
 | 
			
		||||
@@ -40,7 +44,7 @@ TEST_CASE("dns", "[net]")
 | 
			
		||||
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        // The callback returning true means we are requesting cancellation
 | 
			
		||||
        auto res = dnsLookup->resolve(errMsg, [] { return true; });
 | 
			
		||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; });
 | 
			
		||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
			
		||||
        REQUIRE(res == nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,7 @@
 | 
			
		||||
#include "catch.hpp"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <ixwebsocket/IXGetFreePort.h>
 | 
			
		||||
#include <ixwebsocket/IXHttpClient.h>
 | 
			
		||||
#include <ixwebsocket/IXHttpServer.h>
 | 
			
		||||
 | 
			
		||||
using namespace ix;
 | 
			
		||||
 | 
			
		||||
@@ -97,52 +95,6 @@ TEST_CASE("http_client", "[http]")
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(IXWEBSOCKET_USE_TLS) && !defined(IXWEBSOCKET_USE_SECURE_TRANSPORT)
 | 
			
		||||
    SECTION("Disable hostname validation")
 | 
			
		||||
    {
 | 
			
		||||
        static auto test_cert_with_wrong_name = [](bool validate_hostname)
 | 
			
		||||
        {
 | 
			
		||||
            int port = getFreePort();
 | 
			
		||||
            ix::HttpServer server(port, "127.0.0.1");
 | 
			
		||||
 | 
			
		||||
            SocketTLSOptions tlsOptionsServer;
 | 
			
		||||
            tlsOptionsServer.tls = true;
 | 
			
		||||
            tlsOptionsServer.caFile = "NONE";
 | 
			
		||||
            tlsOptionsServer.certFile = "./.certs/wrong-name-server-crt.pem";
 | 
			
		||||
            tlsOptionsServer.keyFile = "./.certs/wrong-name-server-key.pem";
 | 
			
		||||
            server.setTLSOptions(tlsOptionsServer);
 | 
			
		||||
 | 
			
		||||
            auto res = server.listen();
 | 
			
		||||
            REQUIRE(res.first);
 | 
			
		||||
            server.start();
 | 
			
		||||
 | 
			
		||||
            HttpClient httpClient;
 | 
			
		||||
            SocketTLSOptions tlsOptionsClient;
 | 
			
		||||
            tlsOptionsClient.caFile = "./.certs/trusted-ca-crt.pem";
 | 
			
		||||
            tlsOptionsClient.disable_hostname_validation = validate_hostname;
 | 
			
		||||
            httpClient.setTLSOptions(tlsOptionsClient);
 | 
			
		||||
 | 
			
		||||
            std::string url("https://localhost:" + std::to_string(port));
 | 
			
		||||
            auto args = httpClient.createRequest(url);
 | 
			
		||||
            args->connectTimeout = 10;
 | 
			
		||||
            args->transferTimeout = 10;
 | 
			
		||||
 | 
			
		||||
            auto response = httpClient.get(url, args);
 | 
			
		||||
 | 
			
		||||
            std::cerr << "Status: " << response->statusCode << std::endl;
 | 
			
		||||
            std::cerr << "Error code: " << (int) response->errorCode << std::endl;
 | 
			
		||||
            std::cerr << "Error message: " << response->errorMsg << std::endl;
 | 
			
		||||
 | 
			
		||||
            server.stop();
 | 
			
		||||
            return std::make_tuple(response->errorCode, response->statusCode);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        REQUIRE(test_cert_with_wrong_name(false) ==
 | 
			
		||||
                std::make_tuple(HttpErrorCode::CannotConnect, 0));
 | 
			
		||||
        REQUIRE(test_cert_with_wrong_name(true) == std::make_tuple(HttpErrorCode::Ok, 404));
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    SECTION("Async API, one call")
 | 
			
		||||
    {
 | 
			
		||||
        bool async = true;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -77,6 +77,24 @@ namespace
 | 
			
		||||
        return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Assume the file exists
 | 
			
		||||
    std::string readBytes(const std::string& path)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<uint8_t> memblock;
 | 
			
		||||
        std::ifstream file(path);
 | 
			
		||||
 | 
			
		||||
        file.seekg(0, file.end);
 | 
			
		||||
        std::streamoff size = file.tellg();
 | 
			
		||||
        file.seekg(0, file.beg);
 | 
			
		||||
 | 
			
		||||
        memblock.reserve((size_t) size);
 | 
			
		||||
        memblock.insert(
 | 
			
		||||
            memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>());
 | 
			
		||||
 | 
			
		||||
        std::string bytes(memblock.begin(), memblock.end());
 | 
			
		||||
        return bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string truncate(const std::string& str, size_t n)
 | 
			
		||||
    {
 | 
			
		||||
        if (str.size() < n)
 | 
			
		||||
@@ -89,6 +107,12 @@ namespace
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool fileExists(const std::string& fileName)
 | 
			
		||||
    {
 | 
			
		||||
        std::ifstream infile(fileName);
 | 
			
		||||
        return infile.good();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string extractFilename(const std::string& path)
 | 
			
		||||
    {
 | 
			
		||||
        std::string::size_type idx;
 | 
			
		||||
@@ -892,8 +916,9 @@ namespace ix
 | 
			
		||||
        auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80);
 | 
			
		||||
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        struct addrinfo* res;
 | 
			
		||||
 | 
			
		||||
        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
        res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
			
		||||
 | 
			
		||||
        auto addr = res->ai_addr;
 | 
			
		||||
 | 
			
		||||
@@ -2461,8 +2486,10 @@ int main(int argc, char** argv)
 | 
			
		||||
    bool verbose = false;
 | 
			
		||||
    bool save = false;
 | 
			
		||||
    bool quiet = false;
 | 
			
		||||
    bool fluentd = false;
 | 
			
		||||
    bool compress = false;
 | 
			
		||||
    bool compressRequest = false;
 | 
			
		||||
    bool stress = false;
 | 
			
		||||
    bool disableAutomaticReconnection = false;
 | 
			
		||||
    bool disablePerMessageDeflate = false;
 | 
			
		||||
    bool greetings = false;
 | 
			
		||||
@@ -2478,6 +2505,7 @@ int main(int argc, char** argv)
 | 
			
		||||
    int transferTimeout = 1800;
 | 
			
		||||
    int maxRedirects = 5;
 | 
			
		||||
    int delayMs = -1;
 | 
			
		||||
    int count = 1;
 | 
			
		||||
    int msgCount = 1000 * 1000;
 | 
			
		||||
    uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds
 | 
			
		||||
    int pingIntervalSecs = 30;
 | 
			
		||||
@@ -2501,7 +2529,6 @@ int main(int argc, char** argv)
 | 
			
		||||
                        "A (comma/space/colon) separated list of ciphers to use for TLS");
 | 
			
		||||
        app->add_flag("--tls", tlsOptions.tls, "Enable TLS (server only)");
 | 
			
		||||
        app->add_flag("--verify_none", verifyNone, "Disable peer cert verification");
 | 
			
		||||
        app->add_flag("--disable-hostname-validation", tlsOptions.disable_hostname_validation, "Disable validation of certificates' hostnames");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    app.add_flag("--version", version, "Print ws version");
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user