242 lines
6.7 KiB
C
242 lines
6.7 KiB
C
#include "cache.h"
|
||
|
||
|
||
struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点
|
||
int cache_size = 0; // 当前缓存中的 IP 数量
|
||
|
||
// 将新 IP 添加到缓存,若缓存过大则移除最早的 IP
|
||
void add_ip_to_cache(const char *ip)
|
||
{
|
||
// 如果缓存大小超过限制,移除最早的 IP
|
||
if (cache_size >= MAX_CACHE_SIZE) {
|
||
struct ip_cache_node *current = ip_cache_head;
|
||
struct ip_cache_node *prev = NULL;
|
||
|
||
// 找到链表的最后一个节点
|
||
while (current->next != NULL) {
|
||
prev = current;
|
||
current = current->next;
|
||
}
|
||
|
||
// 移除最后一个节点(最早的 IP)
|
||
if (prev != NULL) {
|
||
prev->next = NULL;
|
||
} else {
|
||
ip_cache_head = NULL;
|
||
}
|
||
free(current);
|
||
cache_size--;
|
||
}
|
||
|
||
// 创建新的缓存节点并添加到链表头部
|
||
struct ip_cache_node *new_node = (struct ip_cache_node *)malloc(sizeof(struct ip_cache_node));
|
||
if (new_node == NULL) {
|
||
perror("malloc");
|
||
return;
|
||
}
|
||
strncpy(new_node->ip, ip, INET_ADDRSTRLEN);
|
||
new_node->timestamp = time(NULL); // 记录当前时间
|
||
new_node->next = ip_cache_head;
|
||
ip_cache_head = new_node;
|
||
cache_size++;
|
||
}
|
||
|
||
// 检查 IP 是否已在缓存中并是否过期
|
||
int is_ip_in_cache(const char *ip)
|
||
{
|
||
time_t now = time(NULL); // 获取当前时间
|
||
struct ip_cache_node *current = ip_cache_head;
|
||
struct ip_cache_node *prev = NULL;
|
||
|
||
if (ip_cache_head == NULL) return 0; // 如果 ip_cache_head == NULL,current->next 可能导致段错误 (Segmentation Fault)。
|
||
|
||
while (current != NULL) {
|
||
// 如果 IP 匹配并且未过期
|
||
if (strcmp(current->ip, ip) == 0) {
|
||
if (now - current->timestamp <= CACHE_TTL) {
|
||
return 1; // IP 在缓存中,且未过期
|
||
} else {
|
||
// 如果过期,从链表中移除这个节点
|
||
if (prev == NULL) {
|
||
ip_cache_head = current->next;
|
||
} else {
|
||
prev->next = current->next;
|
||
}
|
||
|
||
free(current);
|
||
cache_size--;
|
||
return 0; // IP 过期,不再缓存
|
||
}
|
||
}
|
||
|
||
prev = current;
|
||
current = current->next;
|
||
}
|
||
return 0; // IP 不在缓存中
|
||
}
|
||
|
||
// 清理缓存链表,释放所有节点的内存
|
||
void free_ip_cache()
|
||
{
|
||
struct ip_cache_node *current = ip_cache_head;
|
||
while (current != NULL) {
|
||
struct ip_cache_node *next = current->next;
|
||
free(current);
|
||
current = next;
|
||
}
|
||
|
||
ip_cache_head = NULL;
|
||
cache_size = 0;
|
||
}
|
||
|
||
|
||
|
||
char cn_ip[MAXIPSET_][MAXIPLEN] = { 0 };
|
||
|
||
// 添加一个 IP 到集合(如果已存在则不添加)
|
||
int add_cn_ip(char cn_ip[MAXIPSET_][MAXIPLEN], char *ip)
|
||
{
|
||
if (ip == NULL || strlen(ip) >= MAXIPLEN) {
|
||
return -1; // 错误:无效的 IP 地址或过长
|
||
}
|
||
// 检查是否已存在
|
||
for (int i = 0; i < MAXIPSET_; i++) {
|
||
if (cn_ip[i][0] != '\0' && strcmp(cn_ip[i], ip) == 0) {
|
||
return 1; // IP 已存在,返回特殊代码
|
||
}
|
||
}
|
||
// 查找空位并添加
|
||
for (int i = 0; i < MAXIPSET_; i++) {
|
||
if (cn_ip[i][0] == '\0') { // 检查是否为空
|
||
strcpy(cn_ip[i], ip);
|
||
return 0; // 成功添加
|
||
}
|
||
}
|
||
return -1; // 错误:集合已满
|
||
}
|
||
|
||
// 判断给定的IP地址是否在集合中
|
||
int is_ip_in_set(char cn_ip[MAXIPSET_][MAXIPLEN], const char *ip)
|
||
{
|
||
if (ip == NULL) {
|
||
return 0; // 错误:无效的IP地址指针
|
||
}
|
||
for (int i = 0; i < MAXIPSET_; i++) {
|
||
if (cn_ip[i][0] != '\0' && strcmp(cn_ip[i], ip) == 0) {
|
||
return 1; // 找到匹配的IP地址
|
||
}
|
||
}
|
||
return 0; // 没有找到匹配的IP地址
|
||
}
|
||
|
||
// 计算集合中非空IP的数量
|
||
int cn_ip_len(char cn_ip[MAXIPSET_][MAXIPLEN])
|
||
{
|
||
int count = 0; // 用于计数非空IP
|
||
for (int i = 0; i < MAXIPSET_; i++) {
|
||
if (cn_ip[i][0] != '\0') {
|
||
count++; // 非空IP计数
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
// 安全的清理IP地址集合,将所有位置置为空字符串
|
||
void clear_ip_set(char cn_ip[MAXIPSET_][MAXIPLEN])
|
||
{
|
||
if (cn_ip == NULL) {
|
||
return; // 如果指针无效,则直接返回
|
||
}
|
||
for (int i = 0; i < MAXIPSET_; i++) {
|
||
memset(cn_ip[i], '\0', MAXIPLEN);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// 保存字符串到文件
|
||
int append_string_to_file(const char *filepath, const char *str)
|
||
{
|
||
// 检查输入是否为空
|
||
if (filepath == NULL || str == NULL) {
|
||
fprintf(stderr, "Invalid argument(s).\n");
|
||
return -1;
|
||
}
|
||
// 打开文件以追加模式
|
||
FILE *file = fopen(filepath, "a");
|
||
if (file == NULL) {
|
||
perror("Error opening file");
|
||
return -1;
|
||
}
|
||
// 追加字符串到文件
|
||
if (fprintf(file, "%s\n", str) < 0) {
|
||
perror("Error writing to file");
|
||
fclose(file);
|
||
return -1;
|
||
}
|
||
// 刷新缓冲区确保数据写入磁盘
|
||
if (fflush(file) != 0) {
|
||
perror("Error flushing file");
|
||
fclose(file);
|
||
return -1;
|
||
}
|
||
// 关闭文件
|
||
if (fclose(file) != 0) {
|
||
perror("Error closing file");
|
||
return -1;
|
||
}
|
||
// 成功返回
|
||
return 0;
|
||
}
|
||
|
||
int read_file_to_array(const char *filepath, char cn_ip[MAXIPSET_][MAXIPLEN], int *line_count)
|
||
{
|
||
// 参数校验
|
||
if (filepath == NULL || cn_ip == NULL || line_count == NULL) {
|
||
fprintf(stderr, "Invalid argument(s).\n");
|
||
return -1;
|
||
}
|
||
|
||
FILE *file = fopen(filepath, "r");
|
||
if (file == NULL) {
|
||
fprintf(stderr, "Error opening file '%s': %s\n", filepath, strerror(errno));
|
||
return -2;
|
||
}
|
||
|
||
int count = 0;
|
||
while (fgets(cn_ip[count], MAXIPLEN, file)) {
|
||
// 去掉行尾的换行符
|
||
size_t len = strlen(cn_ip[count]);
|
||
if (len > 0 && cn_ip[count][len - 1] == '\n') {
|
||
cn_ip[count][len - 1] = '\0';
|
||
}
|
||
count++;
|
||
if (count >= MAXIPSET_) {
|
||
fprintf(stderr, "Exceeded maximum number of lines (%d).\n", MAXIPSET_);
|
||
fclose(file);
|
||
return -3;
|
||
}
|
||
}
|
||
|
||
if (ferror(file)) {
|
||
fprintf(stderr, "Error reading file '%s'.\n", filepath);
|
||
fclose(file);
|
||
return -4;
|
||
}
|
||
|
||
fclose(file);
|
||
*line_count = count;
|
||
return 0;
|
||
}
|
||
|
||
// 判断文件是否存在,返回 1 表示存在,0 表示不存在
|
||
int file_exists_access(const char *filepath)
|
||
{
|
||
if (filepath == NULL) {
|
||
fprintf(stderr, "Invalid argument.\n");
|
||
return 0;
|
||
}
|
||
|
||
return access(filepath, F_OK) == 0;
|
||
}
|