Files
DenyIP/libcurl.c
2025-07-23 14:27:02 +08:00

260 lines
8.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "libcurl.h"
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
// 注意这里根据每次被调用获得的数据重新动态分配缓存区的大小
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if (ptr == NULL) {
/* 内存不足! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
char *GetLocalAddr(char *url)
{
CURL *curl_handle;
CURLcode res;
struct curl_slist *headers = NULL;
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
chunk.size = 0; /* 此时没有数据 */
curl_global_init(CURL_GLOBAL_ALL);
/* 初始化curl会话 */
curl_handle = curl_easy_init();
char *p = NULL;
char *buff;
p = strstr(url, "-H");
if (p) {
buff = (char *)alloca(p - url + 1);
if (buff == NULL)
perror("out of memory.");
memset(buff, 0, p - url + 1);
memcpy(buff, url, (int)(p - url - 1));
// 赋值header值
headers = curl_slist_append(headers, p + 3);
// 设置header
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl_handle, CURLOPT_URL, buff);
} else {
/* 指定要获取的URL */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
}
/* 将所有数据发送到此函数 */
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* 将"chunk"结构传递给回调函数 */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
//printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
//printf("%s", chunk.memory);
;
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return chunk.memory;
}
// 获取公网IP
char *CurlGetIpArea(char *ip)
{
char url[256] = { 0 };
snprintf(url, sizeof(url), "https://qifu-api.baidubce.com/ip/geo/v1/district?ip=%s", ip);
CURL *curl_handle;
CURLcode res;
struct curl_slist *headers = NULL;
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
chunk.size = 0; /* 此时没有数据 */
curl_global_init(CURL_GLOBAL_ALL);
/* 初始化curl会话 */
curl_handle = curl_easy_init();
char *p = NULL;
char *buff;
p = strstr(url, "-H");
if (p) {
buff = (char *)alloca(p - url + 1);
if (buff == NULL)
perror("out of memory.");
memset(buff, 0, p - url + 1);
memcpy(buff, url, (int)(p - url - 1));
// 赋值header值
headers = curl_slist_append(headers, p + 3);
// 设置header
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl_handle, CURLOPT_URL, buff);
} else {
/* 指定要获取的URL */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
}
/* 将所有数据发送到此函数 */
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* 将"chunk"结构传递给回调函数 */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
//printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
//printf("%s", chunk.memory);
;
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return chunk.memory;
}
// 函数用于从 cJSON 对象提取字段内容
void parse_string_field(cJSON *parent, const char *field_name, char *output, size_t max_len)
{
cJSON *item = cJSON_GetObjectItemCaseSensitive(parent, field_name);
if (cJSON_IsString(item) && item->valuestring) {
strncpy(output, item->valuestring, max_len - 1);
output[max_len - 1] = '\0'; // 确保字符串以 '\0' 结尾
} else {
output[0] = '\0'; // 如果字段不存在或不是字符串,设置为空字符串
}
}
// 函数用于从 JSON 字符串解析为结构体
int parse_json_to_struct(const char *json_string, Response *response)
{
if (!json_string || !response) {
fprintf(stderr, "Invalid input parameters!\n");
return -1;
}
// 初始化结构体
memset(response, 0, sizeof(Response));
// 解析 JSON 字符串
cJSON *root = cJSON_Parse(json_string);
if (!root) {
fprintf(stderr, "Error parsing JSON: %s\n", cJSON_GetErrorPtr());
printf("%s\n", json_string);
return -1;
}
// 解析字段
parse_string_field(root, "code", response->code, sizeof(response->code));
parse_string_field(root, "ip", response->ip, sizeof(response->ip));
// 如果 code 不是 "Success",直接返回
if (strcmp(response->code, "Success") != 0) {
fprintf(stderr, "Invalid code: %s\n", response->code);
cJSON_Delete(root);
return -1;
}
// 解析 data 对象
cJSON *data_item = cJSON_GetObjectItemCaseSensitive(root, "data");
if (cJSON_IsObject(data_item)) {
parse_string_field(data_item, "continent", response->data.continent, sizeof(response->data.continent));
parse_string_field(data_item, "country", response->data.country, sizeof(response->data.country));
parse_string_field(data_item, "zipcode", response->data.zipcode, sizeof(response->data.zipcode));
parse_string_field(data_item, "owner", response->data.owner, sizeof(response->data.owner));
parse_string_field(data_item, "isp", response->data.isp, sizeof(response->data.isp));
parse_string_field(data_item, "adcode", response->data.adcode, sizeof(response->data.adcode));
parse_string_field(data_item, "prov", response->data.prov, sizeof(response->data.prov));
parse_string_field(data_item, "city", response->data.city, sizeof(response->data.city));
parse_string_field(data_item, "district", response->data.district, sizeof(response->data.district));
parse_string_field(data_item, "region", response->data.region, sizeof(response->data.region));
}
// ----------- 拼接 continent_country ---------------
if (snprintf(response->continent_country, sizeof(response->continent_country), "%s%s", response->data.continent, response->data.country) >= sizeof(response->continent_country)) {
fprintf(stderr, "continent_country truncated!\n");
}
//snprintf(response->continent_country, 256, "%s%s", response->data.continent, response->data.country);
// 清理 JSON 对象
cJSON_Delete(root);
return 0;
}
/*
int main(int argc, char *argv[])
{
char *p = curl_get_area("1.1.1.1");
puts(p);
// 定义 Response 结构体
Response response;
// 解析 JSON 到结构体
if (parse_json_to_struct(p, &response) == 0) {
// 输出解析结果
printf("Code: %s\n", response.code);
printf("IP: %s\n", response.ip);
printf("Continent: %s\n", response.data.continent);
printf("Country: %s\n", response.data.country);
printf("ISP: %s\n", response.data.isp);
printf("Region: %s\n", response.data.region);
} else {
fprintf(stderr, "Failed to parse JSON.\n");
}
free(p);
}
*/