/**

    *1.调用qqwry_init_parser创建一个qqwry_parser_t类型的解析器

    *2.初始化一个存放查询结果信息的qqwry_record

    *3.调用qqwry_querey_iprecord查询指定ip的归属地

    *4.调用qqwry_release_parser释放资源

    **/

    qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE,

    CACHE_ENABLE, 1);

    qqwry_record qr = QQWARY_RECORD_INITIALIZER();

    qqwry_querey_iprecord(parser, "61.172.201.195", &qr);

    qqwry_release_parser(parser);

    这是一个初级版本,还没有经过大量的测试,可能存在很多不完备的地方,希望亲们试用了之后,能够提出改进意见啊。

    qqwry_utils.h

    点击(此处)折叠或打开

    /*

    * qqwry_utils.h

    *

    * Created on: 2012-4-26

    * Author: zhanlin

    */

    #ifndef QQWRY_UTILS_H_

    #define QQWRY_UTILS_H_

    int ipaddr_to_bytes(const char *src, char *dest);

    void bytes_to_ipaddr(const char *src, char *dest);

    inline int32_t char3_to_int32(const char *buf);

    #endif /* QQWRY_UTILS_H_ */

    qqwry_utils.c

    点击(此处)折叠或打开

    /*

    * qqwry_utils.c

    *

    * Created on: 2012-4-26

    * Author: zhanlin

    */

    #include <string.h>

    #include <sys/types.h>

    #include <stdlib.h>

    #include <stdio.h>

    #include <string.h>

    #include "qqwry_utils.h"

    int ipaddr_to_bytes(const char *src, char *dest) {

    int n;

    char *newstr;

    char *sub;

    int i = 0;

    n = strlen(src);

    newstr = (char *) malloc(n + 1);

    if (newstr == NULL) {

    return -1;

    }

    memcpy(newstr, src, n);

    *(newstr + n) = 0;

    sub = strtok(newstr, ".");

    while (sub != NULL) {

    // printf("%s atoi %d\n", sub, atoi(sub));

    *(dest + i) = (char) atoi(sub);

    sub = strtok(NULL, ".");

    i++;

    }

    free(newstr);

    return 0;

    }

    void bytes_to_ipaddr(const char *src, char *dest) {

    sprintf(dest, "%c.%c.%c.%c", src[0], src[1], src[2], src[3]);

    }

    inline int32_t char3_to_int32(const char *buf) {

    int32_t i = 0;

    memcpy(&i, buf, 3);

    return i;

    }

    qqwry_types.h

    点击(此处)折叠或打开

    /*

    * qqwry_types.h

    *

    * Created on: 2012-4-26

    * Author: zhanlin

    */

    #ifndef QQWRY_TYPES_H_

    #define QQWRY_TYPES_H_

    #include <sys/types.h>

    #include <string.h>

    #include <stdio.h>

    #include <stdlib.h>

    #include <dirent.h>

    #pragma pack(0)

    typedef struct _qqwry_header {

    u_int32_t qh_idx_start;

    u_int32_t qh_idx_end;

    } qqwry_header, *qqwry_header_t;

    #endif /* QQWRY_TYPES_H_ */

    qqwry_parser.h

    点击(此处)折叠或打开

    /*

    * qqwry_parser.h

    *

    * Created on: 2012-4-26

    * Author: zhanlin

    */

    #ifndef QQWRY_PARSER_H_

    #define QQWRY_PARSER_H_

    #include <sys/types.h>

    enum {

    VERBOSE_DISABLE = 0, VERBOSE_ENABLE = 1

    };

    enum {

    CACHE_DISABLE = 0, CACHE_ENABLE = 1

    };

    typedef struct _qqwry_record {

    char qr_ipaddr[20];

    int32_t qr_ip;

    char qr_bigzone[1024];

    char qr_smallzone[1024];

    } qqwry_record, *qqwry_record_t;

    #define QQWARY_RECORD_INITIALIZER() {\

    .qr_ipaddr = {0}, \

    .qr_ip = 0, \

    .qr_bigzone = {0}, \

    .qr_smallzone = {0}, \

    }

    struct _qqwry_parser;

    typedef struct _qqwry_parser qqwry_parser, *qqwry_parser_t;

    qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache,

    int loaddb);

    int qqwry_load_db(qqwry_parser_t parser);

    void qqwry_unload_db(qqwry_parser_t parser);

    int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr, qqwry_record_t qr);

    void qqwry_release_parser(qqwry_parser_t parser);

    int load_db_to_mem(qqwry_parser_t parser);

    #endif /* QQWRY_PARSER_H_ */

    qqwry_types.c

    点击(此处)折叠或打开

    /*

    * qqwry_types.c

    *

    * Created on: 2012-4-26

    * Author: root

    */

 #include "qqwry_parser.h"

    #include "qqwry_utils.h"

    #include "qqwry_types.h"

    #include <sys/stat.h>

    #include <fcntl.h>

    #include <unistd.h>

    #include <errno.h>

    #include <iconv.h>

    #include <arpa/inet.h>

    #define trace(parser, fmt, …) {\

    if((parser)->verbose) {\

    printf(fmt, ##);\

    }\

    }

    struct _qqwry_parser {

    char qp_db_path[PATH_MAX];

    int qp_db_fd;

    int qp_verbose;

    int qp_cache;

    int qp_errno;

    char *qp_memaddr;

    u_int32_t qp_foff;

    u_int32_t qp_fsize;

    qqwry_header_t qp_header;

    iconv_t qp_cd;

    };

    /*

    int load_db_to_mem(qqwry_parser_t parser);

    void unload_db(qqwry_parser_t parser);*/

    int qqwry_load_db(qqwry_parser_t parser) {

    struct stat buf;

    int retval = 0;

    parser->qp_errno = 0;

    //

    if ((retval = fstat(parser->qp_db_fd, &buf)) != 0) {

    parser->qp_errno = errno;

    if (parser->qp_verbose)

    perror("fstat execute failed");

    return retval;

    }

    //

    parser->qp_fsize = buf.st_size;

    parser->qp_memaddr = (char *) malloc(buf.st_size);

    if (parser->qp_memaddr == NULL) {

    parser->qp_errno = errno;

    if (parser->qp_verbose)

    perror("malloc execute failed");

    return -1;

    }

    //

    if ((retval = read(parser->qp_db_fd, parser->qp_memaddr, buf.st_size))

    != buf.st_size) {

    parser->qp_errno = errno;

    if (parser->qp_verbose)

    perror("read file failed");

    }

    parser->qp_header = (qqwry_header_t) parser->qp_memaddr;

    //

    parser->qp_cd = iconv_open("UTF-8", "GBK");

    return 0;

    }

    void qqwry_unload_db(qqwry_parser_t parser) {

    if (parser->qp_memaddr) {

    free(parser->qp_memaddr);

    parser->qp_memaddr = NULL;

    }

    if (parser->qp_cd) {

    iconv_close(parser->qp_cd);

    }

    }

    int qqwry_open_db(qqwry_parser_t parser) {

    parser->qp_db_fd = open(parser->qp_db_path, O_RDONLY, 0777);

    parser->qp_errno = errno;

    if (parser->qp_verbose && parser->qp_db_fd < 0)

    perror("open qqwry datafile failed");

    return parser->qp_db_fd;

    }

    void qqwry_close_db(qqwry_parser_t parser) {

    if (parser->qp_db_fd >= 0) {

    close(parser->qp_db_fd);

    parser->qp_db_fd = -1;

    }

    }

    int qqwry_read(qqwry_parser_t p, void *buf, int n) {

    if (p->qp_fsize < p->qp_foff + n) {

    n = p->qp_fsize - p->qp_foff;

    }

    memcpy(buf, (p->qp_memaddr + p->qp_foff), n);

    p->qp_foff += n;

    return n;

    }

    int qqwry_seek(qqwry_parser_t p, int32_t off) {

    if (p->qp_fsize < off) {

    return -1;

    }

    return (p->qp_foff = off);

    }

    int32_t qqwry_read3c_to_int32(qqwry_parser_t p) {

    char b3[3] = { 0 };

    int32_t ret = 0;

    if (qqwry_read(p, b3, 3) != 3) {

    return -1;

    }

    ret |= (b3[0] & 0xFF);

    ret |= ((b3[1] 《 8) & 0xFF00);

    ret |= ((b3[2] 《 16) & 0xFF0000);

    return ret;

    }

    char qqwry_readc(qqwry_parser_t p) {

    char b[1] = { 0 };

    if (qqwry_read(p, b, 1) != 1) {

    return -1;

    }

    return b[0];

    }

 

 int qqwry_read_ip(qqwry_parser_t p, int32_t offset, int32_t *ip) {

    int ret = 0;

    ret = qqwry_seek(p, offset);

    if (ret < 0)

    return ret;

    ret = qqwry_read(p, ip, 4);

    *ip = ntohl(*ip);

    return ret;

    }

    /**

    * 把两个byte当作无符号数进行比较

    *

    * @param b1

    * @param b2

    * @return 若b1大于b2则返回1,相等返回0,小于返回-1

    */

    int qqwry_compare_char(char c1, char c2) {

    if ((c1 & 0xFF) > (c2 & 0xFF)) // 比较是否大于

    return 1;

    else if ((c1 ^ c2) == 0) // 判断是否相等

    return 0;

    else

    return -1;

    }

    /**

    * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的

    *

    * @param ip

    * 要查询的IP

    * @param beginIp

    * 和被查询IP相比较的IP

    * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。

    */

    inline int qqwry_compare_ip(int32_t *ip, int32_t *beginip) {

    char *ipc = (char *) ip;

    char *beginipc = (char *) beginip;

    int i = 0;

    for (; i < 4; i++) {

    int r = qqwry_compare_char((*(ipc + i)), *(beginipc + i));

    if (r != 0)

    return r;

    }

    return 0;

    }

    qqwry_parser_t qqwry_init_parser(const char *dbpath, int verb, int cache,

    int loaddb) {

    qqwry_parser_t qp = (qqwry_parser_t) malloc(sizeof(qqwry_parser));

    if (qp) {

    //

    qp->qp_cache = cache;

    qp->qp_errno = 0;

    qp->qp_db_fd = -1;

    qp->qp_verbose = verb;

    qp->qp_memaddr = NULL;

    qp->qp_foff = 0;

    qp->qp_header = NULL;

    strncpy(qp->qp_db_path, dbpath, PATH_MAX);

    //

    if (loaddb) {

    if (qqwry_open_db(qp) >= 0) {

    if (qqwry_load_db(qp) != 0)

    qp->qp_errno = errno;

    else

    qqwry_close_db(qp);

    } else {

    qp->qp_errno = errno;

    }

    }

    }

    return qp;

    }

    int32_t get_middle_offset(int32_t begin, int32_t end) {

    #define IP_RECORD_LENGTH 7

    long records = (end - begin) / IP_RECORD_LENGTH;

    records 》= 1;

    if (records == 0)

    records = 1;

    return begin + records * IP_RECORD_LENGTH;

    }

    int32_t qqwry_locate_ip(qqwry_parser_t p, const char *ipaddr) {

    int32_t ip = 0;

    int32_t rip;

    int ret = 0;

    int32_t m;

    int32_t i = p->qp_header->qh_idx_start;

    int j = p->qp_header->qh_idx_end;

    ip = (int32_t) inet_addr(ipaddr) ;

    // ipaddr_to_bytes(ipaddr, (char *) &ip);

    qqwry_read_ip(p, p->qp_header->qh_idx_start, &rip);

    ret = qqwry_compare_ip(&ip, &rip);

    if (ret == 0)

    return p->qp_header->qh_idx_start;

    else if (ret < 0)

    return -1;

    // 开始二分搜索

    for (; i < j;) {

    m = get_middle_offset(i, j);

    qqwry_read_ip(p, m, &rip);

    ret = qqwry_compare_ip(&ip, &rip);

    // log.debug(Utils.getIpStringFromBytes(b));

    if (ret > 0)

    i = m;

    else if (ret < 0) {

    if (m == j) {

    j -= IP_RECORD_LENGTH;

    m = j;

    } else {

    j = m;

    }

    } else {

    qqwry_seek(p, m + 4);

    return qqwry_read3c_to_int32(p);

    }

    }

 

  // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非

    // 肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移

    qqwry_seek(p, m + 4);

    m = qqwry_read3c_to_int32(p);

    qqwry_read_ip(p, m, &rip);

    ret = qqwry_compare_ip(&ip, &rip);

    if (ret <= 0)

    return m;

    else

    return -1;

    }

    size_t conver_gbk_to_utf8(qqwry_parser_t p, char *inbuf, char *outbuf) {

    int n = strlen(inbuf);

    char *in = inbuf;

    char *out = outbuf;

    size_t outlen = n * 4;

    iconv(p->qp_cd, &in, (size_t *) &n, &out, &outlen);

    outlen = strlen(outbuf);

    return outlen;

    }

    void qqwry_read_string(qqwry_parser_t p, char *buf) {

    int i = 0;

    char tmp[512] = { 0 };

    for (i = 0, tmp[i] = qqwry_readc(p); tmp[i] != 0; tmp[++i] = qqwry_readc(p))

    ;

    conver_gbk_to_utf8(p, tmp, buf);

    }

    void qqwry_read_smallzone(qqwry_parser_t p, char *buf) {

    char flag = qqwry_readc(p);

    if (flag == 0x01 || flag == 0x02) {

    long areaOffset = qqwry_read3c_to_int32(p);

    if (areaOffset == 0)

    p->qp_errno = 0;

    else {

    qqwry_seek(p, areaOffset);

    qqwry_read_string(p, buf);

    }

    } else {

    return qqwry_read_string(p, buf);

    }

    }

    int qqwry_querey_iprecord(qqwry_parser_t parser, const char *ipaddr,

    qqwry_record_t qr) {

    #define AREA_FOLLOWED 0x1

    #define NO_AREA 0x2

    int32_t offset = qqwry_locate_ip(parser, ipaddr);

    char flag = 0;

    printf("ip off: %d\n", offset);

    qqwry_seek(parser, offset + 4);

    // 读取第一个字节判断是否标志字节

    flag = qqwry_readc(parser);

    if (flag == AREA_FOLLOWED) {

    // 读取国家偏移

    int32_t country_offset = qqwry_read3c_to_int32(parser);

    // 跳转至偏移处

    qqwry_seek(parser, country_offset);

    // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向

    flag = qqwry_readc(parser);

    if (flag == NO_AREA) {

    qqwry_seek(parser, qqwry_read3c_to_int32(parser));

    qqwry_read_string(parser, qr->qr_bigzone);

    qqwry_seek(parser, country_offset + 4);

    } else {

    qqwry_seek(parser, country_offset);

    qqwry_read_string(parser, qr->qr_bigzone);

    }

    // 读取地区标志

    qqwry_read_smallzone(parser, qr->qr_smallzone);

    } else if (flag == NO_AREA) {

    int32_t country_offset = qqwry_read3c_to_int32(parser);

    qqwry_seek(parser, country_offset);

    qqwry_read_string(parser, qr->qr_bigzone);

    qqwry_seek(parser, offset + 8);

    qqwry_read_string(parser, qr->qr_smallzone);

    } else {

    qqwry_seek(parser, parser->qp_foff - 1);

    qqwry_read_string(parser, qr->qr_bigzone);

    qqwry_read_string(parser, qr->qr_smallzone);

    }

    return 0;

    }

    void qqwry_release_parser(qqwry_parser_t parser) {

    if (parser != NULL) {

    //

    if (parser->qp_memaddr) {

    qqwry_unload_db(parser);

    }

    //

    free(parser);

    parser = NULL;

    }

    }

    ipinfo.c

    点击(此处)折叠或打开

    /*

    ============================================================================

    Name : ipinfo.c

    Author : ZhanLin

    Version :

    Copyright : GPL v2

    Ansi-style

    ============================================================================

    */

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include "qqwry_parser.h"

    #include <iconv.h>

    int main(void) {

    qqwry_parser_t parser = qqwry_init_parser("/root/QQWry.Dat", VERBOSE_ENABLE,

    CACHE_ENABLE, 1);

    qqwry_record qr = QQWARY_RECORD_INITIALIZER();

    qqwry_querey_iprecord(parser, "61.172.201.195", &qr);

    qqwry_release_parser(parser);

    printf("big zone: %s, small zone: %s\n", qr.qr_bigzone, qr.qr_smallzone);

    return EXIT_SUCCESS;

    }

創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()