Compare commits

..

16 Commits

Author SHA1 Message Date
e417e63605 Update CHANGELOG.md 2022-05-13 10:45:46 -07:00
7b1524d7ec Update IXWebSocketVersion.h 2022-05-13 10:43:32 -07:00
e8048ad826 BoringSSL does not allow setting the hostname with a null-terminated string. The length is always required: https://boringssl.googlesource.com/boringssl/+/master/crypto/x509/x509_vpm.c#93 (#391) 2022-05-05 08:11:18 -07:00
2b40a30c8f Update README.md 2022-05-02 09:34:43 -07:00
d7bfe89e43 Set shorter thread names (#379) 2022-04-30 10:18:20 -07:00
84aa652846 Set shorter thread names (#379) 2022-04-30 10:16:53 -07:00
edb6ded99f Fix Sec-WebSocket-Key to contain valid Base64. (#389)
The generated header only "looked like" Base64, but if the other side
actually tried to decode it as such, it could fail. This change fixes
that to always generate a valid Base64 value.

The Base64 code is copied from
https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594.
2022-04-29 00:05:06 -07:00
2f560ff4c0 Update IXWebSocketVersion.h 2022-04-28 23:56:40 -07:00
002d9c8985 Update ixwebsocket-config.cmake.in (#390) 2022-04-28 23:56:00 -07:00
6d8495bd73 Update CHANGELOG.md 2022-04-23 22:53:36 -07:00
b8563eddd1 11.4.1 2022-04-23 22:52:32 -07:00
46bd2aa4a1 vcpkg zlib dep fix (#385)
* vcpkg zlib dep fix

* Use cmake.in file instead of write file directly

Co-authored-by: Cheney-Wang <v-xincwa@microsoft.com>
2022-04-23 18:16:13 -07:00
4420bc70b5 Revert "Export static symbols when building ws with shared library (#370)" (#383)
This reverts commit a3d2fa4b7e.
2022-04-12 08:55:43 -07:00
20921f341a Update README.md 2022-03-28 22:04:27 -07:00
2829c62ef9 Fix error handling after calling X509_NAME_get_index_by_NID
This should fix #376
2022-03-27 19:14:40 -07:00
a3d2fa4b7e Export static symbols when building ws with shared library (#370) 2022-03-19 11:41:40 -07:00
10 changed files with 169 additions and 25 deletions

View File

@ -66,6 +66,7 @@ set( IXWEBSOCKET_SOURCES
)
set( IXWEBSOCKET_HEADERS
ixwebsocket/IXBase64.h
ixwebsocket/IXBench.h
ixwebsocket/IXCancellationRequest.h
ixwebsocket/IXConnectionState.h
@ -234,11 +235,7 @@ endif()
option(USE_ZLIB "Enable zlib support" TRUE)
if (USE_ZLIB)
# This ZLIB_FOUND check is to help find a cmake manually configured zlib
if (NOT ZLIB_FOUND)
find_package(ZLIB REQUIRED)
endif()
target_include_directories(ixwebsocket PUBLIC $<BUILD_INTERFACE:${ZLIB_INCLUDE_DIRS}>)
find_package(ZLIB REQUIRED)
target_link_libraries(ixwebsocket PRIVATE ZLIB::ZLIB)
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_ZLIB)
@ -289,10 +286,14 @@ if (IXWEBSOCKET_INSTALL)
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ixwebsocket/
)
configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-config.cmake.in" "${CMAKE_BINARY_DIR}/ixwebsocket-config.cmake" @ONLY)
install(FILES "${CMAKE_BINARY_DIR}/ixwebsocket-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket")
install(EXPORT ixwebsocket
FILE ixwebsocket-config.cmake
FILE ixwebsocket-targets.cmake
NAMESPACE ixwebsocket::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket
)
endif()
if (USE_WS OR USE_TEST)

View File

@ -2,9 +2,7 @@
IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use and support everything you'll likely need for websocket dev (SSL, deflate compression, compiles on most platforms, etc...). HTTP client and server code is also available, but it hasn't received as much testing.
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Note that the MinGW compiler is not supported at this point. Two important design goals are simplicity and correctness.
A bad security bug affecting users compiling with SSL enabled and OpenSSL as the backend was just fixed in newly released version 11.0.0. Please upgrade ! (more details in the [https://github.com/machinezone/IXWebSocket/pull/250](PR).
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Two important design goals are simplicity and correctness.
```cpp
/*
@ -37,6 +35,7 @@ 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);

View File

@ -2,6 +2,16 @@
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
## [11.4.0] - 2022-01-05
(Windows) Use wsa select event, which should lead to a much better behavior on Windows in general, and also when sending large payloads (#342)

View File

@ -0,0 +1,9 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if (@USE_ZLIB@)
find_dependency(ZLIB)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-targets.cmake")

124
ixwebsocket/IXBase64.h Normal file
View File

@ -0,0 +1,124 @@
#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 <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_ */

View File

@ -339,12 +339,12 @@ namespace ix
{
int cn_pos = X509_NAME_get_index_by_NID(
X509_get_subject_name((X509*) server_cert), NID_commonName, -1);
if (cn_pos)
if (cn_pos >= 0)
{
X509_NAME_ENTRY* cn_entry =
X509_NAME_get_entry(X509_get_subject_name((X509*) server_cert), cn_pos);
if (cn_entry)
if (cn_entry != nullptr)
{
ASN1_STRING* cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
char* cn = (char*) ASN1_STRING_data(cn_asn1);
@ -755,7 +755,7 @@ namespace ix
// 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.)
X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size());
#endif
handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested);
}

View File

@ -268,7 +268,10 @@ namespace ix
// Set the socket to non blocking mode, so that accept calls are not blocking
SocketConnect::configure(_serverFd);
setThreadName("SocketServer::accept");
// 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));
for (;;)
{
@ -425,7 +428,10 @@ namespace ix
void SocketServer::runGC()
{
setThreadName("SocketServer::GC");
// 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));
for (;;)
{

View File

@ -6,6 +6,7 @@
#include "IXWebSocketHandshake.h"
#include "IXBase64.h"
#include "IXHttp.h"
#include "IXSocketConnect.h"
#include "IXStrCaseCompare.h"
@ -17,7 +18,6 @@
#include <random>
#include <sstream>
namespace ix
{
WebSocketHandshake::WebSocketHandshake(
@ -106,15 +106,10 @@ namespace ix
return WebSocketInitResult(false, 0, ss.str());
}
//
// Generate a random 24 bytes string which looks like it is base64 encoded
// y3JJHMbDL1EzLkh9GBhXDw==
// 0cb3Vd9HkbpVVumoS3Noka==
// Generate a random 16 bytes string and base64 encode it.
//
// See https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for
//
std::string secWebSocketKey = genRandomString(22);
secWebSocketKey += "==";
std::string secWebSocketKey = macaron::Base64::Encode(genRandomString(16));
std::stringstream ss;
ss << "GET " << path << " HTTP/1.1\r\n";

View File

@ -79,7 +79,7 @@ namespace ix
void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket,
std::shared_ptr<ConnectionState> connectionState)
{
setThreadName("WebSocketServer::" + connectionState->getId());
setThreadName("Srv:ws:" + connectionState->getId());
auto webSocket = std::make_shared<WebSocket>();
if (_onConnectionCallback)

View File

@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "11.4.0"
#define IX_WEBSOCKET_VERSION "11.4.3"