getifaddrs源码
时间: 2023-07-27 20:06:20 浏览: 63
以下是getifaddrs函数的源码实现,它定义在头文件<ifaddrs.h>中:
```c
#include <sys/socket.h>
#include <ifaddrs.h>
int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union {
struct sockaddr *ifu_broadaddr;
struct sockaddr *ifu_dstaddr;
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};
```
getifaddrs函数返回系统中所有网络接口的基本信息,包括接口名称、地址和标志等。它的参数ifap是一个指向ifaddrs结构体链表的指针,函数将通过该指针返回结果。freeifaddrs函数用于释放该链表。
以下是getifaddrs函数的具体实现:
```c
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <ifaddrs.h>
int getifaddrs(struct ifaddrs **ifap)
{
int fd, err, n;
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
return -1;
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
close(fd);
return -1;
}
*ifap = NULL;
for (n = 0; n < ifc.ifc_len; ) {
struct ifaddrs *ifa;
struct sockaddr_in *sin;
ifr = ((struct ifreq *)(ifc.ifc_buf + n))->ifr_name;
n += sizeof(ifr);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
err = errno;
close(fd);
return err;
}
if ((ifr.ifr_flags & IFF_UP) == 0)
continue;
ifa = malloc(sizeof(struct ifaddrs));
if (ifa == NULL) {
close(fd);
return -1;
}
memset(ifa, 0, sizeof(struct ifaddrs));
ifa->ifa_flags = ifr.ifr_flags;
ifa->ifa_name = strdup(ifr.ifr_name);
sin = (struct sockaddr_in *)&ifr.ifr_addr;
memcpy(&ifa->ifa_addr, sin, sizeof(struct sockaddr));
if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) {
err = errno;
freeifaddrs(ifa);
close(fd);
return err;
}
sin = (struct sockaddr_in *)&ifr.ifr_addr;
memcpy(&ifa->ifa_netmask, sin, sizeof(struct sockaddr));
if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) {
if (ifr.ifr_flags & IFF_POINTOPOINT) {
memcpy(&ifa->ifa_dstaddr, sin, sizeof(struct sockaddr));
}
} else {
sin = (struct sockaddr_in *)&ifr.ifr_addr;
memcpy(&ifa->ifa_broadaddr, sin, sizeof(struct sockaddr));
}
if ((*ifap) != NULL) {
ifa->ifa_next = (*ifap);
}
*ifap = ifa;
}
close(fd);
return 0;
}
void freeifaddrs(struct ifaddrs *ifa)
{
if (ifa == NULL)
return;
freeifaddrs(ifa->ifa_next);
free(ifa->ifa_name);
free(ifa);
}
```