Compare commits
	
		
			8 Commits
		
	
	
		
			v7.4.3
			...
			feature/pi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a5179cd17f | ||
|  | e158175819 | ||
|  | ec2f229489 | ||
|  | ead9616d04 | ||
|  | 922d58eb59 | ||
|  | d1a7b9a985 | ||
|  | 11092027cd | ||
|  | 4de3ec995e | 
| @@ -1 +0,0 @@ | |||||||
| docker/Dockerfile.debian |  | ||||||
							
								
								
									
										31
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | FROM debian:stretch | ||||||
|  |  | ||||||
|  | ENV DEBIAN_FRONTEND noninteractive | ||||||
|  | RUN apt-get update  | ||||||
|  | RUN apt-get -y install g++  | ||||||
|  | RUN apt-get -y install libssl-dev | ||||||
|  | RUN apt-get -y install gdb | ||||||
|  | RUN apt-get -y install screen | ||||||
|  | RUN apt-get -y install procps | ||||||
|  | RUN apt-get -y install lsof | ||||||
|  | RUN apt-get -y install libz-dev | ||||||
|  | RUN apt-get -y install vim | ||||||
|  | RUN apt-get -y install make | ||||||
|  | RUN apt-get -y install cmake | ||||||
|  | RUN apt-get -y install curl | ||||||
|  | RUN apt-get -y install python | ||||||
|  | RUN apt-get -y install netcat | ||||||
|  |  | ||||||
|  | # debian strech cmake is too old for building with Docker | ||||||
|  | COPY makefile . | ||||||
|  | RUN ["make", "install_cmake_for_linux"] | ||||||
|  |  | ||||||
|  | COPY . . | ||||||
|  |  | ||||||
|  | ARG CMAKE_BIN_PATH=/tmp/cmake/cmake-3.14.0-rc4-Linux-x86_64/bin | ||||||
|  | ENV PATH="${CMAKE_BIN_PATH}:${PATH}" | ||||||
|  |  | ||||||
|  | # RUN ["make"] | ||||||
|  |  | ||||||
|  | EXPOSE 8765 | ||||||
|  | CMD ["/ws/ws", "transfer", "--port", "8765", "--host", "0.0.0.0"] | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| FROM debian:stretch |  | ||||||
|  |  | ||||||
| # RUN yum install -y gcc-c++ make cmake openssl-devel gdb |  | ||||||
| ENV DEBIAN_FRONTEND noninteractive |  | ||||||
| RUN apt-get update  |  | ||||||
| RUN apt-get -y install g++  |  | ||||||
| RUN apt-get -y install libssl-dev |  | ||||||
| RUN apt-get -y install gdb |  | ||||||
| RUN apt-get -y install screen |  | ||||||
| RUN apt-get -y install procps |  | ||||||
| RUN apt-get -y install lsof |  | ||||||
|  |  | ||||||
| COPY . . |  | ||||||
|  |  | ||||||
| WORKDIR examples/ws_connect |  | ||||||
| RUN ["sh", "build_linux.sh"] |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| FROM alpine:3.8 |  | ||||||
|  |  | ||||||
| RUN apk add --no-cache g++ musl-dev make cmake openssl-dev |  | ||||||
|  |  | ||||||
| COPY . . |  | ||||||
|  |  | ||||||
| WORKDIR examples/ws_connect |  | ||||||
| RUN ["sh", "build_linux.sh"] |  | ||||||
|  |  | ||||||
| EXPOSE 8765 |  | ||||||
| CMD ["ws_connect"] |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| FROM alpine:3.8 |  | ||||||
|  |  | ||||||
| RUN apk add --no-cache g++ musl-dev make cmake openssl-dev |  | ||||||
|  |  | ||||||
| COPY . . |  | ||||||
|  |  | ||||||
| WORKDIR examples/ws_connect |  | ||||||
| RUN ["sh", "build_linux.sh"] |  | ||||||
|  |  | ||||||
| EXPOSE 8765 |  | ||||||
| CMD ["ws_connect"] |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| FROM debian:stretch |  | ||||||
|  |  | ||||||
| ENV DEBIAN_FRONTEND noninteractive |  | ||||||
| RUN apt-get update  |  | ||||||
| RUN apt-get -y install g++  |  | ||||||
| RUN apt-get -y install libssl-dev |  | ||||||
| RUN apt-get -y install gdb |  | ||||||
| RUN apt-get -y install screen |  | ||||||
| RUN apt-get -y install procps |  | ||||||
| RUN apt-get -y install lsof |  | ||||||
| RUN apt-get -y install libz-dev |  | ||||||
| RUN apt-get -y install vim |  | ||||||
| RUN apt-get -y install make |  | ||||||
| RUN apt-get -y install cmake |  | ||||||
|  |  | ||||||
| COPY . . |  | ||||||
|  |  | ||||||
| WORKDIR ws |  | ||||||
| RUN ["sh", "docker_build.sh"] |  | ||||||
|  |  | ||||||
| EXPOSE 8765 |  | ||||||
| CMD ["/ws/ws", "transfer", "--port", "8765", "--hostname", "0.0.0.0"] |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| FROM gcc:8 |  | ||||||
|  |  | ||||||
| # RUN yum install -y gcc-c++ make cmake openssl-devel gdb |  | ||||||
|  |  | ||||||
| COPY . . |  | ||||||
|  |  | ||||||
| WORKDIR examples/ws_connect |  | ||||||
| RUN ["sh", "build_linux.sh"] |  | ||||||
| @@ -17,6 +17,8 @@ | |||||||
| // cf Android/Kernel table here | // cf Android/Kernel table here | ||||||
| // https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel | // https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel | ||||||
| // | // | ||||||
|  | // On macOS we use UNIX pipes to wake up select. | ||||||
|  | // | ||||||
|  |  | ||||||
| #include "IXEventFd.h" | #include "IXEventFd.h" | ||||||
|  |  | ||||||
| @@ -24,17 +26,24 @@ | |||||||
| # include <sys/eventfd.h> | # include <sys/eventfd.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef _WIN32 |  | ||||||
| #include <unistd.h> // for write | #include <unistd.h> // for write | ||||||
| #endif | #include <fcntl.h> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     EventFd::EventFd() : |     EventFd::EventFd() | ||||||
|         _eventfd(-1) |  | ||||||
|     { |     { | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
|  |         _eventfd = -1; | ||||||
|         _eventfd = eventfd(0, 0); |         _eventfd = eventfd(0, 0); | ||||||
|  |         fcntl(_eventfd, F_SETFL, O_NONBLOCK); | ||||||
|  | #else | ||||||
|  |         _fildes[0] = -1; | ||||||
|  |         _fildes[1] = -1; | ||||||
|  |  | ||||||
|  |         pipe(_fildes); | ||||||
|  |         fcntl(_fildes[0], F_SETFL, O_NONBLOCK); | ||||||
|  |         fcntl(_fildes[1], F_SETFL, O_NONBLOCK); | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -42,22 +51,44 @@ namespace ix | |||||||
|     { |     { | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
|         ::close(_eventfd); |         ::close(_eventfd); | ||||||
|  | #else | ||||||
|  |         ::close(_fildes[0]); | ||||||
|  |         ::close(_fildes[1]); | ||||||
|  |         _fildes[0] = -1; | ||||||
|  |         _fildes[1] = -1; | ||||||
| #endif | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool EventFd::notify() |     bool EventFd::notify(uint64_t value) | ||||||
|     { |     { | ||||||
| #if defined(__linux__) |         int fd; | ||||||
|         if (_eventfd == -1) return false; |  | ||||||
|  |  | ||||||
|         // select will wake up when a non-zero value is written to our eventfd | #if defined(__linux__) | ||||||
|         uint64_t value = 1; |         fd = _eventfd; | ||||||
|  | #else | ||||||
|  |         // File descriptor at index 1 in _fildes is the write end of the pipe | ||||||
|  |         fd = _fildes[1]; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |         if (fd == -1) return false; | ||||||
|  |  | ||||||
|         // we should write 8 bytes for an uint64_t |         // we should write 8 bytes for an uint64_t | ||||||
|         return write(_eventfd, &value, sizeof(value)) == 8; |         return write(fd, &value, sizeof(value)) == 8; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO: return max uint64_t for errors ? | ||||||
|  |     uint64_t EventFd::read() | ||||||
|  |     { | ||||||
|  |         int fd; | ||||||
|  |  | ||||||
|  | #if defined(__linux__) | ||||||
|  |         fd = _eventfd; | ||||||
| #else | #else | ||||||
|         return true; |         fd = _fildes[0]; | ||||||
| #endif | #endif | ||||||
|  |         uint64_t value = 0; | ||||||
|  |         ::read(fd, &value, sizeof(value)); | ||||||
|  |         return value; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool EventFd::clear() |     bool EventFd::clear() | ||||||
| @@ -77,6 +108,10 @@ namespace ix | |||||||
|  |  | ||||||
|     int EventFd::getFd() |     int EventFd::getFd() | ||||||
|     { |     { | ||||||
|  | #if defined(__linux__) | ||||||
|         return _eventfd; |         return _eventfd; | ||||||
|  | #else | ||||||
|  |         return _fildes[0]; | ||||||
|  | #endif | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,8 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     class EventFd { |     class EventFd { | ||||||
| @@ -13,11 +15,19 @@ namespace ix | |||||||
|         EventFd(); |         EventFd(); | ||||||
|         virtual ~EventFd(); |         virtual ~EventFd(); | ||||||
|  |  | ||||||
|         bool notify(); |         bool notify(uint64_t value); | ||||||
|         bool clear(); |         bool clear(); | ||||||
|  |         uint64_t read(); | ||||||
|         int getFd(); |         int getFd(); | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|  | #if defined(__linux__) | ||||||
|         int _eventfd; |         int _eventfd; | ||||||
|  | #else | ||||||
|  |         // Store file descriptors used by the communication pipe. Communication | ||||||
|  |         // happens between a control thread and a background thread, which is | ||||||
|  |         // blocked on select. | ||||||
|  |         int _fildes[2]; | ||||||
|  | #endif | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,6 +23,8 @@ namespace ix | |||||||
| { | { | ||||||
|     const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default |     const int Socket::kDefaultPollNoTimeout = -1; // No poll timeout by default | ||||||
|     const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout; |     const int Socket::kDefaultPollTimeout = kDefaultPollNoTimeout; | ||||||
|  |     const uint8_t Socket::kSendRequest = 1; | ||||||
|  |     const uint8_t Socket::kCloseRequest = 2; | ||||||
|     constexpr size_t Socket::kChunkSize; |     constexpr size_t Socket::kChunkSize; | ||||||
|  |  | ||||||
|     Socket::Socket(int fd) : |     Socket::Socket(int fd) : | ||||||
| @@ -44,7 +46,34 @@ namespace ix | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int ret = select(timeoutSecs, 0); |         PollResultType pollResult = select(timeoutSecs, 0); | ||||||
|  |  | ||||||
|  |         if (onPollCallback) onPollCallback(pollResult); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     PollResultType Socket::select(int timeoutSecs, int timeoutMs) | ||||||
|  |     { | ||||||
|  |         fd_set rfds; | ||||||
|  |         FD_ZERO(&rfds); | ||||||
|  |         FD_SET(_sockfd, &rfds); | ||||||
|  |  | ||||||
|  |         // File descriptor at index 0 in _fildes is the read end of the pipe | ||||||
|  |         int eventfd = _eventfd.getFd(); | ||||||
|  |         if (eventfd != -1) | ||||||
|  |         { | ||||||
|  |             FD_SET(eventfd, &rfds); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         struct timeval timeout; | ||||||
|  |         timeout.tv_sec = timeoutSecs; | ||||||
|  |         timeout.tv_usec = 1000 * timeoutMs; | ||||||
|  |  | ||||||
|  |         // Compute the highest fd. | ||||||
|  |         int sockfd = _sockfd; | ||||||
|  |         int nfds = (std::max)(sockfd, eventfd); | ||||||
|  |  | ||||||
|  |         int ret = ::select(nfds + 1, &rfds, nullptr, nullptr, | ||||||
|  |                            (timeoutSecs < 0) ? nullptr : &timeout); | ||||||
|  |  | ||||||
|         PollResultType pollResult = PollResultType_ReadyForRead; |         PollResultType pollResult = PollResultType_ReadyForRead; | ||||||
|         if (ret < 0) |         if (ret < 0) | ||||||
| @@ -55,35 +84,27 @@ namespace ix | |||||||
|         { |         { | ||||||
|             pollResult = PollResultType_Timeout; |             pollResult = PollResultType_Timeout; | ||||||
|         } |         } | ||||||
|  |         else if (eventfd != -1 && FD_ISSET(eventfd, &rfds)) | ||||||
|  |         { | ||||||
|  |             uint8_t value = _eventfd.read(); | ||||||
|  |  | ||||||
|         if (onPollCallback) onPollCallback(pollResult); |             if (value == kSendRequest) | ||||||
|  |             { | ||||||
|  |                 pollResult = PollResultType_SendRequest; | ||||||
|  |             } | ||||||
|  |             else if (value == kCloseRequest) | ||||||
|  |             { | ||||||
|  |                 pollResult = PollResultType_CloseRequest; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return pollResult; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     int Socket::select(int timeoutSecs, int timeoutMs) |     // Wake up from poll/select by writing to the pipe which is watched by select | ||||||
|  |     bool Socket::wakeUpFromPoll(uint8_t wakeUpCode) | ||||||
|     { |     { | ||||||
|         fd_set rfds; |         return _eventfd.notify(wakeUpCode); | ||||||
|         FD_ZERO(&rfds); |  | ||||||
|         FD_SET(_sockfd, &rfds); |  | ||||||
|  |  | ||||||
| #ifdef __linux__ |  | ||||||
|         FD_SET(_eventfd.getFd(), &rfds); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|         struct timeval timeout; |  | ||||||
|         timeout.tv_sec = timeoutSecs; |  | ||||||
|         timeout.tv_usec = 1000 * timeoutMs; |  | ||||||
|  |  | ||||||
|         int sockfd = _sockfd; |  | ||||||
|         int nfds = (std::max)(sockfd, _eventfd.getFd()); |  | ||||||
|         int ret = ::select(nfds + 1, &rfds, nullptr, nullptr, |  | ||||||
|                            (timeoutSecs < 0) ? nullptr : &timeout); |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void Socket::wakeUpFromPoll() |  | ||||||
|     { |  | ||||||
|         // this will wake up the thread blocked on select, only needed on Linux |  | ||||||
|         _eventfd.notify(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Socket::connect(const std::string& host, |     bool Socket::connect(const std::string& host, | ||||||
|   | |||||||
| @@ -17,9 +17,9 @@ | |||||||
| typedef SSIZE_T ssize_t; | typedef SSIZE_T ssize_t; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "IXEventFd.h" |  | ||||||
| #include "IXCancellationRequest.h" | #include "IXCancellationRequest.h" | ||||||
| #include "IXProgressCallback.h" | #include "IXProgressCallback.h" | ||||||
|  | #include "IXEventFd.h" | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
| @@ -27,7 +27,9 @@ namespace ix | |||||||
|     { |     { | ||||||
|         PollResultType_ReadyForRead = 0, |         PollResultType_ReadyForRead = 0, | ||||||
|         PollResultType_Timeout = 1, |         PollResultType_Timeout = 1, | ||||||
|         PollResultType_Error = 2 |         PollResultType_Error = 2, | ||||||
|  |         PollResultType_SendRequest = 3, | ||||||
|  |         PollResultType_CloseRequest = 4 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class Socket { |     class Socket { | ||||||
| @@ -39,10 +41,10 @@ namespace ix | |||||||
|  |  | ||||||
|         void configure(); |         void configure(); | ||||||
|  |  | ||||||
|         int select(int timeoutSecs, int timeoutMs); |         PollResultType select(int timeoutSecs, int timeoutMs); | ||||||
|         virtual void poll(const OnPollCallback& onPollCallback, |         virtual void poll(const OnPollCallback& onPollCallback, | ||||||
|                           int timeoutSecs = kDefaultPollTimeout); |                           int timeoutSecs = kDefaultPollTimeout); | ||||||
|         virtual void wakeUpFromPoll(); |         virtual bool wakeUpFromPoll(uint8_t wakeUpCode); | ||||||
|  |  | ||||||
|         // Virtual methods |         // Virtual methods | ||||||
|         virtual bool connect(const std::string& url, |         virtual bool connect(const std::string& url, | ||||||
| @@ -73,12 +75,15 @@ namespace ix | |||||||
|         static bool init(); // Required on Windows to initialize WinSocket |         static bool init(); // Required on Windows to initialize WinSocket | ||||||
|         static void cleanup(); // Required on Windows to cleanup WinSocket |         static void cleanup(); // Required on Windows to cleanup WinSocket | ||||||
|  |  | ||||||
|  |         // Used as special codes for pipe communication | ||||||
|  |         static const uint8_t kSendRequest; | ||||||
|  |         static const uint8_t kCloseRequest; | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         void closeSocket(int fd); |         void closeSocket(int fd); | ||||||
|  |  | ||||||
|         std::atomic<int> _sockfd; |         std::atomic<int> _sockfd; | ||||||
|         std::mutex _socketMutex; |         std::mutex _socketMutex; | ||||||
|         EventFd _eventfd; |  | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         static const int kDefaultPollTimeout; |         static const int kDefaultPollTimeout; | ||||||
| @@ -87,5 +92,7 @@ namespace ix | |||||||
|         // Buffer for reading from our socket. That buffer is never resized. |         // Buffer for reading from our socket. That buffer is never resized. | ||||||
|         std::vector<uint8_t> _readBuffer; |         std::vector<uint8_t> _readBuffer; | ||||||
|         static constexpr size_t kChunkSize = 1 << 15; |         static constexpr size_t kChunkSize = 1 << 15; | ||||||
|  |  | ||||||
|  |         EventFd _eventfd; | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -379,4 +379,9 @@ namespace ix | |||||||
|     { |     { | ||||||
|         _automaticReconnection = false; |         _automaticReconnection = false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     size_t WebSocket::bufferedAmount() const | ||||||
|  |     { | ||||||
|  |         return _ws.bufferedAmount(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -112,6 +112,7 @@ namespace ix | |||||||
|         const std::string& getUrl() const; |         const std::string& getUrl() const; | ||||||
|         const WebSocketPerMessageDeflateOptions& getPerMessageDeflateOptions() const; |         const WebSocketPerMessageDeflateOptions& getPerMessageDeflateOptions() const; | ||||||
|         int getHeartBeatPeriod() const; |         int getHeartBeatPeriod() const; | ||||||
|  |         size_t bufferedAmount() const; | ||||||
|  |  | ||||||
|         void enableAutomaticReconnection(); |         void enableAutomaticReconnection(); | ||||||
|         void disableAutomaticReconnection(); |         void disableAutomaticReconnection(); | ||||||
|   | |||||||
| @@ -1,7 +1,31 @@ | |||||||
|  | /* | ||||||
|  |  * The MIT License (MIT) | ||||||
|  |  *  | ||||||
|  |  * Copyright (c) 2012, 2013 <dhbaird@gmail.com> | ||||||
|  |  *  | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  *  IXWebSocketTransport.cpp |  *  IXWebSocketTransport.cpp | ||||||
|  *  Author: Benjamin Sergeant |  *  Author: Benjamin Sergeant | ||||||
|  *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. |  *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| // | // | ||||||
| @@ -14,14 +38,6 @@ | |||||||
| #include "IXUrlParser.h" | #include "IXUrlParser.h" | ||||||
| #include "IXSocketFactory.h" | #include "IXSocketFactory.h" | ||||||
|  |  | ||||||
| #ifdef IXWEBSOCKET_USE_TLS |  | ||||||
| # ifdef __APPLE__ |  | ||||||
| #  include "IXSocketAppleSSL.h" |  | ||||||
| # else |  | ||||||
| #  include "IXSocketOpenSSL.h" |  | ||||||
| # endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
| @@ -80,16 +96,6 @@ namespace ix | |||||||
|                                        std::string("Could not parse URL ") + url); |                                        std::string("Could not parse URL ") + url); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (protocol != "ws" && protocol != "wss") |  | ||||||
|         { |  | ||||||
|             std::stringstream ss; |  | ||||||
|             ss << "Invalid protocol: " << protocol |  | ||||||
|                << " for url " << url |  | ||||||
|                << " . Supported protocols are ws and wss"; |  | ||||||
|  |  | ||||||
|             return WebSocketInitResult(false, 0, ss.str()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         bool tls = protocol == "wss"; |         bool tls = protocol == "wss"; | ||||||
|         std::string errorMsg; |         std::string errorMsg; | ||||||
|         _socket = createSocket(tls, errorMsg); |         _socket = createSocket(tls, errorMsg); | ||||||
| @@ -184,38 +190,57 @@ namespace ix | |||||||
|                     std::stringstream ss; |                     std::stringstream ss; | ||||||
|                     ss << kHeartBeatPingMessage << "::" << _heartBeatPeriod << "s"; |                     ss << kHeartBeatPingMessage << "::" << _heartBeatPeriod << "s"; | ||||||
|                     sendPing(ss.str()); |                     sendPing(ss.str()); | ||||||
|                     return; |  | ||||||
|                 } |                 } | ||||||
|  |                 // Make sure we send all the buffered data | ||||||
|                 while (true) |                 // there can be a lot of it for large messages. | ||||||
|  |                 else if (pollResult == PollResultType_SendRequest) | ||||||
|                 { |                 { | ||||||
|                     ssize_t ret = _socket->recv((char*)&_readbuf[0], _readbuf.size()); |                     while (!isSendBufferEmpty() && !_requestInitCancellation) | ||||||
|  |                     { | ||||||
|  |                         sendOnSocket(); | ||||||
|  |  | ||||||
|                     if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK || |                         // Sleep 10ms between each send so that we dont busy loop | ||||||
|                                     _socket->getErrno() == EAGAIN)) |                         // A better strategy would be to select on the socket to  | ||||||
|                     { |                         // check whether we can write to it without blocking | ||||||
|                         break; |                         std::chrono::duration<double, std::micro> duration(10); | ||||||
|                     } |                         std::this_thread::sleep_for(duration); | ||||||
|                     else if (ret <= 0) |  | ||||||
|                     { |  | ||||||
|                         _rxbuf.clear(); |  | ||||||
|                         _socket->close(); |  | ||||||
|                         setReadyState(CLOSED); |  | ||||||
|                         break; |  | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         _rxbuf.insert(_rxbuf.end(), |  | ||||||
|                                       _readbuf.begin(), |  | ||||||
|                                       _readbuf.begin() + ret); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                 else if (pollResult == PollResultType_ReadyForRead) | ||||||
|  |                 { | ||||||
|  |                     while (true) | ||||||
|  |                     { | ||||||
|  |                         ssize_t ret = _socket->recv((char*)&_readbuf[0], _readbuf.size()); | ||||||
|  |  | ||||||
|                 if (isSendBufferEmpty() && _readyState == CLOSING) |                         if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK || | ||||||
|  |                                         _socket->getErrno() == EAGAIN)) | ||||||
|  |                         { | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                         else if (ret <= 0) | ||||||
|  |                         { | ||||||
|  |                             _rxbuf.clear(); | ||||||
|  |                             _socket->close(); | ||||||
|  |                             setReadyState(CLOSED); | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                             _rxbuf.insert(_rxbuf.end(), | ||||||
|  |                                           _readbuf.begin(), | ||||||
|  |                                           _readbuf.begin() + ret); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else if (pollResult == PollResultType_Error) | ||||||
|                 { |                 { | ||||||
|                     _socket->close(); |                     _socket->close(); | ||||||
|                     setReadyState(CLOSED); |  | ||||||
|                 } |                 } | ||||||
|  |                 else if (pollResult == PollResultType_CloseRequest) | ||||||
|  |                 { | ||||||
|  |                     ; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|             }, |             }, | ||||||
|             _heartBeatPeriod); |             _heartBeatPeriod); | ||||||
|     } |     } | ||||||
| @@ -586,11 +611,11 @@ namespace ix | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Make sure we send all the buffered data ; there can be a lot of it |         // Request to flush the send buffer on the background thread if it isn't empty | ||||||
|         // for large messages. |         if (!isSendBufferEmpty()) | ||||||
|         // TODO / this will block the sending thread ; we need to eval whether |         { | ||||||
|         //        this is the right fix |             _socket->wakeUpFromPoll(Socket::kSendRequest); | ||||||
|         while (!isSendBufferEmpty()) sendOnSocket(); |         } | ||||||
|  |  | ||||||
|         return WebSocketSendInfo(true, compressionError, payloadSize, wireSize); |         return WebSocketSendInfo(true, compressionError, payloadSize, wireSize); | ||||||
|     } |     } | ||||||
| @@ -737,8 +762,17 @@ namespace ix | |||||||
|         sendData(wsheader_type::CLOSE, normalClosure, compress); |         sendData(wsheader_type::CLOSE, normalClosure, compress); | ||||||
|         setReadyState(CLOSING); |         setReadyState(CLOSING); | ||||||
|  |  | ||||||
|         _socket->wakeUpFromPoll(); |         _socket->wakeUpFromPoll(Socket::kCloseRequest); | ||||||
|         _socket->close(); |         _socket->close(); | ||||||
|  |  | ||||||
|  |         _closeCode = 1000; | ||||||
|  |         setReadyState(CLOSED); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     size_t WebSocketTransport::bufferedAmount() const | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(_txbufMutex); | ||||||
|  |         return _txbuf.size(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -77,6 +77,7 @@ namespace ix | |||||||
|         void setReadyState(ReadyStateValues readyStateValue); |         void setReadyState(ReadyStateValues readyStateValue); | ||||||
|         void setOnCloseCallback(const OnCloseCallback& onCloseCallback); |         void setOnCloseCallback(const OnCloseCallback& onCloseCallback); | ||||||
|         void dispatch(const OnMessageCallback& onMessageCallback); |         void dispatch(const OnMessageCallback& onMessageCallback); | ||||||
|  |         size_t bufferedAmount() const; | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         std::string _url; |         std::string _url; | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								makefile
									
									
									
									
									
								
							| @@ -8,10 +8,10 @@ brew: | |||||||
|  |  | ||||||
| .PHONY: docker | .PHONY: docker | ||||||
| docker: | docker: | ||||||
| 	docker build -t broadcast_server:latest . | 	docker build -t ws:latest . | ||||||
|  |  | ||||||
| run: | run: | ||||||
| 	docker run --cap-add sys_ptrace -it broadcast_server:latest bash | 	docker run --cap-add sys_ptrace -it ws:latest | ||||||
|  |  | ||||||
| # this is helpful to remove trailing whitespaces | # this is helpful to remove trailing whitespaces | ||||||
| trail: | trail: | ||||||
| @@ -36,6 +36,9 @@ test_server: | |||||||
| test: | test: | ||||||
| 	python test/run.py | 	python test/run.py | ||||||
|  |  | ||||||
|  | ws_test: | ||||||
|  | 	(cd ws ; sh test_ws.sh) | ||||||
|  |  | ||||||
| # For the fork that is configured with appveyor | # For the fork that is configured with appveyor | ||||||
| rebase_upstream: | rebase_upstream: | ||||||
| 	git fetch upstream | 	git fetch upstream | ||||||
| @@ -43,5 +46,9 @@ rebase_upstream: | |||||||
| 	git reset --hard upstream/master | 	git reset --hard upstream/master | ||||||
| 	git push origin master --force | 	git push origin master --force | ||||||
|  |  | ||||||
|  | install_cmake_for_linux: | ||||||
|  | 	mkdir -p /tmp/cmake | ||||||
|  | 	(cd /tmp/cmake ; curl -L -O https://github.com/Kitware/CMake/releases/download/v3.14.0-rc4/cmake-3.14.0-rc4-Linux-x86_64.tar.gz ; tar zxf cmake-3.14.0-rc4-Linux-x86_64.tar.gz) | ||||||
|  |  | ||||||
| .PHONY: test | .PHONY: test | ||||||
| .PHONY: build | .PHONY: build | ||||||
|   | |||||||
| @@ -66,7 +66,13 @@ TEST_CASE("socket", "[socket]") | |||||||
|         std::shared_ptr<Socket> socket(new Socket); |         std::shared_ptr<Socket> socket(new Socket); | ||||||
|         std::string host("www.google.com"); |         std::string host("www.google.com"); | ||||||
|         int port = 80; |         int port = 80; | ||||||
|         std::string request("GET / HTTP/1.1\r\n\r\n"); |  | ||||||
|  |         std::stringstream ss; | ||||||
|  |         ss << "GET / HTTP/1.1\r\n"; | ||||||
|  |         ss << "Host: " << host << "\r\n"; | ||||||
|  |         ss << "\r\n"; | ||||||
|  |         std::string request(ss.str()); | ||||||
|  |  | ||||||
|         int expectedStatus = 200; |         int expectedStatus = 200; | ||||||
|         int timeoutSecs = 3; |         int timeoutSecs = 3; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -164,10 +164,21 @@ namespace | |||||||
|                     ss << "cmd_websocket_chat: Error ! " << error.reason; |                     ss << "cmd_websocket_chat: Error ! " << error.reason; | ||||||
|                     log(ss.str()); |                     log(ss.str()); | ||||||
|                 } |                 } | ||||||
|  |                 else if (messageType == ix::WebSocket_MessageType_Ping) | ||||||
|  |                 { | ||||||
|  |                     log("cmd_websocket_chat: received ping message"); | ||||||
|  |                 } | ||||||
|  |                 else if (messageType == ix::WebSocket_MessageType_Pong) | ||||||
|  |                 { | ||||||
|  |                     log("cmd_websocket_chat: received pong message"); | ||||||
|  |                 } | ||||||
|  |                 else if (messageType == ix::WebSocket_MessageType_Fragment) | ||||||
|  |                 { | ||||||
|  |                     log("cmd_websocket_chat: received message fragment"); | ||||||
|  |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     // FIXME: missing ping/pong messages |                     ss << "Unexpected ix::WebSocketMessageType"; | ||||||
|                     ss << "Invalid ix::WebSocketMessageType"; |  | ||||||
|                     log(ss.str()); |                     log(ss.str()); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								test/run.py
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								test/run.py
									
									
									
									
									
								
							| @@ -6,10 +6,10 @@ osName = platform.system() | |||||||
| print('os name = {}'.format(osName)) | print('os name = {}'.format(osName)) | ||||||
|  |  | ||||||
| root = os.path.dirname(os.path.realpath(__file__)) | root = os.path.dirname(os.path.realpath(__file__)) | ||||||
| buildDir = os.path.join(root, 'build') | buildDir = os.path.join(root, 'build', osName) | ||||||
|  |  | ||||||
| if not os.path.exists(buildDir): | if not os.path.exists(buildDir): | ||||||
|     os.mkdir(buildDir) |     os.makedirs(buildDir) | ||||||
|  |  | ||||||
| os.chdir(buildDir) | os.chdir(buildDir) | ||||||
|  |  | ||||||
| @@ -38,7 +38,7 @@ sanitizerFlags = sanitizersFlags[sanitizer] | |||||||
| #     os.environ['CC'] = 'clang-cl' | #     os.environ['CC'] = 'clang-cl' | ||||||
| #     os.environ['CXX'] = 'clang-cl' | #     os.environ['CXX'] = 'clang-cl' | ||||||
|  |  | ||||||
| cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug {} {} ..'.format(generator, sanitizerFlags) | cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug {} {} ../..'.format(generator, sanitizerFlags) | ||||||
| print(cmakeCmd) | print(cmakeCmd) | ||||||
| ret = os.system(cmakeCmd) | ret = os.system(cmakeCmd) | ||||||
| assert ret == 0, 'CMake failed, exiting' | assert ret == 0, 'CMake failed, exiting' | ||||||
| @@ -67,6 +67,7 @@ def findFiles(prefix): | |||||||
|  |  | ||||||
| # We need to copy the zlib DLL in the current work directory | # We need to copy the zlib DLL in the current work directory | ||||||
| shutil.copy(os.path.join( | shutil.copy(os.path.join( | ||||||
|  |     '..', | ||||||
|     '..', |     '..', | ||||||
|     '..', |     '..', | ||||||
|     'third_party', |     'third_party', | ||||||
| @@ -77,6 +78,8 @@ shutil.copy(os.path.join( | |||||||
|     'bin', |     'bin', | ||||||
|     'zlib.dll'), '.') |     'zlib.dll'), '.') | ||||||
|  |  | ||||||
| testCommand = '{} {}'.format(testBinary, os.getenv('TEST', '')) | lldb = "lldb --batch -o 'run' -k 'thread backtrace all' -k 'quit 1'" | ||||||
|  | lldb = ""  # Disabled for now | ||||||
|  | testCommand = '{} {} {}'.format(lldb, testBinary, os.getenv('TEST', '')) | ||||||
| ret = os.system(testCommand) | ret = os.system(testCommand) | ||||||
| assert ret == 0, 'Test command failed' | assert ret == 0, 'Test command failed' | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								ws/test_ws.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								ws/test_ws.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | rm -rf /tmp/ws_test | ||||||
|  | mkdir -p /tmp/ws_test | ||||||
|  |  | ||||||
|  | # Start a transport server | ||||||
|  | cd /tmp/ws_test | ||||||
|  | ws transfer --port 8090 --pidfile /tmp/ws_test/pidfile & | ||||||
|  |  | ||||||
|  | # Wait until the transfer server is up  | ||||||
|  | while true | ||||||
|  | do | ||||||
|  |     nc -zv 127.0.0.1 8090 && { | ||||||
|  |         echo "Transfer server up and running" | ||||||
|  |         break | ||||||
|  |     } | ||||||
|  |     echo "sleep ..." | ||||||
|  |     sleep 0.1 | ||||||
|  | done | ||||||
|  |  | ||||||
|  | # Start a receiver | ||||||
|  | mkdir -p /tmp/ws_test/receive | ||||||
|  | cd /tmp/ws_test/receive | ||||||
|  | ws receive ws://127.0.0.1:8090 & | ||||||
|  |  | ||||||
|  | mkdir /tmp/ws_test/send | ||||||
|  | cd /tmp/ws_test/send | ||||||
|  | # mkfile 10m 10M_file | ||||||
|  | dd if=/dev/urandom of=10M_file count=10000 bs=1024 | ||||||
|  |  | ||||||
|  | # Start the sender job | ||||||
|  | ws send ws://127.0.0.1:8090 10M_file | ||||||
|  |  | ||||||
|  | # Wait until the file has been written to disk | ||||||
|  | while true | ||||||
|  | do | ||||||
|  |     if test -f /tmp/ws_test/receive/10M_file ; then | ||||||
|  |         echo "Received file does exists, exiting loop" | ||||||
|  |         break | ||||||
|  |     fi | ||||||
|  |     echo "sleep ..." | ||||||
|  |     sleep 0.1 | ||||||
|  | done | ||||||
|  |  | ||||||
|  | cksum /tmp/ws_test/send/10M_file | ||||||
|  | cksum /tmp/ws_test/receive/10M_file | ||||||
|  |  | ||||||
|  | # Give some time to ws receive to terminate | ||||||
|  | sleep 2 | ||||||
|  |  | ||||||
|  | # Cleanup | ||||||
|  | kill `cat /tmp/ws_test/pidfile` | ||||||
							
								
								
									
										28
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -16,6 +16,8 @@ | |||||||
| #include <string> | #include <string> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <iostream> | #include <iostream> | ||||||
|  | #include <fstream> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
| #include <cli11/CLI11.hpp> | #include <cli11/CLI11.hpp> | ||||||
| #include <ixwebsocket/IXSocket.h> | #include <ixwebsocket/IXSocket.h> | ||||||
| @@ -32,6 +34,7 @@ int main(int argc, char** argv) | |||||||
|     std::string headers; |     std::string headers; | ||||||
|     std::string output; |     std::string output; | ||||||
|     std::string hostname("127.0.0.1"); |     std::string hostname("127.0.0.1"); | ||||||
|  |     std::string pidfile; | ||||||
|     bool headersOnly = false; |     bool headersOnly = false; | ||||||
|     bool followRedirects = false; |     bool followRedirects = false; | ||||||
|     bool verbose = false; |     bool verbose = false; | ||||||
| @@ -51,6 +54,8 @@ int main(int argc, char** argv) | |||||||
|  |  | ||||||
|     CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server"); |     CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server"); | ||||||
|     transferApp->add_option("--port", port, "Connection url"); |     transferApp->add_option("--port", port, "Connection url"); | ||||||
|  |     transferApp->add_option("--host", hostname, "Hostname"); | ||||||
|  |     transferApp->add_option("--pidfile", pidfile, "Pid file"); | ||||||
|  |  | ||||||
|     CLI::App* connectApp = app.add_subcommand("connect", "Connect to a remote server"); |     CLI::App* connectApp = app.add_subcommand("connect", "Connect to a remote server"); | ||||||
|     connectApp->add_option("url", url, "Connection url")->required(); |     connectApp->add_option("url", url, "Connection url")->required(); | ||||||
| @@ -60,11 +65,12 @@ int main(int argc, char** argv) | |||||||
|     chatApp->add_option("user", user, "User name")->required(); |     chatApp->add_option("user", user, "User name")->required(); | ||||||
|  |  | ||||||
|     CLI::App* echoServerApp = app.add_subcommand("echo_server", "Echo server"); |     CLI::App* echoServerApp = app.add_subcommand("echo_server", "Echo server"); | ||||||
|     echoServerApp->add_option("--port", port, "Connection url"); |     echoServerApp->add_option("--port", port, "Port"); | ||||||
|  |     echoServerApp->add_option("--host", hostname, "Hostname"); | ||||||
|  |  | ||||||
|     CLI::App* broadcastServerApp = app.add_subcommand("broadcast_server", "Broadcasting server"); |     CLI::App* broadcastServerApp = app.add_subcommand("broadcast_server", "Broadcasting server"); | ||||||
|     broadcastServerApp->add_option("--port", port, "Connection url"); |     broadcastServerApp->add_option("--port", port, "Port"); | ||||||
|     broadcastServerApp->add_option("--hostname", hostname, "Hostname"); |     broadcastServerApp->add_option("--host", hostname, "Hostname"); | ||||||
|  |  | ||||||
|     CLI::App* pingPongApp = app.add_subcommand("ping", "Ping pong"); |     CLI::App* pingPongApp = app.add_subcommand("ping", "Ping pong"); | ||||||
|     pingPongApp->add_option("url", url, "Connection url")->required(); |     pingPongApp->add_option("url", url, "Connection url")->required(); | ||||||
| @@ -88,9 +94,21 @@ int main(int argc, char** argv) | |||||||
|  |  | ||||||
|     ix::Socket::init(); |     ix::Socket::init(); | ||||||
|  |  | ||||||
|  |     // pid file handling | ||||||
|  |  | ||||||
|     if (app.got_subcommand("transfer")) |     if (app.got_subcommand("transfer")) | ||||||
|     { |     { | ||||||
|         return ix::ws_transfer_main(port); |         if (!pidfile.empty()) | ||||||
|  |         { | ||||||
|  |             unlink(pidfile.c_str()); | ||||||
|  |  | ||||||
|  |             std::ofstream f; | ||||||
|  |             f.open(pidfile); | ||||||
|  |             f << getpid(); | ||||||
|  |             f.close(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return ix::ws_transfer_main(port, hostname); | ||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("send")) |     else if (app.got_subcommand("send")) | ||||||
|     { |     { | ||||||
| @@ -111,7 +129,7 @@ int main(int argc, char** argv) | |||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("echo_server")) |     else if (app.got_subcommand("echo_server")) | ||||||
|     { |     { | ||||||
|         return ix::ws_echo_server_main(port); |         return ix::ws_echo_server_main(port, hostname); | ||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("broadcast_server")) |     else if (app.got_subcommand("broadcast_server")) | ||||||
|     { |     { | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								ws/ws.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								ws/ws.h
									
									
									
									
									
								
							| @@ -24,9 +24,9 @@ namespace ix | |||||||
|  |  | ||||||
|     int ws_ping_pong_main(const std::string& url); |     int ws_ping_pong_main(const std::string& url); | ||||||
|  |  | ||||||
|     int ws_echo_server_main(int port); |     int ws_echo_server_main(int port, const std::string& hostname); | ||||||
|  |  | ||||||
|     int ws_broadcast_server_main(int port, const std::string& hostname); |     int ws_broadcast_server_main(int port, const std::string& hostname); | ||||||
|  |     int ws_transfer_main(int port, const std::string& hostname); | ||||||
|  |  | ||||||
|     int ws_chat_main(const std::string& url, |     int ws_chat_main(const std::string& url, | ||||||
|                      const std::string& user); |                      const std::string& user); | ||||||
| @@ -36,8 +36,6 @@ namespace ix | |||||||
|     int ws_receive_main(const std::string& url, |     int ws_receive_main(const std::string& url, | ||||||
|                         bool enablePerMessageDeflate); |                         bool enablePerMessageDeflate); | ||||||
|  |  | ||||||
|     int ws_transfer_main(int port); |  | ||||||
|  |  | ||||||
|     int ws_send_main(const std::string& url, |     int ws_send_main(const std::string& url, | ||||||
|                      const std::string& path); |                      const std::string& path); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -71,6 +71,15 @@ namespace ix | |||||||
|                                                   << " out of " << total << std::endl; |                                                   << " out of " << total << std::endl; | ||||||
|                                         return true; |                                         return true; | ||||||
|                                     }); |                                     }); | ||||||
|  |  | ||||||
|  |                                     do | ||||||
|  |                                     { | ||||||
|  |                                         size_t bufferedAmount = client->bufferedAmount(); | ||||||
|  |                                         std::cerr << bufferedAmount << " bytes left to be sent" << std::endl; | ||||||
|  |  | ||||||
|  |                                         std::chrono::duration<double, std::milli> duration(10); | ||||||
|  |                                         std::this_thread::sleep_for(duration); | ||||||
|  |                                     } while (client->bufferedAmount() != 0); | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|   | |||||||
| @@ -10,11 +10,11 @@ | |||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     int ws_echo_server_main(int port) |     int ws_echo_server_main(int port, const std::string& hostname) | ||||||
|     { |     { | ||||||
|         std::cout << "Listening on port " << port << std::endl; |         std::cout << "Listening on " << hostname << ":" << port << std::endl; | ||||||
|  |  | ||||||
|         ix::WebSocketServer server(port); |         ix::WebSocketServer server(port, hostname); | ||||||
|  |  | ||||||
|         server.setOnConnectionCallback( |         server.setOnConnectionCallback( | ||||||
|             [](std::shared_ptr<ix::WebSocket> webSocket) |             [](std::shared_ptr<ix::WebSocket> webSocket) | ||||||
|   | |||||||
| @@ -146,11 +146,16 @@ namespace ix | |||||||
|         std::string filename = data["filename"].string_value(); |         std::string filename = data["filename"].string_value(); | ||||||
|         filename = extractFilename(filename); |         filename = extractFilename(filename); | ||||||
|  |  | ||||||
|         std::cout << "Writing to disk: " << filename << std::endl; |         std::string filenameTmp = filename + ".tmp"; | ||||||
|         std::ofstream out(filename); |  | ||||||
|  |         std::cout << "Writing to disk: " << filenameTmp << std::endl; | ||||||
|  |         std::ofstream out(filenameTmp); | ||||||
|         out.write((char*)&content.front(), content.size()); |         out.write((char*)&content.front(), content.size()); | ||||||
|         out.close(); |         out.close(); | ||||||
|  |  | ||||||
|  |         std::cout << "Renaming " << filenameTmp << " to " << filename << std::endl; | ||||||
|  |         rename(filenameTmp.c_str(), filename.c_str()); | ||||||
|  |  | ||||||
|         std::map<MsgPack, MsgPack> pdu; |         std::map<MsgPack, MsgPack> pdu; | ||||||
|         pdu["ack"] = true; |         pdu["ack"] = true; | ||||||
|         pdu["id"] = data["id"]; |         pdu["id"] = data["id"]; | ||||||
|   | |||||||
| @@ -257,6 +257,15 @@ namespace ix | |||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         do | ||||||
|  |         { | ||||||
|  |             size_t bufferedAmount = _webSocket.bufferedAmount(); | ||||||
|  |             std::cout << bufferedAmount << " bytes left to be sent" << std::endl; | ||||||
|  |  | ||||||
|  |             std::chrono::duration<double, std::milli> duration(10); | ||||||
|  |             std::this_thread::sleep_for(duration); | ||||||
|  |         } while (_webSocket.bufferedAmount() != 0); | ||||||
|  |  | ||||||
|         bench.report(); |         bench.report(); | ||||||
|         auto duration = bench.getDuration(); |         auto duration = bench.getDuration(); | ||||||
|         auto transferRate = 1000 * content.size() / duration; |         auto transferRate = 1000 * content.size() / duration; | ||||||
|   | |||||||
| @@ -10,11 +10,11 @@ | |||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     int ws_transfer_main(int port) |     int ws_transfer_main(int port, const std::string& hostname) | ||||||
|     { |     { | ||||||
|         std::cout << "Listening on port " << port << std::endl; |         std::cout << "Listening on " << hostname << ":" << port << std::endl; | ||||||
|  |  | ||||||
|         ix::WebSocketServer server(port); |         ix::WebSocketServer server(port, hostname); | ||||||
|  |  | ||||||
|         server.setOnConnectionCallback( |         server.setOnConnectionCallback( | ||||||
|             [&server](std::shared_ptr<ix::WebSocket> webSocket) |             [&server](std::shared_ptr<ix::WebSocket> webSocket) | ||||||
| @@ -70,6 +70,15 @@ namespace ix | |||||||
|                                                   << " out of " << total << std::endl; |                                                   << " out of " << total << std::endl; | ||||||
|                                         return true; |                                         return true; | ||||||
|                                     }); |                                     }); | ||||||
|  |  | ||||||
|  |                                     do | ||||||
|  |                                     { | ||||||
|  |                                         size_t bufferedAmount = client->bufferedAmount(); | ||||||
|  |                                         std::cerr << bufferedAmount << " bytes left to be sent" << std::endl; | ||||||
|  |  | ||||||
|  |                                         std::chrono::duration<double, std::milli> duration(10); | ||||||
|  |                                         std::this_thread::sleep_for(duration); | ||||||
|  |                                     } while (client->bufferedAmount() != 0); | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user