Line data Source code
1 : /*
2 : * Distributed under the OpenDDS License.
3 : * See: http://www.opendds.org/license.html
4 : */
5 :
6 : #include "GuidGenerator.h"
7 :
8 : #include <dds/DCPS/GuidUtils.h>
9 : #include <dds/DCPS/TimeTypes.h>
10 : #include <dds/DCPS/debug.h>
11 :
12 : #include <dds/DdsDcpsGuidTypeSupportImpl.h>
13 :
14 : #include <ace/OS_NS_unistd.h>
15 : #include <ace/OS_NS_stdlib.h>
16 : #include <ace/OS_NS_netdb.h>
17 : #include <ace/OS_NS_sys_socket.h>
18 : #include <ace/OS_NS_sys_time.h>
19 : #include <ace/Log_Msg.h>
20 : #include <ace/os_include/net/os_if.h>
21 :
22 : #include <cstring>
23 :
24 : #ifdef ACE_HAS_CPP11
25 : # include <random>
26 : #endif
27 :
28 : #ifdef ACE_LINUX
29 : # include <sys/types.h>
30 : # include <ifaddrs.h>
31 : #endif
32 :
33 : #if defined ACE_WIN32 && !defined ACE_HAS_WINCE
34 : # include <winsock2.h>
35 : # include <iphlpapi.h>
36 : # include <ace/Version.h>
37 : #endif
38 :
39 : #ifdef ACE_VXWORKS
40 : # include <ace/os_include/sys/os_sysctl.h>
41 : # include <net/route.h>
42 : #endif
43 :
44 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
45 :
46 : namespace OpenDDS {
47 : namespace RTPS {
48 :
49 : using DCPS::SystemTimePoint;
50 :
51 5 : GuidGenerator::GuidGenerator()
52 5 : : pid_(ACE_OS::getpid())
53 : {
54 5 : unsigned seed = static_cast<unsigned>(SystemTimePoint::now().value().usec() + reinterpret_cast<size_t>(this));
55 :
56 5 : if (pid_ == -1) {
57 0 : pid_ = static_cast<pid_t>(ACE_OS::rand_r(&seed));
58 : }
59 :
60 : #ifdef ACE_HAS_CPP11
61 5 : std::mt19937 generator(seed);
62 5 : std::uniform_int_distribution<ACE_UINT16> distribution(0, ACE_UINT16_MAX);
63 5 : counter_ = distribution(generator);
64 : #else
65 : counter_ = static_cast<ACE_UINT16>(ACE_OS::rand_r(&seed));
66 : #endif
67 :
68 : ACE_OS::macaddr_node_t macaddress;
69 5 : const int result = ACE_OS::getmacaddress(&macaddress);
70 :
71 : #ifndef ACE_HAS_IOS
72 5 : if (-1 != result) {
73 5 : ACE_OS::memcpy(node_id_, macaddress.node, NODE_ID_SIZE);
74 : } else {
75 0 : for (int i = 0; i < NODE_ID_SIZE; ++i) {
76 0 : node_id_[i] = static_cast<unsigned char>(ACE_OS::rand_r(&seed));
77 : }
78 : }
79 : #else
80 : // iOS has non-unique MAC addresses
81 : ACE_UNUSED_ARG(result);
82 :
83 : for (int i = 0; i < NODE_ID_SIZE; ++i) {
84 : node_id_[i] = static_cast<unsigned char>(ACE_OS::rand_r(&seed));
85 : }
86 : #endif /* ACE_HAS_IOS */
87 5 : }
88 :
89 : ACE_UINT16
90 93 : GuidGenerator::getCount(bool doIncrement)
91 : {
92 93 : ACE_Guard<ACE_Thread_Mutex> guard(counter_lock_);
93 93 : if (doIncrement) {
94 90 : ++counter_;
95 : }
96 93 : return counter_;
97 93 : }
98 :
99 : int
100 2 : GuidGenerator::interfaceName(const char* iface)
101 : {
102 : // A shortcut to determine if a *valid* interface was already checked.
103 : // The shortcut value (interface_name_) is stored IFF the method returns 0.
104 2 : if (interface_name_ == iface) {
105 0 : return 0;
106 : }
107 :
108 : // See ace/OS_NS_netdb.cpp ACE_OS::getmacaddress()
109 : #if defined ACE_WIN32 && !defined ACE_HAS_WINCE
110 : ULONG size;
111 : if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &size)
112 : != ERROR_BUFFER_OVERFLOW) {
113 : return -1;
114 : }
115 : ACE_Allocator* const alloc = DCPS::SafetyProfilePool::instance();
116 : IP_ADAPTER_ADDRESSES* const addrs =
117 : static_cast<IP_ADAPTER_ADDRESSES*>(alloc->malloc(size));
118 : if (!addrs) {
119 : return -1;
120 : }
121 : if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, addrs, &size) != NO_ERROR) {
122 : alloc->free(addrs);
123 : return -1;
124 : }
125 :
126 : bool found = false;
127 : for (IP_ADAPTER_ADDRESSES* iter = addrs; iter && !found; iter = iter->Next) {
128 : if (ACE_Wide_To_Ascii(iter->FriendlyName).char_rep() == iface) {
129 : std::memcpy(node_id_, iter->PhysicalAddress,
130 : std::min(static_cast<size_t>(iter->PhysicalAddressLength),
131 : sizeof node_id_));
132 : found = true;
133 : }
134 : }
135 :
136 : alloc->free(addrs);
137 : if (found) {
138 : interface_name_ = iface;
139 : return 0;
140 : } else {
141 : return -1;
142 : }
143 :
144 : #elif defined ACE_LINUX || defined ACE_ANDROID
145 : ifreq ifr;
146 : // Guarantee that iface will fit in ifr.ifr_name and still be null terminated
147 : // ifr.ifr_name is sized to IFNAMSIZ
148 2 : if (std::strlen(iface) >= sizeof(ifr.ifr_name)) {
149 2 : if (DCPS::log_level >= DCPS::LogLevel::Error) {
150 0 : ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: GuidGenerator::interfaceName: "
151 : "Interface name %C exceeds max allowable length, must be < %d.\n",
152 : iface, IFNAMSIZ));
153 : }
154 2 : return -1;
155 : }
156 0 : std::strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
157 0 : const ACE_HANDLE h = ACE_OS::socket(PF_INET, SOCK_DGRAM, 0);
158 0 : if (h == ACE_INVALID_HANDLE) {
159 0 : return -1;
160 : }
161 0 : if (ACE_OS::ioctl(h, SIOCGIFHWADDR, &ifr) < 0) {
162 0 : ACE_OS::close(h);
163 0 : return -1;
164 : }
165 0 : ACE_OS::close(h);
166 0 : std::memcpy(node_id_, ifr.ifr_addr.sa_data, sizeof node_id_);
167 :
168 0 : interface_name_ = iface;
169 0 : return 0;
170 : #elif defined ACE_HAS_SIOCGIFCONF || defined ACE_HAS_MAC_OSX
171 : const ACE_HANDLE h = ACE_OS::socket(AF_INET, SOCK_DGRAM, 0);
172 : if (h == ACE_INVALID_HANDLE) {
173 : return -1;
174 : }
175 :
176 : const int BUFFERSIZE = 4000;
177 : char buffer[BUFFERSIZE];
178 : ifconf ifc;
179 : ifc.ifc_len = BUFFERSIZE;
180 : ifc.ifc_buf = buffer;
181 :
182 : if (ACE_OS::ioctl(h, SIOCGIFCONF, &ifc) < 0) {
183 : ACE_OS::close(h);
184 : return -1;
185 : }
186 :
187 : bool found = false;
188 : for (const char* ptr = buffer; !found && ptr < buffer + ifc.ifc_len;) {
189 : const ifreq* ifr = reinterpret_cast<const ifreq*>(ptr);
190 : if (ifr->ifr_addr.sa_family == AF_LINK && ifr->ifr_name == interface_name_) {
191 : const sockaddr_dl* sdl =
192 : reinterpret_cast<const sockaddr_dl*>(&ifr->ifr_addr);
193 : std::memcpy(node_id_, LLADDR(sdl), sizeof node_id_);
194 : found = true;
195 : }
196 :
197 : ptr += sizeof ifr->ifr_name + std::max(sizeof ifr->ifr_addr,
198 : static_cast<size_t>(ifr->ifr_addr.sa_len));
199 : }
200 :
201 : ACE_OS::close(h);
202 :
203 : if (found) {
204 : interface_name_ = iface;
205 : return 0;
206 : } else {
207 : return -1;
208 : }
209 : #elif defined ACE_VXWORKS
210 : int name[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
211 : static const size_t name_elts = sizeof name / sizeof name[0];
212 :
213 : size_t result_sz = 0u;
214 : if (sysctl(name, name_elts, 0, &result_sz, 0, 0u) != 0) {
215 : return -1;
216 : }
217 :
218 : ACE_Allocator* const alloc = DCPS::SafetyProfilePool::instance();
219 : char* const result = static_cast<char*>(alloc->malloc(result_sz));
220 :
221 : if (sysctl(name, name_elts, result, &result_sz, 0, 0u) != 0) {
222 : alloc->free(result);
223 : return -1;
224 : }
225 :
226 : for (size_t pos = 0, n; pos + sizeof(if_msghdr) < result_sz; pos += n) {
227 : if_msghdr* const hdr = reinterpret_cast<if_msghdr*>(result + pos);
228 : n = hdr->ifm_msglen;
229 : sockaddr_dl* const addr =
230 : reinterpret_cast<sockaddr_dl*>(result + pos + sizeof(if_msghdr));
231 :
232 : if (hdr->ifm_type == RTM_IFINFO && (hdr->ifm_addrs & RTA_IFP)
233 : && std::memcmp(addr->sdl_data, iface, addr->sdl_nlen) == 0
234 : && addr->sdl_alen >= sizeof node_id_) {
235 : std::memcpy(node_id_, LLADDR(addr), sizeof node_id_);
236 : alloc->free(result);
237 :
238 : interface_name_ = iface;
239 : return 0;
240 : }
241 :
242 : while (pos + n < result_sz) {
243 : if_msghdr* const nxt = reinterpret_cast<if_msghdr*>(result + pos + n);
244 : if (nxt->ifm_type != RTM_NEWADDR) {
245 : break;
246 : }
247 : n += nxt->ifm_msglen;
248 : }
249 : }
250 :
251 : alloc->free(result);
252 : return -1;
253 : #else
254 : return -1;
255 : #endif
256 : }
257 :
258 : void
259 90 : GuidGenerator::populate(DCPS::GUID_t &container)
260 : {
261 90 : container.guidPrefix[0] = DCPS::VENDORID_OCI[0];
262 90 : container.guidPrefix[1] = DCPS::VENDORID_OCI[1];
263 :
264 90 : const ACE_UINT16 count = getCount();
265 90 : ACE_OS::memcpy(&container.guidPrefix[2], node_id_, NODE_ID_SIZE);
266 90 : container.guidPrefix[8] = static_cast<CORBA::Octet>(pid_ >> 8);
267 90 : container.guidPrefix[9] = static_cast<CORBA::Octet>(pid_ & 0xFF);
268 90 : container.guidPrefix[10] = static_cast<CORBA::Octet>(count >> 8);
269 90 : container.guidPrefix[11] = static_cast<CORBA::Octet>(count & 0xFF);
270 90 : }
271 :
272 : } // namespace RTPS
273 : } // namespace OpenDDS
274 :
275 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
|