Compare commits
	
		
			6 Commits
		
	
	
		
			v1.0.2
			...
			user/bserg
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4373a92c61 | ||
| 
						 | 
					91e67f6e53 | ||
| 
						 | 
					1ca1f612be | ||
| 
						 | 
					1b9e55d3f8 | ||
| 
						 | 
					0d80971328 | ||
| 
						 | 
					80c1ed0611 | 
@@ -1 +0,0 @@
 | 
				
			|||||||
build
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -2,16 +2,10 @@ language: cpp
 | 
				
			|||||||
dist: xenial
 | 
					dist: xenial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
compiler:
 | 
					compiler:
 | 
				
			||||||
  - gcc
 | 
					 | 
				
			||||||
  - clang
 | 
					  - clang
 | 
				
			||||||
os:
 | 
					#   - gcc
 | 
				
			||||||
  - linux
 | 
					 | 
				
			||||||
  - osx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
matrix:
 | 
					 | 
				
			||||||
  exclude:
 | 
					 | 
				
			||||||
    # GCC fails on recent Travis OSX images.
 | 
					 | 
				
			||||||
    - compiler: gcc
 | 
					 | 
				
			||||||
      os: osx
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					os: osx
 | 
				
			||||||
 | 
					# os: windows
 | 
				
			||||||
 | 
					# script: make test
 | 
				
			||||||
script: python test/run.py
 | 
					script: python test/run.py
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,6 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/IXSetThreadName.h
 | 
					    ixwebsocket/IXSetThreadName.h
 | 
				
			||||||
    ixwebsocket/IXDNSLookup.h
 | 
					    ixwebsocket/IXDNSLookup.h
 | 
				
			||||||
    ixwebsocket/IXCancellationRequest.h
 | 
					    ixwebsocket/IXCancellationRequest.h
 | 
				
			||||||
    ixwebsocket/IXProgressCallback.h
 | 
					 | 
				
			||||||
    ixwebsocket/IXWebSocket.h
 | 
					    ixwebsocket/IXWebSocket.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketServer.h
 | 
					    ixwebsocket/IXWebSocketServer.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketTransport.h
 | 
					    ixwebsocket/IXWebSocketTransport.h
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,10 +134,6 @@ No manual polling to fetch data is required. Data is sent and received instantly
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
If the remote end (server) breaks the connection, the code will try to perpetually reconnect, by using an exponential backoff strategy, capped at one retry every 10 seconds.
 | 
					If the remote end (server) breaks the connection, the code will try to perpetually reconnect, by using an exponential backoff strategy, capped at one retry every 10 seconds.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Large messages
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Large frames are broken up into smaller chunks or messages to avoid filling up the os tcp buffers, which is permitted thanks to WebSocket [fragmentation](https://tools.ietf.org/html/rfc6455#section-5.4). Messages up to 500M were sent and received succesfully.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Limitations
 | 
					## Limitations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* There is no text support for sending data, only the binary protocol is supported. Sending json or text over the binary protocol works well.
 | 
					* There is no text support for sending data, only the binary protocol is supported. Sending json or text over the binary protocol works well.
 | 
				
			||||||
@@ -313,7 +309,6 @@ A ping message can be sent to the server, with an optional data string.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
websocket.ping("ping data, optional (empty string is ok): limited to 125 bytes long");
 | 
					websocket.ping("ping data, optional (empty string is ok): limited to 125 bytes long");
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Heartbeat.
 | 
					### Heartbeat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,8 +15,5 @@ RUN apt-get -y install cmake
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
COPY . .
 | 
					COPY . .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR ws
 | 
					WORKDIR test
 | 
				
			||||||
RUN ["sh", "docker_build.sh"]
 | 
					RUN ["sh", "build_linux.sh"]
 | 
				
			||||||
 | 
					 | 
				
			||||||
EXPOSE 8765
 | 
					 | 
				
			||||||
CMD ["/ws/ws", "transfer", "8765"]
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,6 @@ int main(int argc, char** argv)
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (messageType == ix::WebSocket_MessageType_Message)
 | 
					                    else if (messageType == ix::WebSocket_MessageType_Message)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        std::cerr << "Received " << wireSize << " bytes" << std::endl;
 | 
					 | 
				
			||||||
                        for (auto&& client : server.getClients())
 | 
					                        for (auto&& client : server.getClients())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            if (client != webSocket)
 | 
					                            if (client != webSocket)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,55 +81,4 @@ namespace ix
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    static inline bool is_base64(unsigned char c)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return (isalnum(c) || (c == '+') || (c == '/'));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string base64_decode(const std::string& encoded_string)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int in_len = (int)encoded_string.size();
 | 
					 | 
				
			||||||
        int i = 0;
 | 
					 | 
				
			||||||
        int j = 0;
 | 
					 | 
				
			||||||
        int in_ = 0;
 | 
					 | 
				
			||||||
        unsigned char char_array_4[4], char_array_3[3];
 | 
					 | 
				
			||||||
        std::string ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while(in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            char_array_4[i++] = encoded_string[in_]; in_++;
 | 
					 | 
				
			||||||
            if(i ==4)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                for(i = 0; i <4; i++)
 | 
					 | 
				
			||||||
                    char_array_4[i] = base64_chars.find(char_array_4[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
					 | 
				
			||||||
                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
					 | 
				
			||||||
                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for(i = 0; (i < 3); i++)
 | 
					 | 
				
			||||||
                    ret += char_array_3[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                i = 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for(j = i; j <4; j++)
 | 
					 | 
				
			||||||
                char_array_4[j] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for(j = 0; j <4; j++)
 | 
					 | 
				
			||||||
                char_array_4[j] = base64_chars.find(char_array_4[j]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
					 | 
				
			||||||
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
					 | 
				
			||||||
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for(j = 0; (j < i - 1); j++) ret += char_array_3[j];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -11,5 +11,4 @@
 | 
				
			|||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::string base64_encode(const std::string& data, size_t len);
 | 
					    std::string base64_encode(const std::string& data, size_t len);
 | 
				
			||||||
    std::string base64_decode(const std::string& encoded_string);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXProgressCallback.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using OnProgressCallback = std::function<bool(int current, int total)>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -15,6 +15,7 @@
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <poll.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
@@ -43,22 +44,21 @@ namespace ix
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fd_set rfds;
 | 
					 | 
				
			||||||
        FD_ZERO(&rfds);
 | 
					 | 
				
			||||||
        FD_SET(_sockfd, &rfds);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
        FD_SET(_eventfd.getFd(), &rfds);
 | 
					        constexpr int nfds = 2;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        constexpr int nfds = 1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct timeval timeout;
 | 
					        struct pollfd fds[nfds];
 | 
				
			||||||
        timeout.tv_sec = timeoutSecs;
 | 
					        fds[0].fd = _sockfd;
 | 
				
			||||||
        timeout.tv_usec = 0;
 | 
					        fds[0].events = POLLIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int sockfd = _sockfd;
 | 
					#ifdef __linux__
 | 
				
			||||||
        int nfds = (std::max)(sockfd, _eventfd.getFd());
 | 
					        fds[1].fd = _eventfd.getFd();
 | 
				
			||||||
        int ret = select(nfds + 1, &rfds, nullptr, nullptr,
 | 
					        fds[1].events = POLLIN;
 | 
				
			||||||
                         (timeoutSecs < 0) ? nullptr : &timeout);
 | 
					#endif
 | 
				
			||||||
 | 
					        int ret = ::poll(fds, nfds, timeoutSecs * 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PollResultType pollResult = PollResultType_ReadyForRead;
 | 
					        PollResultType pollResult = PollResultType_ReadyForRead;
 | 
				
			||||||
        if (ret < 0)
 | 
					        if (ret < 0)
 | 
				
			||||||
@@ -71,6 +71,7 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        onPollCallback(pollResult);
 | 
					        onPollCallback(pollResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Socket::wakeUpFromPoll()
 | 
					    void Socket::wakeUpFromPoll()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -294,10 +294,9 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocket::send(const std::string& text,
 | 
					    WebSocketSendInfo WebSocket::send(const std::string& text)
 | 
				
			||||||
                                      const OnProgressCallback& onProgressCallback)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return sendMessage(text, false, onProgressCallback);
 | 
					        return sendMessage(text, false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocket::ping(const std::string& text)
 | 
					    WebSocketSendInfo WebSocket::ping(const std::string& text)
 | 
				
			||||||
@@ -309,9 +308,7 @@ namespace ix
 | 
				
			|||||||
        return sendMessage(text, true);
 | 
					        return sendMessage(text, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocket::sendMessage(const std::string& text,
 | 
					    WebSocketSendInfo WebSocket::sendMessage(const std::string& text, bool ping)
 | 
				
			||||||
                                             bool ping,
 | 
					 | 
				
			||||||
                                             const OnProgressCallback& onProgressCallback)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!isConnected()) return WebSocketSendInfo(false);
 | 
					        if (!isConnected()) return WebSocketSendInfo(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -333,7 +330,7 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            webSocketSendInfo = _ws.sendBinary(text, onProgressCallback);
 | 
					            webSocketSendInfo = _ws.sendBinary(text);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocket::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize, false);
 | 
					        WebSocket::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize, false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,6 @@
 | 
				
			|||||||
#include "IXWebSocketSendInfo.h"
 | 
					#include "IXWebSocketSendInfo.h"
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
					#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
				
			||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include "IXProgressCallback.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -98,8 +97,7 @@ namespace ix
 | 
				
			|||||||
        WebSocketInitResult connect(int timeoutSecs);
 | 
					        WebSocketInitResult connect(int timeoutSecs);
 | 
				
			||||||
        void run();
 | 
					        void run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketSendInfo send(const std::string& text,
 | 
					        WebSocketSendInfo send(const std::string& text);
 | 
				
			||||||
                               const OnProgressCallback& onProgressCallback = nullptr);
 | 
					 | 
				
			||||||
        WebSocketSendInfo ping(const std::string& text);
 | 
					        WebSocketSendInfo ping(const std::string& text);
 | 
				
			||||||
        void close();
 | 
					        void close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,9 +115,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketSendInfo sendMessage(const std::string& text,
 | 
					        WebSocketSendInfo sendMessage(const std::string& text, bool ping);
 | 
				
			||||||
                                      bool ping,
 | 
					 | 
				
			||||||
                                      const OnProgressCallback& callback = nullptr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool isConnected() const;
 | 
					        bool isConnected() const;
 | 
				
			||||||
        bool isClosing() const;
 | 
					        bool isClosing() const;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,15 +29,12 @@
 | 
				
			|||||||
#include <cstdarg>
 | 
					#include <cstdarg>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const std::string WebSocketTransport::kHeartBeatPingMessage("ixwebsocket::hearbeat");
 | 
					    const std::string WebSocketTransport::kHeartBeatPingMessage("ixwebsocket::hearbeat");
 | 
				
			||||||
    const int WebSocketTransport::kDefaultHeartBeatPeriod(-1);
 | 
					    const int WebSocketTransport::kDefaultHeartBeatPeriod(-1);
 | 
				
			||||||
    constexpr size_t WebSocketTransport::kChunkSize;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketTransport::WebSocketTransport() :
 | 
					    WebSocketTransport::WebSocketTransport() :
 | 
				
			||||||
        _readyState(CLOSED),
 | 
					        _readyState(CLOSED),
 | 
				
			||||||
@@ -48,7 +45,7 @@ namespace ix
 | 
				
			|||||||
        _heartBeatPeriod(kDefaultHeartBeatPeriod),
 | 
					        _heartBeatPeriod(kDefaultHeartBeatPeriod),
 | 
				
			||||||
        _lastSendTimePoint(std::chrono::steady_clock::now())
 | 
					        _lastSendTimePoint(std::chrono::steady_clock::now())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _readbuf.resize(kChunkSize);
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketTransport::~WebSocketTransport()
 | 
					    WebSocketTransport::~WebSocketTransport()
 | 
				
			||||||
@@ -187,25 +184,27 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                while (true) 
 | 
					                while (true) 
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ssize_t ret = _socket->recv((char*)&_readbuf[0], _readbuf.size());
 | 
					                    int N = (int) _rxbuf.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    _rxbuf.resize(N + 1500);
 | 
				
			||||||
 | 
					                    ssize_t ret = _socket->recv((char*)&_rxbuf[0] + N, 1500);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK || 
 | 
					                    if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK || 
 | 
				
			||||||
                                    _socket->getErrno() == EAGAIN))
 | 
					                                    _socket->getErrno() == EAGAIN)) {
 | 
				
			||||||
                    {
 | 
					                        _rxbuf.resize(N);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (ret <= 0) 
 | 
					                    else if (ret <= 0) 
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _rxbuf.clear();
 | 
					                        _rxbuf.resize(N);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        _socket->close();
 | 
					                        _socket->close();
 | 
				
			||||||
                        setReadyState(CLOSED);
 | 
					                        setReadyState(CLOSED);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else 
 | 
					                    else 
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _rxbuf.insert(_rxbuf.end(),
 | 
					                        _rxbuf.resize(N + ret);
 | 
				
			||||||
                                      _readbuf.begin(),
 | 
					 | 
				
			||||||
                                      _readbuf.begin() + ret);
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -361,35 +360,17 @@ namespace ix
 | 
				
			|||||||
                || ws.opcode == wsheader_type::CONTINUATION
 | 
					                || ws.opcode == wsheader_type::CONTINUATION
 | 
				
			||||||
            ) {
 | 
					            ) {
 | 
				
			||||||
                unmaskReceiveBuffer(ws);
 | 
					                unmaskReceiveBuffer(ws);
 | 
				
			||||||
 | 
					                _receivedData.insert(_receivedData.end(),
 | 
				
			||||||
                //
 | 
					                                     _rxbuf.begin()+ws.header_size,
 | 
				
			||||||
                // Usual case. Small unfragmented messages
 | 
					                                     _rxbuf.begin()+ws.header_size+(size_t)ws.N);// just feed
 | 
				
			||||||
                //
 | 
					 | 
				
			||||||
                if (ws.fin && _chunks.empty())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    emitMessage(MSG,
 | 
					 | 
				
			||||||
                                std::string(_rxbuf.begin()+ws.header_size,
 | 
					 | 
				
			||||||
                                            _rxbuf.begin()+ws.header_size+(size_t) ws.N),
 | 
					 | 
				
			||||||
                                ws,
 | 
					 | 
				
			||||||
                                onMessageCallback);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    //
 | 
					 | 
				
			||||||
                    // Add intermediary message to our chunk list.
 | 
					 | 
				
			||||||
                    // We use a chunk list instead of a big buffer because resizing
 | 
					 | 
				
			||||||
                    // large buffer can be very costly when we need to re-allocate
 | 
					 | 
				
			||||||
                    // the internal buffer which is slow and can let the internal OS
 | 
					 | 
				
			||||||
                    // receive buffer fill out.
 | 
					 | 
				
			||||||
                    //
 | 
					 | 
				
			||||||
                    _chunks.emplace_back(
 | 
					 | 
				
			||||||
                        std::vector<uint8_t>(_rxbuf.begin()+ws.header_size,
 | 
					 | 
				
			||||||
                                             _rxbuf.begin()+ws.header_size+(size_t)ws.N));
 | 
					 | 
				
			||||||
                if (ws.fin)
 | 
					                if (ws.fin)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                        emitMessage(MSG, getMergedChunks(), ws, onMessageCallback);
 | 
					                    // fire callback with a string message
 | 
				
			||||||
                        _chunks.clear();
 | 
					                    std::string stringMessage(_receivedData.begin(),
 | 
				
			||||||
                    }
 | 
					                                              _receivedData.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    emitMessage(MSG, stringMessage, ws, onMessageCallback);
 | 
				
			||||||
 | 
					                    _receivedData.clear();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (ws.opcode == wsheader_type::PING)
 | 
					            else if (ws.opcode == wsheader_type::PING)
 | 
				
			||||||
@@ -439,32 +420,11 @@ namespace ix
 | 
				
			|||||||
                close();
 | 
					                close();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Erase the message that has been processed from the input/read buffer
 | 
					 | 
				
			||||||
            _rxbuf.erase(_rxbuf.begin(),
 | 
					            _rxbuf.erase(_rxbuf.begin(),
 | 
				
			||||||
                         _rxbuf.begin() + ws.header_size + (size_t) ws.N);
 | 
					                         _rxbuf.begin() + ws.header_size + (size_t) ws.N);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string WebSocketTransport::getMergedChunks() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        size_t length = 0;
 | 
					 | 
				
			||||||
        for (auto&& chunk : _chunks)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            length += chunk.size();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string msg;
 | 
					 | 
				
			||||||
        msg.reserve(length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (auto&& chunk : _chunks)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::string str(chunk.begin(), chunk.end());
 | 
					 | 
				
			||||||
            msg += str;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return msg;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketTransport::emitMessage(MessageKind messageKind, 
 | 
					    void WebSocketTransport::emitMessage(MessageKind messageKind, 
 | 
				
			||||||
                                         const std::string& message,
 | 
					                                         const std::string& message,
 | 
				
			||||||
                                         const wsheader_type& ws,
 | 
					                                         const wsheader_type& ws,
 | 
				
			||||||
@@ -494,11 +454,9 @@ namespace ix
 | 
				
			|||||||
        return static_cast<unsigned>(seconds);
 | 
					        return static_cast<unsigned>(seconds);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocketTransport::sendData(
 | 
					    WebSocketSendInfo WebSocketTransport::sendData(wsheader_type::opcode_type type, 
 | 
				
			||||||
        wsheader_type::opcode_type type,
 | 
					 | 
				
			||||||
                                                   const std::string& message,
 | 
					                                                   const std::string& message,
 | 
				
			||||||
        bool compress,
 | 
					                                                   bool compress)
 | 
				
			||||||
        const OnProgressCallback& onProgressCallback)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_readyState == CLOSING || _readyState == CLOSED)
 | 
					        if (_readyState == CLOSING || _readyState == CLOSED)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -515,81 +473,15 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (compress)
 | 
					        if (compress)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!_perMessageDeflate.compress(message, compressedMessage))
 | 
					            bool success = _perMessageDeflate.compress(message, compressedMessage);
 | 
				
			||||||
            {
 | 
					            compressionError = !success;
 | 
				
			||||||
                bool success = false;
 | 
					 | 
				
			||||||
                compressionError = true;
 | 
					 | 
				
			||||||
                payloadSize = 0;
 | 
					 | 
				
			||||||
                wireSize = 0;
 | 
					 | 
				
			||||||
                return WebSocketSendInfo(success, compressionError, payloadSize, wireSize);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            compressionError = false;
 | 
					 | 
				
			||||||
            wireSize = compressedMessage.size();
 | 
					            wireSize = compressedMessage.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            message_begin = compressedMessage.begin();
 | 
					            message_begin = compressedMessage.begin();
 | 
				
			||||||
            message_end = compressedMessage.end();
 | 
					            message_end = compressedMessage.end();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Common case for most message. No fragmentation required.
 | 
					        uint64_t message_size = wireSize;
 | 
				
			||||||
        if (wireSize < kChunkSize)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sendFragment(type, true, message_begin, message_end, compress);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            // Large messages need to be fragmented
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            // Rules:
 | 
					 | 
				
			||||||
            // First message needs to specify a proper type (BINARY or TEXT)
 | 
					 | 
				
			||||||
            // Intermediary and last messages need to be of type CONTINUATION
 | 
					 | 
				
			||||||
            // Last message must set the fin byte.
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            auto steps = wireSize / kChunkSize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            std::string::const_iterator begin = message_begin;
 | 
					 | 
				
			||||||
            std::string::const_iterator end = message_end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (uint64_t i = 0 ; i < steps; ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                bool firstStep = i == 0;
 | 
					 | 
				
			||||||
                bool lastStep = (i+1) == steps;
 | 
					 | 
				
			||||||
                bool fin = lastStep;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                end = begin + kChunkSize;
 | 
					 | 
				
			||||||
                if (lastStep)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    end = message_end;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                auto opcodeType = type;
 | 
					 | 
				
			||||||
                if (!firstStep)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    opcodeType = wsheader_type::CONTINUATION;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Send message
 | 
					 | 
				
			||||||
                sendFragment(opcodeType, fin, begin, end, compress);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (onProgressCallback && !onProgressCallback(i, steps))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                begin += kChunkSize;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return WebSocketSendInfo(true, compressionError, payloadSize, wireSize);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketTransport::sendFragment(wsheader_type::opcode_type type,
 | 
					 | 
				
			||||||
                                          bool fin,
 | 
					 | 
				
			||||||
                                          std::string::const_iterator message_begin,
 | 
					 | 
				
			||||||
                                          std::string::const_iterator message_end,
 | 
					 | 
				
			||||||
                                          bool compress)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto message_size = message_end - message_begin;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unsigned x = getRandomUnsigned();
 | 
					        unsigned x = getRandomUnsigned();
 | 
				
			||||||
        uint8_t masking_key[4] = {};
 | 
					        uint8_t masking_key[4] = {};
 | 
				
			||||||
@@ -602,13 +494,7 @@ namespace ix
 | 
				
			|||||||
        header.assign(2 +
 | 
					        header.assign(2 +
 | 
				
			||||||
                      (message_size >= 126 ? 2 : 0) +
 | 
					                      (message_size >= 126 ? 2 : 0) +
 | 
				
			||||||
                      (message_size >= 65536 ? 6 : 0) + 4, 0);
 | 
					                      (message_size >= 65536 ? 6 : 0) + 4, 0);
 | 
				
			||||||
        header[0] = type;
 | 
					        header[0] = 0x80 | type;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The fin bit indicate that this is the last fragment. Fin is French for end.
 | 
					 | 
				
			||||||
        if (fin)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            header[0] |= 0x80;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This bit indicate that the frame is compressed
 | 
					        // This bit indicate that the frame is compressed
 | 
				
			||||||
        if (compress)
 | 
					        if (compress)
 | 
				
			||||||
@@ -660,6 +546,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Now actually send this data
 | 
					        // Now actually send this data
 | 
				
			||||||
        sendOnSocket();
 | 
					        sendOnSocket();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return WebSocketSendInfo(true, compressionError, payloadSize, wireSize);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocketTransport::sendPing(const std::string& message)
 | 
					    WebSocketSendInfo WebSocketTransport::sendPing(const std::string& message)
 | 
				
			||||||
@@ -668,13 +556,9 @@ namespace ix
 | 
				
			|||||||
        return sendData(wsheader_type::PING, message, compress);
 | 
					        return sendData(wsheader_type::PING, message, compress);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocketTransport::sendBinary(
 | 
					    WebSocketSendInfo WebSocketTransport::sendBinary(const std::string& message) 
 | 
				
			||||||
        const std::string& message,
 | 
					 | 
				
			||||||
        const OnProgressCallback& onProgressCallback)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return sendData(wsheader_type::BINARY_FRAME, message,
 | 
					        return sendData(wsheader_type::BINARY_FRAME, message, _enablePerMessageDeflate);
 | 
				
			||||||
                        _enablePerMessageDeflate, onProgressCallback);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void WebSocketTransport::sendOnSocket()
 | 
					    void WebSocketTransport::sendOnSocket()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,6 @@
 | 
				
			|||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
#include <list>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXWebSocketSendInfo.h"
 | 
					#include "IXWebSocketSendInfo.h"
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflate.h"
 | 
					#include "IXWebSocketPerMessageDeflate.h"
 | 
				
			||||||
@@ -24,7 +23,6 @@
 | 
				
			|||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
#include "IXWebSocketHandshake.h"
 | 
					#include "IXWebSocketHandshake.h"
 | 
				
			||||||
#include "IXProgressCallback.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix 
 | 
					namespace ix 
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -68,8 +66,7 @@ namespace ix
 | 
				
			|||||||
                                            int timeoutSecs);
 | 
					                                            int timeoutSecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void poll();
 | 
					        void poll();
 | 
				
			||||||
        WebSocketSendInfo sendBinary(const std::string& message,
 | 
					        WebSocketSendInfo sendBinary(const std::string& message);
 | 
				
			||||||
                                     const OnProgressCallback& onProgressCallback);
 | 
					 | 
				
			||||||
        WebSocketSendInfo sendPing(const std::string& message);
 | 
					        WebSocketSendInfo sendPing(const std::string& message);
 | 
				
			||||||
        void close();
 | 
					        void close();
 | 
				
			||||||
        ReadyStateValues getReadyState() const;
 | 
					        ReadyStateValues getReadyState() const;
 | 
				
			||||||
@@ -79,6 +76,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::string _url;
 | 
					        std::string _url;
 | 
				
			||||||
 | 
					        std::string _origin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct wsheader_type {
 | 
					        struct wsheader_type {
 | 
				
			||||||
            unsigned header_size;
 | 
					            unsigned header_size;
 | 
				
			||||||
@@ -98,31 +96,13 @@ namespace ix
 | 
				
			|||||||
            uint8_t masking_key[4];
 | 
					            uint8_t masking_key[4];
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Buffer for reading from our socket. That buffer is never resized.
 | 
					 | 
				
			||||||
        std::vector<uint8_t> _readbuf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Contains all messages that were fetched in the last socket read.
 | 
					 | 
				
			||||||
        // This could be a mix of control messages (Close, Ping, etc...) and
 | 
					 | 
				
			||||||
        // data messages. That buffer
 | 
					 | 
				
			||||||
        std::vector<uint8_t> _rxbuf;
 | 
					        std::vector<uint8_t> _rxbuf;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Contains all messages that are waiting to be sent
 | 
					 | 
				
			||||||
        std::vector<uint8_t> _txbuf;
 | 
					        std::vector<uint8_t> _txbuf;
 | 
				
			||||||
        mutable std::mutex _txbufMutex;
 | 
					        mutable std::mutex _txbufMutex;
 | 
				
			||||||
 | 
					        std::vector<uint8_t> _receivedData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Hold fragments for multi-fragments messages in a list. We support receiving very large
 | 
					 | 
				
			||||||
        // messages (tested messages up to 700M) and we cannot put them in a single
 | 
					 | 
				
			||||||
        // buffer that is resized, as this operation can be slow when a buffer has its
 | 
					 | 
				
			||||||
        // size increased 2 fold, while appending to a list has a fixed cost.
 | 
					 | 
				
			||||||
        std::list<std::vector<uint8_t>> _chunks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Fragments are 32K long
 | 
					 | 
				
			||||||
        static constexpr size_t kChunkSize = 1 << 15;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Underlying TCP socket
 | 
					 | 
				
			||||||
        std::shared_ptr<Socket> _socket;
 | 
					        std::shared_ptr<Socket> _socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Hold the state of the connection (OPEN, CLOSED, etc...)
 | 
					 | 
				
			||||||
        std::atomic<ReadyStateValues> _readyState;
 | 
					        std::atomic<ReadyStateValues> _readyState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        OnCloseCallback _onCloseCallback;
 | 
					        OnCloseCallback _onCloseCallback;
 | 
				
			||||||
@@ -131,7 +111,6 @@ namespace ix
 | 
				
			|||||||
        size_t _closeWireSize;
 | 
					        size_t _closeWireSize;
 | 
				
			||||||
        mutable std::mutex _closeDataMutex;
 | 
					        mutable std::mutex _closeDataMutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Data used for Per Message Deflate compression (with zlib)
 | 
					 | 
				
			||||||
        WebSocketPerMessageDeflate _perMessageDeflate;
 | 
					        WebSocketPerMessageDeflate _perMessageDeflate;
 | 
				
			||||||
        WebSocketPerMessageDeflateOptions _perMessageDeflateOptions;
 | 
					        WebSocketPerMessageDeflateOptions _perMessageDeflateOptions;
 | 
				
			||||||
        std::atomic<bool> _enablePerMessageDeflate;
 | 
					        std::atomic<bool> _enablePerMessageDeflate;
 | 
				
			||||||
@@ -152,13 +131,6 @@ namespace ix
 | 
				
			|||||||
        void sendOnSocket();
 | 
					        void sendOnSocket();
 | 
				
			||||||
        WebSocketSendInfo sendData(wsheader_type::opcode_type type, 
 | 
					        WebSocketSendInfo sendData(wsheader_type::opcode_type type, 
 | 
				
			||||||
                                   const std::string& message,
 | 
					                                   const std::string& message,
 | 
				
			||||||
                                   bool compress,
 | 
					 | 
				
			||||||
                                   const OnProgressCallback& onProgressCallback = nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void sendFragment(wsheader_type::opcode_type type,
 | 
					 | 
				
			||||||
                          bool fin,
 | 
					 | 
				
			||||||
                          std::string::const_iterator begin,
 | 
					 | 
				
			||||||
                          std::string::const_iterator end,
 | 
					 | 
				
			||||||
                                   bool compress);
 | 
					                                   bool compress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void emitMessage(MessageKind messageKind, 
 | 
					        void emitMessage(MessageKind messageKind, 
 | 
				
			||||||
@@ -176,7 +148,5 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        unsigned getRandomUnsigned();
 | 
					        unsigned getRandomUnsigned();
 | 
				
			||||||
        void unmaskReceiveBuffer(const wsheader_type& ws);
 | 
					        void unmaskReceiveBuffer(const wsheader_type& ws);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string getMergedChunks() const;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								makefile
									
									
									
									
									
								
							@@ -3,19 +3,12 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
all: run
 | 
					all: run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
brew:
 | 
					 | 
				
			||||||
	mkdir -p ws/build && (cd ws/build ; cmake .. ; make)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.PHONY: docker
 | 
					.PHONY: docker
 | 
				
			||||||
docker:
 | 
					docker:
 | 
				
			||||||
	docker build -t broadcast_server:latest .
 | 
						docker build -t ws_connect:latest .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run:
 | 
					run: docker
 | 
				
			||||||
	docker run --cap-add sys_ptrace -it broadcast_server:latest bash
 | 
						docker run --cap-add sys_ptrace -it ws_connect:latest bash
 | 
				
			||||||
 | 
					 | 
				
			||||||
# this is helpful to remove trailing whitespaces
 | 
					 | 
				
			||||||
trail:
 | 
					 | 
				
			||||||
	sh third_party/remove_trailing_whitespaces.sh
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
build:
 | 
					build:
 | 
				
			||||||
	(cd examples/satori_publisher ; mkdir -p build ; cd build ; cmake .. ; make)
 | 
						(cd examples/satori_publisher ; mkdir -p build ; cd build ; cmake .. ; make)
 | 
				
			||||||
@@ -31,7 +24,7 @@ test_server:
 | 
				
			|||||||
	(cd test && npm i ws && node broadcast-server.js)
 | 
						(cd test && npm i ws && node broadcast-server.js)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# env TEST=Websocket_server make test
 | 
					# env TEST=Websocket_server make test
 | 
				
			||||||
# env TEST=Websocket_chat make test
 | 
					# env TEST=websocket_server make test
 | 
				
			||||||
# env TEST=heartbeat make test
 | 
					# env TEST=heartbeat make test
 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
	python test/run.py
 | 
						python test/run.py
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,14 +18,13 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/.. ixwebsocket)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include_directories(
 | 
					include_directories(
 | 
				
			||||||
  ${PROJECT_SOURCE_DIR}/Catch2/single_include
 | 
					  ${PROJECT_SOURCE_DIR}/Catch2/single_include
 | 
				
			||||||
  ../third_party/msgpack11
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Shared sources
 | 
					# Shared sources
 | 
				
			||||||
set (SOURCES 
 | 
					set (SOURCES 
 | 
				
			||||||
  test_runner.cpp
 | 
					  test_runner.cpp
 | 
				
			||||||
  IXTest.cpp
 | 
					  IXTest.cpp
 | 
				
			||||||
  ../third_party/msgpack11/msgpack11.cpp
 | 
					  msgpack11.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  IXDNSLookupTest.cpp
 | 
					  IXDNSLookupTest.cpp
 | 
				
			||||||
  IXSocketTest.cpp
 | 
					  IXSocketTest.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,7 @@ namespace ix
 | 
				
			|||||||
        Logger() << msg;
 | 
					        Logger() << msg;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int getAnyFreePort()
 | 
					    int getFreePort()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int defaultPort = 8090;
 | 
					        int defaultPort = 8090;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,23 +117,4 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return port;
 | 
					        return port;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    int getFreePort()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        while (true)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            int port = getAnyFreePort();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            // Only port above 1024 can be used by non root users, but for some
 | 
					 | 
				
			||||||
            // reason I got port 7 returned with macOS when binding on port 0...
 | 
					 | 
				
			||||||
            //
 | 
					 | 
				
			||||||
            if (port > 1024)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return port;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <vector>
 | 
					#include <queue>
 | 
				
			||||||
#include <mutex>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketServer.h>
 | 
					#include <ixwebsocket/IXWebSocketServer.h>
 | 
				
			||||||
#include "msgpack11.hpp"
 | 
					#include "msgpack11.hpp"
 | 
				
			||||||
@@ -40,11 +39,9 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            void sendMessage(const std::string& text);
 | 
					            void sendMessage(const std::string& text);
 | 
				
			||||||
            size_t getReceivedMessagesCount() const;
 | 
					            size_t getReceivedMessagesCount() const;
 | 
				
			||||||
            const std::vector<std::string>& getReceivedMessages() const;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string encodeMessage(const std::string& text);
 | 
					            std::string encodeMessage(const std::string& text);
 | 
				
			||||||
            std::pair<std::string, std::string> decodeMessage(const std::string& str);
 | 
					            std::pair<std::string, std::string> decodeMessage(const std::string& str);
 | 
				
			||||||
            void appendMessage(const std::string& message);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private:
 | 
					        private:
 | 
				
			||||||
            std::string _user;
 | 
					            std::string _user;
 | 
				
			||||||
@@ -53,8 +50,7 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            ix::WebSocket _webSocket;
 | 
					            ix::WebSocket _webSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::vector<std::string> _receivedMessages;
 | 
					            std::queue<std::string> _receivedQueue;
 | 
				
			||||||
            mutable std::mutex _mutex;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketChat::WebSocketChat(const std::string& user,
 | 
					    WebSocketChat::WebSocketChat(const std::string& user,
 | 
				
			||||||
@@ -69,20 +65,7 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    size_t WebSocketChat::getReceivedMessagesCount() const
 | 
					    size_t WebSocketChat::getReceivedMessagesCount() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_mutex);
 | 
					        return _receivedQueue.size();
 | 
				
			||||||
        return _receivedMessages.size();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const std::vector<std::string>& WebSocketChat::getReceivedMessages() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_mutex);
 | 
					 | 
				
			||||||
        return _receivedMessages;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketChat::appendMessage(const std::string& message)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_mutex);
 | 
					 | 
				
			||||||
        _receivedMessages.push_back(message);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool WebSocketChat::isReady() const
 | 
					    bool WebSocketChat::isReady() const
 | 
				
			||||||
@@ -102,8 +85,7 @@ namespace
 | 
				
			|||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
            ss << "ws://localhost:"
 | 
					            ss << "ws://localhost:"
 | 
				
			||||||
               << _port 
 | 
					               << _port 
 | 
				
			||||||
               << "/"
 | 
					               << "/";
 | 
				
			||||||
               << _user;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            url = ss.str();
 | 
					            url = ss.str();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -145,16 +127,10 @@ namespace
 | 
				
			|||||||
                    // as we do for the satori chat example.
 | 
					                    // as we do for the satori chat example.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // store text
 | 
					                    // store text
 | 
				
			||||||
                    appendMessage(result.second);
 | 
					                    _receivedQueue.push(result.second);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    std::string payload = result.second;
 | 
					 | 
				
			||||||
                    if (payload.size() > 2000)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        payload = "<message too large>";
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    ss << std::endl 
 | 
					                    ss << std::endl 
 | 
				
			||||||
                       << result.first << " > " << payload
 | 
					                       << result.first << " > " << result.second
 | 
				
			||||||
                       << std::endl
 | 
					                       << std::endl
 | 
				
			||||||
                       << _user << " > ";
 | 
					                       << _user << " > ";
 | 
				
			||||||
                    log(ss.str());
 | 
					                    log(ss.str());
 | 
				
			||||||
@@ -293,36 +269,15 @@ TEST_CASE("Websocket_chat", "[websocket_chat]")
 | 
				
			|||||||
        chatB.sendMessage("from B1");
 | 
					        chatB.sendMessage("from B1");
 | 
				
			||||||
        chatB.sendMessage("from B2");
 | 
					        chatB.sendMessage("from B2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Test large messages that needs to be broken into small fragments
 | 
					        // Give us 1s for all messages to be received
 | 
				
			||||||
        size_t size = 1 * 1024 * 1024; // ~1Mb
 | 
					 | 
				
			||||||
        std::string bigMessage(size, 'a');
 | 
					 | 
				
			||||||
        chatB.sendMessage(bigMessage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        log("Sent all messages");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Wait until all messages are received. 10s timeout
 | 
					 | 
				
			||||||
        int attempts = 0;
 | 
					 | 
				
			||||||
        while (chatA.getReceivedMessagesCount() != 3 ||
 | 
					 | 
				
			||||||
               chatB.getReceivedMessagesCount() != 3)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            REQUIRE(attempts++ < 10);
 | 
					 | 
				
			||||||
        ix::msleep(1000);
 | 
					        ix::msleep(1000);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        chatA.stop();
 | 
					        chatA.stop();
 | 
				
			||||||
        chatB.stop();
 | 
					        chatB.stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        REQUIRE(chatA.getReceivedMessagesCount() == 3);
 | 
					        REQUIRE(chatA.getReceivedMessagesCount() == 2);
 | 
				
			||||||
        REQUIRE(chatB.getReceivedMessagesCount() == 3);
 | 
					        REQUIRE(chatB.getReceivedMessagesCount() == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        REQUIRE(chatB.getReceivedMessages()[0] == "from A1");
 | 
					 | 
				
			||||||
        REQUIRE(chatB.getReceivedMessages()[1] == "from A2");
 | 
					 | 
				
			||||||
        REQUIRE(chatB.getReceivedMessages()[2] == "from A3");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        REQUIRE(chatA.getReceivedMessages()[0] == "from B1");
 | 
					 | 
				
			||||||
        REQUIRE(chatA.getReceivedMessages()[1] == "from B2");
 | 
					 | 
				
			||||||
        REQUIRE(chatA.getReceivedMessages()[2].size() == bigMessage.size());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Give us 500ms for the server to notice that clients went away
 | 
					        // Give us 500ms for the server to notice that clients went away
 | 
				
			||||||
        ix::msleep(500);
 | 
					        ix::msleep(500);
 | 
				
			||||||
        REQUIRE(server.getClients().size() == 0);
 | 
					        REQUIRE(server.getClients().size() == 0);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4641
									
								
								third_party/cli11/CLI11.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4641
									
								
								third_party/cli11/CLI11.hpp
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										333
									
								
								third_party/jsoncpp/json/json-forwards.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										333
									
								
								third_party/jsoncpp/json/json-forwards.h
									
									
									
									
										vendored
									
									
								
							@@ -1,333 +0,0 @@
 | 
				
			|||||||
/// 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
									
								
								third_party/jsoncpp/json/json.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2186
									
								
								third_party/jsoncpp/json/json.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5386
									
								
								third_party/jsoncpp/jsoncpp.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5386
									
								
								third_party/jsoncpp/jsoncpp.cpp
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								third_party/remove_trailing_whitespaces.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/remove_trailing_whitespaces.sh
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +0,0 @@
 | 
				
			|||||||
find . -type f -name '*.cpp' -exec sed -i '' 's/[[:space:]]*$//' {} \+
 | 
					 | 
				
			||||||
find . -type f -name '*.h' -exec sed -i '' 's/[[:space:]]*$//' {} \+
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								ws/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								ws/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
build
 | 
					 | 
				
			||||||
@@ -1,37 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cmake_minimum_required (VERSION 3.4.1)
 | 
					 | 
				
			||||||
project (ws)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# 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 .)
 | 
					 | 
				
			||||||
include_directories(ws ../third_party)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
add_executable(ws 
 | 
					 | 
				
			||||||
  ../third_party/msgpack11/msgpack11.cpp
 | 
					 | 
				
			||||||
  ixcrypto/IXBase64.cpp
 | 
					 | 
				
			||||||
  ixcrypto/IXHash.cpp
 | 
					 | 
				
			||||||
  ixcrypto/IXUuid.cpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ws_transfer.cpp
 | 
					 | 
				
			||||||
  ws_send.cpp
 | 
					 | 
				
			||||||
  ws_receive.cpp
 | 
					 | 
				
			||||||
  ws.cpp)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (APPLE AND USE_TLS)
 | 
					 | 
				
			||||||
    target_link_libraries(ws "-framework foundation" "-framework security")
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(ws ixwebsocket)
 | 
					 | 
				
			||||||
install(TARGETS ws RUNTIME DESTINATION bin)
 | 
					 | 
				
			||||||
							
								
								
									
										10
									
								
								ws/README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								ws/README.md
									
									
									
									
									
								
							@@ -1,10 +0,0 @@
 | 
				
			|||||||
```
 | 
					 | 
				
			||||||
# Start receiver first
 | 
					 | 
				
			||||||
./ws receive ws://localhost:8080 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Sender
 | 
					 | 
				
			||||||
./ws send ws://localhost:8080 /file/to/path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Server
 | 
					 | 
				
			||||||
./ws transfer # running on port 8080.
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
# Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# 'manual' way of building. I cannot get CMake to work to build in a container.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
g++ --std=c++14 \
 | 
					 | 
				
			||||||
    -DIXWEBSOCKET_USE_TLS \
 | 
					 | 
				
			||||||
    -g \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXEventFd.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXSocket.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXSocketServer.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXSocketConnect.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXDNSLookup.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXCancellationRequest.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocket.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketServer.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketTransport.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketHandshake.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketPerMessageDeflate.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/IXSocketOpenSSL.cpp \
 | 
					 | 
				
			||||||
    ../ixwebsocket/linux/IXSetThreadName_linux.cpp \
 | 
					 | 
				
			||||||
    ../third_party/jsoncpp/jsoncpp.cpp \
 | 
					 | 
				
			||||||
    ixcrypto/IXBase64.cpp \
 | 
					 | 
				
			||||||
    ixcrypto/IXHash.cpp \
 | 
					 | 
				
			||||||
    ixcrypto/IXUuid.cpp \
 | 
					 | 
				
			||||||
    ws_transfer.cpp \
 | 
					 | 
				
			||||||
    ws_send.cpp \
 | 
					 | 
				
			||||||
    ws_receive.cpp \
 | 
					 | 
				
			||||||
    ws.cpp \
 | 
					 | 
				
			||||||
    -I . \
 | 
					 | 
				
			||||||
    -I .. \
 | 
					 | 
				
			||||||
    -I ../third_party \
 | 
					 | 
				
			||||||
    -o ws \
 | 
					 | 
				
			||||||
    -lcrypto -lssl -lz -lpthread
 | 
					 | 
				
			||||||
@@ -1,22 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXHash.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018 Machine Zone. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXHash.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint64_t djb2Hash(const std::vector<uint8_t>& data)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uint64_t hashAddress = 5381;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (auto&& c : data)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            hashAddress = ((hashAddress << 5) + hashAddress) + c;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return hashAddress;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXHash.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018 Machine Zone. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint64_t djb2Hash(const std::vector<uint8_t>& data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,75 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  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();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,17 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  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();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										68
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -1,68 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  ws.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 
 | 
					 | 
				
			||||||
// Main drive for websocket utilities
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cli11/CLI11.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ws_receive_main(const std::string& url,
 | 
					 | 
				
			||||||
                        bool enablePerMessageDeflate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extern int ws_transfer_main(int port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    extern int ws_send_main(const std::string& url,
 | 
					 | 
				
			||||||
                            const std::string& path);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char** argv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    CLI::App app{"ws is a websocket tool"};
 | 
					 | 
				
			||||||
    app.require_subcommand();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string url;
 | 
					 | 
				
			||||||
    std::string path;
 | 
					 | 
				
			||||||
    int port = 8080;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CLI::App* sendApp = app.add_subcommand("send", "Send a file");
 | 
					 | 
				
			||||||
    sendApp->add_option("url", url, "Connection url")->required();
 | 
					 | 
				
			||||||
    sendApp->add_option("path", path, "Path to the file to send")->required();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CLI::App* receiveApp = app.add_subcommand("receive", "Receive a file");
 | 
					 | 
				
			||||||
    receiveApp->add_option("url", url, "Connection url")->required();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server");
 | 
					 | 
				
			||||||
    transferApp->add_option("--port", port, "Connection url");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    CLI11_PARSE(app, argc, argv);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (app.got_subcommand("transfer"))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ix::ws_transfer_main(port);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else if (app.got_subcommand("send"))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ix::ws_send_main(url, path);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else if (app.got_subcommand("receive"))
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bool enablePerMessageDeflate = false;
 | 
					 | 
				
			||||||
        return ix::ws_receive_main(url, enablePerMessageDeflate);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        assert(false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,251 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  ws_receiver.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 <msgpack11/msgpack11.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using msgpack11::MsgPack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class WebSocketReceiver
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public:
 | 
					 | 
				
			||||||
            WebSocketReceiver(const std::string& _url,
 | 
					 | 
				
			||||||
                              bool enablePerMessageDeflate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            void subscribe(const std::string& channel);
 | 
					 | 
				
			||||||
            void start();
 | 
					 | 
				
			||||||
            void stop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            void waitForConnection();
 | 
					 | 
				
			||||||
            void waitForMessage();
 | 
					 | 
				
			||||||
            void handleMessage(const std::string& str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private:
 | 
					 | 
				
			||||||
            std::string _url;
 | 
					 | 
				
			||||||
            std::string _id;
 | 
					 | 
				
			||||||
            ix::WebSocket _webSocket;
 | 
					 | 
				
			||||||
            bool _enablePerMessageDeflate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            std::mutex _conditionVariableMutex;
 | 
					 | 
				
			||||||
            std::condition_variable _condition;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            std::string extractFilename(const std::string& path);
 | 
					 | 
				
			||||||
            void handleError(const std::string& errMsg, const std::string& id);
 | 
					 | 
				
			||||||
            void log(const std::string& msg);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WebSocketReceiver::WebSocketReceiver(const std::string& url,
 | 
					 | 
				
			||||||
                                         bool enablePerMessageDeflate) :
 | 
					 | 
				
			||||||
        _url(url),
 | 
					 | 
				
			||||||
        _enablePerMessageDeflate(enablePerMessageDeflate)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::stop()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _webSocket.stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::log(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout << msg << std::endl;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::waitForConnection()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout << "Connecting..." << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::unique_lock<std::mutex> lock(_conditionVariableMutex);
 | 
					 | 
				
			||||||
        _condition.wait(lock);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::waitForMessage()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout << "Waiting for message..." << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::unique_lock<std::mutex> lock(_conditionVariableMutex);
 | 
					 | 
				
			||||||
        _condition.wait(lock);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // We should cleanup the file name and full path further to remove .. as well
 | 
					 | 
				
			||||||
    std::string WebSocketReceiver::extractFilename(const std::string& path)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::string::size_type idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        idx = path.rfind('/');
 | 
					 | 
				
			||||||
        if (idx != std::string::npos)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::string filename = path.substr(idx+1);
 | 
					 | 
				
			||||||
            return filename;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return path;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::handleError(const std::string& errMsg,
 | 
					 | 
				
			||||||
                                        const std::string& id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::map<MsgPack, MsgPack> pdu;
 | 
					 | 
				
			||||||
        pdu["kind"] = "error";
 | 
					 | 
				
			||||||
        pdu["id"] = id;
 | 
					 | 
				
			||||||
        pdu["message"] = errMsg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MsgPack msg(pdu);
 | 
					 | 
				
			||||||
        _webSocket.send(msg.dump());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::handleMessage(const std::string& str)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cerr << "Received message: " << str.size() << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string errMsg;
 | 
					 | 
				
			||||||
        MsgPack data = MsgPack::parse(str, errMsg);
 | 
					 | 
				
			||||||
        if (!errMsg.empty())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            handleError("Invalid MsgPack", std::string());
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::cout << "id: " << data["id"].string_value() << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::vector<uint8_t> content = data["content"].binary_items();
 | 
					 | 
				
			||||||
        std::cout << "Content size: " << content.size() << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Validate checksum
 | 
					 | 
				
			||||||
        uint64_t cksum = ix::djb2Hash(content);
 | 
					 | 
				
			||||||
        auto cksumRef = data["djb2_hash"].string_value();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::cout << "Computed hash: " << cksum << std::endl;
 | 
					 | 
				
			||||||
        std::cout << "Reference hash: " << cksumRef << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (std::to_string(cksum) != cksumRef)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            handleError("Hash mismatch.", std::string());
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string filename = data["filename"].string_value();
 | 
					 | 
				
			||||||
        filename = extractFilename(filename);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::cout << "Writing to disk: " << filename << std::endl;
 | 
					 | 
				
			||||||
        std::ofstream out(filename);
 | 
					 | 
				
			||||||
        out.write((char*)&content.front(), content.size());
 | 
					 | 
				
			||||||
        out.close();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::map<MsgPack, MsgPack> pdu;
 | 
					 | 
				
			||||||
        pdu["ack"] = true;
 | 
					 | 
				
			||||||
        pdu["id"] = data["id"];
 | 
					 | 
				
			||||||
        pdu["filename"] = data["filename"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MsgPack msg(pdu);
 | 
					 | 
				
			||||||
        _webSocket.send(msg.dump());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketReceiver::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_receive: 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_receive: connection closed:";
 | 
					 | 
				
			||||||
                    ss << " code " << closeInfo.code;
 | 
					 | 
				
			||||||
                    ss << " reason " << closeInfo.reason << std::endl;
 | 
					 | 
				
			||||||
                    log(ss.str());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else if (messageType == ix::WebSocket_MessageType_Message)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ss << "ws_receive: transfered " << wireSize << " bytes";
 | 
					 | 
				
			||||||
                    log(ss.str());
 | 
					 | 
				
			||||||
                    handleMessage(str);
 | 
					 | 
				
			||||||
                    _condition.notify_one();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                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();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void wsReceive(const std::string& url,
 | 
					 | 
				
			||||||
                   bool enablePerMessageDeflate)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate);
 | 
					 | 
				
			||||||
        webSocketReceiver.start();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        webSocketReceiver.waitForConnection();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        webSocketReceiver.waitForMessage();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::chrono::duration<double, std::milli> duration(1000);
 | 
					 | 
				
			||||||
        std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::cout << "Done !" << std::endl;
 | 
					 | 
				
			||||||
        webSocketReceiver.stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int ws_receive_main(const std::string& url,
 | 
					 | 
				
			||||||
                        bool enablePerMessageDeflate)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Socket::init();
 | 
					 | 
				
			||||||
        wsReceive(url, enablePerMessageDeflate);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										296
									
								
								ws/ws_send.cpp
									
									
									
									
									
								
							
							
						
						
									
										296
									
								
								ws/ws_send.cpp
									
									
									
									
									
								
							@@ -1,296 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  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 <msgpack11/msgpack11.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using msgpack11::MsgPack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            void log(const std::string& msg);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    WebSocketSender::WebSocketSender(const std::string& url,
 | 
					 | 
				
			||||||
                                     bool enablePerMessageDeflate) :
 | 
					 | 
				
			||||||
        _url(url),
 | 
					 | 
				
			||||||
        _enablePerMessageDeflate(enablePerMessageDeflate)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketSender::stop()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _webSocket.stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketSender::log(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout << msg << std::endl;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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::vector<uint8_t> load(const std::string& path)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::vector<uint8_t> memblock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::ifstream file(path);
 | 
					 | 
				
			||||||
        if (!file.is_open()) return memblock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.seekg(0, file.end);
 | 
					 | 
				
			||||||
        std::streamoff size = file.tellg();
 | 
					 | 
				
			||||||
        file.seekg(0, file.beg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        memblock.resize(size);
 | 
					 | 
				
			||||||
        file.read((char*)&memblock.front(), static_cast<std::streamsize>(size));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return memblock;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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 (" << wireSize << " bytes)";
 | 
					 | 
				
			||||||
                    log(ss.str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    std::string errMsg;
 | 
					 | 
				
			||||||
                    MsgPack data = MsgPack::parse(str, errMsg);
 | 
					 | 
				
			||||||
                    if (!errMsg.empty())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        std::cerr << "Invalid MsgPack response" << std::endl;
 | 
					 | 
				
			||||||
                        return;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    std::string id = data["id"].string_value();
 | 
					 | 
				
			||||||
                    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::vector<uint8_t> content;
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Bench bench("load file from disk");
 | 
					 | 
				
			||||||
            content = load(filename);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        _id = uuid4();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::map<MsgPack, MsgPack> pdu;
 | 
					 | 
				
			||||||
        pdu["kind"] = "send";
 | 
					 | 
				
			||||||
        pdu["id"] = _id;
 | 
					 | 
				
			||||||
        pdu["content"] = content;
 | 
					 | 
				
			||||||
        auto hash = djb2Hash(content);
 | 
					 | 
				
			||||||
        pdu["djb2_hash"] = std::to_string(hash);
 | 
					 | 
				
			||||||
        pdu["filename"] = filename;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MsgPack msg(pdu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Bench bench("Sending file through websocket");
 | 
					 | 
				
			||||||
        _webSocket.send(msg.dump(),
 | 
					 | 
				
			||||||
                        [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 * content.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 ws_send_main(const std::string& url,
 | 
					 | 
				
			||||||
                     const std::string& path)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bool throttle = false;
 | 
					 | 
				
			||||||
        bool enablePerMessageDeflate = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Socket::init();
 | 
					 | 
				
			||||||
        wsSend(url, path, enablePerMessageDeflate, throttle);
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,72 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  ws_transfer.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocketServer.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ws_transfer_main(int port)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::cout << "Listening on port " << port << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            std::cerr << "Received " << wireSize << " bytes" << std::endl;
 | 
					 | 
				
			||||||
                            for (auto&& client : server.getClients())
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                if (client != webSocket)
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    client->send(str);
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto res = server.listen();
 | 
					 | 
				
			||||||
        if (!res.first)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::cerr << res.second << std::endl;
 | 
					 | 
				
			||||||
            return 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        server.start();
 | 
					 | 
				
			||||||
        server.wait();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user