mirror of
				https://github.com/VCMP-SqMod/SqMod.git
				synced 2025-11-04 00:07:19 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			898 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			898 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# NAME
 | 
						|
 | 
						|
libmaxminddb - a library for working with MaxMind DB files
 | 
						|
 | 
						|
# SYNOPSIS
 | 
						|
 | 
						|
```c
 | 
						|
#include <maxminddb.h>
 | 
						|
 | 
						|
int MMDB_open(
 | 
						|
    const char *const filename,
 | 
						|
    uint32_t flags,
 | 
						|
    MMDB_s *const mmdb);
 | 
						|
void MMDB_close(MMDB_s *const mmdb);
 | 
						|
 | 
						|
MMDB_lookup_result_s MMDB_lookup_string(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    const char *const ipstr,
 | 
						|
    int *const gai_error,
 | 
						|
    int *const mmdb_error);
 | 
						|
MMDB_lookup_result_s MMDB_lookup_sockaddr(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    const struct sockaddr *const
 | 
						|
    sockaddr,
 | 
						|
    int *const mmdb_error);
 | 
						|
 | 
						|
int MMDB_get_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    ...);
 | 
						|
int MMDB_vget_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    va_list va_path);
 | 
						|
int MMDB_aget_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    const char *const *const path);
 | 
						|
 | 
						|
int MMDB_get_entry_data_list(
 | 
						|
    MMDB_entry_s *start,
 | 
						|
    MMDB_entry_data_list_s **const entry_data_list);
 | 
						|
void MMDB_free_entry_data_list(
 | 
						|
    MMDB_entry_data_list_s *const entry_data_list);
 | 
						|
int MMDB_get_metadata_as_entry_data_list(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    MMDB_entry_data_list_s **const entry_data_list);
 | 
						|
int MMDB_dump_entry_data_list(
 | 
						|
    FILE *const stream,
 | 
						|
    MMDB_entry_data_list_s *const entry_data_list,
 | 
						|
    int indent);
 | 
						|
 | 
						|
int MMDB_read_node(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    uint32_t node_number,
 | 
						|
    MMDB_search_node_s *const node);
 | 
						|
 | 
						|
const char *MMDB_lib_version(void);
 | 
						|
const char *MMDB_strerror(int error_code);
 | 
						|
 | 
						|
typedef struct MMDB_lookup_result_s {
 | 
						|
    bool found_entry;
 | 
						|
    MMDB_entry_s entry;
 | 
						|
    uint16_t netmask;
 | 
						|
} MMDB_lookup_result_s;
 | 
						|
 | 
						|
typedef struct MMDB_entry_data_s {
 | 
						|
    bool has_data;
 | 
						|
    union {
 | 
						|
        uint32_t pointer;
 | 
						|
        const char *utf8_string;
 | 
						|
        double double_value;
 | 
						|
        const uint8_t *bytes;
 | 
						|
        uint16_t uint16;
 | 
						|
        uint32_t uint32;
 | 
						|
        int32_t int32;
 | 
						|
        uint64_t uint64;
 | 
						|
        {mmdb_uint128_t or uint8_t[16]} uint128;
 | 
						|
        bool boolean;
 | 
						|
        float float_value;
 | 
						|
    };
 | 
						|
    ...
 | 
						|
    uint32_t data_size;
 | 
						|
    uint32_t type;
 | 
						|
} MMDB_entry_data_s;
 | 
						|
 | 
						|
typedef struct MMDB_entry_data_list_s {
 | 
						|
    MMDB_entry_data_s entry_data;
 | 
						|
    struct MMDB_entry_data_list_s *next;
 | 
						|
} MMDB_entry_data_list_s;
 | 
						|
```
 | 
						|
 | 
						|
# DESCRIPTION
 | 
						|
 | 
						|
The libmaxminddb library provides functions for working MaxMind DB files. See
 | 
						|
http://maxmind.github.io/MaxMind-DB/ for the MaxMind DB format specification.
 | 
						|
The database and results are all represented by different data structures.
 | 
						|
Databases are opened by calling `MMDB_open()`. You can look up IP addresses as
 | 
						|
a string with `MMDB_lookup_string()` or as a pointer to a `sockaddr`
 | 
						|
structure with `MMDB_lookup_sockaddr()`.
 | 
						|
 | 
						|
If the lookup finds the IP address in the database, it returns a
 | 
						|
`MMDB_lookup_result_s` structure. If that structure indicates that the database
 | 
						|
has data for the IP, there are a number of functions that can be used to fetch
 | 
						|
that data. These include `MMDB_get_value()` and `MMDB_get_entry_data_list()`.
 | 
						|
See the function documentation below for more details.
 | 
						|
 | 
						|
When you are done with the database handle you should call `MMDB_close()`.
 | 
						|
 | 
						|
All publicly visible functions, structures, and macros begin with "MMDB_".
 | 
						|
 | 
						|
# DATA STRUCTURES
 | 
						|
 | 
						|
All data structures exported by this library's `maxminddb.h` header are
 | 
						|
typedef'd in the form `typedef struct foo_s { ... } foo_s` so you can refer to
 | 
						|
them without the `struct` prefix.
 | 
						|
 | 
						|
This library provides the following data structures:
 | 
						|
 | 
						|
## `MMDB_s`
 | 
						|
 | 
						|
This is the handle for a MaxMind DB file. We only document some of this
 | 
						|
structure's fields intended for public use. All other fields are subject to
 | 
						|
change and are intended only for internal use.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_s {
 | 
						|
    uint32_t flags;
 | 
						|
    const char *filename;
 | 
						|
    ...
 | 
						|
    MMDB_metadata_s metadata;
 | 
						|
} MMDB_s;
 | 
						|
```
 | 
						|
 | 
						|
* `uint32_t flags` - the flags this database was opened with. See the
 | 
						|
  `MMDB_open()` documentation for more details.
 | 
						|
* `const char *filename` - the name of the file which was opened, as passed to
 | 
						|
  `MMDB_open()`.
 | 
						|
* `MMDB_metadata_s metadata` - the metadata for the database.
 | 
						|
 | 
						|
## `MMDB_metadata_s` and `MMDB_description_s`
 | 
						|
 | 
						|
This structure can be retrieved from the `MMDB_s` structure. It contains the
 | 
						|
metadata read from the database file. Note that you may find it more convenient
 | 
						|
to access this metadata by calling `MMDB_get_metadata_as_entry_data_list()`
 | 
						|
instead.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_metadata_s {
 | 
						|
    uint32_t node_count;
 | 
						|
    uint16_t record_size;
 | 
						|
    uint16_t ip_version;
 | 
						|
    const char *database_type;
 | 
						|
    struct {
 | 
						|
        size_t count;
 | 
						|
        const char **names;
 | 
						|
    } languages;
 | 
						|
    uint16_t binary_format_major_version;
 | 
						|
    uint16_t binary_format_minor_version;
 | 
						|
    uint64_t build_epoch;
 | 
						|
    struct {
 | 
						|
        size_t count;
 | 
						|
        MMDB_description_s **descriptions;
 | 
						|
    } description;
 | 
						|
} MMDB_metadata_s;
 | 
						|
 | 
						|
typedef struct MMDB_description_s {
 | 
						|
    const char *language;
 | 
						|
    const char *description;
 | 
						|
} MMDB_description_s;
 | 
						|
```
 | 
						|
 | 
						|
These structures should be mostly self-explanatory.
 | 
						|
 | 
						|
The `ip_version` member should always be `4` or `6`. The
 | 
						|
`binary_format_major_version` should always be `2`.
 | 
						|
 | 
						|
There is no requirement that the database metadata include languages or
 | 
						|
descriptions, so the `count` for these parts of the metadata can be zero. All
 | 
						|
of the other `MMDB_metadata_s` fields should be populated.
 | 
						|
 | 
						|
## `MMDB_lookup_result_s`
 | 
						|
 | 
						|
This structure is returned as the result of looking up an IP address.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_lookup_result_s {
 | 
						|
    bool found_entry;
 | 
						|
    MMDB_entry_s entry;
 | 
						|
    uint16_t netmask;
 | 
						|
} MMDB_lookup_result_s;
 | 
						|
```
 | 
						|
 | 
						|
If the `found_entry` member is false then the other members of this structure
 | 
						|
do not contain meaningful values. Always check that `found_entry` is true
 | 
						|
first.
 | 
						|
 | 
						|
The `entry` member is used to look up the data associated with the IP address.
 | 
						|
 | 
						|
The `netmask` member tells you what subnet the IP address belongs to in this
 | 
						|
database. For example, if you look up the address `1.1.1.1` in an IPv4 database
 | 
						|
and the returned `netmask` is 16, then the address is part of the `1.1.0.0/16`
 | 
						|
subnet.
 | 
						|
 | 
						|
If the database is an IPv6 database, the returned netmask is always an IPv6
 | 
						|
prefix length (from 0-128), even if that database *also* contains IPv4
 | 
						|
networks. If you look up an IPv4 address and would like to turn the netmask
 | 
						|
into an IPv4 netmask value, you can simply subtract `96` from the value.
 | 
						|
 | 
						|
## `MMDB_result_s`
 | 
						|
 | 
						|
You don't really need to dig around in this structure. You'll get this from a
 | 
						|
`MMDB_lookup_result_s` structure and pass it to various functions.
 | 
						|
 | 
						|
## `MMDB_entry_data_s`
 | 
						|
 | 
						|
This structure is used to return a single data section entry for an IP. These
 | 
						|
entries can in turn point to other entries, as is the case for things like maps
 | 
						|
and arrays. Some members of this structure are not documented as they are only
 | 
						|
for internal use.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_entry_data_s {
 | 
						|
    bool has_data;
 | 
						|
    union {
 | 
						|
        uint32_t pointer;
 | 
						|
        const char *utf8_string;
 | 
						|
        double double_value;
 | 
						|
        const uint8_t *bytes;
 | 
						|
        uint16_t uint16;
 | 
						|
        uint32_t uint32;
 | 
						|
        int32_t int32;
 | 
						|
        uint64_t uint64;
 | 
						|
        {mmdb_uint128_t or uint8_t[16]} uint128;
 | 
						|
        bool boolean;
 | 
						|
        float float_value;
 | 
						|
    };
 | 
						|
    ...
 | 
						|
    uint32_t data_size;
 | 
						|
    uint32_t type;
 | 
						|
} MMDB_entry_data_s;
 | 
						|
```
 | 
						|
 | 
						|
The `has_data` member is true if data was found for a given lookup. See
 | 
						|
`MMDB_get_value()` for more details. If this member is false then none of the
 | 
						|
other values in the structure are meaningful.
 | 
						|
 | 
						|
The union at the beginning of the structure defines the actual data. To
 | 
						|
determine which union member is populated you should look at the `type` member.
 | 
						|
The `pointer` member of the union should never be populated in any data
 | 
						|
returned by the API. Pointers should always be resolved internally.
 | 
						|
 | 
						|
The `data_size` member is only relevant for `utf8_string` and `bytes` data.
 | 
						|
`utf8_string` is not null terminated and `data_size` _must_ be used to
 | 
						|
determine its length.
 | 
						|
 | 
						|
The `type` member can be compared to one of the `MMDB_DATA_TYPE_*` macros.
 | 
						|
 | 
						|
### 128-bit Integers
 | 
						|
 | 
						|
The handling of `uint128` data depends on how your platform supports 128-bit
 | 
						|
integers, if it does so at all. With GCC 4.4 and 4.5 we can write `unsigned
 | 
						|
int __attribute__ ((__mode__ (TI)))`. With newer versions of GCC (4.6+) and
 | 
						|
clang (3.2+) we can simply write "unsigned __int128".
 | 
						|
 | 
						|
In order to work around these differences, this library defines an
 | 
						|
`mmdb_uint128_t` type. This type is defined in the `maxminddb.h` header so you
 | 
						|
can use it in your own code.
 | 
						|
 | 
						|
With older compilers, we can't use an integer so we instead use a 16 byte
 | 
						|
array of `uint8_t` values. This is the raw data from the database.
 | 
						|
 | 
						|
This library provides a public macro `MMDB_UINT128_IS_BYTE_ARRAY` macro. If
 | 
						|
this is true (1), then `uint128` values are returned as a byte array, if it is
 | 
						|
false then they are returned as a `mmdb_uint128_t` integer.
 | 
						|
 | 
						|
### Data Type Macros
 | 
						|
 | 
						|
This library provides a macro for every data type defined by the MaxMind DB
 | 
						|
spec.
 | 
						|
 | 
						|
* `MMDB_DATA_TYPE_UTF8_STRING`
 | 
						|
* `MMDB_DATA_TYPE_DOUBLE`
 | 
						|
* `MMDB_DATA_TYPE_BYTES`
 | 
						|
* `MMDB_DATA_TYPE_UINT16`
 | 
						|
* `MMDB_DATA_TYPE_UINT32`
 | 
						|
* `MMDB_DATA_TYPE_MAP`
 | 
						|
* `MMDB_DATA_TYPE_INT32`
 | 
						|
* `MMDB_DATA_TYPE_UINT64`
 | 
						|
* `MMDB_DATA_TYPE_UINT128`
 | 
						|
* `MMDB_DATA_TYPE_ARRAY`
 | 
						|
* `MMDB_DATA_TYPE_BOOLEAN`
 | 
						|
* `MMDB_DATA_TYPE_FLOAT`
 | 
						|
 | 
						|
There are also a few types that are for internal use only:
 | 
						|
 | 
						|
* `MMDB_DATA_TYPE_EXTENDED`
 | 
						|
* `MMDB_DATA_TYPE_POINTER`
 | 
						|
* `MMDB_DATA_TYPE_CONTAINER`
 | 
						|
* `MMDB_DATA_TYPE_END_MARKER`
 | 
						|
 | 
						|
If you see one of these in returned data then something has gone very wrong.
 | 
						|
The database is damaged or was generated incorrectly or there is a bug in the
 | 
						|
libmaxminddb code.
 | 
						|
 | 
						|
### Pointer Values and `MMDB_close()`
 | 
						|
 | 
						|
The `utf8_string`, `bytes`, and (maybe) the `uint128` members of this structure
 | 
						|
are all pointers directly into the database's data section. This can either be
 | 
						|
a `calloc`'d or `mmap`'d block of memory. In either case, these pointers will
 | 
						|
become invalid after `MMDB_close()` is called.
 | 
						|
 | 
						|
If you need to refer to this data after that time you should copy the data
 | 
						|
with an appropriate function (`strdup`, `memcpy`, etc.).
 | 
						|
 | 
						|
## `MMDB_entry_data_list_s`
 | 
						|
 | 
						|
This structure encapsulates a linked list of `MMDB_entry_data_s` structures.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_entry_data_list_s {
 | 
						|
    MMDB_entry_data_s entry_data;
 | 
						|
    struct MMDB_entry_data_list_s *next;
 | 
						|
} MMDB_entry_data_list_s;
 | 
						|
```
 | 
						|
 | 
						|
This structure lets you look at entire map or array data entry by iterating
 | 
						|
over the linked list.
 | 
						|
 | 
						|
## `MMDB_search_node_s`
 | 
						|
 | 
						|
This structure encapsulates the two records in a search node. This is really
 | 
						|
only useful if you want to write code that iterates over the entire search
 | 
						|
tree as opposed to looking up a specific IP address.
 | 
						|
 | 
						|
```c
 | 
						|
typedef struct MMDB_search_node_s {
 | 
						|
    uint64_t left_record;
 | 
						|
    uint64_t right_record;
 | 
						|
    uint8_t left_record_type;
 | 
						|
    uint8_t right_record_type;
 | 
						|
    MMDB_entry_s left_record_entry;
 | 
						|
    MMDB_entry_s right_record_entry;
 | 
						|
} MMDB_search_node_s;
 | 
						|
```
 | 
						|
 | 
						|
The two record types will take one of the following values:
 | 
						|
 | 
						|
* `MMDB_RECORD_TYPE_SEARCH_NODE` - The record points to the next search node.
 | 
						|
* `MMDB_RECORD_TYPE_EMPTY` - The record is a placeholder that indicates there
 | 
						|
  is no data for the IP address. The search should end here.
 | 
						|
* `MMDB_RECORD_TYPE_DATA` - The record is for data in the data section of the
 | 
						|
  database. Use the entry for the record when looking up the data for the
 | 
						|
  record.
 | 
						|
* `MMDB_RECORD_TYPE_INVALID` - The record is invalid. Either an invalid node
 | 
						|
  was looked up or the database is corrupt.
 | 
						|
 | 
						|
The `MMDB_entry_s` for the record is only valid if the type is
 | 
						|
`MMDB_RECORD_TYPE_DATA`. Attempts to use an entry for other record types will
 | 
						|
result in an error or invalid data.
 | 
						|
 | 
						|
# STATUS CODES
 | 
						|
 | 
						|
This library returns (or populates) status codes for many functions. These
 | 
						|
status codes are:
 | 
						|
 | 
						|
* `MMDB_SUCCESS` - everything worked
 | 
						|
* `MMDB_FILE_OPEN_ERROR` - there was an error trying to open the MaxMind DB
 | 
						|
  file.
 | 
						|
* `MMDB_IO_ERROR` - an IO operation failed. Check `errno` for more details.
 | 
						|
* `MMDB_CORRUPT_SEARCH_TREE_ERROR` - looking up an IP address in the search
 | 
						|
  tree gave us an impossible result. The database is damaged or was generated
 | 
						|
  incorrectly or there is a bug in the libmaxminddb code.
 | 
						|
* `MMDB_INVALID_METADATA_ERROR` - something in the database is wrong. This
 | 
						|
  includes missing metadata keys as well as impossible values (like an
 | 
						|
  `ip_version` of 7).
 | 
						|
* `MMDB_UNKNOWN_DATABASE_FORMAT_ERROR` - The database metadata indicates that
 | 
						|
  it's major version is not 2. This library can only handle major version 2.
 | 
						|
* `MMDB_OUT_OF_MEMORY_ERROR` - a memory allocation call (`malloc`, etc.)
 | 
						|
  failed.
 | 
						|
* `MMDB_INVALID_DATA_ERROR` - an entry in the data section contains invalid
 | 
						|
  data. For example, a `uint16` field is claiming to be more than 2 bytes long.
 | 
						|
  The database is probably damaged or was generated incorrectly.
 | 
						|
* `MMDB_INVALID_LOOKUP_PATH_ERROR` - The lookup path passed to
 | 
						|
  `MMDB_get_value`, `MMDB_vget_value`, or `MMDB_aget_value` contains an array
 | 
						|
  offset that is larger than LONG_MAX or smaller than LONG_MIN.
 | 
						|
* `MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR` - The lookup path passed to
 | 
						|
  `MMDB_get_value`,`MMDB_vget_value`, or `MMDB_aget_value` does not match the
 | 
						|
  data structure for the entry. There are number of reasons this can
 | 
						|
  happen. The lookup path could include a key not in a map. The lookup path
 | 
						|
  could include an array index larger than an array or smaller than the
 | 
						|
  minimum offset from the end of an array. It can also happen when the path
 | 
						|
  expects to find a map or array where none exist.
 | 
						|
 | 
						|
All status codes should be treated as `int` values.
 | 
						|
 | 
						|
## `MMDB_strerror()`
 | 
						|
 | 
						|
```c
 | 
						|
const char *MMDB_strerror(int error_code)
 | 
						|
```
 | 
						|
 | 
						|
This function takes a status code and returns an English string explaining the
 | 
						|
status.
 | 
						|
 | 
						|
# FUNCTIONS
 | 
						|
 | 
						|
This library provides the following exported functions:
 | 
						|
 | 
						|
## `MMDB_open()`
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_open(
 | 
						|
    const char *const filename,
 | 
						|
    uint32_t flags,
 | 
						|
    MMDB_s *const mmdb);
 | 
						|
```
 | 
						|
 | 
						|
This function opens a handle to a MaxMind DB file. Its return value is a
 | 
						|
status code as defined above. Always check this call's return value.
 | 
						|
 | 
						|
```c
 | 
						|
MMDB_s mmdb;
 | 
						|
int status =
 | 
						|
    MMDB_open("/path/to/file.mmdb", MMDB_MODE_MMAP, &mmdb);
 | 
						|
if (MMDB_SUCCESS != status) { ... }
 | 
						|
...
 | 
						|
MMDB_close(&mmdb);
 | 
						|
```
 | 
						|
 | 
						|
`filename` must be encoded as UTF-8 on Windows.
 | 
						|
 | 
						|
The `MMDB_s` structure you pass in can be on the stack or allocated from the
 | 
						|
heap. However, if the open is successful it will contain heap-allocated data,
 | 
						|
so you need to close it with `MMDB_close()`. If the status returned is not
 | 
						|
`MMDB_SUCCESS` then this library makes sure that all allocated memory is freed
 | 
						|
before returning.
 | 
						|
 | 
						|
The flags currently provided are:
 | 
						|
 | 
						|
* `MMDB_MODE_MMAP` - open the database with `mmap()`.
 | 
						|
 | 
						|
Passing in other values for `flags` may yield unpredictable results. In the
 | 
						|
future we may add additional flags that you can bitwise-or together with the
 | 
						|
mode, as well as additional modes.
 | 
						|
 | 
						|
You can also pass `0` as the `flags` value in which case the database will be
 | 
						|
opened with the default flags. However, these defaults may change in future
 | 
						|
releases. The current default is `MMDB_MODE_MMAP`.
 | 
						|
 | 
						|
## `MMDB_close()`
 | 
						|
 | 
						|
```c
 | 
						|
void MMDB_close(MMDB_s *const mmdb);
 | 
						|
```
 | 
						|
 | 
						|
This frees any allocated or mmap'd memory that is held from the `MMDB_s`
 | 
						|
structure. *It does not free the memory allocated for the structure itself!*
 | 
						|
If you allocated the structure from the heap then you are responsible for
 | 
						|
freeing it.
 | 
						|
 | 
						|
## `MMDB_lookup_string()`
 | 
						|
 | 
						|
```c
 | 
						|
MMDB_lookup_result_s MMDB_lookup_string(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    const char *const ipstr,
 | 
						|
    int *const gai_error,
 | 
						|
    int *const mmdb_error);
 | 
						|
```
 | 
						|
 | 
						|
This function looks up an IP address that is passed in as a null-terminated
 | 
						|
string. Internally it calls `getaddrinfo()` to resolve the address into a
 | 
						|
binary form. It then calls `MMDB_lookup_sockaddr()` to look the address up in
 | 
						|
the database. If you have already resolved an address you can call
 | 
						|
`MMDB_lookup_sockaddr()` directly, rather than resolving the address twice.
 | 
						|
 | 
						|
```c
 | 
						|
int gai_error, mmdb_error;
 | 
						|
MMDB_lookup_result_s result =
 | 
						|
    MMDB_lookup_string(&mmdb, "1.2.3.4", &gai_error, &mmdb_error);
 | 
						|
if (0 != gai_error) { ... }
 | 
						|
if (MMDB_SUCCESS != mmdb_error) { ... }
 | 
						|
 | 
						|
if (result.found_entry) { ... }
 | 
						|
```
 | 
						|
 | 
						|
This function always returns an `MMDB_lookup_result_s` structure, but you
 | 
						|
should also check the `gai_error` and `mmdb_error` parameters. If either of
 | 
						|
these indicates an error then the returned structure is meaningless.
 | 
						|
 | 
						|
If no error occurred you still need to make sure that the `found_entry` member
 | 
						|
in the returned result is true. If it's not, this means that the IP address
 | 
						|
does not have an entry in the database.
 | 
						|
 | 
						|
This function will work with IPv4 addresses even when the database contains
 | 
						|
data for both IPv4 and IPv6 addresses. The IPv4 address will be looked up as
 | 
						|
'::xxx.xxx.xxx.xxx' rather than being remapped to the `::ffff:xxx.xxx.xxx.xxx`
 | 
						|
block allocated for IPv4-mapped IPv6 addresses.
 | 
						|
 | 
						|
If you pass an IPv6 address to a database with only IPv4 data then the
 | 
						|
`found_entry` member will be false, but the `mmdb_error` status will still be
 | 
						|
`MMDB_SUCCESS`.
 | 
						|
 | 
						|
## `MMDB_lookup_sockaddr()`
 | 
						|
 | 
						|
```c
 | 
						|
MMDB_lookup_result_s MMDB_lookup_sockaddr(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    const struct sockaddr *const sockaddr,
 | 
						|
    int *const mmdb_error);
 | 
						|
```
 | 
						|
 | 
						|
This function looks up an IP address that has already been resolved by
 | 
						|
`getaddrinfo()`.
 | 
						|
 | 
						|
Other than not calling `getaddrinfo()` itself, this function is identical to
 | 
						|
the `MMDB_lookup_string()` function.
 | 
						|
 | 
						|
```c
 | 
						|
int mmdb_error;
 | 
						|
MMDB_lookup_result_s result =
 | 
						|
    MMDB_lookup_sockaddr(&mmdb, address->ai_addr, &mmdb_error);
 | 
						|
if (MMDB_SUCCESS != mmdb_error) { ... }
 | 
						|
 | 
						|
if (result.found_entry) { ... }
 | 
						|
```
 | 
						|
 | 
						|
## Data Lookup Functions
 | 
						|
 | 
						|
There are three functions for looking up data associated with an IP address.
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_get_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    ...);
 | 
						|
int MMDB_vget_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    va_list va_path);
 | 
						|
int MMDB_aget_value(
 | 
						|
    MMDB_entry_s *const start,
 | 
						|
    MMDB_entry_data_s *const entry_data,
 | 
						|
    const char *const *const path);
 | 
						|
```
 | 
						|
 | 
						|
The three functions allow three slightly different calling styles, but they
 | 
						|
all do the same thing.
 | 
						|
 | 
						|
The first parameter is an `MMDB_entry_s` value. In most cases this will come
 | 
						|
from the `MMDB_lookup_result_s` value returned by `MMDB_lookup_string()` or
 | 
						|
`MMDB_lookup_sockaddr()`.
 | 
						|
 | 
						|
The second parameter is a reference to an `MMDB_entry_data_s` structure. This
 | 
						|
will be populated with the data that is being looked up, if any is found. If
 | 
						|
nothing is found, then the `has_data` member of this structure will be false.
 | 
						|
If `has_data` is true then you can look at the `data_type` member.
 | 
						|
 | 
						|
The final parameter is a lookup path. The path consists of a set of strings
 | 
						|
representing either map keys (e.g, "city") or array indexes (e.g., "0", "1",
 | 
						|
"-1") to use in the lookup.
 | 
						|
 | 
						|
Negative array indexes will be treated as an offset from the end of the array.
 | 
						|
For instance, "-1" refers to the last element of the array.
 | 
						|
 | 
						|
The lookup path allows you to navigate a complex data structure. For example,
 | 
						|
given this data:
 | 
						|
 | 
						|
```js
 | 
						|
{
 | 
						|
    "names": {
 | 
						|
        "en": "Germany",
 | 
						|
        "de": "Deutschland"
 | 
						|
    },
 | 
						|
    "cities": [ "Berlin", "Frankfurt" ]
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
We could look up the English name with this code:
 | 
						|
 | 
						|
```c
 | 
						|
MMDB_lookup_result_s result =
 | 
						|
    MMDB_lookup_sockaddr(&mmdb, address->ai_addr, &mmdb_error);
 | 
						|
MMDB_entry_data_s entry_data;
 | 
						|
int status =
 | 
						|
    MMDB_get_value(&result.entry, &entry_data,
 | 
						|
                   "names", "en", NULL);
 | 
						|
if (MMDB_SUCCESS != status) { ... }
 | 
						|
if (entry_data.has_data) { ... }
 | 
						|
```
 | 
						|
 | 
						|
If we wanted to find the first city the lookup path would be `"cities",
 | 
						|
"0"`. If you don't provide a lookup path at all, you'll get the entry which
 | 
						|
corresponds to the top level map. The lookup path must always end with `NULL`,
 | 
						|
regardless of which function you call.
 | 
						|
 | 
						|
The `MMDB_get_value` function takes a variable number of arguments. All of the
 | 
						|
arguments after the `MMDB_entry_data_s *` structure pointer are the lookup
 | 
						|
path. The last argument must be `NULL`.
 | 
						|
 | 
						|
The `MMDB_vget_value` function accepts a `va_list` as the lookup path. The
 | 
						|
last element retrieved by `va_arg()` must be `NULL`.
 | 
						|
 | 
						|
Finally, the `MMDB_aget_value` accepts an array of strings as the lookup
 | 
						|
path. The last member of this array must be `NULL`.
 | 
						|
 | 
						|
If you want to get all of the entry data at once you can call
 | 
						|
`MMDB_get_entry_data_list()` instead.
 | 
						|
 | 
						|
For each of the three functions, the return value is a status code as
 | 
						|
defined above.
 | 
						|
 | 
						|
## `MMDB_get_entry_data_list()`
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_get_entry_data_list(
 | 
						|
    MMDB_entry_s *start,
 | 
						|
    MMDB_entry_data_list_s **const entry_data_list);
 | 
						|
```
 | 
						|
 | 
						|
This function allows you to get all of the data for a complex data structure
 | 
						|
at once, rather than looking up each piece using repeated calls to
 | 
						|
`MMDB_get_value()`.
 | 
						|
 | 
						|
```c
 | 
						|
MMDB_lookup_result_s result =
 | 
						|
    MMDB_lookup_sockaddr(&mmdb, address->ai_addr, &mmdb_error);
 | 
						|
MMDB_entry_data_list_s *entry_data_list, *first;
 | 
						|
int status =
 | 
						|
    MMDB_get_entry_data_list(&result.entry, &entry_data_list);
 | 
						|
if (MMDB_SUCCESS != status) { ... }
 | 
						|
// save this so we can free this data later
 | 
						|
first = entry_data_list;
 | 
						|
 | 
						|
while (1) {
 | 
						|
    MMDB_entry_data_list_s *next = entry_data_list = entry_data_list->next;
 | 
						|
    if (NULL == next) {
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (next->entry_data.type) {
 | 
						|
        case MMDB_DATA_TYPE_MAP: { ... }
 | 
						|
        case MMDB_DATA_TYPE_UTF8_STRING: { ... }
 | 
						|
        ...
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
MMDB_free_entry_data_list(first);
 | 
						|
```
 | 
						|
 | 
						|
It's up to you to interpret the `entry_data_list` data structure. The list is
 | 
						|
linked in a depth-first traversal. Let's use this structure as an example:
 | 
						|
 | 
						|
```js
 | 
						|
{
 | 
						|
    "names": {
 | 
						|
        "en": "Germany",
 | 
						|
        "de": "Deutschland"
 | 
						|
    },
 | 
						|
    "cities": [ "Berlin", "Frankfurt" ]
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
The list will consist of the following items:
 | 
						|
 | 
						|
1. MAP - top level map
 | 
						|
2. UTF8_STRING - "names" key
 | 
						|
3. MAP - map for "names" key
 | 
						|
4. UTF8_STRING - "en" key
 | 
						|
5. UTF8_STRING - value for "en" key
 | 
						|
6. UTF8_STRING - "de" key
 | 
						|
7. UTF8_STRING - value for "de" key
 | 
						|
8. UTF8_STRING - "cities" key
 | 
						|
9. ARRAY - value for "cities" key
 | 
						|
10. UTF8_STRING - array[0]
 | 
						|
11. UTF8_STRING - array[1]
 | 
						|
 | 
						|
The return value of the function is a status code as defined above.
 | 
						|
 | 
						|
## `MMDB_free_entry_data_list()`
 | 
						|
 | 
						|
```c
 | 
						|
void MMDB_free_entry_data_list(
 | 
						|
    MMDB_entry_data_list_s *const entry_data_list);
 | 
						|
```
 | 
						|
 | 
						|
The `MMDB_get_entry_data_list()` and `MMDB_get_metadata_as_entry_data_list()`
 | 
						|
functions will allocate the linked list structure from the heap. Call this
 | 
						|
function to free the `MMDB_entry_data_list_s` structure.
 | 
						|
 | 
						|
## `MMDB_get_metadata_as_entry_data_list()`
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_get_metadata_as_entry_data_list(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    MMDB_entry_data_list_s **const entry_data_list);
 | 
						|
```
 | 
						|
 | 
						|
This function allows you to retrieve the database metadata as a linked list of
 | 
						|
`MMDB_entry_data_list_s` structures. This can be a more convenient way to deal
 | 
						|
with the metadata than using the metadata structure directly.
 | 
						|
 | 
						|
```c
 | 
						|
    MMDB_entry_data_list_s *entry_data_list, *first;
 | 
						|
    int status =
 | 
						|
        MMDB_get_metadata_as_entry_data_list(&mmdb, &entry_data_list);
 | 
						|
    if (MMDB_SUCCESS != status) { ... }
 | 
						|
    first = entry_data_list;
 | 
						|
    ... // do something with the data
 | 
						|
    MMDB_free_entry_data_list(first);
 | 
						|
```
 | 
						|
 | 
						|
The return value of the function is a status code as defined above.
 | 
						|
 | 
						|
## `MMDB_dump_entry_data_list()`
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_dump_entry_data_list(
 | 
						|
    FILE *const stream,
 | 
						|
    MMDB_entry_data_list_s *const entry_data_list,
 | 
						|
    int indent);
 | 
						|
```
 | 
						|
 | 
						|
This function takes a linked list of `MMDB_entry_data_list_s` structures and
 | 
						|
stringifies it to the given `stream`. The `indent` parameter is the starting
 | 
						|
indent level for the generated output. It is incremented for nested data
 | 
						|
structures (maps, array, etc.).
 | 
						|
 | 
						|
The `stream` must be a file handle (`stdout`, etc). If your platform provides
 | 
						|
something like the GNU `open_memstream()` you can use that to capture the
 | 
						|
output as a string.
 | 
						|
 | 
						|
The output is formatted in a JSON-ish fashion, but values are marked with their
 | 
						|
data type (except for maps and arrays which are shown with "{}" and "[]"
 | 
						|
respectively).
 | 
						|
 | 
						|
The specific output format may change in future releases, so you should not
 | 
						|
rely on the specific formatting produced by this function. It is intended to be
 | 
						|
used to show data to users in a readable way and for debugging purposes.
 | 
						|
 | 
						|
The return value of the function is a status code as defined above.
 | 
						|
 | 
						|
## `MMDB_read_node()`
 | 
						|
 | 
						|
```c
 | 
						|
int MMDB_read_node(
 | 
						|
    MMDB_s *const mmdb,
 | 
						|
    uint32_t node_number,
 | 
						|
    MMDB_search_node_s *const node);
 | 
						|
```
 | 
						|
 | 
						|
This reads a specific node in the search tree. The third argument is a
 | 
						|
reference to an `MMDB_search_node_s` structure that will be populated by this
 | 
						|
function.
 | 
						|
 | 
						|
The return value is a status code. If you pass a `node_number` that is greater
 | 
						|
than the number of nodes in the database, this function will return
 | 
						|
`MMDB_INVALID_NODE_NUMBER_ERROR`, otherwise it will return `MMDB_SUCCESS`.
 | 
						|
 | 
						|
The first node in the search tree is always node 0. If you wanted to iterate
 | 
						|
over the whole search tree, you would start by reading node 0 and then
 | 
						|
following the the records that make up this node, based on the type of each
 | 
						|
record. If the type is `MMDB_RECORD_TYPE_SEARCH_NODE` then the record contains
 | 
						|
an integer for the next node to look up.
 | 
						|
 | 
						|
## `MMDB_lib_version()`
 | 
						|
 | 
						|
```c
 | 
						|
const char *MMDB_lib_version(void)
 | 
						|
```
 | 
						|
 | 
						|
This function returns the library version as a string, something like "2.0.0".
 | 
						|
 | 
						|
# EXAMPLE
 | 
						|
 | 
						|
```c
 | 
						|
#include <errno.h>
 | 
						|
#include <maxminddb.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
    char *filename = argv[1];
 | 
						|
    char *ip_address = argv[2];
 | 
						|
 | 
						|
    MMDB_s mmdb;
 | 
						|
    int status = MMDB_open(filename, MMDB_MODE_MMAP, &mmdb);
 | 
						|
 | 
						|
    if (MMDB_SUCCESS != status) {
 | 
						|
        fprintf(stderr, "\n  Can't open %s - %s\n",
 | 
						|
                filename, MMDB_strerror(status));
 | 
						|
 | 
						|
        if (MMDB_IO_ERROR == status) {
 | 
						|
            fprintf(stderr, "    IO error: %s\n", strerror(errno));
 | 
						|
        }
 | 
						|
        exit(1);
 | 
						|
    }
 | 
						|
 | 
						|
    int gai_error, mmdb_error;
 | 
						|
    MMDB_lookup_result_s result =
 | 
						|
        MMDB_lookup_string(&mmdb, ip_address, &gai_error, &mmdb_error);
 | 
						|
 | 
						|
    if (0 != gai_error) {
 | 
						|
        fprintf(stderr,
 | 
						|
                "\n  Error from getaddrinfo for %s - %s\n\n",
 | 
						|
                ip_address, gai_strerror(gai_error));
 | 
						|
        exit(2);
 | 
						|
    }
 | 
						|
 | 
						|
    if (MMDB_SUCCESS != mmdb_error) {
 | 
						|
        fprintf(stderr,
 | 
						|
                "\n  Got an error from libmaxminddb: %s\n\n",
 | 
						|
                MMDB_strerror(mmdb_error));
 | 
						|
        exit(3);
 | 
						|
    }
 | 
						|
 | 
						|
    MMDB_entry_data_list_s *entry_data_list = NULL;
 | 
						|
 | 
						|
    int exit_code = 0;
 | 
						|
    if (result.found_entry) {
 | 
						|
        int status = MMDB_get_entry_data_list(&result.entry,
 | 
						|
                                              &entry_data_list);
 | 
						|
 | 
						|
        if (MMDB_SUCCESS != status) {
 | 
						|
            fprintf(
 | 
						|
                stderr,
 | 
						|
                "Got an error looking up the entry data - %s\n",
 | 
						|
                MMDB_strerror(status));
 | 
						|
            exit_code = 4;
 | 
						|
            goto end;
 | 
						|
        }
 | 
						|
 | 
						|
        if (NULL != entry_data_list) {
 | 
						|
            MMDB_dump_entry_data_list(stdout, entry_data_list, 2);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        fprintf(
 | 
						|
            stderr,
 | 
						|
            "\n  No entry for this IP address (%s) was found\n\n",
 | 
						|
            ip_address);
 | 
						|
        exit_code = 5;
 | 
						|
    }
 | 
						|
 | 
						|
    end:
 | 
						|
        MMDB_free_entry_data_list(entry_data_list);
 | 
						|
        MMDB_close(&mmdb);
 | 
						|
        exit(exit_code);
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
# THREAD SAFETY
 | 
						|
 | 
						|
This library is thread safe when compiled and linked with a thread-safe
 | 
						|
`malloc` and `free` implementation.
 | 
						|
 | 
						|
# INSTALLATION AND SOURCE
 | 
						|
 | 
						|
You can download the latest release of libmaxminddb
 | 
						|
[from GitHub](https://github.com/maxmind/libmaxminddb/releases).
 | 
						|
 | 
						|
[Our GitHub repo](https://github.com/maxmind/libmaxminddb) is publicly
 | 
						|
available. Please fork it!
 | 
						|
 | 
						|
# BUG REPORTS AND PULL REQUESTS
 | 
						|
 | 
						|
Please report all issues to
 | 
						|
[our GitHub issue tracker](https://github.com/maxmind/libmaxminddb/issues). We
 | 
						|
welcome bug reports and pull requests. Please note that pull requests are
 | 
						|
greatly preferred over patches.
 | 
						|
 | 
						|
# AUTHORS
 | 
						|
 | 
						|
This library was written by Boris Zentner (bzentner@maxmind.com) and Dave
 | 
						|
Rolsky (drolsky@maxmind.com).
 | 
						|
 | 
						|
# COPYRIGHT AND LICENSE
 | 
						|
 | 
						|
Copyright 2013-2014 MaxMind, Inc.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
 | 
						|
# SEE ALSO
 | 
						|
 | 
						|
mmdblookup(1)
 |