65 changed files with 356 additions and 3007 deletions
-
4CMakeLists.txt
-
124libs/libixwebsocket/include/ixwebsocket/IXBase64.h
-
32libs/libixwebsocket/include/ixwebsocket/IXBench.h
-
18libs/libixwebsocket/include/ixwebsocket/IXCancellationRequest.h
-
54libs/libixwebsocket/include/ixwebsocket/IXConnectionState.h
-
67libs/libixwebsocket/include/ixwebsocket/IXDNSLookup.h
-
16libs/libixwebsocket/include/ixwebsocket/IXExponentialBackoff.h
-
12libs/libixwebsocket/include/ixwebsocket/IXGetFreePort.h
-
15libs/libixwebsocket/include/ixwebsocket/IXGzipCodec.h
-
134libs/libixwebsocket/include/ixwebsocket/IXHttp.h
-
123libs/libixwebsocket/include/ixwebsocket/IXHttpClient.h
-
59libs/libixwebsocket/include/ixwebsocket/IXHttpServer.h
-
87libs/libixwebsocket/include/ixwebsocket/IXNetSystem.h
-
16libs/libixwebsocket/include/ixwebsocket/IXProgressCallback.h
-
35libs/libixwebsocket/include/ixwebsocket/IXSelectInterrupt.h
-
39libs/libixwebsocket/include/ixwebsocket/IXSelectInterruptEvent.h
-
16libs/libixwebsocket/include/ixwebsocket/IXSelectInterruptFactory.h
-
40libs/libixwebsocket/include/ixwebsocket/IXSelectInterruptPipe.h
-
12libs/libixwebsocket/include/ixwebsocket/IXSetThreadName.h
-
99libs/libixwebsocket/include/ixwebsocket/IXSocket.h
-
31libs/libixwebsocket/include/ixwebsocket/IXSocketConnect.h
-
21libs/libixwebsocket/include/ixwebsocket/IXSocketFactory.h
-
130libs/libixwebsocket/include/ixwebsocket/IXSocketServer.h
-
54libs/libixwebsocket/include/ixwebsocket/IXSocketTLSOptions.h
-
25libs/libixwebsocket/include/ixwebsocket/IXStrCaseCompare.h
-
45libs/libixwebsocket/include/ixwebsocket/IXUdpSocket.h
-
18libs/libixwebsocket/include/ixwebsocket/IXUniquePtr.h
-
23libs/libixwebsocket/include/ixwebsocket/IXUrlParser.h
-
14libs/libixwebsocket/include/ixwebsocket/IXUserAgent.h
-
178libs/libixwebsocket/include/ixwebsocket/IXUtf8Validator.h
-
17libs/libixwebsocket/include/ixwebsocket/IXUuid.h
-
180libs/libixwebsocket/include/ixwebsocket/IXWebSocket.h
-
37libs/libixwebsocket/include/ixwebsocket/IXWebSocketCloseConstants.h
-
28libs/libixwebsocket/include/ixwebsocket/IXWebSocketCloseInfo.h
-
22libs/libixwebsocket/include/ixwebsocket/IXWebSocketErrorInfo.h
-
54libs/libixwebsocket/include/ixwebsocket/IXWebSocketHandshake.h
-
171libs/libixwebsocket/include/ixwebsocket/IXWebSocketHandshakeKeyGen.h
-
23libs/libixwebsocket/include/ixwebsocket/IXWebSocketHttpHeaders.h
-
36libs/libixwebsocket/include/ixwebsocket/IXWebSocketInitResult.h
-
60libs/libixwebsocket/include/ixwebsocket/IXWebSocketMessage.h
-
21libs/libixwebsocket/include/ixwebsocket/IXWebSocketMessageType.h
-
31libs/libixwebsocket/include/ixwebsocket/IXWebSocketOpenInfo.h
-
64libs/libixwebsocket/include/ixwebsocket/IXWebSocketPerMessageDeflate.h
-
64libs/libixwebsocket/include/ixwebsocket/IXWebSocketPerMessageDeflateCodec.h
-
47libs/libixwebsocket/include/ixwebsocket/IXWebSocketPerMessageDeflateOptions.h
-
24libs/libixwebsocket/include/ixwebsocket/IXWebSocketProxyServer.h
-
128libs/libixwebsocket/include/ixwebsocket/IXWebSocketSendData.h
-
27libs/libixwebsocket/include/ixwebsocket/IXWebSocketSendInfo.h
-
77libs/libixwebsocket/include/ixwebsocket/IXWebSocketServer.h
-
276libs/libixwebsocket/include/ixwebsocket/IXWebSocketTransport.h
-
9libs/libixwebsocket/include/ixwebsocket/IXWebSocketVersion.h
-
49resources/config.ini
-
2resources/iflytopzexcand.service
-
41src/app.cpp
-
33src/app.hpp
-
45src/components/linuxsocket/unix_socket.cpp
-
68src/components/linuxsocket/unix_socket.hpp
-
1src/components/zcanreceiver/socket_can/socket_can.cpp
-
12src/components/zcanreceiver/zcanreceiverhost.cpp
-
9src/main.cpp
-
0test/client.c
-
63test/receiver.c
-
70test/sender.c
-
5tools/build_pc.sh
@ -1,124 +0,0 @@ |
|||
#ifndef _MACARON_BASE64_H_ |
|||
#define _MACARON_BASE64_H_ |
|||
|
|||
/** |
|||
* The MIT License (MIT) |
|||
* Copyright (c) 2016 tomykaira |
|||
* |
|||
* 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. |
|||
*/ |
|||
|
|||
#include <string> |
|||
|
|||
namespace macaron { |
|||
|
|||
class Base64 { |
|||
public: |
|||
|
|||
static std::string Encode(const std::string data) { |
|||
static constexpr char sEncodingTable[] = { |
|||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |
|||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |
|||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |
|||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |
|||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |
|||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |
|||
'w', 'x', 'y', 'z', '0', '1', '2', '3', |
|||
'4', '5', '6', '7', '8', '9', '+', '/' |
|||
}; |
|||
|
|||
size_t in_len = data.size(); |
|||
size_t out_len = 4 * ((in_len + 2) / 3); |
|||
std::string ret(out_len, '\0'); |
|||
size_t i; |
|||
char *p = const_cast<char*>(ret.c_str()); |
|||
|
|||
for (i = 0; i < in_len - 2; i += 3) { |
|||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; |
|||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; |
|||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; |
|||
*p++ = sEncodingTable[data[i + 2] & 0x3F]; |
|||
} |
|||
if (i < in_len) { |
|||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; |
|||
if (i == (in_len - 1)) { |
|||
*p++ = sEncodingTable[((data[i] & 0x3) << 4)]; |
|||
*p++ = '='; |
|||
} |
|||
else { |
|||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; |
|||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; |
|||
} |
|||
*p++ = '='; |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
static std::string Decode(const std::string& input, std::string& out) { |
|||
static constexpr unsigned char kDecodingTable[] = { |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, |
|||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, |
|||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
|||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, |
|||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
|||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |
|||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 |
|||
}; |
|||
|
|||
size_t in_len = input.size(); |
|||
if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; |
|||
|
|||
size_t out_len = in_len / 4 * 3; |
|||
if (input[in_len - 1] == '=') out_len--; |
|||
if (input[in_len - 2] == '=') out_len--; |
|||
|
|||
out.resize(out_len); |
|||
|
|||
for (size_t i = 0, j = 0; i < in_len;) { |
|||
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |
|||
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |
|||
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |
|||
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |
|||
|
|||
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); |
|||
|
|||
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; |
|||
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; |
|||
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; |
|||
} |
|||
|
|||
return ""; |
|||
} |
|||
|
|||
}; |
|||
|
|||
} |
|||
|
|||
#endif /* _MACARON_BASE64_H_ */ |
@ -1,32 +0,0 @@ |
|||
/* |
|||
* IXBench.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
#pragma once |
|||
|
|||
#include <chrono> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class Bench |
|||
{ |
|||
public: |
|||
Bench(const std::string& description); |
|||
~Bench(); |
|||
|
|||
void reset(); |
|||
void record(); |
|||
void report(); |
|||
void setReported(); |
|||
uint64_t getDuration() const; |
|||
|
|||
private: |
|||
std::string _description; |
|||
std::chrono::time_point<std::chrono::high_resolution_clock> _start; |
|||
uint64_t _duration; |
|||
bool _reported; |
|||
}; |
|||
} // namespace ix |
@ -1,18 +0,0 @@ |
|||
/* |
|||
* IXCancellationRequest.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <functional> |
|||
|
|||
namespace ix |
|||
{ |
|||
using CancellationRequest = std::function<bool()>; |
|||
|
|||
CancellationRequest makeCancellationRequestWithTimeout( |
|||
int seconds, std::atomic<bool>& requestInitCancellation); |
|||
} // namespace ix |
@ -1,54 +0,0 @@ |
|||
/* |
|||
* IXConnectionState.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <functional> |
|||
#include <memory> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
using OnSetTerminatedCallback = std::function<void()>; |
|||
|
|||
class ConnectionState |
|||
{ |
|||
public: |
|||
ConnectionState(); |
|||
virtual ~ConnectionState() = default; |
|||
|
|||
virtual void computeId(); |
|||
virtual const std::string& getId() const; |
|||
|
|||
void setTerminated(); |
|||
bool isTerminated() const; |
|||
|
|||
const std::string& getRemoteIp(); |
|||
int getRemotePort(); |
|||
|
|||
static std::shared_ptr<ConnectionState> createConnectionState(); |
|||
|
|||
private: |
|||
void setOnSetTerminatedCallback(const OnSetTerminatedCallback& callback); |
|||
|
|||
void setRemoteIp(const std::string& remoteIp); |
|||
void setRemotePort(int remotePort); |
|||
|
|||
protected: |
|||
std::atomic<bool> _terminated; |
|||
std::string _id; |
|||
OnSetTerminatedCallback _onSetTerminatedCallback; |
|||
|
|||
static std::atomic<uint64_t> _globalId; |
|||
|
|||
std::string _remoteIp; |
|||
int _remotePort; |
|||
|
|||
friend class SocketServer; |
|||
}; |
|||
} // namespace ix |
@ -1,67 +0,0 @@ |
|||
/* |
|||
* IXDNSLookup.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
* |
|||
* Resolve a hostname+port to a struct addrinfo obtained with getaddrinfo |
|||
* Does this in a background thread so that it can be cancelled, since |
|||
* getaddrinfo is a blocking call, and we don't want to block the main thread on Mobile. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include <atomic> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <set> |
|||
#include <string> |
|||
|
|||
struct addrinfo; |
|||
|
|||
namespace ix |
|||
{ |
|||
class DNSLookup : public std::enable_shared_from_this<DNSLookup> |
|||
{ |
|||
public: |
|||
DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait); |
|||
~DNSLookup() = default; |
|||
|
|||
struct addrinfo* resolve(std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested, |
|||
bool cancellable = true); |
|||
|
|||
void release(struct addrinfo* addr); |
|||
|
|||
private: |
|||
struct addrinfo* resolveCancellable(std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested); |
|||
struct addrinfo* resolveUnCancellable(std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested); |
|||
|
|||
static struct addrinfo* getAddrInfo(const std::string& hostname, |
|||
int port, |
|||
std::string& errMsg); |
|||
|
|||
void run(std::weak_ptr<DNSLookup> self, std::string hostname, int port); // thread runner |
|||
|
|||
void setErrMsg(const std::string& errMsg); |
|||
const std::string& getErrMsg(); |
|||
|
|||
void setRes(struct addrinfo* addr); |
|||
struct addrinfo* getRes(); |
|||
|
|||
std::string _hostname; |
|||
int _port; |
|||
int64_t _wait; |
|||
const static int64_t kDefaultWait; |
|||
|
|||
struct addrinfo* _res; |
|||
std::mutex _resMutex; |
|||
|
|||
std::string _errMsg; |
|||
std::mutex _errMsgMutex; |
|||
|
|||
std::atomic<bool> _done; |
|||
}; |
|||
} // namespace ix |
@ -1,16 +0,0 @@ |
|||
/* |
|||
* IXExponentialBackoff.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
|
|||
namespace ix |
|||
{ |
|||
uint32_t calculateRetryWaitMilliseconds(uint32_t retryCount, |
|||
uint32_t maxWaitBetweenReconnectionRetries, |
|||
uint32_t minWaitBetweenReconnectionRetries); |
|||
} // namespace ix |
@ -1,12 +0,0 @@ |
|||
/* |
|||
* IXGetFreePort.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
namespace ix |
|||
{ |
|||
int getFreePort(); |
|||
} // namespace ix |
@ -1,15 +0,0 @@ |
|||
/* |
|||
* IXGzipCodec.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
std::string gzipCompress(const std::string& str); |
|||
bool gzipDecompress(const std::string& in, std::string& out); |
|||
} // namespace ix |
@ -1,134 +0,0 @@ |
|||
/* |
|||
* IXHttp.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXProgressCallback.h" |
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include <atomic> |
|||
#include <tuple> |
|||
#include <unordered_map> |
|||
|
|||
namespace ix |
|||
{ |
|||
enum class HttpErrorCode : int |
|||
{ |
|||
Ok = 0, |
|||
CannotConnect = 1, |
|||
Timeout = 2, |
|||
Gzip = 3, |
|||
UrlMalformed = 4, |
|||
CannotCreateSocket = 5, |
|||
SendError = 6, |
|||
ReadError = 7, |
|||
CannotReadStatusLine = 8, |
|||
MissingStatus = 9, |
|||
HeaderParsingError = 10, |
|||
MissingLocation = 11, |
|||
TooManyRedirects = 12, |
|||
ChunkReadError = 13, |
|||
CannotReadBody = 14, |
|||
Cancelled = 15, |
|||
Invalid = 100 |
|||
}; |
|||
|
|||
struct HttpResponse |
|||
{ |
|||
int statusCode; |
|||
std::string description; |
|||
HttpErrorCode errorCode; |
|||
WebSocketHttpHeaders headers; |
|||
std::string body; |
|||
std::string errorMsg; |
|||
uint64_t uploadSize; |
|||
uint64_t downloadSize; |
|||
|
|||
HttpResponse(int s = 0, |
|||
const std::string& des = std::string(), |
|||
const HttpErrorCode& c = HttpErrorCode::Ok, |
|||
const WebSocketHttpHeaders& h = WebSocketHttpHeaders(), |
|||
const std::string& b = std::string(), |
|||
const std::string& e = std::string(), |
|||
uint64_t u = 0, |
|||
uint64_t d = 0) |
|||
: statusCode(s) |
|||
, description(des) |
|||
, errorCode(c) |
|||
, headers(h) |
|||
, body(b) |
|||
, errorMsg(e) |
|||
, uploadSize(u) |
|||
, downloadSize(d) |
|||
{ |
|||
; |
|||
} |
|||
}; |
|||
|
|||
using HttpResponsePtr = std::shared_ptr<HttpResponse>; |
|||
using HttpParameters = std::unordered_map<std::string, std::string>; |
|||
using HttpFormDataParameters = std::unordered_map<std::string, std::string>; |
|||
using Logger = std::function<void(const std::string&)>; |
|||
using OnResponseCallback = std::function<void(const HttpResponsePtr&)>; |
|||
|
|||
struct HttpRequestArgs |
|||
{ |
|||
std::string url; |
|||
std::string verb; |
|||
WebSocketHttpHeaders extraHeaders; |
|||
std::string body; |
|||
std::string multipartBoundary; |
|||
int connectTimeout = 60; |
|||
int transferTimeout = 1800; |
|||
bool followRedirects = true; |
|||
int maxRedirects = 5; |
|||
bool verbose = false; |
|||
bool compress = true; |
|||
bool compressRequest = false; |
|||
Logger logger; |
|||
OnProgressCallback onProgressCallback; |
|||
OnChunkCallback onChunkCallback; |
|||
std::atomic<bool> cancel; |
|||
}; |
|||
|
|||
using HttpRequestArgsPtr = std::shared_ptr<HttpRequestArgs>; |
|||
|
|||
struct HttpRequest |
|||
{ |
|||
std::string uri; |
|||
std::string method; |
|||
std::string version; |
|||
std::string body; |
|||
WebSocketHttpHeaders headers; |
|||
|
|||
HttpRequest(const std::string& u, |
|||
const std::string& m, |
|||
const std::string& v, |
|||
const std::string& b, |
|||
const WebSocketHttpHeaders& h = WebSocketHttpHeaders()) |
|||
: uri(u) |
|||
, method(m) |
|||
, version(v) |
|||
, body(b) |
|||
, headers(h) |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
using HttpRequestPtr = std::shared_ptr<HttpRequest>; |
|||
|
|||
class Http |
|||
{ |
|||
public: |
|||
static std::tuple<bool, std::string, HttpRequestPtr> parseRequest( |
|||
std::unique_ptr<Socket>& socket, int timeoutSecs); |
|||
static bool sendResponse(HttpResponsePtr response, std::unique_ptr<Socket>& socket); |
|||
|
|||
static std::pair<std::string, int> parseStatusLine(const std::string& line); |
|||
static std::tuple<std::string, std::string, std::string> parseRequestLine( |
|||
const std::string& line); |
|||
static std::string trim(const std::string& str); |
|||
}; |
|||
} // namespace ix |
@ -1,123 +0,0 @@ |
|||
/* |
|||
* IXHttpClient.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXHttp.h" |
|||
#include "IXSocket.h" |
|||
#include "IXSocketTLSOptions.h" |
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include <algorithm> |
|||
#include <atomic> |
|||
#include <condition_variable> |
|||
#include <functional> |
|||
#include <map> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <queue> |
|||
#include <thread> |
|||
|
|||
namespace ix |
|||
{ |
|||
class HttpClient |
|||
{ |
|||
public: |
|||
HttpClient(bool async = false); |
|||
~HttpClient(); |
|||
|
|||
HttpResponsePtr get(const std::string& url, HttpRequestArgsPtr args); |
|||
HttpResponsePtr head(const std::string& url, HttpRequestArgsPtr args); |
|||
HttpResponsePtr Delete(const std::string& url, HttpRequestArgsPtr args); |
|||
|
|||
HttpResponsePtr post(const std::string& url, |
|||
const HttpParameters& httpParameters, |
|||
const HttpFormDataParameters& httpFormDataParameters, |
|||
HttpRequestArgsPtr args); |
|||
HttpResponsePtr post(const std::string& url, |
|||
const std::string& body, |
|||
HttpRequestArgsPtr args); |
|||
|
|||
HttpResponsePtr put(const std::string& url, |
|||
const HttpParameters& httpParameters, |
|||
const HttpFormDataParameters& httpFormDataParameters, |
|||
HttpRequestArgsPtr args); |
|||
HttpResponsePtr put(const std::string& url, |
|||
const std::string& body, |
|||
HttpRequestArgsPtr args); |
|||
|
|||
HttpResponsePtr patch(const std::string& url, |
|||
const HttpParameters& httpParameters, |
|||
const HttpFormDataParameters& httpFormDataParameters, |
|||
HttpRequestArgsPtr args); |
|||
HttpResponsePtr patch(const std::string& url, |
|||
const std::string& body, |
|||
HttpRequestArgsPtr args); |
|||
|
|||
HttpResponsePtr request(const std::string& url, |
|||
const std::string& verb, |
|||
const std::string& body, |
|||
HttpRequestArgsPtr args, |
|||
int redirects = 0); |
|||
|
|||
HttpResponsePtr request(const std::string& url, |
|||
const std::string& verb, |
|||
const HttpParameters& httpParameters, |
|||
const HttpFormDataParameters& httpFormDataParameters, |
|||
HttpRequestArgsPtr args); |
|||
|
|||
void setForceBody(bool value); |
|||
|
|||
// Async API |
|||
HttpRequestArgsPtr createRequest(const std::string& url = std::string(), |
|||
const std::string& verb = HttpClient::kGet); |
|||
|
|||
bool performRequest(HttpRequestArgsPtr request, |
|||
const OnResponseCallback& onResponseCallback); |
|||
|
|||
// TLS |
|||
void setTLSOptions(const SocketTLSOptions& tlsOptions); |
|||
|
|||
std::string serializeHttpParameters(const HttpParameters& httpParameters); |
|||
|
|||
std::string serializeHttpFormDataParameters( |
|||
const std::string& multipartBoundary, |
|||
const HttpFormDataParameters& httpFormDataParameters, |
|||
const HttpParameters& httpParameters = HttpParameters()); |
|||
|
|||
std::string generateMultipartBoundary(); |
|||
|
|||
std::string urlEncode(const std::string& value); |
|||
|
|||
const static std::string kPost; |
|||
const static std::string kGet; |
|||
const static std::string kHead; |
|||
const static std::string kDelete; |
|||
const static std::string kPut; |
|||
const static std::string kPatch; |
|||
|
|||
private: |
|||
void log(const std::string& msg, HttpRequestArgsPtr args); |
|||
|
|||
// Async API background thread runner |
|||
void run(); |
|||
// Async API |
|||
bool _async; |
|||
std::queue<std::pair<HttpRequestArgsPtr, OnResponseCallback>> _queue; |
|||
mutable std::mutex _queueMutex; |
|||
std::condition_variable _condition; |
|||
std::atomic<bool> _stop; |
|||
std::thread _thread; |
|||
|
|||
std::unique_ptr<Socket> _socket; |
|||
std::recursive_mutex _mutex; // to protect accessing the _socket (only one socket per |
|||
// client) the mutex needs to be recursive as this function |
|||
// might be called recursively to follow HTTP redirections |
|||
|
|||
SocketTLSOptions _tlsOptions; |
|||
|
|||
bool _forceBody; |
|||
}; |
|||
} // namespace ix |
@ -1,59 +0,0 @@ |
|||
/* |
|||
* IXHttpServer.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXHttp.h" |
|||
#include "IXSocketServer.h" |
|||
#include "IXWebSocket.h" |
|||
#include <functional> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <set> |
|||
#include <string> |
|||
#include <thread> |
|||
#include <utility> // pair |
|||
|
|||
namespace ix |
|||
{ |
|||
class HttpServer final : public SocketServer |
|||
{ |
|||
public: |
|||
using OnConnectionCallback = |
|||
std::function<HttpResponsePtr(HttpRequestPtr, std::shared_ptr<ConnectionState>)>; |
|||
|
|||
HttpServer(int port = SocketServer::kDefaultPort, |
|||
const std::string& host = SocketServer::kDefaultHost, |
|||
int backlog = SocketServer::kDefaultTcpBacklog, |
|||
size_t maxConnections = SocketServer::kDefaultMaxConnections, |
|||
int addressFamily = SocketServer::kDefaultAddressFamily, |
|||
int timeoutSecs = HttpServer::kDefaultTimeoutSecs); |
|||
virtual ~HttpServer(); |
|||
virtual void stop() final; |
|||
|
|||
void setOnConnectionCallback(const OnConnectionCallback& callback); |
|||
|
|||
void makeRedirectServer(const std::string& redirectUrl); |
|||
|
|||
void makeDebugServer(); |
|||
|
|||
int getTimeoutSecs(); |
|||
private: |
|||
// Member variables |
|||
OnConnectionCallback _onConnectionCallback; |
|||
std::atomic<int> _connectedClientsCount; |
|||
|
|||
const static int kDefaultTimeoutSecs; |
|||
int _timeoutSecs; |
|||
|
|||
// Methods |
|||
virtual void handleConnection(std::unique_ptr<Socket>, |
|||
std::shared_ptr<ConnectionState> connectionState) final; |
|||
virtual size_t getConnectedClientsCount() final; |
|||
|
|||
void setDefaultConnectionCallback(); |
|||
}; |
|||
} // namespace ix |
@ -1,87 +0,0 @@ |
|||
/* |
|||
* IXNetSystem.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#ifdef _WIN32 |
|||
|
|||
#ifndef WIN32_LEAN_AND_MEAN |
|||
#define WIN32_LEAN_AND_MEAN |
|||
#endif |
|||
|
|||
#include <ws2tcpip.h> |
|||
#include <winsock2.h> |
|||
#include <basetsd.h> |
|||
#include <io.h> |
|||
#include <ws2def.h> |
|||
#include <cerrno> |
|||
|
|||
#undef EWOULDBLOCK |
|||
#undef EAGAIN |
|||
#undef EINPROGRESS |
|||
#undef EBADF |
|||
#undef EINVAL |
|||
|
|||
// map to WSA error codes |
|||
#define EWOULDBLOCK WSAEWOULDBLOCK |
|||
#define EAGAIN WSATRY_AGAIN |
|||
#define EINPROGRESS WSAEINPROGRESS |
|||
#define EBADF WSAEBADF |
|||
#define EINVAL WSAEINVAL |
|||
|
|||
// Define our own poll on Windows, as a wrapper on top of select |
|||
typedef unsigned long int nfds_t; |
|||
|
|||
// pollfd is not defined by some versions of mingw64 since _WIN32_WINNT is too low |
|||
#if _WIN32_WINNT < 0x0600 |
|||
struct pollfd |
|||
{ |
|||
int fd; /* file descriptor */ |
|||
short events; /* requested events */ |
|||
short revents; /* returned events */ |
|||
}; |
|||
|
|||
#define POLLIN 0x001 /* There is data to read. */ |
|||
#define POLLOUT 0x004 /* Writing now will not block. */ |
|||
#define POLLERR 0x008 /* Error condition. */ |
|||
#define POLLHUP 0x010 /* Hung up. */ |
|||
#define POLLNVAL 0x020 /* Invalid polling request. */ |
|||
#endif |
|||
|
|||
#else |
|||
#include <arpa/inet.h> |
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
#include <netdb.h> |
|||
#include <netinet/in.h> |
|||
#include <netinet/ip.h> |
|||
#include <netinet/tcp.h> |
|||
#include <poll.h> |
|||
#include <sys/select.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/time.h> |
|||
#include <unistd.h> |
|||
#endif |
|||
|
|||
namespace ix |
|||
{ |
|||
#ifdef _WIN32 |
|||
typedef SOCKET socket_t; |
|||
#else |
|||
typedef int socket_t; |
|||
#endif |
|||
|
|||
bool initNetSystem(); |
|||
bool uninitNetSystem(); |
|||
|
|||
int poll(struct pollfd* fds, nfds_t nfds, int timeout, void** event); |
|||
|
|||
const char* inet_ntop(int af, const void* src, char* dst, socklen_t size); |
|||
int inet_pton(int af, const char* src, void* dst); |
|||
|
|||
unsigned short network_to_host_short(unsigned short value); |
|||
} // namespace ix |
@ -1,16 +0,0 @@ |
|||
/* |
|||
* IXProgressCallback.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <functional> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
using OnProgressCallback = std::function<bool(int current, int total)>; |
|||
using OnChunkCallback = std::function<void(const std::string&)>; |
|||
} |
@ -1,35 +0,0 @@ |
|||
/* |
|||
* IXSelectInterrupt.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class SelectInterrupt |
|||
{ |
|||
public: |
|||
SelectInterrupt(); |
|||
virtual ~SelectInterrupt(); |
|||
|
|||
virtual bool init(std::string& errorMsg); |
|||
|
|||
virtual bool notify(uint64_t value); |
|||
virtual bool clear(); |
|||
virtual uint64_t read(); |
|||
virtual int getFd() const; |
|||
virtual void* getEvent() const; |
|||
|
|||
// Used as special codes for pipe communication |
|||
static const uint64_t kSendRequest; |
|||
static const uint64_t kCloseRequest; |
|||
}; |
|||
|
|||
using SelectInterruptPtr = std::unique_ptr<SelectInterrupt>; |
|||
} // namespace ix |
@ -1,39 +0,0 @@ |
|||
/* |
|||
* IXSelectInterruptEvent.h |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXSelectInterrupt.h" |
|||
#include <mutex> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
#include <deque> |
|||
#ifdef _WIN32 |
|||
#include <windows.h> |
|||
#endif |
|||
|
|||
namespace ix |
|||
{ |
|||
class SelectInterruptEvent final : public SelectInterrupt |
|||
{ |
|||
public: |
|||
SelectInterruptEvent(); |
|||
virtual ~SelectInterruptEvent(); |
|||
|
|||
bool init(std::string& /*errorMsg*/) final; |
|||
|
|||
bool notify(uint64_t value) final; |
|||
bool clear() final; |
|||
uint64_t read() final; |
|||
void* getEvent() const final; |
|||
private: |
|||
// contains every value only once, new values are inserted at the begin, nu |
|||
std::deque<uint64_t> _values; |
|||
std::mutex _valuesMutex; |
|||
#ifdef _WIN32 |
|||
// Windows Event to wake up the socket poll |
|||
HANDLE _event; |
|||
#endif |
|||
}; |
|||
} // namespace ix |
@ -1,16 +0,0 @@ |
|||
/* |
|||
* IXSelectInterruptFactory.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
|
|||
namespace ix |
|||
{ |
|||
class SelectInterrupt; |
|||
using SelectInterruptPtr = std::unique_ptr<SelectInterrupt>; |
|||
SelectInterruptPtr createSelectInterrupt(); |
|||
} // namespace ix |
@ -1,40 +0,0 @@ |
|||
/* |
|||
* IXSelectInterruptPipe.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXSelectInterrupt.h" |
|||
#include <mutex> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class SelectInterruptPipe final : public SelectInterrupt |
|||
{ |
|||
public: |
|||
SelectInterruptPipe(); |
|||
virtual ~SelectInterruptPipe(); |
|||
|
|||
bool init(std::string& errorMsg) final; |
|||
|
|||
bool notify(uint64_t value) final; |
|||
bool clear() final; |
|||
uint64_t read() final; |
|||
int getFd() const final; |
|||
|
|||
private: |
|||
// Store file descriptors used by the communication pipe. Communication |
|||
// happens between a control thread and a background thread, which is |
|||
// blocked on select. |
|||
int _fildes[2]; |
|||
mutable std::mutex _fildesMutex; |
|||
|
|||
// Used to identify the read/write idx |
|||
static const int kPipeReadIndex; |
|||
static const int kPipeWriteIndex; |
|||
}; |
|||
} // namespace ix |
@ -1,12 +0,0 @@ |
|||
/* |
|||
* IXSetThreadName.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
#pragma once |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
void setThreadName(const std::string& name); |
|||
} |
@ -1,99 +0,0 @@ |
|||
/* |
|||
* IXSocket.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <functional> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <string> |
|||
|
|||
#ifdef _WIN32 |
|||
#include <basetsd.h> |
|||
#ifdef _MSC_VER |
|||
typedef SSIZE_T ssize_t; |
|||
#endif |
|||
#endif |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include "IXProgressCallback.h" |
|||
#include "IXSelectInterrupt.h" |
|||
|
|||
namespace ix |
|||
{ |
|||
enum class PollResultType |
|||
{ |
|||
ReadyForRead = 0, |
|||
ReadyForWrite = 1, |
|||
Timeout = 2, |
|||
Error = 3, |
|||
SendRequest = 4, |
|||
CloseRequest = 5 |
|||
}; |
|||
|
|||
class Socket |
|||
{ |
|||
public: |
|||
Socket(int fd = -1); |
|||
virtual ~Socket(); |
|||
bool init(std::string& errorMsg); |
|||
|
|||
// Functions to check whether there is activity on the socket |
|||
PollResultType poll(int timeoutMs = kDefaultPollTimeout); |
|||
bool wakeUpFromPoll(uint64_t wakeUpCode); |
|||
bool isWakeUpFromPollSupported(); |
|||
|
|||
PollResultType isReadyToWrite(int timeoutMs); |
|||
PollResultType isReadyToRead(int timeoutMs); |
|||
|
|||
// Virtual methods |
|||
virtual bool accept(std::string& errMsg); |
|||
|
|||
virtual bool connect(const std::string& host, |
|||
int port, |
|||
std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested); |
|||
virtual void close(); |
|||
|
|||
virtual ssize_t send(char* buffer, size_t length); |
|||
ssize_t send(const std::string& buffer); |
|||
virtual ssize_t recv(void* buffer, size_t length); |
|||
|
|||
// Blocking and cancellable versions, working with socket that can be set |
|||
// to non blocking mode. Used during HTTP upgrade. |
|||
bool readByte(void* buffer, const CancellationRequest& isCancellationRequested); |
|||
bool writeBytes(const std::string& str, const CancellationRequest& isCancellationRequested); |
|||
|
|||
std::pair<bool, std::string> readLine(const CancellationRequest& isCancellationRequested); |
|||
std::pair<bool, std::string> readBytes(size_t length, |
|||
const OnProgressCallback& onProgressCallback, |
|||
const OnChunkCallback& onChunkCallback, |
|||
const CancellationRequest& isCancellationRequested); |
|||
|
|||
static int getErrno(); |
|||
static bool isWaitNeeded(); |
|||
static void closeSocket(int fd); |
|||
|
|||
static PollResultType poll(bool readyToRead, |
|||
int timeoutMs, |
|||
int sockfd, |
|||
const SelectInterruptPtr& selectInterrupt); |
|||
|
|||
protected: |
|||
std::atomic<int> _sockfd; |
|||
std::mutex _socketMutex; |
|||
|
|||
static bool readSelectInterruptRequest(const SelectInterruptPtr& selectInterrupt, |
|||
PollResultType* pollResult); |
|||
|
|||
private: |
|||
static const int kDefaultPollTimeout; |
|||
static const int kDefaultPollNoTimeout; |
|||
|
|||
SelectInterruptPtr _selectInterrupt; |
|||
}; |
|||
} // namespace ix |
@ -1,31 +0,0 @@ |
|||
/* |
|||
* IXSocketConnect.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include <string> |
|||
|
|||
struct addrinfo; |
|||
|
|||
namespace ix |
|||
{ |
|||
class SocketConnect |
|||
{ |
|||
public: |
|||
static int connect(const std::string& hostname, |
|||
int port, |
|||
std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested); |
|||
|
|||
static void configure(int sockfd); |
|||
|
|||
private: |
|||
static int connectToAddress(const struct addrinfo* address, |
|||
std::string& errMsg, |
|||
const CancellationRequest& isCancellationRequested); |
|||
}; |
|||
} // namespace ix |
@ -1,21 +0,0 @@ |
|||
|
|||
/* |
|||
* IXSocketFactory.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXSocketTLSOptions.h" |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class Socket; |
|||
std::unique_ptr<Socket> createSocket(bool tls, |
|||
int fd, |
|||
std::string& errorMsg, |
|||
const SocketTLSOptions& tlsOptions); |
|||
} // namespace ix |
@ -1,130 +0,0 @@ |
|||
/* |
|||
* IXSocketServer.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXConnectionState.h" |
|||
#include "IXNetSystem.h" |
|||
#include "IXSelectInterrupt.h" |
|||
#include "IXSocketTLSOptions.h" |
|||
#include <atomic> |
|||
#include <condition_variable> |
|||
#include <functional> |
|||
#include <list> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <set> |
|||
#include <string> |
|||
#include <thread> |
|||
#include <utility> // pair |
|||
|
|||
namespace ix |
|||
{ |
|||
class Socket; |
|||
|
|||
class SocketServer |
|||
{ |
|||
public: |
|||
using ConnectionStateFactory = std::function<std::shared_ptr<ConnectionState>()>; |
|||
|
|||
// Each connection is handled by its own worker thread. |
|||
// We use a list as we only care about remove and append operations. |
|||
using ConnectionThreads = |
|||
std::list<std::pair<std::shared_ptr<ConnectionState>, std::thread>>; |
|||
|
|||
SocketServer(int port = SocketServer::kDefaultPort, |
|||
const std::string& host = SocketServer::kDefaultHost, |
|||
int backlog = SocketServer::kDefaultTcpBacklog, |
|||
size_t maxConnections = SocketServer::kDefaultMaxConnections, |
|||
int addressFamily = SocketServer::kDefaultAddressFamily); |
|||
virtual ~SocketServer(); |
|||
virtual void stop(); |
|||
|
|||
// It is possible to override ConnectionState through inheritance |
|||
// this method allows user to change the factory by returning an object |
|||
// that inherits from ConnectionState but has its own methods. |
|||
void setConnectionStateFactory(const ConnectionStateFactory& connectionStateFactory); |
|||
|
|||
const static int kDefaultPort; |
|||
const static std::string kDefaultHost; |
|||
const static int kDefaultTcpBacklog; |
|||
const static size_t kDefaultMaxConnections; |
|||
const static int kDefaultAddressFamily; |
|||
|
|||
void start(); |
|||
std::pair<bool, std::string> listen(); |
|||
void wait(); |
|||
|
|||
void setTLSOptions(const SocketTLSOptions& socketTLSOptions); |
|||
|
|||
int getPort(); |
|||
std::string getHost(); |
|||
int getBacklog(); |
|||
std::size_t getMaxConnections(); |
|||
int getAddressFamily(); |
|||
protected: |
|||
// Logging |
|||
void logError(const std::string& str); |
|||
void logInfo(const std::string& str); |
|||
|
|||
void stopAcceptingConnections(); |
|||
|
|||
private: |
|||
// Member variables |
|||
int _port; |
|||
std::string _host; |
|||
int _backlog; |
|||
size_t _maxConnections; |
|||
int _addressFamily; |
|||
|
|||
// socket for accepting connections |
|||
socket_t _serverFd; |
|||
|
|||
std::atomic<bool> _stop; |
|||
|
|||
std::mutex _logMutex; |
|||
|
|||
// background thread to wait for incoming connections |
|||
std::thread _thread; |
|||
void run(); |
|||
void onSetTerminatedCallback(); |
|||
|
|||
// background thread to cleanup (join) terminated threads |
|||
std::atomic<bool> _stopGc; |
|||
std::thread _gcThread; |
|||
void runGC(); |
|||
|
|||
// the list of (connectionState, threads) for each connections |
|||
ConnectionThreads _connectionsThreads; |
|||
std::mutex _connectionsThreadsMutex; |
|||
|
|||
// used to have the main control thread for a server |
|||
// wait for a 'terminate' notification without busy polling |
|||
std::condition_variable _conditionVariable; |
|||
std::mutex _conditionVariableMutex; |
|||
|
|||
// the factory to create ConnectionState objects |
|||
ConnectionStateFactory _connectionStateFactory; |
|||
|
|||
virtual void handleConnection(std::unique_ptr<Socket>, |
|||
std::shared_ptr<ConnectionState> connectionState) = 0; |
|||
virtual size_t getConnectedClientsCount() = 0; |
|||
|
|||
// Returns true if all connection threads are joined |
|||
void closeTerminatedThreads(); |
|||
size_t getConnectionsThreadsCount(); |
|||
|
|||
SocketTLSOptions _socketTLSOptions; |
|||
|
|||
// to wake up from select |
|||
SelectInterruptPtr _acceptSelectInterrupt; |
|||
|
|||
// used by the gc thread, to know that a thread needs to be garbage collected |
|||
// as a connection |
|||
std::condition_variable _conditionVariableGC; |
|||
std::mutex _conditionVariableMutexGC; |
|||
}; |
|||
} // namespace ix |
@ -1,54 +0,0 @@ |
|||
/* |
|||
* IXSocketTLSOptions.h |
|||
* Author: Matt DeBoer |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct SocketTLSOptions |
|||
{ |
|||
public: |
|||
// check validity of the object |
|||
bool isValid() const; |
|||
|
|||
// the certificate presented to peers |
|||
std::string certFile; |
|||
|
|||
// the key used for signing/encryption |
|||
std::string keyFile; |
|||
|
|||
// the ca certificate (or certificate bundle) file containing |
|||
// certificates to be trusted by peers; use 'SYSTEM' to |
|||
// leverage the system defaults, use 'NONE' to disable peer verification |
|||
std::string caFile = "SYSTEM"; |
|||
|
|||
// list of ciphers (rsa, etc...) |
|||
std::string ciphers = "DEFAULT"; |
|||
|
|||
// whether tls is enabled, used for server code |
|||
bool tls = false; |
|||
|
|||
bool hasCertAndKey() const; |
|||
|
|||
bool isUsingSystemDefaults() const; |
|||
|
|||
bool isUsingInMemoryCAs() const; |
|||
|
|||
bool isPeerVerifyDisabled() const; |
|||
|
|||
bool isUsingDefaultCiphers() const; |
|||
|
|||
const std::string& getErrorMsg() const; |
|||
|
|||
std::string getDescription() const; |
|||
|
|||
private: |
|||
mutable std::string _errMsg; |
|||
mutable bool _validated = false; |
|||
}; |
|||
} // namespace ix |
@ -1,25 +0,0 @@ |
|||
/* |
|||
* IXStrCaseCompare.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2020 Machine Zone. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct CaseInsensitiveLess |
|||
{ |
|||
// Case Insensitive compare_less binary function |
|||
struct NocaseCompare |
|||
{ |
|||
bool operator()(const unsigned char& c1, const unsigned char& c2) const; |
|||
}; |
|||
|
|||
static bool cmp(const std::string& s1, const std::string& s2); |
|||
|
|||
bool operator()(const std::string& s1, const std::string& s2) const; |
|||
}; |
|||
} // namespace ix |
@ -1,45 +0,0 @@ |
|||
/* |
|||
* IXUdpSocket.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
#ifdef _WIN32 |
|||
#include <basetsd.h> |
|||
#ifdef _MSC_VER |
|||
typedef SSIZE_T ssize_t; |
|||
#endif |
|||
#endif |
|||
|
|||
#include "IXNetSystem.h" |
|||
|
|||
namespace ix |
|||
{ |
|||
class UdpSocket |
|||
{ |
|||
public: |
|||
UdpSocket(int fd = -1); |
|||
~UdpSocket(); |
|||
|
|||
// Virtual methods |
|||
bool init(const std::string& host, int port, std::string& errMsg); |
|||
ssize_t sendto(const std::string& buffer); |
|||
ssize_t recvfrom(char* buffer, size_t length); |
|||
|
|||
void close(); |
|||
|
|||
static int getErrno(); |
|||
static bool isWaitNeeded(); |
|||
static void closeSocket(int fd); |
|||
|
|||
private: |
|||
std::atomic<int> _sockfd; |
|||
struct sockaddr_in _server; |
|||
}; |
|||
} // namespace ix |
@ -1,18 +0,0 @@ |
|||
/* |
|||
* IXUniquePtr.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
|
|||
namespace ix |
|||
{ |
|||
template<typename T, typename... Args> |
|||
std::unique_ptr<T> make_unique(Args&&... args) |
|||
{ |
|||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
|||
} |
|||
} // namespace ix |
@ -1,23 +0,0 @@ |
|||
/* |
|||
* IXUrlParser.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class UrlParser |
|||
{ |
|||
public: |
|||
static bool parse(const std::string& url, |
|||
std::string& protocol, |
|||
std::string& host, |
|||
std::string& path, |
|||
std::string& query, |
|||
int& port); |
|||
}; |
|||
} // namespace ix |
@ -1,14 +0,0 @@ |
|||
/* |
|||
* IXUserAgent.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
std::string userAgent(); |
|||
} // namespace ix |
@ -1,178 +0,0 @@ |
|||
/* |
|||
* The following code is adapted from code originally written by Bjoern |
|||
* Hoehrmann <bjoern@hoehrmann.de>. See |
|||
* http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. |
|||
* |
|||
* The original license: |
|||
* |
|||
* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> |
|||
* |
|||
* 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. |
|||
*/ |
|||
|
|||
/* |
|||
* IXUtf8Validator.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
* |
|||
* From websocketpp. Tiny modifications made for code style, function names etc... |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
/// State that represents a valid utf8 input sequence |
|||
static unsigned int const utf8_accept = 0; |
|||
/// State that represents an invalid utf8 input sequence |
|||
static unsigned int const utf8_reject = 1; |
|||
|
|||
/// Lookup table for the UTF8 decode state machine |
|||
static uint8_t const utf8d[] = { |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f |
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
|||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f |
|||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf |
|||
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
|||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df |
|||
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef |
|||
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff |
|||
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 |
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
|||
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 |
|||
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, |
|||
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 |
|||
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, |
|||
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 |
|||
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, |
|||
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8 |
|||
}; |
|||
|
|||
/// Decode the next byte of a UTF8 sequence |
|||
/** |
|||
* @param [out] state The decoder state to advance |
|||
* @param [out] codep The codepoint to fill in |
|||
* @param [in] byte The byte to input |
|||
* @return The ending state of the decode operation |
|||
*/ |
|||
inline uint32_t decodeNextByte(uint32_t* state, uint32_t* codep, uint8_t byte) |
|||
{ |
|||
uint32_t type = utf8d[byte]; |
|||
|
|||
*codep = (*state != utf8_accept) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); |
|||
|
|||
*state = utf8d[256 + *state * 16 + type]; |
|||
return *state; |
|||
} |
|||
|
|||
/// Provides streaming UTF8 validation functionality |
|||
class Utf8Validator |
|||
{ |
|||
public: |
|||
/// Construct and initialize the validator |
|||
Utf8Validator() |
|||
: m_state(utf8_accept) |
|||
, m_codepoint(0) |
|||
{ |
|||
} |
|||
|
|||
/// Advance the state of the validator with the next input byte |
|||
/** |
|||
* @param byte The byte to advance the validation state with |
|||
* @return Whether or not the byte resulted in a validation error. |
|||
*/ |
|||
bool consume(uint8_t byte) |
|||
{ |
|||
if (decodeNextByte(&m_state, &m_codepoint, byte) == utf8_reject) |
|||
{ |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/// Advance Validator state with input from an iterator pair |
|||
/** |
|||
* @param begin Input iterator to the start of the input range |
|||
* @param end Input iterator to the end of the input range |
|||
* @return Whether or not decoding the bytes resulted in a validation error. |
|||
*/ |
|||
template<typename iterator_type> |
|||
bool decode(iterator_type begin, iterator_type end) |
|||
{ |
|||
for (iterator_type it = begin; it != end; ++it) |
|||
{ |
|||
unsigned int result = |
|||
decodeNextByte(&m_state, &m_codepoint, static_cast<uint8_t>(*it)); |
|||
|
|||
if (result == utf8_reject) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/// Return whether the input sequence ended on a valid utf8 codepoint |
|||
/** |
|||
* @return Whether or not the input sequence ended on a valid codepoint. |
|||
*/ |
|||
bool complete() |
|||
{ |
|||
return m_state == utf8_accept; |
|||
} |
|||
|
|||
/// Reset the Validator to decode another message |
|||
void reset() |
|||
{ |
|||
m_state = utf8_accept; |
|||
m_codepoint = 0; |
|||
} |
|||
|
|||
private: |
|||
uint32_t m_state; |
|||
uint32_t m_codepoint; |
|||
}; |
|||
|
|||
/// Validate a UTF8 string |
|||
/** |
|||
* convenience function that creates a Validator, validates a complete string |
|||
* and returns the result. |
|||
*/ |
|||
inline bool validateUtf8(std::string const& s) |
|||
{ |
|||
Utf8Validator v; |
|||
if (!v.decode(s.begin(), s.end())) |
|||
{ |
|||
return false; |
|||
} |
|||
return v.complete(); |
|||
} |
|||
|
|||
} // namespace ix |
@ -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(); |
|||
|
|||
} // namespace ix |
@ -1,180 +0,0 @@ |
|||
/* |
|||
* IXWebSocket.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. |
|||
* |
|||
* WebSocket RFC |
|||
* https://tools.ietf.org/html/rfc6455 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXProgressCallback.h" |
|||
#include "IXSocketTLSOptions.h" |
|||
#include "IXWebSocketCloseConstants.h" |
|||
#include "IXWebSocketErrorInfo.h" |
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include "IXWebSocketMessage.h" |
|||
#include "IXWebSocketPerMessageDeflateOptions.h" |
|||
#include "IXWebSocketSendInfo.h" |
|||
#include "IXWebSocketSendData.h" |
|||
#include "IXWebSocketTransport.h" |
|||
#include <atomic> |
|||
#include <condition_variable> |
|||
#include <mutex> |
|||
#include <string> |
|||
#include <thread> |
|||
|
|||
namespace ix |
|||
{ |
|||
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants |
|||
enum class ReadyState |
|||
{ |
|||
Connecting = 0, |
|||
Open = 1, |
|||
Closing = 2, |
|||
Closed = 3 |
|||
}; |
|||
|
|||
using OnMessageCallback = std::function<void(const WebSocketMessagePtr&)>; |
|||
|
|||
using OnTrafficTrackerCallback = std::function<void(size_t size, bool incoming)>; |
|||
|
|||
class WebSocket |
|||
{ |
|||
public: |
|||
WebSocket(); |
|||
~WebSocket(); |
|||
|
|||
void setUrl(const std::string& url); |
|||
|
|||
// send extra headers in client handshake request |
|||
void setExtraHeaders(const WebSocketHttpHeaders& headers); |
|||
void setPerMessageDeflateOptions( |
|||
const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions); |
|||
void setTLSOptions(const SocketTLSOptions& socketTLSOptions); |
|||
void setPingInterval(int pingIntervalSecs); |
|||
void enablePong(); |
|||
void disablePong(); |
|||
void enablePerMessageDeflate(); |
|||
void disablePerMessageDeflate(); |
|||
void addSubProtocol(const std::string& subProtocol); |
|||
void setHandshakeTimeout(int handshakeTimeoutSecs); |
|||
|
|||
// Run asynchronously, by calling start and stop. |
|||
void start(); |
|||
|
|||
// stop is synchronous |
|||
void stop(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, |
|||
const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage); |
|||
|
|||
// Run in blocking mode, by connecting first manually, and then calling run. |
|||
WebSocketInitResult connect(int timeoutSecs); |
|||
void run(); |
|||
|
|||
// send is in text mode by default |
|||
WebSocketSendInfo send(const std::string& data, |
|||
bool binary = false, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
WebSocketSendInfo sendBinary(const std::string& data, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
WebSocketSendInfo sendBinary(const IXWebSocketSendData& data, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
// does not check for valid UTF-8 characters. Caller must check that. |
|||
WebSocketSendInfo sendUtf8Text(const std::string& text, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
// does not check for valid UTF-8 characters. Caller must check that. |
|||
WebSocketSendInfo sendUtf8Text(const IXWebSocketSendData& text, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
WebSocketSendInfo sendText(const std::string& text, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
WebSocketSendInfo ping(const std::string& text); |
|||
|
|||
void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, |
|||
const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage); |
|||
|
|||
void setOnMessageCallback(const OnMessageCallback& callback); |
|||
bool isOnMessageCallbackRegistered() const; |
|||
static void setTrafficTrackerCallback(const OnTrafficTrackerCallback& callback); |
|||
static void resetTrafficTrackerCallback(); |
|||
|
|||
ReadyState getReadyState() const; |
|||
static std::string readyStateToString(ReadyState readyState); |
|||
|
|||
const std::string getUrl() const; |
|||
const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const; |
|||
int getPingInterval() const; |
|||
size_t bufferedAmount() const; |
|||
|
|||
void enableAutomaticReconnection(); |
|||
void disableAutomaticReconnection(); |
|||
bool isAutomaticReconnectionEnabled() const; |
|||
void setMaxWaitBetweenReconnectionRetries(uint32_t maxWaitBetweenReconnectionRetries); |
|||
void setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries); |
|||
uint32_t getMaxWaitBetweenReconnectionRetries() const; |
|||
uint32_t getMinWaitBetweenReconnectionRetries() const; |
|||
const std::vector<std::string>& getSubProtocols(); |
|||
|
|||
private: |
|||
WebSocketSendInfo sendMessage(const IXWebSocketSendData& message, |
|||
SendMessageKind sendMessageKind, |
|||
const OnProgressCallback& callback = nullptr); |
|||
|
|||
bool isConnected() const; |
|||
bool isClosing() const; |
|||
void checkConnection(bool firstConnectionAttempt); |
|||
static void invokeTrafficTrackerCallback(size_t size, bool incoming); |
|||
|
|||
// Server |
|||
WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, |
|||
int timeoutSecs, |
|||
bool enablePerMessageDeflate); |
|||
|
|||
WebSocketTransport _ws; |
|||
|
|||
std::string _url; |
|||
WebSocketHttpHeaders _extraHeaders; |
|||
|
|||
WebSocketPerMessageDeflateOptions _perMessageDeflateOptions; |
|||
|
|||
SocketTLSOptions _socketTLSOptions; |
|||
|
|||
mutable std::mutex _configMutex; // protect all config variables access |
|||
|
|||
OnMessageCallback _onMessageCallback; |
|||
static OnTrafficTrackerCallback _onTrafficTrackerCallback; |
|||
|
|||
std::atomic<bool> _stop; |
|||
std::thread _thread; |
|||
std::mutex _writeMutex; |
|||
|
|||
// Automatic reconnection |
|||
std::atomic<bool> _automaticReconnection; |
|||
static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries; |
|||
static const uint32_t kDefaultMinWaitBetweenReconnectionRetries; |
|||
uint32_t _maxWaitBetweenReconnectionRetries; |
|||
uint32_t _minWaitBetweenReconnectionRetries; |
|||
|
|||
// Make the sleeping in the automatic reconnection cancellable |
|||
std::mutex _sleepMutex; |
|||
std::condition_variable _sleepCondition; |
|||
|
|||
std::atomic<int> _handshakeTimeoutSecs; |
|||
static const int kDefaultHandShakeTimeoutSecs; |
|||
|
|||
// enable or disable PONG frame response to received PING frame |
|||
bool _enablePong; |
|||
static const bool kDefaultEnablePong; |
|||
|
|||
// Optional ping and pong timeout |
|||
int _pingIntervalSecs; |
|||
int _pingTimeoutSecs; |
|||
static const int kDefaultPingIntervalSecs; |
|||
static const int kDefaultPingTimeoutSecs; |
|||
|
|||
// Subprotocols |
|||
std::vector<std::string> _subProtocols; |
|||
|
|||
friend class WebSocketServer; |
|||
}; |
|||
} // namespace ix |
@ -1,37 +0,0 @@ |
|||
/* |
|||
* IXWebSocketCloseConstants.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketCloseConstants |
|||
{ |
|||
static const uint16_t kNormalClosureCode; |
|||
static const uint16_t kInternalErrorCode; |
|||
static const uint16_t kAbnormalCloseCode; |
|||
static const uint16_t kProtocolErrorCode; |
|||
static const uint16_t kNoStatusCodeErrorCode; |
|||
static const uint16_t kInvalidFramePayloadData; |
|||
|
|||
static const std::string kNormalClosureMessage; |
|||
static const std::string kInternalErrorMessage; |
|||
static const std::string kAbnormalCloseMessage; |
|||
static const std::string kPingTimeoutMessage; |
|||
static const std::string kProtocolErrorMessage; |
|||
static const std::string kNoStatusCodeErrorMessage; |
|||
static const std::string kProtocolErrorReservedBitUsed; |
|||
static const std::string kProtocolErrorPingPayloadOversized; |
|||
static const std::string kProtocolErrorCodeControlMessageFragmented; |
|||
static const std::string kProtocolErrorCodeDataOpcodeOutOfSequence; |
|||
static const std::string kProtocolErrorCodeContinuationOpCodeOutOfSequence; |
|||
static const std::string kInvalidFramePayloadDataMessage; |
|||
static const std::string kInvalidCloseCodeMessage; |
|||
}; |
|||
} // namespace ix |
@ -1,28 +0,0 @@ |
|||
/* |
|||
* IXWebSocketCloseInfo.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketCloseInfo |
|||
{ |
|||
uint16_t code; |
|||
std::string reason; |
|||
bool remote; |
|||
|
|||
WebSocketCloseInfo(uint16_t c = 0, const std::string& r = std::string(), bool rem = false) |
|||
: code(c) |
|||
, reason(r) |
|||
, remote(rem) |
|||
{ |
|||
; |
|||
} |
|||
}; |
|||
} // namespace ix |
@ -1,22 +0,0 @@ |
|||
/* |
|||
* IXWebSocketErrorInfo.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketErrorInfo |
|||
{ |
|||
uint32_t retries = 0; |
|||
double wait_time = 0; |
|||
int http_status = 0; |
|||
std::string reason; |
|||
bool decompressionError = false; |
|||
}; |
|||
} // namespace ix |
@ -1,54 +0,0 @@ |
|||
/* |
|||
* IXWebSocketHandshake.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include "IXSocket.h" |
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include "IXWebSocketInitResult.h" |
|||
#include "IXWebSocketPerMessageDeflate.h" |
|||
#include "IXWebSocketPerMessageDeflateOptions.h" |
|||
#include <atomic> |
|||
#include <chrono> |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class WebSocketHandshake |
|||
{ |
|||
public: |
|||
WebSocketHandshake(std::atomic<bool>& requestInitCancellation, |
|||
std::unique_ptr<Socket>& _socket, |
|||
WebSocketPerMessageDeflatePtr& perMessageDeflate, |
|||
WebSocketPerMessageDeflateOptions& perMessageDeflateOptions, |
|||
std::atomic<bool>& enablePerMessageDeflate); |
|||
|
|||
WebSocketInitResult clientHandshake(const std::string& url, |
|||
const WebSocketHttpHeaders& extraHeaders, |
|||
const std::string& host, |
|||
const std::string& path, |
|||
int port, |
|||
int timeoutSecs); |
|||
|
|||
WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate); |
|||
|
|||
private: |
|||
std::string genRandomString(const int len); |
|||
|
|||
// Parse HTTP headers |
|||
WebSocketInitResult sendErrorResponse(int code, const std::string& reason); |
|||
|
|||
bool insensitiveStringCompare(const std::string& a, const std::string& b); |
|||
|
|||
std::atomic<bool>& _requestInitCancellation; |
|||
std::unique_ptr<Socket>& _socket; |
|||
WebSocketPerMessageDeflatePtr& _perMessageDeflate; |
|||
WebSocketPerMessageDeflateOptions& _perMessageDeflateOptions; |
|||
std::atomic<bool>& _enablePerMessageDeflate; |
|||
}; |
|||
} // namespace ix |
@ -1,171 +0,0 @@ |
|||
// Copyright (c) 2016 Alex Hultman and contributors |
|||
|
|||
// This software is provided 'as-is', without any express or implied |
|||
// warranty. In no event will the authors be held liable for any damages |
|||
// arising from the use of this software. |
|||
|
|||
// Permission is granted to anyone to use this software for any purpose, |
|||
// including commercial applications, and to alter it and redistribute it |
|||
// freely, subject to the following restrictions: |
|||
|
|||
// 1. The origin of this software must not be misrepresented; you must not |
|||
// claim that you wrote the original software. If you use this software |
|||
// in a product, an acknowledgement in the product documentation would be |
|||
// appreciated but is not required. |
|||
// 2. Altered source versions must be plainly marked as such, and must not be |
|||
// misrepresented as being the original software. |
|||
// 3. This notice may not be removed or altered from any source distribution. |
|||
|
|||
#pragma once |
|||
|
|||
#include <cstddef> |
|||
#include <cstdint> |
|||
#include <string.h> |
|||
#include <string> |
|||
|
|||
class WebSocketHandshakeKeyGen |
|||
{ |
|||
template<int N, typename T> |
|||
struct static_for |
|||
{ |
|||
void operator()(uint32_t* a, uint32_t* b) |
|||
{ |
|||
static_for<N - 1, T>()(a, b); |
|||
T::template f<N - 1>(a, b); |
|||
} |
|||
}; |
|||
|
|||
template<typename T> |
|||
struct static_for<0, T> |
|||
{ |
|||
void operator()(uint32_t* /*a*/, uint32_t* /*hash*/) |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
template<int state> |
|||
struct Sha1Loop |
|||
{ |
|||
static inline uint32_t rol(uint32_t value, size_t bits) |
|||
{ |
|||
return (value << bits) | (value >> (32 - bits)); |
|||
} |
|||
static inline uint32_t blk(uint32_t b[16], size_t i) |
|||
{ |
|||
return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1); |
|||
} |
|||
|
|||
template<int i> |
|||
static inline void f(uint32_t* a, uint32_t* b) |
|||
{ |
|||
switch (state) |
|||
{ |
|||
case 1: |
|||
a[i % 5] += |
|||
((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + |
|||
b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); |
|||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
|||
break; |
|||
case 2: |
|||
b[i] = blk(b, i); |
|||
a[(1 + i) % 5] += |
|||
((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + |
|||
b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); |
|||
a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); |
|||
break; |
|||
case 3: |
|||
b[(i + 4) % 16] = blk(b, (i + 4) % 16); |
|||
a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + |
|||
b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); |
|||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
|||
break; |
|||
case 4: |
|||
b[(i + 8) % 16] = blk(b, (i + 8) % 16); |
|||
a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | |
|||
(a[(3 + i) % 5] & a[(2 + i) % 5])) + |
|||
b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); |
|||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
|||
break; |
|||
case 5: |
|||
b[(i + 12) % 16] = blk(b, (i + 12) % 16); |
|||
a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + |
|||
b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); |
|||
a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
|||
break; |
|||
case 6: b[i] += a[4 - i]; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
static inline void sha1(uint32_t hash[5], uint32_t b[16]) |
|||
{ |
|||
uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; |
|||
static_for<16, Sha1Loop<1>>()(a, b); |
|||
static_for<4, Sha1Loop<2>>()(a, b); |
|||
static_for<20, Sha1Loop<3>>()(a, b); |
|||
static_for<20, Sha1Loop<4>>()(a, b); |
|||
static_for<20, Sha1Loop<5>>()(a, b); |
|||
static_for<5, Sha1Loop<6>>()(a, hash); |
|||
} |
|||
|
|||
static inline void base64(unsigned char* src, char* dst) |
|||
{ |
|||
const char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|||
for (int i = 0; i < 18; i += 3) |
|||
{ |
|||
*dst++ = b64[(src[i] >> 2) & 63]; |
|||
*dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; |
|||
*dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; |
|||
*dst++ = b64[src[i + 2] & 63]; |
|||
} |
|||
*dst++ = b64[(src[18] >> 2) & 63]; |
|||
*dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; |
|||
*dst++ = b64[((src[19] & 15) << 2)]; |
|||
*dst++ = '='; |
|||
} |
|||
|
|||
public: |
|||
static inline void generate(const std::string& inputStr, char output[28]) |
|||
{ |
|||
char input[25] = {}; |
|||
strncpy(input, inputStr.c_str(), 25 - 1); |
|||
input[25 - 1] = '\0'; |
|||
|
|||
uint32_t b_output[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; |
|||
uint32_t b_input[16] = {0, |
|||
0, |
|||
0, |
|||
0, |
|||
0, |
|||
0, |
|||
0x32353845, |
|||
0x41464135, |
|||
0x2d453931, |
|||
0x342d3437, |
|||
0x44412d39, |
|||
0x3543412d, |
|||
0x43354142, |
|||
0x30444338, |
|||
0x35423131, |
|||
0x80000000}; |
|||
|
|||
for (int i = 0; i < 6; i++) |
|||
{ |
|||
b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | |
|||
(input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24; |
|||
} |
|||
sha1(b_output, b_input); |
|||
uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; |
|||
sha1(b_output, last_b); |
|||
for (int i = 0; i < 5; i++) |
|||
{ |
|||
uint32_t tmp = b_output[i]; |
|||
char* bytes = (char*) &b_output[i]; |
|||
bytes[3] = tmp & 0xff; |
|||
bytes[2] = (tmp >> 8) & 0xff; |
|||
bytes[1] = (tmp >> 16) & 0xff; |
|||
bytes[0] = (tmp >> 24) & 0xff; |
|||
} |
|||
base64((unsigned char*) b_output, output); |
|||
} |
|||
}; |
@ -1,23 +0,0 @@ |
|||
/* |
|||
* IXWebSocketHttpHeaders.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include "IXStrCaseCompare.h" |
|||
#include <map> |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class Socket; |
|||
|
|||
using WebSocketHttpHeaders = std::map<std::string, std::string, CaseInsensitiveLess>; |
|||
|
|||
std::pair<bool, WebSocketHttpHeaders> parseHttpHeaders( |
|||
std::unique_ptr<Socket>& socket, const CancellationRequest& isCancellationRequested); |
|||
} // namespace ix |
@ -1,36 +0,0 @@ |
|||
/* |
|||
* IXWebSocketInitResult.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXWebSocketHttpHeaders.h" |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketInitResult |
|||
{ |
|||
bool success; |
|||
int http_status; |
|||
std::string errorStr; |
|||
WebSocketHttpHeaders headers; |
|||
std::string uri; |
|||
std::string protocol; |
|||
|
|||
WebSocketInitResult(bool s = false, |
|||
int status = 0, |
|||
const std::string& e = std::string(), |
|||
WebSocketHttpHeaders h = WebSocketHttpHeaders(), |
|||
const std::string& u = std::string()) |
|||
{ |
|||
success = s; |
|||
http_status = status; |
|||
errorStr = e; |
|||
headers = h; |
|||
uri = u; |
|||
protocol = h["Sec-WebSocket-Protocol"]; |
|||
} |
|||
}; |
|||
} // namespace ix |
@ -1,60 +0,0 @@ |
|||
/* |
|||
* IXWebSocketMessage.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXWebSocketCloseInfo.h" |
|||
#include "IXWebSocketErrorInfo.h" |
|||
#include "IXWebSocketMessageType.h" |
|||
#include "IXWebSocketOpenInfo.h" |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketMessage |
|||
{ |
|||
WebSocketMessageType type; |
|||
const std::string& str; |
|||
size_t wireSize; |
|||
WebSocketErrorInfo errorInfo; |
|||
WebSocketOpenInfo openInfo; |
|||
WebSocketCloseInfo closeInfo; |
|||
bool binary; |
|||
|
|||
WebSocketMessage(WebSocketMessageType t, |
|||
const std::string& s, |
|||
size_t w, |
|||
WebSocketErrorInfo e, |
|||
WebSocketOpenInfo o, |
|||
WebSocketCloseInfo c, |
|||
bool b = false) |
|||
: type(t) |
|||
, str(s) |
|||
, wireSize(w) |
|||
, errorInfo(e) |
|||
, openInfo(o) |
|||
, closeInfo(c) |
|||
, binary(b) |
|||
{ |
|||
; |
|||
} |
|||
|
|||
/** |
|||
* @brief Deleted overload to prevent binding `str` to a temporary, which would cause |
|||
* undefined behavior since class members don't extend lifetime beyond the constructor call. |
|||
*/ |
|||
WebSocketMessage(WebSocketMessageType t, |
|||
std::string&& s, |
|||
size_t w, |
|||
WebSocketErrorInfo e, |
|||
WebSocketOpenInfo o, |
|||
WebSocketCloseInfo c, |
|||
bool b = false) = delete; |
|||
}; |
|||
|
|||
using WebSocketMessagePtr = std::unique_ptr<WebSocketMessage>; |
|||
} // namespace ix |
@ -1,21 +0,0 @@ |
|||
/* |
|||
* IXWebSocketMessageType.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
namespace ix |
|||
{ |
|||
enum class WebSocketMessageType |
|||
{ |
|||
Message = 0, |
|||
Open = 1, |
|||
Close = 2, |
|||
Error = 3, |
|||
Ping = 4, |
|||
Pong = 5, |
|||
Fragment = 6 |
|||
}; |
|||
} |
@ -1,31 +0,0 @@ |
|||
/* |
|||
* IXWebSocketOpenInfo.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketOpenInfo |
|||
{ |
|||
std::string uri; |
|||
WebSocketHttpHeaders headers; |
|||
std::string protocol; |
|||
|
|||
WebSocketOpenInfo(const std::string& u = std::string(), |
|||
const WebSocketHttpHeaders& h = WebSocketHttpHeaders(), |
|||
const std::string& p = std::string()) |
|||
: uri(u) |
|||
, headers(h) |
|||
, protocol(p) |
|||
{ |
|||
; |
|||
} |
|||
}; |
|||
} // namespace ix |
@ -1,64 +0,0 @@ |
|||
/* |
|||
* Copyright (c) 2015, Peter Thorson. All rights reserved. |
|||
* |
|||
* Redistribution and use in source and binary forms, with or without |
|||
* modification, are permitted provided that the following conditions are met: |
|||
* * Redistributions of source code must retain the above copyright |
|||
* notice, this list of conditions and the following disclaimer. |
|||
* * Redistributions in binary form must reproduce the above copyright |
|||
* notice, this list of conditions and the following disclaimer in the |
|||
* documentation and/or other materials provided with the distribution. |
|||
* * Neither the name of the WebSocket++ Project nor the |
|||
* names of its contributors may be used to endorse or promote products |
|||
* derived from this software without specific prior written permission. |
|||
* |
|||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY |
|||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
*/ |
|||
|
|||
/* |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
* |
|||
* Adapted from websocketpp/extensions/permessage_deflate/enabled.hpp |
|||
* (same license as MZ: https://opensource.org/licenses/BSD-3-Clause) |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <string> |
|||
#include "IXWebSocketSendData.h" |
|||
|
|||
namespace ix |
|||
{ |
|||
class WebSocketPerMessageDeflateOptions; |
|||
class WebSocketPerMessageDeflateCompressor; |
|||
class WebSocketPerMessageDeflateDecompressor; |
|||
|
|||
class WebSocketPerMessageDeflate |
|||
{ |
|||
public: |
|||
WebSocketPerMessageDeflate(); |
|||
~WebSocketPerMessageDeflate(); |
|||
|
|||
bool init(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions); |
|||
bool compress(const IXWebSocketSendData& in, std::string& out); |
|||
bool compress(const std::string& in, std::string& out); |
|||
bool decompress(const std::string& in, std::string& out); |
|||
|
|||
private: |
|||
std::unique_ptr<WebSocketPerMessageDeflateCompressor> _compressor; |
|||
std::unique_ptr<WebSocketPerMessageDeflateDecompressor> _decompressor; |
|||
}; |
|||
|
|||
using WebSocketPerMessageDeflatePtr = std::unique_ptr<WebSocketPerMessageDeflate>; |
|||
} // namespace ix |
@ -1,64 +0,0 @@ |
|||
/* |
|||
* IXWebSocketPerMessageDeflateCodec.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#ifdef IXWEBSOCKET_USE_ZLIB |
|||
#include "zlib.h" |
|||
#endif |
|||
#include <array> |
|||
#include <string> |
|||
#include <vector> |
|||
#include "IXWebSocketSendData.h" |
|||
|
|||
namespace ix |
|||
{ |
|||
class WebSocketPerMessageDeflateCompressor |
|||
{ |
|||
public: |
|||
WebSocketPerMessageDeflateCompressor(); |
|||
~WebSocketPerMessageDeflateCompressor(); |
|||
|
|||
bool init(uint8_t deflateBits, bool clientNoContextTakeOver); |
|||
bool compress(const IXWebSocketSendData& in, std::string& out); |
|||
bool compress(const std::string& in, std::string& out); |
|||
bool compress(const std::string& in, std::vector<uint8_t>& out); |
|||
bool compress(const std::vector<uint8_t>& in, std::string& out); |
|||
bool compress(const std::vector<uint8_t>& in, std::vector<uint8_t>& out); |
|||
|
|||
private: |
|||
template<typename T, typename S> |
|||
bool compressData(const T& in, S& out); |
|||
template<typename T> |
|||
bool endsWithEmptyUnCompressedBlock(const T& value); |
|||
|
|||
int _flush; |
|||
std::array<unsigned char, 1 << 14> _compressBuffer; |
|||
|
|||
#ifdef IXWEBSOCKET_USE_ZLIB |
|||
z_stream _deflateState; |
|||
#endif |
|||
}; |
|||
|
|||
class WebSocketPerMessageDeflateDecompressor |
|||
{ |
|||
public: |
|||
WebSocketPerMessageDeflateDecompressor(); |
|||
~WebSocketPerMessageDeflateDecompressor(); |
|||
|
|||
bool init(uint8_t inflateBits, bool clientNoContextTakeOver); |
|||
bool decompress(const std::string& in, std::string& out); |
|||
|
|||
private: |
|||
int _flush; |
|||
std::array<unsigned char, 1 << 14> _compressBuffer; |
|||
|
|||
#ifdef IXWEBSOCKET_USE_ZLIB |
|||
z_stream _inflateState; |
|||
#endif |
|||
}; |
|||
|
|||
} // namespace ix |
@ -1,47 +0,0 @@ |
|||
/* |
|||
* IXWebSocketPerMessageDeflateOptions.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
class WebSocketPerMessageDeflateOptions |
|||
{ |
|||
public: |
|||
WebSocketPerMessageDeflateOptions( |
|||
bool enabled = false, |
|||
bool clientNoContextTakeover = false, |
|||
bool serverNoContextTakeover = false, |
|||
uint8_t clientMaxWindowBits = kDefaultClientMaxWindowBits, |
|||
uint8_t serverMaxWindowBits = kDefaultServerMaxWindowBits); |
|||
|
|||
WebSocketPerMessageDeflateOptions(std::string extension); |
|||
|
|||
std::string generateHeader(); |
|||
bool enabled() const; |
|||
bool getClientNoContextTakeover() const; |
|||
bool getServerNoContextTakeover() const; |
|||
uint8_t getServerMaxWindowBits() const; |
|||
uint8_t getClientMaxWindowBits() const; |
|||
|
|||
static bool startsWith(const std::string& str, const std::string& start); |
|||
static std::string removeSpaces(const std::string& str); |
|||
|
|||
static uint8_t const kDefaultClientMaxWindowBits; |
|||
static uint8_t const kDefaultServerMaxWindowBits; |
|||
|
|||
private: |
|||
bool _enabled; |
|||
bool _clientNoContextTakeover; |
|||
bool _serverNoContextTakeover; |
|||
uint8_t _clientMaxWindowBits; |
|||
uint8_t _serverMaxWindowBits; |
|||
|
|||
void sanitizeClientMaxWindowBits(); |
|||
}; |
|||
} // namespace ix |
@ -1,24 +0,0 @@ |
|||
/* |
|||
* IXWebSocketProxyServer.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
#pragma once |
|||
|
|||
#include "IXSocketTLSOptions.h" |
|||
#include <cstdint> |
|||
#include <map> |
|||
#include <stddef.h> |
|||
#include <string> |
|||
|
|||
namespace ix |
|||
{ |
|||
using RemoteUrlsMapping = std::map<std::string, std::string>; |
|||
|
|||
int websocket_proxy_server_main(int port, |
|||
const std::string& hostname, |
|||
const ix::SocketTLSOptions& tlsOptions, |
|||
const std::string& remoteUrl, |
|||
const RemoteUrlsMapping& remoteUrlsMapping, |
|||
bool verbose); |
|||
} // namespace ix |
@ -1,128 +0,0 @@ |
|||
/* |
|||
* IXWebSocketSendData.h |
|||
* |
|||
* WebSocket (Binary/Text) send data buffer |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
#include <iterator> |
|||
|
|||
namespace ix |
|||
{ |
|||
/* |
|||
* IXWebSocketSendData implements a wrapper for std::string, std:vector<char/uint8_t> and char*. |
|||
* It removes the necessarity to copy the data or string into a std::string |
|||
*/ |
|||
class IXWebSocketSendData { |
|||
public: |
|||
|
|||
template<typename T> |
|||
struct IXWebSocketSendData_const_iterator |
|||
//: public std::iterator<std::forward_iterator_tag, T> |
|||
{ |
|||
typedef IXWebSocketSendData_const_iterator<T> const_iterator; |
|||
|
|||
using iterator_category = std::forward_iterator_tag; |
|||
using difference_type = std::ptrdiff_t; |
|||
using value_type = T; |
|||
using pointer = value_type*; |
|||
using reference = const value_type&; |
|||
|
|||
pointer _ptr; |
|||
public: |
|||
IXWebSocketSendData_const_iterator() : _ptr(nullptr) {} |
|||
IXWebSocketSendData_const_iterator(pointer ptr) : _ptr(ptr) {} |
|||
~IXWebSocketSendData_const_iterator() {} |
|||
|
|||
const_iterator operator++(int) { return const_iterator(_ptr++); } |
|||
const_iterator& operator++() { ++_ptr; return *this; } |
|||
reference operator* () const { return *_ptr; } |
|||
pointer operator->() const { return _ptr; } |
|||
const_iterator operator+ (const difference_type offset) const { return const_iterator(_ptr + offset); } |
|||
const_iterator operator- (const difference_type offset) const { return const_iterator(_ptr - offset); } |
|||
difference_type operator- (const const_iterator& rhs) const { return _ptr - rhs._ptr; } |
|||
bool operator==(const const_iterator& rhs) const { return _ptr == rhs._ptr; } |
|||
bool operator!=(const const_iterator& rhs) const { return _ptr != rhs._ptr; } |
|||
const_iterator& operator+=(const difference_type offset) { _ptr += offset; return *this; } |
|||
const_iterator& operator-=(const difference_type offset) { _ptr -= offset; return *this; } |
|||
}; |
|||
|
|||
using const_iterator = IXWebSocketSendData_const_iterator<char>; |
|||
|
|||
/* The assigned std::string must be kept alive for the lifetime of the input buffer */ |
|||
IXWebSocketSendData(const std::string& str) |
|||
: _data(str.data()) |
|||
, _size(str.size()) |
|||
{ |
|||
} |
|||
|
|||
/* The assigned std::vector must be kept alive for the lifetime of the input buffer */ |
|||
IXWebSocketSendData(const std::vector<char>& v) |
|||
: _data(v.data()) |
|||
, _size(v.size()) |
|||
{ |
|||
} |
|||
|
|||
/* The assigned std::vector must be kept alive for the lifetime of the input buffer */ |
|||
IXWebSocketSendData(const std::vector<uint8_t>& v) |
|||
: _data(reinterpret_cast<const char*>(v.data())) |
|||
, _size(v.size()) |
|||
{ |
|||
} |
|||
|
|||
/* The assigned memory must be kept alive for the lifetime of the input buffer */ |
|||
IXWebSocketSendData(const char* data, size_t size) |
|||
: _data(data) |
|||
, _size(data == nullptr ? 0 : size) |
|||
{ |
|||
} |
|||
|
|||
bool empty() const |
|||
{ |
|||
return _data == nullptr || _size == 0; |
|||
} |
|||
|
|||
const char* c_str() const |
|||
{ |
|||
return _data; |
|||
} |
|||
|
|||
const char* data() const |
|||
{ |
|||
return _data; |
|||
} |
|||
|
|||
size_t size() const |
|||
{ |
|||
return _size; |
|||
} |
|||
|
|||
inline const_iterator begin() const |
|||
{ |
|||
return const_iterator(const_cast<char*>(_data)); |
|||
} |
|||
|
|||
inline const_iterator end() const |
|||
{ |
|||
return const_iterator(const_cast<char*>(_data) + _size); |
|||
} |
|||
|
|||
inline const_iterator cbegin() const |
|||
{ |
|||
return begin(); |
|||
} |
|||
|
|||
inline const_iterator cend() const |
|||
{ |
|||
return end(); |
|||
} |
|||
|
|||
private: |
|||
const char* _data; |
|||
const size_t _size; |
|||
}; |
|||
|
|||
} |
@ -1,27 +0,0 @@ |
|||
/* |
|||
* IXWebSocketSendInfo.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
namespace ix |
|||
{ |
|||
struct WebSocketSendInfo |
|||
{ |
|||
bool success; |
|||
bool compressionError; |
|||
size_t payloadSize; |
|||
size_t wireSize; |
|||
|
|||
WebSocketSendInfo(bool s = false, bool c = false, size_t p = 0, size_t w = 0) |
|||
: success(s) |
|||
, compressionError(c) |
|||
, payloadSize(p) |
|||
, wireSize(w) |
|||
{ |
|||
; |
|||
} |
|||
}; |
|||
} // namespace ix |
@ -1,77 +0,0 @@ |
|||
/* |
|||
* IXWebSocketServer.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "IXSocketServer.h" |
|||
#include "IXWebSocket.h" |
|||
#include <condition_variable> |
|||
#include <functional> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <set> |
|||
#include <string> |
|||
#include <thread> |
|||
#include <utility> // pair |
|||
|
|||
namespace ix |
|||
{ |
|||
class WebSocketServer : public SocketServer |
|||
{ |
|||
public: |
|||
using OnConnectionCallback = |
|||
std::function<void(std::weak_ptr<WebSocket>, std::shared_ptr<ConnectionState>)>; |
|||
|
|||
using OnClientMessageCallback = std::function<void( |
|||
std::shared_ptr<ConnectionState>, WebSocket&, const WebSocketMessagePtr&)>; |
|||
|
|||
WebSocketServer(int port = SocketServer::kDefaultPort, |
|||
const std::string& host = SocketServer::kDefaultHost, |
|||
int backlog = SocketServer::kDefaultTcpBacklog, |
|||
size_t maxConnections = SocketServer::kDefaultMaxConnections, |
|||
int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs, |
|||
int addressFamily = SocketServer::kDefaultAddressFamily); |
|||
virtual ~WebSocketServer(); |
|||
virtual void stop() final; |
|||
|
|||
void enablePong(); |
|||
void disablePong(); |
|||
void disablePerMessageDeflate(); |
|||
|
|||
void setOnConnectionCallback(const OnConnectionCallback& callback); |
|||
void setOnClientMessageCallback(const OnClientMessageCallback& callback); |
|||
|
|||
// Get all the connected clients |
|||
std::set<std::shared_ptr<WebSocket>> getClients(); |
|||
|
|||
void makeBroadcastServer(); |
|||
bool listenAndStart(); |
|||
|
|||
const static int kDefaultHandShakeTimeoutSecs; |
|||
|
|||
int getHandshakeTimeoutSecs(); |
|||
bool isPongEnabled(); |
|||
bool isPerMessageDeflateEnabled(); |
|||
private: |
|||
// Member variables |
|||
int _handshakeTimeoutSecs; |
|||
bool _enablePong; |
|||
bool _enablePerMessageDeflate; |
|||
|
|||
OnConnectionCallback _onConnectionCallback; |
|||
OnClientMessageCallback _onClientMessageCallback; |
|||
|
|||
std::mutex _clientsMutex; |
|||
std::set<std::shared_ptr<WebSocket>> _clients; |
|||
|
|||
const static bool kDefaultEnablePong; |
|||
|
|||
// Methods |
|||
virtual void handleConnection(std::unique_ptr<Socket> socket, |
|||
std::shared_ptr<ConnectionState> connectionState); |
|||
virtual size_t getConnectedClientsCount() final; |
|||
}; |
|||
} // namespace ix |
@ -1,276 +0,0 @@ |
|||
/* |
|||
* IXWebSocketTransport.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
// |
|||
// Adapted from https://github.com/dhbaird/easywsclient |
|||
// |
|||
|
|||
#include "IXCancellationRequest.h" |
|||
#include "IXProgressCallback.h" |
|||
#include "IXSocketTLSOptions.h" |
|||
#include "IXWebSocketCloseConstants.h" |
|||
#include "IXWebSocketHandshake.h" |
|||
#include "IXWebSocketHttpHeaders.h" |
|||
#include "IXWebSocketPerMessageDeflate.h" |
|||
#include "IXWebSocketPerMessageDeflateOptions.h" |
|||
#include "IXWebSocketSendInfo.h" |
|||
#include "IXWebSocketSendData.h" |
|||
#include <atomic> |
|||
#include <functional> |
|||
#include <list> |
|||
#include <memory> |
|||
#include <mutex> |
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
namespace ix |
|||
{ |
|||
class Socket; |
|||
|
|||
enum class SendMessageKind |
|||
{ |
|||
Text, |
|||
Binary, |
|||
Ping |
|||
}; |
|||
|
|||
class WebSocketTransport |
|||
{ |
|||
public: |
|||
enum class ReadyState |
|||
{ |
|||
CLOSING, |
|||
CLOSED, |
|||
CONNECTING, |
|||
OPEN |
|||
}; |
|||
|
|||
enum class MessageKind |
|||
{ |
|||
MSG_TEXT, |
|||
MSG_BINARY, |
|||
PING, |
|||
PONG, |
|||
FRAGMENT |
|||
}; |
|||
|
|||
enum class PollResult |
|||
{ |
|||
Succeeded, |
|||
AbnormalClose, |
|||
CannotFlushSendBuffer |
|||
}; |
|||
|
|||
using OnMessageCallback = |
|||
std::function<void(const std::string&, size_t, bool, MessageKind)>; |
|||
using OnCloseCallback = std::function<void(uint16_t, const std::string&, size_t, bool)>; |
|||
|
|||
WebSocketTransport(); |
|||
~WebSocketTransport(); |
|||
|
|||
void configure(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions, |
|||
const SocketTLSOptions& socketTLSOptions, |
|||
bool enablePong, |
|||
int pingIntervalSecs); |
|||
|
|||
// Client |
|||
WebSocketInitResult connectToUrl(const std::string& url, |
|||
const WebSocketHttpHeaders& headers, |
|||
int timeoutSecs); |
|||
|
|||
// Server |
|||
WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, |
|||
int timeoutSecs, |
|||
bool enablePerMessageDeflate); |
|||
|
|||
PollResult poll(); |
|||
WebSocketSendInfo sendBinary(const IXWebSocketSendData& message, |
|||
const OnProgressCallback& onProgressCallback); |
|||
WebSocketSendInfo sendText(const IXWebSocketSendData& message, |
|||
const OnProgressCallback& onProgressCallback); |
|||
WebSocketSendInfo sendPing(const IXWebSocketSendData& message); |
|||
|
|||
void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, |
|||
const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage, |
|||
size_t closeWireSize = 0, |
|||
bool remote = false); |
|||
|
|||
void closeSocket(); |
|||
|
|||
ReadyState getReadyState() const; |
|||
void setReadyState(ReadyState readyState); |
|||
void setOnCloseCallback(const OnCloseCallback& onCloseCallback); |
|||
void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback); |
|||
size_t bufferedAmount() const; |
|||
|
|||
// internal |
|||
WebSocketSendInfo sendHeartBeat(); |
|||
|
|||
private: |
|||
std::string _url; |
|||
|
|||
struct wsheader_type |
|||
{ |
|||
unsigned header_size; |
|||
bool fin; |
|||
bool rsv1; |
|||
bool rsv2; |
|||
bool rsv3; |
|||
bool mask; |
|||
enum opcode_type |
|||
{ |
|||
CONTINUATION = 0x0, |
|||
TEXT_FRAME = 0x1, |
|||
BINARY_FRAME = 0x2, |
|||
CLOSE = 8, |
|||
PING = 9, |
|||
PONG = 0xa, |
|||
} opcode; |
|||
int N0; |
|||
uint64_t N; |
|||
uint8_t masking_key[4]; |
|||
}; |
|||
|
|||
// Tells whether we should mask the data we send. |
|||
// client should mask but server should not |
|||
std::atomic<bool> _useMask; |
|||
|
|||
// Tells whether we should flush the send buffer before |
|||
// saying that a send is complete. This is the mode for server code. |
|||
std::atomic<bool> _blockingSend; |
|||
|
|||
// 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 is resized |
|||
std::vector<uint8_t> _rxbuf; |
|||
|
|||
// Contains all messages that are waiting to be sent |
|||
std::vector<uint8_t> _txbuf; |
|||
mutable std::mutex _txbufMutex; |
|||
|
|||
// 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::string> _chunks; |
|||
|
|||
// Record the message kind (will be TEXT or BINARY) for a fragmented |
|||
// message, present in the first chunk, since the final chunk will be a |
|||
// CONTINUATION opcode and doesn't tell the full message kind |
|||
MessageKind _fragmentedMessageKind; |
|||
|
|||
// Ditto for whether a message is compressed |
|||
bool _receivedMessageCompressed; |
|||
|
|||
// Fragments are 32K long |
|||
static constexpr size_t kChunkSize = 1 << 15; |
|||
|
|||
// Underlying TCP socket |
|||
std::unique_ptr<Socket> _socket; |
|||
std::mutex _socketMutex; |
|||
|
|||
// Hold the state of the connection (OPEN, CLOSED, etc...) |
|||
std::atomic<ReadyState> _readyState; |
|||
|
|||
OnCloseCallback _onCloseCallback; |
|||
std::string _closeReason; |
|||
mutable std::mutex _closeReasonMutex; |
|||
std::atomic<uint16_t> _closeCode; |
|||
std::atomic<size_t> _closeWireSize; |
|||
std::atomic<bool> _closeRemote; |
|||
|
|||
// Data used for Per Message Deflate compression (with zlib) |
|||
WebSocketPerMessageDeflatePtr _perMessageDeflate; |
|||
WebSocketPerMessageDeflateOptions _perMessageDeflateOptions; |
|||
std::atomic<bool> _enablePerMessageDeflate; |
|||
|
|||
std::string _decompressedMessage; |
|||
std::string _compressedMessage; |
|||
|
|||
// Used to control TLS connection behavior |
|||
SocketTLSOptions _socketTLSOptions; |
|||
|
|||
// Used to cancel dns lookup + socket connect + http upgrade |
|||
std::atomic<bool> _requestInitCancellation; |
|||
|
|||
mutable std::mutex _closingTimePointMutex; |
|||
std::chrono::time_point<std::chrono::steady_clock> _closingTimePoint; |
|||
static const int kClosingMaximumWaitingDelayInMs; |
|||
|
|||
// enable auto response to ping |
|||
std::atomic<bool> _enablePong; |
|||
static const bool kDefaultEnablePong; |
|||
|
|||
// Optional ping and pong timeout |
|||
int _pingIntervalSecs; |
|||
std::atomic<bool> _pongReceived; |
|||
|
|||
static const int kDefaultPingIntervalSecs; |
|||
static const std::string kPingMessage; |
|||
std::atomic<uint64_t> _pingCount; |
|||
|
|||
// We record when ping are being sent so that we can know when to send the next one |
|||
mutable std::mutex _lastSendPingTimePointMutex; |
|||
std::chrono::time_point<std::chrono::steady_clock> _lastSendPingTimePoint; |
|||
|
|||
// If this function returns true, it is time to send a new ping |
|||
bool pingIntervalExceeded(); |
|||
void initTimePointsAfterConnect(); |
|||
|
|||
// after calling close(), if no CLOSE frame answer is received back from the remote, we |
|||
// should close the connexion |
|||
bool closingDelayExceeded(); |
|||
|
|||
void sendCloseFrame(uint16_t code, const std::string& reason); |
|||
|
|||
void closeSocketAndSwitchToClosedState(uint16_t code, |
|||
const std::string& reason, |
|||
size_t closeWireSize, |
|||
bool remote); |
|||
|
|||
bool wakeUpFromPoll(uint64_t wakeUpCode); |
|||
|
|||
bool flushSendBuffer(); |
|||
bool sendOnSocket(); |
|||
bool receiveFromSocket(); |
|||
|
|||
WebSocketSendInfo sendData(wsheader_type::opcode_type type, |
|||
const IXWebSocketSendData& message, |
|||
bool compress, |
|||
const OnProgressCallback& onProgressCallback = nullptr); |
|||
|
|||
template<class Iterator> |
|||
bool sendFragment( |
|||
wsheader_type::opcode_type type, bool fin, Iterator begin, Iterator end, bool compress); |
|||
|
|||
void emitMessage(MessageKind messageKind, |
|||
const std::string& message, |
|||
bool compressedMessage, |
|||
const OnMessageCallback& onMessageCallback); |
|||
|
|||
bool isSendBufferEmpty() const; |
|||
|
|||
template<class Iterator> |
|||
void appendToSendBuffer(const std::vector<uint8_t>& header, |
|||
Iterator begin, |
|||
Iterator end, |
|||
uint64_t message_size, |
|||
uint8_t masking_key[4]); |
|||
|
|||
unsigned getRandomUnsigned(); |
|||
void unmaskReceiveBuffer(const wsheader_type& ws); |
|||
|
|||
std::string getMergedChunks() const; |
|||
|
|||
void setCloseReason(const std::string& reason); |
|||
const std::string& getCloseReason() const; |
|||
}; |
|||
} // namespace ix |
@ -1,9 +0,0 @@ |
|||
/* |
|||
* IXWebSocketVersion.h |
|||
* Author: Benjamin Sergeant |
|||
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#define IX_WEBSOCKET_VERSION "11.4.3" |
@ -1,48 +1,3 @@ |
|||
[server] |
|||
cmdport=19004 |
|||
wsport=19005 |
|||
|
|||
[[channels]] |
|||
type="zexcan" |
|||
name="zexcan" |
|||
[basic] |
|||
ifname="can0" |
|||
baudrate=500000 |
|||
enable=true |
|||
|
|||
[[channels]] |
|||
type="uart" |
|||
name="uart_p0" |
|||
alias="uart_p0" |
|||
ifname="/dev/ttyS5" |
|||
baudrate=115200 |
|||
rxovertime=3 |
|||
hexchar=true |
|||
enable=true |
|||
|
|||
[[channels]] |
|||
type="uart" |
|||
name="uart_p1" |
|||
alias="uart_p1" |
|||
ifname="/dev/ttyS0" |
|||
baudrate=115200 |
|||
rxovertime=3 |
|||
hexchar=true |
|||
enable=true |
|||
|
|||
[[channels]] |
|||
type="uart" |
|||
name="uart_p2" |
|||
alias="uart_p2" |
|||
ifname="/dev/ttyS1" |
|||
baudrate=115200 |
|||
rxovertime=3 |
|||
hexchar=true |
|||
enable=true |
|||
|
|||
[[channels]] |
|||
type="gpio-key" |
|||
name="key" |
|||
pins=["GPIO3_A6"] # IO0->GPIO3_A6, |
|||
pinalias=["io0"] |
|||
mirror=[true] |
|||
enable=true |
|||
baudrate=500000 |
@ -0,0 +1,41 @@ |
|||
#include "app.hpp"
|
|||
|
|||
#include <toml++/toml.hpp>
|
|||
|
|||
#include "utils/stringutils.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace std; |
|||
|
|||
void App::initialize() { |
|||
try { |
|||
auto config = toml::parse_file("config.ini"); |
|||
string ifname = config["basic"]["ifname"].value_or("can0"); |
|||
int baudrate = config["basic"]["baudrate"].value_or(500000); |
|||
|
|||
m_zcanreceiverhost.reset(new ZCanReceiverHost()); |
|||
m_zcanreceiverhost->initialize(ifname, baudrate); |
|||
} catch (const toml::parse_error& err) { |
|||
logger->error("parse config error, {}", err); |
|||
exit(1); |
|||
} |
|||
|
|||
m_unixsocket.reset(new UnixScoket(UnixScoket::Server, "zexcan")); |
|||
m_unixsocket->start(); |
|||
|
|||
m_zcanreceiverhost->registerListener([this](uint8_t fromboardid, uint8_t* packet, size_t packetlen) { |
|||
string hexStr = StringUtils().bytesToString((uint8_t*)packet, packetlen); |
|||
logger->info("RX_FROM_CAN:<- {}({})", hexStr, hexStr.size()); |
|||
|
|||
// Tx to Unix socket
|
|||
m_unixsocket->sendPacket(packet, packetlen); |
|||
}); |
|||
|
|||
m_unixsocket->onPacket.connect([this](const uint8_t* packet, size_t packetlen) { |
|||
logger->info("RX_FROM_UNIX_SOCKET:-> {}", StringUtils().bytesToString((uint8_t*)packet, packetlen)); |
|||
|
|||
// Tx to CAN
|
|||
m_zcanreceiverhost->sendPacket((uint8_t*)packet, packetlen); |
|||
}); |
|||
} |
@ -0,0 +1,33 @@ |
|||
|
|||
#include <signal.h>
|
|||
|
|||
//
|
|||
#include "configs/version.hpp"
|
|||
//
|
|||
//
|
|||
|
|||
#include "components/linuxsocket//unix_socket.hpp"
|
|||
#include "components/thread/thread.hpp"
|
|||
#include "components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
#include "thirdlib/nod/nod.hpp"
|
|||
#include "thirdlib/spdlogfactory/logger_factory.hpp"
|
|||
|
|||
namespace iflytop { |
|||
|
|||
using namespace std; |
|||
using namespace core; |
|||
|
|||
class App { |
|||
ENABLE_LOGGER(App); |
|||
|
|||
private: |
|||
unique_ptr<ZCanReceiverHost> m_zcanreceiverhost; |
|||
unique_ptr<UnixScoket> m_unixsocket; |
|||
|
|||
public: |
|||
App() {} |
|||
|
|||
void initialize(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -0,0 +1,45 @@ |
|||
#include "unix_socket.hpp"
|
|||
using namespace iflytop; |
|||
using namespace std; |
|||
using namespace core; |
|||
|
|||
void UnixScoket::start() { |
|||
logger->info("Creating UNIX domain socket at path: {}", m_path); |
|||
logger->info("Connecting to opposite path: {}", m_opposite_path); |
|||
|
|||
sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
|||
if (sock_fd == -1) { |
|||
logger->error("socket creation failed: {}", strerror(errno)); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
// Remove socket file if it already exists
|
|||
unlink(m_path.c_str()); |
|||
if (bind(sock_fd, (struct sockaddr *)&rx_addr, sizeof(rx_addr)) == -1) { |
|||
perror("bind"); |
|||
close(sock_fd); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
m_thread.reset(new Thread("UnixSocketThread", [this]() { |
|||
uint8_t rxbuffer[1024]; |
|||
struct sockaddr_un client_addr; |
|||
ThisThread thisThread; |
|||
while (!thisThread.getExitFlag()) { |
|||
memset(rxbuffer, 0, sizeof(rxbuffer)); |
|||
socklen_t client_len = sizeof(client_addr); |
|||
ssize_t num_bytes = recvfrom(sock_fd, rxbuffer, sizeof(rxbuffer) - 1, 0, (struct sockaddr *)&client_addr, &client_len); |
|||
if (num_bytes > 0) { |
|||
onPacket(rxbuffer, num_bytes); |
|||
} |
|||
} |
|||
close(sock_fd); |
|||
unlink(m_path.c_str()); |
|||
})); |
|||
} |
|||
void UnixScoket::sendPacket(uint8_t *data, size_t len) { |
|||
int ret = sendto(sock_fd, data, len, 0, (struct sockaddr *)&tx_addr, sizeof(tx_addr)); |
|||
if (ret == -1) { |
|||
logger->error("sendto failed: {}", strerror(errno)); |
|||
} |
|||
} |
@ -0,0 +1,68 @@ |
|||
//
|
|||
// Created by zwsd
|
|||
//
|
|||
|
|||
#pragma once
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/un.h>
|
|||
#include <unistd.h>
|
|||
|
|||
#include <mutex>
|
|||
|
|||
#include "components/thread/thread.hpp"
|
|||
#include "thirdlib/nod/nod.hpp"
|
|||
#include "thirdlib/spdlogfactory/logger_factory.hpp"
|
|||
|
|||
namespace iflytop { |
|||
|
|||
using namespace std; |
|||
using namespace core; |
|||
|
|||
class UnixScoket { |
|||
ENABLE_LOGGER(UnixScoket); |
|||
|
|||
public: |
|||
typedef enum { |
|||
Server, |
|||
Client, |
|||
} role_t; |
|||
|
|||
private: |
|||
string m_path; |
|||
string m_opposite_path; |
|||
role_t m_role; |
|||
|
|||
int sock_fd = -1; |
|||
|
|||
struct sockaddr_un rx_addr; |
|||
struct sockaddr_un tx_addr; |
|||
|
|||
unique_ptr<Thread> m_thread; |
|||
|
|||
public: |
|||
nod::signal<void(uint8_t*, size_t)> onPacket; |
|||
|
|||
public: |
|||
UnixScoket(role_t role, string path) { //
|
|||
m_role = role; |
|||
|
|||
m_path = fmt::format("/tmp/un_socket_{}_{}", path, m_role == Server ? "server" : "client"); |
|||
m_opposite_path = fmt::format("/tmp/un_socket_{}_{}", path, m_role == Server ? "client" : "server"); |
|||
|
|||
memset(&rx_addr, 0, sizeof(rx_addr)); |
|||
rx_addr.sun_family = AF_UNIX; |
|||
strncpy(rx_addr.sun_path, m_path.c_str(), sizeof(rx_addr.sun_path) - 1); |
|||
|
|||
memset(&tx_addr, 0, sizeof(tx_addr)); |
|||
tx_addr.sun_family = AF_UNIX; |
|||
strncpy(tx_addr.sun_path, m_opposite_path.c_str(), sizeof(tx_addr.sun_path) - 1); |
|||
|
|||
} |
|||
|
|||
void start(); |
|||
void sendPacket(uint8_t* data, size_t len); |
|||
}; |
|||
} // namespace iflytop
|
@ -0,0 +1,63 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
|
|||
#define SOCKET_PATH "/tmp/unix_dgram_demo" |
|||
|
|||
int main() { |
|||
int sock_fd; |
|||
struct sockaddr_un server_addr, client_addr; |
|||
socklen_t client_len; |
|||
char buffer[256]; |
|||
|
|||
// Create socket |
|||
sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
|||
if (sock_fd == -1) { |
|||
perror("socket"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
// Remove socket file if it already exists |
|||
unlink(SOCKET_PATH); |
|||
|
|||
// Configure server address |
|||
memset(&server_addr, 0, sizeof(server_addr)); |
|||
server_addr.sun_family = AF_UNIX; |
|||
strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1); |
|||
|
|||
// Bind socket to address |
|||
if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { |
|||
perror("bind"); |
|||
close(sock_fd); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
printf("Receiver is waiting for messages on %s...\n", SOCKET_PATH); |
|||
|
|||
// Receive message |
|||
client_len = sizeof(client_addr); |
|||
ssize_t num_bytes = recvfrom(sock_fd, buffer, sizeof(buffer) - 1, 0, |
|||
(struct sockaddr *)&client_addr, &client_len); |
|||
if (num_bytes == -1) { |
|||
perror("recvfrom"); |
|||
} else { |
|||
buffer[num_bytes] = '\0'; |
|||
printf("Received message: %s\n", buffer); |
|||
|
|||
// Send response |
|||
const char *response = "Hello from receiver!"; |
|||
if (sendto(sock_fd, response, strlen(response), 0, |
|||
(struct sockaddr *)&client_addr, client_len) == -1) { |
|||
perror("sendto"); |
|||
} |
|||
} |
|||
|
|||
// Clean up |
|||
close(sock_fd); |
|||
unlink(SOCKET_PATH); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,70 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
|
|||
#define SOCKET_PATH "/tmp/unix_dgram_demo" |
|||
#define SENDER_PATH "/tmp/unix_dgram_sender" |
|||
|
|||
int main() { |
|||
int sock_fd; |
|||
struct sockaddr_un server_addr, client_addr; |
|||
char buffer[256]; |
|||
|
|||
// Create socket |
|||
sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
|||
if (sock_fd == -1) { |
|||
perror("socket"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
// Configure client address (we need to bind to send/receive) |
|||
memset(&client_addr, 0, sizeof(client_addr)); |
|||
client_addr.sun_family = AF_UNIX; |
|||
strncpy(client_addr.sun_path, SENDER_PATH, sizeof(client_addr.sun_path) - 1); |
|||
|
|||
// Remove socket file if it already exists |
|||
unlink(SENDER_PATH); |
|||
|
|||
// Bind to our own address (required for receiving response) |
|||
if (bind(sock_fd, (struct sockaddr *)&client_addr, sizeof(client_addr)) == -1) { |
|||
perror("bind"); |
|||
close(sock_fd); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
// Configure server address |
|||
memset(&server_addr, 0, sizeof(server_addr)); |
|||
server_addr.sun_family = AF_UNIX; |
|||
strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1); |
|||
|
|||
// Send message to server |
|||
const char *message = "Hello from sender!"; |
|||
if (sendto(sock_fd, message, strlen(message), 0, |
|||
(struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { |
|||
perror("sendto"); |
|||
close(sock_fd); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
printf("Message sent to receiver.\n"); |
|||
|
|||
// Receive response |
|||
socklen_t server_len = sizeof(server_addr); |
|||
ssize_t num_bytes = recvfrom(sock_fd, buffer, sizeof(buffer) - 1, 0, |
|||
(struct sockaddr *)&server_addr, &server_len); |
|||
if (num_bytes == -1) { |
|||
perror("recvfrom"); |
|||
} else { |
|||
buffer[num_bytes] = '\0'; |
|||
printf("Received response: %s\n", buffer); |
|||
} |
|||
|
|||
// Clean up |
|||
close(sock_fd); |
|||
unlink(SENDER_PATH); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,5 @@ |
|||
mkdir -p buildpc |
|||
cd buildpc |
|||
cmake .. |
|||
make -j8 |
|||
make install |
Write
Preview
Loading…
Cancel
Save
Reference in new issue