~ubuntu-branches/ubuntu/gutsy/poco/gutsy

« back to all changes in this revision

Viewing changes to Foundation/src/UUIDGenerator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Krzysztof Burghardt
  • Date: 2007-04-27 18:33:48 UTC
  • Revision ID: james.westby@ubuntu.com-20070427183348-xgnpct0qd6a2ip34
Tags: upstream-1.2.9
ImportĀ upstreamĀ versionĀ 1.2.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// UUIDGenerator.cpp
 
3
//
 
4
// $Id: //poco/1.2/Foundation/src/UUIDGenerator.cpp#1 $
 
5
//
 
6
// Library: Foundation
 
7
// Package: UUID
 
8
// Module:  UUID
 
9
//
 
10
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
 
11
// and Contributors.
 
12
//
 
13
// Permission is hereby granted, free of charge, to any person or organization
 
14
// obtaining a copy of the software and accompanying documentation covered by
 
15
// this license (the "Software") to use, reproduce, display, distribute,
 
16
// execute, and transmit the Software, and to prepare derivative works of the
 
17
// Software, and to permit third-parties to whom the Software is furnished to
 
18
// do so, all subject to the following:
 
19
// 
 
20
// The copyright notices in the Software and this entire statement, including
 
21
// the above license grant, this restriction and the following disclaimer,
 
22
// must be included in all copies of the Software, in whole or in part, and
 
23
// all derivative works of the Software, unless such copies or derivative
 
24
// works are solely in the form of machine-executable object code generated by
 
25
// a source language processor.
 
26
// 
 
27
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
28
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
29
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 
30
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 
31
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 
32
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
33
// DEALINGS IN THE SOFTWARE.
 
34
//
 
35
 
 
36
 
 
37
#include "Poco/UUIDGenerator.h"
 
38
#include "Poco/Thread.h"
 
39
#include "Poco/RandomStream.h"
 
40
#include "Poco/DigestEngine.h"
 
41
#include "Poco/MD5Engine.h"
 
42
#include "Poco/SingletonHolder.h"
 
43
#include <string.h>
 
44
 
 
45
 
 
46
namespace Poco {
 
47
 
 
48
 
 
49
UUIDGenerator::UUIDGenerator(): _ticks(0), _haveNode(false)
 
50
{
 
51
}
 
52
 
 
53
 
 
54
UUIDGenerator::~UUIDGenerator()
 
55
{
 
56
}
 
57
 
 
58
 
 
59
UUID UUIDGenerator::create()
 
60
{
 
61
        FastMutex::ScopedLock lock(_mutex);
 
62
 
 
63
        if (!_haveNode)
 
64
        {
 
65
                getNode();
 
66
                _haveNode = true;
 
67
        }
 
68
        Timestamp::UtcTimeVal tv = timeStamp();
 
69
        UInt32 timeLow = UInt32(tv & 0xFFFFFFFF);
 
70
        UInt16 timeMid = UInt16((tv >> 32) & 0xFFFF);
 
71
        UInt16 timeHiAndVersion = UInt16((tv >> 48) & 0x0FFF) + (UUID::UUID_TIME_BASED << 12);
 
72
        UInt16 clockSeq = (UInt16(_random.next() >> 4) & 0x3FFF) | 0x8000;
 
73
        return UUID(timeLow, timeMid, timeHiAndVersion, clockSeq, _node);
 
74
}
 
75
 
 
76
 
 
77
UUID UUIDGenerator::createFromName(const UUID& nsid, const std::string& name)
 
78
{
 
79
        MD5Engine md5;
 
80
        return createFromName(nsid, name, md5);
 
81
}
 
82
 
 
83
 
 
84
UUID UUIDGenerator::createFromName(const UUID& nsid, const std::string& name, DigestEngine& de)
 
85
{
 
86
        poco_assert_dbg (de.digestLength() >= 16);
 
87
 
 
88
        UUID netNsid = nsid;
 
89
        netNsid.toNetwork();
 
90
        de.reset();
 
91
        de.update(&netNsid, sizeof(netNsid));
 
92
        de.update(name);
 
93
        char buffer[16];
 
94
        const DigestEngine::Digest& d = de.digest();
 
95
        for (int i = 0; i < 16; ++i)
 
96
        {
 
97
                buffer[i] = d[i];
 
98
        }
 
99
        return UUID(buffer, UUID::UUID_NAME_BASED);
 
100
}
 
101
 
 
102
        
 
103
UUID UUIDGenerator::createRandom()
 
104
{
 
105
        char buffer[16];
 
106
        RandomInputStream ris;
 
107
        ris.read(buffer, sizeof(buffer));
 
108
        return UUID(buffer, UUID::UUID_RANDOM);
 
109
}
 
110
 
 
111
 
 
112
Timestamp::UtcTimeVal UUIDGenerator::timeStamp()
 
113
{
 
114
        Timestamp now;
 
115
        for (;;)
 
116
        {
 
117
                if (now != _lastTime)
 
118
                {
 
119
                        _lastTime = now;
 
120
                        _ticks = 0;
 
121
                        break;
 
122
                }
 
123
                if (_ticks < 100)
 
124
                {
 
125
                        ++_ticks;
 
126
                        break;
 
127
                }
 
128
                now.update();
 
129
        }
 
130
        Timestamp::UtcTimeVal tv = now.utcTime();
 
131
        return tv + _ticks;
 
132
}
 
133
 
 
134
 
 
135
UUID UUIDGenerator::createOne()
 
136
{
 
137
        try
 
138
        {
 
139
                return create();
 
140
        }
 
141
        catch (Exception&)
 
142
        {
 
143
                return createRandom();
 
144
        }
 
145
}
 
146
 
 
147
 
 
148
UUIDGenerator& UUIDGenerator::defaultGenerator()
 
149
{
 
150
        static SingletonHolder<UUIDGenerator> sh;
 
151
        return *sh.get();
 
152
}
 
153
 
 
154
 
 
155
} // namespace Poco
 
156
 
 
157
 
 
158
//
 
159
// platform-specific code below
 
160
//
 
161
 
 
162
 
 
163
#if defined(POCO_OS_FAMILY_WINDOWS)
 
164
//
 
165
// Windows
 
166
//
 
167
#include <windows.h>
 
168
#include <iphlpapi.h>
 
169
 
 
170
 
 
171
namespace Poco {
 
172
 
 
173
 
 
174
void UUIDGenerator::getNode()
 
175
{
 
176
        PIP_ADAPTER_INFO pAdapterInfo;
 
177
        PIP_ADAPTER_INFO pAdapter = 0;
 
178
        ULONG len    = sizeof(IP_ADAPTER_INFO);
 
179
        pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]);
 
180
        // Make an initial call to GetAdaptersInfo to get
 
181
        // the necessary size into len
 
182
        DWORD rc = GetAdaptersInfo(pAdapterInfo, &len);
 
183
        if (rc == ERROR_BUFFER_OVERFLOW) 
 
184
        {
 
185
                delete [] reinterpret_cast<char*>(pAdapterInfo);
 
186
                pAdapterInfo = reinterpret_cast<IP_ADAPTER_INFO*>(new char[len]);
 
187
        }
 
188
        else if (rc != ERROR_SUCCESS)
 
189
        {
 
190
                throw SystemException("cannot get network adapter list");
 
191
        }
 
192
        try
 
193
        {
 
194
                bool found = false;
 
195
                if (GetAdaptersInfo(pAdapterInfo, &len) == NO_ERROR) 
 
196
                {
 
197
                        pAdapter = pAdapterInfo;
 
198
                        while (pAdapter && !found) 
 
199
                        {
 
200
                                if (pAdapter->Type == MIB_IF_TYPE_ETHERNET && pAdapter->AddressLength == sizeof(_node))
 
201
                                {
 
202
                                        memcpy(_node, pAdapter->Address, pAdapter->AddressLength);
 
203
                                        found = true;
 
204
                                }
 
205
                        }
 
206
                }
 
207
                else throw SystemException("cannot get network adapter list");
 
208
                if (!found) throw SystemException("no Ethernet adapter found");
 
209
        }
 
210
        catch (Exception&)
 
211
        {
 
212
                delete [] reinterpret_cast<char*>(pAdapterInfo);
 
213
                throw;
 
214
        }
 
215
        delete [] reinterpret_cast<char*>(pAdapterInfo);
 
216
}
 
217
 
 
218
 
 
219
} // namespace Poco
 
220
 
 
221
 
 
222
#elif defined(POCO_OS_FAMILY_BSD) || POCO_OS == POCO_OS_QNX
 
223
//
 
224
// BSD variants
 
225
//
 
226
#include <sys/types.h>
 
227
#include <sys/socket.h>
 
228
#include <ifaddrs.h>
 
229
#include <net/if_dl.h>
 
230
 
 
231
 
 
232
namespace Poco {
 
233
 
 
234
 
 
235
void UUIDGenerator::getNode()
 
236
{
 
237
        struct ifaddrs* ifaphead;
 
238
        int rc = getifaddrs(&ifaphead);
 
239
        if (rc) throw SystemException("cannot get network adapter list");
 
240
 
 
241
        bool foundAdapter = false;
 
242
        for (struct ifaddrs* ifap = ifaphead; ifap; ifap = ifap->ifa_next) 
 
243
        {
 
244
                if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_LINK) 
 
245
                {
 
246
                        struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifap->ifa_addr);
 
247
                        caddr_t ap = (caddr_t) (sdl->sdl_data + sdl->sdl_nlen);
 
248
                        int alen = sdl->sdl_alen;
 
249
                        if (ap && alen > 0) 
 
250
                        {
 
251
                                memcpy(_node, ap, sizeof(_node));
 
252
                                foundAdapter = true;
 
253
                                break;
 
254
                        }
 
255
                }
 
256
        }
 
257
        freeifaddrs(ifaphead);
 
258
        if (!foundAdapter) throw SystemException("cannot determine MAC address (no suitable network adapter found)");
 
259
}
 
260
 
 
261
 
 
262
} // namespace Poco
 
263
 
 
264
 
 
265
#elif defined(__CYGWIN__) || POCO_OS == POCO_OS_LINUX
 
266
//
 
267
// Linux
 
268
//
 
269
#include <sys/ioctl.h>
 
270
#include <sys/socket.h>
 
271
#include <netinet/in.h>
 
272
#include <net/if.h>
 
273
#include <arpa/inet.h>
 
274
#include <unistd.h>
 
275
 
 
276
 
 
277
namespace Poco {
 
278
 
 
279
 
 
280
void UUIDGenerator::getNode()
 
281
{
 
282
        struct ifreq ifr;
 
283
 
 
284
        int s = socket(PF_INET, SOCK_DGRAM, 0);
 
285
        if (s == -1) throw SystemException("cannot open socket");
 
286
 
 
287
        strcpy(ifr.ifr_name, "eth0");
 
288
        int rc = ioctl(s, SIOCGIFHWADDR, &ifr);
 
289
        close(s);
 
290
        if (rc < 0) throw SystemException("cannot get MAC address");
 
291
        struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(&ifr.ifr_addr);
 
292
        memcpy(_node, sa->sa_data, sizeof(_node));
 
293
}
 
294
 
 
295
 
 
296
} // namespace Poco
 
297
 
 
298
 
 
299
#elif defined(POCO_OS_FAMILY_UNIX) || defined(POCO_OS_FAMILY_VMS)
 
300
//
 
301
// Unix/VMS
 
302
//
 
303
#if defined(__VMS)
 
304
#include <ioctl.h>
 
305
#else
 
306
#include <sys/ioctl.h>
 
307
#endif
 
308
#if defined(sun) || defined(__sun)
 
309
#include <sys/sockio.h>
 
310
#endif
 
311
#include <sys/socket.h>
 
312
#include <sys/types.h>
 
313
#include <netinet/in.h>
 
314
#include <net/if.h>
 
315
#if defined(__VMS)
 
316
#include <inet.h>
 
317
#else
 
318
#include <arpa/inet.h>
 
319
#endif
 
320
#include <netdb.h>
 
321
#include <net/if.h>
 
322
#include <net/if_arp.h>
 
323
#include <unistd.h>
 
324
 
 
325
 
 
326
#if defined(__VMS)
 
327
#define MAXHOSTNAMELEN 64
 
328
#endif
 
329
 
 
330
 
 
331
namespace Poco {
 
332
 
 
333
 
 
334
void UUIDGenerator::getNode()
 
335
{
 
336
        char name[MAXHOSTNAMELEN];
 
337
        if (gethostname(name, sizeof(name)))
 
338
                throw SystemException("cannot get host name");
 
339
 
 
340
        struct hostent* pHost = gethostbyname(name);
 
341
        if (!pHost) throw SystemException("cannot get host IP address");
 
342
 
 
343
        int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 
344
        if (s == -1) throw SystemException("cannot open socket");
 
345
 
 
346
        struct arpreq ar;
 
347
        memset(&ar, 0, sizeof(ar));
 
348
        struct sockaddr_in* pAddr = reinterpret_cast<struct sockaddr_in*>(&ar.arp_pa);
 
349
        pAddr->sin_family = AF_INET;
 
350
        memcpy(&pAddr->sin_addr, *pHost->h_addr_list, sizeof(struct in_addr));
 
351
        int rc = ioctl(s, SIOCGARP, &ar);
 
352
        close(s);
 
353
        if (rc < 0) throw SystemException("cannot get MAC address");
 
354
        memcpy(_node, ar.arp_ha.sa_data, sizeof(_node));
 
355
}
 
356
 
 
357
 
 
358
} // namespace Poco
 
359
 
 
360
 
 
361
#endif