如果 IPv6 或某些虛擬介面可用,則以下代碼不再適用于 macOS。
我總是得到錯誤 getnameinfo() failed: Unknown error (ai_family not supported)
知道這有什么問題嗎?我只需要一個帶有 ipv4 和互聯網的正確網路介面。
該問題首先出現在 macOS Sierra 上。
#include "jni.h"
#include "bla_nativeclasses_JNISubNetMask.h"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
static jobjectArray make_row(JNIEnv *env, jsize count, const char* elements[])
{
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
jobjectArray row = (*env)->NewObjectArray(env, count, stringClass, 0);
jsize i;
for (i = 0; i < count; i) {
(*env)->SetObjectArrayElement(env, row, i, (*env)->NewStringUTF(env, elements[i]));
}
return row;
}
JNIEXPORT jobjectArray JNICALL Java_bla_JNISubNetMask_getSubNetMask(JNIEnv *env, jobject jobj){
struct ifaddrs *ifaddr, *ifa;
int family, s ,s2;
int i = 0;
int count = 0;
char host[NI_MAXHOST];
char subnet[NI_MAXHOST];
char *tmp = NULL;
const char* net[1000];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* Walk through linked list, maintaining head pointer so we can free list later */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
s2 = getnameinfo(ifa->ifa_netmask, sizeof(struct sockaddr_in), subnet, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0 || s2 != 0) {
printf("getnameinfo() failed: %s (%s)\n", gai_strerror(s), gai_strerror(s2));
exit(EXIT_FAILURE);
}
tmp = (char *)malloc(100*sizeof(char));
strcpy (tmp,ifa->ifa_name);
net[i ] = tmp;
tmp = (char *)malloc(100*sizeof(char));
strcpy (tmp,host);
net[i ] = tmp;
tmp = (char *)malloc(100*sizeof(char));
strcpy (tmp,subnet);
net[i ] = tmp;
}
freeifaddrs(ifaddr);
count = i;
jobjectArray jnet = make_row(env, count, net);
return jnet;
}
我知道已經有另一個類似的問題,但我不太明白答案
uj5u.com熱心網友回復:
出現問題是因為 IPV4 和 IPV6 的大小不同。考慮以下兩行代碼
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
s2 = getnameinfo(ifa->ifa_netmask, sizeof(struct sockaddr_in), subnet, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
如果地址 family 是AF_INET,sizeof操作將適用于您的代碼,但對于 IPV6 aka AF_INET6您必須使用sizeof(sockaddr_in6); ,它們都有不同的大小(分別為 4 和 6 位元組)。
你可以做的是以下 -
int len;
switch (fa->ifa_addr->sa_family) {
case AF_INET:
len = sizeof(sockaddr_in);
break;
case AF_INET6:
len= sizeof(sockaddr_in6);
break;
default:
std::cerr << "Unknown Address family\n";
break;
}
然后使用您呼叫getnameinfo的長度。
編輯
@leo_poldX,似乎是因為if (ifa->ifa_addr->sa_family != AF_INET) continue; ,其余代碼不應針對 IPV6 執行。你能檢查它是否正確嗎?
uj5u.com熱心網友回復:
我總是收到錯誤 getnameinfo() failed: Unknown error (ai_family not supported)
根據您的代碼中該訊息的來源,很明顯它是由以下情況引起的
s2 = getnameinfo(ifa->ifa_netmask, sizeof(struct sockaddr_in), subnet, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
失敗并出現錯誤代碼EAI_FAMILY,即使前面的
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
成功了。根據特定的錯誤代碼,失敗可能是ifa->ifa_netmask->ai_family由于設定為不同于 的值AF_INET,要么
- 一個不同的已知家族,其地址需要更大的地址結構,或
- 一個無效/未知的家庭。
我可以想象其中任何一種可能出現的方式,但無論哪種方式,我都會將其描述為一個錯誤,因為它getifaddrs()會回傳地址和網路掩碼來自不同地址系列的任何條目。
合理的緩解措施取決于問題的具體性質。例如,
- 如果整個條目根本無效,那么您應該檢測到并跳過它。
- 如果網路掩碼資料采用 IPv4 地址的形式,但系統未能 [正確] 設定族,那么您可以嘗試檢測這種情況并在呼叫
getnameinfo(). - 如果網路掩碼采用 IPv6 地址的形式,那么您可以檢測到它并將其讀取為 IPv6 地址,并找出從那里去哪里。結果可能是編碼為 IPv6 地址的 IPv4 地址,在這種情況下,您可以從后者中提取前者。
- 如果您可以不使用子網掩碼,那么您可以在這種情況下將其虛擬化,或者甚至將其從方法結果中完全洗掉。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/412097.html
標籤:
