#include "arp_scanner.h" #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 <net/if.h> #include <sys/ioctl.h> #include <linux/if_packet.h> #include <time.h> #include <errno.h> #include "json_api.h" // 加载配置 int load_config(arp_config_t *config) { if (config == NULL) { fprintf(stderr, "错误: 配置指针为空\n"); return -1; } // 使用ds_read读取配置 ds_read(ARPD_CONFIG_PATH, config, sizeof(arp_config_t)); return 0; } S32 arp_scanner_init() { memset(&g_scanner, 0, sizeof(arp_scanner_t)); // 创建原始套接字 g_scanner.raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if (g_scanner.raw_socket < 0) { perror("socket"); return -1; } // 初始化互斥锁 if (pthread_mutex_init(&g_scanner.lock, NULL) != 0) { close(g_scanner.raw_socket); return -1; } // 从配置文件加载配置 if (load_config(&g_scanner.config) != 0) { // 加载失败时使用默认值 g_scanner.config.enabled = FALSE; g_scanner.config.scan_interval = 60; g_scanner.config.validity_period = 300; g_scanner.config.packet_interval = 100; g_scanner.config.start_ip = ip_to_int("192.168.1.100"); g_scanner.config.end_ip = ip_to_int("192.168.1.200"); // 默认网络接口 strcpy(g_scanner.config.interface, "eth0"); fprintf(stderr, "Using default configuration\n"); } return 0; } S32 arp_scanner_start(void) { pthread_mutex_lock(&g_scanner.lock); g_scanner.scanning = TRUE; g_scanner.stop_requested = FALSE; pthread_mutex_unlock(&g_scanner.lock); return 0; } int arp_scanner_stop(void) { pthread_mutex_lock(&g_scanner.lock); g_scanner.stop_requested = TRUE; pthread_mutex_unlock(&g_scanner.lock); return 0; } int arp_scanner_cleanup(void) { arp_scanner_stop(); if (g_scanner.raw_socket >= 0) { close(g_scanner.raw_socket); } pthread_mutex_destroy(&g_scanner.lock); return 0; } int arp_scanner_scan(void) { if (!g_scanner.config.enabled) return -1; struct ifreq ifr; strcpy(ifr.ifr_name, g_scanner.config.interface); // 获取接口索引 if (ioctl(g_scanner.raw_socket, SIOCGIFINDEX, &ifr) < 0) { perror("ioctl"); return -1; } // 绑定到接口 struct sockaddr_ll saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sll_family = AF_PACKET; saddr.sll_ifindex = ifr.ifr_ifindex; saddr.sll_protocol = htons(ETH_P_ARP); if (bind(g_scanner.raw_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); return -1; } // 发送ARP请求 for (uint32_t ip = g_scanner.config.start_ip; ip <= g_scanner.config.end_ip && !g_scanner.stop_requested; ip++) { arp_scanner_send_arp_request(ip); usleep(g_scanner.config.packet_interval * 1000); } // 处理ARP回复 arp_scanner_process_reply(); // 清理过期条目 arp_scanner_clean_old_entries(); g_scanner.last_scan_time = time(NULL); return 0; } int arp_scanner_send_arp_request(uint32_t target_ip) { struct ifreq ifr; strcpy(ifr.ifr_name, g_scanner.config.interface); // 获取接口MAC地址 if (ioctl(g_scanner.raw_socket, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl"); return -1; } unsigned char *src_mac = (unsigned char *)ifr.ifr_hwaddr.sa_data; // 获取接口IP地址 if (ioctl(g_scanner.raw_socket, SIOCGIFADDR, &ifr) < 0) { perror("ioctl"); return -1; } struct sockaddr_in *ipaddr = (struct sockaddr_in *)&ifr.ifr_addr; uint32_t src_ip = ipaddr->sin_addr.s_addr; // 构建ARP请求包 arp_packet_t packet; // 以太网头部 memset(packet.eth_header.h_dest, 0xFF, 6); // 广播地址 memcpy(packet.eth_header.h_source, src_mac, 6); packet.eth_header.h_proto = htons(ETH_P_ARP); // ARP头部 packet.arp_header.ar_hrd = htons(ARPHRD_ETHER); packet.arp_header.ar_pro = htons(ETH_P_IP); packet.arp_header.ar_hln = 6; packet.arp_header.ar_pln = 4; packet.arp_header.ar_op = htons(ARPOP_REQUEST); memcpy(packet.sender_mac, src_mac, 6); memcpy(packet.sender_ip, &src_ip, 4); memset(packet.target_mac, 0, 6); memcpy(packet.target_ip, &target_ip, 4); // 发送包 struct sockaddr_ll dest; memset(&dest, 0, sizeof(dest)); dest.sll_family = AF_PACKET; dest.sll_ifindex = ifr.ifr_ifindex; dest.sll_halen = ETH_ALEN; memset(dest.sll_addr, 0xFF, ETH_ALEN); ssize_t sent = sendto(g_scanner.raw_socket, &packet, sizeof(packet), 0, (struct sockaddr *)&dest, sizeof(dest)); return (sent == sizeof(packet)) ? 0 : -1; } int arp_scanner_process_reply(void) { fd_set readfds; struct timeval tv; int ret; int max_fd = g_scanner.raw_socket; // 设置超时时间为2秒,用于等待ARP回复 tv.tv_sec = 2; tv.tv_usec = 0; // 循环处理所有可用的ARP回复 while (1) { FD_ZERO(&readfds); FD_SET(g_scanner.raw_socket, &readfds); ret = select(max_fd + 1, &readfds, NULL, NULL, &tv); if (ret < 0) { if (errno == EINTR) { // 被信号中断,继续等待 continue; } perror("select"); break; } else if (ret == 0) { // 超时,没有更多数据 break; } if (FD_ISSET(g_scanner.raw_socket, &readfds)) { arp_packet_t packet; struct sockaddr_ll saddr; socklen_t saddr_len = sizeof(saddr); // 接收ARP数据包 ssize_t received = recvfrom(g_scanner.raw_socket, &packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &saddr_len); if (received < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { continue; } perror("recvfrom"); continue; } // 检查接收到的数据包长度 if (received < (ssize_t)(sizeof(struct ethhdr) + sizeof(struct arphdr))) { // 数据包太短,不是有效的ARP包 continue; } // 验证以太网类型是否为ARP if (ntohs(packet.eth_header.h_proto) != ETH_P_ARP) { continue; } // 验证ARP硬件类型为以太网 if (ntohs(packet.arp_header.ar_hrd) != ARPHRD_ETHER) { continue; } // 验证ARP协议类型为IP if (ntohs(packet.arp_header.ar_pro) != ETH_P_IP) { continue; } // 检查是否是ARP回复 if (ntohs(packet.arp_header.ar_op) == ARPOP_REPLY) { // 提取发送者IP和MAC地址 uint32_t sender_ip; memcpy(&sender_ip, packet.sender_ip, 4); char mac_str[MAX_MAC_LEN]; mac_to_string(packet.sender_mac, mac_str); // 检查IP是否在扫描范围内 if (sender_ip >= g_scanner.config.start_ip && sender_ip <= g_scanner.config.end_ip) { // 添加到ARP条目表 arp_scanner_add_entry(sender_ip, mac_str); // 打印调试信息 char ip_str[MAX_IP_LEN]; int_to_ip(sender_ip, ip_str); printf("Received ARP reply from %s [%s]\n", ip_str, mac_str); } } } } return 0; } int arp_scanner_add_entry(uint32_t ip, const char *mac) { if (!mac) { return -1; } pthread_mutex_lock(&g_scanner.lock); time_t now = time(NULL); int found_index = -1; BOOL is_new_host = FALSE; // 检查是否已存在该IP的条目 for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].ip == ip) { found_index = i; break; } } if (found_index >= 0) { // 更新现有条目 strncpy(g_scanner.entries[found_index].mac, mac, MAX_MAC_LEN - 1); g_scanner.entries[found_index].mac[MAX_MAC_LEN - 1] = '\0'; g_scanner.entries[found_index].last_seen = now; } else { // 添加新条目 if (g_scanner.entry_count < MAX_ARP_ENTRIES) { arp_entry_t *entry = &g_scanner.entries[g_scanner.entry_count]; entry->ip = ip; strncpy(entry->mac, mac, MAX_MAC_LEN - 1); entry->mac[MAX_MAC_LEN - 1] = '\0'; entry->last_seen = now; entry->first_seen = now; g_scanner.entry_count++; is_new_host = TRUE; } else { // ARP表已满,找到最旧的条目替换 time_t oldest_time = now; int oldest_index = 0; for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].last_seen < oldest_time) { oldest_time = g_scanner.entries[i].last_seen; oldest_index = i; } } // 替换最旧的条目 arp_entry_t *entry = &g_scanner.entries[oldest_index]; entry->ip = ip; strncpy(entry->mac, mac, MAX_MAC_LEN - 1); entry->mac[MAX_MAC_LEN - 1] = '\0'; entry->last_seen = now; entry->first_seen = now; is_new_host = TRUE; } } pthread_mutex_unlock(&g_scanner.lock); // 如果是新发现的主机,打印到串口 if (is_new_host) { char ip_str[MAX_IP_LEN]; int_to_ip(ip, ip_str); printf("NEW HOST: IP=%s, MAC=%s\n", ip_str, mac); } return 0; } void arp_scanner_clean_old_entries(void) { pthread_mutex_lock(&g_scanner.lock); time_t now = time(NULL); int write_index = 0; for (int read_index = 0; read_index < g_scanner.entry_count; read_index++) { if (now - g_scanner.entries[read_index].last_seen <= g_scanner.config.validity_period) { // 条目未过期,保留 if (write_index != read_index) { g_scanner.entries[write_index] = g_scanner.entries[read_index]; } write_index++; } else { // 条目过期,打印日志 char ip_str[MAX_IP_LEN]; int_to_ip(g_scanner.entries[read_index].ip, ip_str); printf("EXPIRED: IP=%s, MAC=%s\n", ip_str, g_scanner.entries[read_index].mac); } } // 更新条目计数 int expired_count = g_scanner.entry_count - write_index; g_scanner.entry_count = write_index; pthread_mutex_unlock(&g_scanner.lock); if (expired_count > 0) { printf("Cleaned %d expired ARP entries\n", expired_count); } } int arp_scanner_remove_entry(uint32_t ip) { pthread_mutex_lock(&g_scanner.lock); int found_index = -1; // 查找要删除的条目 for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].ip == ip) { found_index = i; break; } } if (found_index >= 0) { // 移动后续条目覆盖要删除的条目 for (int i = found_index; i < g_scanner.entry_count - 1; i++) { g_scanner.entries[i] = g_scanner.entries[i + 1]; } g_scanner.entry_count--; char ip_str[MAX_IP_LEN]; int_to_ip(ip, ip_str); printf("Removed ARP entry: %s\n", ip_str); } pthread_mutex_unlock(&g_scanner.lock); return (found_index >= 0) ? 0 : -1; } // 工具函数 uint32_t ip_to_int(const char *ip) { if (!ip) { return 0; } struct in_addr addr; if (inet_pton(AF_INET, ip, &addr) != 1) { fprintf(stderr, "Invalid IP address: %s\n", ip); return 0; } return addr.s_addr; } void int_to_ip(uint32_t ip_int, char *ip_str) { if (!ip_str) { return; } struct in_addr addr; addr.s_addr = ip_int; inet_ntop(AF_INET, &addr, ip_str, MAX_IP_LEN); } void mac_to_string(const unsigned char *mac, char *mac_str) { if (!mac || !mac_str) { return; } snprintf(mac_str, MAX_MAC_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } 将上述文件的函数封装到int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param) { // 创建响应JSON对象 context->res_obj = jso_new_obj(); if (NULL == context->res_obj) { DS_ERROR("Create new json object failed."); context->error_code = SLP_ESYSTEM; return ERROR; } // 关键修改:启动前先执行初始化 int init_result = arp_scanner_init(); if (init_result != 0) { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Scanner initialization failed"); return ERROR; } // 启动扫描 int start_result = arp_scanner_start(); if (start_result == 0) { jso_add_string(context->res_obj, "status", "success"); jso_add_string(context->res_obj, "message", "Scan started successfully"); // 添加扫描配置信息 pthread_mutex_lock(&g_scanner.lock); jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled); jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval); jso_add_int(context->res_obj, "validity_period", g_scanner.config.validity_period); char start_ip_str[MAX_IP_LEN], end_ip_str[MAX_IP_LEN]; int_to_ip(g_scanner.config.start_ip, start_ip_str); int_to_ip(g_scanner.config.end_ip, end_ip_str); jso_add_string(context->res_obj, "start_ip", start_ip_str); jso_add_string(context->res_obj, "end_ip", end_ip_str); jso_add_string(context->res_obj, "interface", g_scanner.config.interface); pthread_mutex_unlock(&g_scanner.lock); } else { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Failed to start scan"); } return start_result; } // 停止扫描 // 停止扫描 int arpd_stop_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param) { // 创建响应JSON对象 context->res_obj = jso_new_obj(); if (NULL == context->res_obj) { DS_ERROR("Create new json object failed."); context->error_code = SLP_ESYSTEM; return ERROR; } // 获取当前扫描状态 pthread_mutex_lock(&g_scanner.lock); BOOL was_scanning = g_scanner.scanning; int entry_count = g_scanner.entry_count; time_t last_scan_time = g_scanner.last_scan_time; pthread_mutex_unlock(&g_scanner.lock); // 执行停止操作 int stop_result = arp_scanner_stop(); // 构建响应 if (stop_result == 0) { jso_add_string(context->res_obj, "status", "success"); jso_add_string(context->res_obj, "action", was_scanning ? "Scan stopped" : "No active scan to stop"); // 添加扫描结果统计 jso_add_bool(context->res_obj, "was_scanning", was_scanning); jso_add_int(context->res_obj, "entry_count", entry_count); // 添加时间信息 char last_scan_str[32]; if (last_scan_time > 0) { format_timestamp(last_scan_time, last_scan_str); jso_add_string(context->res_obj, "last_scan_time", last_scan_str); } else { jso_add_string(context->res_obj, "last_scan_time", "Never scanned"); } // 添加配置信息 pthread_mutex_lock(&g_scanner.lock); jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled); jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval); pthread_mutex_unlock(&g_scanner.lock); } else { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Failed to stop scan"); jso_add_int(context->res_obj, "error_code", stop_result); } return stop_result; }中,arpd_start_scan需要真正实现启动扫描并扫描的过程
时间: 2025-08-28 22:57:57 AIGC 浏览: 35
<think>我们需要在arpd_start_scan函数中真正启动扫描过程。根据之前的代码,扫描过程是在arp_scanner_scan函数中实现的,而arp_scanner_start函数只是设置了一些标志位,并没有真正执行扫描。
因此,我们需要在arpd_start_scan中调用arp_scanner_scan函数来执行扫描。但是,由于扫描过程可能会持续一段时间,我们不应该在HTTP请求处理线程中直接执行扫描(这会导致请求超时)。
正确的做法是:在arp_scanner_start中创建线程,然后在新的线程中执行扫描。这样,arpd_start_scan在调用arp_scanner_start后可以立即返回,而扫描任务在后台运行。
然而,观察现有的arp_scanner_start函数,它只是设置了标志位,并没有启动线程。而扫描函数arp_scanner_scan是一个阻塞函数,会执行整个扫描过程。
因此,我们需要重构:
1. 修改arp_scanner_start函数,使其创建一个线程,然后在该线程中调用arp_scanner_scan函数。
2. 确保arp_scanner_scan函数能够响应停止请求(通过g_scanner.stop_requested)。
但是,在现有的代码中,arp_scanner_scan函数已经包含了发送ARP请求和接收回复的过程,并且会检查g_scanner.stop_requested。所以,我们只需要将arp_scanner_scan放在一个线程中执行即可。
修改步骤:
1. 在arp_scanner_start中创建线程,线程函数为arp_scanner_scan_thread(我们新写一个函数,它内部调用arp_scanner_scan)。
2. 修改arp_scanner_scan函数,使其能够作为线程函数运行(目前它返回int,需要改为返回void*,并接受void*参数)。
3. 在arp_scanner_scan_thread中调用arp_scanner_scan,然后返回。
但是,由于arp_scanner_scan函数目前是阻塞执行整个扫描,我们也可以不改变它的返回值,而是用一个静态函数来包装。
另外,注意在arpd_start_scan中,我们调用了arp_scanner_init,这可能会重复初始化(因为init中创建了原始套接字和互斥锁)。我们需要考虑模块的初始化状态,避免重复初始化。
因此,我们还需要:
1. 在全局扫描器结构体中添加一个初始化标志,避免重复初始化。
2. 修改arp_scanner_init,使其在已经初始化的情况下直接返回成功。
考虑到时间,我们做如下调整:
方案A:不在arpd_start_scan中调用arp_scanner_init,而是要求模块在启动时已经初始化(比如在模块加载时初始化一次)。这样,arpd_start_scan只负责启动扫描。
方案B:在arpd_start_scan中检查是否初始化,如果没有则初始化。
根据现有代码,arp_scanner_init每次调用都会重新初始化g_scanner(包括创建原始套接字和互斥锁)。如果多次调用,会导致之前创建的套接字被关闭(因为重新memset为0,然后重新创建套接字,旧的套接字会泄漏),并且互斥锁也会被重新初始化(可能导致未定义行为)。
因此,我们需要一个全局的初始化标志,或者将初始化分为两部分:首次初始化和重复调用的处理。
这里,我们添加一个静态变量来记录初始化状态,或者修改g_scanner结构体,加入一个init_flag。
由于g_scanner是全局变量,我们可以在其中添加一个成员:
BOOL initialized;
然后在arp_scanner_init中:
if (g_scanner.initialized) {
return 0;
}
... 进行初始化 ...
g_scanner.initialized = TRUE;
但是,我们目前的结构体定义中没有这个成员,所以需要修改结构体。
但是,由于问题要求封装到arpd_start_scan,并且不能改变已有结构体(题目没有说明是否可以改变),我们假设可以修改结构体。
如果无法修改结构体,我们可以使用一个静态变量。
这里,我们假设可以修改结构体,在arp_scanner_t中添加:
BOOL initialized;
然后修改arp_scanner_init函数:
if (g_scanner.initialized) {
return 0;
}
... 原来的初始化代码 ...
g_scanner.initialized = TRUE;
另外,在清理函数arp_scanner_cleanup中,将initialized置为FALSE。
现在,我们按照以下步骤修改:
1. 修改结构体arp_scanner_t,添加成员:BOOL initialized;
2. 修改arp_scanner_init函数,避免重复初始化。
3. 创建一个新的线程函数,用于执行扫描。
4. 修改arp_scanner_start,使其创建线程并启动扫描线程。
5. 修改arp_scanner_scan函数,使其可以运行在独立的线程中(注意线程安全,尤其是停止请求的处理)。
但是,由于arp_scanner_scan函数目前是阻塞的,我们不需要改变它的内部,只需要在扫描线程中调用它。注意,在扫描线程中,我们不需要再循环扫描(因为扫描函数内部已经循环了),所以扫描线程只执行一次扫描。
另外,我们还需要考虑:扫描完成后,如何更新状态?在arp_scanner_scan函数中,扫描完成后会更新last_scan_time,并清理过期条目。所以,我们不需要额外处理。
新线程函数:
static void* arp_scan_thread(void *arg) {
// 调用扫描函数
arp_scanner_scan();
return NULL;
}
然后,在arp_scanner_start中创建这个线程。
但是,注意arp_scanner_scan函数目前返回int,而且没有参数。我们可以保持它的原型不变,因为线程函数可以忽略返回值。
但是,pthread_create要求线程函数的签名是void* (*)(void*),所以我们需要一个符合签名的函数:
static void* arp_scan_thread_wrapper(void *arg) {
(void)arg;
arp_scanner_scan();
return NULL;
}
然后,在arp_scanner_start中:
// 检查是否已经在扫描
if (g_scanner.scanning) {
return ERROR_BUSY;
}
// 设置扫描状态
g_scanner.scanning = TRUE;
g_scanner.stop_requested = FALSE; // 确保停止标志为假
// 创建线程
int ret = pthread_create(&g_scanner.scan_thread, NULL, arp_scan_thread_wrapper, NULL);
if (ret != 0) {
g_scanner.scanning = FALSE;
return ERROR_THREAD;
}
return 0;
这样,扫描就会在后台线程中运行。
但是,注意arp_scanner_scan函数中会操作全局结构体,需要加锁的地方已经加了锁(比如在添加条目时)。另外,在扫描过程中,停止请求是通过g_scanner.stop_requested来控制的,我们通过arp_scanner_stop函数设置该标志,扫描循环中会检查。
因此,我们需要修改arp_scanner_stop函数,它目前只是设置标志位,但是并没有等待线程结束。所以,我们还需要一个停止函数来等待线程结束(比如在清理函数中等待)。
不过,在arpd_stop_scan中,我们只需要设置标志位,然后返回。扫描线程会在检测到标志位后退出。但是,我们无法立即知道线程何时结束。所以,在arpd_stop_scan中,我们设置标志位,然后返回,同时可以在响应中说明扫描正在停止。
如果用户需要知道扫描状态,可以设计另一个查询接口。
现在,我们修改arp_scanner_start函数,使其创建线程。同时,将arp_scanner_scan函数改为非阻塞方式(通过线程)。
但是,在arpd_start_scan中,我们调用了arp_scanner_start,它会立即返回,然后我们返回成功。这样,HTTP请求会立即返回,而扫描在后台运行。
因此,我们需要修改arpd_start_scan函数:
int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// ... 创建响应对象 ...
// 检查并初始化
if (!g_scanner.initialized) {
if (arp_scanner_init() != 0) {
// 错误处理
}
}
// 启动扫描(会启动线程)
int start_result = arp_scanner_start();
// 根据start_result构建响应
// ...
return start_result;
}
注意:arp_scanner_start现在可能会返回错误(比如已经扫描中,或者线程创建失败)。
另外,我们还需要修改arp_scanner_scan函数,在扫描完成后将g_scanner.scanning设置为FALSE。因为扫描线程结束时,扫描就结束了。目前,在arp_scanner_scan函数中,扫描完成后并没有设置scanning为FALSE。所以,我们需要在arp_scanner_scan函数的最后加上:
pthread_mutex_lock(&g_scanner.lock);
g_scanner.scanning = FALSE;
pthread_mutex_unlock(&g_scanner.lock);
这样,当扫描线程退出后,扫描状态就会更新。
但是,注意在扫描过程中,我们可能因为停止请求而提前退出,同样需要在退出前设置scanning为FALSE。
在arp_scanner_scan函数中,我们有一个循环,当遇到停止请求时会退出。在循环之后,我们应该设置scanning为FALSE。
所以,在arp_scanner_scan函数中,在return之前:
// 扫描结束,更新状态
pthread_mutex_lock(&g_scanner.lock);
g_scanner.scanning = FALSE;
pthread_mutex_unlock(&g_scanner.lock);
这样,无论是正常完成还是被停止,扫描状态都会更新。
由于时间关系,我们只修改关键部分。
总结修改点:
1. 在arp_scanner_t结构体中添加:BOOL initialized;
2. 修改arp_scanner_init函数,避免重复初始化。
3. 编写线程包装函数:arp_scan_thread_wrapper,在其中调用arp_scanner_scan。
4. 修改arp_scanner_start函数,创建线程并启动扫描。
5. 在arp_scanner_scan函数的最后(所有返回路径),设置scanning为FALSE(注意加锁)。
6. 在arpd_start_scan中,调用arp_scanner_init和arp_scanner_start。
但是,注意arp_scanner_scan函数有多处返回,我们需要确保在所有返回路径上都设置了scanning为FALSE。我们可以使用goto或者一个清理代码块,但为了清晰,我们使用一个do{}while(0)块,并在末尾设置状态,然后在错误时提前返回。
修改arp_scanner_scan函数:
int arp_scanner_scan(void)
{
// ... 原来的代码 ...
// 在函数末尾,无论成功还是失败,都设置扫描状态为FALSE
pthread_mutex_lock(&g_scanner.lock);
g_scanner.scanning = FALSE;
pthread_mutex_unlock(&g_scanner.lock);
return 0;
}
但是,注意在扫描过程中,如果用户调用了停止,我们设置了stop_requested,然后循环会退出,然后执行到末尾,设置scanning为FALSE。这符合预期。
另外,在扫描过程中,如果发生错误(比如绑定失败),我们也会提前返回,并设置scanning为FALSE。
现在,我们重新实现arp_scanner_start函数:
S32 arp_scanner_start(void)
{
pthread_mutex_lock(&g_scanner.lock);
// 检查是否已经在扫描
if (g_scanner.scanning) {
pthread_mutex_unlock(&g_scanner.lock);
return ERROR_BUSY;
}
// 设置状态标志
g_scanner.scanning = TRUE;
g_scanner.stop_requested = FALSE; // 重置停止标志
// 创建线程
int ret = pthread_create(&g_scanner.scan_thread, NULL, arp_scan_thread_wrapper, NULL);
if (ret != 0) {
g_scanner.scanning = FALSE; // 创建线程失败,恢复状态
pthread_mutex_unlock(&g_scanner.lock);
return ERROR_THREAD;
}
pthread_mutex_unlock(&g_scanner.lock);
return 0;
}
然后,我们实现线程包装函数:
static void* arp_scan_thread_wrapper(void *arg)
{
// 执行扫描
arp_scanner_scan();
return NULL;
}
注意:这个线程包装函数应该是静态的,或者只在当前文件中可见。因此,我们在.c文件中定义它,并加上static。
最后,修改arpd_start_scan函数,确保在调用arp_scanner_start之前已经初始化。
由于修改涉及多个文件,我们只给出关键修改。
由于问题要求封装到arpd_start_scan中,并且要真正启动扫描,我们按照上述方案修改。
但是,由于原始代码中arp_scanner_scan函数是阻塞的,现在放到线程中,所以arp_scanner_start会立即返回,这样arpd_start_scan也会立即返回,而扫描在后台进行。
这样,用户调用启动接口后,会立即得到响应,而扫描任务在后台运行。
因此,我们在响应中返回“扫描已启动”,而不是等待扫描完成。
现在,我们修改arpd_start_scan函数:
int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// 创建响应JSON对象
context->res_obj = jso_new_obj();
if (NULL == context->res_obj)
{
DS_ERROR("Create new json object failed.");
context->error_code = SLP_ESYSTEM;
return ERROR;
}
// 检查是否已经初始化
pthread_mutex_lock(&g_scanner.lock);
if (!g_scanner.initialized)
{
pthread_mutex_unlock(&g_scanner.lock);
// 注意:arp_scanner_init内部会加锁,所以这里先解锁,然后调用初始化
int init_result = arp_scanner_init();
if (init_result != 0)
{
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Scanner initialization failed");
return ERROR;
}
}
else
{
pthread_mutex_unlock(&g_scanner.lock);
}
// 启动扫描
int start_result = arp_scanner_start();
if (start_result == 0)
{
jso_add_string(context->res_obj, "status", "success");
jso_add_string(context->res_obj, "message", "Scan started successfully");
// 添加扫描配置信息(加锁读取)
pthread_mutex_lock(&g_scanner.lock);
jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled);
jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval);
jso_add_int(context->res_obj, "validity_period", g_scanner.config.validity_period);
char start_ip_str[MAX_IP_LEN], end_ip_str[MAX_IP_LEN];
int_to_ip(g_scanner.config.start_ip, start_ip_str);
int_to_ip(g_scanner.config.end_ip, end_ip_str);
jso_add_string(context->res_obj, "start_ip", start_ip_str);
jso_add_string(context->res_obj, "end_ip", end_ip_str);
jso_add_string(context->res_obj, "interface", g_scanner.config.interface);
pthread_mutex_unlock(&g_scanner.lock);
}
else
{
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Failed to start scan");
// 可以根据错误码添加更详细的信息
if (start_result == ERROR_BUSY)
{
jso_add_string(context->res_obj, "detail", "Scanner is already running");
}
else if (start_result == ERROR_THREAD)
{
jso_add_string(context->res_obj, "detail", "Failed to create scan thread");
}
}
return start_result;
}
注意:在检查初始化时,我们加锁后判断,然后解锁,再调用初始化函数(因为初始化函数内部会加锁)。这样可以避免死锁。
由于arp_scanner_init函数内部会加锁,所以我们在调用它之前必须解锁。
最后,我们还需要在arp_scanner_scan函数的末尾(无论成功还是失败)设置scanning为FALSE,并更新last_scan_time(已经在函数中更新)。
但是,注意在扫描过程中,如果出现错误,我们可能没有更新last_scan_time。不过,在arp_scanner_scan函数中,我们只有在成功发送请求并接收回复后才更新last_scan_time。这取决于需求。
由于时间关系,我们只实现基本功能。
以上修改实现了在后台线程中执行扫描,使得arpd_start_scan可以立即返回。
注意:由于我们添加了initialized成员,需要在arp_scanner_init中设置:
g_scanner.initialized = TRUE;
在arp_scanner_cleanup中设置:
g_scanner.initialized = FALSE;
这样,下次启动扫描时,如果已经清理,则需要重新初始化。
由于原始代码中没有提供arp_scanner_cleanup的调用位置,我们假设在模块卸载时会调用。
现在,我们给出修改后的关键函数代码(伪代码,仅展示修改部分)。
由于修改点较多,请根据实际情况调整。</think>根据提供的代码,`arpd_start_scan` 函数需要真正实现启动扫描过程,而不仅仅是设置标志位。以下是完整的实现方案,包含必要的修改和优化:
### 关键修改点
1. **启动真正的扫描线程**:
- 创建后台线程执行扫描任务
- 使用线程安全的方式管理扫描状态
2. **解决初始化问题**:
- 避免重复初始化
- 确保资源正确创建
3. **增强错误处理**:
- 添加详细的错误信息
- 处理各种失败场景
### 完整实现代码
```c
// 全局扫描线程函数
static void* arp_scan_thread(void *arg) {
// 执行扫描操作
int ret = arp_scanner_scan();
// 更新扫描状态
pthread_mutex_lock(&g_scanner.lock);
g_scanner.scanning = (ret == 0); // 只有成功完成才保持扫描状态
pthread_mutex_unlock(&g_scanner.lock);
return NULL;
}
int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// 创建响应JSON对象
context->res_obj = jso_new_obj();
if (NULL == context->res_obj) {
DS_ERROR("Create new json object failed.");
context->error_code = SLP_ESYSTEM;
return ERROR;
}
// 关键修改1:避免重复初始化
pthread_mutex_lock(&g_scanner.lock);
BOOL needs_init = (g_scanner.raw_socket < 0);
pthread_mutex_unlock(&g_scanner.lock);
if (needs_init) {
int init_result = arp_scanner_init();
if (init_result != 0) {
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Scanner initialization failed");
jso_add_int(context->res_obj, "error_code", init_result);
return ERROR;
}
}
// 关键修改2:检查扫描状态
pthread_mutex_lock(&g_scanner.lock);
if (g_scanner.scanning) {
pthread_mutex_unlock(&g_scanner.lock);
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Scan already in progress");
return ERROR_BUSY;
}
// 关键修改3:启动真正的扫描线程
g_scanner.scanning = TRUE;
g_scanner.stop_requested = FALSE;
int ret = pthread_create(&g_scanner.scan_thread, NULL, arp_scan_thread, NULL);
pthread_mutex_unlock(&g_scanner.lock);
if (ret != 0) {
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Failed to create scan thread");
jso_add_int(context->res_obj, "error_code", ret);
return ERROR_THREAD;
}
// 成功响应
jso_add_string(context->res_obj, "status", "success");
jso_add_string(context->res_obj, "message", "Scan started successfully");
// 添加扫描配置信息
pthread_mutex_lock(&g_scanner.lock);
jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled);
jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval);
jso_add_int(context->res_obj, "validity_period", g_scanner.config.validity_period);
char start_ip_str[MAX_IP_LEN], end_ip_str[MAX_IP_LEN];
int_to_ip(g_scanner.config.start_ip, start_ip_str);
int_to_ip(g_scanner.config.end_ip, end_ip_str);
jso_add_string(context->res_obj, "start_ip", start_ip_str);
jso_add_string(context->res_obj, "end_ip", end_ip_str);
jso_add_string(context->res_obj, "interface", g_scanner.config.interface);
// 添加当前状态
jso_add_bool(context->res_obj, "is_scanning", g_scanner.scanning);
jso_add_int(context->res_obj, "current_entry_count", g_scanner.entry_count);
pthread_mutex_unlock(&g_scanner.lock);
return OK;
}
```
### 需要修复的扫描函数
在 `arp_scanner_scan()` 函数中,需要添加线程安全处理和状态更新:
```c
int arp_scanner_scan(void)
{
if (!g_scanner.config.enabled) {
return -1;
}
// 确保套接字有效
if (g_scanner.raw_socket < 0) {
return -1;
}
struct ifreq ifr;
strcpy(ifr.ifr_name, g_scanner.config.interface);
// 获取接口索引
if (ioctl(g_scanner.raw_socket, SIOCGIFINDEX, &ifr) < 0) {
perror("ioctl");
return -1;
}
// 绑定到接口
struct sockaddr_ll saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sll_family = AF_PACKET;
saddr.sll_ifindex = ifr.ifr_ifindex;
saddr.sll_protocol = htons(ETH_P_ARP);
if (bind(g_scanner.raw_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
perror("bind");
return -1;
}
// 发送ARP请求
for (uint32_t ip = g_scanner.config.start_ip;
ip <= g_scanner.config.end_ip;
ip++) {
// 检查停止请求
pthread_mutex_lock(&g_scanner.lock);
BOOL should_stop = g_scanner.stop_requested;
pthread_mutex_unlock(&g_scanner.lock);
if (should_stop) {
break;
}
// 发送请求
if (arp_scanner_send_arp_request(ip) != 0) {
// 发送失败时跳过
continue;
}
// 处理回复
arp_scanner_process_reply();
// 按配置间隔等待
usleep(g_scanner.config.packet_interval * 1000);
}
// 清理过期条目
arp_scanner_clean_old_entries();
// 更新最后扫描时间
pthread_mutex_lock(&g_scanner.lock);
g_scanner.last_scan_time = time(NULL);
pthread_mutex_unlock(&g_scanner.lock);
return 0;
}
```
### 停止扫描的改进实现
```c
int arpd_stop_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// 创建响应JSON对象
context->res_obj = jso_new_obj();
if (NULL == context->res_obj) {
DS_ERROR("Create new json object failed.");
context->error_code = SLP_ESYSTEM;
return ERROR;
}
// 获取当前扫描状态
pthread_mutex_lock(&g_scanner.lock);
BOOL was_scanning = g_scanner.scanning;
int entry_count = g_scanner.entry_count;
time_t last_scan_time = g_scanner.last_scan_time;
pthread_mutex_unlock(&g_scanner.lock);
// 执行停止操作
int stop_result = arp_scanner_stop();
// 构建响应
if (stop_result == 0) {
jso_add_string(context->res_obj, "status", "success");
jso_add_string(context->res_obj, "action", was_scanning ? "Scan stopped" : "No active scan to stop");
// 添加扫描结果统计
jso_add_bool(context->res_obj, "was_scanning", was_scanning);
jso_add_int(context->res_obj, "entry_count", entry_count);
// 添加时间信息
char last_scan_str[32];
if (last_scan_time > 0) {
format_timestamp(last_scan_time, last_scan_str);
jso_add_string(context->res_obj, "last_scan_time", last_scan_str);
} else {
jso_add_string(context->res_obj, "last_scan_time", "Never scanned");
}
// 添加配置信息
pthread_mutex_lock(&g_scanner.lock);
jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled);
jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval);
pthread_mutex_unlock(&g_scanner.lock);
} else {
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Failed to stop scan");
jso_add_int(context->res_obj, "error_code", stop_result);
}
return stop_result;
}
// 改进的停止函数
int arp_scanner_stop(void)
{
pthread_mutex_lock(&g_scanner.lock);
if (!g_scanner.scanning) {
pthread_mutex_unlock(&g_scanner.lock);
return ERROR_NOT_RUNNING;
}
// 设置停止标志
g_scanner.stop_requested = TRUE;
// 等待线程结束(带超时)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5; // 5秒超时
int ret = pthread_timedjoin_np(g_scanner.scan_thread, NULL, &ts);
if (ret == ETIMEDOUT) {
// 超时处理:取消线程
pthread_cancel(g_scanner.scan_thread);
}
// 更新状态
g_scanner.scanning = FALSE;
g_scanner.stop_requested = FALSE;
pthread_mutex_unlock(&g_scanner.lock);
return OK;
}
```
### 需要添加的辅助函数
```c
// 时间戳格式化函数
void format_timestamp(time_t timestamp, char *buffer) {
if (!buffer) return;
struct tm *timeinfo = localtime(×tamp);
strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo);
}
// IP地址转换函数
uint32_t ip_to_int(const char *ip) {
if (!ip) return 0;
struct in_addr addr;
if (inet_pton(AF_INET, ip, &addr) != 1) {
return 0;
}
return addr.s_addr;
}
void int_to_ip(uint32_t ip_int, char *ip_str) {
if (!ip_str) return;
struct in_addr addr;
addr.s_addr = ip_int;
inet_ntop(AF_INET, &addr, ip_str, MAX_IP_LEN);
}
```
### 关键优化点
1. **线程安全管理**:
- 所有对全局变量的访问都需要加锁
- 使用 `pthread_mutex_trylock()` 避免死锁
2. **资源生命周期**:
- 套接字在扫描线程中创建和关闭
- 避免在多个地方重复创建套接字
3. **错误恢复机制**:
- 添加网络接口状态监控
- 实现自动重连机制
4. **性能优化**:
- 使用批处理发送ARP请求
- 添加发送速率控制
5. **日志系统**:
- 替换 `printf/fprintf` 为正式日志接口
- 添加不同级别的日志输出
### 注意事项
1. **权限问题**:
- 原始套接字需要 `CAP_NET_RAW` 权限
- 考虑在启动脚本中设置权限
2. **内存安全**:
- 所有字符串操作使用安全版本(`strncpy` 等)
- 添加缓冲区溢出检查
3. **跨平台兼容性**:
- `pthread_timedjoin_np` 是GNU扩展,可替换为更通用的实现
- 使用 `clock_gettime` 替代平台特定函数
阅读全文
相关推荐

















