/** * default ip2region implementation * * @see #ip2region.h * @author chenxin * @date 2015-10-30 */ #include "ip2region.h" #include #include /** * create a new ip2region object * * @param dbFile path */ IP2R_API uint_t ip2region_create(ip2region_t ip2rObj, char *dbFile) { memset(ip2rObj, 0x00, sizeof(ip2region_entry)); ip2rObj->headerLen = 0; ip2rObj->HeaderSip = (uint_t *) IP2R_MALLOC(TOTAL_HEADER_LENGTH); if ( ip2rObj->HeaderSip == NULL ) { return 0; } ip2rObj->HeaderPtr = (uint_t *) IP2R_MALLOC(TOTAL_HEADER_LENGTH); if ( ip2rObj->HeaderPtr == NULL ) { IP2R_FREE(ip2rObj->HeaderSip); return 0; } //open the db file ip2rObj->dbHandler = fopen(dbFile, "rb"); if ( ip2rObj->dbHandler == NULL ) { IP2R_FREE(ip2rObj->HeaderSip); IP2R_FREE(ip2rObj->HeaderPtr); return 0; } ip2rObj->firstIndexPtr = 0; ip2rObj->lastIndexPtr = 0; ip2rObj->totalBlocks = 0; return 1; } /** * destroy the specifield ip2region object * * @param ip2region_t */ IP2R_API uint_t ip2region_destroy(ip2region_t ip2rObj) { IP2R_FREE(ip2rObj->HeaderSip); ip2rObj->HeaderSip = NULL; IP2R_FREE(ip2rObj->HeaderPtr); ip2rObj->HeaderPtr = NULL; //close the db file resource fclose(ip2rObj->dbHandler); return 1; } /** * get the region associated with the specifield ip address with binary search algorithm * * @param ip2rObj * @param ip * @param datablock * @return uint_t */ IP2R_API uint_t ip2region_binary_search(ip2region_t ip2rObj, uint_t ip, datablock_t datablock) { int l, h, m, p; uint_t sip, eip, dptr; char buffer[256]; int dataLen, dataptr; if ( ip2rObj->totalBlocks == 0 ) { fseek(ip2rObj->dbHandler, 0, 0); if ( fread(buffer, 8, 1, ip2rObj->dbHandler) != 1 ) { return 0; } ip2rObj->firstIndexPtr = getUnsignedInt(buffer, 0); ip2rObj->lastIndexPtr = getUnsignedInt(buffer, 4); ip2rObj->totalBlocks = (ip2rObj->lastIndexPtr-ip2rObj->firstIndexPtr)/INDEX_BLOCK_LENGTH + 1; } //binary search the index blocks to define the data block l = 0; h = ip2rObj->totalBlocks; dptr = 0; while ( l <= h ) { m = (l + h) >> 1; p = ip2rObj->firstIndexPtr + m * INDEX_BLOCK_LENGTH; fseek(ip2rObj->dbHandler, p, 0); if ( fread(buffer, INDEX_BLOCK_LENGTH, 1, ip2rObj->dbHandler) != 1 ) { return 0; } sip = getUnsignedInt(buffer, 0); if ( ip < sip ) { h = m - 1; } else { eip = getUnsignedInt(buffer, 4); if ( ip > eip ) { l = m + 1; } else { dptr = getUnsignedInt(buffer, 8); break; } } } if ( dptr == 0 ) return 0; //get the data dataLen = ((dptr >> 24) & 0xFF); dataptr = (dptr & 0x00FFFFFF); //memset(data, 0x00, sizeof(data)); fseek(ip2rObj->dbHandler, dataptr, 0); if ( fread(buffer, dataLen, 1, ip2rObj->dbHandler) != 1 ) { return 0; } //fill the data to the datablock datablock->city_id = getUnsignedInt(buffer, 0); dataLen -= 4; //reduce the length of the city_id memcpy(datablock->region, buffer + 4, dataLen); datablock->region[dataLen] = '\0'; return 1; } IP2R_API uint_t ip2region_binary_search_string(ip2region_t ip2rObj, char *ip, datablock_t datablock) { return ip2region_binary_search(ip2rObj, ip2long(ip), datablock); } /** * get the region associated with the specifield ip address with b-tree algorithm * * @param ip2rObj * @param ip * @param datablock * @return uint_t */ IP2R_API uint_t ip2region_btree_search(ip2region_t ip2rObj, uint_t ip, datablock_t datablock) { int i, idx; int l, m, h, p, sptr, eptr, indexBlockLen, dataLen, dataptr; uint_t sip, eip, idxptr, dptr; char buffer[TOTAL_HEADER_LENGTH]; if ( ip2rObj->headerLen == 0 ) { idx = 0; fseek(ip2rObj->dbHandler, 8, 0); //pass the super block if ( fread(buffer, TOTAL_HEADER_LENGTH, 1, ip2rObj->dbHandler) != 1 ) { return 0; } for ( i = 0; i < TOTAL_HEADER_LENGTH; i += 8 ) { sip = getUnsignedInt(buffer, i); idxptr = getUnsignedInt(buffer, i + 4); if ( idxptr == 0 ) break; ip2rObj->HeaderSip[idx] = sip; ip2rObj->HeaderPtr[idx] = idxptr; idx++; } ip2rObj->headerLen = idx; } //search the header block to define the index block l = 0; h = ip2rObj->headerLen; sptr = 0; eptr = 0; while ( l <= h ) { m = ((l + h) >> 1); //perfetc matched, just return it if ( ip == ip2rObj->HeaderSip[m] ) { if ( m > 0 ) { sptr = ip2rObj->HeaderPtr[m-1]; eptr = ip2rObj->HeaderPtr[m ]; } else { sptr = ip2rObj->HeaderPtr[m ]; eptr = ip2rObj->HeaderPtr[m+1]; } break; } //less then the middle value if ( ip < ip2rObj->HeaderSip[m] ) { if ( m == 0 ) { sptr = ip2rObj->HeaderPtr[m ]; eptr = ip2rObj->HeaderPtr[m+1]; break; } else if ( ip > ip2rObj->HeaderSip[m-1] ) { sptr = ip2rObj->HeaderPtr[m-1]; eptr = ip2rObj->HeaderPtr[m ]; break; } h = m - 1; } else { if ( m == ip2rObj->headerLen - 1 ) { sptr = ip2rObj->HeaderPtr[m-1]; eptr = ip2rObj->HeaderPtr[m ]; break; } else if ( ip <= ip2rObj->HeaderSip[m+1] ) { sptr = ip2rObj->HeaderPtr[m ]; eptr = ip2rObj->HeaderPtr[m+1]; break; } l = m + 1; } } //not matched just stop it if ( sptr == 0 ) return 0; indexBlockLen = eptr - sptr; fseek(ip2rObj->dbHandler, sptr, 0); if ( fread(buffer, indexBlockLen + INDEX_BLOCK_LENGTH, 1, ip2rObj->dbHandler) != 1 ) { return 0; } dptr = 0; l = 0; h = indexBlockLen / INDEX_BLOCK_LENGTH; while ( l <= h ) { m = ((l + h) >> 1); p = m * INDEX_BLOCK_LENGTH; sip = getUnsignedInt(buffer, p); if ( ip < sip ) { h = m - 1; } else { eip = getUnsignedInt(buffer, p + 4); if ( ip > eip ) { l = m + 1; } else { dptr = getUnsignedInt(buffer, p + 8); break; } } } if ( dptr == 0 ) return 0; dataLen = ((dptr >> 24) & 0xFF); dataptr = (dptr & 0x00FFFFFF); fseek(ip2rObj->dbHandler, dataptr, 0); if ( fread(buffer, dataLen, 1, ip2rObj->dbHandler) != 1 ) { return 0; } datablock->city_id = getUnsignedInt(buffer, 0); dataLen -= 4; memcpy(datablock->region, buffer + 4, dataLen); datablock->region[dataLen] = '\0'; return 1; } IP2R_API uint_t ip2region_btree_search_string(ip2region_t ip2rObj, char *ip, datablock_t datablock) { return ip2region_btree_search(ip2rObj, ip2long(ip), datablock); } /** * get a unsinged long(4bytes) from a specifield buffer start from the specifield offset * * @param buffer * @param offset * @return uint_t */ IP2R_API uint_t getUnsignedInt(char *buffer, int offset) { return ( ((buffer[offset ]) & 0x000000FF) | ((buffer[offset+1] << 8) & 0x0000FF00) | ((buffer[offset+2] << 16) & 0x00FF0000) | ((buffer[offset+3] << 24) & 0xFF000000) ); } /** * string ip to long * * @param ip * @return uint_t */ IP2R_API uint_t ip2long(char *ip) { int i = 0, p = 24; char buffer[4], *cs = ip; uint_t ipval = 0; while ( *cs != '\0' ) { if ( *cs == '.' ) { //single part length limit if ( i > 3 ) { ipval = 0; break; } if ( p < 0 ) break; buffer[i] = '\0'; ipval |= (atoi(buffer) << p); p -= 8; i = 0; } else { buffer[i++] = *cs; } cs++; } //append the rest parts if ( i > 3 ) return 0; buffer[i] = '\0'; ipval |= atoi(buffer); return ipval; } /** * long to string ip * * @param ip * @param buffer * @return uint_t(1 for success and 0 for failed) */ IP2R_API uint_t long2ip(uint_t ip, char *buffer) { return 0; }