ua_network_pubsub_udp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
  6. */
  7. /* Enable POSIX features */
  8. #if !defined(_XOPEN_SOURCE) && !defined(_WRS_KERNEL)
  9. # define _XOPEN_SOURCE 600
  10. #endif
  11. #ifndef _DEFAULT_SOURCE
  12. # define _DEFAULT_SOURCE
  13. #endif
  14. /* On older systems we need to define _BSD_SOURCE.
  15. * _DEFAULT_SOURCE is an alias for that. */
  16. #ifndef _BSD_SOURCE
  17. # define _BSD_SOURCE
  18. #endif
  19. /* Disable some security warnings on MSVC */
  20. #ifdef _MSC_VER
  21. # define _CRT_SECURE_NO_WARNINGS
  22. #endif
  23. /* Assume that Windows versions are newer than Windows XP */
  24. #if defined(__MINGW32__) && (!defined(WINVER) || WINVER < 0x501)
  25. # undef WINVER
  26. # undef _WIN32_WINDOWS
  27. # undef _WIN32_WINNT
  28. # define WINVER 0x0501
  29. # define _WIN32_WINDOWS 0x0501
  30. # define _WIN32_WINNT 0x0501
  31. #endif
  32. #ifdef _WIN32
  33. # include <winsock2.h>
  34. # include <ws2tcpip.h>
  35. # include <Iphlpapi.h>
  36. # define CLOSESOCKET(S) closesocket((SOCKET)S)
  37. # define ssize_t int
  38. # define UA_fd_set(fd, fds) FD_SET((unsigned int)fd, fds)
  39. # define UA_fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds)
  40. #else /* _WIN32 */
  41. # define CLOSESOCKET(S) close(S)
  42. #include <sys/types.h>
  43. #include <sys/socket.h>
  44. #include <netdb.h>
  45. #include <unistd.h>
  46. #include <arpa/inet.h>
  47. #include <net/if.h>
  48. # define UA_fd_set(fd, fds) FD_SET(fd, fds)
  49. # define UA_fd_isset(fd, fds) FD_ISSET(fd, fds)
  50. # endif /* Not Windows */
  51. #include <stdio.h>
  52. #include "ua_plugin_network.h"
  53. #include "ua_network_pubsub_udp.h"
  54. #include "ua_util.h"
  55. #include "ua_log_stdout.h"
  56. //UDP multicast network layer specific internal data
  57. typedef struct {
  58. int ai_family; //Protocol family for socket. IPv4/IPv6
  59. struct sockaddr_storage *ai_addr; //https://msdn.microsoft.com/de-de/library/windows/desktop/ms740496(v=vs.85).aspx
  60. UA_UInt32 messageTTL;
  61. UA_Boolean enableLoopback;
  62. UA_Boolean enableReuse;
  63. } UA_PubSubChannelDataUDPMC;
  64. /**
  65. * Open communication socket based on the connectionConfig. Protocol specific parameters are
  66. * provided within the connectionConfig as KeyValuePair.
  67. * Currently supported options: "ttl" , "loopback", "reuse"
  68. *
  69. * @return ref to created channel, NULL on error
  70. */
  71. static UA_PubSubChannel *
  72. UA_PubSubChannelUDPMC_open(const UA_PubSubConnectionConfig *connectionConfig) {
  73. #ifdef _WIN32
  74. WSADATA wsaData;
  75. WSAStartup(MAKEWORD(2, 2), &wsaData);
  76. #endif /* Not Windows */
  77. UA_NetworkAddressUrlDataType address;
  78. if(UA_Variant_hasScalarType(&connectionConfig->address, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE])){
  79. address = *(UA_NetworkAddressUrlDataType *)connectionConfig->address.data;
  80. } else {
  81. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection creation failed. Invalid Address.");
  82. return NULL;
  83. }
  84. //allocate and init memory for the UDP multicast specific internal data
  85. UA_PubSubChannelDataUDPMC * channelDataUDPMC =
  86. (UA_PubSubChannelDataUDPMC *) UA_calloc(1, (sizeof(UA_PubSubChannelDataUDPMC)));
  87. if(!channelDataUDPMC){
  88. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection creation failed. Out of memory.");
  89. return NULL;
  90. }
  91. //set default values
  92. memcpy(channelDataUDPMC, &(UA_PubSubChannelDataUDPMC){0, NULL, 255, UA_TRUE, UA_TRUE}, sizeof(UA_PubSubChannelDataUDPMC));
  93. //iterate over the given KeyValuePair paramters
  94. UA_String ttlParam = UA_STRING("ttl"), loopbackParam = UA_STRING("loopback"), reuseParam = UA_STRING("reuse");
  95. for(size_t i = 0; i < connectionConfig->connectionPropertiesSize; i++){
  96. if(UA_String_equal(&connectionConfig->connectionProperties[i].key.name, &ttlParam)){
  97. if(UA_Variant_hasScalarType(&connectionConfig->connectionProperties[i].value, &UA_TYPES[UA_TYPES_UINT32])){
  98. channelDataUDPMC->messageTTL = *(UA_UInt32 *) connectionConfig->connectionProperties[i].value.data;
  99. }
  100. } else if(UA_String_equal(&connectionConfig->connectionProperties[i].key.name, &loopbackParam)){
  101. if(UA_Variant_hasScalarType(&connectionConfig->connectionProperties[i].value, &UA_TYPES[UA_TYPES_BOOLEAN])){
  102. channelDataUDPMC->enableLoopback = *(UA_Boolean *) connectionConfig->connectionProperties[i].value.data;
  103. }
  104. } else if(UA_String_equal(&connectionConfig->connectionProperties[i].key.name, &reuseParam)){
  105. if(UA_Variant_hasScalarType(&connectionConfig->connectionProperties[i].value, &UA_TYPES[UA_TYPES_BOOLEAN])){
  106. channelDataUDPMC->enableReuse = *(UA_Boolean *) connectionConfig->connectionProperties[i].value.data;
  107. }
  108. } else {
  109. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection creation. Unknown connection parameter.");
  110. }
  111. }
  112. UA_PubSubChannel *newChannel = (UA_PubSubChannel *) UA_calloc(1, sizeof(UA_PubSubChannel));
  113. if(!newChannel){
  114. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection creation failed. Out of memory.");
  115. UA_free(channelDataUDPMC);
  116. return NULL;
  117. }
  118. struct addrinfo hints, *rp, *requestResult = NULL;
  119. memset(&hints, 0, sizeof hints);
  120. hints.ai_family = AF_UNSPEC;
  121. hints.ai_socktype = SOCK_DGRAM;
  122. hints.ai_flags = 0;
  123. hints.ai_protocol = 0;
  124. UA_String hostname, path;
  125. UA_UInt16 networkPort;
  126. if(UA_parseEndpointUrl(&address.url, &hostname, &networkPort, &path) != UA_STATUSCODE_GOOD){
  127. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  128. "PubSub Connection creation failed. Invalid URL.");
  129. UA_free(channelDataUDPMC);
  130. UA_free(newChannel);
  131. return NULL;
  132. }
  133. if(hostname.length > 512) {
  134. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  135. "PubSub Connection creation failed. URL maximum length is 512.");
  136. UA_free(channelDataUDPMC);
  137. UA_free(newChannel);
  138. return NULL;
  139. }
  140. UA_STACKARRAY(char, addressAsChar, sizeof(char) * hostname.length +1);
  141. memcpy(addressAsChar, hostname.data, hostname.length);
  142. addressAsChar[hostname.length] = 0;
  143. char port[6];
  144. sprintf(port, "%u", networkPort);
  145. if(getaddrinfo(addressAsChar, port, &hints, &requestResult) != 0) {
  146. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  147. "PubSub Connection creation failed. Internal error.");
  148. UA_free(channelDataUDPMC);
  149. UA_free(newChannel);
  150. return NULL;
  151. }
  152. //check if the ip address is a multicast address
  153. if(requestResult->ai_family == PF_INET){
  154. struct in_addr imr_interface;
  155. inet_pton(AF_INET, addressAsChar, &imr_interface);
  156. if((ntohl(imr_interface.s_addr) & 0xF0000000) != 0xE0000000){
  157. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  158. "PubSub Connection creation failed. No multicast address.");
  159. freeaddrinfo(requestResult);
  160. UA_free(channelDataUDPMC);
  161. UA_free(newChannel);
  162. return NULL;
  163. }
  164. } else {
  165. //TODO check if ipv6 addrr is multicast address.
  166. }
  167. for(rp = requestResult; rp != NULL; rp = rp->ai_next){
  168. newChannel->sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  169. if(newChannel->sockfd != -1){
  170. break; /*success*/
  171. }
  172. }
  173. if(!rp){
  174. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  175. "PubSub Connection creation failed. Internal error.");
  176. freeaddrinfo(requestResult);
  177. UA_free(channelDataUDPMC);
  178. UA_free(newChannel);
  179. return NULL;
  180. }
  181. channelDataUDPMC->ai_family = rp->ai_family;
  182. channelDataUDPMC->ai_addr = (struct sockaddr_storage *) UA_calloc(1, sizeof(struct sockaddr_storage));
  183. if(!channelDataUDPMC->ai_addr){
  184. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  185. "PubSub Connection creation failed. Out of memory.");
  186. CLOSESOCKET(newChannel->sockfd);
  187. freeaddrinfo(requestResult);
  188. UA_free(channelDataUDPMC);
  189. UA_free(newChannel);
  190. return NULL;
  191. }
  192. memcpy(channelDataUDPMC->ai_addr, rp->ai_addr, sizeof(*rp->ai_addr));
  193. //link channel and internal channel data
  194. newChannel->handle = channelDataUDPMC;
  195. //Set loop back data to your host
  196. if(setsockopt(newChannel->sockfd,
  197. requestResult->ai_family == PF_INET6 ? IPPROTO_IPV6:IPPROTO_IP,
  198. requestResult->ai_family == PF_INET6 ? IPV6_MULTICAST_LOOP : IP_MULTICAST_LOOP,
  199. (const char *)&channelDataUDPMC->enableLoopback, sizeof (channelDataUDPMC->enableLoopback)) < 0) {
  200. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  201. "PubSub Connection creation failed. Loopback setup failed.");
  202. CLOSESOCKET(newChannel->sockfd);
  203. freeaddrinfo(requestResult);
  204. UA_free(channelDataUDPMC);
  205. UA_free(newChannel);
  206. return NULL;
  207. }
  208. //Set Time to live (TTL). Value of 1 prevent forward beyond the local network.
  209. if(setsockopt(newChannel->sockfd,
  210. requestResult->ai_family == PF_INET6 ? IPPROTO_IPV6:IPPROTO_IP,
  211. requestResult->ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
  212. (const char *)&channelDataUDPMC->messageTTL, sizeof(channelDataUDPMC->messageTTL)) < 0) {
  213. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  214. "PubSub Connection creation problem. Time to live setup failed.");
  215. }
  216. //Set reuse address -> enables sharing of the same listening address on different sockets.
  217. if(channelDataUDPMC->enableReuse){
  218. int enableReuse = 1;
  219. if(setsockopt(newChannel->sockfd,
  220. SOL_SOCKET, SO_REUSEADDR,
  221. (const char*)&enableReuse, sizeof(enableReuse)) < 0){
  222. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  223. "PubSub Connection creation problem. Reuse address setup failed.");
  224. }
  225. }
  226. //Set the physical interface for outgoing traffic
  227. if(address.networkInterface.length > 0){
  228. UA_STACKARRAY(char, interfaceAsChar, sizeof(char) * address.networkInterface.length + 1);
  229. memcpy(interfaceAsChar, address.networkInterface.data, address.networkInterface.length);
  230. interfaceAsChar[address.networkInterface.length] = 0;
  231. enum{
  232. IPv4,
  233. IPv6,
  234. INVALID
  235. } ipVersion;
  236. union {
  237. struct ip_mreq ipv4;
  238. struct ipv6_mreq ipv6;
  239. } group;
  240. if(inet_pton(AF_INET, interfaceAsChar, &group.ipv4.imr_interface)){
  241. ipVersion = IPv4;
  242. } else if (inet_pton(AF_INET6, interfaceAsChar, &group.ipv6.ipv6mr_multiaddr)){
  243. group.ipv6.ipv6mr_interface = if_nametoindex(interfaceAsChar);
  244. ipVersion = IPv6;
  245. } else {
  246. ipVersion = INVALID;
  247. }
  248. if(ipVersion == INVALID ||
  249. setsockopt(newChannel->sockfd,
  250. requestResult->ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
  251. requestResult->ai_family == PF_INET6 ? IPV6_MULTICAST_IF : IP_MULTICAST_IF,
  252. ipVersion == IPv6 ? (void *) &group.ipv6.ipv6mr_interface : &group.ipv4.imr_interface,
  253. ipVersion == IPv6 ? sizeof(group.ipv6.ipv6mr_interface) : sizeof(struct in_addr)) < 0){
  254. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  255. "PubSub Connection creation problem. Interface selection failed.");
  256. };
  257. }
  258. freeaddrinfo(requestResult);
  259. newChannel->state = UA_PUBSUB_CHANNEL_PUB;
  260. return newChannel;
  261. }
  262. /**
  263. * Subscribe to a given address.
  264. *
  265. * @return UA_STATUSCODE_GOOD on success
  266. */
  267. static UA_StatusCode
  268. UA_PubSubChannelUDPMC_regist(UA_PubSubChannel *channel, UA_ExtensionObject *transportSettings) {
  269. if(!(channel->state == UA_PUBSUB_CHANNEL_PUB || channel->state == UA_PUBSUB_CHANNEL_RDY)){
  270. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection regist failed.");
  271. return UA_STATUSCODE_BADINTERNALERROR;
  272. }
  273. UA_PubSubChannelDataUDPMC * connectionConfig = (UA_PubSubChannelDataUDPMC *) channel->handle;
  274. if(connectionConfig->ai_family == PF_INET){//IPv4 handling
  275. struct sockaddr_in addr;
  276. memcpy(&addr, connectionConfig->ai_addr, sizeof(struct sockaddr_in));
  277. addr.sin_addr.s_addr = INADDR_ANY;
  278. if (bind(channel->sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0){
  279. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection regist failed.");
  280. return UA_STATUSCODE_BADINTERNALERROR;
  281. }
  282. struct ip_mreq groupV4;
  283. memcpy(&groupV4.imr_multiaddr, &((const struct sockaddr_in *)connectionConfig->ai_addr)->sin_addr, sizeof(struct ip_mreq));
  284. groupV4.imr_interface.s_addr = htonl(INADDR_ANY);
  285. //multihomed hosts can join several groups on different IF, INADDR_ANY -> kernel decides
  286. if(setsockopt(channel->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &groupV4, sizeof(groupV4)) != 0){
  287. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection regist failed.");
  288. return UA_STATUSCODE_BADINTERNALERROR;
  289. }
  290. } else if (connectionConfig->ai_family == PF_INET6) {//IPv6 handling
  291. //TODO implement regist for IPv6
  292. } else {
  293. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection regist failed.");
  294. return UA_STATUSCODE_BADINTERNALERROR;
  295. }
  296. return UA_STATUSCODE_GOOD;
  297. }
  298. /**
  299. * Remove current subscription.
  300. *
  301. * @return UA_STATUSCODE_GOOD on success
  302. */
  303. static UA_StatusCode
  304. UA_PubSubChannelUDPMC_unregist(UA_PubSubChannel *channel, UA_ExtensionObject *transportSettings) {
  305. if(!(channel->state == UA_PUBSUB_CHANNEL_PUB_SUB || channel->state == UA_PUBSUB_CHANNEL_SUB)){
  306. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection unregist failed.");
  307. return UA_STATUSCODE_BADINTERNALERROR;
  308. }
  309. UA_PubSubChannelDataUDPMC * connectionConfig = (UA_PubSubChannelDataUDPMC *) channel->handle;
  310. if(connectionConfig->ai_family == PF_INET){//IPv4 handling
  311. struct ip_mreq groupV4;
  312. memcpy(&groupV4.imr_multiaddr, &((const struct sockaddr_in *)connectionConfig->ai_addr)->sin_addr, sizeof(struct ip_mreq));
  313. groupV4.imr_interface.s_addr = htonl(INADDR_ANY);
  314. if(setsockopt(channel->sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &groupV4, sizeof(groupV4)) != 0){
  315. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection unregist failed.");
  316. return UA_STATUSCODE_BADINTERNALERROR;
  317. }
  318. } else if (connectionConfig->ai_family == PF_INET6) {//IPv6 handling
  319. //TODO implement unregist for IPv6
  320. } else {
  321. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection unregist failed.");
  322. return UA_STATUSCODE_BADINTERNALERROR;
  323. }
  324. return UA_STATUSCODE_GOOD;
  325. }
  326. /**
  327. * Send messages to the connection defined address
  328. *
  329. * @return UA_STATUSCODE_GOOD if success
  330. */
  331. static UA_StatusCode
  332. UA_PubSubChannelUDPMC_send(UA_PubSubChannel *channel, UA_ExtensionObject *transportSettigns, const UA_ByteString *buf) {
  333. UA_PubSubChannelDataUDPMC *channelConfigUDPMC = (UA_PubSubChannelDataUDPMC *) channel->handle;
  334. if(!(channel->state == UA_PUBSUB_CHANNEL_PUB || channel->state == UA_PUBSUB_CHANNEL_PUB_SUB)){
  335. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection sending failed. Invalid state.");
  336. return UA_STATUSCODE_BADINTERNALERROR;
  337. }
  338. //TODO evalute: chunk messages or check against MTU?
  339. long nWritten = 0;
  340. while (nWritten < (long)buf->length) {
  341. long n = sendto(channel->sockfd, buf->data, buf->length, 0,
  342. (struct sockaddr *) channelConfigUDPMC->ai_addr, sizeof(struct sockaddr_storage));
  343. if(n == -1L) {
  344. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection sending failed.");
  345. return UA_STATUSCODE_BADINTERNALERROR;
  346. }
  347. nWritten += n;
  348. }
  349. return UA_STATUSCODE_GOOD;
  350. }
  351. /**
  352. * Receive messages. The regist function should be called before.
  353. *
  354. * @param timeout in usec | on windows platforms are only multiples of 1000usec possible
  355. * @return
  356. */
  357. static UA_StatusCode
  358. UA_PubSubChannelUDPMC_receive(UA_PubSubChannel *channel, UA_ByteString *message, UA_ExtensionObject *transportSettigns, UA_UInt32 timeout){
  359. if(!(channel->state == UA_PUBSUB_CHANNEL_PUB || channel->state == UA_PUBSUB_CHANNEL_PUB_SUB)) {
  360. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection receive failed. Invalid state.");
  361. return UA_STATUSCODE_BADINTERNALERROR;
  362. }
  363. UA_PubSubChannelDataUDPMC *channelConfigUDPMC = (UA_PubSubChannelDataUDPMC *) channel->handle;
  364. if(timeout > 0) {
  365. fd_set fdset;
  366. FD_ZERO(&fdset);
  367. UA_fd_set(channel->sockfd, &fdset);
  368. struct timeval tmptv = {(long int)(timeout / 1000000),
  369. (long int)(timeout % 1000000)};
  370. int resultsize = select(channel->sockfd+1, &fdset, NULL,
  371. NULL, &tmptv);
  372. if(resultsize == 0) {
  373. message->length = 0;
  374. return UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
  375. }
  376. if (resultsize == -1) {
  377. message->length = 0;
  378. return UA_STATUSCODE_BADINTERNALERROR;
  379. }
  380. }
  381. if(channelConfigUDPMC->ai_family == PF_INET){
  382. ssize_t messageLength;
  383. messageLength = recvfrom(channel->sockfd, message->data, message->length, 0, NULL, NULL);
  384. if(messageLength > 0){
  385. message->length = (size_t) messageLength;
  386. } else {
  387. message->length = 0;
  388. }
  389. } else {
  390. //TODO implement recieve for IPv6
  391. }
  392. return UA_STATUSCODE_GOOD;
  393. }
  394. /**
  395. * Close channel and free the channel data.
  396. *
  397. * @return UA_STATUSCODE_GOOD if success
  398. */
  399. static UA_StatusCode
  400. UA_PubSubChannelUDPMC_close(UA_PubSubChannel *channel) {
  401. #ifdef _WIN32
  402. WSACleanup();
  403. #endif /* Not Windows */
  404. if(CLOSESOCKET(channel->sockfd) != 0){
  405. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection delete failed.");
  406. return UA_STATUSCODE_BADINTERNALERROR;
  407. }
  408. //cleanup the internal NetworkLayer data
  409. UA_PubSubChannelDataUDPMC *networkLayerData = (UA_PubSubChannelDataUDPMC *) channel->handle;
  410. UA_free(networkLayerData->ai_addr);
  411. UA_free(networkLayerData);
  412. UA_free(channel);
  413. return UA_STATUSCODE_GOOD;
  414. }
  415. /**
  416. * Generate a new channel. based on the given configuration.
  417. *
  418. * @param connectionConfig connection configuration
  419. * @return ref to created channel, NULL on error
  420. */
  421. static UA_PubSubChannel *
  422. TransportLayerUDPMC_addChannel(UA_PubSubConnectionConfig *connectionConfig) {
  423. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "PubSub channel requested");
  424. UA_PubSubChannel * pubSubChannel = UA_PubSubChannelUDPMC_open(connectionConfig);
  425. if(pubSubChannel){
  426. pubSubChannel->regist = UA_PubSubChannelUDPMC_regist;
  427. pubSubChannel->unregist = UA_PubSubChannelUDPMC_unregist;
  428. pubSubChannel->send = UA_PubSubChannelUDPMC_send;
  429. pubSubChannel->receive = UA_PubSubChannelUDPMC_receive;
  430. pubSubChannel->close = UA_PubSubChannelUDPMC_close;
  431. pubSubChannel->connectionConfig = connectionConfig;
  432. }
  433. return pubSubChannel;
  434. }
  435. //UDPMC channel factory
  436. UA_PubSubTransportLayer
  437. UA_PubSubTransportLayerUDPMP() {
  438. UA_PubSubTransportLayer pubSubTransportLayer;
  439. pubSubTransportLayer.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  440. pubSubTransportLayer.createPubSubChannel = &TransportLayerUDPMC_addChannel;
  441. return pubSubTransportLayer;
  442. }
  443. #undef _POSIX_C_SOURCE