libm3/src/uid/POSIX/MachineIDPosixC.c
/* Copyright (C) 1993, Digital Equipment Corporation */
/* All rights reserved. */
/* See the file COPYRIGHT for a full description. */
/* */
/* Last modified on Mon Sep 20 11:46:17 PDT 1993 by kalsow */
/* modified on Thu Jul 15 16:23:08 PDT 1993 by swart */
#include "m3core.h"
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifdef __sun
#include <sys/sockio.h>
#endif
#ifndef __CYGWIN__
#include <net/if.h>
#include <net/if_arp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !(defined(__APPLE__) \
|| defined(__CYGWIN__) \
|| defined(__FreeBSD__) \
|| defined(__linux__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__osf__) \
|| defined(__sun))
#error Please test/port this.
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
#define HAS_GETIFADDRS
#endif
#if defined(__linux__) || defined(__CYGWIN__) || defined(__osf__)
#define HAS_SIOCGIFCONF
#endif
#ifdef HAS_GETIFADDRS
#include <net/if_dl.h>
#include <ifaddrs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if 0
static
char
ToPrintable(unsigned char a)
{
if (a >= 32 && a < 127)
return a;
return '.';
}
static
void
HexDump(void* a, size_t n)
{
char buffer[256];
unsigned char* b = (unsigned char*)a;
size_t i;
size_t j;
size_t k = 0;
const static char hex[] = "0123456789ABCDEF";
for (i = 0; i < n; ++i)
{
buffer[k++] = hex[b[i] >> 4];
buffer[k++] = hex[b[i] & 0xF];
buffer[k++] = ' ';
if (((i + 1) % 8) == 0)
buffer[k++] = ' ';
if (((i + 1) % 16) == 0)
{
for (j = i - 15; j <= i; ++j)
{
buffer[k++] = ToPrintable(b[j]);
if (((j + 1) % 8) == 0)
buffer[k++] = ' ';
}
buffer[k++] = '\n';
buffer[k++] = 0;
printf("%s", buffer);
k = 0;
}
}
}
#endif
static
UINT32
get_ipv4_address(void)
{
char hostname[256];
if (gethostname(hostname, sizeof(hostname)) == 0)
{
struct hostent* hostent = gethostbyname(hostname);
if (hostent && hostent->h_length == 4)
{
return *(UINT32*)hostent->h_addr;
}
}
return 0;
}
int/*boolean*/
__cdecl
MachineIDC__CanGet(unsigned char *id)
{
int result = { 0 };
int sock = { 0 };
#if defined(HAS_GETIFADDRS)
struct ifaddrs* if1 = { 0 };
struct ifaddrs* if2 = { 0 };
#elif defined(HAS_SIOCGIFCONF)
union {
struct ifreq req[64];
unsigned char b[4096];
} buf;
struct ifconf list;
struct ifreq* req1 = { 0 };
size_t i = { 0 };
struct ifreq req2;
#ifdef __osf__
struct ifdevea ifdev;
ZeroMemory(&ifdev, sizeof(ifdev));
#endif
ZeroMemory(&buf, sizeof(buf));
ZeroMemory(&list, sizeof(list));
ZeroMemory(&req2, sizeof(req2));
#endif
ZeroMemory(id, 6);
/* try to find an ethernet hardware address */
#ifdef __sun
sock = socket(AF_INET, SOCK_DGRAM, 0);
#else
sock = socket(PF_UNIX, SOCK_STREAM, AF_UNSPEC);
#endif
if (sock >= 0)
{
#ifdef HAS_GETIFADDRS
if (getifaddrs(&if1) == 0)
{
for (if2 = if1; (!result) && if2; if2 = if2->ifa_next)
{
if (((if2->ifa_flags & IFF_LOOPBACK) == 0) && (if2->ifa_addr->sa_family == AF_LINK))
{
struct sockaddr_dl* dl = (struct sockaddr_dl*)if2->ifa_addr;
unsigned char* mac = (unsigned char*)LLADDR(dl);
if (dl->sdl_alen == 6) /* 48 bits */
{
memcpy(id, mac, 6);
result = 1;
}
}
}
freeifaddrs(if1);
}
else
{
perror("getifaddrs");
}
#elif defined(HAS_SIOCGIFCONF)
list.ifc_len = sizeof(buf);
list.ifc_req = (struct ifreq*)&buf;
if (ioctl(sock, SIOCGIFCONF, &list) >= 0)
{
for (i = 0; (!result) && (i < list.ifc_len); i += sizeof(*req1))
{
req1 = (struct ifreq*)&buf.b[i];
memcpy(req2.ifr_name, req1->ifr_name, IFNAMSIZ);
if (ioctl(sock, SIOCGIFFLAGS, &req2) < 0)
{
perror("ioctl SIOCGIFFLAGS");
continue;
}
if ((req2.ifr_flags & IFF_LOOPBACK) != 0)
continue;
#if defined(__linux__) || defined(__CYGWIN__)
/* This memcpy probably not needed. */
memcpy(req2.ifr_name, req1->ifr_name, IFNAMSIZ);
if (ioctl(sock, SIOCGIFHWADDR, &req2) < 0)
{
perror("ioctl SIOCGIFHWADDR");
continue;
}
memcpy(id, req2.ifr_hwaddr.sa_data, 6);
#elif defined(__osf__)
memcpy(ifdev.ifr_name, req1->ifr_name, IFNAMSIZ);
if (ioctl(sock, SIOCRPHYSADDR, &ifdev) < 0)
{
/* This does happen, but then we try
* additional addresses and it works.
*/
continue;
}
memcpy(id, ifdev.default_pa, 6);
#else
#error unknown system
#endif
result = 1;
}
}
else
{
perror("ioctl SIOCGIFCONF");
}
#elif defined(__sun)
/* Use ARP on Solaris. */
if (result == 0)
{
struct arpreq arp;
struct sockaddr_in* in = (struct sockaddr_in*)&arp.arp_pa; /* protocol address */
ZeroMemory(&arp, sizeof(arp));
arp.arp_pa.sa_family = AF_INET;
arp.arp_ha.sa_family = AF_UNSPEC;
in->sin_addr.s_addr = get_ipv4_address();
if (ioctl(sock, SIOCGARP, &arp) == -1)
{
perror("ioctl SIOCGARP");
}
else
{
memcpy(id, arp.arp_ha.sa_data, 6); /* hardware address */
result = 1;
}
}
#else
#error unknown system
#endif
close(sock);
}
else
{
perror("socket");
}
/* really lame fallback */
if (result == 0)
{
union
{
UINT32 a;
unsigned char b[4];
} u;
u.a = get_ipv4_address();
memcpy(&id[2], u.b, 4);
result = (u.a != 0);
}
return result;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#if 0 /* test code */
int main()
{
unsigned char id[6] = { 0 };
int i = { 0 };
i = MachineIDC__CanGet(id);
printf("%d %02X-%02X-%02X-%02X-%02X-%02X\n", i, id[0], id[1], id[2], id[3], id[4], id[5]);
printf(" %u.%u.%u.%u.%u.%u\n", id[0], id[1], id[2], id[3], id[4], id[5]);
#if defined(__sun)
system("/usr/sbin/arp -a | grep L"); /* L for local */
#elif defined(__CYGWIN__)
system("getmac");
#elif defined(__osf__)
/*system("/usr/sbin/netstat -ia | grep :");*/
#else
system("/sbin/ifconfig -a | grep addr");
system("/sbin/ifconfig -a | grep ether");
#endif
return 0;
}
#endif