260 lines
8.4 KiB
C
260 lines
8.4 KiB
C
#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);
|
||
}
|
||
*/
|