getifaddrs fix

This commit is contained in:
Caten
2023-11-10 21:29:07 +08:00
parent cf8ce47662
commit 6dbe710fdc
10 changed files with 692 additions and 138 deletions

View File

@@ -0,0 +1,222 @@
// getifaddrs_bridge_server.c -- This file is part of tiny_computer.
// Copyright (C) 2023 Caten Hu
// Tiny Computer is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or any later version.
// Tiny Computer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
/* this file is mainly generated by Bing */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/un.h>
#define BUFSIZE 1024 // 定义缓冲区大小
// 定义一个序列化函数将ifaddrs结构体转换为字节数组
int serialize_ifaddrs(struct ifaddrs *ifa, char *buf, int size) {
int len = 0; // 记录已经写入的字节数
while (ifa != NULL && len < size) {
// 写入接口名称
int namelen = strlen(ifa->ifa_name) + 1; // 包括结束符
if (len + namelen > size) break; // 缓冲区不足
memcpy(buf + len, ifa->ifa_name, namelen);
len += namelen;
// 写入接口标志
if (len + sizeof(unsigned int) > size) break; // 缓冲区不足
memcpy(buf + len, &ifa->ifa_flags, sizeof(unsigned int));
len += sizeof(unsigned int);
// 写入接口地址
if (ifa->ifa_addr != NULL) {
int addrlen = sizeof(struct sockaddr); // 地址结构体长度
if (len + addrlen > size) break; // 缓冲区不足
memcpy(buf + len, ifa->ifa_addr, addrlen);
len += addrlen;
} else {
// 如果没有地址,写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
}
// 写入接口掩码
if (ifa->ifa_netmask != NULL) {
int masklen = sizeof(struct sockaddr); // 掩码结构体长度
if (len + masklen > size) break; // 缓冲区不足
memcpy(buf + len, ifa->ifa_netmask, masklen);
len += masklen;
} else {
// 如果没有掩码,写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
}
// 写入接口广播地址或点对点地址
if (ifa->ifa_flags & IFF_BROADCAST) {
// 如果有广播地址
if (ifa->ifa_broadaddr != NULL) {
int broadlen = sizeof(struct sockaddr); // 广播地址结构体长度
if (len + broadlen > size) break; // 缓冲区不足
memcpy(buf + len, ifa->ifa_broadaddr, broadlen);
len += broadlen;
} else {
// 如果没有广播地址,写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
}
} else if (ifa->ifa_flags & IFF_POINTOPOINT) {
// 如果有点对点地址
if (ifa->ifa_dstaddr != NULL) {
int dstlen = sizeof(struct sockaddr); // 点对点地址结构体长度
if (len + dstlen > size) break; // 缓冲区不足
memcpy(buf + len, ifa->ifa_dstaddr, dstlen);
len += dstlen;
} else {
// 如果没有点对点地址,写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
}
} else {
// 如果没有广播地址或点对点地址,写入两个空字节
if (len + 2 > size) break; // 缓冲区不足
buf[len] = '\0';
buf[len + 1] = '\0';
len += 2;
}
// 写入接口数据
if (ifa->ifa_data != NULL) {
// TODO: 根据不同的地址族,写入不同的数据
// 这里暂时省略,只写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
} else {
// 如果没有数据,写入一个空字节
if (len + 1 > size) break; // 缓冲区不足
buf[len] = '\0';
len += 1;
}
// 跳到下一个接口
ifa = ifa->ifa_next;
}
return len; // 返回写入的总字节数
}
// 定义一个接收信号的函数,从客户端接收一个信号
int receive_signal(int sockfd) {
char sig; // 定义信号变量
int n = read(sockfd, &sig, 1); // 从套接字读取一个字节
if (n < 0) {
perror("read");
return -1; // 返回错误
}
if (sig == 'S') {
// 如果收到信号S表示客户端需要数据
return 0; // 返回成功
} else {
// 如果收到其他信号,表示无效信号
fprintf(stderr, "invalid signal: %c\n", sig);
return -1; // 返回错误
}
}
// 定义一个发送数据的函数,向客户端发送数据并序列化
int send_data(int sockfd) {
struct ifaddrs *ifap = NULL; // 定义ifaddrs结构体指针
// 调用getifaddrs函数获取本地接口信息
if (getifaddrs(&ifap) < 0) {
perror("getifaddrs");
return -1; // 返回错误
}
char buf[BUFSIZE]; // 定义缓冲区
// 调用序列化函数将ifaddrs结构体转换为字节数组
int len = serialize_ifaddrs(ifap, buf, BUFSIZE);
if (len < 0) {
fprintf(stderr, "serialize_ifaddrs failed\n");
return -1; // 返回错误
}
// 向套接字写入数据
int n = write(sockfd, buf, len);
if (n < 0) {
perror("write");
return -1; // 返回错误
}
// 释放ifaddrs结构体
freeifaddrs(ifap);
return 0; // 返回成功
}
// 主函数
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("usage: %s <socket_path>\n", argv[0]);
return 0;
}
// 创建一个套接字
int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
// 定义服务器地址结构体
struct sockaddr_un un;
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
snprintf(un.sun_path, sizeof(un.sun_path), "%s", argv[1]);
unlink(un.sun_path);
// 绑定套接字到服务器地址
if (bind(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) {
perror("bind");
exit(1);
}
// 监听套接字
if (listen(sockfd, 5) < 0) {
perror("listen");
exit(1);
}
// 循环接受客户端连接
while (1) {
int connfd = accept(sockfd, NULL, NULL);
if (connfd < 0) {
perror("accept");
continue; // 如果接受失败,继续循环
}
// 循环接收和发送数据
while (1) {
// 接收信号
if (receive_signal(connfd) < 0) {
fprintf(stderr, "receive_signal failed\n");
close(connfd); // 如果接收失败,关闭连接套接字
break; // 跳出循环
}
// 发送数据
if (send_data(connfd) < 0) {
fprintf(stderr, "send_data failed\n");
close(connfd); // 如果发送失败,关闭连接套接字
break; // 跳出循环
}
}
}
// 关闭监听套接字
close(sockfd);
return 0;
}