mirror of
https://github.com/defold/extension-websocket.git
synced 2025-06-27 01:47:42 +02:00
Added support for SSL
This commit is contained in:
parent
0e589290ed
commit
1e6c534609
@ -707,6 +707,68 @@ nodes {
|
|||||||
text_leading: 1.0
|
text_leading: 1.0
|
||||||
text_tracking: 0.0
|
text_tracking: 0.0
|
||||||
}
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 320.0
|
||||||
|
y: 568.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "<text>"
|
||||||
|
font: "example"
|
||||||
|
id: "connection_text"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
layers {
|
layers {
|
||||||
name: "below"
|
name: "below"
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
--local websocket_async = require "websocket.client_async"
|
|
||||||
|
|
||||||
local URL="://echo.websocket.org"
|
local URL="://echo.websocket.org"
|
||||||
|
|
||||||
local function click_button(node, action)
|
local function click_button(node, action)
|
||||||
--print("mouse", action.x, action.y)
|
--print("mouse", action.x, action.y)
|
||||||
|
|
||||||
return gui.is_enabled(node) and action.released and gui.pick_node(node, action.x, action.y)
|
return gui.is_enabled(node) and action.pressed and gui.pick_node(node, action.x, action.y)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_buttons(self)
|
local function http_handle_response(self, id, response)
|
||||||
|
print(response.status, response.response)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_gui(self)
|
||||||
if self.connection then
|
if self.connection then
|
||||||
gui.set_enabled(self.connect_ws_node, false)
|
gui.set_enabled(self.connect_ws_node, false)
|
||||||
gui.set_enabled(self.connect_wss_node, false)
|
gui.set_enabled(self.connect_wss_node, false)
|
||||||
gui.set_enabled(self.send_node, true)
|
gui.set_enabled(self.send_node, true)
|
||||||
gui.set_enabled(self.close_node, true)
|
gui.set_enabled(self.close_node, true)
|
||||||
|
gui.set_enabled(self.connection_text, true)
|
||||||
|
gui.set_text(self.connection_text, "Connected to " .. self.url)
|
||||||
else
|
else
|
||||||
gui.set_enabled(self.connect_ws_node, true)
|
gui.set_enabled(self.connect_ws_node, true)
|
||||||
gui.set_enabled(self.connect_wss_node, true)
|
gui.set_enabled(self.connect_wss_node, true)
|
||||||
gui.set_enabled(self.send_node, false)
|
gui.set_enabled(self.send_node, false)
|
||||||
gui.set_enabled(self.close_node, false)
|
gui.set_enabled(self.close_node, false)
|
||||||
|
gui.set_enabled(self.connection_text, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -41,7 +46,10 @@ function init(self)
|
|||||||
self.connect_wss_node = gui.get_node("connect_wss/button")
|
self.connect_wss_node = gui.get_node("connect_wss/button")
|
||||||
self.send_node = gui.get_node("send/button")
|
self.send_node = gui.get_node("send/button")
|
||||||
self.close_node = gui.get_node("close/button")
|
self.close_node = gui.get_node("close/button")
|
||||||
update_buttons(self)
|
self.connection_text = gui.get_node("connection_text")
|
||||||
|
update_gui(self)
|
||||||
|
|
||||||
|
--http.request("https://www.google.com", "GET", http_handle_response)
|
||||||
|
|
||||||
self.connection = nil
|
self.connection = nil
|
||||||
end
|
end
|
||||||
@ -59,7 +67,7 @@ end
|
|||||||
local function websocket_callback(self, conn, data)
|
local function websocket_callback(self, conn, data)
|
||||||
if data.event == websocket.EVENT_DISCONNECTED then
|
if data.event == websocket.EVENT_DISCONNECTED then
|
||||||
self.connection = nil
|
self.connection = nil
|
||||||
update_buttons(self)
|
update_gui(self)
|
||||||
if data.error then
|
if data.error then
|
||||||
log("Diconnect error:", data.error)
|
log("Diconnect error:", data.error)
|
||||||
self.connection = nil
|
self.connection = nil
|
||||||
@ -69,7 +77,7 @@ local function websocket_callback(self, conn, data)
|
|||||||
log("Connection error:", data.error)
|
log("Connection error:", data.error)
|
||||||
self.connection = nil
|
self.connection = nil
|
||||||
end
|
end
|
||||||
update_buttons(self)
|
update_gui(self)
|
||||||
elseif data.event == websocket.EVENT_MESSAGE then
|
elseif data.event == websocket.EVENT_MESSAGE then
|
||||||
log("Receiving: '" .. tostring(data.message) .. "'")
|
log("Receiving: '" .. tostring(data.message) .. "'")
|
||||||
end
|
end
|
||||||
@ -84,12 +92,11 @@ local function connect(self, scheme)
|
|||||||
--options = "all",
|
--options = "all",
|
||||||
}
|
}
|
||||||
|
|
||||||
local url = scheme .. URL
|
self.url = scheme .. URL
|
||||||
|
log("Connecting to " .. self.url)
|
||||||
log("Connecting to " .. url)
|
self.connection = websocket.connect(self.url, params, websocket_callback)
|
||||||
self.connection = websocket.connect(url, params, websocket_callback)
|
|
||||||
if self.connection == nil then
|
if self.connection == nil then
|
||||||
print("Failed to connect to " .. url .. ": " .. err)
|
print("Failed to connect to " .. self.url .. ": " .. err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -104,10 +111,8 @@ end
|
|||||||
function on_input(self, action_id, action)
|
function on_input(self, action_id, action)
|
||||||
--print("MAWE", action_id)
|
--print("MAWE", action_id)
|
||||||
if click_button(self.connect_ws_node, action) then
|
if click_button(self.connect_ws_node, action) then
|
||||||
print("MAWE click connect_ws_node")
|
|
||||||
connect(self, "ws")
|
connect(self, "ws")
|
||||||
elseif click_button(self.connect_wss_node, action) then
|
elseif click_button(self.connect_wss_node, action) then
|
||||||
print("MAWE click connect_wss_node")
|
|
||||||
connect(self, "wss")
|
connect(self, "wss")
|
||||||
elseif click_button(self.close_node, action) then
|
elseif click_button(self.close_node, action) then
|
||||||
disconnect(self)
|
disconnect(self)
|
||||||
|
@ -5,4 +5,4 @@ platforms:
|
|||||||
common:
|
common:
|
||||||
context:
|
context:
|
||||||
includes: ["upload/websocket/include/wslay"]
|
includes: ["upload/websocket/include/wslay"]
|
||||||
defines: ["FOO"]
|
defines: ["HAVE_CONFIG_H"]
|
||||||
|
@ -1,174 +0,0 @@
|
|||||||
// Copyright 2020 The Defold Foundation
|
|
||||||
// Licensed under the Defold License version 1.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License.
|
|
||||||
//
|
|
||||||
// You may obtain a copy of the License, together with FAQs at
|
|
||||||
// https://www.defold.com/license
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
#ifndef DMSDK_CONNECTION_POOL
|
|
||||||
#define DMSDK_CONNECTION_POOL
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <dlib/socket.h>
|
|
||||||
#include <dlib/dns.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection pooling
|
|
||||||
*/
|
|
||||||
namespace dmConnectionPool
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Connection pool handle
|
|
||||||
*/
|
|
||||||
typedef struct ConnectionPool* HPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection handle
|
|
||||||
*/
|
|
||||||
typedef uint32_t HConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result codes
|
|
||||||
*/
|
|
||||||
enum Result
|
|
||||||
{
|
|
||||||
RESULT_OK = 0, //!< RESULT_OK
|
|
||||||
RESULT_OUT_OF_RESOURCES = -1,//!< RESULT_OUT_OF_RESOURCES
|
|
||||||
RESULT_SOCKET_ERROR = -2, //!< RESULT_SOCKET_ERROR
|
|
||||||
RESULT_HANDSHAKE_FAILED = -3,//!< RESULT_HANDSHAKE_FAILED
|
|
||||||
RESULT_SHUT_DOWN = -4, //<! RESULT_SHUT_DOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats
|
|
||||||
*/
|
|
||||||
struct Stats
|
|
||||||
{
|
|
||||||
uint32_t m_Free;
|
|
||||||
uint32_t m_Connected;
|
|
||||||
uint32_t m_InUse;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters
|
|
||||||
*/
|
|
||||||
struct Params
|
|
||||||
{
|
|
||||||
Params()
|
|
||||||
{
|
|
||||||
m_MaxConnections = 64;
|
|
||||||
m_MaxKeepAlive = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Max connection in pool
|
|
||||||
uint32_t m_MaxConnections;
|
|
||||||
/// Default max-keep-alive time in seconds
|
|
||||||
uint32_t m_MaxKeepAlive;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new connection pool
|
|
||||||
* @param params
|
|
||||||
* @param pool
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result New(const Params* params, HPool* pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete connnection pool
|
|
||||||
* @param pool
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Delete(HPool pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set max keep-alive for sockets in seconds. Sockets older than max_keep_alive
|
|
||||||
* are not reused and hence closed
|
|
||||||
* @param pool
|
|
||||||
* @param max_keep_alive
|
|
||||||
*/
|
|
||||||
void SetMaxKeepAlive(HPool pool, uint32_t max_keep_alive);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get statistics
|
|
||||||
* @param pool
|
|
||||||
* @param stats
|
|
||||||
*/
|
|
||||||
void GetStats(HPool pool, Stats* stats);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection to a host/port
|
|
||||||
* @param pool pool
|
|
||||||
* @param host host
|
|
||||||
* @param port port
|
|
||||||
* @param dns_channel The DNS channel that will be used for translating the host to an address
|
|
||||||
* @param ssl true for ssl connection
|
|
||||||
* @param timeout The timeout (micro seconds) for the connection and ssl handshake
|
|
||||||
* @param connection connection (out)
|
|
||||||
* @param sock_res socket-result code on failure
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Dial(HPool pool, const char* host, uint16_t port, dmDNS::HChannel dns_channel, bool ssl, int timeout, HConnection* connection, dmSocket::Result* sock_res);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return connection to pool
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
*/
|
|
||||||
void Return(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close connection. Use this function whenever an error occur in eg http.
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
*/
|
|
||||||
void Close(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get socket for connection
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
dmSocket::Socket GetSocket(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get ssl-handle. The returned value is an mbedtls_ssl_context* (mbedtls)
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return An mbedtls_ssl_context* pointer on success
|
|
||||||
*/
|
|
||||||
void* GetSSLConnection(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get reuse count for a connection
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return reuse count
|
|
||||||
*/
|
|
||||||
uint32_t GetReuseCount(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shuts down all open sockets in the pool and block new connection attempts. The function can be
|
|
||||||
* called repeatedly on the same pool until it returns no more connections in use.
|
|
||||||
*
|
|
||||||
* @param pool pool
|
|
||||||
* @param how shutdown type to pass to socket shutdown function
|
|
||||||
* @return current number of connections in use
|
|
||||||
*/
|
|
||||||
uint32_t Shutdown(HPool pool, dmSocket::ShutdownType how);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reopen the pool from a Shutdown call so it allows Dialing again. This function is here so the pool can be reset
|
|
||||||
* during testing, or subsequent tests will break when the pool has been put in shutdown mode.
|
|
||||||
*/
|
|
||||||
void Reopen(HPool pool);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #ifndef DMSDK_CONNECTION_POOL
|
|
@ -1,174 +0,0 @@
|
|||||||
// Copyright 2020 The Defold Foundation
|
|
||||||
// Licensed under the Defold License version 1.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License.
|
|
||||||
//
|
|
||||||
// You may obtain a copy of the License, together with FAQs at
|
|
||||||
// https://www.defold.com/license
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
#ifndef DMSDK_CONNECTION_POOL
|
|
||||||
#define DMSDK_CONNECTION_POOL
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <dlib/socket.h>
|
|
||||||
#include <dlib/dns.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection pooling
|
|
||||||
*/
|
|
||||||
namespace dmConnectionPool
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Connection pool handle
|
|
||||||
*/
|
|
||||||
typedef struct ConnectionPool* HPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection handle
|
|
||||||
*/
|
|
||||||
typedef uint32_t HConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result codes
|
|
||||||
*/
|
|
||||||
enum Result
|
|
||||||
{
|
|
||||||
RESULT_OK = 0, //!< RESULT_OK
|
|
||||||
RESULT_OUT_OF_RESOURCES = -1,//!< RESULT_OUT_OF_RESOURCES
|
|
||||||
RESULT_SOCKET_ERROR = -2, //!< RESULT_SOCKET_ERROR
|
|
||||||
RESULT_HANDSHAKE_FAILED = -3,//!< RESULT_HANDSHAKE_FAILED
|
|
||||||
RESULT_SHUT_DOWN = -4, //<! RESULT_SHUT_DOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stats
|
|
||||||
*/
|
|
||||||
struct Stats
|
|
||||||
{
|
|
||||||
uint32_t m_Free;
|
|
||||||
uint32_t m_Connected;
|
|
||||||
uint32_t m_InUse;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters
|
|
||||||
*/
|
|
||||||
struct Params
|
|
||||||
{
|
|
||||||
Params()
|
|
||||||
{
|
|
||||||
m_MaxConnections = 64;
|
|
||||||
m_MaxKeepAlive = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Max connection in pool
|
|
||||||
uint32_t m_MaxConnections;
|
|
||||||
/// Default max-keep-alive time in seconds
|
|
||||||
uint32_t m_MaxKeepAlive;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new connection pool
|
|
||||||
* @param params
|
|
||||||
* @param pool
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result New(const Params* params, HPool* pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete connnection pool
|
|
||||||
* @param pool
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Delete(HPool pool);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set max keep-alive for sockets in seconds. Sockets older than max_keep_alive
|
|
||||||
* are not reused and hence closed
|
|
||||||
* @param pool
|
|
||||||
* @param max_keep_alive
|
|
||||||
*/
|
|
||||||
void SetMaxKeepAlive(HPool pool, uint32_t max_keep_alive);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get statistics
|
|
||||||
* @param pool
|
|
||||||
* @param stats
|
|
||||||
*/
|
|
||||||
void GetStats(HPool pool, Stats* stats);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection to a host/port
|
|
||||||
* @param pool pool
|
|
||||||
* @param host host
|
|
||||||
* @param port port
|
|
||||||
* @param dns_channel The DNS channel that will be used for translating the host to an address
|
|
||||||
* @param ssl true for ssl connection
|
|
||||||
* @param timeout The timeout (micro seconds) for the connection and ssl handshake
|
|
||||||
* @param connection connection (out)
|
|
||||||
* @param sock_res socket-result code on failure
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Dial(HPool pool, const char* host, uint16_t port, dmDNS::HChannel dns_channel, bool ssl, int timeout, HConnection* connection, dmSocket::Result* sock_res);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return connection to pool
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
*/
|
|
||||||
void Return(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close connection. Use this function whenever an error occur in eg http.
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
*/
|
|
||||||
void Close(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get socket for connection
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
dmSocket::Socket GetSocket(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get ssl-handle. The returned value is an mbedtls_ssl_context* (mbedtls)
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return An mbedtls_ssl_context* pointer on success
|
|
||||||
*/
|
|
||||||
void* GetSSLConnection(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get reuse count for a connection
|
|
||||||
* @param pool
|
|
||||||
* @param connection
|
|
||||||
* @return reuse count
|
|
||||||
*/
|
|
||||||
uint32_t GetReuseCount(HPool pool, HConnection connection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shuts down all open sockets in the pool and block new connection attempts. The function can be
|
|
||||||
* called repeatedly on the same pool until it returns no more connections in use.
|
|
||||||
*
|
|
||||||
* @param pool pool
|
|
||||||
* @param how shutdown type to pass to socket shutdown function
|
|
||||||
* @return current number of connections in use
|
|
||||||
*/
|
|
||||||
uint32_t Shutdown(HPool pool, dmSocket::ShutdownType how);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reopen the pool from a Shutdown call so it allows Dialing again. This function is here so the pool can be reset
|
|
||||||
* during testing, or subsequent tests will break when the pool has been put in shutdown mode.
|
|
||||||
*/
|
|
||||||
void Reopen(HPool pool);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // #ifndef DMSDK_CONNECTION_POOL
|
|
@ -1,93 +0,0 @@
|
|||||||
// Copyright 2020 The Defold Foundation
|
|
||||||
// Licensed under the Defold License version 1.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License.
|
|
||||||
//
|
|
||||||
// You may obtain a copy of the License, together with FAQs at
|
|
||||||
// https://www.defold.com/license
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
#ifndef DM_DNS_H
|
|
||||||
#define DM_DNS_H
|
|
||||||
|
|
||||||
namespace dmSocket
|
|
||||||
{
|
|
||||||
struct Address;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace dmDNS
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A channel roughly translates to a socket on which to put the name lookup requests on.
|
|
||||||
* Internal implementation resides in dns.cpp.
|
|
||||||
*/
|
|
||||||
struct Channel;
|
|
||||||
typedef Channel* HChannel;
|
|
||||||
|
|
||||||
enum Result
|
|
||||||
{
|
|
||||||
RESULT_OK = 0,
|
|
||||||
RESULT_INIT_ERROR = -1,
|
|
||||||
RESULT_HOST_NOT_FOUND = -2,
|
|
||||||
RESULT_CANCELLED = -3,
|
|
||||||
RESULT_UNKNOWN_ERROR = -4
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the DNS system. Some platforms require socket initialization to be called
|
|
||||||
* before this function. I.e: call dmSocket::Initialize() before dmDNS::Initialize() on win32.
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Initialize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalize DNS system.
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Finalize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new channel that can be used for DNS queries.
|
|
||||||
* @param channel Pointer to the created channel if successfull, will be left alone otherwise
|
|
||||||
* @return RESULT_OK on succcess
|
|
||||||
*/
|
|
||||||
Result NewChannel(HChannel* channel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the current request (if available) on a channel.
|
|
||||||
* @param channel Handle to the channel
|
|
||||||
*/
|
|
||||||
void StopChannel(HChannel channel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the current channel and cancels all requests.
|
|
||||||
* Note: You must always make sure to call StopChannel(channel) before calling this function.
|
|
||||||
* @param channel Handle to the channel
|
|
||||||
*/
|
|
||||||
void DeleteChannel(HChannel channel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the channel configuration so that the latest DNS servers are used.
|
|
||||||
* @param channel Handle to the channel
|
|
||||||
*/
|
|
||||||
Result RefreshChannel(HChannel channel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get host by name. Note that this function is not entirely thread-safe, even though it is used in a threaded environment.
|
|
||||||
* @param name Hostname to resolve
|
|
||||||
* @param address Host address result
|
|
||||||
* @param channel Channel handle to put the request on. The function does not handle invalid handles - the channel handle must exist.
|
|
||||||
* @param ipv4 Whether or not to search for IPv4 addresses
|
|
||||||
* @param ipv6 Whether or not to search for IPv6 addresses
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result GetHostByName(const char* name, dmSocket::Address* address, HChannel channel, bool ipv4 = true, bool ipv6 = true);
|
|
||||||
|
|
||||||
// Used for unit testing
|
|
||||||
const char* ResultToString(Result r);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //DM_DSTRINGS_H
|
|
@ -1,570 +0,0 @@
|
|||||||
// Copyright 2020 The Defold Foundation
|
|
||||||
// Licensed under the Defold License version 1.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License.
|
|
||||||
//
|
|
||||||
// You may obtain a copy of the License, together with FAQs at
|
|
||||||
// https://www.defold.com/license
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
#ifndef DM_SOCKET_H
|
|
||||||
#define DM_SOCKET_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h> // memset, memcmp
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__MACH__) || defined(ANDROID) || defined(__EMSCRIPTEN__) || defined(__NX__)
|
|
||||||
#include <sys/select.h>
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#error "Unsupported platform"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket abstraction
|
|
||||||
* @note For Recv* and Send* function ETIMEDOUT is translated to EWOULDBLOCK
|
|
||||||
* on win32 for compatibility with BSD sockets.
|
|
||||||
*/
|
|
||||||
namespace dmSocket
|
|
||||||
{
|
|
||||||
struct Selector
|
|
||||||
{
|
|
||||||
fd_set m_FdSets[3];
|
|
||||||
int m_Nfds;
|
|
||||||
Selector();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket result
|
|
||||||
*/
|
|
||||||
enum Result
|
|
||||||
{
|
|
||||||
RESULT_OK = 0, //!< RESULT_OK
|
|
||||||
|
|
||||||
RESULT_ACCES = -1, //!< RESULT_ACCES
|
|
||||||
RESULT_AFNOSUPPORT = -2, //!< RESULT_AFNOSUPPORT
|
|
||||||
RESULT_WOULDBLOCK = -3, //!< RESULT_WOULDBLOCK
|
|
||||||
RESULT_BADF = -4, //!< RESULT_BADF
|
|
||||||
RESULT_CONNRESET = -5, //!< RESULT_CONNRESET
|
|
||||||
RESULT_DESTADDRREQ = -6, //!< RESULT_DESTADDRREQ
|
|
||||||
RESULT_FAULT = -7, //!< RESULT_FAULT
|
|
||||||
RESULT_HOSTUNREACH = -8, //!< RESULT_HOSTUNREACH
|
|
||||||
RESULT_INTR = -9, //!< RESULT_INTR
|
|
||||||
RESULT_INVAL = -10, //!< RESULT_INVAL
|
|
||||||
RESULT_ISCONN = -11, //!< RESULT_ISCONN
|
|
||||||
RESULT_MFILE = -12, //!< RESULT_MFILE
|
|
||||||
RESULT_MSGSIZE = -13, //!< RESULT_MSGSIZE
|
|
||||||
RESULT_NETDOWN = -14, //!< RESULT_NETDOWN
|
|
||||||
RESULT_NETUNREACH = -15, //!< RESULT_NETUNREACH
|
|
||||||
//RESULT_NFILE = -16,
|
|
||||||
RESULT_NOBUFS = -17, //!< RESULT_NOBUFS
|
|
||||||
//RESULT_NOENT = -18,
|
|
||||||
//RESULT_NOMEM = -19,
|
|
||||||
RESULT_NOTCONN = -20, //!< RESULT_NOTCONN
|
|
||||||
//RESULT_NOTDIR = -21,
|
|
||||||
RESULT_NOTSOCK = -22, //!< RESULT_NOTSOCK
|
|
||||||
RESULT_OPNOTSUPP = -23, //!< RESULT_OPNOTSUPP
|
|
||||||
RESULT_PIPE = -24, //!< RESULT_PIPE
|
|
||||||
RESULT_PROTONOSUPPORT = -25, //!< RESULT_PROTONOSUPPORT
|
|
||||||
RESULT_PROTOTYPE = -26, //!< RESULT_PROTOTYPE
|
|
||||||
RESULT_TIMEDOUT = -27, //!< RESULT_TIMEDOUT
|
|
||||||
|
|
||||||
RESULT_ADDRNOTAVAIL = -28, //!< RESULT_ADDRNOTAVAIL
|
|
||||||
RESULT_CONNREFUSED = -29, //!< RESULT_CONNREFUSED
|
|
||||||
RESULT_ADDRINUSE = -30, //!< RESULT_ADDRINUSE
|
|
||||||
RESULT_CONNABORTED = -31, //!< RESULT_CONNABORTED
|
|
||||||
RESULT_INPROGRESS = -32, //!< RESULT_INPROGRESS
|
|
||||||
|
|
||||||
// gethostbyname errors
|
|
||||||
RESULT_HOST_NOT_FOUND = -100, //!< RESULT_HOST_NOT_FOUND
|
|
||||||
RESULT_TRY_AGAIN = -101, //!< RESULT_TRY_AGAIN
|
|
||||||
RESULT_NO_RECOVERY = -102, //!< RESULT_NO_RECOVERY
|
|
||||||
RESULT_NO_DATA = -103, //!< RESULT_NO_DATA
|
|
||||||
|
|
||||||
RESULT_UNKNOWN = -1000,//!< RESULT_UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket handle
|
|
||||||
* @note Use INVALID_SOCKET_HANDLE instead of zero for unset values. This is an exception
|
|
||||||
* from all other handles.
|
|
||||||
*/
|
|
||||||
typedef int Socket;
|
|
||||||
|
|
||||||
enum SelectorKind
|
|
||||||
{
|
|
||||||
SELECTOR_KIND_READ = 0,
|
|
||||||
SELECTOR_KIND_WRITE = 1,
|
|
||||||
SELECTOR_KIND_EXCEPT = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
FLAGS_UP = (1 << 0),
|
|
||||||
FLAGS_RUNNING = (1 << 1),
|
|
||||||
FLAGS_INET = (1 << 2),
|
|
||||||
FLAGS_LINK = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalid socket handle
|
|
||||||
*/
|
|
||||||
const Socket INVALID_SOCKET_HANDLE = 0xffffffff;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Domain type
|
|
||||||
*/
|
|
||||||
enum Domain
|
|
||||||
{
|
|
||||||
DOMAIN_MISSING, //!< DOMAIN_MISSING
|
|
||||||
DOMAIN_IPV4, //!< DOMAIN_IPV4
|
|
||||||
DOMAIN_IPV6, //!< DOMAIN_IPV6
|
|
||||||
DOMAIN_UNKNOWN, //!< DOMAIN_UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket type
|
|
||||||
*/
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
TYPE_STREAM, //!< TYPE_STREAM
|
|
||||||
TYPE_DGRAM, //!< TYPE_DGRAM
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Network protocol
|
|
||||||
*/
|
|
||||||
enum Protocol
|
|
||||||
{
|
|
||||||
PROTOCOL_TCP, //!< PROTOCOL_TCP
|
|
||||||
PROTOCOL_UDP, //!< PROTOCOL_UDP
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket shutdown type
|
|
||||||
*/
|
|
||||||
enum ShutdownType
|
|
||||||
{
|
|
||||||
SHUTDOWNTYPE_READ,
|
|
||||||
SHUTDOWNTYPE_WRITE,
|
|
||||||
SHUTDOWNTYPE_READWRITE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Network address
|
|
||||||
* Network addresses were previously represented as an uint32_t, but in
|
|
||||||
* order to support IPv6 the internal representation was changed to a
|
|
||||||
* struct.
|
|
||||||
*/
|
|
||||||
struct Address
|
|
||||||
{
|
|
||||||
|
|
||||||
Address() {
|
|
||||||
m_family = dmSocket::DOMAIN_MISSING;
|
|
||||||
memset(m_address, 0x0, sizeof(m_address));
|
|
||||||
}
|
|
||||||
|
|
||||||
Domain m_family;
|
|
||||||
uint32_t m_address[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparison operators for dmSocket::Address (network address).
|
|
||||||
* These operators are required since network code was initially designed
|
|
||||||
* with the assumption that addresses were stored as uint32_t (IPv4), and
|
|
||||||
* thus sortable.
|
|
||||||
*/
|
|
||||||
inline bool operator==(const Address& lhs, const Address& rhs)
|
|
||||||
{
|
|
||||||
return memcmp(lhs.m_address, rhs.m_address, sizeof(lhs.m_address)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator< (const Address& lhs, const Address& rhs)
|
|
||||||
{
|
|
||||||
return memcmp(lhs.m_address, rhs.m_address, sizeof(lhs.m_address)) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!=(const Address& lhs, const Address& rhs) { return !operator==(lhs,rhs); }
|
|
||||||
inline bool operator> (const Address& lhs, const Address& rhs) { return operator< (rhs,lhs); }
|
|
||||||
inline bool operator<=(const Address& lhs, const Address& rhs) { return !operator> (lhs,rhs); }
|
|
||||||
inline bool operator>=(const Address& lhs, const Address& rhs) { return !operator< (lhs,rhs); }
|
|
||||||
|
|
||||||
struct IfAddr
|
|
||||||
{
|
|
||||||
char m_Name[128];
|
|
||||||
uint32_t m_Flags;
|
|
||||||
Address m_Address;
|
|
||||||
uint8_t m_MacAddress[6];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize socket system. Network initialization is required on some platforms.
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Initialize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalize socket system.
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Finalize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new socket. Corresponds to BSD socket function socket().
|
|
||||||
* @note SIGPIPE is disabled on applicable platforms. This has the implication
|
|
||||||
* that Receive can return zero bytes when the connection is closed by remote peer.
|
|
||||||
* @param type Soccket type
|
|
||||||
* @param protocol Protocol
|
|
||||||
* @param socket Pointer to created socket
|
|
||||||
* @return RESULT_OK on succcess
|
|
||||||
*/
|
|
||||||
Result New(Domain domain, Type type, enum Protocol protocol, Socket* socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a socket. Corresponds to BSD socket function close()
|
|
||||||
* @param socket Socket to close
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Delete(Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get underlying file descriptor
|
|
||||||
* @param socket socket to get fd for
|
|
||||||
* @return file-descriptor
|
|
||||||
*/
|
|
||||||
int GetFD(Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set reuse socket address option on socket. Socket option SO_REUSEADDR on most platforms
|
|
||||||
* @param socket Socket to set reuse address to
|
|
||||||
* @param reuse True if reuse
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetReuseAddress(Socket socket, bool reuse);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set broadcast address option on socket. Socket option SO_BROADCAST on most platforms.
|
|
||||||
* @param socket Socket to set reuse address to
|
|
||||||
* @param broadcast True if broadcast
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetBroadcast(Socket socket, bool broadcast);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set blocking option on a socket
|
|
||||||
* @param socket Socket to set blocking on
|
|
||||||
* @param blocking True to block
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetBlocking(Socket socket, bool blocking);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set TCP_NODELAY on socket
|
|
||||||
* @param socket Socket to set TCP_NODELAY on
|
|
||||||
* @param no_delay True for no delay
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetNoDelay(Socket socket, bool no_delay);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set socket send timeout
|
|
||||||
* @note Timeout resolution might be in milliseconds, e.g. windows. Use values
|
|
||||||
* larger than or equal to 1000.
|
|
||||||
* @param socket socket
|
|
||||||
* @param timeout timeout in microseconds
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetSendTimeout(Socket socket, uint64_t timeout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set socket receive timeout
|
|
||||||
* @note Timeout resolution might be in milliseconds, e.g. windows. Use values
|
|
||||||
* larger than or equal to 1000
|
|
||||||
* @param socket socket
|
|
||||||
* @param timeout timeout in microseconds
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SetReceiveTimeout(Socket socket, uint64_t timeout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add multicast membership
|
|
||||||
* @param socket socket to add membership on
|
|
||||||
* @param multi_addr multicast address
|
|
||||||
* @param interface_addr interface address
|
|
||||||
* @param ttl multicast package time to live
|
|
||||||
* @return RESULT_OK
|
|
||||||
*/
|
|
||||||
Result AddMembership(Socket socket, Address multi_addr, Address interface_addr, int ttl);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set address for outgoing multicast datagrams
|
|
||||||
* @param socket socket to set multicast address for
|
|
||||||
* @param address address of network interface to use
|
|
||||||
* @return RESULT_OK
|
|
||||||
*/
|
|
||||||
Result SetMulticastIf(Socket socket, Address address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept a connection on a socket
|
|
||||||
* @param socket Socket to accept connections on
|
|
||||||
* @param address Result address parameter
|
|
||||||
* @param accept_socket Pointer to accepted socket (result)
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Accept(Socket socket, Address* address, Socket* accept_socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind a name to a socket
|
|
||||||
* @param socket Socket to bind name to
|
|
||||||
* @param address Address to bind
|
|
||||||
* @param port Port to bind to
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Bind(Socket socket, Address address, int port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiate a connection on a socket
|
|
||||||
* @param socket Socket to initiate connection on
|
|
||||||
* @param address Address to connect to
|
|
||||||
* @param port Port to connect to
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Connect(Socket socket, Address address, int port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen for connections on a socket
|
|
||||||
* @param socket Socket to listen on
|
|
||||||
* @param backlog Maximum length for the queue of pending connections
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Listen(Socket socket, int backlog);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shutdown part of a socket connection
|
|
||||||
* @param socket Socket to shutdown connection ow
|
|
||||||
* @param how Shutdown type
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Shutdown(Socket socket, ShutdownType how);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message on a socket
|
|
||||||
* @param socket Socket to send a message on
|
|
||||||
* @param buffer Buffer to send
|
|
||||||
* @param length Length of buffer to send
|
|
||||||
* @param sent_bytes Number of bytes sent (result)
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Send(Socket socket, const void* buffer, int length, int* sent_bytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message to a specific address
|
|
||||||
* @param socket Socket to send a message on
|
|
||||||
* @param buffer Buffer to send
|
|
||||||
* @param length Length of buffer to send
|
|
||||||
* @param sent_bytes Number of bytes sent (result)
|
|
||||||
* @param to_addr To address
|
|
||||||
* @param to_port From addres
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result SendTo(Socket socket, const void* buffer, int length, int* sent_bytes, Address to_addr, uint16_t to_port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive data on a socket
|
|
||||||
* @param socket Socket to receive data on
|
|
||||||
* @param buffer Buffer to receive to
|
|
||||||
* @param length Receive buffer length
|
|
||||||
* @param received_bytes Number of received bytes (result)
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Receive(Socket socket, void* buffer, int length, int* received_bytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive from socket
|
|
||||||
* @param socket Socket to receive data on
|
|
||||||
* @param buffer Buffer to receive to
|
|
||||||
* @param length Receive buffer length
|
|
||||||
* @param received_bytes Number of received bytes (result)
|
|
||||||
* @param from_addr From address (result)
|
|
||||||
* @param from_port To address (result)
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result ReceiveFrom(Socket socket, void* buffer, int length, int* received_bytes,
|
|
||||||
Address* from_addr, uint16_t* from_port);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get name, address and port for socket
|
|
||||||
* @param socket Socket to get name for
|
|
||||||
* @param address Address (result)
|
|
||||||
* @param port Socket (result)
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result GetName(Socket socket, Address*address, uint16_t* port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get local hostname
|
|
||||||
* @param hostname hostname buffer
|
|
||||||
* @param hostname_length hostname buffer length
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result GetHostname(char* hostname, int hostname_length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get first local IP address
|
|
||||||
* The function tries to determine the local IP address. If several
|
|
||||||
* IP addresses are available only a single is returned
|
|
||||||
* @note This function might fallback to 127.0.0.1 if no adapter is found
|
|
||||||
* Sometimes it might be appropriate to run this function periodically
|
|
||||||
* @param address address result
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result GetLocalAddress(Address* address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get address from ip string
|
|
||||||
* @param address IP-string
|
|
||||||
* @return Address
|
|
||||||
*/
|
|
||||||
Address AddressFromIPString(const char* address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert address to ip string
|
|
||||||
* @param address address to convert
|
|
||||||
* @return IP string. The caller is responsible to free the string using free()
|
|
||||||
*/
|
|
||||||
char* AddressToIPString(Address address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get host by name.
|
|
||||||
* @param name Hostname to resolve
|
|
||||||
* @param address Host address result
|
|
||||||
* @param ipv4 Whether or not to search for IPv4 addresses
|
|
||||||
* @param ipv6 Whether or not to search for IPv6 addresses
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result GetHostByName(const char* name, Address* address, bool ipv4 = true, bool ipv6 = true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get information about network adapters (loopback devices are not included)
|
|
||||||
* @note Make sure that addresses is large enough. If too small
|
|
||||||
* the result is capped.
|
|
||||||
* @param addresses array of if-addresses
|
|
||||||
* @param addresses_count count
|
|
||||||
* @param count actual count
|
|
||||||
*/
|
|
||||||
void GetIfAddresses(IfAddr* addresses, uint32_t addresses_count, uint32_t* count);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert result value to string
|
|
||||||
* @param result Result to convert
|
|
||||||
* @return Result as string
|
|
||||||
*/
|
|
||||||
const char* ResultToString(Result result);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a native result (error) to dmSocket::Result
|
|
||||||
* Also logs the error
|
|
||||||
* @param filename the file that calls this function
|
|
||||||
* @param line the line number of this call
|
|
||||||
* @param r the native result
|
|
||||||
* @return Result
|
|
||||||
*/
|
|
||||||
Result NativeToResult(const char* filename, int line, int r);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a network address is empty (all zeroes).
|
|
||||||
* @param address The address to check
|
|
||||||
* @return True if the address is empty, false otherwise
|
|
||||||
*/
|
|
||||||
bool Empty(Address address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a pointer to the IPv4 buffer of address.
|
|
||||||
* @note Make sure the address family of address is actually AF_INET before
|
|
||||||
* attempting to retrieve the IPv4 buffer, otherwise an assert will trigger.
|
|
||||||
* @param address Pointer to the address containing the buffer
|
|
||||||
* @return Pointer to the buffer that holds the IPv4 address
|
|
||||||
*/
|
|
||||||
uint32_t* IPv4(Address* address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a pointer to the IPv6 buffer of address.
|
|
||||||
* @note Make sure the address family of address is actually AF_INET6 before
|
|
||||||
* attempting to retrieve the IPv6 buffer, otherwise an assert will trigger.
|
|
||||||
* @param address Pointer to the address containing the buffer
|
|
||||||
* @return Pointer to the buffer that holds the IPv6 address
|
|
||||||
*/
|
|
||||||
uint32_t* IPv6(Address* address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a socket was created for IPv4 (AF_INET).
|
|
||||||
* @param socket The socket to check
|
|
||||||
* @return True if the socket was created for IPv4 communication, false otherwise
|
|
||||||
*/
|
|
||||||
bool IsSocketIPv4(Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a socket was created for IPv6 (AF_INET6).
|
|
||||||
* @param socket The socket to check
|
|
||||||
* @return True if the socket was created for IPv6 communication, false otherwise
|
|
||||||
*/
|
|
||||||
bool IsSocketIPv6(Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the number of bits that differs between address a and b.
|
|
||||||
* @note This is used for the Hamming Distance.
|
|
||||||
* @param a The first address to compare
|
|
||||||
* @param b The second address to compare
|
|
||||||
* @return Number of bits that differs between a and b
|
|
||||||
*/
|
|
||||||
uint32_t BitDifference(Address a, Address b);
|
|
||||||
|
|
||||||
struct Selector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear selector for socket. Similar to FD_CLR
|
|
||||||
* @param selector Selector
|
|
||||||
* @param selector_kind Kind to clear
|
|
||||||
* @param socket Socket to clear
|
|
||||||
*/
|
|
||||||
void SelectorClear(Selector* selector, SelectorKind selector_kind, Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set selector for socket. Similar to FD_SET
|
|
||||||
* @param selector Selector
|
|
||||||
* @param selector_kind Kind to clear
|
|
||||||
* @param socket Socket to set
|
|
||||||
*/
|
|
||||||
void SelectorSet(Selector* selector, SelectorKind selector_kind, Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if selector is set. Similar to FD_ISSET
|
|
||||||
* @param selector Selector
|
|
||||||
* @param selector_kind Selector kind
|
|
||||||
* @param socket Socket to check for
|
|
||||||
* @return True if set.
|
|
||||||
*/
|
|
||||||
bool SelectorIsSet(Selector* selector, SelectorKind selector_kind, Socket socket);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear selector (all kinds). Similar to FD_ZERO
|
|
||||||
* @param selector Selector
|
|
||||||
*/
|
|
||||||
void SelectorZero(Selector* selector);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select for pending data
|
|
||||||
* @param selector Selector
|
|
||||||
* @param timeout Timeout. For blocking pass -1
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Select(Selector* selector, int32_t timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DM_SOCKET_H
|
|
@ -1,85 +0,0 @@
|
|||||||
// Copyright 2020 The Defold Foundation
|
|
||||||
// Licensed under the Defold License version 1.0 (the "License"); you may not use
|
|
||||||
// this file except in compliance with the License.
|
|
||||||
//
|
|
||||||
// You may obtain a copy of the License, together with FAQs at
|
|
||||||
// https://www.defold.com/license
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
// specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
#ifndef DM_URI_H
|
|
||||||
#define DM_URI_H
|
|
||||||
|
|
||||||
namespace dmURI
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* URI parsing result
|
|
||||||
*/
|
|
||||||
enum Result
|
|
||||||
{
|
|
||||||
RESULT_OK,//!< RESULT_OK
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint32_t MAX_SCHEME_LEN = 8;
|
|
||||||
const uint32_t MAX_LOCATION_LEN = 64;
|
|
||||||
const uint32_t MAX_PATH_LEN = 2048;
|
|
||||||
// Maximum length of an URI
|
|
||||||
// scheme :// location / path
|
|
||||||
const uint32_t MAX_URI_LEN = MAX_SCHEME_LEN + 3 + MAX_LOCATION_LEN + 1 + MAX_PATH_LEN;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URI parsing result parts
|
|
||||||
*/
|
|
||||||
struct Parts
|
|
||||||
{
|
|
||||||
/// Scheme parts, eg http
|
|
||||||
char m_Scheme[MAX_SCHEME_LEN];
|
|
||||||
|
|
||||||
/// Location part, eg foo.com:80
|
|
||||||
char m_Location[MAX_LOCATION_LEN];
|
|
||||||
|
|
||||||
/// Hostname part of location, eg foo.com
|
|
||||||
char m_Hostname[MAX_LOCATION_LEN];
|
|
||||||
|
|
||||||
/// Port part of location, eg 80. -1 if not present
|
|
||||||
int m_Port;
|
|
||||||
|
|
||||||
/// Path part, eg index.html
|
|
||||||
// Increased from 512 to 2048 (DEF-3410). 2048 seems like a reasonable
|
|
||||||
// number based on the following SO answer: https://stackoverflow.com/a/417184/1266551
|
|
||||||
char m_Path[MAX_PATH_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URI and split in three parts. (scheme, location, path)
|
|
||||||
* @note This is a simplified URI parser and does not conform to rfc2396.
|
|
||||||
* Missing features are: parameters, query, fragment part of URI and support for escaped sequences
|
|
||||||
* @note For http m_Port is set to 80 if not specified in uri.
|
|
||||||
* @param uri URI to parse
|
|
||||||
* @param parts Result
|
|
||||||
* @return RESULT_OK on success
|
|
||||||
*/
|
|
||||||
Result Parse(const char* uri, Parts* parts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs URL encoding of the supplied buffer
|
|
||||||
* @param src String to encode
|
|
||||||
* @param dst Encoded string
|
|
||||||
* @param dst_size size of the provided out buffer
|
|
||||||
*/
|
|
||||||
void Encode(const char* src, char* dst, uint32_t dst_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Undoes URL decoding on a buffer.
|
|
||||||
* @note The output will never be larger than the input.
|
|
||||||
* @param src Input
|
|
||||||
* @param dst Decoded output
|
|
||||||
*/
|
|
||||||
void Decode(const char* src, char* dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DM_URI_H
|
|
@ -1,20 +1,11 @@
|
|||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
#include "dmsdk/socket.h"
|
#include <dmsdk/dlib/socket.h>
|
||||||
|
|
||||||
namespace dmWebsocket
|
namespace dmWebsocket
|
||||||
{
|
{
|
||||||
|
|
||||||
const char* RFC_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // as per the rfc document on page 7 (https://tools.ietf.org/html/rfc6455)
|
const char* RFC_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // as per the rfc document on page 7 (https://tools.ietf.org/html/rfc6455)
|
||||||
|
|
||||||
|
|
||||||
static void printHex(const uint8_t* data, size_t len)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
printf("%x", data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CreateKey(uint8_t* key, size_t len)
|
static void CreateKey(uint8_t* key, size_t len)
|
||||||
{
|
{
|
||||||
pcg32_random_t rnd;
|
pcg32_random_t rnd;
|
||||||
@ -38,19 +29,11 @@ Result SendClientHandshake(WebsocketConnection* conn)
|
|||||||
char encoded_key[64] = {0};
|
char encoded_key[64] = {0};
|
||||||
uint32_t encoded_key_len = sizeof(encoded_key);
|
uint32_t encoded_key_len = sizeof(encoded_key);
|
||||||
|
|
||||||
//mbedtls_base64_encode((unsigned char*)encoded_key, sizeof(encoded_key), &encoded_key_len, (const unsigned char*)conn->m_Key, sizeof(conn->m_Key));
|
|
||||||
if (!dmCrypt::Base64Encode((const unsigned char*)conn->m_Key, sizeof(conn->m_Key), (unsigned char*)encoded_key, &encoded_key_len))
|
if (!dmCrypt::Base64Encode((const unsigned char*)conn->m_Key, sizeof(conn->m_Key), (unsigned char*)encoded_key, &encoded_key_len))
|
||||||
{
|
{
|
||||||
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Failed to base64 encode key");
|
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Failed to base64 encode key");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
printf("DBG: CreateKey: '");
|
|
||||||
printHex((const uint8_t*)conn->m_Key, 16);
|
|
||||||
printf("'\n");
|
|
||||||
|
|
||||||
printf("DBG: encoded: '%s'\n", encoded_key);
|
|
||||||
|
|
||||||
char port[8] = "";
|
char port[8] = "";
|
||||||
if (!(conn->m_Url.m_Port == 80 || conn->m_Url.m_Port == 443))
|
if (!(conn->m_Url.m_Port == 80 || conn->m_Url.m_Port == 443))
|
||||||
dmSnPrintf(port, sizeof(port), ":%d", conn->m_Url.m_Port);
|
dmSnPrintf(port, sizeof(port), ":%d", conn->m_Url.m_Port);
|
||||||
@ -88,26 +71,6 @@ bail:
|
|||||||
#undef WS_SENDALL
|
#undef WS_SENDALL
|
||||||
|
|
||||||
|
|
||||||
void debugPrintBuffer(const char* s, size_t len)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < len; ++i)
|
|
||||||
{
|
|
||||||
const char* p = s + i;
|
|
||||||
if (*p == '\r') {
|
|
||||||
printf("\\r");
|
|
||||||
}
|
|
||||||
else if (*p == '\n') {
|
|
||||||
printf("\\n\n");
|
|
||||||
}
|
|
||||||
else if (*p == '\t') {
|
|
||||||
printf("\t");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("%c", *p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently blocking!
|
// Currently blocking!
|
||||||
Result ReceiveHeaders(WebsocketConnection* conn)
|
Result ReceiveHeaders(WebsocketConnection* conn)
|
||||||
{
|
{
|
||||||
@ -136,8 +99,6 @@ Result ReceiveHeaders(WebsocketConnection* conn)
|
|||||||
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Receive error: %s", dmSocket::ResultToString(r));
|
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Receive error: %s", dmSocket::ResultToString(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrintBuffer(conn->m_Buffer + conn->m_BufferSize, recv_bytes);
|
|
||||||
|
|
||||||
conn->m_BufferSize += recv_bytes;
|
conn->m_BufferSize += recv_bytes;
|
||||||
|
|
||||||
// NOTE: We have an extra byte for null-termination so no buffer overrun here.
|
// NOTE: We have an extra byte for null-termination so no buffer overrun here.
|
||||||
@ -160,8 +121,6 @@ Result VerifyHeaders(WebsocketConnection* conn)
|
|||||||
{
|
{
|
||||||
char* r = conn->m_Buffer;
|
char* r = conn->m_Buffer;
|
||||||
|
|
||||||
printf("SERVER RESPONSE:\n%s\n", r);
|
|
||||||
|
|
||||||
const char* http_version_and_status_protocol = "HTTP/1.1 101"; // optionally "Web Socket Protocol Handshake"
|
const char* http_version_and_status_protocol = "HTTP/1.1 101"; // optionally "Web Socket Protocol Handshake"
|
||||||
if (strstr(r, http_version_and_status_protocol) != r) {
|
if (strstr(r, http_version_and_status_protocol) != r) {
|
||||||
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Missing: '%s' in header", http_version_and_status_protocol);
|
return SetStatus(conn, RESULT_HANDSHAKE_FAILED, "Missing: '%s' in header", http_version_and_status_protocol);
|
||||||
@ -189,8 +148,6 @@ Result VerifyHeaders(WebsocketConnection* conn)
|
|||||||
*r = 0;
|
*r = 0;
|
||||||
r += 2;
|
r += 2;
|
||||||
|
|
||||||
printf("KEY: '%s', VALUE: '%s'\n", key, value);
|
|
||||||
|
|
||||||
if (strcmp(key, "Connection") == 0 && strcmp(value, "Upgrade") == 0)
|
if (strcmp(key, "Connection") == 0 && strcmp(value, "Upgrade") == 0)
|
||||||
upgraded = true;
|
upgraded = true;
|
||||||
else if (strcmp(key, "Sec-WebSocket-Accept") == 0)
|
else if (strcmp(key, "Sec-WebSocket-Accept") == 0)
|
||||||
@ -216,8 +173,6 @@ printf("KEY: '%s', VALUE: '%s'\n", key, value);
|
|||||||
|
|
||||||
if (strcmp(value, (const char*)client_key) == 0)
|
if (strcmp(value, (const char*)client_key) == 0)
|
||||||
valid_key = true;
|
valid_key = true;
|
||||||
|
|
||||||
printf("DBG: CLIENT KEY+MAGIC: '%s'\n", client_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(r, "\r\n") == 0)
|
if (strcmp(r, "\r\n") == 0)
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* \file base64.h
|
|
||||||
*
|
|
||||||
* \brief RFC 1521 base64 encoding/decoding
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_BASE64_H
|
|
||||||
#define MBEDTLS_BASE64_H
|
|
||||||
|
|
||||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
||||||
#include "config.h"
|
|
||||||
#else
|
|
||||||
#include MBEDTLS_CONFIG_FILE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */
|
|
||||||
#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Encode a buffer into base64 format
|
|
||||||
*
|
|
||||||
* \param dst destination buffer
|
|
||||||
* \param dlen size of the destination buffer
|
|
||||||
* \param olen number of bytes written
|
|
||||||
* \param src source buffer
|
|
||||||
* \param slen amount of data to be encoded
|
|
||||||
*
|
|
||||||
* \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL.
|
|
||||||
* *olen is always updated to reflect the amount
|
|
||||||
* of data that has (or would have) been written.
|
|
||||||
* If that length cannot be represented, then no data is
|
|
||||||
* written to the buffer and *olen is set to the maximum
|
|
||||||
* length representable as a size_t.
|
|
||||||
*
|
|
||||||
* \note Call this function with dlen = 0 to obtain the
|
|
||||||
* required buffer size in *olen
|
|
||||||
*/
|
|
||||||
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
|
|
||||||
const unsigned char *src, size_t slen );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Decode a base64-formatted buffer
|
|
||||||
*
|
|
||||||
* \param dst destination buffer (can be NULL for checking size)
|
|
||||||
* \param dlen size of the destination buffer
|
|
||||||
* \param olen number of bytes written
|
|
||||||
* \param src source buffer
|
|
||||||
* \param slen amount of data to be decoded
|
|
||||||
*
|
|
||||||
* \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or
|
|
||||||
* MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is
|
|
||||||
* not correct. *olen is always updated to reflect the amount
|
|
||||||
* of data that has (or would have) been written.
|
|
||||||
*
|
|
||||||
* \note Call this function with *dst = NULL or dlen = 0 to obtain
|
|
||||||
* the required buffer size in *olen
|
|
||||||
*/
|
|
||||||
int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
|
|
||||||
const unsigned char *src, size_t slen );
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_SELF_TEST)
|
|
||||||
/**
|
|
||||||
* \brief Checkup routine
|
|
||||||
*
|
|
||||||
* \return 0 if successful, or 1 if the test failed
|
|
||||||
*/
|
|
||||||
int mbedtls_base64_self_test( int verbose );
|
|
||||||
|
|
||||||
#endif /* MBEDTLS_SELF_TEST */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* base64.h */
|
|
File diff suppressed because it is too large
Load Diff
@ -1,107 +1,48 @@
|
|||||||
#include "dmsdk/socket.h"
|
#include <dmsdk/dlib/socket.h>
|
||||||
|
#include <dmsdk/dlib/sslsocket.h>
|
||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
|
|
||||||
namespace dmWebsocket
|
namespace dmWebsocket
|
||||||
{
|
{
|
||||||
|
|
||||||
extern void debugPrintBuffer(const char* s, size_t len);
|
|
||||||
|
|
||||||
dmSocket::Result Send(WebsocketConnection* conn, const char* buffer, int length, int* out_sent_bytes)
|
dmSocket::Result Send(WebsocketConnection* conn, const char* buffer, int length, int* out_sent_bytes)
|
||||||
{
|
{
|
||||||
// if (response->m_SSLConnection != 0) {
|
int total_sent_bytes = 0;
|
||||||
// int r = 0;
|
int sent_bytes = 0;
|
||||||
// while( ( r = mbedtls_ssl_write(response->m_SSLConnection, (const uint8_t*) buffer, length) ) < 0 )
|
|
||||||
// {
|
|
||||||
// if (r == MBEDTLS_ERR_SSL_WANT_WRITE ||
|
|
||||||
// r == MBEDTLS_ERR_SSL_WANT_READ) {
|
|
||||||
// return dmSocket::RESULT_TRY_AGAIN;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (r < 0) {
|
while (total_sent_bytes < length) {
|
||||||
// return SSLToSocket(r);
|
dmSocket::Result r;
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // In order to mimic the http code path, we return the same error number
|
if (conn->m_SSLSocket)
|
||||||
// if( (r == length) && HasRequestTimedOut(response->m_Client) )
|
r = dmSSLSocket::Send(conn->m_SSLSocket, buffer + total_sent_bytes, length - total_sent_bytes, &sent_bytes);
|
||||||
// {
|
else
|
||||||
// return dmSocket::RESULT_WOULDBLOCK;
|
r = dmSocket::Send(conn->m_Socket, buffer + total_sent_bytes, length - total_sent_bytes, &sent_bytes);
|
||||||
// }
|
|
||||||
|
|
||||||
// if (r != length) {
|
if( r == dmSocket::RESULT_WOULDBLOCK )
|
||||||
// return SSLToSocket(r);
|
{
|
||||||
// }
|
r = dmSocket::RESULT_TRY_AGAIN;
|
||||||
|
|
||||||
// return dmSocket::RESULT_OK;
|
|
||||||
// } else {
|
|
||||||
int total_sent_bytes = 0;
|
|
||||||
int sent_bytes = 0;
|
|
||||||
|
|
||||||
while (total_sent_bytes < length) {
|
|
||||||
|
|
||||||
dmSocket::Result r = dmSocket::Send(conn->m_Socket, buffer + total_sent_bytes, length - total_sent_bytes, &sent_bytes);
|
|
||||||
|
|
||||||
debugPrintBuffer(buffer + total_sent_bytes, sent_bytes);
|
|
||||||
|
|
||||||
if( r == dmSocket::RESULT_WOULDBLOCK )
|
|
||||||
{
|
|
||||||
r = dmSocket::RESULT_TRY_AGAIN;
|
|
||||||
}
|
|
||||||
// if( (r == dmSocket::RESULT_OK || r == dmSocket::RESULT_TRY_AGAIN) && HasRequestTimedOut(response->m_Client) )
|
|
||||||
// {
|
|
||||||
// r = dmSocket::RESULT_WOULDBLOCK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (r == dmSocket::RESULT_TRY_AGAIN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (r != dmSocket::RESULT_OK) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
total_sent_bytes += sent_bytes;
|
|
||||||
}
|
}
|
||||||
if (out_sent_bytes)
|
|
||||||
*out_sent_bytes = total_sent_bytes;
|
if (r == dmSocket::RESULT_TRY_AGAIN)
|
||||||
return dmSocket::RESULT_OK;
|
continue;
|
||||||
// }
|
|
||||||
|
if (r != dmSocket::RESULT_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_sent_bytes += sent_bytes;
|
||||||
|
}
|
||||||
|
if (out_sent_bytes)
|
||||||
|
*out_sent_bytes = total_sent_bytes;
|
||||||
|
return dmSocket::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmSocket::Result Receive(WebsocketConnection* conn, void* buffer, int length, int* received_bytes)
|
dmSocket::Result Receive(WebsocketConnection* conn, void* buffer, int length, int* received_bytes)
|
||||||
{
|
{
|
||||||
// if (response->m_SSLConnection != 0) {
|
if (conn->m_SSLSocket)
|
||||||
|
return dmSSLSocket::Receive(conn->m_SSLSocket, buffer, length, received_bytes);
|
||||||
// int ret = 0;
|
else
|
||||||
// do
|
|
||||||
// {
|
|
||||||
// memset(buffer, 0, length);
|
|
||||||
// ret = mbedtls_ssl_read( response->m_SSLConnection, (unsigned char*)buffer, length-1 );
|
|
||||||
|
|
||||||
// if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
|
|
||||||
// ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
|
|
||||||
// ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
|
|
||||||
// {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (HasRequestTimedOut(response->m_Client)) {
|
|
||||||
// return dmSocket::RESULT_WOULDBLOCK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if( ret <= 0 )
|
|
||||||
// {
|
|
||||||
// return SSLToSocket(ret);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ((uint8_t*)buffer)[ret] = 0;
|
|
||||||
|
|
||||||
// *received_bytes = ret;
|
|
||||||
// return dmSocket::RESULT_OK;
|
|
||||||
// }
|
|
||||||
// while( 1 );
|
|
||||||
// } else {
|
|
||||||
return dmSocket::Receive(conn->m_Socket, buffer, length, received_bytes);
|
return dmSocket::Receive(conn->m_Socket, buffer, length, received_bytes);
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -5,45 +5,9 @@
|
|||||||
#define MODULE_NAME "websocket"
|
#define MODULE_NAME "websocket"
|
||||||
|
|
||||||
#include "websocket.h"
|
#include "websocket.h"
|
||||||
|
|
||||||
|
|
||||||
#include "script_util.h"
|
#include "script_util.h"
|
||||||
|
#include <dmsdk/dlib/connection_pool.h>
|
||||||
|
#include <dmsdk/dlib/dns.h>
|
||||||
// *****************************************************************************************************************************************************************
|
|
||||||
// DMSDK
|
|
||||||
|
|
||||||
extern "C" int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen );
|
|
||||||
extern "C" int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen );
|
|
||||||
|
|
||||||
// TODO: MOVE TO DMSDK
|
|
||||||
bool dmCrypt::Base64Encode(const uint8_t* src, uint32_t src_len, uint8_t* dst, uint32_t* dst_len)
|
|
||||||
{
|
|
||||||
size_t out_len = 0;
|
|
||||||
int r = mbedtls_base64_encode(dst, *dst_len, &out_len, src, src_len);
|
|
||||||
if (r != 0)
|
|
||||||
{
|
|
||||||
*dst_len = 0xFFFFFFFF;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*dst_len = (uint32_t)out_len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dmCrypt::Base64Decode(const uint8_t* src, uint32_t src_len, uint8_t* dst, uint32_t* dst_len)
|
|
||||||
{
|
|
||||||
size_t out_len = 0;
|
|
||||||
int r = mbedtls_base64_decode(dst, *dst_len, &out_len, src, src_len);
|
|
||||||
if (r != 0)
|
|
||||||
{
|
|
||||||
*dst_len = 0xFFFFFFFF;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*dst_len = (uint32_t)out_len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// *****************************************************************************************************************************************************************
|
|
||||||
|
|
||||||
namespace dmWebsocket {
|
namespace dmWebsocket {
|
||||||
|
|
||||||
@ -76,17 +40,6 @@ Result SetStatus(WebsocketConnection* conn, Result status, const char* format, .
|
|||||||
// ***************************************************************************************************
|
// ***************************************************************************************************
|
||||||
// LUA functions
|
// LUA functions
|
||||||
|
|
||||||
// struct wslay_event_msg msg; // Should I use fragmented?
|
|
||||||
// msg.opcode = write_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME;
|
|
||||||
// msg.msg = p_buffer;
|
|
||||||
// msg.msg_length = p_buffer_size;
|
|
||||||
|
|
||||||
// wslay_event_queue_msg(_data->ctx, &msg);
|
|
||||||
// if (wslay_event_send(_data->ctx) < 0) {
|
|
||||||
// close_now();
|
|
||||||
// return FAILED;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const struct wslay_event_callbacks g_WslCallbacks = {
|
const struct wslay_event_callbacks g_WslCallbacks = {
|
||||||
WSL_RecvCallback,
|
WSL_RecvCallback,
|
||||||
WSL_SendCallback,
|
WSL_SendCallback,
|
||||||
@ -332,7 +285,7 @@ static void LuaInit(lua_State* L)
|
|||||||
static dmExtension::Result WebsocketAppInitialize(dmExtension::AppParams* params)
|
static dmExtension::Result WebsocketAppInitialize(dmExtension::AppParams* params)
|
||||||
{
|
{
|
||||||
g_Websocket.m_BufferSize = dmConfigFile::GetInt(params->m_ConfigFile, "websocket.buffer_size", 64 * 1024);
|
g_Websocket.m_BufferSize = dmConfigFile::GetInt(params->m_ConfigFile, "websocket.buffer_size", 64 * 1024);
|
||||||
g_Websocket.m_Timeout = dmConfigFile::GetInt(params->m_ConfigFile, "websocket.socket_timeout", 250 * 1000);
|
g_Websocket.m_Timeout = dmConfigFile::GetInt(params->m_ConfigFile, "websocket.socket_timeout", 500 * 1000);
|
||||||
g_Websocket.m_Connections.SetCapacity(4);
|
g_Websocket.m_Connections.SetCapacity(4);
|
||||||
g_Websocket.m_Channel = 0;
|
g_Websocket.m_Channel = 0;
|
||||||
g_Websocket.m_Pool = 0;
|
g_Websocket.m_Pool = 0;
|
||||||
@ -350,7 +303,7 @@ static dmExtension::Result WebsocketAppInitialize(dmExtension::AppParams* params
|
|||||||
|
|
||||||
if (dmDNS::RESULT_OK != dns_result)
|
if (dmDNS::RESULT_OK != dns_result)
|
||||||
{
|
{
|
||||||
dmLogError("Failed to create connection pool: %s", dmDNS::ResultToString(dns_result));
|
dmLogError("Failed to create connection pool: %d", dns_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Websocket.m_Initialized = 1;
|
g_Websocket.m_Initialized = 1;
|
||||||
@ -380,6 +333,8 @@ static dmExtension::Result WebsocketInitialize(dmExtension::Params* params)
|
|||||||
|
|
||||||
static dmExtension::Result WebsocketAppFinalize(dmExtension::AppParams* params)
|
static dmExtension::Result WebsocketAppFinalize(dmExtension::AppParams* params)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
dmConnectionPool::Shutdown(g_Websocket.m_Pool, dmSocket::SHUTDOWNTYPE_READWRITE);
|
||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,6 +446,7 @@ static dmExtension::Result WebsocketOnUpdate(dmExtension::Params* params)
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn->m_Socket = dmConnectionPool::GetSocket(g_Websocket.m_Pool, conn->m_Connection);
|
conn->m_Socket = dmConnectionPool::GetSocket(g_Websocket.m_Pool, conn->m_Connection);
|
||||||
|
conn->m_SSLSocket = dmConnectionPool::GetSSLSocket(g_Websocket.m_Pool, conn->m_Connection);
|
||||||
conn->m_State = STATE_HANDSHAKE;
|
conn->m_State = STATE_HANDSHAKE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
#include <wslay/wslay.h>
|
#include <wslay/wslay.h>
|
||||||
|
|
||||||
#include "dmsdk/connection_pool.h"
|
#include <dmsdk/dlib/connection_pool.h>
|
||||||
#include "dmsdk/socket.h"
|
#include <dmsdk/dlib/socket.h>
|
||||||
#include "dmsdk/dns.h"
|
#include <dmsdk/dlib/dns.h>
|
||||||
#include "dmsdk/uri.h"
|
#include <dmsdk/dlib/uri.h>
|
||||||
|
|
||||||
namespace dmCrypt
|
namespace dmCrypt
|
||||||
{
|
{
|
||||||
@ -49,6 +49,7 @@ namespace dmWebsocket
|
|||||||
dmURI::Parts m_Url;
|
dmURI::Parts m_Url;
|
||||||
dmConnectionPool::HConnection m_Connection;
|
dmConnectionPool::HConnection m_Connection;
|
||||||
dmSocket::Socket m_Socket;
|
dmSocket::Socket m_Socket;
|
||||||
|
dmSSLSocket::Socket m_SSLSocket;
|
||||||
uint8_t m_Key[16];
|
uint8_t m_Key[16];
|
||||||
State m_State;
|
State m_State;
|
||||||
uint32_t m_SSL:1;
|
uint32_t m_SSL:1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user