// 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;
}
