Compare commits

..

1 Commits

Author SHA1 Message Date
74833f95e4 (Windows) OpenSSL can be used for SSL communication 2020-01-09 11:59:34 -08:00
41 changed files with 288 additions and 1898 deletions

View File

@ -129,6 +129,9 @@ if (USE_TLS)
elseif (APPLE AND NOT USE_OPEN_SSL)
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
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()
set(USE_OPEN_SSL ON)
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)

View File

@ -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/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

View File

@ -21,7 +21,6 @@ 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
@ -37,3 +36,4 @@ WORKDIR /home/app
ENTRYPOINT ["ws"]
EXPOSE 8008
C

View File

@ -1,21 +1,9 @@
# Changelog
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
## [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
(Windows) OpenSSL can be used for SSL communication
## [7.9.2] - 2020-01-06

View File

@ -54,17 +54,14 @@ namespace ix
// to ::poll does fix that.
//
// 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.
//
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
@ -135,11 +132,6 @@ namespace ix
}
#endif
}
else if (sockfd != -1 && (fds[0].revents & POLLERR || fds[0].revents & POLLHUP ||
fds[0].revents & POLLNVAL))
{
pollResult = PollResultType::Error;
}
return pollResult;
}

View File

@ -73,7 +73,7 @@ namespace ix
virtual void close();
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);
// Blocking and cancellable versions, working with socket that can be set

View File

@ -20,7 +20,6 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sstream>
#define socketerrno errno
#include <Security/SecureTransport.h>
@ -32,17 +31,12 @@ namespace ix
, _sslContext(nullptr)
, _tlsOptions(tlsOptions)
{
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
SSLSetIOFuncs(
_sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
;
}
SocketAppleSSL::~SocketAppleSSL()
{
CFRelease(_sslContext);
_sslContext = nullptr;
Socket::close();
SocketAppleSSL::close();
}
std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status)
@ -183,16 +177,14 @@ 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);
@ -235,7 +227,12 @@ namespace ix
{
std::lock_guard<std::mutex> lock(_mutex);
if (_sslContext == nullptr) return;
SSLClose(_sslContext);
CFRelease(_sslContext);
_sslContext = nullptr;
Socket::close();
}
@ -268,6 +265,11 @@ 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)
{

View File

@ -30,6 +30,7 @@ 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:
@ -41,8 +42,6 @@ namespace ix
mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
SocketTLSOptions _tlsOptions;
std::string _peerId;
};
} // namespace ix

View File

@ -19,12 +19,10 @@
#include <linux/tcp.h>
#endif
#include <iostream>
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
// connection which is already trying to reconnect, and can be blocked waiting for
// ::connect to respond.
@ -46,15 +44,8 @@ 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());
@ -107,19 +98,11 @@ 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;

View File

@ -14,6 +14,8 @@
#include "IXSocketOpenSSL.h"
#elif __APPLE__
#include "IXSocketAppleSSL.h"
#elif defined(_WIN32)
#include "IXSocketSChannel.h"
#endif
#else
@ -44,6 +46,8 @@ 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

View File

@ -230,23 +230,35 @@ namespace ix
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)
{
return res;
}
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
{
errno = EWOULDBLOCK;
return -1;
}
else
{
return -1;
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 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)

View File

@ -35,6 +35,7 @@ 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:

View File

@ -603,30 +603,42 @@ namespace ix
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();
ssize_t write_result = SSL_write(_ssl_connection, buf, (int) nbyte);
int reason = SSL_get_error(_ssl_connection, (int) write_result);
if (_ssl_connection == nullptr || _ssl_context == nullptr)
{
return 0;
}
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;
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 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)

View File

@ -33,6 +33,7 @@ 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:

View 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

View 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

View File

@ -15,9 +15,6 @@
#include <random>
#include <sstream>
#include <iostream>
#include <chrono>
namespace ix
{
@ -100,16 +97,8 @@ 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;

View File

@ -151,18 +151,7 @@ namespace ix
std::string errorMsg;
bool tls = protocol == "wss";
if (_host == host)
{
_socket->close();
}
else
{
_socket = createSocket(tls, -1, errorMsg, _socketTLSOptions);
}
// Record the host for later
_host = host;
_socket = createSocket(tls, -1, errorMsg, _socketTLSOptions);
if (!_socket)
{
@ -361,9 +350,28 @@ namespace ix
}
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)
@ -731,7 +739,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::Succeeded)
if (pollResult == PollResult::AbnormalClose)
{
_rxbuf.clear();
@ -1045,17 +1053,19 @@ 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 = 0;
{
std::lock_guard<std::mutex> lock(_socketMutex);
ret = _socket->send((char*) &_txbuf[0], _txbuf.size());
}
ssize_t ret = send();
if (ret < 0 && Socket::isWaitNeeded())
{
@ -1076,34 +1086,6 @@ 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;

View File

@ -99,6 +99,7 @@ namespace ix
bool remote = false);
void closeSocket();
ssize_t send();
ReadyState getReadyState() const;
void setReadyState(ReadyState readyState);
@ -107,7 +108,7 @@ namespace ix
size_t bufferedAmount() const;
private:
std::string _host;
std::string _url;
struct wsheader_type
{
@ -244,8 +245,6 @@ namespace ix
bool flushSendBuffer();
bool sendOnSocket();
bool receiveFromSocket();
WebSocketSendInfo sendData(wsheader_type::opcode_type type,
const std::string& message,
bool compress,

View File

@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "7.9.6"
#define IX_WEBSOCKET_VERSION "7.9.3"

View File

@ -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()

View File

@ -1,17 +1,8 @@
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
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"]
EXPOSE 8765
CMD ["python", "/usr/bin/ws_proxy.py"]

View File

@ -830,17 +830,3 @@ $ 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
```

View 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()

View File

@ -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()

View File

@ -3,7 +3,6 @@
# WS server example
import asyncio
import os
import websockets
@ -12,10 +11,9 @@ 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')
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_forever()

View File

@ -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()

View File

@ -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

View File

@ -1 +0,0 @@
trusted-client-crt.pem

View File

@ -3,7 +3,7 @@ all:
.PHONY: docker
NAME := bsergean/echo_server
NAME := bsergean/ws_proxy
TAG := $(shell cat DOCKER_VERSION)
IMG := ${NAME}:${TAG}
LATEST := ${NAME}:latest
@ -21,15 +21,3 @@ 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

View File

@ -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-----

View File

@ -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-----

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,6 @@ 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)

View File

@ -338,9 +338,6 @@ 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
@ -512,10 +509,6 @@ 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());

View File

@ -163,6 +163,4 @@ namespace ix
const std::string& project,
const std::string& key,
bool verbose);
int ws_dns_lookup(const std::string& hostname);
} // namespace ix

View File

@ -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(500);
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (client->bufferedAmount() != 0);
}

View File

@ -10,12 +10,12 @@
//
#include "nlohmann/json.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <queue>
#include <spdlog/spdlog.h>
#include <sstream>
#include <iostream>
// for convenience
using json = nlohmann::json;

View File

@ -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

View File

@ -45,8 +45,6 @@ namespace ix
ix::WebSocket _webSocket;
bool _enablePerMessageDeflate;
std::atomic<bool> _connected;
std::mutex _conditionVariableMutex;
std::condition_variable _condition;
@ -58,7 +56,6 @@ namespace ix
const ix::SocketTLSOptions& tlsOptions)
: _url(url)
, _enablePerMessageDeflate(enablePerMessageDeflate)
, _connected(false)
{
_webSocket.disableAutomaticReconnection();
_webSocket.setTLSOptions(tlsOptions);
@ -122,8 +119,6 @@ namespace ix
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
_connected = true;
_condition.notify_one();
log("ws_send: connected");
@ -136,8 +131,6 @@ 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;
@ -241,7 +234,7 @@ namespace ix
{
std::vector<uint8_t> content;
{
Bench bench("ws_send: load file from disk");
Bench bench("load file from disk");
content = load(filename);
}
@ -257,22 +250,18 @@ namespace ix
MsgPack msg(pdu);
auto serializedMsg = msg.dump();
spdlog::info("ws_send: sending {} bytes", serializedMsg.size());
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);
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);
if (throttle)
{
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
}
if (throttle)
{
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
}
return _connected;
});
return true;
});
if (!result.success)
{
@ -280,37 +269,22 @@ 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(500);
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (_webSocket.bufferedAmount() != 0 && _connected);
} while (_webSocket.bufferedAmount() != 0);
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");
}
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);
return _connected;
return true;
}
void wsSend(const std::string& url,
@ -330,10 +304,6 @@ namespace ix
webSocketSender.waitForAck();
spdlog::info("ws_send: Done !");
}
else
{
spdlog::error("ws_send: Error sending file.");
}
webSocketSender.stop();
}

View File

@ -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,