Compare commits
	
		
			8 Commits
		
	
	
		
			v1.3.0
			...
			feature/pi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a5179cd17f | ||
| 
						 | 
					e158175819 | ||
| 
						 | 
					ec2f229489 | ||
| 
						 | 
					ead9616d04 | ||
| 
						 | 
					922d58eb59 | ||
| 
						 | 
					d1a7b9a985 | ||
| 
						 | 
					11092027cd | ||
| 
						 | 
					4de3ec995e | 
							
								
								
									
										0
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -16,6 +16,7 @@ if (NOT WIN32)
 | 
				
			|||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set( IXWEBSOCKET_SOURCES
 | 
					set( IXWEBSOCKET_SOURCES
 | 
				
			||||||
 | 
					    ixwebsocket/IXEventFd.cpp
 | 
				
			||||||
    ixwebsocket/IXSocket.cpp
 | 
					    ixwebsocket/IXSocket.cpp
 | 
				
			||||||
    ixwebsocket/IXSocketServer.cpp
 | 
					    ixwebsocket/IXSocketServer.cpp
 | 
				
			||||||
    ixwebsocket/IXSocketConnect.cpp
 | 
					    ixwebsocket/IXSocketConnect.cpp
 | 
				
			||||||
@@ -32,12 +33,10 @@ set( IXWEBSOCKET_SOURCES
 | 
				
			|||||||
    ixwebsocket/IXWebSocketHttpHeaders.cpp
 | 
					    ixwebsocket/IXWebSocketHttpHeaders.cpp
 | 
				
			||||||
    ixwebsocket/IXHttpClient.cpp
 | 
					    ixwebsocket/IXHttpClient.cpp
 | 
				
			||||||
    ixwebsocket/IXUrlParser.cpp
 | 
					    ixwebsocket/IXUrlParser.cpp
 | 
				
			||||||
    ixwebsocket/IXSelectInterrupt.cpp
 | 
					 | 
				
			||||||
    ixwebsocket/IXSelectInterruptPipe.cpp
 | 
					 | 
				
			||||||
    ixwebsocket/IXSelectInterruptFactory.cpp
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set( IXWEBSOCKET_HEADERS
 | 
					set( IXWEBSOCKET_HEADERS
 | 
				
			||||||
 | 
					    ixwebsocket/IXEventFd.h
 | 
				
			||||||
    ixwebsocket/IXSocket.h
 | 
					    ixwebsocket/IXSocket.h
 | 
				
			||||||
    ixwebsocket/IXSocketServer.h
 | 
					    ixwebsocket/IXSocketServer.h
 | 
				
			||||||
    ixwebsocket/IXSocketConnect.h
 | 
					    ixwebsocket/IXSocketConnect.h
 | 
				
			||||||
@@ -59,9 +58,6 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/libwshandshake.hpp
 | 
					    ixwebsocket/libwshandshake.hpp
 | 
				
			||||||
    ixwebsocket/IXHttpClient.h
 | 
					    ixwebsocket/IXHttpClient.h
 | 
				
			||||||
    ixwebsocket/IXUrlParser.h
 | 
					    ixwebsocket/IXUrlParser.h
 | 
				
			||||||
    ixwebsocket/IXSelectInterrupt.h
 | 
					 | 
				
			||||||
    ixwebsocket/IXSelectInterruptPipe.h
 | 
					 | 
				
			||||||
    ixwebsocket/IXSelectInterruptFactory.h
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Platform specific code
 | 
					# Platform specific code
 | 
				
			||||||
@@ -71,8 +67,6 @@ elseif (WIN32)
 | 
				
			|||||||
    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/windows/IXSetThreadName_windows.cpp)
 | 
					    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/windows/IXSetThreadName_windows.cpp)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
 | 
					    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
 | 
				
			||||||
    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSelectInterruptEventFd.cpp)
 | 
					 | 
				
			||||||
    list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptEventFd.h)
 | 
					 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (USE_TLS)
 | 
					if (USE_TLS)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ communication channels over a single TCP connection. *IXWebSocket* is a C++ libr
 | 
				
			|||||||
* iOS
 | 
					* iOS
 | 
				
			||||||
* Linux
 | 
					* Linux
 | 
				
			||||||
* Android 
 | 
					* Android 
 | 
				
			||||||
 | 
					* Windows (no TLS support yet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Examples
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,7 +125,7 @@ HttpRequestArgs args;
 | 
				
			|||||||
// Custom headers can be set
 | 
					// Custom headers can be set
 | 
				
			||||||
WebSocketHttpHeaders headers;
 | 
					WebSocketHttpHeaders headers;
 | 
				
			||||||
headers["Foo"] = "bar";
 | 
					headers["Foo"] = "bar";
 | 
				
			||||||
args.extraHeaders = headers;
 | 
					args.extraHeaders = parseHeaders(headersData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Timeout options
 | 
					// Timeout options
 | 
				
			||||||
args.connectTimeout = connectTimeout;
 | 
					args.connectTimeout = connectTimeout;
 | 
				
			||||||
@@ -379,7 +380,7 @@ websocket.ping("ping data, optional (empty string is ok): limited to 125 bytes l
 | 
				
			|||||||
### Heartbeat.
 | 
					### Heartbeat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can configure an optional heart beat / keep-alive, sent every 45 seconds
 | 
					You can configure an optional heart beat / keep-alive, sent every 45 seconds
 | 
				
			||||||
when there is no any traffic to make sure that load balancers do not kill an
 | 
					when there is not any traffic to make sure that load balancers do not kill an
 | 
				
			||||||
idle connection.
 | 
					idle connection.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								examples/cobra_publisher/ixcrypto/IXHash.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								examples/cobra_publisher/ixcrypto/IXHash.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXHash.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t djb2Hash(const std::string& data)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint64_t hashAddress = 5381;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (auto& c : data)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            hashAddress = ((hashAddress << 5) + hashAddress) + c;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return hashAddress;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								examples/cobra_publisher/ixcrypto/IXHash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								examples/cobra_publisher/ixcrypto/IXHash.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXHash.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t djb2Hash(const std::string& data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										75
									
								
								examples/cobra_publisher/ixcrypto/IXUuid.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								examples/cobra_publisher/ixcrypto/IXUuid.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXUuid.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Generate a random uuid similar to the uuid python module
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * >>> import uuid
 | 
				
			||||||
 | 
					 * >>> uuid.uuid4().hex
 | 
				
			||||||
 | 
					 * 'bec08155b37d4050a1f3c3fa0276bf12'
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Code adapted from https://github.com/r-lyeh-archived/sole
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXUuid.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class Uuid
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public:
 | 
				
			||||||
 | 
					            Uuid();
 | 
				
			||||||
 | 
					            std::string toString() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private:
 | 
				
			||||||
 | 
					            uint64_t _ab;
 | 
				
			||||||
 | 
					            uint64_t _cd;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Uuid::Uuid()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        static std::random_device rd;
 | 
				
			||||||
 | 
					        static std::uniform_int_distribution<uint64_t> dist(0, (uint64_t)(~0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _ab = dist(rd);
 | 
				
			||||||
 | 
					        _cd = dist(rd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _ab = (_ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL;
 | 
				
			||||||
 | 
					        _cd = (_cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string Uuid::toString() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        ss << std::hex << std::nouppercase << std::setfill('0');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint32_t a = (_ab >> 32);
 | 
				
			||||||
 | 
					        uint32_t b = (_ab & 0xFFFFFFFF);
 | 
				
			||||||
 | 
					        uint32_t c = (_cd >> 32);
 | 
				
			||||||
 | 
					        uint32_t d = (_cd & 0xFFFFFFFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ss << std::setw(8) << (a);
 | 
				
			||||||
 | 
					        ss << std::setw(4) << (b >> 16);
 | 
				
			||||||
 | 
					        ss << std::setw(4) << (b & 0xFFFF);
 | 
				
			||||||
 | 
					        ss << std::setw(4) << (c >> 16 );
 | 
				
			||||||
 | 
					        ss << std::setw(4) << (c & 0xFFFF);
 | 
				
			||||||
 | 
					        ss << std::setw(8) << d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ss.str();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string uuid4()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Uuid id;
 | 
				
			||||||
 | 
					        return id.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								examples/cobra_publisher/ixcrypto/IXUuid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								examples/cobra_publisher/ixcrypto/IXUuid.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXUuid.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2017 Machine Zone. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   /**
 | 
				
			||||||
 | 
					    * Generate a random uuid
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   std::string uuid4();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_receive/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/ws_receive/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					build
 | 
				
			||||||
							
								
								
									
										30
									
								
								examples/ws_receive/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/ws_receive/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cmake_minimum_required (VERSION 3.4.1)
 | 
				
			||||||
 | 
					project (ws_receive)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# There's -Weverything too for clang
 | 
				
			||||||
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshorten-64-to-32")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set (CMAKE_CXX_STANDARD 14)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option(USE_TLS "Add TLS support" ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include_directories(ws_receive .)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_executable(ws_receive 
 | 
				
			||||||
 | 
					  jsoncpp/jsoncpp.cpp
 | 
				
			||||||
 | 
					  ixcrypto/IXBase64.cpp
 | 
				
			||||||
 | 
					  ixcrypto/IXHash.cpp
 | 
				
			||||||
 | 
					  ws_receive.cpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (APPLE AND USE_TLS)
 | 
				
			||||||
 | 
					    target_link_libraries(ws_receive "-framework foundation" "-framework security")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(ws_receive ixwebsocket)
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_receive/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/ws_receive/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ws_receive is a simple server upload program. It needs to be used in conjonction with ws_send.
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_receive/ixcrypto
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								examples/ws_receive/ixcrypto
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../cobra_publisher/ixcrypto
 | 
				
			||||||
							
								
								
									
										333
									
								
								examples/ws_receive/jsoncpp/json/json-forwards.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								examples/ws_receive/jsoncpp/json/json-forwards.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,333 @@
 | 
				
			|||||||
 | 
					/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/).
 | 
				
			||||||
 | 
					/// It is intended to be used with #include "json/json-forwards.h"
 | 
				
			||||||
 | 
					/// This header provides forward declaration for all JsonCpp types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Beginning of content of file: LICENSE
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					The JsonCpp library's source code, including accompanying documentation,
 | 
				
			||||||
 | 
					tests and demonstration applications, are licensed under the following
 | 
				
			||||||
 | 
					conditions...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
 | 
				
			||||||
 | 
					jurisdictions which recognize such a disclaimer. In such jurisdictions,
 | 
				
			||||||
 | 
					this software is released into the Public Domain.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
 | 
				
			||||||
 | 
					2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
 | 
				
			||||||
 | 
					The JsonCpp Authors, and is released under the terms of the MIT License (see below).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In jurisdictions which recognize Public Domain property, the user of this
 | 
				
			||||||
 | 
					software may choose to accept it either as 1) Public Domain, 2) under the
 | 
				
			||||||
 | 
					conditions of the MIT License (see below), or 3) under the terms of dual
 | 
				
			||||||
 | 
					Public Domain/MIT License conditions described here, as they choose.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The MIT License is about as close to Public Domain as a license can get, and is
 | 
				
			||||||
 | 
					described in clear, concise terms at:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   http://en.wikipedia.org/wiki/MIT_License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The full text of the MIT License follows:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					========================================================================
 | 
				
			||||||
 | 
					Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person
 | 
				
			||||||
 | 
					obtaining a copy of this software and associated documentation
 | 
				
			||||||
 | 
					files (the "Software"), to deal in the Software without
 | 
				
			||||||
 | 
					restriction, including without limitation the rights to use, copy,
 | 
				
			||||||
 | 
					modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
				
			||||||
 | 
					of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be
 | 
				
			||||||
 | 
					included in all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
				
			||||||
 | 
					EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
				
			||||||
 | 
					MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
				
			||||||
 | 
					NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | 
				
			||||||
 | 
					BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
				
			||||||
 | 
					ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
				
			||||||
 | 
					CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
 | 
					========================================================================
 | 
				
			||||||
 | 
					(END LICENSE TEXT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The MIT license is compatible with both the GPL and commercial
 | 
				
			||||||
 | 
					software, affording one all of the rights of Public Domain with the
 | 
				
			||||||
 | 
					minor nuisance of being required to keep the above copyright notice
 | 
				
			||||||
 | 
					and license text in the source code. Note also that by accepting the
 | 
				
			||||||
 | 
					Public Domain "license" you can re-license your copy using whatever
 | 
				
			||||||
 | 
					license you like.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// End of content of file: LICENSE
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
 | 
				
			||||||
 | 
					# define JSON_FORWARD_AMALGATED_H_INCLUDED
 | 
				
			||||||
 | 
					/// If defined, indicates that the source file is amalgated
 | 
				
			||||||
 | 
					/// to prevent private header inclusion.
 | 
				
			||||||
 | 
					#define JSON_IS_AMALGAMATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Beginning of content of file: include/json/config.h
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
 | 
				
			||||||
 | 
					// Distributed under MIT license, or public domain if desired and
 | 
				
			||||||
 | 
					// recognized in your jurisdiction.
 | 
				
			||||||
 | 
					// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef JSON_CONFIG_H_INCLUDED
 | 
				
			||||||
 | 
					#define JSON_CONFIG_H_INCLUDED
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <string> //typedef String
 | 
				
			||||||
 | 
					#include <stdint.h> //typedef int64_t, uint64_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// If defined, indicates that json library is embedded in CppTL library.
 | 
				
			||||||
 | 
					//# define JSON_IN_CPPTL 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// If defined, indicates that json may leverage CppTL library
 | 
				
			||||||
 | 
					//#  define JSON_USE_CPPTL 1
 | 
				
			||||||
 | 
					/// If defined, indicates that cpptl vector based map should be used instead of
 | 
				
			||||||
 | 
					/// std::map
 | 
				
			||||||
 | 
					/// as Value container.
 | 
				
			||||||
 | 
					//#  define JSON_USE_CPPTL_SMALLMAP 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If non-zero, the library uses exceptions to report bad input instead of C
 | 
				
			||||||
 | 
					// assertion macros. The default is to use exceptions.
 | 
				
			||||||
 | 
					#ifndef JSON_USE_EXCEPTION
 | 
				
			||||||
 | 
					#define JSON_USE_EXCEPTION 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// If defined, indicates that the source file is amalgated
 | 
				
			||||||
 | 
					/// to prevent private header inclusion.
 | 
				
			||||||
 | 
					/// Remarks: it is automatically defined in the generated amalgated header.
 | 
				
			||||||
 | 
					// #define JSON_IS_AMALGAMATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef JSON_IN_CPPTL
 | 
				
			||||||
 | 
					#include <cpptl/config.h>
 | 
				
			||||||
 | 
					#ifndef JSON_USE_CPPTL
 | 
				
			||||||
 | 
					#define JSON_USE_CPPTL 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef JSON_IN_CPPTL
 | 
				
			||||||
 | 
					#define JSON_API CPPTL_API
 | 
				
			||||||
 | 
					#elif defined(JSON_DLL_BUILD)
 | 
				
			||||||
 | 
					#if defined(_MSC_VER) || defined(__MINGW32__)
 | 
				
			||||||
 | 
					#define JSON_API __declspec(dllexport)
 | 
				
			||||||
 | 
					#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
 | 
				
			||||||
 | 
					#endif // if defined(_MSC_VER)
 | 
				
			||||||
 | 
					#elif defined(JSON_DLL)
 | 
				
			||||||
 | 
					#if defined(_MSC_VER) || defined(__MINGW32__)
 | 
				
			||||||
 | 
					#define JSON_API __declspec(dllimport)
 | 
				
			||||||
 | 
					#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
 | 
				
			||||||
 | 
					#endif // if defined(_MSC_VER)
 | 
				
			||||||
 | 
					#endif // ifdef JSON_IN_CPPTL
 | 
				
			||||||
 | 
					#if !defined(JSON_API)
 | 
				
			||||||
 | 
					#define JSON_API
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
 | 
				
			||||||
 | 
					// integer
 | 
				
			||||||
 | 
					// Storages, and 64 bits integer support is disabled.
 | 
				
			||||||
 | 
					// #define JSON_NO_INT64 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(_MSC_VER) // MSVC
 | 
				
			||||||
 | 
					#  if _MSC_VER <= 1200 // MSVC 6
 | 
				
			||||||
 | 
					    // Microsoft Visual Studio 6 only support conversion from __int64 to double
 | 
				
			||||||
 | 
					    // (no conversion from unsigned __int64).
 | 
				
			||||||
 | 
					#    define JSON_USE_INT64_DOUBLE_CONVERSION 1
 | 
				
			||||||
 | 
					    // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
 | 
				
			||||||
 | 
					    // characters in the debug information)
 | 
				
			||||||
 | 
					    // All projects I've ever seen with VS6 were using this globally (not bothering
 | 
				
			||||||
 | 
					    // with pragma push/pop).
 | 
				
			||||||
 | 
					#    pragma warning(disable : 4786)
 | 
				
			||||||
 | 
					#  endif // MSVC 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#  if _MSC_VER >= 1500 // MSVC 2008
 | 
				
			||||||
 | 
					    /// Indicates that the following function is deprecated.
 | 
				
			||||||
 | 
					#    define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
 | 
				
			||||||
 | 
					#  endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // defined(_MSC_VER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// In c++11 the override keyword allows you to explicity define that a function
 | 
				
			||||||
 | 
					// is intended to override the base-class version.  This makes the code more
 | 
				
			||||||
 | 
					// managable and fixes a set of common hard-to-find bugs.
 | 
				
			||||||
 | 
					#if __cplusplus >= 201103L
 | 
				
			||||||
 | 
					# define JSONCPP_OVERRIDE override
 | 
				
			||||||
 | 
					# define JSONCPP_NOEXCEPT noexcept
 | 
				
			||||||
 | 
					#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900
 | 
				
			||||||
 | 
					# define JSONCPP_OVERRIDE override
 | 
				
			||||||
 | 
					# define JSONCPP_NOEXCEPT throw()
 | 
				
			||||||
 | 
					#elif defined(_MSC_VER) && _MSC_VER >= 1900
 | 
				
			||||||
 | 
					# define JSONCPP_OVERRIDE override
 | 
				
			||||||
 | 
					# define JSONCPP_NOEXCEPT noexcept
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					# define JSONCPP_OVERRIDE
 | 
				
			||||||
 | 
					# define JSONCPP_NOEXCEPT throw()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef JSON_HAS_RVALUE_REFERENCES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
 | 
				
			||||||
 | 
					#define JSON_HAS_RVALUE_REFERENCES 1
 | 
				
			||||||
 | 
					#endif // MSVC >= 2010
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __clang__
 | 
				
			||||||
 | 
					#if __has_feature(cxx_rvalue_references)
 | 
				
			||||||
 | 
					#define JSON_HAS_RVALUE_REFERENCES 1
 | 
				
			||||||
 | 
					#endif  // has_feature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
 | 
				
			||||||
 | 
					#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
 | 
				
			||||||
 | 
					#define JSON_HAS_RVALUE_REFERENCES 1
 | 
				
			||||||
 | 
					#endif  // GXX_EXPERIMENTAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // __clang__ || __GNUC__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // not defined JSON_HAS_RVALUE_REFERENCES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef JSON_HAS_RVALUE_REFERENCES
 | 
				
			||||||
 | 
					#define JSON_HAS_RVALUE_REFERENCES 0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __clang__
 | 
				
			||||||
 | 
					#  if __has_extension(attribute_deprecated_with_message)
 | 
				
			||||||
 | 
					#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
 | 
				
			||||||
 | 
					#  endif
 | 
				
			||||||
 | 
					#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
 | 
				
			||||||
 | 
					#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
 | 
				
			||||||
 | 
					#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
 | 
				
			||||||
 | 
					#  elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
 | 
				
			||||||
 | 
					#    define JSONCPP_DEPRECATED(message)  __attribute__((__deprecated__))
 | 
				
			||||||
 | 
					#  endif  // GNUC version
 | 
				
			||||||
 | 
					#endif // __clang__ || __GNUC__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(JSONCPP_DEPRECATED)
 | 
				
			||||||
 | 
					#define JSONCPP_DEPRECATED(message)
 | 
				
			||||||
 | 
					#endif // if !defined(JSONCPP_DEPRECATED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if __GNUC__ >= 6
 | 
				
			||||||
 | 
					#  define JSON_USE_INT64_DOUBLE_CONVERSION 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(JSON_IS_AMALGAMATION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# include "version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# if JSONCPP_USING_SECURE_MEMORY
 | 
				
			||||||
 | 
					#  include "allocator.h" //typedef Allocator
 | 
				
			||||||
 | 
					# endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // if !defined(JSON_IS_AMALGAMATION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Json {
 | 
				
			||||||
 | 
					typedef int Int;
 | 
				
			||||||
 | 
					typedef unsigned int UInt;
 | 
				
			||||||
 | 
					#if defined(JSON_NO_INT64)
 | 
				
			||||||
 | 
					typedef int LargestInt;
 | 
				
			||||||
 | 
					typedef unsigned int LargestUInt;
 | 
				
			||||||
 | 
					#undef JSON_HAS_INT64
 | 
				
			||||||
 | 
					#else                 // if defined(JSON_NO_INT64)
 | 
				
			||||||
 | 
					// For Microsoft Visual use specific types as long long is not supported
 | 
				
			||||||
 | 
					#if defined(_MSC_VER) // Microsoft Visual Studio
 | 
				
			||||||
 | 
					typedef __int64 Int64;
 | 
				
			||||||
 | 
					typedef unsigned __int64 UInt64;
 | 
				
			||||||
 | 
					#else                 // if defined(_MSC_VER) // Other platforms, use long long
 | 
				
			||||||
 | 
					typedef int64_t Int64;
 | 
				
			||||||
 | 
					typedef uint64_t UInt64;
 | 
				
			||||||
 | 
					#endif // if defined(_MSC_VER)
 | 
				
			||||||
 | 
					typedef Int64 LargestInt;
 | 
				
			||||||
 | 
					typedef UInt64 LargestUInt;
 | 
				
			||||||
 | 
					#define JSON_HAS_INT64
 | 
				
			||||||
 | 
					#endif // if defined(JSON_NO_INT64)
 | 
				
			||||||
 | 
					#if JSONCPP_USING_SECURE_MEMORY
 | 
				
			||||||
 | 
					#define JSONCPP_STRING        std::basic_string<char, std::char_traits<char>, Json::SecureAllocator<char> >
 | 
				
			||||||
 | 
					#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
 | 
				
			||||||
 | 
					#define JSONCPP_OSTREAM       std::basic_ostream<char, std::char_traits<char>>
 | 
				
			||||||
 | 
					#define JSONCPP_ISTRINGSTREAM std::basic_istringstream<char, std::char_traits<char>, Json::SecureAllocator<char> >
 | 
				
			||||||
 | 
					#define JSONCPP_ISTREAM       std::istream
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define JSONCPP_STRING        std::string
 | 
				
			||||||
 | 
					#define JSONCPP_OSTRINGSTREAM std::ostringstream
 | 
				
			||||||
 | 
					#define JSONCPP_OSTREAM       std::ostream
 | 
				
			||||||
 | 
					#define JSONCPP_ISTRINGSTREAM std::istringstream
 | 
				
			||||||
 | 
					#define JSONCPP_ISTREAM       std::istream
 | 
				
			||||||
 | 
					#endif // if JSONCPP_USING_SECURE_MEMORY
 | 
				
			||||||
 | 
					} // end namespace Json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // JSON_CONFIG_H_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// End of content of file: include/json/config.h
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// Beginning of content of file: include/json/forwards.h
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
 | 
				
			||||||
 | 
					// Distributed under MIT license, or public domain if desired and
 | 
				
			||||||
 | 
					// recognized in your jurisdiction.
 | 
				
			||||||
 | 
					// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef JSON_FORWARDS_H_INCLUDED
 | 
				
			||||||
 | 
					#define JSON_FORWARDS_H_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(JSON_IS_AMALGAMATION)
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif // if !defined(JSON_IS_AMALGAMATION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Json {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// writer.h
 | 
				
			||||||
 | 
					class FastWriter;
 | 
				
			||||||
 | 
					class StyledWriter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// reader.h
 | 
				
			||||||
 | 
					class Reader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// features.h
 | 
				
			||||||
 | 
					class Features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// value.h
 | 
				
			||||||
 | 
					typedef unsigned int ArrayIndex;
 | 
				
			||||||
 | 
					class StaticString;
 | 
				
			||||||
 | 
					class Path;
 | 
				
			||||||
 | 
					class PathArgument;
 | 
				
			||||||
 | 
					class Value;
 | 
				
			||||||
 | 
					class ValueIteratorBase;
 | 
				
			||||||
 | 
					class ValueIterator;
 | 
				
			||||||
 | 
					class ValueConstIterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // JSON_FORWARDS_H_INCLUDED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					// End of content of file: include/json/forwards.h
 | 
				
			||||||
 | 
					// //////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED
 | 
				
			||||||
							
								
								
									
										2186
									
								
								examples/ws_receive/jsoncpp/json/json.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2186
									
								
								examples/ws_receive/jsoncpp/json/json.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5386
									
								
								examples/ws_receive/jsoncpp/jsoncpp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5386
									
								
								examples/ws_receive/jsoncpp/jsoncpp.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29
									
								
								examples/ws_receive/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/ws_receive/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "requires": true,
 | 
				
			||||||
 | 
					  "lockfileVersion": 1,
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "async-limiter": {
 | 
				
			||||||
 | 
					      "version": "1.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "base-64": {
 | 
				
			||||||
 | 
					      "version": "0.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "djb2": {
 | 
				
			||||||
 | 
					      "version": "0.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/djb2/-/djb2-0.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-RAs4kao6uBQrVNRpsXe66p6W5O8="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "ws": {
 | 
				
			||||||
 | 
					      "version": "6.1.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "async-limiter": "1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										153
									
								
								examples/ws_receive/ws_receive.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								examples/ws_receive/ws_receive.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ws_receive.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocketServer.h>
 | 
				
			||||||
 | 
					#include <jsoncpp/json/json.h>
 | 
				
			||||||
 | 
					#include <ixcrypto/IXBase64.h>
 | 
				
			||||||
 | 
					#include <ixcrypto/IXHash.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // We should cleanup the file name and full path further to remove .. as well
 | 
				
			||||||
 | 
					    std::string extractFilename(const std::string& path)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::string filename("filename.conf");
 | 
				
			||||||
 | 
					        std::string::size_type idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        idx = path.rfind('/');
 | 
				
			||||||
 | 
					        if (idx != std::string::npos)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::string filename = path.substr(idx+1);
 | 
				
			||||||
 | 
					            return filename;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return std::string();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void errorHandler(const std::string& errMsg,
 | 
				
			||||||
 | 
					                      const std::string& id,
 | 
				
			||||||
 | 
					                      std::shared_ptr<ix::WebSocket> webSocket)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Json::Value pdu;
 | 
				
			||||||
 | 
					        pdu["kind"] = "error";
 | 
				
			||||||
 | 
					        pdu["id"] = id;
 | 
				
			||||||
 | 
					        pdu["message"] = errMsg;
 | 
				
			||||||
 | 
					        webSocket->send(pdu.toStyledString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void messageHandler(const std::string& str,
 | 
				
			||||||
 | 
					                        std::shared_ptr<ix::WebSocket> webSocket)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cerr << "Received message: " << str.size() << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Json::Value data;
 | 
				
			||||||
 | 
					        Json::Reader reader;
 | 
				
			||||||
 | 
					        if (!reader.parse(str, data))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errorHandler("Invalid JSON", std::string(), webSocket);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "id: " << data["id"].asString() << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string content = ix::base64_decode(data["content"].asString());
 | 
				
			||||||
 | 
					        std::cout << "Content size: " << content.size() << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Validate checksum
 | 
				
			||||||
 | 
					        uint64_t cksum = ix::djb2Hash(data["content"].asString());
 | 
				
			||||||
 | 
					        uint64_t cksumRef = data["djb2_hash"].asUInt64();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "Computed hash: " << cksum << std::endl;
 | 
				
			||||||
 | 
					        std::cout << "Reference hash: " << cksumRef << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (cksum != cksumRef)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errorHandler("Hash mismatch.", std::string(), webSocket);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string filename = data["filename"].asString();
 | 
				
			||||||
 | 
					        filename = extractFilename(filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::ofstream out(filename);
 | 
				
			||||||
 | 
					        out << content;
 | 
				
			||||||
 | 
					        out.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Json::Value pdu;
 | 
				
			||||||
 | 
					        pdu["ack"] = true;
 | 
				
			||||||
 | 
					        pdu["id"] = data["id"];
 | 
				
			||||||
 | 
					        pdu["filename"] = data["filename"];
 | 
				
			||||||
 | 
					        webSocket->send(pdu.toStyledString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char** argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int port = 8080;
 | 
				
			||||||
 | 
					    if (argc == 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        ss << argv[1];
 | 
				
			||||||
 | 
					        ss >> port;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ix::WebSocketServer server(port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server.setOnConnectionCallback(
 | 
				
			||||||
 | 
					        [&server](std::shared_ptr<ix::WebSocket> webSocket)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            webSocket->setOnMessageCallback(
 | 
				
			||||||
 | 
					                [webSocket, &server](ix::WebSocketMessageType messageType,
 | 
				
			||||||
 | 
					                                     const std::string& str,
 | 
				
			||||||
 | 
					                                     size_t wireSize,
 | 
				
			||||||
 | 
					                                     const ix::WebSocketErrorInfo& error,
 | 
				
			||||||
 | 
					                                     const ix::WebSocketOpenInfo& openInfo,
 | 
				
			||||||
 | 
					                                     const ix::WebSocketCloseInfo& closeInfo)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (messageType == ix::WebSocket_MessageType_Open)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::cerr << "New connection" << std::endl;
 | 
				
			||||||
 | 
					                        std::cerr << "Uri: " << openInfo.uri << std::endl;
 | 
				
			||||||
 | 
					                        std::cerr << "Headers:" << std::endl;
 | 
				
			||||||
 | 
					                        for (auto it : openInfo.headers)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            std::cerr << it.first << ": " << it.second << std::endl;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (messageType == ix::WebSocket_MessageType_Close)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::cerr << "Closed connection" << std::endl;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (messageType == ix::WebSocket_MessageType_Message)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        messageHandler(str, webSocket);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto res = server.listen();
 | 
				
			||||||
 | 
					    if (!res.first)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cerr << res.second << std::endl;
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server.start();
 | 
				
			||||||
 | 
					    server.wait();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								examples/ws_receive/ws_receive.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								examples/ws_receive/ws_receive.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ws_receive.js
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const WebSocket = require('ws')
 | 
				
			||||||
 | 
					const djb2 = require('djb2')
 | 
				
			||||||
 | 
					const fs = require('fs')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const wss = new WebSocket.Server({ port: 8080,
 | 
				
			||||||
 | 
					                                   perMessageDeflate: false,
 | 
				
			||||||
 | 
					                                   maxPayload: 1024 * 1024 * 1024 * 1024});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wss.on('connection', function connection(ws) {
 | 
				
			||||||
 | 
					  ws.on('message', function incoming(data) {
 | 
				
			||||||
 | 
					    console.log('Received message')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let str = data.toString()
 | 
				
			||||||
 | 
					    let obj = JSON.parse(str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log(obj.id)
 | 
				
			||||||
 | 
					    console.log(obj.djb2_hash)
 | 
				
			||||||
 | 
					    console.log(djb2(obj.content))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var content = Buffer.from(obj.content, 'base64')
 | 
				
			||||||
 | 
					    // let bytes = base64.decode(obj.content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let path = obj.filename
 | 
				
			||||||
 | 
					    fs.writeFile(path, content, function(err) {
 | 
				
			||||||
 | 
					      if (err) {
 | 
				
			||||||
 | 
					        throw err
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        console.log('wrote data to disk')
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let response = {
 | 
				
			||||||
 | 
					      id: obj.id
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ws.send(JSON.stringify(response))
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_send/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/ws_send/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					build
 | 
				
			||||||
							
								
								
									
										31
									
								
								examples/ws_send/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								examples/ws_send/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cmake_minimum_required (VERSION 3.4.1)
 | 
				
			||||||
 | 
					project (ws_send)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# There's -Weverything too for clang
 | 
				
			||||||
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshorten-64-to-32")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set (CMAKE_CXX_STANDARD 14)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option(USE_TLS "Add TLS support" ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include_directories(ws_send .)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_executable(ws_send 
 | 
				
			||||||
 | 
					  jsoncpp/jsoncpp.cpp
 | 
				
			||||||
 | 
					  ixcrypto/IXBase64.cpp
 | 
				
			||||||
 | 
					  ixcrypto/IXUuid.cpp
 | 
				
			||||||
 | 
					  ixcrypto/IXHash.cpp
 | 
				
			||||||
 | 
					  ws_send.cpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (APPLE AND USE_TLS)
 | 
				
			||||||
 | 
					    target_link_libraries(ws_send "-framework foundation" "-framework security")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(ws_send ixwebsocket)
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_send/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/ws_send/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ws_send is a simple upload program. It needs to be used in conjonction with ws_receive.
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_send/ixcrypto
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								examples/ws_send/ixcrypto
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../cobra_publisher/ixcrypto
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/ws_send/jsoncpp
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								examples/ws_send/jsoncpp
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../cobra_publisher/jsoncpp
 | 
				
			||||||
							
								
								
									
										306
									
								
								examples/ws_send/ws_send.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								examples/ws_send/ws_send.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,306 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  ws_send.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <condition_variable>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
 | 
					#include <ixcrypto/IXUuid.h>
 | 
				
			||||||
 | 
					#include <ixcrypto/IXBase64.h>
 | 
				
			||||||
 | 
					#include <ixcrypto/IXHash.h>
 | 
				
			||||||
 | 
					#include <jsoncpp/json/json.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace ix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void log(const std::string& msg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cout << msg << std::endl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class WebSocketSender
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public:
 | 
				
			||||||
 | 
					            WebSocketSender(const std::string& _url,
 | 
				
			||||||
 | 
					                            bool enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void subscribe(const std::string& channel);
 | 
				
			||||||
 | 
					            void start();
 | 
				
			||||||
 | 
					            void stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void waitForConnection();
 | 
				
			||||||
 | 
					            void waitForAck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void sendMessage(const std::string& filename, bool throttle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private:
 | 
				
			||||||
 | 
					            std::string _url;
 | 
				
			||||||
 | 
					            std::string _id;
 | 
				
			||||||
 | 
					            ix::WebSocket _webSocket;
 | 
				
			||||||
 | 
					            bool _enablePerMessageDeflate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::mutex _conditionVariableMutex;
 | 
				
			||||||
 | 
					            std::condition_variable _condition;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WebSocketSender::WebSocketSender(const std::string& url,
 | 
				
			||||||
 | 
					                                     bool enablePerMessageDeflate) :
 | 
				
			||||||
 | 
					        _url(url),
 | 
				
			||||||
 | 
					        _enablePerMessageDeflate(enablePerMessageDeflate)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketSender::stop()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _webSocket.stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketSender::waitForConnection()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cout << "Connecting..." << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::unique_lock<std::mutex> lock(_conditionVariableMutex);
 | 
				
			||||||
 | 
					        _condition.wait(lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketSender::waitForAck()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cout << "Waiting for ack..." << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::unique_lock<std::mutex> lock(_conditionVariableMutex);
 | 
				
			||||||
 | 
					        _condition.wait(lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string load(const std::string& path)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // std::vector<uint8_t> memblock;
 | 
				
			||||||
 | 
					        std::string str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::ifstream file(path);
 | 
				
			||||||
 | 
					        if (!file.is_open()) return std::string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        file.seekg(0, file.end);
 | 
				
			||||||
 | 
					        std::streamoff size = file.tellg();
 | 
				
			||||||
 | 
					        file.seekg(0, file.beg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        str.resize(size);
 | 
				
			||||||
 | 
					        file.read((char*)&str.front(), static_cast<std::streamsize>(size));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketSender::start()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _webSocket.setUrl(_url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ix::WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(
 | 
				
			||||||
 | 
					            _enablePerMessageDeflate, false, false, 15, 15);
 | 
				
			||||||
 | 
					        _webSocket.setPerMessageDeflateOptions(webSocketPerMessageDeflateOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        log(std::string("Connecting to url: ") + _url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _webSocket.setOnMessageCallback(
 | 
				
			||||||
 | 
					            [this](ix::WebSocketMessageType messageType,
 | 
				
			||||||
 | 
					               const std::string& str,
 | 
				
			||||||
 | 
					               size_t wireSize,
 | 
				
			||||||
 | 
					               const ix::WebSocketErrorInfo& error,
 | 
				
			||||||
 | 
					               const ix::WebSocketOpenInfo& openInfo,
 | 
				
			||||||
 | 
					               const ix::WebSocketCloseInfo& closeInfo)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					                if (messageType == ix::WebSocket_MessageType_Open)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _condition.notify_one();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    log("ws_send: connected");
 | 
				
			||||||
 | 
					                    std::cout << "Uri: " << openInfo.uri << std::endl;
 | 
				
			||||||
 | 
					                    std::cout << "Handshake Headers:" << std::endl;
 | 
				
			||||||
 | 
					                    for (auto it : openInfo.headers)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::cout << it.first << ": " << it.second << std::endl;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (messageType == ix::WebSocket_MessageType_Close)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "ws_send: connection closed:";
 | 
				
			||||||
 | 
					                    ss << " code " << closeInfo.code;
 | 
				
			||||||
 | 
					                    ss << " reason " << closeInfo.reason << std::endl;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (messageType == ix::WebSocket_MessageType_Message)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _condition.notify_one();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    ss << "ws_send: received message: "
 | 
				
			||||||
 | 
					                       << str;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Json::Value data;
 | 
				
			||||||
 | 
					                    Json::Reader reader;
 | 
				
			||||||
 | 
					                    if (!reader.parse(str, data))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::cerr << "Invalid JSON response" << std::endl;
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    std::string id = data["id"].asString();
 | 
				
			||||||
 | 
					                    if (_id != id)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::cerr << "Invalid id" << std::endl;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (messageType == ix::WebSocket_MessageType_Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Connection error: " << error.reason      << std::endl;
 | 
				
			||||||
 | 
					                    ss << "#retries: "         << error.retries     << std::endl;
 | 
				
			||||||
 | 
					                    ss << "Wait time(ms): "    << error.wait_time   << std::endl;
 | 
				
			||||||
 | 
					                    ss << "HTTP Status: "      << error.http_status << std::endl;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Invalid ix::WebSocketMessageType";
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _webSocket.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Bench
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public:
 | 
				
			||||||
 | 
					            Bench(const std::string& description) :
 | 
				
			||||||
 | 
					                _description(description),
 | 
				
			||||||
 | 
					                _start(std::chrono::system_clock::now()),
 | 
				
			||||||
 | 
					                _reported(false)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ~Bench()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!_reported)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    report();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void report()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto now = std::chrono::system_clock::now();
 | 
				
			||||||
 | 
					                auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _ms = milliseconds.count();
 | 
				
			||||||
 | 
					                std::cout << _description << " completed in "
 | 
				
			||||||
 | 
					                          << _ms << "ms" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _reported = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint64_t getDuration() const
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return _ms;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private:
 | 
				
			||||||
 | 
					            std::string _description;
 | 
				
			||||||
 | 
					            std::chrono::time_point<std::chrono::system_clock> _start;
 | 
				
			||||||
 | 
					            uint64_t _ms;
 | 
				
			||||||
 | 
					            bool _reported;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketSender::sendMessage(const std::string& filename,
 | 
				
			||||||
 | 
					                                      bool throttle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::string content;
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Bench bench("load file from disk");
 | 
				
			||||||
 | 
					            content = load(filename);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _id = uuid4();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string b64Content;
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Bench bench("base 64 encode file");
 | 
				
			||||||
 | 
					            b64Content = base64_encode(content, content.size());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Json::Value pdu;
 | 
				
			||||||
 | 
					        pdu["kind"] = "send";
 | 
				
			||||||
 | 
					        pdu["id"] = _id;
 | 
				
			||||||
 | 
					        pdu["content"] = b64Content;
 | 
				
			||||||
 | 
					        pdu["djb2_hash"] = djb2Hash(b64Content);
 | 
				
			||||||
 | 
					        pdu["filename"] = filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Bench bench("Sending file through websocket");
 | 
				
			||||||
 | 
					        _webSocket.send(pdu.toStyledString(),
 | 
				
			||||||
 | 
					                        [throttle](int current, int total) -> bool
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::cout << "Step " << current << " out of " << total << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (throttle)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                std::chrono::duration<double, std::milli> duration(10);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bench.report();
 | 
				
			||||||
 | 
					        auto duration = bench.getDuration();
 | 
				
			||||||
 | 
					        auto transferRate = 1000 * b64Content.size() / duration;
 | 
				
			||||||
 | 
					        transferRate /= (1024 * 1024);
 | 
				
			||||||
 | 
					        std::cout << "Send transfer rate: " << transferRate << "MB/s" << std::endl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void wsSend(const std::string& url,
 | 
				
			||||||
 | 
					                const std::string& path,
 | 
				
			||||||
 | 
					                bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                bool throttle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        WebSocketSender webSocketSender(url, enablePerMessageDeflate);
 | 
				
			||||||
 | 
					        webSocketSender.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        webSocketSender.waitForConnection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "Sending..." << std::endl;
 | 
				
			||||||
 | 
					        webSocketSender.sendMessage(path, throttle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        webSocketSender.waitForAck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "Done !" << std::endl;
 | 
				
			||||||
 | 
					        webSocketSender.stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char** argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (argc != 3)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::cerr << "Usage: ws_send <url> <path>" << std::endl;
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::string url = argv[1];
 | 
				
			||||||
 | 
					    std::string path = argv[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool throttle = false;
 | 
				
			||||||
 | 
					    bool enablePerMessageDeflate = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Socket::init();
 | 
				
			||||||
 | 
					    wsSend(url, path, enablePerMessageDeflate, throttle);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										117
									
								
								ixwebsocket/IXEventFd.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								ixwebsocket/IXEventFd.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXEventFd.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Linux/Android has a special type of virtual files. select(2) will react
 | 
				
			||||||
 | 
					// when reading/writing to those files, unlike closing sockets.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// https://linux.die.net/man/2/eventfd
 | 
				
			||||||
 | 
					// http://www.sourcexr.com/articles/2013/10/26/lightweight-inter-process-signaling-with-eventfd
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// eventfd was added in Linux kernel 2.x, and our oldest Android (Kitkat 4.4)
 | 
				
			||||||
 | 
					// is on Kernel 3.x
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// cf Android/Kernel table here
 | 
				
			||||||
 | 
					// https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// On macOS we use UNIX pipes to wake up select.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXEventFd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					# include <sys/eventfd.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h> // for write
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EventFd::EventFd()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					        _eventfd = -1;
 | 
				
			||||||
 | 
					        _eventfd = eventfd(0, 0);
 | 
				
			||||||
 | 
					        fcntl(_eventfd, F_SETFL, O_NONBLOCK);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        _fildes[0] = -1;
 | 
				
			||||||
 | 
					        _fildes[1] = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pipe(_fildes);
 | 
				
			||||||
 | 
					        fcntl(_fildes[0], F_SETFL, O_NONBLOCK);
 | 
				
			||||||
 | 
					        fcntl(_fildes[1], F_SETFL, O_NONBLOCK);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EventFd::~EventFd()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					        ::close(_eventfd);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        ::close(_fildes[0]);
 | 
				
			||||||
 | 
					        ::close(_fildes[1]);
 | 
				
			||||||
 | 
					        _fildes[0] = -1;
 | 
				
			||||||
 | 
					        _fildes[1] = -1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool EventFd::notify(uint64_t value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					        fd = _eventfd;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        // File descriptor at index 1 in _fildes is the write end of the pipe
 | 
				
			||||||
 | 
					        fd = _fildes[1];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fd == -1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // we should write 8 bytes for an uint64_t
 | 
				
			||||||
 | 
					        return write(fd, &value, sizeof(value)) == 8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: return max uint64_t for errors ?
 | 
				
			||||||
 | 
					    uint64_t EventFd::read()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					        fd = _eventfd;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        fd = _fildes[0];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        uint64_t value = 0;
 | 
				
			||||||
 | 
					        ::read(fd, &value, sizeof(value));
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool EventFd::clear()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					        if (_eventfd == -1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 0 is a special value ; select will not wake up
 | 
				
			||||||
 | 
					        uint64_t value = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // we should write 8 bytes for an uint64_t
 | 
				
			||||||
 | 
					        return write(_eventfd, &value, sizeof(value)) == 8;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int EventFd::getFd()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					        return _eventfd;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return _fildes[0];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								ixwebsocket/IXEventFd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ixwebsocket/IXEventFd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXEventFd.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class EventFd {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        EventFd();
 | 
				
			||||||
 | 
					        virtual ~EventFd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool notify(uint64_t value);
 | 
				
			||||||
 | 
					        bool clear();
 | 
				
			||||||
 | 
					        uint64_t read();
 | 
				
			||||||
 | 
					        int getFd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					#if defined(__linux__)
 | 
				
			||||||
 | 
					        int _eventfd;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        // Store file descriptors used by the communication pipe. Communication
 | 
				
			||||||
 | 
					        // happens between a control thread and a background thread, which is
 | 
				
			||||||
 | 
					        // blocked on select.
 | 
				
			||||||
 | 
					        int _fildes[2];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,46 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterrupt.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    SelectInterrupt::SelectInterrupt()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SelectInterrupt::~SelectInterrupt()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterrupt::init(std::string& /*errorMsg*/)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterrupt::notify(uint64_t /*value*/)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint64_t SelectInterrupt::read()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterrupt::clear()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int SelectInterrupt::getFd() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,28 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterrupt.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class SelectInterrupt {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        SelectInterrupt();
 | 
					 | 
				
			||||||
        virtual ~SelectInterrupt();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        virtual bool init(std::string& errorMsg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        virtual bool notify(uint64_t value);
 | 
					 | 
				
			||||||
        virtual bool clear();
 | 
					 | 
				
			||||||
        virtual uint64_t read();
 | 
					 | 
				
			||||||
        virtual int getFd() const;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,116 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptEventFd.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// On Linux we use eventd to wake up select.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Linux/Android has a special type of virtual files. select(2) will react
 | 
					 | 
				
			||||||
// when reading/writing to those files, unlike closing sockets.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// https://linux.die.net/man/2/eventfd
 | 
					 | 
				
			||||||
// http://www.sourcexr.com/articles/2013/10/26/lightweight-inter-process-signaling-with-eventfd
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// eventfd was added in Linux kernel 2.x, and our oldest Android (Kitkat 4.4)
 | 
					 | 
				
			||||||
// is on Kernel 3.x
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// cf Android/Kernel table here
 | 
					 | 
				
			||||||
// https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// On macOS we use UNIX pipes to wake up select.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterruptEventFd.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sys/eventfd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <unistd.h> // for write
 | 
					 | 
				
			||||||
#include <string.h> // for strerror
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    SelectInterruptEventFd::SelectInterruptEventFd()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _eventfd = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SelectInterruptEventFd::~SelectInterruptEventFd()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ::close(_eventfd);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptEventFd::init(std::string& errorMsg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // calling init twice is a programming error
 | 
					 | 
				
			||||||
        assert(_eventfd == -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        _eventfd = eventfd(0, 0);
 | 
					 | 
				
			||||||
        if (_eventfd < 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "SelectInterruptEventFd::init() failed in eventfd()"
 | 
					 | 
				
			||||||
               << " : " << strerror(errno);
 | 
					 | 
				
			||||||
            errorMsg = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _eventfd = -1;
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fcntl(_eventfd, F_SETFL, O_NONBLOCK) == -1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "SelectInterruptEventFd::init() failed in fcntl() call"
 | 
					 | 
				
			||||||
               << " : " << strerror(errno);
 | 
					 | 
				
			||||||
            errorMsg = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _eventfd = -1;
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptEventFd::notify(uint64_t value)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int fd = _eventfd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fd == -1) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // we should write 8 bytes for an uint64_t
 | 
					 | 
				
			||||||
        return write(fd, &value, sizeof(value)) == 8;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: return max uint64_t for errors ?
 | 
					 | 
				
			||||||
    uint64_t SelectInterruptEventFd::read()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int fd = _eventfd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint64_t value = 0;
 | 
					 | 
				
			||||||
        ::read(fd, &value, sizeof(value));
 | 
					 | 
				
			||||||
        return value;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptEventFd::clear()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (_eventfd == -1) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 0 is a special value ; select will not wake up
 | 
					 | 
				
			||||||
        uint64_t value = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // we should write 8 bytes for an uint64_t
 | 
					 | 
				
			||||||
        return write(_eventfd, &value, sizeof(value)) == 8;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int SelectInterruptEventFd::getFd() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return _eventfd;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptEventFd.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class SelectInterruptEventFd : public SelectInterrupt {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        SelectInterruptEventFd();
 | 
					 | 
				
			||||||
        virtual ~SelectInterruptEventFd();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool init(std::string& errorMsg) final;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool notify(uint64_t value) final;
 | 
					 | 
				
			||||||
        bool clear() final;
 | 
					 | 
				
			||||||
        uint64_t read() final;
 | 
					 | 
				
			||||||
        int getFd() const final;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        int _eventfd;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptFactory.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterruptFactory.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__linux__) || defined(__APPLE__)
 | 
					 | 
				
			||||||
# include <ixwebsocket/IXSelectInterruptPipe.h>
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# include <ixwebsocket/IXSelectInterrupt.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    std::shared_ptr<SelectInterrupt> createSelectInterrupt()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
#if defined(__linux__) || defined(__APPLE__)
 | 
					 | 
				
			||||||
        return std::make_shared<SelectInterruptPipe>();
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        return std::make_shared<SelectInterrupt>();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptFactory.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class SelectInterrupt;
 | 
					 | 
				
			||||||
    std::shared_ptr<SelectInterrupt> createSelectInterrupt();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,119 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptPipe.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// On macOS we use UNIX pipes to wake up select.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterruptPipe.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <unistd.h> // for write
 | 
					 | 
				
			||||||
#include <string.h> // for strerror
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // File descriptor at index 0 in _fildes is the read end of the pipe
 | 
					 | 
				
			||||||
    // File descriptor at index 1 in _fildes is the write end of the pipe
 | 
					 | 
				
			||||||
    const int SelectInterruptPipe::kPipeReadIndex = 0;
 | 
					 | 
				
			||||||
    const int SelectInterruptPipe::kPipeWriteIndex = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SelectInterruptPipe::SelectInterruptPipe()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _fildes[kPipeReadIndex] = -1;
 | 
					 | 
				
			||||||
        _fildes[kPipeWriteIndex] = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SelectInterruptPipe::~SelectInterruptPipe()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ::close(_fildes[kPipeReadIndex]);
 | 
					 | 
				
			||||||
        ::close(_fildes[kPipeWriteIndex]);
 | 
					 | 
				
			||||||
        _fildes[kPipeReadIndex] = -1;
 | 
					 | 
				
			||||||
        _fildes[kPipeWriteIndex] = -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptPipe::init(std::string& errorMsg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // calling init twice is a programming error
 | 
					 | 
				
			||||||
        assert(_fildes[kPipeReadIndex] == -1);
 | 
					 | 
				
			||||||
        assert(_fildes[kPipeWriteIndex] == -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (pipe(_fildes) < 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "SelectInterruptPipe::init() failed in pipe() call"
 | 
					 | 
				
			||||||
               << " : " << strerror(errno);
 | 
					 | 
				
			||||||
            errorMsg = ss.str();
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fcntl(_fildes[kPipeReadIndex], F_SETFL, O_NONBLOCK) == -1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "SelectInterruptPipe::init() failed in fcntl() call"
 | 
					 | 
				
			||||||
               << " : " << strerror(errno);
 | 
					 | 
				
			||||||
            errorMsg = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _fildes[kPipeReadIndex] = -1;
 | 
					 | 
				
			||||||
            _fildes[kPipeWriteIndex] = -1;
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (fcntl(_fildes[kPipeWriteIndex], F_SETFL, O_NONBLOCK) == -1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "SelectInterruptPipe::init() failed in fcntl() call"
 | 
					 | 
				
			||||||
               << " : " << strerror(errno);
 | 
					 | 
				
			||||||
            errorMsg = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _fildes[kPipeReadIndex] = -1;
 | 
					 | 
				
			||||||
            _fildes[kPipeWriteIndex] = -1;
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // FIXME: on macOS we should configure the pipe to not trigger SIGPIPE
 | 
					 | 
				
			||||||
        // on reads/writes to a closed fd
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // The generation of the SIGPIPE signal can be suppressed using the
 | 
					 | 
				
			||||||
        // F_SETNOSIGPIPE fcntl command.
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptPipe::notify(uint64_t value)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int fd = _fildes[kPipeWriteIndex];
 | 
					 | 
				
			||||||
        if (fd == -1) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // we should write 8 bytes for an uint64_t
 | 
					 | 
				
			||||||
        return write(fd, &value, sizeof(value)) == 8;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: return max uint64_t for errors ?
 | 
					 | 
				
			||||||
    uint64_t SelectInterruptPipe::read()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int fd = _fildes[kPipeReadIndex];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint64_t value = 0;
 | 
					 | 
				
			||||||
        ::read(fd, &value, sizeof(value));
 | 
					 | 
				
			||||||
        return value;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SelectInterruptPipe::clear()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int SelectInterruptPipe::getFd() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return _fildes[kPipeReadIndex];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXSelectInterruptPipe.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class SelectInterruptPipe : public SelectInterrupt {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        SelectInterruptPipe();
 | 
					 | 
				
			||||||
        virtual ~SelectInterruptPipe();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool init(std::string& errorMsg) final;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool notify(uint64_t value) final;
 | 
					 | 
				
			||||||
        bool clear() final;
 | 
					 | 
				
			||||||
        uint64_t read() final;
 | 
					 | 
				
			||||||
        int getFd() const final;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        // Store file descriptors used by the communication pipe. Communication
 | 
					 | 
				
			||||||
        // happens between a control thread and a background thread, which is
 | 
					 | 
				
			||||||
        // blocked on select.
 | 
					 | 
				
			||||||
        int _fildes[2];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Used to identify the read/write idx
 | 
					 | 
				
			||||||
        static const int kPipeReadIndex;
 | 
					 | 
				
			||||||
        static const int kPipeWriteIndex;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -7,8 +7,6 @@
 | 
				
			|||||||
#include "IXSocket.h"
 | 
					#include "IXSocket.h"
 | 
				
			||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
#include "IXNetSystem.h"
 | 
					#include "IXNetSystem.h"
 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					 | 
				
			||||||
#include "IXSelectInterruptFactory.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
@@ -25,13 +23,12 @@ namespace ix
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default
 | 
					    const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default
 | 
				
			||||||
    const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout;
 | 
					    const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout;
 | 
				
			||||||
    const uint64_t Socket::kSendRequest = 1;
 | 
					    const uint8_t Socket::kSendRequest = 1;
 | 
				
			||||||
    const uint64_t Socket::kCloseRequest = 2;
 | 
					    const uint8_t Socket::kCloseRequest = 2;
 | 
				
			||||||
    constexpr size_t Socket::kChunkSize;
 | 
					    constexpr size_t Socket::kChunkSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Socket::Socket(int fd) :
 | 
					    Socket::Socket(int fd) :
 | 
				
			||||||
        _sockfd(fd),
 | 
					        _sockfd(fd)
 | 
				
			||||||
        _selectInterrupt(createSelectInterrupt())
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ;
 | 
					        ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -49,27 +46,22 @@ namespace ix
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PollResultType pollResult = isReadyToRead(timeoutSecs, 0);
 | 
					        PollResultType pollResult = select(timeoutSecs, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (onPollCallback) onPollCallback(pollResult);
 | 
					        if (onPollCallback) onPollCallback(pollResult);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PollResultType Socket::select(bool readyToRead, int timeoutSecs, int timeoutMs)
 | 
					    PollResultType Socket::select(int timeoutSecs, int timeoutMs)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        fd_set rfds;
 | 
					        fd_set rfds;
 | 
				
			||||||
        fd_set wfds;
 | 
					 | 
				
			||||||
        FD_ZERO(&rfds);
 | 
					        FD_ZERO(&rfds);
 | 
				
			||||||
        FD_ZERO(&wfds);
 | 
					        FD_SET(_sockfd, &rfds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fd_set* fds = (readyToRead) ? &rfds : & wfds;
 | 
					        // File descriptor at index 0 in _fildes is the read end of the pipe
 | 
				
			||||||
 | 
					        int eventfd = _eventfd.getFd();
 | 
				
			||||||
        FD_SET(_sockfd, fds);
 | 
					        if (eventfd != -1)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // File descriptor used to interrupt select when needed
 | 
					 | 
				
			||||||
        int interruptFd = _selectInterrupt->getFd();
 | 
					 | 
				
			||||||
        if (interruptFd != -1)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            FD_SET(interruptFd, fds);
 | 
					            FD_SET(eventfd, &rfds);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct timeval timeout;
 | 
					        struct timeval timeout;
 | 
				
			||||||
@@ -78,9 +70,9 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Compute the highest fd.
 | 
					        // Compute the highest fd.
 | 
				
			||||||
        int sockfd = _sockfd;
 | 
					        int sockfd = _sockfd;
 | 
				
			||||||
        int nfds = (std::max)(sockfd, interruptFd);
 | 
					        int nfds = (std::max)(sockfd, eventfd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int ret = ::select(nfds + 1, &rfds, &wfds, nullptr,
 | 
					        int ret = ::select(nfds + 1, &rfds, nullptr, nullptr,
 | 
				
			||||||
                           (timeoutSecs < 0) ? nullptr : &timeout);
 | 
					                           (timeoutSecs < 0) ? nullptr : &timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PollResultType pollResult = PollResultType_ReadyForRead;
 | 
					        PollResultType pollResult = PollResultType_ReadyForRead;
 | 
				
			||||||
@@ -92,9 +84,9 @@ namespace ix
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            pollResult = PollResultType_Timeout;
 | 
					            pollResult = PollResultType_Timeout;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (interruptFd != -1 && FD_ISSET(interruptFd, fds))
 | 
					        else if (eventfd != -1 && FD_ISSET(eventfd, &rfds))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            uint64_t value = _selectInterrupt->read();
 | 
					            uint8_t value = _eventfd.read();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (value == kSendRequest)
 | 
					            if (value == kSendRequest)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -105,38 +97,14 @@ namespace ix
 | 
				
			|||||||
                pollResult = PollResultType_CloseRequest;
 | 
					                pollResult = PollResultType_CloseRequest;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if (sockfd != -1 && FD_ISSET(sockfd, fds))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (readyToRead)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                pollResult = PollResultType_ReadyForRead;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                pollResult = PollResultType_ReadyForWrite;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return pollResult;
 | 
					        return pollResult;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PollResultType Socket::isReadyToRead(int timeoutSecs, int timeoutMs)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bool readyToRead = true;
 | 
					 | 
				
			||||||
        return select(readyToRead, timeoutSecs, timeoutMs);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PollResultType Socket::isReadyToWrite(int timeoutSecs, int timeoutMs)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bool readyToRead = false;
 | 
					 | 
				
			||||||
        return select(readyToRead, timeoutSecs, timeoutMs);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Wake up from poll/select by writing to the pipe which is watched by select
 | 
					    // Wake up from poll/select by writing to the pipe which is watched by select
 | 
				
			||||||
    bool Socket::wakeUpFromPoll(uint8_t wakeUpCode)
 | 
					    bool Socket::wakeUpFromPoll(uint8_t wakeUpCode)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return _selectInterrupt->notify(wakeUpCode);
 | 
					        return _eventfd.notify(wakeUpCode);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Socket::connect(const std::string& host,
 | 
					    bool Socket::connect(const std::string& host,
 | 
				
			||||||
@@ -146,7 +114,7 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
					        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!_selectInterrupt->clear()) return false;
 | 
					        if (!_eventfd.clear()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
 | 
					        _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
 | 
				
			||||||
        return _sockfd != -1;
 | 
					        return _sockfd != -1;
 | 
				
			||||||
@@ -205,9 +173,24 @@ namespace ix
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Socket::init(std::string& errorMsg)
 | 
					    bool Socket::init()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return _selectInterrupt->init(errorMsg);
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					        INT rc;
 | 
				
			||||||
 | 
					        WSADATA wsaData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
 | 
				
			||||||
 | 
					        return rc != 0;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Socket::cleanup()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					        WSACleanup();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool Socket::writeBytes(const std::string& str,
 | 
					    bool Socket::writeBytes(const std::string& str,
 | 
				
			||||||
@@ -260,9 +243,10 @@ namespace ix
 | 
				
			|||||||
            else if (ret < 0 && (getErrno() == EWOULDBLOCK ||
 | 
					            else if (ret < 0 && (getErrno() == EWOULDBLOCK ||
 | 
				
			||||||
                                 getErrno() == EAGAIN))
 | 
					                                 getErrno() == EAGAIN))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // Wait with a 1ms timeout until the socket is ready to read.
 | 
					                // Wait with a timeout until something is ready to read.
 | 
				
			||||||
                // This way we are not busy looping
 | 
					                // This way we are not busy looping
 | 
				
			||||||
                if (isReadyToRead(0, 1) == PollResultType_Error)
 | 
					                int res = select(0, 1);
 | 
				
			||||||
 | 
					                if (res < 0 && (errno == EBADF || errno == EINVAL))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return false;
 | 
					                    return false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -329,12 +313,9 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (onProgressCallback) onProgressCallback((int) output.size(), (int) length);
 | 
					            if (onProgressCallback) onProgressCallback((int) output.size(), (int) length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Wait with a 1ms timeout until the socket is ready to read.
 | 
					            // Wait with a timeout until something is ready to read.
 | 
				
			||||||
            // This way we are not busy looping
 | 
					            // This way we are not busy looping
 | 
				
			||||||
            if (isReadyToRead(0, 1) == PollResultType_Error)
 | 
					            select(0, 1);
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return std::make_pair(false, std::string());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return std::make_pair(true, std::string(output.begin(),
 | 
					        return std::make_pair(true, std::string(output.begin(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@
 | 
				
			|||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#include <BaseTsd.h>
 | 
					#include <BaseTsd.h>
 | 
				
			||||||
@@ -20,19 +19,17 @@ typedef SSIZE_T ssize_t;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
#include "IXProgressCallback.h"
 | 
					#include "IXProgressCallback.h"
 | 
				
			||||||
 | 
					#include "IXEventFd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class SelectInterrupt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    enum PollResultType
 | 
					    enum PollResultType
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        PollResultType_ReadyForRead = 0,
 | 
					        PollResultType_ReadyForRead = 0,
 | 
				
			||||||
        PollResultType_ReadyForWrite = 1,
 | 
					        PollResultType_Timeout = 1,
 | 
				
			||||||
        PollResultType_Timeout = 2,
 | 
					        PollResultType_Error = 2,
 | 
				
			||||||
        PollResultType_Error = 3,
 | 
					        PollResultType_SendRequest = 3,
 | 
				
			||||||
        PollResultType_SendRequest = 4,
 | 
					        PollResultType_CloseRequest = 4
 | 
				
			||||||
        PollResultType_CloseRequest = 5
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Socket {
 | 
					    class Socket {
 | 
				
			||||||
@@ -41,18 +38,13 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Socket(int fd = -1);
 | 
					        Socket(int fd = -1);
 | 
				
			||||||
        virtual ~Socket();
 | 
					        virtual ~Socket();
 | 
				
			||||||
        bool init(std::string& errorMsg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void configure();
 | 
					        void configure();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Functions to check whether there is activity on the socket
 | 
					        PollResultType select(int timeoutSecs, int timeoutMs);
 | 
				
			||||||
        void poll(const OnPollCallback& onPollCallback,
 | 
					        virtual void poll(const OnPollCallback& onPollCallback,
 | 
				
			||||||
                  int timeoutSecs = kDefaultPollTimeout);
 | 
					                          int timeoutSecs = kDefaultPollTimeout);
 | 
				
			||||||
        bool wakeUpFromPoll(uint8_t wakeUpCode);
 | 
					        virtual bool wakeUpFromPoll(uint8_t wakeUpCode);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        PollResultType select(bool readyToRead, int timeoutSecs, int timeoutMs);
 | 
					 | 
				
			||||||
        PollResultType isReadyToWrite(int timeoutSecs, int timeoutMs);
 | 
					 | 
				
			||||||
        PollResultType isReadyToRead(int timeoutSecs, int timeoutMs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Virtual methods
 | 
					        // Virtual methods
 | 
				
			||||||
        virtual bool connect(const std::string& url,
 | 
					        virtual bool connect(const std::string& url,
 | 
				
			||||||
@@ -80,10 +72,12 @@ namespace ix
 | 
				
			|||||||
            const CancellationRequest& isCancellationRequested);
 | 
					            const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static int getErrno();
 | 
					        static int getErrno();
 | 
				
			||||||
 | 
					        static bool init(); // Required on Windows to initialize WinSocket
 | 
				
			||||||
 | 
					        static void cleanup(); // Required on Windows to cleanup WinSocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Used as special codes for pipe communication
 | 
					        // Used as special codes for pipe communication
 | 
				
			||||||
        static const uint64_t kSendRequest;
 | 
					        static const uint8_t kSendRequest;
 | 
				
			||||||
        static const uint64_t kCloseRequest;
 | 
					        static const uint8_t kCloseRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected:
 | 
					    protected:
 | 
				
			||||||
        void closeSocket(int fd);
 | 
					        void closeSocket(int fd);
 | 
				
			||||||
@@ -99,6 +93,6 @@ namespace ix
 | 
				
			|||||||
        std::vector<uint8_t> _readBuffer;
 | 
					        std::vector<uint8_t> _readBuffer;
 | 
				
			||||||
        static constexpr size_t kChunkSize = 1 << 15;
 | 
					        static constexpr size_t kChunkSize = 1 << 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::shared_ptr<SelectInterrupt> _selectInterrupt;
 | 
					        EventFd _eventfd;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,45 +20,23 @@ namespace ix
 | 
				
			|||||||
                                         std::string& errorMsg)
 | 
					                                         std::string& errorMsg)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        errorMsg.clear();
 | 
					        errorMsg.clear();
 | 
				
			||||||
        std::shared_ptr<Socket> socket;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!tls)
 | 
					        if (!tls)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            socket = std::make_shared<Socket>();
 | 
					            return std::make_shared<Socket>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_TLS
 | 
					#ifdef IXWEBSOCKET_USE_TLS
 | 
				
			||||||
# ifdef __APPLE__
 | 
					# ifdef __APPLE__
 | 
				
			||||||
            socket = std::make_shared<SocketAppleSSL>();
 | 
					            return std::make_shared<SocketAppleSSL>();
 | 
				
			||||||
# else
 | 
					# else
 | 
				
			||||||
            socket = std::make_shared<SocketOpenSSL>();
 | 
					            return std::make_shared<SocketOpenSSL>();
 | 
				
			||||||
# endif
 | 
					# endif
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
            errorMsg = "TLS support is not enabled on this platform.";
 | 
					            errorMsg = "TLS support is not enabled on this platform.";
 | 
				
			||||||
            return nullptr;
 | 
					            return nullptr;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!socket->init(errorMsg))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            socket.reset();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return socket;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<Socket> createSocket(int fd,
 | 
					 | 
				
			||||||
                                         std::string& errorMsg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        errorMsg.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> socket = std::make_shared<Socket>(fd);
 | 
					 | 
				
			||||||
        if (!socket->init(errorMsg))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            socket.reset();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return socket;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,4 @@ namespace ix
 | 
				
			|||||||
    class Socket;
 | 
					    class Socket;
 | 
				
			||||||
    std::shared_ptr<Socket> createSocket(bool tls,
 | 
					    std::shared_ptr<Socket> createSocket(bool tls,
 | 
				
			||||||
                                         std::string& errorMsg);
 | 
					                                         std::string& errorMsg);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::shared_ptr<Socket> createSocket(int fd,
 | 
					 | 
				
			||||||
                                         std::string& errorMsg);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,18 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * The MIT License (MIT)
 | 
					 * The MIT License (MIT)
 | 
				
			||||||
 *
 | 
					 * 
 | 
				
			||||||
 * Copyright (c) 2012, 2013 <dhbaird@gmail.com>
 | 
					 * Copyright (c) 2012, 2013 <dhbaird@gmail.com>
 | 
				
			||||||
 *
 | 
					 * 
 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
					 * of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 * in the Software without restriction, including without limitation the rights
 | 
					 * in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
					 * copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 * furnished to do so, subject to the following conditions:
 | 
					 * furnished to do so, subject to the following conditions:
 | 
				
			||||||
 *
 | 
					 * 
 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in
 | 
					 * The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 * all copies or substantial portions of the Software.
 | 
					 * all copies or substantial portions of the Software.
 | 
				
			||||||
 *
 | 
					 * 
 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
@@ -123,13 +123,8 @@ namespace ix
 | 
				
			|||||||
    // Server
 | 
					    // Server
 | 
				
			||||||
    WebSocketInitResult WebSocketTransport::connectToSocket(int fd, int timeoutSecs)
 | 
					    WebSocketInitResult WebSocketTransport::connectToSocket(int fd, int timeoutSecs)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string errorMsg;
 | 
					        _socket.reset();
 | 
				
			||||||
        _socket = createSocket(fd, errorMsg);
 | 
					        _socket = std::make_shared<Socket>(fd);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!_socket)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return WebSocketInitResult(false, 0, errorMsg);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketHandshake webSocketHandshake(_requestInitCancellation,
 | 
					        WebSocketHandshake webSocketHandshake(_requestInitCancellation,
 | 
				
			||||||
                                              _socket,
 | 
					                                              _socket,
 | 
				
			||||||
@@ -202,19 +197,13 @@ namespace ix
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    while (!isSendBufferEmpty() && !_requestInitCancellation)
 | 
					                    while (!isSendBufferEmpty() && !_requestInitCancellation)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        // Wait with a 10ms timeout until the socket is ready to write.
 | 
					                        sendOnSocket();
 | 
				
			||||||
                        // This way we are not busy looping
 | 
					
 | 
				
			||||||
                        PollResultType result = _socket->isReadyToWrite(0, 10);
 | 
					                        // Sleep 10ms between each send so that we dont busy loop
 | 
				
			||||||
                        if (result == PollResultType_Error)
 | 
					                        // A better strategy would be to select on the socket to 
 | 
				
			||||||
                        {
 | 
					                        // check whether we can write to it without blocking
 | 
				
			||||||
                            _socket->close();
 | 
					                        std::chrono::duration<double, std::micro> duration(10);
 | 
				
			||||||
                            setReadyState(CLOSED);
 | 
					                        std::this_thread::sleep_for(duration);
 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else if (result == PollResultType_ReadyForWrite)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            sendOnSocket();
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (pollResult == PollResultType_ReadyForRead)
 | 
					                else if (pollResult == PollResultType_ReadyForRead)
 | 
				
			||||||
@@ -249,15 +238,9 @@ namespace ix
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (pollResult == PollResultType_CloseRequest)
 | 
					                else if (pollResult == PollResultType_CloseRequest)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _socket->close();
 | 
					                    ;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Avoid a race condition where we get stuck in select
 | 
					 | 
				
			||||||
                // while closing.
 | 
					 | 
				
			||||||
                if (_readyState == CLOSING)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    _socket->close();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            _heartBeatPeriod);
 | 
					            _heartBeatPeriod);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -783,7 +766,6 @@ namespace ix
 | 
				
			|||||||
        _socket->close();
 | 
					        _socket->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _closeCode = 1000;
 | 
					        _closeCode = 1000;
 | 
				
			||||||
        _closeReason = "Normal Closure";
 | 
					 | 
				
			||||||
        setReadyState(CLOSED);
 | 
					        setReadyState(CLOSED);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								makefile
									
									
									
									
									
								
							@@ -3,8 +3,6 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
all: brew
 | 
					all: brew
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: brew
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
brew:
 | 
					brew:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake .. ; make -j install)
 | 
						mkdir -p build && (cd build ; cmake .. ; make -j install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +36,7 @@ test_server:
 | 
				
			|||||||
test:
 | 
					test:
 | 
				
			||||||
	python test/run.py
 | 
						python test/run.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_test: all
 | 
					ws_test:
 | 
				
			||||||
	(cd ws ; sh test_ws.sh)
 | 
						(cd ws ; sh test_ws.sh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# For the fork that is configured with appveyor
 | 
					# For the fork that is configured with appveyor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,17 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <ixwebsocket/IXSocketFactory.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocket.h>
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXCancellationRequest.h>
 | 
					#include <ixwebsocket/IXCancellationRequest.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__APPLE__) or defined(__linux__)
 | 
				
			||||||
 | 
					# ifdef __APPLE__
 | 
				
			||||||
 | 
					#  include <ixwebsocket/IXSocketAppleSSL.h>
 | 
				
			||||||
 | 
					# else
 | 
				
			||||||
 | 
					#  include <ixwebsocket/IXSocketOpenSSL.h>
 | 
				
			||||||
 | 
					# endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXTest.h"
 | 
					#include "IXTest.h"
 | 
				
			||||||
#include "catch.hpp"
 | 
					#include "catch.hpp"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
@@ -33,15 +40,16 @@ namespace ix
 | 
				
			|||||||
        Logger() << "errMsg: " << errMsg;
 | 
					        Logger() << "errMsg: " << errMsg;
 | 
				
			||||||
        REQUIRE(success);
 | 
					        REQUIRE(success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger() << "Sending request: " << request
 | 
					        std::cout << "Sending request: " << request
 | 
				
			||||||
                 << "to " << host << ":" << port;
 | 
					                  << "to " << host << ":" << port
 | 
				
			||||||
 | 
					                  << std::endl;
 | 
				
			||||||
        REQUIRE(socket->writeBytes(request, isCancellationRequested));
 | 
					        REQUIRE(socket->writeBytes(request, isCancellationRequested));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto lineResult = socket->readLine(isCancellationRequested);
 | 
					        auto lineResult = socket->readLine(isCancellationRequested);
 | 
				
			||||||
        auto lineValid = lineResult.first;
 | 
					        auto lineValid = lineResult.first;
 | 
				
			||||||
        auto line = lineResult.second;
 | 
					        auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger() << "read error: " << strerror(Socket::getErrno());
 | 
					        std::cout << "read error: " << strerror(Socket::getErrno()) << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        REQUIRE(lineValid);
 | 
					        REQUIRE(lineValid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,9 +63,7 @@ TEST_CASE("socket", "[socket]")
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    SECTION("Connect to google HTTP server. Send GET request without header. Should return 200")
 | 
					    SECTION("Connect to google HTTP server. Send GET request without header. Should return 200")
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::shared_ptr<Socket> socket(new Socket);
 | 
				
			||||||
        bool tls = false;
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
 | 
					 | 
				
			||||||
        std::string host("www.google.com");
 | 
					        std::string host("www.google.com");
 | 
				
			||||||
        int port = 80;
 | 
					        int port = 80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,9 +82,11 @@ TEST_CASE("socket", "[socket]")
 | 
				
			|||||||
#if defined(__APPLE__) or defined(__linux__)
 | 
					#if defined(__APPLE__) or defined(__linux__)
 | 
				
			||||||
    SECTION("Connect to google HTTPS server. Send GET request without header. Should return 200")
 | 
					    SECTION("Connect to google HTTPS server. Send GET request without header. Should return 200")
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string errMsg;
 | 
					# ifdef __APPLE__
 | 
				
			||||||
        bool tls = true;
 | 
					        std::shared_ptr<Socket> socket = std::make_shared<SocketAppleSSL>();
 | 
				
			||||||
        std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
 | 
					# else
 | 
				
			||||||
 | 
					        std::shared_ptr<Socket> socket = std::make_shared<SocketOpenSSL>();
 | 
				
			||||||
 | 
					# endif
 | 
				
			||||||
        std::string host("www.google.com");
 | 
					        std::string host("www.google.com");
 | 
				
			||||||
        int port = 443;
 | 
					        int port = 443;
 | 
				
			||||||
        std::string request("GET / HTTP/1.1\r\n\r\n");
 | 
					        std::string request("GET / HTTP/1.1\r\n\r\n");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@
 | 
				
			|||||||
#include <ixwebsocket/IXSocket.h>
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketServer.h>
 | 
					#include <ixwebsocket/IXWebSocketServer.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketFactory.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXTest.h"
 | 
					#include "IXTest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,18 +79,17 @@ TEST_CASE("Websocket_server", "[websocket_server]")
 | 
				
			|||||||
        ix::WebSocketServer server(port);
 | 
					        ix::WebSocketServer server(port);
 | 
				
			||||||
        REQUIRE(startServer(server));
 | 
					        REQUIRE(startServer(server));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        Socket socket;
 | 
				
			||||||
        bool tls = false;
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
 | 
					 | 
				
			||||||
        std::string host("localhost");
 | 
					        std::string host("localhost");
 | 
				
			||||||
 | 
					        std::string errMsg;
 | 
				
			||||||
        auto isCancellationRequested = []() -> bool
 | 
					        auto isCancellationRequested = []() -> bool
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        bool success = socket->connect(host, port, errMsg, isCancellationRequested);
 | 
					        bool success = socket.connect(host, port, errMsg, isCancellationRequested);
 | 
				
			||||||
        REQUIRE(success);
 | 
					        REQUIRE(success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto lineResult = socket->readLine(isCancellationRequested);
 | 
					        auto lineResult = socket.readLine(isCancellationRequested);
 | 
				
			||||||
        auto lineValid = lineResult.first;
 | 
					        auto lineValid = lineResult.first;
 | 
				
			||||||
        auto line = lineResult.second;
 | 
					        auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,21 +111,20 @@ TEST_CASE("Websocket_server", "[websocket_server]")
 | 
				
			|||||||
        ix::WebSocketServer server(port);
 | 
					        ix::WebSocketServer server(port);
 | 
				
			||||||
        REQUIRE(startServer(server));
 | 
					        REQUIRE(startServer(server));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        Socket socket;
 | 
				
			||||||
        bool tls = false;
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
 | 
					 | 
				
			||||||
        std::string host("localhost");
 | 
					        std::string host("localhost");
 | 
				
			||||||
 | 
					        std::string errMsg;
 | 
				
			||||||
        auto isCancellationRequested = []() -> bool
 | 
					        auto isCancellationRequested = []() -> bool
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        bool success = socket->connect(host, port, errMsg, isCancellationRequested);
 | 
					        bool success = socket.connect(host, port, errMsg, isCancellationRequested);
 | 
				
			||||||
        REQUIRE(success);
 | 
					        REQUIRE(success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger() << "writeBytes";
 | 
					        Logger() << "writeBytes";
 | 
				
			||||||
        socket->writeBytes("GET /\r\n", isCancellationRequested);
 | 
					        socket.writeBytes("GET /\r\n", isCancellationRequested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto lineResult = socket->readLine(isCancellationRequested);
 | 
					        auto lineResult = socket.readLine(isCancellationRequested);
 | 
				
			||||||
        auto lineValid = lineResult.first;
 | 
					        auto lineValid = lineResult.first;
 | 
				
			||||||
        auto line = lineResult.second;
 | 
					        auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,25 +146,24 @@ TEST_CASE("Websocket_server", "[websocket_server]")
 | 
				
			|||||||
        ix::WebSocketServer server(port);
 | 
					        ix::WebSocketServer server(port);
 | 
				
			||||||
        REQUIRE(startServer(server));
 | 
					        REQUIRE(startServer(server));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        Socket socket;
 | 
				
			||||||
        bool tls = false;
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
 | 
					 | 
				
			||||||
        std::string host("localhost");
 | 
					        std::string host("localhost");
 | 
				
			||||||
 | 
					        std::string errMsg;
 | 
				
			||||||
        auto isCancellationRequested = []() -> bool
 | 
					        auto isCancellationRequested = []() -> bool
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        bool success = socket->connect(host, port, errMsg, isCancellationRequested);
 | 
					        bool success = socket.connect(host, port, errMsg, isCancellationRequested);
 | 
				
			||||||
        REQUIRE(success);
 | 
					        REQUIRE(success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        socket->writeBytes("GET / HTTP/1.1\r\n"
 | 
					        socket.writeBytes("GET / HTTP/1.1\r\n"
 | 
				
			||||||
                           "Upgrade: websocket\r\n"
 | 
					                          "Upgrade: websocket\r\n"
 | 
				
			||||||
                           "Sec-WebSocket-Version: 13\r\n"
 | 
					                          "Sec-WebSocket-Version: 13\r\n"
 | 
				
			||||||
                           "Sec-WebSocket-Key: foobar\r\n"
 | 
					                          "Sec-WebSocket-Key: foobar\r\n"
 | 
				
			||||||
                           "\r\n",
 | 
					                          "\r\n",
 | 
				
			||||||
                           isCancellationRequested);
 | 
					                          isCancellationRequested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto lineResult = socket->readLine(isCancellationRequested);
 | 
					        auto lineResult = socket.readLine(isCancellationRequested);
 | 
				
			||||||
        auto lineValid = lineResult.first;
 | 
					        auto lineValid = lineResult.first;
 | 
				
			||||||
        auto line = lineResult.second;
 | 
					        auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								test/run.py
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								test/run.py
									
									
									
									
									
								
							@@ -2,39 +2,6 @@ import os
 | 
				
			|||||||
import platform
 | 
					import platform
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import threading
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Command(object):
 | 
					 | 
				
			||||||
    """Run system commands with timeout
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    From http://www.bo-yang.net/2016/12/01/python-run-command-with-timeout
 | 
					 | 
				
			||||||
    Python3 might have a builtin way to do that.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    def __init__(self, cmd):
 | 
					 | 
				
			||||||
        self.cmd = cmd
 | 
					 | 
				
			||||||
        self.process = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def run_command(self, capture = False):
 | 
					 | 
				
			||||||
        self.process = subprocess.Popen(self.cmd, shell=True)
 | 
					 | 
				
			||||||
        self.process.communicate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def run(self, timeout = 5 * 60):
 | 
					 | 
				
			||||||
        '''5 minutes default timeout'''
 | 
					 | 
				
			||||||
        thread = threading.Thread(target=self.run_command, args=())
 | 
					 | 
				
			||||||
        thread.start()
 | 
					 | 
				
			||||||
        thread.join(timeout)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if thread.is_alive():
 | 
					 | 
				
			||||||
            print 'Command timeout, kill it: ' + self.cmd
 | 
					 | 
				
			||||||
            self.process.terminate()
 | 
					 | 
				
			||||||
            thread.join()
 | 
					 | 
				
			||||||
            return False, 255
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return True, self.process.returncode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
osName = platform.system()
 | 
					osName = platform.system()
 | 
				
			||||||
print('os name = {}'.format(osName))
 | 
					print('os name = {}'.format(osName))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,9 +78,8 @@ shutil.copy(os.path.join(
 | 
				
			|||||||
    'bin',
 | 
					    'bin',
 | 
				
			||||||
    'zlib.dll'), '.')
 | 
					    'zlib.dll'), '.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# lldb = "lldb --batch -o 'run' -k 'thread backtrace all' -k 'quit 1'"
 | 
					lldb = "lldb --batch -o 'run' -k 'thread backtrace all' -k 'quit 1'"
 | 
				
			||||||
lldb = ""  # Disabled for now
 | 
					lldb = ""  # Disabled for now
 | 
				
			||||||
testCommand = '{} {} {}'.format(lldb, testBinary, os.getenv('TEST', ''))
 | 
					testCommand = '{} {} {}'.format(lldb, testBinary, os.getenv('TEST', ''))
 | 
				
			||||||
command = Command(testCommand)
 | 
					ret = os.system(testCommand)
 | 
				
			||||||
timedout, ret = command.run()
 | 
					 | 
				
			||||||
assert ret == 0, 'Test command failed'
 | 
					assert ret == 0, 'Test command failed'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int main(int argc, char* argv[])
 | 
					int main(int argc, char* argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    ix::Socket::init(); // for Windows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int result = Catch::Session().run(argc, argv);
 | 
					    int result = Catch::Session().run(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ix::Socket::cleanup(); // for Windows
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,19 +21,20 @@ done
 | 
				
			|||||||
# Start a receiver
 | 
					# Start a receiver
 | 
				
			||||||
mkdir -p /tmp/ws_test/receive
 | 
					mkdir -p /tmp/ws_test/receive
 | 
				
			||||||
cd /tmp/ws_test/receive
 | 
					cd /tmp/ws_test/receive
 | 
				
			||||||
ws receive --delay 5 ws://127.0.0.1:8090 &
 | 
					ws receive ws://127.0.0.1:8090 &
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir /tmp/ws_test/send
 | 
					mkdir /tmp/ws_test/send
 | 
				
			||||||
cd /tmp/ws_test/send
 | 
					cd /tmp/ws_test/send
 | 
				
			||||||
dd if=/dev/urandom of=20M_file count=20000 bs=1024
 | 
					# mkfile 10m 10M_file
 | 
				
			||||||
 | 
					dd if=/dev/urandom of=10M_file count=10000 bs=1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Start the sender job
 | 
					# Start the sender job
 | 
				
			||||||
ws send ws://127.0.0.1:8090 20M_file
 | 
					ws send ws://127.0.0.1:8090 10M_file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Wait until the file has been written to disk
 | 
					# Wait until the file has been written to disk
 | 
				
			||||||
while true
 | 
					while true
 | 
				
			||||||
do
 | 
					do
 | 
				
			||||||
    if test -f /tmp/ws_test/receive/20M_file ; then
 | 
					    if test -f /tmp/ws_test/receive/10M_file ; then
 | 
				
			||||||
        echo "Received file does exists, exiting loop"
 | 
					        echo "Received file does exists, exiting loop"
 | 
				
			||||||
        break
 | 
					        break
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
@@ -41,8 +42,8 @@ do
 | 
				
			|||||||
    sleep 0.1
 | 
					    sleep 0.1
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cksum /tmp/ws_test/send/20M_file
 | 
					cksum /tmp/ws_test/send/10M_file
 | 
				
			||||||
cksum /tmp/ws_test/receive/20M_file
 | 
					cksum /tmp/ws_test/receive/10M_file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Give some time to ws receive to terminate
 | 
					# Give some time to ws receive to terminate
 | 
				
			||||||
sleep 2
 | 
					sleep 2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -44,17 +44,13 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    int connectTimeOut = 60;
 | 
					    int connectTimeOut = 60;
 | 
				
			||||||
    int transferTimeout = 1800;
 | 
					    int transferTimeout = 1800;
 | 
				
			||||||
    int maxRedirects = 5;
 | 
					    int maxRedirects = 5;
 | 
				
			||||||
    int delayMs = -1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CLI::App* sendApp = app.add_subcommand("send", "Send a file");
 | 
					    CLI::App* sendApp = app.add_subcommand("send", "Send a file");
 | 
				
			||||||
    sendApp->add_option("url", url, "Connection url")->required();
 | 
					    sendApp->add_option("url", url, "Connection url")->required();
 | 
				
			||||||
    sendApp->add_option("path", path, "Path to the file to send")
 | 
					    sendApp->add_option("path", path, "Path to the file to send")
 | 
				
			||||||
        ->required()->check(CLI::ExistingPath);
 | 
					        ->required()->check(CLI::ExistingPath);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    CLI::App* receiveApp = app.add_subcommand("receive", "Receive a file");
 | 
					    CLI::App* receiveApp = app.add_subcommand("receive", "Receive a file");
 | 
				
			||||||
    receiveApp->add_option("url", url, "Connection url")->required();
 | 
					    receiveApp->add_option("url", url, "Connection url")->required();
 | 
				
			||||||
    receiveApp->add_option("--delay", delayMs, "Delay (ms) to wait after receiving a fragment"
 | 
					 | 
				
			||||||
                                               " to artificially slow down the receiver");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server");
 | 
					    CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server");
 | 
				
			||||||
    transferApp->add_option("--port", port, "Connection url");
 | 
					    transferApp->add_option("--port", port, "Connection url");
 | 
				
			||||||
@@ -96,9 +92,12 @@ int main(int argc, char** argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    CLI11_PARSE(app, argc, argv);
 | 
					    CLI11_PARSE(app, argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ix::Socket::init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pid file handling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (app.got_subcommand("transfer"))
 | 
					    if (app.got_subcommand("transfer"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // pid file handling
 | 
					 | 
				
			||||||
        if (!pidfile.empty())
 | 
					        if (!pidfile.empty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unlink(pidfile.c_str());
 | 
					            unlink(pidfile.c_str());
 | 
				
			||||||
@@ -118,7 +117,7 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    else if (app.got_subcommand("receive"))
 | 
					    else if (app.got_subcommand("receive"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bool enablePerMessageDeflate = false;
 | 
					        bool enablePerMessageDeflate = false;
 | 
				
			||||||
        return ix::ws_receive_main(url, enablePerMessageDeflate, delayMs);
 | 
					        return ix::ws_receive_main(url, enablePerMessageDeflate);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (app.got_subcommand("connect"))
 | 
					    else if (app.got_subcommand("connect"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								ws/ws.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								ws/ws.h
									
									
									
									
									
								
							@@ -34,8 +34,7 @@ namespace ix
 | 
				
			|||||||
    int ws_connect_main(const std::string& url);
 | 
					    int ws_connect_main(const std::string& url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ws_receive_main(const std::string& url,
 | 
					    int ws_receive_main(const std::string& url,
 | 
				
			||||||
                        bool enablePerMessageDeflate,
 | 
					                        bool enablePerMessageDeflate);
 | 
				
			||||||
                        int delayMs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ws_send_main(const std::string& url,
 | 
					    int ws_send_main(const std::string& url,
 | 
				
			||||||
                     const std::string& path);
 | 
					                     const std::string& path);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,6 +153,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    int ws_connect_main(const std::string& url)
 | 
					    int ws_connect_main(const std::string& url)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        Socket::init();
 | 
				
			||||||
        interactiveMain(url);
 | 
					        interactiveMain(url);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,8 +26,7 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public:
 | 
					        public:
 | 
				
			||||||
            WebSocketReceiver(const std::string& _url,
 | 
					            WebSocketReceiver(const std::string& _url,
 | 
				
			||||||
                              bool enablePerMessageDeflate,
 | 
					                              bool enablePerMessageDeflate);
 | 
				
			||||||
                              int delayMs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void subscribe(const std::string& channel);
 | 
					            void subscribe(const std::string& channel);
 | 
				
			||||||
            void start();
 | 
					            void start();
 | 
				
			||||||
@@ -42,8 +41,6 @@ namespace ix
 | 
				
			|||||||
            std::string _id;
 | 
					            std::string _id;
 | 
				
			||||||
            ix::WebSocket _webSocket;
 | 
					            ix::WebSocket _webSocket;
 | 
				
			||||||
            bool _enablePerMessageDeflate;
 | 
					            bool _enablePerMessageDeflate;
 | 
				
			||||||
            int _delayMs;
 | 
					 | 
				
			||||||
            int _receivedFragmentCounter;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::mutex _conditionVariableMutex;
 | 
					            std::mutex _conditionVariableMutex;
 | 
				
			||||||
            std::condition_variable _condition;
 | 
					            std::condition_variable _condition;
 | 
				
			||||||
@@ -54,12 +51,9 @@ namespace ix
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketReceiver::WebSocketReceiver(const std::string& url,
 | 
					    WebSocketReceiver::WebSocketReceiver(const std::string& url,
 | 
				
			||||||
                                         bool enablePerMessageDeflate,
 | 
					                                         bool enablePerMessageDeflate) :
 | 
				
			||||||
                                         int delayMs) :
 | 
					 | 
				
			||||||
        _url(url),
 | 
					        _url(url),
 | 
				
			||||||
        _enablePerMessageDeflate(enablePerMessageDeflate),
 | 
					        _enablePerMessageDeflate(enablePerMessageDeflate)
 | 
				
			||||||
        _delayMs(delayMs),
 | 
					 | 
				
			||||||
        _receivedFragmentCounter(0)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ;
 | 
					        ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -219,15 +213,8 @@ namespace ix
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (messageType == ix::WebSocket_MessageType_Fragment)
 | 
					                else if (messageType == ix::WebSocket_MessageType_Fragment)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ss << "ws_receive: received fragment " << _receivedFragmentCounter++;
 | 
					                    ss << "ws_receive: received fragment";
 | 
				
			||||||
                    log(ss.str());
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (_delayMs > 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        // Introduce an arbitrary delay, to simulate a slow connection
 | 
					 | 
				
			||||||
                        std::chrono::duration<double, std::milli> duration(_delayMs);
 | 
					 | 
				
			||||||
                        std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (messageType == ix::WebSocket_MessageType_Error)
 | 
					                else if (messageType == ix::WebSocket_MessageType_Error)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -248,10 +235,9 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void wsReceive(const std::string& url,
 | 
					    void wsReceive(const std::string& url,
 | 
				
			||||||
                   bool enablePerMessageDeflate,
 | 
					                   bool enablePerMessageDeflate)
 | 
				
			||||||
                   int delayMs)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate, delayMs);
 | 
					        WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate);
 | 
				
			||||||
        webSocketReceiver.start();
 | 
					        webSocketReceiver.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        webSocketReceiver.waitForConnection();
 | 
					        webSocketReceiver.waitForConnection();
 | 
				
			||||||
@@ -266,10 +252,10 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ws_receive_main(const std::string& url,
 | 
					    int ws_receive_main(const std::string& url,
 | 
				
			||||||
                        bool enablePerMessageDeflate,
 | 
					                        bool enablePerMessageDeflate)
 | 
				
			||||||
                        int delayMs)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        wsReceive(url, enablePerMessageDeflate, delayMs);
 | 
					        Socket::init();
 | 
				
			||||||
 | 
					        wsReceive(url, enablePerMessageDeflate);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -246,7 +246,7 @@ namespace ix
 | 
				
			|||||||
        _webSocket.send(msg.dump(),
 | 
					        _webSocket.send(msg.dump(),
 | 
				
			||||||
                        [throttle](int current, int total) -> bool
 | 
					                        [throttle](int current, int total) -> bool
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::cout << "ws_send: Step " << current << " out of " << total << std::endl;
 | 
					            std::cout << "Step " << current << " out of " << total << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (throttle)
 | 
					            if (throttle)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -260,8 +260,7 @@ namespace ix
 | 
				
			|||||||
        do
 | 
					        do
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            size_t bufferedAmount = _webSocket.bufferedAmount();
 | 
					            size_t bufferedAmount = _webSocket.bufferedAmount();
 | 
				
			||||||
            std::cout << "ws_send: " << bufferedAmount
 | 
					            std::cout << bufferedAmount << " bytes left to be sent" << std::endl;
 | 
				
			||||||
                      << " bytes left to be sent" << std::endl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::chrono::duration<double, std::milli> duration(10);
 | 
					            std::chrono::duration<double, std::milli> duration(10);
 | 
				
			||||||
            std::this_thread::sleep_for(duration);
 | 
					            std::this_thread::sleep_for(duration);
 | 
				
			||||||
@@ -299,6 +298,7 @@ namespace ix
 | 
				
			|||||||
        bool throttle = false;
 | 
					        bool throttle = false;
 | 
				
			||||||
        bool enablePerMessageDeflate = false;
 | 
					        bool enablePerMessageDeflate = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Socket::init();
 | 
				
			||||||
        wsSend(url, path, enablePerMessageDeflate, throttle);
 | 
					        wsSend(url, path, enablePerMessageDeflate, throttle);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,8 +54,7 @@ namespace ix
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if (messageType == ix::WebSocket_MessageType_Fragment)
 | 
					                        else if (messageType == ix::WebSocket_MessageType_Fragment)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            std::cerr << "Received message fragment "
 | 
					                            std::cerr << "Received message fragment" << std::endl;
 | 
				
			||||||
                                      << std::endl;
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if (messageType == ix::WebSocket_MessageType_Message)
 | 
					                        else if (messageType == ix::WebSocket_MessageType_Message)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -67,7 +66,7 @@ namespace ix
 | 
				
			|||||||
                                    client->send(str,
 | 
					                                    client->send(str,
 | 
				
			||||||
                                                 [](int current, int total) -> bool
 | 
					                                                 [](int current, int total) -> bool
 | 
				
			||||||
                                    {
 | 
					                                    {
 | 
				
			||||||
                                        std::cerr << "ws_transfer: Step " << current
 | 
					                                        std::cerr << "Step " << current
 | 
				
			||||||
                                                  << " out of " << total << std::endl;
 | 
					                                                  << " out of " << total << std::endl;
 | 
				
			||||||
                                        return true;
 | 
					                                        return true;
 | 
				
			||||||
                                    });
 | 
					                                    });
 | 
				
			||||||
@@ -75,8 +74,7 @@ namespace ix
 | 
				
			|||||||
                                    do
 | 
					                                    do
 | 
				
			||||||
                                    {
 | 
					                                    {
 | 
				
			||||||
                                        size_t bufferedAmount = client->bufferedAmount();
 | 
					                                        size_t bufferedAmount = client->bufferedAmount();
 | 
				
			||||||
                                        std::cerr << "ws_transfer: " << bufferedAmount
 | 
					                                        std::cerr << bufferedAmount << " bytes left to be sent" << std::endl;
 | 
				
			||||||
                                                  << " bytes left to be sent" << std::endl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                        std::chrono::duration<double, std::milli> duration(10);
 | 
					                                        std::chrono::duration<double, std::milli> duration(10);
 | 
				
			||||||
                                        std::this_thread::sleep_for(duration);
 | 
					                                        std::this_thread::sleep_for(duration);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user