以下是 make_ioa_addr
函数的详细注释,旨在解释每个部分的功能和逻辑。
/**
* @brief 将给定的地址字符串和端口转换为 ioa_addr 结构体。
*
* @param saddr0 输入的地址字符串(可以是 IPv4 或 IPv6 格式)。
* @param port 要绑定或连接的端口号。
* @param addr 指向要填充的 ioa_addr 结构体指针。
*
* @return 成功时返回 0;失败时返回 -1。
*/
int make_ioa_addr(const uint8_t *saddr0, int port, ioa_addr *addr) {
// 检查输入参数是否有效
if (!saddr0 || !addr) {
return -1; // 参数无效,返回错误
}
char ssaddr[257]; // 存储输入地址字符串的缓冲区
STRCPY(ssaddr, saddr0); // 将输入地址复制到缓冲区
char *saddr = ssaddr;
// 跳过前导空格
while (*saddr == ' ') {
++saddr;
}
size_t len = strlen(saddr);
// 移除末尾空格
while (len > 0) {
if (saddr[len - 1] == ' ') {
saddr[len - 1] = 0; // 替换为空字符以结束字符串
--len;
} else {
break;
}
}
memset(addr, 0, sizeof(ioa_addr)); // 清空 addr 的内容
// 尝试将地址解析为 IPv4 地址
if ((len == 0) || (inet_pton(AF_INET, saddr, &addr->s4.sin_addr) == 1)) {
addr->s4.sin_family = AF_INET; // 设置地址族为 IPv4
#if defined(TURN_HAS_SIN_LEN)
addr->s4.sin_len = sizeof(struct sockaddr_in); // 如果有需要,设置长度字段
#endif
addr->s4.sin_port = nswap16(port); // 设置端口(网络字节序)
} else if (inet_pton(AF_INET6, saddr, &addr->s6.sin6_addr) == 1) {
// 尝试将地址解析为 IPv6 地址
addr->s6.sin6_family = AF_INET6;
#if defined(SIN6_LEN)
addr->s6.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr->s6.sin6_port = nswap16(port);
} else {
struct addrinfo addr_hints;
struct addrinfo *addr_result = NULL;
int err;
memset(&addr_hints, 0, sizeof(struct addrinfo));
addr_hints.ai_family = AF_UNSPEC; /* 支持 IPv4 或 IPv6 */
addr_hints.ai_socktype = SOCK_DGRAM; /* 数据报套接字 */
addr_hints.ai_flags = AI_PASSIVE; /* 用于通配符 IP 地址 */
/* 获取与主机名相关的信息 */
err = getaddrinfo(saddr, NULL, &addr_hints, &addr_result);
if ((err != 0) || (!addr_result)) {
fprintf(stderr, "error resolving '%s' hostname: %s\n", saddr, gai_strerror(err));
return -1;
}
int family = AF_INET; /* 默认使用 IPv4 */
struct addrinfo *addr_result_orig = addr_result;
int found = 0;
beg_af:
while (addr_result) {
if (addr_result->ai_family == family) {
if (family == AF_INET) {
memcpy(addr, addr_result->ai_addr, addr_result->ai_addrlen);
addr->s4.sin_port = nswap16(port);
#if defined(TURN_HAS_SIN_LEN)
addr->s4.sin_len = sizeof(struct sockaddr_in);
#endif
found=1;
break;
} else if (family == AF_INET6) {
memcpy(addr, addr_result->ai_addr, addr_result->ai_addrlen);
addr->s6.sin6_port=nswap16(port);
#if defined(SIN6_LEN)
addr->s6.sin6_len=sizeof(struct sockaddr_in6);
#endif
found=1;
break;
}
}
addressResult=addressResult→ ai_next ;
}
if (!found && family==AF_INET){
family=AF_INET six ; /* 切换到IPv六*/
addressResult=addressResultOrig ;
goto beg_af ; /* 循环进行处理*/
}
freeAddrInfo(addrResultOrig ); /*释放获得的信息*/
}
return 0 ; /*成功*/
}
注释总结:
- 函数作用: 将传入的字符串形式的IP地址和端口号转换成
ioa_addr
类型的数据结构,以便后续网络操作使用。 - 输入检查: 确保输入不为空,以避免潜在的问题。
- 清理和标准化输入: 去除前后空白字符,以确保格式正确。
- 协议处理: 首先尝试解析为IPv4,然后是IPv6,如果都失败则使用
getaddrinfo
来支持主机名解析。 - 内存管理: 使用
freeAddrInfo
来释放通过getAddrInfo
分配的信息。
如果您有特定问题或者想深入了解某一部分,请告诉我!
内容由零声教学AI助手提供,问题来源于学员提问