最近在做Unity局域网对战游戏,需要获取当前可用的IP地址。要使用热点作为外网接入点,使用mono c#的api获取的ip信息是错误的,因此用native的方式来实现。
以下是一个测试版本的代码:
//
// NetInfoHelper.m
// Unity-iPhone
//
// Created by yupeng on 8/18/16.
//
//
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <net/ethernet.h>
#define MAX_IP_SIZE 16
#define MAX_BUFFER_SIZE 4096
#define TARGET_HAED_ADDR "02:00:00:00:00:00"
#define max(a,b) ((a)>(b)?(a):(b))
char* ip_int_names[MAX_IP_SIZE];
char* ip_addr_strs[MAX_IP_SIZE];
char* ip_hardwares[MAX_IP_SIZE];
char* ip_masks[MAX_IP_SIZE];
static uint8_t max_ip_count = 0;
void GetCurNetInfo()
{
uint8_t idx = 0;
for (; idx < MAX_IP_SIZE; idx++)
{
ip_int_names[idx] = ip_addr_strs[idx] = ip_hardwares[idx] = ip_masks[idx] = NULL;
}
idx = 0;
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces))
{
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next)
{
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ )//ignore ipv6
{
continue;
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
if(addr && (addr->sin_family==AF_INET /*|| addr->sin_family==AF_INET6*/))
{
char *name = interface->ifa_name;
char *netmask = inet_ntoa(((struct sockaddr_in*)interface->ifa_netmask)->sin_addr);
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN))
{
printf("netmask = %s name = %s ip = %s \n" , netmask, name, addrBuf);
ip_int_names[idx] = (char*)malloc(strlen(name) + 1);
ip_addr_strs[idx] = (char*)malloc(strlen(addrBuf) + 1);
ip_masks[idx] = (char*)malloc(strlen(netmask) + 1);
if(NULL == ip_int_names[idx] || NULL == ip_addr_strs[idx] || NULL == ip_masks[idx])
{
return;
}
strcpy(ip_int_names[idx], name);
strcpy(ip_addr_strs[idx], addrBuf);
strcpy(ip_masks[idx], netmask);
idx++;
}
}
}
max_ip_count = idx;
freeifaddrs(interfaces);
}
}
void GetHWAddresses()
{
struct ifconf ifc;
struct ifreq *ifr;
int sockfd;
char buffer[MAX_BUFFER_SIZE], *cp, *cplim;
char temp[80];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket failed");
return;
}
ifc.ifc_len = MAX_BUFFER_SIZE;
ifc.ifc_buf = buffer;
if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0)
{
perror("ioctl error");
close(sockfd);
return;
}
ifr = ifc.ifc_req;
cplim = buffer + ifc.ifc_len;
for (cp=buffer; cp < cplim; )
{
ifr = (struct ifreq *)cp;
if (ifr->ifr_addr.sa_family == AF_LINK)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
int a,b,c,d,e,f;
int i;
strcpy(temp, (char *)ether_ntoa((const struct ether_addr *)LLADDR(sdl)));
sscanf(temp, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
sprintf(temp, "%02X:%02X:%02X:%02X:%02X:%02X",a,b,c,d,e,f);
for (i=0; i<max_ip_count; ++i)
{
if ((ip_int_names[i] != NULL) && (strcmp(ifr->ifr_name, ip_int_names[i]) == 0))
{
if (ip_hardwares[i] == NULL)
{
ip_hardwares[i] = (char *)malloc(strlen(temp)+1);
strcpy(ip_hardwares[i], temp);
printf("hdaddr = %s ipaddr = %s name = %s \n", ip_hardwares[i], ip_addr_strs[i], ip_int_names[i]);
break;
}
}
}
}
cp += sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len);
}
close(sockfd);
}
//计算当前可用的广播地址
//先用mask&ip得到ip地址
const char* calculate_broadcast_ip(const char* ip_addr, const char* mask_addr)
{
printf("ipaddr = %s mask = %s \n", ip_addr, mask_addr);
struct in_addr ip;
struct in_addr mask;
if(0 == inet_aton(ip_addr, &ip))
{
return NULL;
}
if(0 == inet_aton(mask_addr, &mask))
{
return NULL;
}
ip.s_addr = ip.s_addr & mask.s_addr;
printf("net ip addr = %s \n", inet_ntoa(ip));
mask.s_addr = (mask.s_addr ^ 0xFFFFFFFF);
printf("mask ip ^ = %s", inet_ntoa(mask));
ip.s_addr = ip.s_addr | mask.s_addr;
printf("broadcast ip addr = %s \n", inet_ntoa(ip));
return inet_ntoa(ip);
}
void GetTargetIpInfo()
{
uint8_t idx = 0;
for (; idx < max_ip_count; idx++)
{
if(0 == strcmp(ip_hardwares[idx], TARGET_HAED_ADDR))
{
calculate_broadcast_ip(ip_addr_strs[idx], ip_masks[idx]);
}
}
}
#ifdef __cplusplus
extern "C"{
#endif
void PrintCurNetInfo()
{
GetCurNetInfo();
GetHWAddresses();
GetTargetIpInfo();
}
#ifdef __cplusplus
}
#endif