Compare commits

..

30 Commits

Author SHA1 Message Date
7ff12a36b9 embedded help 2020-05-30 11:23:39 -07:00
945c692227 build ixhttpd on docker with centos7 2020-05-30 11:16:26 -07:00
c16b64bcb2 c++11 unique_ptr 2020-05-30 10:54:30 -07:00
886b8f54bf no unittest for this branch 2020-05-30 10:54:30 -07:00
02810f9adf compile in C++11 mode 2020-05-30 10:50:49 -07:00
b0b451d2c7 add a simple httpd server standalone example 2020-05-29 22:10:23 -07:00
4872b59fac fix windows build (or operator is not supported || is required 2020-05-29 17:18:09 -07:00
bb1be240ec fix linux compile failure 2020-05-29 16:53:57 -07:00
b008c97c83 (http server) support gzip compression 2020-05-29 16:49:29 -07:00
9886a30490 fix #210 / better standalone example, an echo client 2020-05-27 16:24:33 -07:00
4ed5206d79 fix #210 / add include to README hello world example 2020-05-27 16:04:39 -07:00
33916869f1 add simple doc link for multipart uploads - fix #209 2020-05-27 10:38:32 -07:00
9ddf707804 add script to build with Android NDK 2020-05-26 15:15:45 -07:00
3a020a66b7 Merge branch 'feature/badges' 2020-05-21 09:54:41 -07:00
bd39e69185 Update index.md 2020-05-21 09:42:15 -07:00
9d4ca3f34e Update README.md 2020-05-21 09:35:33 -07:00
de6f3ded09 ci / break unittest job into small job files 2020-05-21 09:01:50 -07:00
e0aace33ea Update CMakeLists.txt (#207) 2020-05-21 08:46:06 -07:00
16eb269e1e bump version for (compiler fix) support clang 5 and earlier (contributed by @LunarWatcher) #206 2020-05-20 10:58:30 -07:00
2319dec278 (cmake) revert CMake changes to fix #203 and be able to use an external OpenSSL 2020-05-20 10:56:58 -07:00
f1be48aff1 Re-enable support for clang 5 and earlier (#206) 2020-05-20 10:56:24 -07:00
93fd44813a extend docs (#204) 2020-05-18 09:22:25 -07:00
54d4d81bf4 (cmake) make install cmake files optional to not conflict with vcpkg
See https://github.com/microsoft/vcpkg/pull/11030
2020-05-17 20:36:46 -07:00
ea207d8199 (windows + tls) mbedtls is the default windows tls backend + add ability to load system certificates with mbdetls on windows 2020-05-17 20:36:46 -07:00
e8287e91e4 Updated project reference/description (#202)
* edit project reference

* simple rephrase
2020-05-15 09:48:28 -07:00
c0505ac7fb windows build fix with max which is a macro 2020-05-12 21:48:41 -07:00
1af39bf0eb (ixbots) add options to limit how many messages per minute should be processed 2020-05-12 21:40:17 -07:00
2e904801a0 (ixbots) add new class to configure a bot to simplify passing options around 2020-05-12 19:08:16 -07:00
cc72494b63 Add reference to DisCPP to the README (fix #198) 2020-05-09 21:08:34 -07:00
fa9a4660c6 bump some test timeout 2020-05-08 10:03:18 -07:00
41 changed files with 663 additions and 371 deletions

View File

@ -1,86 +0,0 @@
name: unittest
on:
push:
paths-ignore:
- 'docs/**'
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: make test_make
run: make test_make
mac_tsan_sectransport:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: make test_tsan
run: make test_tsan
mac_tsan_openssl:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: install openssl
run: brew install openssl@1.1
- name: make test
run: make test_tsan_openssl
mac_tsan_mbedtls:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: install mbedtls
run: brew install mbedtls
- name: make test
run: make test_tsan_mbedtls
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: seanmiddleditch/gha-setup-vsdevenv@master
- run: |
mkdir build
cd build
cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 ..
- run: cmake --build build
# Running the unittest does not work, the binary cannot be found
#- run: ../build/test/ixwebsocket_unittest.exe
# working-directory: test
uwp:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: seanmiddleditch/gha-setup-vsdevenv@master
- run: |
mkdir build
cd build
cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_CXX_COMPILER=cl.exe -DUSE_TEST=1 ..
- run: cmake --build build
#
# Windows with OpenSSL is working but disabled as it takes 13 minutes (10 for openssl) to build with vcpkg
#
# windows_openssl:
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v1
# - uses: seanmiddleditch/gha-setup-vsdevenv@master
# - run: |
# vcpkg install zlib:x64-windows
# vcpkg install openssl:x64-windows
# - run: |
# mkdir build
# cd build
# cmake -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_OPEN_SSL=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 ..
# - run: cmake --build build
#
# # Running the unittest does not work, the binary cannot be found
# #- run: ../build/test/ixwebsocket_unittest.exe
# # working-directory: test

View File

@ -3,7 +3,7 @@
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved. # Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
# #
cmake_minimum_required(VERSION 3.4.1) cmake_minimum_required(VERSION 3.4.1...3.17.2)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
project(ixwebsocket C CXX) project(ixwebsocket C CXX)
@ -123,8 +123,8 @@ if (USE_TLS)
if (NOT USE_MBED_TLS AND NOT USE_OPEN_SSL) # unless we want something else if (NOT USE_MBED_TLS AND NOT USE_OPEN_SSL) # unless we want something else
set(USE_SECURE_TRANSPORT ON) set(USE_SECURE_TRANSPORT ON)
endif() endif()
# default to mbedtls on uwp (universal windows platform) if nothing is configured # default to mbedtls on windows if nothing is configured
elseif (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore") elseif (WIN32)
if (NOT USE_OPEN_SSL) # unless we want something else if (NOT USE_OPEN_SSL) # unless we want something else
set(USE_MBED_TLS ON) set(USE_MBED_TLS ON)
endif() endif()
@ -153,8 +153,6 @@ add_library( ixwebsocket STATIC
${IXWEBSOCKET_HEADERS} ${IXWEBSOCKET_HEADERS}
) )
add_library ( ixwebsocket::ixwebsocket ALIAS ixwebsocket )
if (USE_TLS) if (USE_TLS)
target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_TLS) target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_TLS)
if (USE_MBED_TLS) if (USE_MBED_TLS)
@ -184,20 +182,22 @@ if (USE_TLS)
# This OPENSSL_FOUND check is to help find a cmake manually configured OpenSSL # This OPENSSL_FOUND check is to help find a cmake manually configured OpenSSL
if (NOT OPENSSL_FOUND) if (NOT OPENSSL_FOUND)
include(FindOpenSSL) find_package(OpenSSL REQUIRED)
endif() endif()
message(STATUS "OpenSSL: " ${OPENSSL_VERSION}) message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
target_link_libraries(ixwebsocket PUBLIC OpenSSL::SSL OpenSSL::Crypto) add_definitions(${OPENSSL_DEFINITIONS})
target_include_directories(ixwebsocket PUBLIC ${OPENSSL_INCLUDE_DIR})
target_link_libraries(ixwebsocket ${OPENSSL_LIBRARIES})
elseif (USE_MBED_TLS) elseif (USE_MBED_TLS)
message(STATUS "TLS configured to use mbedtls") message(STATUS "TLS configured to use mbedtls")
find_package(MbedTLS REQUIRED) find_package(MbedTLS REQUIRED)
target_include_directories(ixwebsocket PUBLIC ${MBEDTLS_INCLUDE_DIRS}) target_include_directories(ixwebsocket PUBLIC ${MBEDTLS_INCLUDE_DIRS})
target_link_libraries(ixwebsocket PUBLIC ${MBEDTLS_LIBRARIES}) target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
elseif (USE_SECURE_TRANSPORT) elseif (USE_SECURE_TRANSPORT)
message(STATUS "TLS configured to use secure transport") message(STATUS "TLS configured to use secure transport")
target_link_libraries(ixwebsocket PUBLIC "-framework foundation" "-framework security") target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
endif() endif()
endif() endif()
@ -207,25 +207,25 @@ if (NOT ZLIB_FOUND)
endif() endif()
if (ZLIB_FOUND) if (ZLIB_FOUND)
include_directories(${ZLIB_INCLUDE_DIRS}) include_directories(${ZLIB_INCLUDE_DIRS})
target_link_libraries(ixwebsocket PUBLIC ${ZLIB_LIBRARIES}) target_link_libraries(ixwebsocket ${ZLIB_LIBRARIES})
else() else()
include_directories(third_party/zlib ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib) include_directories(third_party/zlib ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib)
add_subdirectory(third_party/zlib EXCLUDE_FROM_ALL) add_subdirectory(third_party/zlib)
target_link_libraries(ixwebsocket PRIVATE $<LINK_ONLY:zlibstatic>) target_link_libraries(ixwebsocket zlibstatic)
endif() endif()
if (WIN32) if (WIN32)
target_link_libraries(ixwebsocket PUBLIC wsock32 ws2_32 shlwapi) target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if (USE_TLS) if (USE_TLS)
target_link_libraries(ixwebsocket PUBLIC Crypt32) target_link_libraries(ixwebsocket Crypt32)
endif() endif()
endif() endif()
if (UNIX) if (UNIX)
find_package(Threads) find_package(Threads)
target_link_libraries(ixwebsocket PUBLIC ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(ixwebsocket ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
@ -238,18 +238,15 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
target_compile_options(ixwebsocket PRIVATE /MP) target_compile_options(ixwebsocket PRIVATE /MP)
endif() endif()
target_include_directories(ixwebsocket PUBLIC $<BUILD_INTERFACE:${IXWEBSOCKET_INCLUDE_DIRS}> $<INSTALL_INTERFACE:include/ixwebsocket>) target_include_directories(ixwebsocket PUBLIC ${IXWEBSOCKET_INCLUDE_DIRS})
set_target_properties(ixwebsocket PROPERTIES PUBLIC_HEADER "${IXWEBSOCKET_HEADERS}") set_target_properties(ixwebsocket PROPERTIES PUBLIC_HEADER "${IXWEBSOCKET_HEADERS}")
install(TARGETS ixwebsocket EXPORT ixwebsocket install(TARGETS ixwebsocket
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ixwebsocket/ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ixwebsocket/
) )
install(EXPORT ixwebsocket NAMESPACE ixwebsocket:: DESTINATION lib/cmake/ixwebsocket)
export(EXPORT ixwebsocket NAMESPACE ixwebsocket:: FILE ixwebsocketConfig.cmake)
if (USE_WS OR USE_TEST) if (USE_WS OR USE_TEST)
add_subdirectory(ixcore) add_subdirectory(ixcore)
add_subdirectory(ixcrypto) add_subdirectory(ixcrypto)

View File

@ -1 +1 @@
docker/Dockerfile.alpine docker/Dockerfile.centos7_httpd

View File

@ -1,37 +1,72 @@
## Hello world ## Hello world
![Build status](https://github.com/machinezone/IXWebSocket/workflows/unittest/badge.svg)
IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use and support everything you'll likely need for websocket dev (SSL, deflate compression, compiles on most platforms, etc...). HTTP client and server code is also available, but it hasn't received as much testing. IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use and support everything you'll likely need for websocket dev (SSL, deflate compression, compiles on most platforms, etc...). HTTP client and server code is also available, but it hasn't received as much testing.
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Two important design goals are simplicity and correctness. It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Two important design goals are simplicity and correctness.
```cpp ```cpp
// Required on Windows /*
ix::initNetSystem(); * main.cpp
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*
* Super simple standalone example. See ws folder, unittest and doc/usage.md for more.
*
* On macOS
* $ mkdir -p build ; cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install
* $ clang++ --std=c++14 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
* $ ./a.out
*/
// Our websocket object #include <ixwebsocket/IXNetSystem.h>
ix::WebSocket webSocket; #include <ixwebsocket/IXWebSocket.h>
#include <iostream>
std::string url("ws://localhost:8080/"); int main()
webSocket.setUrl(url); {
// Required on Windows
ix::initNetSystem();
// Setup a callback to be fired (in a background thread, watch out for race conditions !) // Our websocket object
// when a message or an event (open, close, error) is received ix::WebSocket webSocket;
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
std::string url("wss://echo.websocket.org");
webSocket.setUrl(url);
std::cout << "Connecting to " << url << "..." << std::endl;
// Setup a callback to be fired (in a background thread, watch out for race conditions !)
// when a message or an event (open, close, error) is received
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
{ {
if (msg->type == ix::WebSocketMessageType::Message) if (msg->type == ix::WebSocketMessageType::Message)
{ {
std::cout << msg->str << std::endl; std::cout << "received message: " << msg->str << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Open)
{
std::cout << "Connection established" << std::endl;
} }
} }
); );
// Now that our callback is setup, we can start our background thread and receive messages // Now that our callback is setup, we can start our background thread and receive messages
webSocket.start(); webSocket.start();
// Send a message to the server (default to TEXT mode) // Send a message to the server (default to TEXT mode)
webSocket.send("hello world"); webSocket.send("hello world");
while (true)
{
std::string text;
std::cout << "> " << std::flush;
std::getline(std::cin, text);
webSocket.send(text);
}
return 0;
}
``` ```
Interested? Go read the [docs](https://machinezone.github.io/IXWebSocket/)! If things don't work as expected, please create an issue on GitHub, or even better a pull request if you know how to fix your problem. Interested? Go read the [docs](https://machinezone.github.io/IXWebSocket/)! If things don't work as expected, please create an issue on GitHub, or even better a pull request if you know how to fix your problem.
@ -45,6 +80,27 @@ IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version.
If your company or project is using this library, feel free to open an issue or PR to amend this list. If your company or project is using this library, feel free to open an issue or PR to amend this list.
- [Machine Zone](https://www.mz.com) - [Machine Zone](https://www.mz.com)
- [dis-light](https://gitlab.com/HCInk/dis-light), a discord library with a node frontend. - [Tokio](https://gitlab.com/HCInk/tokio), a discord library focused on audio playback with node bindings.
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), a work in progress discord library - [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), a work in progress discord library
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod - [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
## Continuous Integration
| OS | TLS | Sanitizer | Status |
|-------------------|-------------------|-------------------|-------------------|
| Linux | OpenSSL | None | [![Build2][1]][7] |
| macOS | Secure Transport | Thread Sanitizer | [![Build2][2]][7] |
| macOS | OpenSSL | Thread Sanitizer | [![Build2][3]][7] |
| macOS | MbedTLS | Thread Sanitizer | [![Build2][4]][7] |
| Windows | Disabled | None | [![Build2][5]][7] |
| UWP | Disabled | None | [![Build2][6]][7] |
[1]: https://github.com/machinezone/IXWebSocket/workflows/linux/badge.svg
[2]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_sectransport/badge.svg
[3]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_openssl/badge.svg
[4]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_mbedtls/badge.svg
[5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg
[6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/badge.svg
[7]: https://github.com/machinezone/IXWebSocket

View File

@ -2,7 +2,7 @@ FROM alpine:3.11 as build
RUN apk add --no-cache \ RUN apk add --no-cache \
gcc g++ musl-dev linux-headers \ gcc g++ musl-dev linux-headers \
cmake mbedtls-dev make zlib-dev cmake mbedtls-dev make zlib-dev ninja
RUN addgroup -S app && \ RUN addgroup -S app && \
adduser -S -G app app && \ adduser -S -G app app && \

View File

@ -0,0 +1,33 @@
FROM centos:7 as build
RUN yum install -y gcc-c++ make zlib-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", "httpd_linux" ]
RUN [ "rm", "-rf", "build" ]
FROM centos:8 as runtime
RUN groupadd app && useradd -g app app
COPY --chown=app:app --from=build /usr/local/bin/ixhttpd /usr/local/bin/ixhttpd
RUN chmod +x /usr/local/bin/ixhttpd
RUN ldd /usr/local/bin/ixhttpd
# Copy source code for gcc
COPY --chown=app:app --from=build /opt /opt
# Now run in usermode
USER app
WORKDIR /home/app
ENTRYPOINT ["ixhttpd"]
EXPOSE 9999

View File

@ -1,6 +1,34 @@
# Changelog # Changelog
All changes to this project will be documented in this file. All changes to this project will be documented in this file.
## [9.6.5] - 2020-05-29
(http server) support gzip compression
## [9.6.4] - 2020-05-20
(compiler fix) support clang 5 and earlier (contributed by @LunarWatcher)
## [9.6.3] - 2020-05-18
(cmake) revert CMake changes to fix #203 and be able to use an external OpenSSL
## [9.6.2] - 2020-05-17
(cmake) make install cmake files optional to not conflict with vcpkg
## [9.6.1] - 2020-05-17
(windows + tls) mbedtls is the default windows tls backend + add ability to load system certificates with mbdetls on windows
## [9.6.0] - 2020-05-12
(ixbots) add options to limit how many messages per minute should be processed
## [9.5.9] - 2020-05-12
(ixbots) add new class to configure a bot to simplify passing options around
## [9.5.8] - 2020-05-08 ## [9.5.8] - 2020-05-08
(openssl tls) (openssl < 1.1) logic inversion - crypto locking callback are not registered properly (openssl tls) (openssl < 1.1) logic inversion - crypto locking callback are not registered properly

View File

@ -42,6 +42,19 @@ It is possible to get IXWebSocket through Microsoft [vcpkg](https://github.com/m
``` ```
vcpkg install ixwebsocket vcpkg install ixwebsocket
``` ```
To use the installed package within a cmake project, use the following:
```cmake
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") # this is super important in order for cmake to include the vcpkg search/lib paths!
# find library and its headers
find_path(IXWEBSOCKET_INCLUDE_DIR ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY ixwebsocket)
# include headers
include_directories(${IXWEBSOCKET_INCLUDE_DIR})
# ...
target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUNS
```
### Conan ### Conan

View File

@ -1,5 +1,3 @@
![Build status](https://github.com/machinezone/IXWebSocket/workflows/unittest/badge.svg)
## Introduction ## Introduction
[*WebSocket*](https://en.wikipedia.org/wiki/WebSocket) is a computer communications protocol, providing full-duplex and bi-directionnal communication channels over a single TCP connection. *IXWebSocket* is a C++ library for client and server Websocket communication, and for client and server HTTP communication. *TLS* aka *SSL* is supported. The code is derived from [easywsclient](https://github.com/dhbaird/easywsclient) and from the [Satori C SDK](https://github.com/satori-com/satori-rtm-sdk-c). It has been tested on the following platforms. [*WebSocket*](https://en.wikipedia.org/wiki/WebSocket) is a computer communications protocol, providing full-duplex and bi-directionnal communication channels over a single TCP connection. *IXWebSocket* is a C++ library for client and server Websocket communication, and for client and server HTTP communication. *TLS* aka *SSL* is supported. The code is derived from [easywsclient](https://github.com/dhbaird/easywsclient) and from the [Satori C SDK](https://github.com/satori-com/satori-rtm-sdk-c). It has been tested on the following platforms.

View File

@ -392,6 +392,8 @@ bool ok = httpClient.performRequest(args, [](const HttpResponsePtr& response)
// ok will be false if your httpClient is not async // ok will be false if your httpClient is not async
``` ```
See this [issue](https://github.com/machinezone/IXWebSocket/issues/209) for links about uploading files with HTTP multipart.
## HTTP server API ## HTTP server API
```cpp ```cpp

46
httpd.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
* httpd.cpp
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*
* Buid with make httpd
*/
#include "IXHttpServer.h"
#include <sstream>
#include <iostream>
int main(int argc, char** argv)
{
if (argc != 3)
{
std::cerr << "Usage: " << argv[0]
<< " <port> <host>" << std::endl;
std::cerr << " " << argv[0] << " 9090 127.0.0.1" << std::endl;
std::cerr << " " << argv[0] << " 9090 0.0.0.0" << std::endl;
return 1;
}
int port;
std::stringstream ss;
ss << argv[1];
ss >> port;
std::string hostname(argv[2]);
std::cout << "Listening on " << hostname
<< ":" << port << std::endl;
ix::HttpServer server(port, hostname);
auto res = server.listen();
if (!res.first)
{
std::cout << res.second << std::endl;
return 1;
}
server.start();
server.wait();
return 0;
}

View File

@ -13,6 +13,7 @@ set (IXBOTS_SOURCES
set (IXBOTS_HEADERS set (IXBOTS_HEADERS
ixbots/IXCobraBot.h ixbots/IXCobraBot.h
ixbots/IXCobraBotConfig.h
ixbots/IXCobraToSentryBot.h ixbots/IXCobraToSentryBot.h
ixbots/IXCobraToStatsdBot.h ixbots/IXCobraToStatsdBot.h
ixbots/IXCobraToStdoutBot.h ixbots/IXCobraToStdoutBot.h

View File

@ -17,14 +17,18 @@
namespace ix namespace ix
{ {
int64_t CobraBot::run(const CobraConfig& config, int64_t CobraBot::run(const CobraBotConfig& botConfig)
const std::string& channel,
const std::string& filter,
const std::string& position,
bool enableHeartbeat,
int heartBeatTimeout,
int runtime)
{ {
auto config = botConfig.cobraConfig;
auto channel = botConfig.channel;
auto filter = botConfig.filter;
auto position = botConfig.position;
auto enableHeartbeat = botConfig.enableHeartbeat;
auto heartBeatTimeout = botConfig.heartBeatTimeout;
auto runtime = botConfig.runtime;
auto maxEventsPerMinute = botConfig.maxEventsPerMinute;
auto limitReceivedEvents = botConfig.limitReceivedEvents;
ix::CobraConnection conn; ix::CobraConnection conn;
conn.configure(config); conn.configure(config);
conn.connect(); conn.connect();
@ -35,9 +39,11 @@ namespace ix
uint64_t receivedCountTotal(0); uint64_t receivedCountTotal(0);
uint64_t sentCountPerSecs(0); uint64_t sentCountPerSecs(0);
uint64_t receivedCountPerSecs(0); uint64_t receivedCountPerSecs(0);
std::atomic<int> receivedCountPerMinutes(0);
std::atomic<bool> stop(false); std::atomic<bool> stop(false);
std::atomic<bool> throttled(false); std::atomic<bool> throttled(false);
std::atomic<bool> fatalCobraError(false); std::atomic<bool> fatalCobraError(false);
int minuteCounter = 0;
auto timer = [&sentCount, auto timer = [&sentCount,
&receivedCount, &receivedCount,
@ -45,6 +51,8 @@ namespace ix
&receivedCountTotal, &receivedCountTotal,
&sentCountPerSecs, &sentCountPerSecs,
&receivedCountPerSecs, &receivedCountPerSecs,
&receivedCountPerMinutes,
&minuteCounter,
&stop] { &stop] {
while (!stop) while (!stop)
{ {
@ -65,13 +73,19 @@ namespace ix
CoreLogger::info(ss.str()); CoreLogger::info(ss.str());
receivedCountPerSecs = receivedCount - receivedCountTotal; receivedCountPerSecs = receivedCount - receivedCountTotal;
sentCountPerSecs = sentCount - receivedCountTotal; sentCountPerSecs = sentCount - sentCountTotal;
receivedCountTotal += receivedCountPerSecs; receivedCountTotal += receivedCountPerSecs;
sentCountTotal += sentCountPerSecs; sentCountTotal += sentCountPerSecs;
auto duration = std::chrono::seconds(1); auto duration = std::chrono::seconds(1);
std::this_thread::sleep_for(duration); std::this_thread::sleep_for(duration);
if (minuteCounter++ == 60)
{
receivedCountPerMinutes = 0;
minuteCounter = 0;
}
} }
CoreLogger::info("timer thread done"); CoreLogger::info("timer thread done");
@ -118,6 +132,9 @@ namespace ix
&subscriptionPosition, &subscriptionPosition,
&throttled, &throttled,
&receivedCount, &receivedCount,
&receivedCountPerMinutes,
maxEventsPerMinute,
limitReceivedEvents,
&fatalCobraError, &fatalCobraError,
&sentCount](const CobraEventPtr& event) { &sentCount](const CobraEventPtr& event) {
if (event->type == ix::CobraEventType::Open) if (event->type == ix::CobraEventType::Open)
@ -139,16 +156,23 @@ namespace ix
CoreLogger::info("Subscribing to " + channel); CoreLogger::info("Subscribing to " + channel);
CoreLogger::info("Subscribing at position " + subscriptionPosition); CoreLogger::info("Subscribing at position " + subscriptionPosition);
CoreLogger::info("Subscribing with filter " + filter); CoreLogger::info("Subscribing with filter " + filter);
conn.subscribe(channel, conn.subscribe(channel, filter, subscriptionPosition,
filter, [&sentCount, &receivedCountPerMinutes,
subscriptionPosition, maxEventsPerMinute, limitReceivedEvents,
[this, &throttled, &receivedCount,
&throttled, &subscriptionPosition, &fatalCobraError,
&receivedCount, this](const Json::Value& msg, const std::string& position) {
&subscriptionPosition,
&fatalCobraError,
&sentCount](const Json::Value& msg, const std::string& position) {
subscriptionPosition = position; subscriptionPosition = position;
++receivedCount;
++receivedCountPerMinutes;
if (limitReceivedEvents)
{
if (receivedCountPerMinutes > maxEventsPerMinute)
{
return;
}
}
// If we cannot send to sentry fast enough, drop the message // If we cannot send to sentry fast enough, drop the message
if (throttled) if (throttled)
@ -156,8 +180,6 @@ namespace ix
return; return;
} }
++receivedCount;
_onBotMessageCallback( _onBotMessageCallback(
msg, position, throttled, msg, position, throttled,
fatalCobraError, sentCount); fatalCobraError, sentCount);

View File

@ -8,7 +8,7 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <ixcobra/IXCobraConfig.h> #include "IXCobraBotConfig.h"
#include <json/json.h> #include <json/json.h>
#include <stddef.h> #include <stddef.h>
@ -25,14 +25,7 @@ namespace ix
public: public:
CobraBot() = default; CobraBot() = default;
int64_t run(const CobraConfig& config, int64_t run(const CobraBotConfig& botConfig);
const std::string& channel,
const std::string& filter,
const std::string& position,
bool enableHeartbeat,
int heartBeatTimeout,
int runtime);
void setOnBotMessageCallback(const OnBotMessageCallback& callback); void setOnBotMessageCallback(const OnBotMessageCallback& callback);
private: private:

View File

@ -0,0 +1,31 @@
/*
* IXCobraBotConfig.h
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*/
#pragma once
#include <string>
#include <limits>
#include <ixcobra/IXCobraConfig.h>
#ifdef max
#undef max
#endif
namespace ix
{
struct CobraBotConfig
{
CobraConfig cobraConfig;
std::string channel;
std::string filter;
std::string position = std::string("$");
bool enableHeartbeat = true;
int heartBeatTimeout = 60;
int runtime = -1;
int maxEventsPerMinute = std::numeric_limits<int>::max();
bool limitReceivedEvents = false;
};
} // namespace ix

View File

@ -16,15 +16,9 @@
namespace ix namespace ix
{ {
int64_t cobra_to_sentry_bot(const CobraConfig& config, int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
SentryClient& sentryClient, SentryClient& sentryClient,
bool verbose, bool verbose)
bool enableHeartbeat,
int heartBeatTimeout,
int runtime)
{ {
CobraBot bot; CobraBot bot;
bot.setOnBotMessageCallback([&sentryClient, &verbose](const Json::Value& msg, bot.setOnBotMessageCallback([&sentryClient, &verbose](const Json::Value& msg,
@ -77,12 +71,6 @@ namespace ix
}); });
}); });
return bot.run(config, return bot.run(config);
channel,
filter,
position,
enableHeartbeat,
heartBeatTimeout,
runtime);
} }
} // namespace ix } // namespace ix

View File

@ -6,19 +6,13 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <ixcobra/IXCobraConfig.h> #include "IXCobraBotConfig.h"
#include <ixsentry/IXSentryClient.h> #include <ixsentry/IXSentryClient.h>
#include <string> #include <string>
namespace ix namespace ix
{ {
int64_t cobra_to_sentry_bot(const CobraConfig& config, int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
SentryClient& sentryClient, SentryClient& sentryClient,
bool verbose, bool verbose);
bool enableHeartbeat,
int heartBeatTimeout,
int runtime);
} // namespace ix } // namespace ix

View File

@ -53,23 +53,13 @@ namespace ix
return val; return val;
} }
int64_t cobra_to_statsd_bot(const ix::CobraConfig& config, int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
StatsdClient& statsdClient, StatsdClient& statsdClient,
const std::string& fields, const std::string& fields,
const std::string& gauge, const std::string& gauge,
const std::string& timer, const std::string& timer,
bool verbose, bool verbose)
bool enableHeartbeat,
int heartBeatTimeout,
int runtime)
{ {
ix::CobraConnection conn;
conn.configure(config);
conn.connect();
auto tokens = parseFields(fields); auto tokens = parseFields(fields);
CobraBot bot; CobraBot bot;
@ -142,12 +132,6 @@ namespace ix
sentCount++; sentCount++;
}); });
return bot.run(config, return bot.run(config);
channel,
filter,
position,
enableHeartbeat,
heartBeatTimeout,
runtime);
} }
} // namespace ix } // namespace ix

View File

@ -7,22 +7,16 @@
#include <cstdint> #include <cstdint>
#include <ixbots/IXStatsdClient.h> #include <ixbots/IXStatsdClient.h>
#include <ixcobra/IXCobraConfig.h> #include "IXCobraBotConfig.h"
#include <stddef.h> #include <stddef.h>
#include <string> #include <string>
namespace ix namespace ix
{ {
int64_t cobra_to_statsd_bot(const ix::CobraConfig& config, int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
StatsdClient& statsdClient, StatsdClient& statsdClient,
const std::string& fields, const std::string& fields,
const std::string& gauge, const std::string& gauge,
const std::string& timer, const std::string& timer,
bool verbose, bool verbose);
bool enableHeartbeat,
int heartBeatTimeout,
int runtime);
} // namespace ix } // namespace ix

View File

@ -63,15 +63,9 @@ namespace ix
} }
} }
int64_t cobra_to_stdout_bot(const CobraConfig& config, int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
bool fluentd, bool fluentd,
bool quiet, bool quiet)
bool enableHeartbeat,
int heartBeatTimeout,
int runtime)
{ {
CobraBot bot; CobraBot bot;
auto jsonWriter = makeStreamWriter(); auto jsonWriter = makeStreamWriter();
@ -89,12 +83,6 @@ namespace ix
sentCount++; sentCount++;
}); });
return bot.run(config, return bot.run(config);
channel,
filter,
position,
enableHeartbeat,
heartBeatTimeout,
runtime);
} }
} // namespace ix } // namespace ix

View File

@ -6,19 +6,13 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <ixcobra/IXCobraConfig.h> #include "IXCobraBotConfig.h"
#include <stddef.h> #include <stddef.h>
#include <string> #include <string>
namespace ix namespace ix
{ {
int64_t cobra_to_stdout_bot(const ix::CobraConfig& config, int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
const std::string& channel,
const std::string& filter,
const std::string& position,
bool fluentd, bool fluentd,
bool quiet, bool quiet);
bool enableHeartbeat,
int heartBeatTimeout,
int runtime);
} // namespace ix } // namespace ix

View File

@ -37,9 +37,7 @@ if (USE_MBED_TLS)
target_include_directories(ixcrypto PUBLIC ${MBEDTLS_INCLUDE_DIRS}) target_include_directories(ixcrypto PUBLIC ${MBEDTLS_INCLUDE_DIRS})
target_link_libraries(ixcrypto ${MBEDTLS_LIBRARIES}) target_link_libraries(ixcrypto ${MBEDTLS_LIBRARIES})
target_compile_definitions(ixcrypto PUBLIC IXCRYPTO_USE_MBED_TLS) target_compile_definitions(ixcrypto PUBLIC IXCRYPTO_USE_MBED_TLS)
elseif (APPLE) elseif (USE_OPEN_SSL)
elseif (WIN32)
else()
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
add_definitions(${OPENSSL_DEFINITIONS}) add_definitions(${OPENSSL_DEFINITIONS})
message(STATUS "OpenSSL: " ${OPENSSL_VERSION}) message(STATUS "OpenSSL: " ${OPENSSL_VERSION})

View File

@ -12,6 +12,8 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <zlib.h>
#include <cstring>
namespace namespace
{ {
@ -38,6 +40,47 @@ namespace
auto vec = res.second; auto vec = res.second;
return std::make_pair(res.first, std::string(vec.begin(), vec.end())); return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
} }
std::string gzipCompress(const std::string& str)
{
z_stream zs; // z_stream is zlib's control structure
memset(&zs, 0, sizeof(zs));
// deflateInit2 configure the file format: request gzip instead of deflate
const int windowBits = 15;
const int GZIP_ENCODING = 16;
deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
windowBits | GZIP_ENCODING, 8,
Z_DEFAULT_STRATEGY);
zs.next_in = (Bytef*) str.data();
zs.avail_in = (uInt) str.size(); // set the z_stream's input
int ret;
char outbuffer[32768];
std::string outstring;
// retrieve the compressed bytes blockwise
do
{
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = deflate(&zs, Z_FINISH);
if(outstring.size() < zs.total_out)
{
// append the block to the output string
outstring.append(outbuffer,
zs.total_out - outstring.size());
}
} while(ret == Z_OK);
deflateEnd(&zs);
return outstring;
}
} // namespace } // namespace
namespace ix namespace ix
@ -120,6 +163,12 @@ namespace ix
std::string content = res.second; std::string content = res.second;
std::string acceptEncoding = request->headers["Accept-encoding"];
if (acceptEncoding == "gzip" || acceptEncoding == "*")
{
content = gzipCompress(content);
}
// Log request // Log request
std::stringstream ss; std::stringstream ss;
ss << request->method << " " << request->headers["User-Agent"] << " " ss << request->method << " " << request->headers["User-Agent"] << " "

View File

@ -6,6 +6,7 @@
#include "IXSelectInterruptFactory.h" #include "IXSelectInterruptFactory.h"
#include "IXUniquePtr.h"
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
#include "IXSelectInterruptPipe.h" #include "IXSelectInterruptPipe.h"
#else #else
@ -17,9 +18,9 @@ namespace ix
SelectInterruptPtr createSelectInterrupt() SelectInterruptPtr createSelectInterrupt()
{ {
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
return std::make_unique<SelectInterruptPipe>(); return ix::make_unique<SelectInterruptPipe>();
#else #else
return std::make_unique<SelectInterrupt>(); return ix::make_unique<SelectInterrupt>();
#endif #endif
} }
} // namespace ix } // namespace ix

View File

@ -10,6 +10,7 @@
#include "IXNetSystem.h" #include "IXNetSystem.h"
#include "IXSelectInterrupt.h" #include "IXSelectInterrupt.h"
#include "IXSocket.h" #include "IXSocket.h"
#include "IXUniquePtr.h"
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
@ -65,7 +66,7 @@ namespace ix
int timeoutMs = 10; int timeoutMs = 10;
bool readyToRead = false; bool readyToRead = false;
auto selectInterrupt = std::make_unique<SelectInterrupt>(); auto selectInterrupt = ix::make_unique<SelectInterrupt>();
PollResultType pollResult = Socket::poll(readyToRead, timeoutMs, fd, selectInterrupt); PollResultType pollResult = Socket::poll(readyToRead, timeoutMs, fd, selectInterrupt);
if (pollResult == PollResultType::Timeout) if (pollResult == PollResultType::Timeout)

View File

@ -5,6 +5,7 @@
*/ */
#include "IXSocketFactory.h" #include "IXSocketFactory.h"
#include "IXUniquePtr.h"
#ifdef IXWEBSOCKET_USE_TLS #ifdef IXWEBSOCKET_USE_TLS
@ -35,17 +36,17 @@ namespace ix
if (!tls) if (!tls)
{ {
socket = std::make_unique<Socket>(fd); socket = ix::make_unique<Socket>(fd);
} }
else else
{ {
#ifdef IXWEBSOCKET_USE_TLS #ifdef IXWEBSOCKET_USE_TLS
#if defined(IXWEBSOCKET_USE_MBED_TLS) #if defined(IXWEBSOCKET_USE_MBED_TLS)
socket = std::make_unique<SocketMbedTLS>(tlsOptions, fd); socket = ix::make_unique<SocketMbedTLS>(tlsOptions, fd);
#elif defined(IXWEBSOCKET_USE_OPEN_SSL) #elif defined(IXWEBSOCKET_USE_OPEN_SSL)
socket = std::make_unique<SocketOpenSSL>(tlsOptions, fd); socket = ix::make_unique<SocketOpenSSL>(tlsOptions, fd);
#elif defined(__APPLE__) #elif defined(__APPLE__)
socket = std::make_unique<SocketAppleSSL>(tlsOptions, fd); socket = ix::make_unique<SocketAppleSSL>(tlsOptions, fd);
#endif #endif
#else #else
errorMsg = "TLS support is not enabled on this platform."; errorMsg = "TLS support is not enabled on this platform.";

View File

@ -43,6 +43,55 @@ namespace ix
mbedtls_pk_init(&_pkey); mbedtls_pk_init(&_pkey);
} }
bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg)
{
#ifdef _WIN32
DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
CERT_SYSTEM_STORE_CURRENT_USER;
HCERTSTORE systemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, flags, L"Root");
if (!systemStore)
{
errorMsg = "CertOpenStore failed with ";
errorMsg += std::to_string(GetLastError());
return false;
}
PCCERT_CONTEXT certificateIterator = NULL;
int certificateCount = 0;
while (certificateIterator = CertEnumCertificatesInStore(systemStore, certificateIterator))
{
if (certificateIterator->dwCertEncodingType & X509_ASN_ENCODING)
{
int ret = mbedtls_x509_crt_parse(&_cacert,
certificateIterator->pbCertEncoded,
certificateIterator->cbCertEncoded);
if (ret == 0)
{
++certificateCount;
}
}
}
CertFreeCertificateContext(certificateIterator);
CertCloseStore(systemStore, 0);
if (certificateCount == 0)
{
errorMsg = "No certificates found";
return false;
}
return true;
#else
// On macOS we can query the system cert location from the keychain
// On Linux we could try to fetch some local files based on the distribution
// On Android we could use JNI to get to the system certs
return false;
#endif
}
bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg) bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg)
{ {
initMBedTLS(); initMBedTLS();
@ -96,13 +145,15 @@ namespace ix
} }
else else
{ {
mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
// FIXME: should we call mbedtls_ssl_conf_verify ? // FIXME: should we call mbedtls_ssl_conf_verify ?
mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
if (_tlsOptions.isUsingSystemDefaults()) if (_tlsOptions.isUsingSystemDefaults())
{ {
; // FIXME if (!loadSystemCertificates(errMsg))
{
return false;
}
} }
else else
{ {

View File

@ -52,6 +52,7 @@ namespace ix
bool init(const std::string& host, bool isClient, std::string& errMsg); bool init(const std::string& host, bool isClient, std::string& errMsg);
void initMBedTLS(); void initMBedTLS();
bool loadSystemCertificates(std::string& errMsg);
}; };
} // namespace ix } // namespace ix

View File

@ -12,6 +12,7 @@
#include "IXSocket.h" #include "IXSocket.h"
#include "IXSocketConnect.h" #include "IXSocketConnect.h"
#include "IXSocketFactory.h" #include "IXSocketFactory.h"
#include "IXUniquePtr.h"
#include <assert.h> #include <assert.h>
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
@ -258,7 +259,7 @@ namespace ix
// Use poll to check whether a new connection is in progress // Use poll to check whether a new connection is in progress
int timeoutMs = 10; int timeoutMs = 10;
bool readyToRead = true; bool readyToRead = true;
auto selectInterrupt = std::make_unique<SelectInterrupt>(); auto selectInterrupt = ix::make_unique<SelectInterrupt>();
PollResultType pollResult = PollResultType pollResult =
Socket::poll(readyToRead, timeoutMs, _serverFd, selectInterrupt); Socket::poll(readyToRead, timeoutMs, _serverFd, selectInterrupt);

18
ixwebsocket/IXUniquePtr.h Normal file
View File

@ -0,0 +1,18 @@
/*
* IXUniquePtr.h
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*/
#pragma once
#include <memory>
namespace ix
{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}

View File

@ -33,6 +33,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <cstdlib>
namespace namespace
{ {

View File

@ -6,4 +6,4 @@
#pragma once #pragma once
#define IX_WEBSOCKET_VERSION "9.5.8" #define IX_WEBSOCKET_VERSION "9.6.5"

62
main.cpp Normal file
View File

@ -0,0 +1,62 @@
/*
* main.cpp
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*
* Super simple standalone example. See ws folder, unittest and doc/usage.md for more.
*
* On macOS
* $ mkdir -p build ; cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install
* $ clang++ --std=c++14 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
* $ ./a.out
*/
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXWebSocket.h>
#include <iostream>
int main()
{
// Required on Windows
ix::initNetSystem();
// Our websocket object
ix::WebSocket webSocket;
std::string url("wss://echo.websocket.org");
webSocket.setUrl(url);
std::cout << "Connecting to " << url << "..." << std::endl;
// Setup a callback to be fired (in a background thread, watch out for race conditions !)
// when a message or an event (open, close, error) is received
webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Message)
{
std::cout << "received message: " << msg->str << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Open)
{
std::cout << "Connection established" << std::endl;
}
}
);
// Now that our callback is setup, we can start our background thread and receive messages
webSocket.start();
// Send a message to the server (default to TEXT mode)
webSocket.send("hello world");
while (true)
{
std::string text;
std::cout << "> " << std::flush;
std::getline(std::cin, text);
webSocket.send(text);
}
return 0;
}

View File

@ -26,10 +26,10 @@ brew:
# server side ?) and I can't work-around it easily, so we're using mbedtls on # server side ?) and I can't work-around it easily, so we're using mbedtls on
# Linux for the SSL backend, which works great. # Linux for the SSL backend, which works great.
ws_mbedtls_install: ws_mbedtls_install:
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j 4 install) mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
ws: ws:
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4) mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; ninja install)
ws_install: ws_install:
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4 install) mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4 install)
@ -169,6 +169,53 @@ ws_test: ws
autobahn_report: autobahn_report:
cp -rvf ~/sandbox/reports/clients/* ../bsergean.github.io/IXWebSocket/autobahn/ cp -rvf ~/sandbox/reports/clients/* ../bsergean.github.io/IXWebSocket/autobahn/
httpd:
clang++ --std=c++11 --stdlib=libc++ -Iixwebsocket httpd.cpp \
ixwebsocket/IXSelectInterruptFactory.cpp \
ixwebsocket/IXCancellationRequest.cpp \
ixwebsocket/IXSocketTLSOptions.cpp \
ixwebsocket/IXUserAgent.cpp \
ixwebsocket/IXDNSLookup.cpp \
ixwebsocket/IXBench.cpp \
ixwebsocket/IXWebSocketHttpHeaders.cpp \
ixwebsocket/IXSelectInterruptPipe.cpp \
ixwebsocket/IXHttp.cpp \
ixwebsocket/IXSocketConnect.cpp \
ixwebsocket/IXSocket.cpp \
ixwebsocket/IXSocketServer.cpp \
ixwebsocket/IXNetSystem.cpp \
ixwebsocket/IXHttpServer.cpp \
ixwebsocket/IXSocketFactory.cpp \
ixwebsocket/IXConnectionState.cpp \
ixwebsocket/IXUrlParser.cpp \
ixwebsocket/IXSelectInterrupt.cpp \
ixwebsocket/apple/IXSetThreadName_apple.cpp \
-lz
httpd_linux:
g++ --std=c++11 -o ixhttpd httpd.cpp -Iixwebsocket \
ixwebsocket/IXSelectInterruptFactory.cpp \
ixwebsocket/IXCancellationRequest.cpp \
ixwebsocket/IXSocketTLSOptions.cpp \
ixwebsocket/IXUserAgent.cpp \
ixwebsocket/IXDNSLookup.cpp \
ixwebsocket/IXBench.cpp \
ixwebsocket/IXWebSocketHttpHeaders.cpp \
ixwebsocket/IXSelectInterruptPipe.cpp \
ixwebsocket/IXHttp.cpp \
ixwebsocket/IXSocketConnect.cpp \
ixwebsocket/IXSocket.cpp \
ixwebsocket/IXSocketServer.cpp \
ixwebsocket/IXNetSystem.cpp \
ixwebsocket/IXHttpServer.cpp \
ixwebsocket/IXSocketFactory.cpp \
ixwebsocket/IXConnectionState.cpp \
ixwebsocket/IXUrlParser.cpp \
ixwebsocket/IXSelectInterrupt.cpp \
ixwebsocket/linux/IXSetThreadName_linux.cpp \
-lz -lpthread
cp -f ixhttpd /usr/local/bin
# For the fork that is configured with appveyor # For the fork that is configured with appveyor
rebase_upstream: rebase_upstream:
git fetch upstream git fetch upstream

View File

@ -138,11 +138,12 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
std::thread publisherThread(runPublisher, config, channel); std::thread publisherThread(runPublisher, config, channel);
std::string filter; ix::CobraBotConfig cobraBotConfig;
std::string position("$"); cobraBotConfig.cobraConfig = config;
cobraBotConfig.channel = channel;
cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
cobraBotConfig.enableHeartbeat = false;
bool verbose = true; bool verbose = true;
bool enableHeartbeat = false;
int heartBeatTimeout = 60;
// FIXME: try to get this working with https instead of http // FIXME: try to get this working with https instead of http
// to regress the TLS 1.3 OpenSSL bug // to regress the TLS 1.3 OpenSSL bug
@ -157,18 +158,7 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
SentryClient sentryClient(dsn); SentryClient sentryClient(dsn);
sentryClient.setTLSOptions(tlsOptionsClient); sentryClient.setTLSOptions(tlsOptionsClient);
// Only run the bot for 3 seconds int64_t sentCount = cobra_to_sentry_bot(cobraBotConfig, sentryClient, verbose);
int runtime = 3;
int64_t sentCount = cobra_to_sentry_bot(config,
channel,
filter,
position,
sentryClient,
verbose,
enableHeartbeat,
heartBeatTimeout,
runtime);
// //
// We want at least 2 messages to be sent // We want at least 2 messages to be sent
// //

View File

@ -87,14 +87,11 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
std::thread publisherThread(runPublisher, config, channel); std::thread publisherThread(runPublisher, config, channel);
std::string filter; ix::CobraBotConfig cobraBotConfig;
std::string position("$"); cobraBotConfig.cobraConfig = config;
bool verbose = true; cobraBotConfig.channel = channel;
bool enableHeartbeat = false; cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
int heartBeatTimeout = 60; cobraBotConfig.enableHeartbeat = false;
// Only run the bot for 3 seconds
int runtime = 3;
std::string hostname("127.0.0.1"); std::string hostname("127.0.0.1");
// std::string hostname("www.google.com"); // std::string hostname("www.google.com");
@ -113,19 +110,10 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
std::string fields("device.game\ndevice.os_name"); std::string fields("device.game\ndevice.os_name");
std::string gauge; std::string gauge;
std::string timer; std::string timer;
bool verbose = true;
int64_t sentCount = ix::cobra_to_statsd_bot(config, int64_t sentCount =
channel, ix::cobra_to_statsd_bot(cobraBotConfig, statsdClient, fields, gauge, timer, verbose);
filter,
position,
statsdClient,
fields,
gauge,
timer,
verbose,
enableHeartbeat,
heartBeatTimeout,
runtime);
// //
// We want at least 2 messages to be sent // We want at least 2 messages to be sent
// //

View File

@ -85,27 +85,17 @@ TEST_CASE("Cobra_to_stdout_bot", "[cobra_bots]")
std::thread publisherThread(runPublisher, config, channel); std::thread publisherThread(runPublisher, config, channel);
std::string filter; ix::CobraBotConfig cobraBotConfig;
std::string position("$"); cobraBotConfig.cobraConfig = config;
cobraBotConfig.channel = channel;
cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
cobraBotConfig.enableHeartbeat = false;
bool quiet = false; bool quiet = false;
bool enableHeartbeat = false;
int heartBeatTimeout = 60;
// Only run the bot for 3 seconds
int runtime = 3;
// We could try to capture the output ... not sure how. // We could try to capture the output ... not sure how.
bool fluentd = true; bool fluentd = true;
int64_t sentCount = ix::cobra_to_stdout_bot(config, int64_t sentCount = ix::cobra_to_stdout_bot(cobraBotConfig, fluentd, quiet);
channel,
filter,
position,
fluentd,
quiet,
enableHeartbeat,
heartBeatTimeout,
runtime);
// //
// We want at least 2 messages to be sent // We want at least 2 messages to be sent
// //

View File

@ -93,10 +93,11 @@ TEST_CASE("subprotocol", "[websocket_subprotocol]")
webSocket.setUrl(url); webSocket.setUrl(url);
webSocket.start(); webSocket.start();
// Give us 3 seconds to connect
int attempts = 0; int attempts = 0;
while (!connected) while (!connected)
{ {
REQUIRE(attempts++ < 100); REQUIRE(attempts++ < 300);
ix::msleep(10); ix::msleep(10);
} }

36
tools/build_android.sh Normal file
View File

@ -0,0 +1,36 @@
#!/bin/sh
#
# Executable : ${HOME}/Android/Sdk/cmake/3.6.3155560/bin/cmake
# arguments :
# -H${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/src/main/cpp
# -B${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/.cxx/cmake/arm7Debug/armeabi-v7a
# -GAndroid Gradle - Ninja
# -DANDROID_ABI=armeabi-v7a
# -DANDROID_NDK=${HOME}/Android/Sdk/ndk-bundle
# -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/build/intermediates/cmake/arm7/debug/obj/armeabi-v7a
# -DCMAKE_BUILD_TYPE=Debug
# -DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.6.3155560/bin/ninja
# -DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake
# -DANDROID_NATIVE_API_LEVEL=23
# -DANDROID_TOOLCHAIN=clang
# jvmArgs :
#
CMAKE_TOOLCHAIN_FILE=/tools/android/android-ndk-r20-darwin/build/cmake/android.toolchain.cmake
ANDROID_HOME=/tools/android/android-sdk-darwin
ANDROID_NDK=${ANDROID_HOME}/ndk-bundle
CMAKE_DIR=${ANDROID_HOME}/cmake/3.10.2.4988404/bin
CMAKE=${CMAKE_DIR}/cmake
NINJA=${CMAKE_DIR}/ninja
${CMAKE} \
.. \
-DANDROID_NATIVE_API_LEVEL=23 \
-DANDROID_ABI=armeabi-v7a \
-DANDROID_TOOLCHAIN=clang \
-DANDROID_NDK=${ANDROID_NDK} \
-G'Unix Makefiles' \
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} \
-DCMAKE_MAKE_PROGRAM=make \
-DUSE_WS=1

View File

@ -120,6 +120,7 @@ int main(int argc, char** argv)
std::string logfile; std::string logfile;
ix::SocketTLSOptions tlsOptions; ix::SocketTLSOptions tlsOptions;
ix::CobraConfig cobraConfig; ix::CobraConfig cobraConfig;
ix::CobraBotConfig cobraBotConfig;
std::string ciphers; std::string ciphers;
std::string redirectUrl; std::string redirectUrl;
bool headersOnly = false; bool headersOnly = false;
@ -149,8 +150,6 @@ int main(int argc, char** argv)
int count = 1; int count = 1;
uint32_t maxWaitBetweenReconnectionRetries; uint32_t maxWaitBetweenReconnectionRetries;
int pingIntervalSecs = 30; int pingIntervalSecs = 30;
int runtime = -1; // run indefinitely
int heartBeatTimeout = 60;
auto addTLSOptions = [&tlsOptions, &verifyNone](CLI::App* app) { auto addTLSOptions = [&tlsOptions, &verifyNone](CLI::App* app) {
app->add_option( app->add_option(
@ -174,6 +173,24 @@ int main(int argc, char** argv)
app->add_option("--rolesecret", cobraConfig.rolesecret, "Role secret")->required(); app->add_option("--rolesecret", cobraConfig.rolesecret, "Role secret")->required();
}; };
auto addCobraBotConfig = [&cobraBotConfig](CLI::App* app) {
app->add_option("--appkey", cobraBotConfig.cobraConfig.appkey, "Appkey")->required();
app->add_option("--endpoint", cobraBotConfig.cobraConfig.endpoint, "Endpoint")->required();
app->add_option("--rolename", cobraBotConfig.cobraConfig.rolename, "Role name")->required();
app->add_option("--rolesecret", cobraBotConfig.cobraConfig.rolesecret, "Role secret")
->required();
app->add_option("--channel", cobraBotConfig.channel, "Channel")->required();
app->add_option("--filter", cobraBotConfig.filter, "Filter");
app->add_option("--position", cobraBotConfig.position, "Position");
app->add_option("--runtime", cobraBotConfig.runtime, "Runtime");
app->add_option("--heartbeat", cobraBotConfig.enableHeartbeat, "Runtime");
app->add_option("--heartbeat_timeout", cobraBotConfig.heartBeatTimeout, "Runtime");
app->add_flag(
"--limit_received_events", cobraBotConfig.limitReceivedEvents, "Max events per minute");
app->add_option(
"--max_events_per_minute", cobraBotConfig.maxEventsPerMinute, "Max events per minute");
};
app.add_flag("--version", version, "Print ws version"); app.add_flag("--version", version, "Print ws version");
app.add_option("--logfile", logfile, "path where all logs will be redirected"); app.add_option("--logfile", logfile, "path where all logs will be redirected");
@ -281,16 +298,11 @@ int main(int argc, char** argv)
CLI::App* cobraSubscribeApp = app.add_subcommand("cobra_subscribe", "Cobra subscriber"); CLI::App* cobraSubscribeApp = app.add_subcommand("cobra_subscribe", "Cobra subscriber");
cobraSubscribeApp->fallthrough(); cobraSubscribeApp->fallthrough();
cobraSubscribeApp->add_option("--channel", channel, "Channel")->required();
cobraSubscribeApp->add_option("--pidfile", pidfile, "Pid file"); cobraSubscribeApp->add_option("--pidfile", pidfile, "Pid file");
cobraSubscribeApp->add_option("--filter", filter, "Stream SQL Filter");
cobraSubscribeApp->add_option("--position", position, "Stream position");
cobraSubscribeApp->add_flag("-q", quiet, "Quiet / only display stats"); cobraSubscribeApp->add_flag("-q", quiet, "Quiet / only display stats");
cobraSubscribeApp->add_flag("--fluentd", fluentd, "Write fluentd prefix"); cobraSubscribeApp->add_flag("--fluentd", fluentd, "Write fluentd prefix");
cobraSubscribeApp->add_option("--runtime", runtime, "Runtime in seconds");
cobraSubscribeApp->add_option("--heartbeat_timeout", heartBeatTimeout, "Heartbeat timeout");
addTLSOptions(cobraSubscribeApp); addTLSOptions(cobraSubscribeApp);
addCobraConfig(cobraSubscribeApp); addCobraBotConfig(cobraSubscribeApp);
CLI::App* cobraPublish = app.add_subcommand("cobra_publish", "Cobra publisher"); CLI::App* cobraPublish = app.add_subcommand("cobra_publish", "Cobra publisher");
cobraPublish->fallthrough(); cobraPublish->fallthrough();
@ -324,28 +336,18 @@ int main(int argc, char** argv)
->join(); ->join();
cobra2statsd->add_option("--timer", timer, "Value to extract, and use as a statsd timer") cobra2statsd->add_option("--timer", timer, "Value to extract, and use as a statsd timer")
->join(); ->join();
cobra2statsd->add_option("channel", channel, "Channel")->required();
cobra2statsd->add_flag("-v", verbose, "Verbose"); cobra2statsd->add_flag("-v", verbose, "Verbose");
cobra2statsd->add_option("--pidfile", pidfile, "Pid file"); cobra2statsd->add_option("--pidfile", pidfile, "Pid file");
cobra2statsd->add_option("--filter", filter, "Stream SQL Filter");
cobra2statsd->add_option("--position", position, "Stream position");
cobra2statsd->add_option("--runtime", runtime, "Runtime in seconds");
cobra2statsd->add_option("--heartbeat_timeout", heartBeatTimeout, "Heartbeat timeout");
addTLSOptions(cobra2statsd); addTLSOptions(cobra2statsd);
addCobraConfig(cobra2statsd); addCobraBotConfig(cobra2statsd);
CLI::App* cobra2sentry = app.add_subcommand("cobra_to_sentry", "Cobra metrics to sentry"); CLI::App* cobra2sentry = app.add_subcommand("cobra_to_sentry", "Cobra metrics to sentry");
cobra2sentry->fallthrough(); cobra2sentry->fallthrough();
cobra2sentry->add_option("--dsn", dsn, "Sentry DSN"); cobra2sentry->add_option("--dsn", dsn, "Sentry DSN");
cobra2sentry->add_option("channel", channel, "Channel")->required();
cobra2sentry->add_flag("-v", verbose, "Verbose"); cobra2sentry->add_flag("-v", verbose, "Verbose");
cobra2sentry->add_option("--pidfile", pidfile, "Pid file"); cobra2sentry->add_option("--pidfile", pidfile, "Pid file");
cobra2sentry->add_option("--filter", filter, "Stream SQL Filter");
cobra2sentry->add_option("--position", position, "Stream position");
cobra2sentry->add_option("--runtime", runtime, "Runtime in seconds");
cobra2sentry->add_option("--heartbeat_timeout", heartBeatTimeout, "Heartbeat timeout");
addTLSOptions(cobra2sentry); addTLSOptions(cobra2sentry);
addCobraConfig(cobra2sentry); addCobraBotConfig(cobra2sentry);
CLI::App* cobra2redisApp = CLI::App* cobra2redisApp =
app.add_subcommand("cobra_metrics_to_redis", "Cobra metrics to redis"); app.add_subcommand("cobra_metrics_to_redis", "Cobra metrics to redis");
@ -456,6 +458,10 @@ int main(int argc, char** argv)
cobraConfig.webSocketPerMessageDeflateOptions = ix::WebSocketPerMessageDeflateOptions(true); cobraConfig.webSocketPerMessageDeflateOptions = ix::WebSocketPerMessageDeflateOptions(true);
cobraConfig.socketTLSOptions = tlsOptions; cobraConfig.socketTLSOptions = tlsOptions;
cobraBotConfig.cobraConfig.webSocketPerMessageDeflateOptions =
ix::WebSocketPerMessageDeflateOptions(true);
cobraBotConfig.cobraConfig.socketTLSOptions = tlsOptions;
int ret = 1; int ret = 1;
if (app.got_subcommand("transfer")) if (app.got_subcommand("transfer"))
{ {
@ -525,16 +531,7 @@ int main(int argc, char** argv)
} }
else if (app.got_subcommand("cobra_subscribe")) else if (app.got_subcommand("cobra_subscribe"))
{ {
bool enableHeartbeat = true; int64_t sentCount = ix::cobra_to_stdout_bot(cobraBotConfig, fluentd, quiet);
int64_t sentCount = ix::cobra_to_stdout_bot(cobraConfig,
channel,
filter,
position,
fluentd,
quiet,
enableHeartbeat,
heartBeatTimeout,
runtime);
ret = (int) sentCount; ret = (int) sentCount;
} }
else if (app.got_subcommand("cobra_publish")) else if (app.got_subcommand("cobra_publish"))
@ -555,7 +552,6 @@ int main(int argc, char** argv)
} }
else else
{ {
bool enableHeartbeat = true;
ix::StatsdClient statsdClient(hostname, statsdPort, prefix); ix::StatsdClient statsdClient(hostname, statsdPort, prefix);
std::string errMsg; std::string errMsg;
@ -567,36 +563,17 @@ int main(int argc, char** argv)
} }
else else
{ {
ret = (int) ix::cobra_to_statsd_bot(cobraConfig, ret = (int) ix::cobra_to_statsd_bot(
channel, cobraBotConfig, statsdClient, fields, gauge, timer, verbose);
filter,
position,
statsdClient,
fields,
gauge,
timer,
verbose,
enableHeartbeat,
heartBeatTimeout,
runtime);
} }
} }
} }
else if (app.got_subcommand("cobra_to_sentry")) else if (app.got_subcommand("cobra_to_sentry"))
{ {
bool enableHeartbeat = true;
ix::SentryClient sentryClient(dsn); ix::SentryClient sentryClient(dsn);
sentryClient.setTLSOptions(tlsOptions); sentryClient.setTLSOptions(tlsOptions);
ret = (int) ix::cobra_to_sentry_bot(cobraConfig, ret = (int) ix::cobra_to_sentry_bot(cobraBotConfig, sentryClient, verbose);
channel,
filter,
position,
sentryClient,
verbose,
enableHeartbeat,
heartBeatTimeout,
runtime);
} }
else if (app.got_subcommand("cobra_metrics_to_redis")) else if (app.got_subcommand("cobra_metrics_to_redis"))
{ {

View File

@ -109,8 +109,11 @@ namespace ix
args->verbose = verbose; args->verbose = verbose;
args->compress = compress; args->compress = compress;
args->logger = [](const std::string& msg) { spdlog::info(msg); }; args->logger = [](const std::string& msg) { spdlog::info(msg); };
args->onProgressCallback = [](int current, int total) -> bool { args->onProgressCallback = [verbose](int current, int total) -> bool {
if (verbose)
{
spdlog::info("Downloaded {} bytes out of {}", current, total); spdlog::info("Downloaded {} bytes out of {}", current, total);
}
return true; return true;
}; };