#pragma once #if defined(_WIN32) #include #endif // include the Defold SDK #include #if !defined(__EMSCRIPTEN__) #define HAVE_WSLAY 1 #endif #if defined(HAVE_WSLAY) #include #endif #include #include #include #include #include namespace dmCrypt { void HashSha1(const uint8_t* buf, uint32_t buflen, uint8_t* digest); bool Base64Encode(const uint8_t* src, uint32_t src_len, uint8_t* dst, uint32_t* dst_len); bool Base64Decode(const uint8_t* src, uint32_t src_len, uint8_t* dst, uint32_t* dst_len); } namespace dmWebsocket { // Maximum time to wait for a socket static const int SOCKET_WAIT_TIMEOUT = 4*1000; enum State { STATE_CONNECTING, STATE_HANDSHAKE_WRITE, STATE_HANDSHAKE_READ, STATE_CONNECTED, STATE_DISCONNECTED, }; enum Result { RESULT_OK, RESULT_ERROR, RESULT_FAIL_WSLAY_INIT, RESULT_NOT_CONNECTED, RESULT_HANDSHAKE_FAILED, RESULT_WOULDBLOCK, }; enum Event { EVENT_CONNECTED, EVENT_DISCONNECTED, EVENT_MESSAGE, EVENT_ERROR, }; struct WebsocketConnection { dmScript::LuaCallbackInfo* m_Callback; #if defined(HAVE_WSLAY) wslay_event_context_ptr m_Ctx; #endif dmURI::Parts m_Url; dmConnectionPool::HConnection m_Connection; dmSocket::Socket m_Socket; dmSSLSocket::Socket m_SSLSocket; dmArray m_Messages; // lengths of the messages in the data buffer uint8_t m_Key[16]; State m_State; char* m_Buffer; int m_BufferSize; uint32_t m_BufferCapacity; Result m_Status; uint8_t m_SSL:1; uint8_t m_HasHandshakeData:1; uint8_t :6; }; // Set error message #ifdef __GNUC__ Result SetStatus(WebsocketConnection* conn, Result status, const char* fmt, ...) __attribute__ ((format (printf, 3, 4))); #else Result SetStatus(WebsocketConnection* conn, Result status, const char* fmt, ...); #endif // Communication dmSocket::Result Send(WebsocketConnection* conn, const char* buffer, int length, int* out_sent_bytes); dmSocket::Result Receive(WebsocketConnection* conn, void* buffer, int length, int* received_bytes); dmSocket::Result WaitForSocket(WebsocketConnection* conn, dmSocket::SelectorKind kind, int timeout); // Handshake Result SendClientHandshake(WebsocketConnection* conn); Result ReceiveHeaders(WebsocketConnection* conn); Result VerifyHeaders(WebsocketConnection* conn); // Messages Result PushMessage(WebsocketConnection* conn, int length); #if defined(HAVE_WSLAY) // Wslay callbacks int WSL_Init(wslay_event_context_ptr* ctx, ssize_t buffer_size, void* userctx); void WSL_Exit(wslay_event_context_ptr ctx); int WSL_Close(wslay_event_context_ptr ctx); int WSL_Poll(wslay_event_context_ptr ctx); int WSL_WantsExit(wslay_event_context_ptr ctx); ssize_t WSL_RecvCallback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, int flags, void *user_data); ssize_t WSL_SendCallback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data); void WSL_OnMsgRecvCallback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data); int WSL_GenmaskCallback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data); const char* WSL_ResultToString(int err); #endif // Random numbers (PCG) typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t; void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq); uint32_t pcg32_random_r(pcg32_random_t* rng); // If level <= dmWebSocket::g_DebugWebSocket, then it outputs the message #ifdef __GNUC__ void DebugLog(int level, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); #else void DebugLog(int level, const char* fmt, ...); #endif void DebugPrint(int level, const char* msg, const void* _bytes, uint32_t num_bytes); }