ua_discovery_manager.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  6. * Copyright 2014, 2017 (c) Florian Palm
  7. * Copyright 2015-2016, 2019 (c) Sten Grüner
  8. * Copyright 2015 (c) Chris Iatrou
  9. * Copyright 2015-2016 (c) Oleksiy Vasylyev
  10. * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
  11. * Copyright 2017 (c) Julian Grothoff
  12. */
  13. #include "ua_server_internal.h"
  14. #ifdef UA_ENABLE_DISCOVERY
  15. #ifdef UA_ENABLE_DISCOVERY_MULTICAST
  16. #ifndef IN_ZERONET
  17. #define IN_ZERONET(addr) ((addr & IN_CLASSA_NET) == 0)
  18. #endif
  19. /* Create multicast 224.0.0.251:5353 socket */
  20. static UA_SOCKET
  21. discovery_createMulticastSocket(UA_Server* server) {
  22. UA_SOCKET s;
  23. int flag = 1, ittl = 255;
  24. struct sockaddr_in in;
  25. struct ip_mreq mc;
  26. char ttl = (char)255; // publish to complete net, not only subnet. See:
  27. // https://docs.oracle.com/cd/E23824_01/html/821-1602/sockets-137.html
  28. memset(&in, 0, sizeof(in));
  29. in.sin_family = AF_INET;
  30. in.sin_port = htons(5353);
  31. in.sin_addr.s_addr = 0;
  32. if((s = UA_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == UA_INVALID_SOCKET)
  33. return UA_INVALID_SOCKET;
  34. #ifdef SO_REUSEPORT
  35. UA_setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char *)&flag, sizeof(flag));
  36. #endif
  37. UA_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag));
  38. if(UA_bind(s, (struct sockaddr *)&in, sizeof(in))) {
  39. UA_close(s);
  40. return UA_INVALID_SOCKET;
  41. }
  42. /* Custom outbound multicast interface */
  43. size_t length = server->config.discovery.mdnsInterfaceIP.length;
  44. if(length > 0){
  45. char* interfaceName = (char*)UA_malloc(length+1);
  46. if (!interfaceName) {
  47. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: cannot alloc memory for iface name");
  48. return 0;
  49. }
  50. struct in_addr ina;
  51. memset(&ina, 0, sizeof(ina));
  52. memcpy(interfaceName, server->config.discovery.mdnsInterfaceIP.data, length);
  53. interfaceName[length] = '\0';
  54. inet_pton(AF_INET, interfaceName, &ina);
  55. UA_free(interfaceName);
  56. /* Set interface for outbound multicast */
  57. if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&ina, sizeof(ina)) < 0)
  58. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Multicast DNS: failed setting IP_MULTICAST_IF to %s: %s", inet_ntoa(ina), strerror(errno));
  59. }
  60. /* Check outbound multicast interface parameters */
  61. struct in_addr interface_addr;
  62. socklen_t addr_size = sizeof(struct in_addr);
  63. if (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&interface_addr, &addr_size) < 0) {
  64. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: getsockopt(IP_MULTICAST_IF) failed");
  65. }
  66. if(IN_ZERONET(ntohl(interface_addr.s_addr))){
  67. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: outbound interface 0.0.0.0, it means that the first OS interface is used (you can explicitly set the interface by using 'discovery.mdnsInterfaceIP' config parameter)");
  68. }else{
  69. char buf[16];
  70. inet_ntop(AF_INET, &interface_addr, buf, 16);
  71. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: outbound interface is %s", buf);
  72. }
  73. mc.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
  74. mc.imr_interface.s_addr = htonl(INADDR_ANY);
  75. UA_setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mc, sizeof(mc));
  76. UA_setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));
  77. UA_setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl, sizeof(ittl));
  78. UA_socket_set_nonblocking(s); //TODO: check return value
  79. return s;
  80. }
  81. static UA_StatusCode
  82. initMulticastDiscoveryServer(UA_DiscoveryManager *dm, UA_Server* server) {
  83. server->discoveryManager.mdnsDaemon = mdnsd_new(QCLASS_IN, 1000);
  84. UA_initialize_architecture_network();
  85. if((server->discoveryManager.mdnsSocket = discovery_createMulticastSocket(server)) == UA_INVALID_SOCKET) {
  86. UA_LOG_SOCKET_ERRNO_WRAP(
  87. UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER,
  88. "Could not create multicast socket. Error: %s", errno_str));
  89. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  90. }
  91. mdnsd_register_receive_callback(server->discoveryManager.mdnsDaemon,
  92. mdns_record_received, server);
  93. return UA_STATUSCODE_GOOD;
  94. }
  95. static void
  96. destroyMulticastDiscoveryServer(UA_DiscoveryManager *dm) {
  97. if (!dm->mdnsDaemon)
  98. return;
  99. mdnsd_shutdown(dm->mdnsDaemon);
  100. mdnsd_free(dm->mdnsDaemon);
  101. if(dm->mdnsSocket != UA_INVALID_SOCKET) {
  102. UA_close(dm->mdnsSocket);
  103. dm->mdnsSocket = UA_INVALID_SOCKET;
  104. }
  105. }
  106. #endif /* UA_ENABLE_DISCOVERY_MULTICAST */
  107. void
  108. UA_DiscoveryManager_init(UA_DiscoveryManager *dm, UA_Server *server) {
  109. LIST_INIT(&dm->registeredServers);
  110. dm->registeredServersSize = 0;
  111. LIST_INIT(&dm->periodicServerRegisterCallbacks);
  112. dm->registerServerCallback = NULL;
  113. dm->registerServerCallbackData = NULL;
  114. #ifdef UA_ENABLE_DISCOVERY_MULTICAST
  115. dm->mdnsDaemon = NULL;
  116. dm->mdnsSocket = UA_INVALID_SOCKET;
  117. dm->mdnsMainSrvAdded = false;
  118. if(server->config.discovery.mdnsEnable)
  119. initMulticastDiscoveryServer(dm, server);
  120. LIST_INIT(&dm->serverOnNetwork);
  121. dm->serverOnNetworkSize = 0;
  122. dm->serverOnNetworkRecordIdCounter = 0;
  123. dm->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
  124. memset(dm->serverOnNetworkHash, 0,
  125. sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME);
  126. dm->serverOnNetworkCallback = NULL;
  127. dm->serverOnNetworkCallbackData = NULL;
  128. #endif /* UA_ENABLE_DISCOVERY_MULTICAST */
  129. }
  130. void
  131. UA_DiscoveryManager_deleteMembers(UA_DiscoveryManager *dm, UA_Server *server) {
  132. registeredServer_list_entry *rs, *rs_tmp;
  133. LIST_FOREACH_SAFE(rs, &dm->registeredServers, pointers, rs_tmp) {
  134. LIST_REMOVE(rs, pointers);
  135. UA_RegisteredServer_deleteMembers(&rs->registeredServer);
  136. UA_free(rs);
  137. }
  138. periodicServerRegisterCallback_entry *ps, *ps_tmp;
  139. LIST_FOREACH_SAFE(ps, &dm->periodicServerRegisterCallbacks, pointers, ps_tmp) {
  140. LIST_REMOVE(ps, pointers);
  141. if (ps->callback->discovery_server_url)
  142. UA_free(ps->callback->discovery_server_url);
  143. UA_free(ps->callback);
  144. UA_free(ps);
  145. }
  146. # ifdef UA_ENABLE_DISCOVERY_MULTICAST
  147. if(server->config.discovery.mdnsEnable)
  148. destroyMulticastDiscoveryServer(dm);
  149. serverOnNetwork_list_entry *son, *son_tmp;
  150. LIST_FOREACH_SAFE(son, &dm->serverOnNetwork, pointers, son_tmp) {
  151. LIST_REMOVE(son, pointers);
  152. UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork);
  153. if(son->pathTmp)
  154. UA_free(son->pathTmp);
  155. UA_free(son);
  156. }
  157. for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) {
  158. serverOnNetwork_hash_entry* currHash = dm->serverOnNetworkHash[i];
  159. while(currHash) {
  160. serverOnNetwork_hash_entry* nextHash = currHash->next;
  161. UA_free(currHash);
  162. currHash = nextHash;
  163. }
  164. }
  165. # endif /* UA_ENABLE_DISCOVERY_MULTICAST */
  166. }
  167. #endif /* UA_ENABLE_DISCOVERY */