Compare commits
1 Commits
feature/ss
...
v7.9.3
Author | SHA1 | Date | |
---|---|---|---|
74833f95e4 |
@ -129,6 +129,9 @@ if (USE_TLS)
|
|||||||
elseif (APPLE AND NOT USE_OPEN_SSL)
|
elseif (APPLE AND NOT USE_OPEN_SSL)
|
||||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
|
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
|
||||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
|
||||||
|
elseif (WIN32 AND NOT USE_OPEN_SSL)
|
||||||
|
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketSChannel.h)
|
||||||
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketSChannel.cpp)
|
||||||
else()
|
else()
|
||||||
set(USE_OPEN_SSL ON)
|
set(USE_OPEN_SSL ON)
|
||||||
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
|
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
|
||||||
|
@ -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 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/autobahn/reports/clients/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/IXWebSocket/autobahn/index.html). Some tests are still failing in the server code.
|
||||||
|
|
||||||
## Users
|
## Users
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ FROM alpine:3.11 as runtime
|
|||||||
|
|
||||||
RUN apk add --no-cache libstdc++
|
RUN apk add --no-cache libstdc++
|
||||||
RUN apk add --no-cache strace
|
RUN apk add --no-cache strace
|
||||||
RUN apk add --no-cache gdb
|
|
||||||
|
|
||||||
RUN addgroup -S app && adduser -S -G app app
|
RUN addgroup -S app && adduser -S -G app app
|
||||||
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws
|
||||||
@ -37,3 +36,4 @@ WORKDIR /home/app
|
|||||||
|
|
||||||
ENTRYPOINT ["ws"]
|
ENTRYPOINT ["ws"]
|
||||||
EXPOSE 8008
|
EXPOSE 8008
|
||||||
|
C
|
||||||
|
@ -1,21 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All changes to this project will be documented in this file.
|
All changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [7.9.6] - 2020-01-22
|
## [7.9.3] - 2020-01-08
|
||||||
|
|
||||||
(ws) add a dnslookup sub-command, to get the ip address of a remote host
|
(Windows) OpenSSL can be used for SSL communication
|
||||||
|
|
||||||
## [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
|
## [7.9.2] - 2020-01-06
|
||||||
|
|
||||||
|
@ -54,17 +54,14 @@ namespace ix
|
|||||||
// to ::poll does fix that.
|
// to ::poll does fix that.
|
||||||
//
|
//
|
||||||
// However poll isn't as portable as select and has bugs on Windows, so we
|
// However poll isn't as portable as select and has bugs on Windows, so we
|
||||||
// have a shim to fallback to select on those platforms. See
|
// should write a shim to fallback to select on those platforms. See
|
||||||
// https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
// https://github.com/mpv-player/mpv/pull/5203/files for such a select wrapper.
|
||||||
//
|
//
|
||||||
nfds_t nfds = 1;
|
nfds_t nfds = 1;
|
||||||
struct pollfd fds[2];
|
struct pollfd fds[2];
|
||||||
memset(fds, 0, sizeof(fds));
|
|
||||||
|
|
||||||
fds[0].fd = sockfd;
|
fds[0].fd = sockfd;
|
||||||
fds[0].events = (readyToRead) ? POLLIN : POLLOUT;
|
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;
|
fds[0].events |= POLLERR;
|
||||||
|
|
||||||
// File descriptor used to interrupt select when needed
|
// File descriptor used to interrupt select when needed
|
||||||
@ -135,11 +132,6 @@ namespace ix
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (sockfd != -1 && (fds[0].revents & POLLERR || fds[0].revents & POLLHUP ||
|
|
||||||
fds[0].revents & POLLNVAL))
|
|
||||||
{
|
|
||||||
pollResult = PollResultType::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pollResult;
|
return pollResult;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace ix
|
|||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
||||||
virtual ssize_t send(char* buffer, size_t length);
|
virtual ssize_t send(char* buffer, size_t length);
|
||||||
ssize_t send(const std::string& buffer);
|
virtual ssize_t send(const std::string& buffer);
|
||||||
virtual ssize_t recv(void* buffer, size_t length);
|
virtual ssize_t recv(void* buffer, size_t length);
|
||||||
|
|
||||||
// Blocking and cancellable versions, working with socket that can be set
|
// Blocking and cancellable versions, working with socket that can be set
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sstream>
|
|
||||||
#define socketerrno errno
|
#define socketerrno errno
|
||||||
|
|
||||||
#include <Security/SecureTransport.h>
|
#include <Security/SecureTransport.h>
|
||||||
@ -32,17 +31,12 @@ namespace ix
|
|||||||
, _sslContext(nullptr)
|
, _sslContext(nullptr)
|
||||||
, _tlsOptions(tlsOptions)
|
, _tlsOptions(tlsOptions)
|
||||||
{
|
{
|
||||||
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
;
|
||||||
SSLSetIOFuncs(
|
|
||||||
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketAppleSSL::~SocketAppleSSL()
|
SocketAppleSSL::~SocketAppleSSL()
|
||||||
{
|
{
|
||||||
CFRelease(_sslContext);
|
SocketAppleSSL::close();
|
||||||
_sslContext = nullptr;
|
|
||||||
|
|
||||||
Socket::close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status)
|
std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status)
|
||||||
@ -183,16 +177,14 @@ namespace ix
|
|||||||
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
||||||
if (_sockfd == -1) return false;
|
if (_sockfd == -1) return false;
|
||||||
|
|
||||||
|
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||||
|
|
||||||
|
SSLSetIOFuncs(
|
||||||
|
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
|
||||||
SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
|
SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
|
||||||
SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
|
SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
|
||||||
SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
|
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())
|
if (_tlsOptions.isPeerVerifyDisabled())
|
||||||
{
|
{
|
||||||
Boolean option(1);
|
Boolean option(1);
|
||||||
@ -235,7 +227,12 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
|
||||||
|
if (_sslContext == nullptr) return;
|
||||||
|
|
||||||
SSLClose(_sslContext);
|
SSLClose(_sslContext);
|
||||||
|
CFRelease(_sslContext);
|
||||||
|
_sslContext = nullptr;
|
||||||
|
|
||||||
Socket::close();
|
Socket::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +265,11 @@ namespace ix
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t SocketAppleSSL::send(const std::string& buffer)
|
||||||
|
{
|
||||||
|
return send((char*) &buffer[0], buffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
// No wait support
|
// No wait support
|
||||||
ssize_t SocketAppleSSL::recv(void* buf, size_t nbyte)
|
ssize_t SocketAppleSSL::recv(void* buf, size_t nbyte)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,7 @@ namespace ix
|
|||||||
virtual void close() final;
|
virtual void close() final;
|
||||||
|
|
||||||
virtual ssize_t send(char* buffer, size_t length) 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;
|
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -41,8 +42,6 @@ namespace ix
|
|||||||
mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
|
mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
|
||||||
|
|
||||||
SocketTLSOptions _tlsOptions;
|
SocketTLSOptions _tlsOptions;
|
||||||
|
|
||||||
std::string _peerId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ix
|
} // namespace ix
|
||||||
|
@ -19,12 +19,10 @@
|
|||||||
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// This function can be cancelled every 10 ms
|
// This function can be cancelled every 50 ms
|
||||||
// This is important so that we don't block the main UI thread when shutting down a
|
// 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
|
// connection which is already trying to reconnect, and can be blocked waiting for
|
||||||
// ::connect to respond.
|
// ::connect to respond.
|
||||||
@ -46,15 +44,8 @@ namespace ix
|
|||||||
// block us for too long
|
// block us for too long
|
||||||
SocketConnect::configure(fd);
|
SocketConnect::configure(fd);
|
||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
int res = ::connect(fd, address->ai_addr, address->ai_addrlen);
|
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())
|
if (res == -1 && !Socket::isWaitNeeded())
|
||||||
{
|
{
|
||||||
errMsg = strerror(Socket::getErrno());
|
errMsg = strerror(Socket::getErrno());
|
||||||
@ -107,19 +98,11 @@ namespace ix
|
|||||||
std::string& errMsg,
|
std::string& errMsg,
|
||||||
const CancellationRequest& isCancellationRequested)
|
const CancellationRequest& isCancellationRequested)
|
||||||
{
|
{
|
||||||
auto start = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// First do DNS resolution
|
// First do DNS resolution
|
||||||
//
|
//
|
||||||
auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
|
auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
|
||||||
struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested);
|
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)
|
if (res == nullptr)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include "IXSocketOpenSSL.h"
|
#include "IXSocketOpenSSL.h"
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
#include "IXSocketAppleSSL.h"
|
#include "IXSocketAppleSSL.h"
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#include "IXSocketSChannel.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -44,6 +46,8 @@ namespace ix
|
|||||||
socket = std::make_shared<SocketMbedTLS>(tlsOptions, fd);
|
socket = std::make_shared<SocketMbedTLS>(tlsOptions, fd);
|
||||||
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
#elif defined(IXWEBSOCKET_USE_OPEN_SSL)
|
||||||
socket = std::make_shared<SocketOpenSSL>(tlsOptions, fd);
|
socket = std::make_shared<SocketOpenSSL>(tlsOptions, fd);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
socket = std::make_shared<SocketSChannel>(tlsOptions, fd);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
socket = std::make_shared<SocketAppleSSL>(tlsOptions, fd);
|
socket = std::make_shared<SocketAppleSSL>(tlsOptions, fd);
|
||||||
#endif
|
#endif
|
||||||
|
@ -230,23 +230,35 @@ namespace ix
|
|||||||
|
|
||||||
ssize_t SocketMbedTLS::send(char* buf, size_t nbyte)
|
ssize_t SocketMbedTLS::send(char* buf, size_t nbyte)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
ssize_t sent = 0;
|
||||||
|
|
||||||
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
while (nbyte > 0)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
|
||||||
if (res > 0)
|
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
|
||||||
{
|
|
||||||
return res;
|
if (res > 0)
|
||||||
}
|
{
|
||||||
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
nbyte -= res;
|
||||||
{
|
sent += res;
|
||||||
errno = EWOULDBLOCK;
|
}
|
||||||
return -1;
|
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||||
}
|
{
|
||||||
else
|
errno = EWOULDBLOCK;
|
||||||
{
|
return -1;
|
||||||
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)
|
ssize_t SocketMbedTLS::recv(void* buf, size_t nbyte)
|
||||||
|
@ -35,6 +35,7 @@ namespace ix
|
|||||||
virtual void close() final;
|
virtual void close() final;
|
||||||
|
|
||||||
virtual ssize_t send(char* buffer, size_t length) 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;
|
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -603,30 +603,42 @@ namespace ix
|
|||||||
|
|
||||||
ssize_t SocketOpenSSL::send(char* buf, size_t nbyte)
|
ssize_t SocketOpenSSL::send(char* buf, size_t nbyte)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
ssize_t sent = 0;
|
||||||
|
|
||||||
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
while (nbyte > 0)
|
||||||
{
|
{
|
||||||
return 0;
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
}
|
|
||||||
|
|
||||||
ERR_clear_error();
|
if (_ssl_connection == nullptr || _ssl_context == nullptr)
|
||||||
ssize_t write_result = SSL_write(_ssl_connection, buf, (int) nbyte);
|
{
|
||||||
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (reason == SSL_ERROR_NONE)
|
ERR_clear_error();
|
||||||
{
|
ssize_t write_result = SSL_write(_ssl_connection, buf + sent, (int) nbyte);
|
||||||
return write_result;
|
int reason = SSL_get_error(_ssl_connection, (int) write_result);
|
||||||
}
|
|
||||||
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
if (reason == SSL_ERROR_NONE)
|
||||||
{
|
{
|
||||||
errno = EWOULDBLOCK;
|
nbyte -= write_result;
|
||||||
return -1;
|
sent += write_result;
|
||||||
}
|
}
|
||||||
else
|
else if (reason == SSL_ERROR_WANT_READ || reason == SSL_ERROR_WANT_WRITE)
|
||||||
{
|
{
|
||||||
return -1;
|
errno = EWOULDBLOCK;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SocketOpenSSL::send(const std::string& buffer)
|
||||||
|
{
|
||||||
|
return send((char*) &buffer[0], buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t SocketOpenSSL::recv(void* buf, size_t nbyte)
|
ssize_t SocketOpenSSL::recv(void* buf, size_t nbyte)
|
||||||
|
@ -33,6 +33,7 @@ namespace ix
|
|||||||
virtual void close() final;
|
virtual void close() final;
|
||||||
|
|
||||||
virtual ssize_t send(char* buffer, size_t length) 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;
|
virtual ssize_t recv(void* buffer, size_t length) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
103
ixwebsocket/IXSocketSChannel.cpp
Normal file
103
ixwebsocket/IXSocketSChannel.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
32
ixwebsocket/IXSocketSChannel.h
Normal file
32
ixwebsocket/IXSocketSChannel.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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,9 +15,6 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
@ -100,16 +97,8 @@ namespace ix
|
|||||||
auto isCancellationRequested =
|
auto isCancellationRequested =
|
||||||
makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
|
makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
|
||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
std::string errMsg;
|
std::string errMsg;
|
||||||
bool success = _socket->connect(host, port, errMsg, isCancellationRequested);
|
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)
|
if (!success)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -151,18 +151,7 @@ namespace ix
|
|||||||
|
|
||||||
std::string errorMsg;
|
std::string errorMsg;
|
||||||
bool tls = protocol == "wss";
|
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)
|
if (!_socket)
|
||||||
{
|
{
|
||||||
@ -361,9 +350,28 @@ namespace ix
|
|||||||
}
|
}
|
||||||
else if (pollResult == PollResultType::ReadyForRead)
|
else if (pollResult == PollResultType::ReadyForRead)
|
||||||
{
|
{
|
||||||
if (!receiveFromSocket())
|
while (true)
|
||||||
{
|
{
|
||||||
return PollResult::AbnormalClose;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pollResult == PollResultType::Error)
|
else if (pollResult == PollResultType::Error)
|
||||||
@ -731,7 +739,7 @@ namespace ix
|
|||||||
|
|
||||||
// if an abnormal closure was raised in poll, and nothing else triggered a CLOSED state in
|
// 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
|
// the received and processed data then close the connection
|
||||||
if (pollResult != PollResult::Succeeded)
|
if (pollResult == PollResult::AbnormalClose)
|
||||||
{
|
{
|
||||||
_rxbuf.clear();
|
_rxbuf.clear();
|
||||||
|
|
||||||
@ -1045,17 +1053,19 @@ namespace ix
|
|||||||
wsheader_type::TEXT_FRAME, message, _enablePerMessageDeflate, onProgressCallback);
|
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()
|
bool WebSocketTransport::sendOnSocket()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_txbufMutex);
|
std::lock_guard<std::mutex> lock(_txbufMutex);
|
||||||
|
|
||||||
while (_txbuf.size())
|
while (_txbuf.size())
|
||||||
{
|
{
|
||||||
ssize_t ret = 0;
|
ssize_t ret = send();
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
|
||||||
ret = _socket->send((char*) &_txbuf[0], _txbuf.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0 && Socket::isWaitNeeded())
|
if (ret < 0 && Socket::isWaitNeeded())
|
||||||
{
|
{
|
||||||
@ -1076,34 +1086,6 @@ namespace ix
|
|||||||
return true;
|
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)
|
void WebSocketTransport::sendCloseFrame(uint16_t code, const std::string& reason)
|
||||||
{
|
{
|
||||||
bool compress = false;
|
bool compress = false;
|
||||||
|
@ -99,6 +99,7 @@ namespace ix
|
|||||||
bool remote = false);
|
bool remote = false);
|
||||||
|
|
||||||
void closeSocket();
|
void closeSocket();
|
||||||
|
ssize_t send();
|
||||||
|
|
||||||
ReadyState getReadyState() const;
|
ReadyState getReadyState() const;
|
||||||
void setReadyState(ReadyState readyState);
|
void setReadyState(ReadyState readyState);
|
||||||
@ -107,7 +108,7 @@ namespace ix
|
|||||||
size_t bufferedAmount() const;
|
size_t bufferedAmount() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _host;
|
std::string _url;
|
||||||
|
|
||||||
struct wsheader_type
|
struct wsheader_type
|
||||||
{
|
{
|
||||||
@ -244,8 +245,6 @@ namespace ix
|
|||||||
|
|
||||||
bool flushSendBuffer();
|
bool flushSendBuffer();
|
||||||
bool sendOnSocket();
|
bool sendOnSocket();
|
||||||
bool receiveFromSocket();
|
|
||||||
|
|
||||||
WebSocketSendInfo sendData(wsheader_type::opcode_type type,
|
WebSocketSendInfo sendData(wsheader_type::opcode_type type,
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
bool compress,
|
bool compress,
|
||||||
|
@ -6,4 +6,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define IX_WEBSOCKET_VERSION "7.9.6"
|
#define IX_WEBSOCKET_VERSION "7.9.3"
|
||||||
|
@ -55,12 +55,12 @@ set (SOURCES
|
|||||||
IXDNSLookupTest.cpp
|
IXDNSLookupTest.cpp
|
||||||
IXWebSocketSubProtocolTest.cpp
|
IXWebSocketSubProtocolTest.cpp
|
||||||
IXSentryClientTest.cpp
|
IXSentryClientTest.cpp
|
||||||
IXWebSocketChatTest.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Some unittest don't work on windows yet
|
# Some unittest don't work on windows yet
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
|
IXWebSocketChatTest.cpp
|
||||||
IXWebSocketCloseTest.cpp
|
IXWebSocketCloseTest.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,17 +1,8 @@
|
|||||||
FROM python:3.8.0-alpine3.10
|
FROM python:3.8.0-alpine3.10
|
||||||
|
|
||||||
RUN pip install websockets
|
RUN pip install websockets
|
||||||
|
COPY ws_proxy.py /usr/bin
|
||||||
|
RUN chmod +x /usr/bin/ws_proxy.py
|
||||||
|
|
||||||
COPY vendor/protocol.py /usr/local/lib/python3.8/site-packages/websockets/protocol.py
|
EXPOSE 8765
|
||||||
|
CMD ["python", "/usr/bin/ws_proxy.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,17 +830,3 @@ $ honcho start
|
|||||||
15:29:59 system | nginx.1 stopped (rc=0)
|
15:29:59 system | nginx.1 stopped (rc=0)
|
||||||
15:29:59 system | websocket_server.1 stopped (rc=-15)
|
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
|
|
||||||
```
|
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
#!/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,7 +3,6 @@
|
|||||||
# WS server example
|
# WS server example
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
|
||||||
import websockets
|
import websockets
|
||||||
|
|
||||||
|
|
||||||
@ -12,10 +11,9 @@ async def echo(websocket, path):
|
|||||||
print(f'Received {len(msg)} bytes')
|
print(f'Received {len(msg)} bytes')
|
||||||
await websocket.send(msg)
|
await websocket.send(msg)
|
||||||
|
|
||||||
host = os.getenv('BIND_HOST', 'localhost')
|
|
||||||
print(f'Serving on {host}:8766')
|
|
||||||
|
|
||||||
start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30)
|
print('Serving on localhost:8766')
|
||||||
|
start_server = websockets.serve(echo, 'localhost', 8766, max_size=2 ** 25)
|
||||||
|
|
||||||
asyncio.get_event_loop().run_until_complete(start_server)
|
asyncio.get_event_loop().run_until_complete(start_server)
|
||||||
asyncio.get_event_loop().run_forever()
|
asyncio.get_event_loop().run_forever()
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#!/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()
|
|
@ -1,16 +0,0 @@
|
|||||||
#!/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 +0,0 @@
|
|||||||
trusted-client-crt.pem
|
|
@ -3,7 +3,7 @@ all:
|
|||||||
|
|
||||||
.PHONY: docker
|
.PHONY: docker
|
||||||
|
|
||||||
NAME := bsergean/echo_server
|
NAME := bsergean/ws_proxy
|
||||||
TAG := $(shell cat DOCKER_VERSION)
|
TAG := $(shell cat DOCKER_VERSION)
|
||||||
IMG := ${NAME}:${TAG}
|
IMG := ${NAME}:${TAG}
|
||||||
LATEST := ${NAME}:latest
|
LATEST := ${NAME}:latest
|
||||||
@ -21,15 +21,3 @@ docker_push:
|
|||||||
docker tag ${IMG} ${LATEST}
|
docker tag ${IMG} ${LATEST}
|
||||||
docker push ${LATEST}
|
docker push ${LATEST}
|
||||||
docker push ${IMG}
|
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
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
-----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-----
|
|
@ -1,27 +0,0 @@
|
|||||||
-----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
1432
test/compatibility/python/websockets/vendor/protocol.py
vendored
File diff suppressed because it is too large
Load Diff
@ -65,7 +65,6 @@ add_executable(ws
|
|||||||
ws_autobahn.cpp
|
ws_autobahn.cpp
|
||||||
ws_proxy_server.cpp
|
ws_proxy_server.cpp
|
||||||
ws_sentry_minidump_upload.cpp
|
ws_sentry_minidump_upload.cpp
|
||||||
ws_dns_lookup.cpp
|
|
||||||
ws.cpp)
|
ws.cpp)
|
||||||
|
|
||||||
target_link_libraries(ws ixsnake)
|
target_link_libraries(ws ixsnake)
|
||||||
|
@ -338,9 +338,6 @@ int main(int argc, char** argv)
|
|||||||
minidumpApp->add_option("--key", key, "Sentry Key")->required();
|
minidumpApp->add_option("--key", key, "Sentry Key")->required();
|
||||||
minidumpApp->add_flag("-v", verbose, "Verbose");
|
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);
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
// pid file handling
|
// pid file handling
|
||||||
@ -512,10 +509,6 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
ret = ix::ws_sentry_minidump_upload(metadata, minidump, project, key, verbose);
|
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)
|
else if (version)
|
||||||
{
|
{
|
||||||
spdlog::info("ws {}", ix::userAgent());
|
spdlog::info("ws {}", ix::userAgent());
|
||||||
|
2
ws/ws.h
2
ws/ws.h
@ -163,6 +163,4 @@ namespace ix
|
|||||||
const std::string& project,
|
const std::string& project,
|
||||||
const std::string& key,
|
const std::string& key,
|
||||||
bool verbose);
|
bool verbose);
|
||||||
|
|
||||||
int ws_dns_lookup(const std::string& hostname);
|
|
||||||
} // namespace ix
|
} // namespace ix
|
||||||
|
@ -72,7 +72,7 @@ namespace ix
|
|||||||
size_t bufferedAmount = client->bufferedAmount();
|
size_t bufferedAmount = client->bufferedAmount();
|
||||||
spdlog::info("{} bytes left to be sent", bufferedAmount);
|
spdlog::info("{} bytes left to be sent", bufferedAmount);
|
||||||
|
|
||||||
std::chrono::duration<double, std::milli> duration(500);
|
std::chrono::duration<double, std::milli> duration(10);
|
||||||
std::this_thread::sleep_for(duration);
|
std::this_thread::sleep_for(duration);
|
||||||
} while (client->bufferedAmount() != 0);
|
} while (client->bufferedAmount() != 0);
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include <iostream>
|
|
||||||
#include <ixwebsocket/IXSocket.h>
|
#include <ixwebsocket/IXSocket.h>
|
||||||
#include <ixwebsocket/IXWebSocket.h>
|
#include <ixwebsocket/IXWebSocket.h>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
// for convenience
|
// for convenience
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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,8 +45,6 @@ namespace ix
|
|||||||
ix::WebSocket _webSocket;
|
ix::WebSocket _webSocket;
|
||||||
bool _enablePerMessageDeflate;
|
bool _enablePerMessageDeflate;
|
||||||
|
|
||||||
std::atomic<bool> _connected;
|
|
||||||
|
|
||||||
std::mutex _conditionVariableMutex;
|
std::mutex _conditionVariableMutex;
|
||||||
std::condition_variable _condition;
|
std::condition_variable _condition;
|
||||||
|
|
||||||
@ -58,7 +56,6 @@ namespace ix
|
|||||||
const ix::SocketTLSOptions& tlsOptions)
|
const ix::SocketTLSOptions& tlsOptions)
|
||||||
: _url(url)
|
: _url(url)
|
||||||
, _enablePerMessageDeflate(enablePerMessageDeflate)
|
, _enablePerMessageDeflate(enablePerMessageDeflate)
|
||||||
, _connected(false)
|
|
||||||
{
|
{
|
||||||
_webSocket.disableAutomaticReconnection();
|
_webSocket.disableAutomaticReconnection();
|
||||||
_webSocket.setTLSOptions(tlsOptions);
|
_webSocket.setTLSOptions(tlsOptions);
|
||||||
@ -122,8 +119,6 @@ namespace ix
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (msg->type == ix::WebSocketMessageType::Open)
|
if (msg->type == ix::WebSocketMessageType::Open)
|
||||||
{
|
{
|
||||||
_connected = true;
|
|
||||||
|
|
||||||
_condition.notify_one();
|
_condition.notify_one();
|
||||||
|
|
||||||
log("ws_send: connected");
|
log("ws_send: connected");
|
||||||
@ -136,8 +131,6 @@ namespace ix
|
|||||||
}
|
}
|
||||||
else if (msg->type == ix::WebSocketMessageType::Close)
|
else if (msg->type == ix::WebSocketMessageType::Close)
|
||||||
{
|
{
|
||||||
_connected = false;
|
|
||||||
|
|
||||||
ss << "ws_send: connection closed:";
|
ss << "ws_send: connection closed:";
|
||||||
ss << " code " << msg->closeInfo.code;
|
ss << " code " << msg->closeInfo.code;
|
||||||
ss << " reason " << msg->closeInfo.reason << std::endl;
|
ss << " reason " << msg->closeInfo.reason << std::endl;
|
||||||
@ -241,7 +234,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::vector<uint8_t> content;
|
std::vector<uint8_t> content;
|
||||||
{
|
{
|
||||||
Bench bench("ws_send: load file from disk");
|
Bench bench("load file from disk");
|
||||||
content = load(filename);
|
content = load(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,22 +250,18 @@ namespace ix
|
|||||||
|
|
||||||
MsgPack msg(pdu);
|
MsgPack msg(pdu);
|
||||||
|
|
||||||
auto serializedMsg = msg.dump();
|
Bench bench("Sending file through websocket");
|
||||||
spdlog::info("ws_send: sending {} bytes", serializedMsg.size());
|
auto result = _webSocket.sendBinary(msg.dump(), [throttle](int current, int total) -> bool {
|
||||||
|
spdlog::info("ws_send: Step {} out of {}", current, total);
|
||||||
|
|
||||||
Bench bench("ws_send: Sending file through websocket");
|
if (throttle)
|
||||||
auto result =
|
{
|
||||||
_webSocket.sendBinary(serializedMsg, [this, throttle](int current, int total) -> bool {
|
std::chrono::duration<double, std::milli> duration(10);
|
||||||
spdlog::info("ws_send: Step {} out of {}", current + 1, total);
|
std::this_thread::sleep_for(duration);
|
||||||
|
}
|
||||||
|
|
||||||
if (throttle)
|
return true;
|
||||||
{
|
});
|
||||||
std::chrono::duration<double, std::milli> duration(10);
|
|
||||||
std::this_thread::sleep_for(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _connected;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.success)
|
if (!result.success)
|
||||||
{
|
{
|
||||||
@ -280,37 +269,22 @@ namespace ix
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_connected)
|
|
||||||
{
|
|
||||||
spdlog::error("ws_send: Got disconnected from the server");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::info("ws_send: sent {} bytes", serializedMsg.size());
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
size_t bufferedAmount = _webSocket.bufferedAmount();
|
size_t bufferedAmount = _webSocket.bufferedAmount();
|
||||||
spdlog::info("ws_send: {} bytes left to be sent", bufferedAmount);
|
spdlog::info("ws_send: {} bytes left to be sent", bufferedAmount);
|
||||||
|
|
||||||
std::chrono::duration<double, std::milli> duration(500);
|
std::chrono::duration<double, std::milli> duration(10);
|
||||||
std::this_thread::sleep_for(duration);
|
std::this_thread::sleep_for(duration);
|
||||||
} while (_webSocket.bufferedAmount() != 0 && _connected);
|
} while (_webSocket.bufferedAmount() != 0);
|
||||||
|
|
||||||
if (_connected)
|
bench.report();
|
||||||
{
|
auto duration = bench.getDuration();
|
||||||
bench.report();
|
auto transferRate = 1000 * content.size() / duration;
|
||||||
auto duration = bench.getDuration();
|
transferRate /= (1024 * 1024);
|
||||||
auto transferRate = 1000 * content.size() / duration;
|
spdlog::info("ws_send: Send transfer rate: {} MB/s", transferRate);
|
||||||
transferRate /= (1024 * 1024);
|
|
||||||
spdlog::info("ws_send: Send transfer rate: {} MB/s", transferRate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spdlog::error("ws_send: Got disconnected from the server");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _connected;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wsSend(const std::string& url,
|
void wsSend(const std::string& url,
|
||||||
@ -330,10 +304,6 @@ namespace ix
|
|||||||
webSocketSender.waitForAck();
|
webSocketSender.waitForAck();
|
||||||
spdlog::info("ws_send: Done !");
|
spdlog::info("ws_send: Done !");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
spdlog::error("ws_send: Error sending file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
webSocketSender.stop();
|
webSocketSender.stop();
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ namespace ix
|
|||||||
size_t bufferedAmount = client->bufferedAmount();
|
size_t bufferedAmount = client->bufferedAmount();
|
||||||
|
|
||||||
spdlog::info(
|
spdlog::info(
|
||||||
"{}: [client {}]: has readystate {} bytes left to be sent {}",
|
"{}: [client {}]: has readystate {} bytes left to be sent",
|
||||||
"ws_transfer",
|
"ws_transfer",
|
||||||
id,
|
id,
|
||||||
readyStateString,
|
readyStateString,
|
||||||
|
Reference in New Issue
Block a user