ua_network_pubsub_udp.c 20 KB

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