Compare commits
25 Commits
v7.9.2
...
feature/ss
Author | SHA1 | Date | |
---|---|---|---|
22118d68d2 | |||
4c15964d43 | |||
99fe6ea493 | |||
acab19fe9f | |||
2f59fcc02d | |||
8a344788ba | |||
5d641bc267 | |||
0c4866420a | |||
8ed7c660d4 | |||
4cbf85f4d4 | |||
a8ff91ac3c | |||
4cb3326078 | |||
87625a8805 | |||
b75264b98f | |||
21f42210a2 | |||
27287aea50 | |||
39f69bd2b6 | |||
00dc8bacee | |||
9e24475fd6 | |||
61bcc9d27d | |||
1a47656ba0 | |||
7e521e38ef | |||
8410a65754 | |||
6db028fd67 | |||
925eb2f1d0 |
@ -113,22 +113,24 @@ else()
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptEventFd.h)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(USE_MBED_TLS TRUE)
|
||||
endif()
|
||||
option(USE_TLS "Enable TLS support" FALSE)
|
||||
|
||||
if (USE_TLS)
|
||||
if (WIN32)
|
||||
option(USE_MBED_TLS "Use Mbed TLS" ON)
|
||||
else()
|
||||
option(USE_MBED_TLS "Use Mbed TLS" OFF)
|
||||
endif()
|
||||
option(USE_OPEN_SSL "Use OpenSSL" OFF)
|
||||
|
||||
if (USE_MBED_TLS)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketMbedTLS.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketMbedTLS.cpp)
|
||||
elseif (APPLE AND NOT USE_OPEN_SSL)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
|
||||
elseif (WIN32)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketSChannel.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketSChannel.cpp)
|
||||
else()
|
||||
set(USE_OPEN_SSL TRUE)
|
||||
set(USE_OPEN_SSL ON)
|
||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
|
||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketOpenSSL.cpp)
|
||||
endif()
|
||||
@ -145,19 +147,15 @@ if (USE_TLS)
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_MBED_TLS)
|
||||
elseif (USE_OPEN_SSL)
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
|
||||
elseif (APPLE)
|
||||
elseif (WIN32)
|
||||
else()
|
||||
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE AND USE_TLS AND NOT USE_MBED_TLS)
|
||||
if (APPLE AND USE_TLS AND NOT USE_MBED_TLS AND NOT USE_OPEN_SSL)
|
||||
target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(ixwebsocket wsock32 ws2_32)
|
||||
target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
@ -174,7 +172,9 @@ if (USE_TLS AND USE_OPEN_SSL)
|
||||
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/local/opt/openssl/include)
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
add_definitions(${OPENSSL_DEFINITIONS})
|
||||
message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
@ -207,7 +207,7 @@ else()
|
||||
endif()
|
||||
|
||||
set( IXWEBSOCKET_INCLUDE_DIRS
|
||||
.
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
|
39
Dockerfile
39
Dockerfile
@ -1,39 +0,0 @@
|
||||
FROM alpine:3.11 as build
|
||||
|
||||
RUN apk add --no-cache gcc g++ musl-dev linux-headers cmake openssl-dev
|
||||
RUN apk add --no-cache make
|
||||
RUN apk add --no-cache zlib-dev
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
RUN chown -R app:app /opt
|
||||
RUN chown -R app:app /usr/local
|
||||
|
||||
# There is a bug in CMake where we cannot build from the root top folder
|
||||
# So we build from /opt
|
||||
COPY --chown=app:app . /opt
|
||||
WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
FROM alpine:3.11 as runtime
|
||||
|
||||
RUN apk add --no-cache libstdc++
|
||||
RUN apk add --no-cache strace
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Copy source code for gcc
|
||||
COPY --chown=app:app --from=build /opt /opt
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
||||
CMD ["--help"]
|
1
Dockerfile
Symbolic link
1
Dockerfile
Symbolic link
@ -0,0 +1 @@
|
||||
docker/Dockerfile.centos
|
@ -38,7 +38,7 @@ Interested? Go read the [docs](https://machinezone.github.io/IXWebSocket/)! If t
|
||||
|
||||
IXWebSocket is actively being developed, check out the [changelog](https://machinezone.github.io/IXWebSocket/CHANGELOG/) to know what's cooking. If you are looking for a real time messaging service (the chat-like 'server' your websocket code will talk to) with many features such as history, backed by Redis, look at [cobra](https://github.com/machinezone/cobra).
|
||||
|
||||
IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/IXWebSocket/autobahn/index.html). Some tests are still failing in the server code.
|
||||
IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code.
|
||||
|
||||
## Users
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM alpine as build
|
||||
FROM alpine:3.11 as build
|
||||
|
||||
RUN apk add --no-cache gcc g++ musl-dev linux-headers cmake openssl-dev
|
||||
RUN apk add --no-cache make
|
||||
@ -15,20 +15,25 @@ WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
FROM alpine as runtime
|
||||
FROM alpine:3.11 as runtime
|
||||
|
||||
RUN apk add --no-cache libstdc++
|
||||
RUN apk add --no-cache strace
|
||||
RUN apk add --no-cache gdb
|
||||
|
||||
RUN addgroup -S app && adduser -S -G app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Copy source code for gcc
|
||||
COPY --chown=app:app --from=build /opt /opt
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
||||
CMD ["--help"]
|
||||
|
35
docker/Dockerfile.centos
Normal file
35
docker/Dockerfile.centos
Normal file
@ -0,0 +1,35 @@
|
||||
FROM centos:8 as build
|
||||
|
||||
RUN yum install -y gcc-c++ make cmake zlib-devel openssl-devel redhat-rpm-config
|
||||
|
||||
RUN groupadd app && useradd -g app app
|
||||
RUN chown -R app:app /opt
|
||||
RUN chown -R app:app /usr/local
|
||||
|
||||
# There is a bug in CMake where we cannot build from the root top folder
|
||||
# So we build from /opt
|
||||
COPY --chown=app:app . /opt
|
||||
WORKDIR /opt
|
||||
|
||||
USER app
|
||||
RUN [ "make", "ws_install" ]
|
||||
RUN [ "rm", "-rf", "build" ]
|
||||
|
||||
FROM centos:8 as runtime
|
||||
|
||||
RUN yum install -y gdb strace
|
||||
|
||||
RUN groupadd app && useradd -g app app
|
||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||
RUN chmod +x /usr/local/bin/ws
|
||||
RUN ldd /usr/local/bin/ws
|
||||
|
||||
# Copy source code for gcc
|
||||
COPY --chown=app:app --from=build /opt /opt
|
||||
|
||||
# Now run in usermode
|
||||
USER app
|
||||
WORKDIR /home/app
|
||||
|
||||
ENTRYPOINT ["ws"]
|
||||
EXPOSE 8008
|
@ -1,6 +1,22 @@
|
||||
# Changelog
|
||||
All changes to this project will be documented in this file.
|
||||
|
||||
## [7.9.6] - 2020-01-22
|
||||
|
||||
(ws) add a dnslookup sub-command, to get the ip address of a remote host
|
||||
|
||||
## [7.9.5] - 2020-01-14
|
||||
|
||||
(windows) fix #144, get rid of stubbed/un-implemented windows schannel ssl backend
|
||||
|
||||
## [7.9.4] - 2020-01-12
|
||||
|
||||
(openssl + mbedssl) fix #140, can send large files with ws send over ssl / still broken with apple ssl
|
||||
|
||||
## [7.9.3] - 2020-01-10
|
||||
|
||||
(apple ssl) model write method after the OpenSSL one for consistency
|
||||
|
||||
## [7.9.2] - 2020-01-06
|
||||
|
||||
(apple ssl) unify read and write ssl utility code
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include "IXSelectInterruptFactory.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <ixwebsocket/IXSelectInterruptPipe.h>
|
||||
#include "IXSelectInterruptPipe.h"
|
||||
#else
|
||||
#include <ixwebsocket/IXSelectInterrupt.h>
|
||||
#include "IXSelectInterrupt.h"
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
|
@ -54,14 +54,17 @@ namespace ix
|
||||
// to ::poll does fix that.
|
||||
//
|
||||
// However poll isn't as portable as select and has bugs on Windows, so we
|
||||
// should write a shim to fallback to select on those platforms. See
|
||||
// have a shim to fallback to select on those platforms. See
|
||||
// https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
||||
//
|
||||
nfds_t nfds = 1;
|
||||
struct pollfd fds[2];
|
||||
memset(fds, 0, sizeof(fds));
|
||||
|
||||
fds[0].fd = sockfd;
|
||||
fds[0].events = (readyToRead) ? POLLIN : POLLOUT;
|
||||
|
||||
// this is ignored by poll, but our select based poll wrapper on Windows needs it
|
||||
fds[0].events |= POLLERR;
|
||||
|
||||
// File descriptor used to interrupt select when needed
|
||||
@ -132,6 +135,11 @@ namespace ix
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (sockfd != -1 && (fds[0].revents & POLLERR || fds[0].revents & POLLHUP ||
|
||||
fds[0].revents & POLLNVAL))
|
||||
{
|
||||
pollResult = PollResultType::Error;
|
||||
}
|
||||
|
||||
return pollResult;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ namespace ix
|
||||
virtual void close();
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length);
|
||||
virtual ssize_t send(const std::string& buffer);
|
||||
ssize_t send(const std::string& buffer);
|
||||
virtual ssize_t recv(void* buffer, size_t length);
|
||||
|
||||
// Blocking and cancellable versions, working with socket that can be set
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
#define socketerrno errno
|
||||
|
||||
#include <Security/SecureTransport.h>
|
||||
@ -31,12 +32,17 @@ namespace ix
|
||||
, _sslContext(nullptr)
|
||||
, _tlsOptions(tlsOptions)
|
||||
{
|
||||
;
|
||||
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||
SSLSetIOFuncs(
|
||||
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
|
||||
}
|
||||
|
||||
SocketAppleSSL::~SocketAppleSSL()
|
||||
{
|
||||
SocketAppleSSL::close();
|
||||
CFRelease(_sslContext);
|
||||
_sslContext = nullptr;
|
||||
|
||||
Socket::close();
|
||||
}
|
||||
|
||||
std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status)
|
||||
@ -177,14 +183,16 @@ namespace ix
|
||||
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
||||
if (_sockfd == -1) return false;
|
||||
|
||||
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||
|
||||
SSLSetIOFuncs(
|
||||
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
|
||||
SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
|
||||
SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
|
||||
SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
|
||||
|
||||
// Record a peer id, which speed up SSL connection when reconnecting to the same host
|
||||
std::stringstream ss;
|
||||
ss << host << ":" << port;
|
||||
_peerId = ss.str();
|
||||
SSLSetPeerID(_sslContext, (void*) _peerId.c_str(), _peerId.size());
|
||||
|
||||
if (_tlsOptions.isPeerVerifyDisabled())
|
||||
{
|
||||
Boolean option(1);
|
||||
@ -227,12 +235,7 @@ namespace ix
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
if (_sslContext == nullptr) return;
|
||||
|
||||
SSLClose(_sslContext);
|
||||
CFRelease(_sslContext);
|
||||
_sslContext = nullptr;
|
||||
|
||||
Socket::close();
|
||||
}
|
||||
|
||||
@ -265,11 +268,6 @@ namespace ix
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t SocketAppleSSL::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
}
|
||||
|
||||
// No wait support
|
||||
ssize_t SocketAppleSSL::recv(void* buf, size_t nbyte)
|
||||
{
|
||||
|
@ -30,7 +30,6 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
@ -42,6 +41,8 @@ namespace ix
|
||||
mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
|
||||
|
||||
SocketTLSOptions _tlsOptions;
|
||||
|
||||
std::string _peerId;
|
||||
};
|
||||
|
||||
} // namespace ix
|
||||
|
@ -19,10 +19,12 @@
|
||||
#include <linux/tcp.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
//
|
||||
// This function can be cancelled every 50 ms
|
||||
// This function can be cancelled every 10 ms
|
||||
// This is important so that we don't block the main UI thread when shutting down a
|
||||
// connection which is already trying to reconnect, and can be blocked waiting for
|
||||
// ::connect to respond.
|
||||
@ -44,8 +46,15 @@ namespace ix
|
||||
// block us for too long
|
||||
SocketConnect::configure(fd);
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
int res = ::connect(fd, address->ai_addr, address->ai_addrlen);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
|
||||
auto ms = milliseconds.count();
|
||||
std::cout << "tcp connection completed in " << ms << "ms" << std::endl;
|
||||
|
||||
if (res == -1 && !Socket::isWaitNeeded())
|
||||
{
|
||||
errMsg = strerror(Socket::getErrno());
|
||||
@ -98,11 +107,19 @@ namespace ix
|
||||
std::string& errMsg,
|
||||
const CancellationRequest& isCancellationRequested)
|
||||
{
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
//
|
||||
// First do DNS resolution
|
||||
//
|
||||
auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
|
||||
struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
|
||||
auto ms = milliseconds.count();
|
||||
std::cout << "dns resolution completed in " << ms << "ms" << std::endl;
|
||||
|
||||
if (res == nullptr)
|
||||
{
|
||||
return -1;
|
||||
|
@ -9,18 +9,16 @@
|
||||
#ifdef IXWEBSOCKET_USE_TLS
|
||||
|
||||
#ifdef IXWEBSOCKET_USE_MBED_TLS
|
||||
#include <ixwebsocket/IXSocketMbedTLS.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <ixwebsocket/IXSocketSChannel.h>
|
||||
#include "IXSocketMbedTLS.h"
|
||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||
#include <ixwebsocket/IXSocketOpenSSL.h>
|
||||
#include "IXSocketOpenSSL.h"
|
||||
#elif __APPLE__
|
||||
#include <ixwebsocket/IXSocketAppleSSL.h>
|
||||
#include "IXSocketAppleSSL.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
#include "IXSocket.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,8 +44,6 @@ namespace ix
|
||||
socket = std::make_shared<SocketMbedTLS>(tlsOptions, fd);
|
||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||
socket = std::make_shared<SocketOpenSSL>(tlsOptions, fd);
|
||||
#elif defined(_WIN32)
|
||||
socket = std::make_shared<SocketSChannel>(tlsOptions, fd);
|
||||
#elif defined(__APPLE__)
|
||||
socket = std::make_shared<SocketAppleSSL>(tlsOptions, fd);
|
||||
#endif
|
||||
|
@ -230,35 +230,23 @@ namespace ix
|
||||
|
||||
ssize_t SocketMbedTLS::send(char* buf, size_t nbyte)
|
||||
{
|
||||
ssize_t sent = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
while (nbyte > 0)
|
||||
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
nbyte -= res;
|
||||
sent += res;
|
||||
}
|
||||
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t SocketMbedTLS::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
}
|
||||
|
||||
ssize_t SocketMbedTLS::recv(void* buf, size_t nbyte)
|
||||
|
@ -35,7 +35,6 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
|
@ -11,8 +11,14 @@
|
||||
#include "IXSocketConnect.h"
|
||||
#include <cassert>
|
||||
#include <errno.h>
|
||||
#ifdef _WIN32
|
||||
#include <Shlwapi.h>
|
||||
#else
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#include <openssl/x509v3.h>
|
||||
#endif
|
||||
#define socketerrno errno
|
||||
|
||||
namespace ix
|
||||
@ -136,7 +142,11 @@ namespace ix
|
||||
*/
|
||||
bool SocketOpenSSL::checkHost(const std::string& host, const char* pattern)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return PathMatchSpecA(host.c_str(), pattern);
|
||||
#else
|
||||
return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl,
|
||||
@ -593,42 +603,30 @@ namespace ix
|
||||
|
||||
ssize_t SocketOpenSSL::send(char* buf, size_t nbyte)
|
||||
{
|
||||
ssize_t sent = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
while (nbyte > 0)
|
||||
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
ssize_t write_result = SSL_write(_ssl_connection, buf + sent, (int) nbyte);
|
||||
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
||||
|
||||
if (reason == SSL_ERROR_NONE)
|
||||
{
|
||||
nbyte -= write_result;
|
||||
sent += write_result;
|
||||
}
|
||||
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t SocketOpenSSL::send(const std::string& buffer)
|
||||
{
|
||||
return send((char*) &buffer[0], buffer.size());
|
||||
ERR_clear_error();
|
||||
ssize_t write_result = SSL_write(_ssl_connection, buf, (int) nbyte);
|
||||
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
||||
|
||||
if (reason == SSL_ERROR_NONE)
|
||||
{
|
||||
return write_result;
|
||||
}
|
||||
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
errno = EWOULDBLOCK;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t SocketOpenSSL::recv(void* buf, size_t nbyte)
|
||||
|
@ -33,7 +33,6 @@ namespace ix
|
||||
virtual void close() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* IXSocketSChannel.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*
|
||||
* See https://docs.microsoft.com/en-us/windows/desktop/WinSock/using-secure-socket-extensions
|
||||
*
|
||||
* https://github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/netds/winsock/securesocket/stcpclient/tcpclient.c
|
||||
*
|
||||
* This is the right example to look at:
|
||||
* https://www.codeproject.com/Articles/1000189/A-Working-TCP-Client-and-Server-With-SSL
|
||||
*
|
||||
* Similar code is available from this git repo
|
||||
* https://github.com/david-maw/StreamSSL
|
||||
*/
|
||||
#include "IXSocketSChannel.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#include <basetsd.h>
|
||||
#include <io.h>
|
||||
#include <schannel.h>
|
||||
#include <ws2def.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <mstcpip.h>
|
||||
#include <ntdsapi.h>
|
||||
#include <rpc.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define RECV_DATA_BUF_SIZE 256
|
||||
|
||||
// Link with ws2_32.lib
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
// link with fwpuclnt.lib for Winsock secure socket extensions
|
||||
#pragma comment(lib, "fwpuclnt.lib")
|
||||
|
||||
// link with ntdsapi.lib for DsMakeSpn function
|
||||
#pragma comment(lib, "ntdsapi.lib")
|
||||
|
||||
// The following function assumes that Winsock
|
||||
// has already been initialized
|
||||
|
||||
|
||||
#else
|
||||
#error("This file should only be built on Windows")
|
||||
#endif
|
||||
|
||||
namespace ix
|
||||
{
|
||||
SocketSChannel::SocketSChannel()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
SocketSChannel::~SocketSChannel()
|
||||
{
|
||||
}
|
||||
|
||||
bool SocketSChannel::connect(const std::string& host, int port, std::string& errMsg)
|
||||
{
|
||||
return Socket::connect(host, port, errMsg, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void SocketSChannel::secureSocket()
|
||||
{
|
||||
// there will be a lot to do here ...
|
||||
}
|
||||
|
||||
void SocketSChannel::close()
|
||||
{
|
||||
Socket::close();
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::send(char* buf, size_t nbyte)
|
||||
{
|
||||
return Socket::send(buf, nbyte);
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::send(const std::string& buffer)
|
||||
{
|
||||
return Socket::send(buffer);
|
||||
}
|
||||
|
||||
ssize_t SocketSChannel::recv(void* buf, size_t nbyte)
|
||||
{
|
||||
return Socket::recv(buf, nbyte);
|
||||
}
|
||||
|
||||
} // namespace ix
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* IXSocketSChannel.h
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IXSocket.h"
|
||||
|
||||
namespace ix
|
||||
{
|
||||
class SocketSChannel final : public Socket
|
||||
{
|
||||
public:
|
||||
SocketSChannel();
|
||||
~SocketSChannel();
|
||||
|
||||
virtual bool connect(const std::string& host, int port, std::string& errMsg) final;
|
||||
virtual void close() final;
|
||||
|
||||
// The important override
|
||||
virtual void secureSocket() final;
|
||||
|
||||
virtual ssize_t send(char* buffer, size_t length) final;
|
||||
virtual ssize_t send(const std::string& buffer) final;
|
||||
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace ix
|
@ -15,6 +15,9 @@
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace ix
|
||||
{
|
||||
@ -97,8 +100,16 @@ namespace ix
|
||||
auto isCancellationRequested =
|
||||
makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
std::string errMsg;
|
||||
bool success = _socket->connect(host, port, errMsg, isCancellationRequested);
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
|
||||
auto ms = milliseconds.count();
|
||||
std::cout << "connection completed in " << ms << "ms" << std::endl;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
@ -151,7 +151,18 @@ namespace ix
|
||||
|
||||
std::string errorMsg;
|
||||
bool tls = protocol == "wss";
|
||||
_socket = createSocket(tls, -1, errorMsg, _socketTLSOptions);
|
||||
|
||||
if (_host == host)
|
||||
{
|
||||
_socket->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
_socket = createSocket(tls, -1, errorMsg, _socketTLSOptions);
|
||||
}
|
||||
|
||||
// Record the host for later
|
||||
_host = host;
|
||||
|
||||
if (!_socket)
|
||||
{
|
||||
@ -350,28 +361,9 @@ namespace ix
|
||||
}
|
||||
else if (pollResult == PollResultType::ReadyForRead)
|
||||
{
|
||||
while (true)
|
||||
if (!receiveFromSocket())
|
||||
{
|
||||
ssize_t ret = _socket->recv((char*) &_readbuf[0], _readbuf.size());
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ret <= 0)
|
||||
{
|
||||
// if there are received data pending to be processed, then delay the abnormal
|
||||
// closure to after dispatch (other close code/reason could be read from the
|
||||
// buffer)
|
||||
|
||||
closeSocket();
|
||||
|
||||
return PollResult::AbnormalClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rxbuf.insert(_rxbuf.end(), _readbuf.begin(), _readbuf.begin() + ret);
|
||||
}
|
||||
return PollResult::AbnormalClose;
|
||||
}
|
||||
}
|
||||
else if (pollResult == PollResultType::Error)
|
||||
@ -739,7 +731,7 @@ namespace ix
|
||||
|
||||
// if an abnormal closure was raised in poll, and nothing else triggered a CLOSED state in
|
||||
// the received and processed data then close the connection
|
||||
if (pollResult == PollResult::AbnormalClose)
|
||||
if (pollResult != PollResult::Succeeded)
|
||||
{
|
||||
_rxbuf.clear();
|
||||
|
||||
@ -1053,19 +1045,17 @@ namespace ix
|
||||
wsheader_type::TEXT_FRAME, message, _enablePerMessageDeflate, onProgressCallback);
|
||||
}
|
||||
|
||||
ssize_t WebSocketTransport::send()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||
return _socket->send((char*) &_txbuf[0], _txbuf.size());
|
||||
}
|
||||
|
||||
bool WebSocketTransport::sendOnSocket()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_txbufMutex);
|
||||
|
||||
while (_txbuf.size())
|
||||
{
|
||||
ssize_t ret = send();
|
||||
ssize_t ret = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||
ret = _socket->send((char*) &_txbuf[0], _txbuf.size());
|
||||
}
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
@ -1086,6 +1076,34 @@ namespace ix
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebSocketTransport::receiveFromSocket()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ssize_t ret = _socket->recv((char*) &_readbuf[0], _readbuf.size());
|
||||
|
||||
if (ret < 0 && Socket::isWaitNeeded())
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ret <= 0)
|
||||
{
|
||||
// if there are received data pending to be processed, then delay the abnormal
|
||||
// closure to after dispatch (other close code/reason could be read from the
|
||||
// buffer)
|
||||
|
||||
closeSocket();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rxbuf.insert(_rxbuf.end(), _readbuf.begin(), _readbuf.begin() + ret);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketTransport::sendCloseFrame(uint16_t code, const std::string& reason)
|
||||
{
|
||||
bool compress = false;
|
||||
|
@ -99,7 +99,6 @@ namespace ix
|
||||
bool remote = false);
|
||||
|
||||
void closeSocket();
|
||||
ssize_t send();
|
||||
|
||||
ReadyState getReadyState() const;
|
||||
void setReadyState(ReadyState readyState);
|
||||
@ -108,7 +107,7 @@ namespace ix
|
||||
size_t bufferedAmount() const;
|
||||
|
||||
private:
|
||||
std::string _url;
|
||||
std::string _host;
|
||||
|
||||
struct wsheader_type
|
||||
{
|
||||
@ -245,6 +244,8 @@ namespace ix
|
||||
|
||||
bool flushSendBuffer();
|
||||
bool sendOnSocket();
|
||||
bool receiveFromSocket();
|
||||
|
||||
WebSocketSendInfo sendData(wsheader_type::opcode_type type,
|
||||
const std::string& message,
|
||||
bool compress,
|
||||
|
@ -6,4 +6,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IX_WEBSOCKET_VERSION "7.9.2"
|
||||
#define IX_WEBSOCKET_VERSION "7.9.6"
|
||||
|
@ -55,12 +55,12 @@ set (SOURCES
|
||||
IXDNSLookupTest.cpp
|
||||
IXWebSocketSubProtocolTest.cpp
|
||||
IXSentryClientTest.cpp
|
||||
IXWebSocketChatTest.cpp
|
||||
)
|
||||
|
||||
# Some unittest don't work on windows yet
|
||||
if (UNIX)
|
||||
list(APPEND SOURCES
|
||||
IXWebSocketChatTest.cpp
|
||||
IXWebSocketCloseTest.cpp
|
||||
)
|
||||
endif()
|
||||
|
@ -1,8 +1,17 @@
|
||||
FROM python:3.8.0-alpine3.10
|
||||
|
||||
RUN pip install websockets
|
||||
COPY ws_proxy.py /usr/bin
|
||||
RUN chmod +x /usr/bin/ws_proxy.py
|
||||
|
||||
EXPOSE 8765
|
||||
CMD ["python", "/usr/bin/ws_proxy.py"]
|
||||
COPY vendor/protocol.py /usr/local/lib/python3.8/site-packages/websockets/protocol.py
|
||||
|
||||
COPY *.py /usr/bin/
|
||||
COPY entrypoint.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/*.py
|
||||
|
||||
RUN mkdir /certs
|
||||
COPY *.pem /certs/
|
||||
|
||||
WORKDIR /certs
|
||||
|
||||
EXPOSE 8765 8766
|
||||
CMD ["sh", "/usr/bin/entrypoint.sh"]
|
||||
|
@ -830,3 +830,17 @@ $ honcho start
|
||||
15:29:59 system | nginx.1 stopped (rc=0)
|
||||
15:29:59 system | websocket_server.1 stopped (rc=-15)
|
||||
```
|
||||
|
||||
## Sending large files over SSL
|
||||
|
||||
Running inside docker
|
||||
|
||||
```
|
||||
$ make docker && make server_ssl
|
||||
```
|
||||
|
||||
On the client
|
||||
|
||||
```
|
||||
$ make ws_mbedtls && cp build/ws/ws /usr/local/bin/ws && ws send --verify_none wss://localhost:8766 /tmp/big_file
|
||||
```
|
||||
|
36
test/compatibility/python/websockets/broadcast_server.py
Normal file
36
test/compatibility/python/websockets/broadcast_server.py
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# WS server example
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import websockets
|
||||
|
||||
|
||||
clients = set()
|
||||
|
||||
|
||||
async def echo(websocket, path):
|
||||
clients.add(websocket)
|
||||
|
||||
try:
|
||||
while True:
|
||||
msg = await websocket.recv()
|
||||
|
||||
for ws in clients:
|
||||
if ws != websocket:
|
||||
print(f'Sending {len(msg)} bytes to {ws}')
|
||||
await ws.send(msg)
|
||||
except websockets.exceptions.ConnectionClosedOK:
|
||||
print('Client terminating')
|
||||
clients.remove(websocket)
|
||||
|
||||
|
||||
host = os.getenv('BIND_HOST', 'localhost')
|
||||
print(f'Serving on {host}:8766')
|
||||
|
||||
start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
||||
|
43
test/compatibility/python/websockets/broadcast_server_ssl.py
Normal file
43
test/compatibility/python/websockets/broadcast_server_ssl.py
Normal file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# WS server example
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import pathlib
|
||||
import ssl
|
||||
import websockets
|
||||
|
||||
|
||||
clients = set()
|
||||
|
||||
|
||||
async def echo(websocket, path):
|
||||
clients.add(websocket)
|
||||
|
||||
try:
|
||||
while True:
|
||||
msg = await websocket.recv()
|
||||
|
||||
for ws in clients:
|
||||
if ws != websocket:
|
||||
print(f'Sending {len(msg)} bytes to {ws}')
|
||||
await ws.send(msg)
|
||||
except websockets.exceptions.ConnectionClosedOK:
|
||||
print('Client terminating')
|
||||
clients.remove(websocket)
|
||||
|
||||
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain('trusted-server-crt.pem',
|
||||
'trusted-server-key.pem')
|
||||
|
||||
host = os.getenv('BIND_HOST', 'localhost')
|
||||
print(f'Serving on {host}:8766')
|
||||
|
||||
start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30, ssl=ssl_context)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
# WS server example
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import websockets
|
||||
|
||||
|
||||
@ -11,9 +12,10 @@ async def echo(websocket, path):
|
||||
print(f'Received {len(msg)} bytes')
|
||||
await websocket.send(msg)
|
||||
|
||||
host = os.getenv('BIND_HOST', 'localhost')
|
||||
print(f'Serving on {host}:8766')
|
||||
|
||||
print('Serving on localhost:8766')
|
||||
start_server = websockets.serve(echo, 'localhost', 8766, max_size=2 ** 25)
|
||||
start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
||||
|
27
test/compatibility/python/websockets/echo_server_ssl.py
Normal file
27
test/compatibility/python/websockets/echo_server_ssl.py
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# WS server example
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import pathlib
|
||||
import ssl
|
||||
import websockets
|
||||
|
||||
|
||||
async def echo(websocket, path):
|
||||
msg = await websocket.recv()
|
||||
print(f'Received {len(msg)} bytes')
|
||||
await websocket.send(msg)
|
||||
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain('trusted-server-crt.pem',
|
||||
'trusted-server-key.pem')
|
||||
|
||||
host = os.getenv('BIND_HOST', 'localhost')
|
||||
print(f'Serving on {host}:8766')
|
||||
|
||||
start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30, ssl=ssl_context)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
16
test/compatibility/python/websockets/entrypoint.sh
Normal file
16
test/compatibility/python/websockets/entrypoint.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
case $MODE in
|
||||
echo_server)
|
||||
python /usr/bin/echo_server.py
|
||||
;;
|
||||
echo_server_ssl)
|
||||
python /usr/bin/echo_server_ssl.py
|
||||
;;
|
||||
broadcast_server)
|
||||
python /usr/bin/broadcast_server.py
|
||||
;;
|
||||
broadcast_server_ssl)
|
||||
python /usr/bin/broadcast_server_ssl.py
|
||||
;;
|
||||
esac
|
1
test/compatibility/python/websockets/localhost.pem
Symbolic link
1
test/compatibility/python/websockets/localhost.pem
Symbolic link
@ -0,0 +1 @@
|
||||
trusted-client-crt.pem
|
@ -3,7 +3,7 @@ all:
|
||||
|
||||
.PHONY: docker
|
||||
|
||||
NAME := bsergean/ws_proxy
|
||||
NAME := bsergean/echo_server
|
||||
TAG := $(shell cat DOCKER_VERSION)
|
||||
IMG := ${NAME}:${TAG}
|
||||
LATEST := ${NAME}:latest
|
||||
@ -21,3 +21,15 @@ docker_push:
|
||||
docker tag ${IMG} ${LATEST}
|
||||
docker push ${LATEST}
|
||||
docker push ${IMG}
|
||||
|
||||
echo_server:
|
||||
docker run -p 8766:8766 -e BIND_HOST=0.0.0.0 -e MODE=echo_server -it --rm bsergean/echo_server:build
|
||||
|
||||
echo_server_ssl:
|
||||
docker run -p 8766:8766 -e BIND_HOST=0.0.0.0 -e MODE=echo_server_ssl -it --rm bsergean/echo_server:build
|
||||
|
||||
broadcast_server:
|
||||
docker run -p 8766:8766 -e BIND_HOST=0.0.0.0 -e MODE=broadcast_server -it --rm bsergean/echo_server:build
|
||||
|
||||
broadcast_server_ssl:
|
||||
docker run -p 8766:8766 -e BIND_HOST=0.0.0.0 -e MODE=broadcast_server_ssl -it --rm bsergean/echo_server:build
|
||||
|
19
test/compatibility/python/websockets/trusted-server-crt.pem
Normal file
19
test/compatibility/python/websockets/trusted-server-crt.pem
Normal file
@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDLDCCAhSgAwIBAgIJALyEpMxNH62fMA0GCSqGSIb3DQEBCwUAMEExFDASBgNV
|
||||
BAoMC21hY2hpbmV6b25lMRQwEgYDVQQKDAtJWFdlYlNvY2tldDETMBEGA1UEAwwK
|
||||
dHJ1c3RlZC1jYTAeFw0xOTEyMjQwMDM3MzVaFw0yMDEyMjMwMDM3MzVaMEUxFDAS
|
||||
BgNVBAoMC21hY2hpbmV6b25lMRQwEgYDVQQKDAtJWFdlYlNvY2tldDEXMBUGA1UE
|
||||
AwwOdHJ1c3RlZC1zZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||
AQCv0T68TZZ7nab+UWPhssGLrInE0egzWn1AF20RkJv1ePIyU0rQbDxuuP+HQbXD
|
||||
FzF6vo2j+5p+VxxvUOfko9V6xad3cB4T3AoFrT5sYI8gQX1uby6pjqVX16TK5t+c
|
||||
i56aNhUXdmcWhuUzlIMIauvueohd+pNj6E6weWqCf8QFD6KYPgK3wWCR4VfWA5QY
|
||||
RJUhv2aI9HrC9P4Mg0mut8LYURRQvGxOhtbAw76FJ6IgBujpgI5GLHgVK5Q1GlXK
|
||||
8W7RlNKNmxX+mzK2D6nHixCUGvrFk9nZgZiaHI/h5x0IGXu0sbwlTPjqQ4Axpofw
|
||||
G1FDi/er4FaGCzU4CKmc7rxRAgMBAAGjIzAhMB8GA1UdEQQYMBaCCWxvY2FsaG9z
|
||||
dIIJMTI3LjAuMC4xMA0GCSqGSIb3DQEBCwUAA4IBAQBkUB6smmApnBfr2eDwKJew
|
||||
GQUMUAa7TlyANYlwQ6EjbAH7H6oNf7Sm63Go2Y72JjZPw3OvZl3QcvvS14QxYJ71
|
||||
kRdvJ1mhEbIaA2QkdZCuDmcQGLfVEyo0j5q03amQKt9QtSv9MsX1Ok2HqGL17Tf1
|
||||
QiUqlkzGCqMIsU20X8QzqwYCGzYZeTFtwLYi75za15Uo/6tE2KwzU7oUhuIebOaS
|
||||
Sa+s2Y1TjpbWyw9usnuQWQ0k1FJR78F1mKJGghmPBoySBHJdLkLYOMhE1u2shgk5
|
||||
N0muMcDRTeHLxm1aBPLHtkRbW3QscEQB6GkT2Dt4U66qNV2CY7Gk0F5xxOrGBC/9
|
||||
-----END CERTIFICATE-----
|
27
test/compatibility/python/websockets/trusted-server-key.pem
Normal file
27
test/compatibility/python/websockets/trusted-server-key.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAr9E+vE2We52m/lFj4bLBi6yJxNHoM1p9QBdtEZCb9XjyMlNK
|
||||
0Gw8brj/h0G1wxcxer6No/uaflccb1Dn5KPVesWnd3AeE9wKBa0+bGCPIEF9bm8u
|
||||
qY6lV9ekyubfnIuemjYVF3ZnFoblM5SDCGrr7nqIXfqTY+hOsHlqgn/EBQ+imD4C
|
||||
t8FgkeFX1gOUGESVIb9miPR6wvT+DINJrrfC2FEUULxsTobWwMO+hSeiIAbo6YCO
|
||||
Rix4FSuUNRpVyvFu0ZTSjZsV/psytg+px4sQlBr6xZPZ2YGYmhyP4ecdCBl7tLG8
|
||||
JUz46kOAMaaH8BtRQ4v3q+BWhgs1OAipnO68UQIDAQABAoIBAG/bIR2uAyJMT7UX
|
||||
VQN/tbFGKTRmE2Owm2UOQl7dcMvAkd5AraViZyROYIvN23TuKZWc7AI7DbR5eWa8
|
||||
w3vsW+JLI9tSImCiKmIoMUHEQOrVn5aF99r6HOmBEZ/hOLyg+1vDMrIFq1pioimp
|
||||
v5+4XrgPjvizddgnMQEHjiLOZIiOtin+alixN/W41Ij0jOtRycM5wq3Xr/0RAs5A
|
||||
ziNeQvWdvDwqa6L9upHZpFfYqP/+KflJPlHLfEkBHZtZQF3uy5tQ1VusfVMO3Xvb
|
||||
Ljk6RBnD9dKayreD9NVzotr36zYEy/V1oGJcP/8AD1xmDA0/2Kb+bfm+WQHG5wp6
|
||||
o09zsZECgYEA5Y3d79Nrfi6InVaZ0r5Y+XXqSZFTsgFnxRseVEbuK4jvrh7eC9jW
|
||||
pWoaXDh8W6RoT59BPSCKtbQ9mjdECh+aJ6MOeCzCiGSppJboOhC1iVFqFuQLDRO7
|
||||
w+2NgkhOvNnJJJYmdTwfokTLmaRUiNqwWAtBm+h7py9e5eXujzqt4+UCgYEAxBKL
|
||||
OO8CWRb0yGlwKoCwYgGCsVauvbZHaELOAKJUB6H+YhZ+SJqd915u8aYs5nbcMyne
|
||||
5kuewzd+32WpkykI0Fz4SrGvDETKB5/Yynblp9m69LNdgYoVWgQqQocXVw0nD/nA
|
||||
KQdFSBZZRExXC/aUAa55txFJitMC4FjgTENgR/0CgYAS/OonxVg15sl8Ika1DPO1
|
||||
JtDLZw8CQWWBA1494GQhC8GvqHP7jOMsaZtml3GJ7w6Fz4mI8eEnaJJT6FBjefu5
|
||||
XZ57yFALEjCKIcVx0CIECsz4ucJEQaadbU/wP+TrcCRYN2dU+TUwqfohaltnupct
|
||||
oTi7Gb7otF1oLN3P0S3DFQKBgEnVjdXPszunOGBrzBBFS6ZsWTG8qarJBFTPq1Fz
|
||||
z17ccrWvMLjYeJnZVr/qyseyhLNDlit02IE82ar4VoYTEr2b9Ofzxy5AjS+X0wRT
|
||||
B6JQjGVvUcvhGq8+GEfbJT/jtQ0ACIuqsD04JT9h2/mmTg/gCveUK/R6B4BCF5zA
|
||||
VnZlAoGBANOG5T7KsOH+Hbb//dEmfZYMQmkO/+1Pac9eP4uDFNAVF00M6XHf5LrR
|
||||
gRp5t46drDtLgxdufN0oUItp8y74EuMa9FHlBQVZRaSqYF4bCgf2PieGApbKWG2n
|
||||
QhnxYfZqf9S2oVK95EHiJxmtumOFBL7YI9NdzNEeoJExS5Bw6kUn
|
||||
-----END RSA PRIVATE KEY-----
|
1432
test/compatibility/python/websockets/vendor/protocol.py
vendored
Normal file
1432
test/compatibility/python/websockets/vendor/protocol.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -65,6 +65,7 @@ add_executable(ws
|
||||
ws_autobahn.cpp
|
||||
ws_proxy_server.cpp
|
||||
ws_sentry_minidump_upload.cpp
|
||||
ws_dns_lookup.cpp
|
||||
ws.cpp)
|
||||
|
||||
target_link_libraries(ws ixsnake)
|
||||
|
10
ws/ws.cpp
10
ws/ws.cpp
@ -21,6 +21,9 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <signal.h>
|
||||
#else
|
||||
#include <process.h>
|
||||
#define getpid _getpid
|
||||
#endif
|
||||
|
||||
|
||||
@ -335,6 +338,9 @@ int main(int argc, char** argv)
|
||||
minidumpApp->add_option("--key", key, "Sentry Key")->required();
|
||||
minidumpApp->add_flag("-v", verbose, "Verbose");
|
||||
|
||||
CLI::App* dnsLookupApp = app.add_subcommand("dnslookup", "DNS lookup");
|
||||
dnsLookupApp->add_option("host", hostname, "Hostname")->required();
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
// pid file handling
|
||||
@ -506,6 +512,10 @@ int main(int argc, char** argv)
|
||||
{
|
||||
ret = ix::ws_sentry_minidump_upload(metadata, minidump, project, key, verbose);
|
||||
}
|
||||
else if (app.got_subcommand("dnslookup"))
|
||||
{
|
||||
ret = ix::ws_dns_lookup(hostname);
|
||||
}
|
||||
else if (version)
|
||||
{
|
||||
spdlog::info("ws {}", ix::userAgent());
|
||||
|
2
ws/ws.h
2
ws/ws.h
@ -163,4 +163,6 @@ namespace ix
|
||||
const std::string& project,
|
||||
const std::string& key,
|
||||
bool verbose);
|
||||
|
||||
int ws_dns_lookup(const std::string& hostname);
|
||||
} // namespace ix
|
||||
|
@ -72,7 +72,7 @@ namespace ix
|
||||
size_t bufferedAmount = client->bufferedAmount();
|
||||
spdlog::info("{} bytes left to be sent", bufferedAmount);
|
||||
|
||||
std::chrono::duration<double, std::milli> duration(10);
|
||||
std::chrono::duration<double, std::milli> duration(500);
|
||||
std::this_thread::sleep_for(duration);
|
||||
} while (client->bufferedAmount() != 0);
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
// Broadcast server can be ran with `ws broadcast_server`
|
||||
//
|
||||
|
||||
#include "linenoise.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <iostream>
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <queue>
|
||||
@ -172,9 +172,10 @@ namespace ix
|
||||
{
|
||||
// Read line
|
||||
std::string line;
|
||||
auto quit = linenoise::Readline("> ", line);
|
||||
std::cout << user << " > " << std::flush;
|
||||
std::getline(std::cin, line);
|
||||
|
||||
if (quit)
|
||||
if (!std::cin)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
34
ws/ws_dns_lookup.cpp
Normal file
34
ws/ws_dns_lookup.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* ws_dns_lookup.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXNetSystem.h>
|
||||
#include <ixwebsocket/IXDNSLookup.h>
|
||||
|
||||
|
||||
namespace ix
|
||||
{
|
||||
int ws_dns_lookup(const std::string& hostname)
|
||||
{
|
||||
auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80);
|
||||
|
||||
std::string errMsg;
|
||||
struct addrinfo* res;
|
||||
|
||||
res = dnsLookup->resolve(errMsg, [] { return false; });
|
||||
|
||||
auto addr = res->ai_addr;
|
||||
|
||||
char str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN);
|
||||
|
||||
spdlog::info("host: {} ip: {}", hostname, str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace ix
|
@ -45,6 +45,8 @@ namespace ix
|
||||
ix::WebSocket _webSocket;
|
||||
bool _enablePerMessageDeflate;
|
||||
|
||||
std::atomic<bool> _connected;
|
||||
|
||||
std::mutex _conditionVariableMutex;
|
||||
std::condition_variable _condition;
|
||||
|
||||
@ -56,6 +58,7 @@ namespace ix
|
||||
const ix::SocketTLSOptions& tlsOptions)
|
||||
: _url(url)
|
||||
, _enablePerMessageDeflate(enablePerMessageDeflate)
|
||||
, _connected(false)
|
||||
{
|
||||
_webSocket.disableAutomaticReconnection();
|
||||
_webSocket.setTLSOptions(tlsOptions);
|
||||
@ -119,6 +122,8 @@ namespace ix
|
||||
std::stringstream ss;
|
||||
if (msg->type == ix::WebSocketMessageType::Open)
|
||||
{
|
||||
_connected = true;
|
||||
|
||||
_condition.notify_one();
|
||||
|
||||
log("ws_send: connected");
|
||||
@ -131,6 +136,8 @@ namespace ix
|
||||
}
|
||||
else if (msg->type == ix::WebSocketMessageType::Close)
|
||||
{
|
||||
_connected = false;
|
||||
|
||||
ss << "ws_send: connection closed:";
|
||||
ss << " code " << msg->closeInfo.code;
|
||||
ss << " reason " << msg->closeInfo.reason << std::endl;
|
||||
@ -234,7 +241,7 @@ namespace ix
|
||||
{
|
||||
std::vector<uint8_t> content;
|
||||
{
|
||||
Bench bench("load file from disk");
|
||||
Bench bench("ws_send: load file from disk");
|
||||
content = load(filename);
|
||||
}
|
||||
|
||||
@ -250,18 +257,22 @@ namespace ix
|
||||
|
||||
MsgPack msg(pdu);
|
||||
|
||||
Bench bench("Sending file through websocket");
|
||||
auto result = _webSocket.sendBinary(msg.dump(), [throttle](int current, int total) -> bool {
|
||||
spdlog::info("ws_send: Step {} out of {}", current, total);
|
||||
auto serializedMsg = msg.dump();
|
||||
spdlog::info("ws_send: sending {} bytes", serializedMsg.size());
|
||||
|
||||
if (throttle)
|
||||
{
|
||||
std::chrono::duration<double, std::milli> duration(10);
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
Bench bench("ws_send: Sending file through websocket");
|
||||
auto result =
|
||||
_webSocket.sendBinary(serializedMsg, [this, throttle](int current, int total) -> bool {
|
||||
spdlog::info("ws_send: Step {} out of {}", current + 1, total);
|
||||
|
||||
return true;
|
||||
});
|
||||
if (throttle)
|
||||
{
|
||||
std::chrono::duration<double, std::milli> duration(10);
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
|
||||
return _connected;
|
||||
});
|
||||
|
||||
if (!result.success)
|
||||
{
|
||||
@ -269,22 +280,37 @@ namespace ix
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_connected)
|
||||
{
|
||||
spdlog::error("ws_send: Got disconnected from the server");
|
||||
return false;
|
||||
}
|
||||
|
||||
spdlog::info("ws_send: sent {} bytes", serializedMsg.size());
|
||||
|
||||
do
|
||||
{
|
||||
size_t bufferedAmount = _webSocket.bufferedAmount();
|
||||
spdlog::info("ws_send: {} bytes left to be sent", bufferedAmount);
|
||||
|
||||
std::chrono::duration<double, std::milli> duration(10);
|
||||
std::chrono::duration<double, std::milli> duration(500);
|
||||
std::this_thread::sleep_for(duration);
|
||||
} while (_webSocket.bufferedAmount() != 0);
|
||||
} while (_webSocket.bufferedAmount() != 0 && _connected);
|
||||
|
||||
bench.report();
|
||||
auto duration = bench.getDuration();
|
||||
auto transferRate = 1000 * content.size() / duration;
|
||||
transferRate /= (1024 * 1024);
|
||||
spdlog::info("ws_send: Send transfer rate: {} MB/s", transferRate);
|
||||
if (_connected)
|
||||
{
|
||||
bench.report();
|
||||
auto duration = bench.getDuration();
|
||||
auto transferRate = 1000 * content.size() / duration;
|
||||
transferRate /= (1024 * 1024);
|
||||
spdlog::info("ws_send: Send transfer rate: {} MB/s", transferRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::error("ws_send: Got disconnected from the server");
|
||||
}
|
||||
|
||||
return true;
|
||||
return _connected;
|
||||
}
|
||||
|
||||
void wsSend(const std::string& url,
|
||||
@ -304,6 +330,10 @@ namespace ix
|
||||
webSocketSender.waitForAck();
|
||||
spdlog::info("ws_send: Done !");
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::error("ws_send: Error sending file.");
|
||||
}
|
||||
|
||||
webSocketSender.stop();
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ namespace ix
|
||||
size_t bufferedAmount = client->bufferedAmount();
|
||||
|
||||
spdlog::info(
|
||||
"{}: [client {}]: has readystate {} bytes left to be sent",
|
||||
"{}: [client {}]: has readystate {} bytes left to be sent {}",
|
||||
"ws_transfer",
|
||||
id,
|
||||
readyStateString,
|
||||
|
Reference in New Issue
Block a user