~ubuntu-branches/ubuntu/karmic/gears/karmic

« back to all changes in this revision

Viewing changes to gears/base/common/exception_handler_osx/nshost_macaddress.m

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Lesicnik
  • Date: 2009-04-30 19:15:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090430191525-0790sb5wzg8ou0xb
Tags: upstream-0.5.21.0~svn3334+dfsg
ImportĀ upstreamĀ versionĀ 0.5.21.0~svn3334+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2007, Google Inc.
 
2
//
 
3
// Redistribution and use in source and binary forms, with or without
 
4
// modification, are permitted provided that the following conditions are met:
 
5
//
 
6
//  1. Redistributions of source code must retain the above copyright notice,
 
7
//     this list of conditions and the following disclaimer.
 
8
//  2. Redistributions in binary form must reproduce the above copyright notice,
 
9
//     this list of conditions and the following disclaimer in the documentation
 
10
//     and/or other materials provided with the distribution.
 
11
//  3. Neither the name of Google Inc. nor the names of its contributors may be
 
12
//     used to endorse or promote products derived from this software without
 
13
//     specific prior written permission.
 
14
//
 
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 
 
26
#import "gears/base/common/exception_handler_osx/nshost_macaddress.h"
 
27
 
 
28
#import <openssl/md5.h>
 
29
#import <stdio.h>
 
30
 
 
31
#import <CoreFoundation/CoreFoundation.h>
 
32
 
 
33
#import <IOKit/IOKitLib.h>
 
34
#import <IOKit/network/IOEthernetController.h>
 
35
#import <IOKit/network/IOEthernetInterface.h>
 
36
#import <IOKit/network/IONetworkInterface.h>
 
37
 
 
38
void GMLog(id x, ...) {}
 
39
#define GMDebuggerAssertAlways(x,y,z)
 
40
 
 
41
// helper functions
 
42
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices);
 
43
static kern_return_t GetMACAddress(io_iterator_t intfIterator,
 
44
  UInt8 *MACAddress, UInt8 bufferSize);
 
45
 
 
46
@implementation NSHost (MACAddress)
 
47
 
 
48
// Return the MAC address of this host.
 
49
// This must be called from [NSHost currentHost];
 
50
// The result may be used as an ID which is unique to this host.
 
51
- (NSString *)MACAddress {
 
52
  NSString *result = nil;
 
53
 
 
54
  if (![self isEqualToHost:[[self class] currentHost]]) {
 
55
    GMDebuggerAssertAlways(@"%@ isn't current host %@", self,
 
56
      [[self class] currentHost]);
 
57
    return nil;
 
58
  }
 
59
 
 
60
  kern_return_t kernResult = KERN_SUCCESS;
 
61
 
 
62
  io_iterator_t intfIterator;
 
63
  UInt8 MACAddress[kIOEthernetAddressSize];
 
64
 
 
65
  kernResult = FindEthernetInterfaces(&intfIterator);
 
66
 
 
67
  if (KERN_SUCCESS != kernResult) {
 
68
    return nil;
 
69
  }
 
70
  else {
 
71
    kernResult = GetMACAddress(intfIterator, MACAddress, sizeof(MACAddress));
 
72
 
 
73
    if (KERN_SUCCESS != kernResult) {
 
74
      return nil;
 
75
    }
 
76
        else {
 
77
      result = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x",
 
78
        MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3],
 
79
        MACAddress[4], MACAddress[5] ];
 
80
        }
 
81
  }
 
82
 
 
83
  IOObjectRelease(intfIterator);        // Release the iterator.
 
84
 
 
85
  return result;
 
86
}
 
87
 
 
88
// Return the MAC address of this host, obfuscated for privacy.
 
89
// This must be called from [NSHost currentHost];
 
90
// The result may be used as an ID which is unique to this host.
 
91
- (NSString *)obfuscatedMACAddress {
 
92
  NSString *address = [self MACAddress];
 
93
 
 
94
  if (!address) return nil;
 
95
 
 
96
  const char *s = [address UTF8String];
 
97
 
 
98
  MD5_CTX c;
 
99
  MD5_Init(&c);
 
100
  MD5_Update(&c, s, strlen(s) );
 
101
 
 
102
  unsigned char hash[16];
 
103
  MD5_Final(hash, &c);
 
104
 
 
105
  UInt32 *hash32 = (UInt32*)hash;
 
106
 
 
107
  NSString *result = [NSString stringWithFormat:@"%04x%04x%04x%04x",
 
108
    hash32[0], hash32[1], hash32[2], hash32[3] ];
 
109
 
 
110
  return result;
 
111
}
 
112
 
 
113
@end
 
114
 
 
115
// code adapted from Apple sample code GetPrimaryMACAddress.c
 
116
// http://developer.apple.com/samplecode/GetPrimaryMACAddress/listing1.html
 
117
//
 
118
 
 
119
// Returns an iterator containing the primary (built-in) Ethernet interface.
 
120
// The caller is responsible for
 
121
// releasing the iterator after the caller is done with it.
 
122
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices) {
 
123
    kern_return_t               kernResult;
 
124
    CFMutableDictionaryRef      matchingDict;
 
125
    CFMutableDictionaryRef      propertyMatchDict;
 
126
 
 
127
    // Ethernet interfaces are instances of class kIOEthernetInterfaceClass.
 
128
    // IOServiceMatching is a convenience function to create a dictionary with
 
129
    // the key kIOProviderClassKey and the specified value.
 
130
    matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
 
131
 
 
132
    // Note that another option here would be:
 
133
    // matchingDict = IOBSDMatching("en0");
 
134
 
 
135
    if (NULL == matchingDict) {
 
136
        GMLog(@"IOServiceMatching returned a NULL dictionary.\n");
 
137
    }
 
138
    else {
 
139
        // Each IONetworkInterface object has a Boolean property with the key
 
140
        // kIOPrimaryInterface.
 
141
        // Only the primary (built-in) interface has this property set to TRUE.
 
142
 
 
143
        // IOServiceGetMatchingServices uses the default matching criteria
 
144
        // defined by IOService. This considers only the following properties
 
145
        // plus any family-specific matching in this order of precedence
 
146
        // (see IOService::passiveMatch):
 
147
        //
 
148
        // kIOProviderClassKey (IOServiceMatching)
 
149
        // kIONameMatchKey (IOServiceNameMatching)
 
150
        // kIOPropertyMatchKey
 
151
        // kIOPathMatchKey
 
152
        // kIOMatchedServiceCountKey
 
153
        // family-specific matching
 
154
        // kIOBSDNameKey (IOBSDNameMatching)
 
155
        // kIOLocationMatchKey
 
156
 
 
157
        // The IONetworkingFamily does not define any family-specific matching.
 
158
        // This means that in order to have IOServiceGetMatchingServices consider
 
159
        // the kIOPrimaryInterface property, we must add that property
 
160
        // to a separate dictionary and then add that to our matching dictionary
 
161
        // specifying kIOPropertyMatchKey.
 
162
 
 
163
        propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
 
164
                                                                                                          &kCFTypeDictionaryKeyCallBacks,
 
165
                                                                                                          &kCFTypeDictionaryValueCallBacks);
 
166
 
 
167
        if (NULL == propertyMatchDict) {
 
168
            GMLog(@"CFDictionaryCreateMutable returned a NULL dictionary.\n");
 
169
        }
 
170
        else {
 
171
            // Set the value in the dictionary of the property with the
 
172
            // given key, or add the key to the dictionary if it doesn't exist.
 
173
            // This call retains the value object passed in.
 
174
            CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface),
 
175
              kCFBooleanTrue);
 
176
 
 
177
            // Now add the dictionary containing the matching value for
 
178
            // kIOPrimaryInterface to our main matching dictionary.
 
179
            // This call will retain propertyMatchDict, so we can release our
 
180
            // reference on propertyMatchDict after adding it to matchingDict.
 
181
            CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey),
 
182
              propertyMatchDict);
 
183
            CFRelease(propertyMatchDict);
 
184
        }
 
185
    }
 
186
 
 
187
    // IOServiceGetMatchingServices retains the returned iterator, so release
 
188
    // the iterator when we're done with it.
 
189
    // IOServiceGetMatchingServices also consumes a reference on the matching
 
190
    // dictionary so we don't need to release the dictionary explicitly.
 
191
    kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict,
 
192
      matchingServices);
 
193
    if (KERN_SUCCESS != kernResult) {
 
194
        GMLog(@"IOServiceGetMatchingServices returned 0x%08x\n", kernResult);
 
195
    }
 
196
 
 
197
    return kernResult;
 
198
}
 
199
 
 
200
// Given an iterator across a set of Ethernet interfaces, return the MAC address
 
201
// of the last one.
 
202
// If no interfaces are found the MAC address is set to an empty string.
 
203
// In this sample the iterator should contain just the primary interface.
 
204
static kern_return_t GetMACAddress( io_iterator_t intfIterator,
 
205
                                    UInt8         *MACAddress,
 
206
                                    UInt8         bufferSize) {
 
207
    io_object_t         intfService;
 
208
    io_object_t         controllerService;
 
209
    kern_return_t       kernResult = KERN_FAILURE;
 
210
 
 
211
    // Make sure the caller provided enough buffer space. Protect against buffer
 
212
    // overflow problems.
 
213
        if (bufferSize < kIOEthernetAddressSize) {
 
214
                return kernResult;
 
215
        }
 
216
 
 
217
        // Initialize the returned address
 
218
    bzero(MACAddress, bufferSize);
 
219
 
 
220
    // IOIteratorNext retains the returned object,
 
221
    // so release it when we're done with it.
 
222
    while ((intfService = IOIteratorNext(intfIterator))) {
 
223
        CFTypeRef       MACAddressAsCFData;
 
224
 
 
225
        // IONetworkControllers can't be found directly by the
 
226
        // IOServiceGetMatchingServices call, since they are hardware nubs
 
227
        // and do not participate in driver matching. In other words,
 
228
        // registerService() is never called on them. So we've found the
 
229
        // IONetworkInterface and will get its parent controller
 
230
        // by asking for it specifically.
 
231
 
 
232
        // IORegistryEntryGetParentEntry retains the returned object,
 
233
        // so release it when we're done with it.
 
234
        kernResult = IORegistryEntryGetParentEntry(intfService,
 
235
                                                                                                   kIOServicePlane,
 
236
                                                                                                   &controllerService);
 
237
 
 
238
        if (KERN_SUCCESS != kernResult) {
 
239
            printf("IORegistryEntryGetParentEntry returned 0x%08x\n",
 
240
              kernResult);
 
241
        }
 
242
        else {
 
243
            // Retrieve the MAC address property from the I/O Registry in
 
244
            // the form of a CFData
 
245
            MACAddressAsCFData = IORegistryEntryCreateCFProperty(
 
246
                controllerService,
 
247
                CFSTR(kIOMACAddress),
 
248
                kCFAllocatorDefault,
 
249
                0);
 
250
 
 
251
            if (MACAddressAsCFData) {
 
252
                // Get the raw bytes of the MAC address from the CFData
 
253
                CFDataGetBytes(MACAddressAsCFData,
 
254
                  CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
 
255
                CFRelease(MACAddressAsCFData);
 
256
            }
 
257
 
 
258
            // Done with the parent Ethernet controller object so we release it.
 
259
            IOObjectRelease(controllerService);
 
260
        }
 
261
 
 
262
        // Done with the Ethernet interface object so we release it.
 
263
        IOObjectRelease(intfService);
 
264
    }
 
265
 
 
266
    return kernResult;
 
267
}