network_ws.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  2. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  3. *
  4. * relies heavily on concepts from libwebsockets minimal examples
  5. * Copyright 2019 (c) Matthias Konnerth
  6. * Copyright 2019 (c) Michael Derfler
  7. */
  8. #define UA_INTERNAL
  9. #include <open62541/network_ws.h>
  10. #include <open62541/plugin/log_stdout.h>
  11. #include <open62541/util.h>
  12. #include "open62541_queue.h"
  13. #include <libwebsockets.h>
  14. #include <string.h>
  15. struct BufferEntry {
  16. UA_ByteString msg;
  17. SIMPLEQ_ENTRY(BufferEntry) next;
  18. };
  19. typedef struct BufferEntry BufferEntry;
  20. struct ConnectionUserData {
  21. struct lws *wsi;
  22. SIMPLEQ_HEAD(, BufferEntry) messages;
  23. };
  24. typedef struct ConnectionUserData ConnectionUserData;
  25. //one of these is created for each client connecting to us
  26. struct SessionData {
  27. UA_Connection *connection;
  28. };
  29. // one of these is created for each vhost our protocol is used with
  30. struct VHostData {
  31. struct lws_context *context;
  32. };
  33. typedef struct {
  34. const UA_Logger *logger;
  35. UA_UInt16 port;
  36. struct lws_context *context;
  37. UA_Server *server;
  38. UA_ConnectionConfig config;
  39. } ServerNetworkLayerWS;
  40. static UA_StatusCode
  41. connection_getsendbuffer(UA_Connection *connection, size_t length, UA_ByteString *buf) {
  42. if(length > connection->config.sendBufferSize)
  43. return UA_STATUSCODE_BADCOMMUNICATIONERROR;
  44. return UA_ByteString_allocBuffer(buf, length);
  45. }
  46. static void
  47. connection_releasesendbuffer(UA_Connection *connection, UA_ByteString *buf) {
  48. UA_ByteString_deleteMembers(buf);
  49. }
  50. static void
  51. connection_releaserecvbuffer(UA_Connection *connection, UA_ByteString *buf) {
  52. UA_ByteString_deleteMembers(buf);
  53. }
  54. static UA_StatusCode
  55. connection_send(UA_Connection *connection, UA_ByteString *buf) {
  56. ConnectionUserData *buffer = (ConnectionUserData *)connection->handle;
  57. if(connection->state == UA_CONNECTION_CLOSED) {
  58. UA_ByteString_deleteMembers(buf);
  59. return UA_STATUSCODE_BADCONNECTIONCLOSED;
  60. }
  61. BufferEntry *entry = (BufferEntry *)malloc(sizeof(BufferEntry));
  62. entry->msg.length = buf->length;
  63. entry->msg.data = (UA_Byte *)malloc(LWS_PRE + buf->length);
  64. memcpy(entry->msg.data + LWS_PRE, buf->data, buf->length);
  65. UA_ByteString_deleteMembers(buf);
  66. SIMPLEQ_INSERT_TAIL(&buffer->messages, entry, next);
  67. lws_callback_on_writable(buffer->wsi);
  68. return UA_STATUSCODE_GOOD;
  69. }
  70. static void
  71. ServerNetworkLayerWS_close(UA_Connection *connection) {
  72. if(connection->state == UA_CONNECTION_CLOSED)
  73. return;
  74. connection->state = UA_CONNECTION_CLOSED;
  75. }
  76. static void
  77. freeConnection(UA_Connection *connection) {
  78. if(connection->handle) {
  79. UA_free(connection->handle);
  80. }
  81. UA_Connection_clear(connection);
  82. UA_free(connection);
  83. }
  84. static int
  85. callback_opcua(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in,
  86. size_t len) {
  87. struct SessionData *pss = (struct SessionData *)user;
  88. struct VHostData *vhd =
  89. (struct VHostData *)lws_protocol_vh_priv_get(lws_get_vhost(wsi),
  90. lws_get_protocol(wsi));
  91. switch(reason) {
  92. case LWS_CALLBACK_PROTOCOL_INIT:
  93. vhd = (struct VHostData *)lws_protocol_vh_priv_zalloc(
  94. lws_get_vhost(wsi), lws_get_protocol(wsi),
  95. sizeof(struct VHostData));
  96. vhd->context = lws_get_context(wsi);
  97. break;
  98. case LWS_CALLBACK_ESTABLISHED:
  99. if(!wsi)
  100. break;
  101. ServerNetworkLayerWS *layer = (ServerNetworkLayerWS*)lws_context_user(vhd->context);
  102. UA_Connection *c = (UA_Connection *)malloc(sizeof(UA_Connection));
  103. ConnectionUserData *buffer =
  104. (ConnectionUserData *)malloc(sizeof(ConnectionUserData));
  105. SIMPLEQ_INIT(&buffer->messages);
  106. buffer->wsi = wsi;
  107. memset(c, 0, sizeof(UA_Connection));
  108. c->sockfd = 0;
  109. c->handle = buffer;
  110. c->config = layer->config;
  111. c->send = connection_send;
  112. c->close = ServerNetworkLayerWS_close;
  113. c->free = freeConnection;
  114. c->getSendBuffer = connection_getsendbuffer;
  115. c->releaseSendBuffer = connection_releasesendbuffer;
  116. c->releaseRecvBuffer = connection_releaserecvbuffer;
  117. // stack sets the connection to established
  118. c->state = UA_CONNECTION_OPENING;
  119. c->openingDate = UA_DateTime_nowMonotonic();
  120. pss->connection = c;
  121. break;
  122. case LWS_CALLBACK_CLOSED:
  123. // notify server
  124. if(!pss->connection->state != UA_CONNECTION_CLOSED) {
  125. pss->connection->state = UA_CONNECTION_CLOSED;
  126. }
  127. layer = (ServerNetworkLayerWS*)lws_context_user(vhd->context);
  128. if(layer && layer->server)
  129. {
  130. UA_Server_removeConnection(layer->server, pss->connection);
  131. }
  132. break;
  133. case LWS_CALLBACK_SERVER_WRITEABLE:
  134. if(!pss->connection)
  135. break;
  136. ConnectionUserData *b = (ConnectionUserData *)pss->connection->handle;
  137. do {
  138. BufferEntry *entry = SIMPLEQ_FIRST(&b->messages);
  139. if(!entry)
  140. break;
  141. int m = lws_write(wsi, entry->msg.data + LWS_PRE, entry->msg.length,
  142. LWS_WRITE_BINARY);
  143. if(m < (int)entry->msg.length) {
  144. lwsl_err("ERROR %d writing to ws\n", m);
  145. return -1;
  146. }
  147. UA_ByteString_deleteMembers(&entry->msg);
  148. UA_free(entry);
  149. SIMPLEQ_REMOVE_HEAD(&b->messages, next);
  150. } while(!lws_send_pipe_choked(wsi));
  151. // process remaining messages
  152. if(SIMPLEQ_FIRST(&b->messages)) {
  153. lws_callback_on_writable(wsi);
  154. }
  155. break;
  156. case LWS_CALLBACK_RECEIVE:
  157. if(!vhd->context)
  158. break;
  159. layer =
  160. (ServerNetworkLayerWS *)lws_context_user(vhd->context);
  161. if(!layer->server)
  162. break;
  163. UA_ByteString message = {len, (UA_Byte *)in};
  164. UA_Server_processBinaryMessage(layer->server, pss->connection, &message);
  165. break;
  166. default:
  167. break;
  168. }
  169. return 0;
  170. }
  171. static struct lws_protocols protocols[] = {
  172. {"http", lws_callback_http_dummy, 0, 0, 0, NULL, 0},
  173. {"opcua", callback_opcua, sizeof(struct SessionData), 0, 0, NULL, 0},
  174. {NULL, NULL, 0, 0, 0, NULL, 0}
  175. };
  176. // make the opcua protocol callback the default one
  177. const struct lws_protocol_vhost_options pvo_opt = {NULL, NULL, "default", "1"};
  178. const struct lws_protocol_vhost_options pvo = {NULL, &pvo_opt, "opcua", ""};
  179. static UA_StatusCode
  180. ServerNetworkLayerWS_start(UA_ServerNetworkLayer *nl, const UA_String *customHostname) {
  181. UA_initialize_architecture_network();
  182. ServerNetworkLayerWS *layer = (ServerNetworkLayerWS *)nl->handle;
  183. /* Get the discovery url from the hostname */
  184. UA_String du = UA_STRING_NULL;
  185. char discoveryUrlBuffer[256];
  186. char hostnameBuffer[256];
  187. if(customHostname->length) {
  188. du.length = (size_t)UA_snprintf(discoveryUrlBuffer, 255, "ws://%.*s:%d/",
  189. (int)customHostname->length, customHostname->data,
  190. layer->port);
  191. du.data = (UA_Byte *)discoveryUrlBuffer;
  192. } else {
  193. if(UA_gethostname(hostnameBuffer, 255) == 0) {
  194. du.length = (size_t)UA_snprintf(discoveryUrlBuffer, 255, "ws://%s:%d/",
  195. hostnameBuffer, layer->port);
  196. du.data = (UA_Byte *)discoveryUrlBuffer;
  197. } else {
  198. UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK,
  199. "Could not get the hostname");
  200. }
  201. }
  202. UA_String_copy(&du, &nl->discoveryUrl);
  203. UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
  204. "Websocket network layer listening on %.*s", (int)nl->discoveryUrl.length,
  205. nl->discoveryUrl.data);
  206. struct lws_context_creation_info info;
  207. int logLevel = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
  208. lws_set_log_level(logLevel, NULL);
  209. memset(&info, 0, sizeof info);
  210. info.port = layer->port;
  211. info.protocols = protocols;
  212. info.vhost_name = (char *)du.data;
  213. info.ws_ping_pong_interval = 10;
  214. info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
  215. info.pvo = &pvo;
  216. info.user = layer;
  217. struct lws_context *context = lws_create_context(&info);
  218. if(!context) {
  219. UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, "lws init failed");
  220. return UA_STATUSCODE_BADOUTOFMEMORY;
  221. }
  222. layer->context = context;
  223. return UA_STATUSCODE_GOOD;
  224. }
  225. static UA_StatusCode
  226. ServerNetworkLayerWS_listen(UA_ServerNetworkLayer *nl, UA_Server *server,
  227. UA_UInt16 timeout) {
  228. ServerNetworkLayerWS *layer = (ServerNetworkLayerWS *)nl->handle;
  229. layer->server = server;
  230. // set timeout to zero to return immediately if nothing to do
  231. lws_service(layer->context, 0);
  232. return UA_STATUSCODE_GOOD;
  233. }
  234. static void
  235. ServerNetworkLayerWS_stop(UA_ServerNetworkLayer *nl, UA_Server *server) {
  236. ServerNetworkLayerWS *layer = (ServerNetworkLayerWS *)nl->handle;
  237. UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
  238. "Shutting down the WS network layer");
  239. lws_context_destroy(layer->context);
  240. UA_deinitialize_architecture_network();
  241. }
  242. static void
  243. ServerNetworkLayerWS_clear(UA_ServerNetworkLayer *nl) {
  244. UA_free(nl->handle);
  245. UA_String_deleteMembers(&nl->discoveryUrl);
  246. }
  247. UA_ServerNetworkLayer
  248. UA_ServerNetworkLayerWS(UA_ConnectionConfig config, UA_UInt16 port, UA_Logger *logger) {
  249. UA_ServerNetworkLayer nl;
  250. memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
  251. nl.clear = ServerNetworkLayerWS_clear;
  252. nl.localConnectionConfig = config;
  253. nl.start = ServerNetworkLayerWS_start;
  254. nl.listen = ServerNetworkLayerWS_listen;
  255. nl.stop = ServerNetworkLayerWS_stop;
  256. ServerNetworkLayerWS *layer =
  257. (ServerNetworkLayerWS *)UA_calloc(1, sizeof(ServerNetworkLayerWS));
  258. if(!layer)
  259. return nl;
  260. nl.handle = layer;
  261. layer->logger = logger;
  262. layer->port = port;
  263. layer->config = config;
  264. return nl;
  265. }