OpenDDS  Snapshot(2023/04/28-20:55)
GuidGenerator.cpp
Go to the documentation of this file.
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>
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
41 # include <net/route.h>
42 #endif
43 
45 
46 namespace OpenDDS {
47 namespace RTPS {
48 
50 
52  : pid_(ACE_OS::getpid())
53 {
54  unsigned seed = static_cast<unsigned>(SystemTimePoint::now().value().usec() + reinterpret_cast<size_t>(this));
55 
56  if (pid_ == -1) {
57  pid_ = static_cast<pid_t>(ACE_OS::rand_r(&seed));
58  }
59 
60 #ifdef ACE_HAS_CPP11
61  std::mt19937 generator(seed);
62  std::uniform_int_distribution<ACE_UINT16> distribution(0, ACE_UINT16_MAX);
63  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  const int result = ACE_OS::getmacaddress(&macaddress);
70 
71 #ifndef ACE_HAS_IOS
72  if (-1 != result) {
74  } else {
75  for (int i = 0; i < NODE_ID_SIZE; ++i) {
76  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 }
88 
89 ACE_UINT16
90 GuidGenerator::getCount(bool doIncrement)
91 {
93  if (doIncrement) {
94  ++counter_;
95  }
96  return counter_;
97 }
98 
99 int
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  if (interface_name_ == iface) {
105  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  }
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  if (std::strlen(iface) >= sizeof(ifr.ifr_name)) {
150  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  return -1;
155  }
156  std::strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
157  const ACE_HANDLE h = ACE_OS::socket(PF_INET, SOCK_DGRAM, 0);
158  if (h == ACE_INVALID_HANDLE) {
159  return -1;
160  }
161  if (ACE_OS::ioctl(h, SIOCGIFHWADDR, &ifr) < 0) {
162  ACE_OS::close(h);
163  return -1;
164  }
165  ACE_OS::close(h);
166  std::memcpy(node_id_, ifr.ifr_addr.sa_data, sizeof node_id_);
167 
168  interface_name_ = iface;
169  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 
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
260 {
261  container.guidPrefix[0] = DCPS::VENDORID_OCI[0];
262  container.guidPrefix[1] = DCPS::VENDORID_OCI[1];
263 
264  const ACE_UINT16 count = getCount();
266  container.guidPrefix[8] = static_cast<CORBA::Octet>(pid_ >> 8);
267  container.guidPrefix[9] = static_cast<CORBA::Octet>(pid_ & 0xFF);
268  container.guidPrefix[10] = static_cast<CORBA::Octet>(count >> 8);
269  container.guidPrefix[11] = static_cast<CORBA::Octet>(count & 0xFF);
270 }
271 
272 } // namespace RTPS
273 } // namespace OpenDDS
274 
#define ACE_ERROR(X)
void populate(DCPS::GUID_t &container)
#define SIOCGIFCONF
ACE_UINT16 getCount(bool doIncrement=true)
ACE_Thread_Mutex counter_lock_
Definition: GuidGenerator.h:68
void * memcpy(void *t, const void *s, size_t len)
virtual void free(void *ptr)=0
#define SIOCGIFHWADDR
char * char_rep(void)
TimePoint_T< SystemClock > SystemTimePoint
Definition: TimeTypes.h:32
key GuidPrefix_t guidPrefix
Definition: DdsDcpsGuid.idl:58
int interfaceName(const char *nic)
int close(ACE_HANDLE handle)
ACE_HANDLE socket(int protocol_family, int type, int proto)
#define AF_UNSPEC
#define ACE_UINT16_MAX
OPENDDS_STRING interface_name_
Definition: GuidGenerator.h:70
static ACE_Allocator * instance(void)
unsigned char node[6]
#define AF_INET
#define PF_INET
const char *const name
Definition: debug.cpp:60
int getmacaddress(struct macaddr_node_t *node)
OpenDDS_Dcps_Export LogLevel log_level
ACE_CDR::Octet Octet
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
const GuidVendorId_t VENDORID_OCI
Vendor Id value specified for OCI is used for OpenDDS.
Definition: GuidUtils.h:29
LM_ERROR
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
pid_t getpid(void)
int rand_r(unsigned int *seed)
#define SOCK_DGRAM
virtual void * malloc(size_type nbytes)=0
int ioctl(ACE_HANDLE handle, ACE_IOCTL_TYPE_ARG2 cmd, void *=0)