Squashed 'src/deps/src/libmaxminddb/' content from commit ac4d0d248

git-subtree-dir: src/deps/src/libmaxminddb
git-subtree-split: ac4d0d2480032a8664e251588e57d7b306ca630c
This commit is contained in:
Théophile Diot 2023-06-30 15:37:55 -04:00
commit bb450ac965
94 changed files with 12768 additions and 0 deletions

5
.clang-format Normal file
View File

@ -0,0 +1,5 @@
BasedOnStyle: LLVM
IndentWidth: 4
BinPackArguments: false
BinPackParameters: false
IndentCaseLabels: true

View File

@ -0,0 +1,26 @@
name: Run Clang AddressSanitizer
on:
push:
pull_request:
schedule:
- cron: '13 20 * * SUN'
jobs:
addresssanitizer:
name: Clang AddressSanitizer
runs-on: ubuntu-latest
env:
ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_invalid_pointer_pairs=2
CC: clang
CXX: clang++
CFLAGS: -fsanitize=address -Wall -Wextra -Wpedantic -Wformat=2 -Walloca -Wvla -Wimplicit-fallthrough -Wcast-qual -Wconversion -Wshadow -Wundef -Wstrict-prototypes -Wswitch-enum -fstack-protector -D_FORTIFY_SOURCE=2
CXXFLAGS: -fsanitize=address
LDFLAGS: -fsanitize=address
steps:
- uses: actions/checkout@v2
with:
submodules: true
- run: sudo apt install clang libipc-run3-perl
- run: ./bootstrap
- run: ./configure
- run: make
- run: make check

19
.github/workflows/clang-analyzer.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Run Clang Static Analysis
on:
push:
pull_request:
schedule:
- cron: '3 20 * * SUN'
jobs:
clang-analyzer:
name: Clang static analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt install clang-tools libipc-run3-perl
- run: ./bootstrap
- run: scan-build ./configure
env:
CFLAGS: -std=c99 -Wall -Wextra -Werror -Wno-unused-function -Wno-unused-parameter -Wno-unknown-pragmas
- run: cd src; scan-build --status-bugs make; cd ..
- run: cd bin; scan-build --status-bugs make; cd ..

40
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: "Code scanning - action"
on:
push:
pull_request:
schedule:
- cron: '0 7 * * 2'
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
submodules: true
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
- run: sudo apt install libipc-run3-perl libipc-system-simple-perl libfile-slurp-perl libfile-which-perl pandoc
- run: |
./bootstrap
./configure
make
make safedist
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

48
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,48 @@
name: Run tests
on:
push:
pull_request:
schedule:
- cron: '3 20 * * SUN'
jobs:
test-autoconf:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
cc: [gcc, clang]
posix: ['', -D_POSIX_C_SOURCE=200112L]
name: Autotools build on ${{matrix.os}} using ${{matrix.cc}} ${{matrix.posix}}
runs-on: ${{ matrix.os }}
env:
CC: ${{ matrix.cc }}
VERBOSE: 1
steps:
- uses: actions/checkout@v2
with:
submodules: true
- run: sudo apt install libipc-run3-perl
if: ${{ matrix.os == 'ubuntu-latest' }}
- run: brew install autoconf automake libtool
if: ${{ matrix.os == 'macos-latest' }}
- run: ./bootstrap
- run: ./configure
env:
# -Wno-unknown-pragmas because we have some Clang specific pragmas
# which aren't interesting to cause failures for.
CFLAGS: -std=c99 -Wall -Wextra -Werror -Wno-unused-function -Wno-unused-parameter -Wno-unknown-pragmas ${{ matrix.posix }}
- run: make
- run: make check
test-cmake:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
name: CMake build on ${{matrix.os}}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: true
- run: cmake -DBUILD_TESTING=ON .
- run: cmake --build .
- run: ctest -V . -C Debug

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
*.a
*.la
*.lo
*.o
*.so
*.swp
*/.deps
*/.libs
*~
.\#*
.gh-pages
/INSTALL
/autom4te.cache
/bin/country_lookup
/bin/mmdbdump
/bin/mmdblookup
/compile
/config.*
/configure
/depcomp
/include/maxminddb_config.h
/install-sh
/libmaxminddb-*
/libtool
/ltmain.sh
/man
/missing
/src/libmaxminddb.pc
/src/test-data-pool
/t/*.log
/t/*.trs
/t/*_t
/t/*-t
/test-driver
\#*\#
aclocal.m4
stamp-h*
CMakeCache.txt
CMakeFiles/
CTestTestfile.cmake
cmake_install.cmake
Makefile
Makefile.in
Testing/
install_manifest.txt

9
.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule "maxmind-db"]
path = maxmind-db
url = https://github.com/maxmind/MaxMind-DB.git
[submodule "t/libtap"]
path = t/libtap
url = https://github.com/zorgnax/libtap.git
[submodule "t/maxmind-db"]
path = t/maxmind-db
url = https://github.com/maxmind/MaxMind-DB.git

11
.perltidyrc Normal file
View File

@ -0,0 +1,11 @@
--blank-lines-before-packages=0
--iterations=2
--no-outdent-long-comments
-bar
-boc
-ci=4
-i=4
-l=78
-nolq
-se
-wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x="

0
AUTHORS Normal file
View File

121
CMakeLists.txt Normal file
View File

@ -0,0 +1,121 @@
cmake_minimum_required (VERSION 3.9)
project(maxminddb
LANGUAGES C
VERSION 1.7.1
)
set(MAXMINDDB_SOVERSION 0.0.7)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS OFF)
if (WIN32)
option(MSVC_STATIC_RUNTIME "When ON the library will be built by using MT/MTd run-time libraries" OFF)
endif()
option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF)
option(BUILD_TESTING "Build test programs" ON)
include(GNUInstallDirs)
include(CheckTypeSize)
check_type_size("unsigned __int128" UINT128)
check_type_size("unsigned int __attribute__((mode(TI)))" UINT128_USING_MODE)
if(HAVE_UINT128)
set(MMDB_UINT128_USING_MODE 0)
set(MMDB_UINT128_IS_BYTE_ARRAY 0)
elseif(HAVE_UINT128_USING_MODE)
set(MMDB_UINT128_USING_MODE 1)
set(MMDB_UINT128_IS_BYTE_ARRAY 0)
else()
set(MMDB_UINT128_USING_MODE 0)
set(MMDB_UINT128_IS_BYTE_ARRAY 1)
endif()
include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
configure_file(${PROJECT_SOURCE_DIR}/include/maxminddb_config.h.cmake.in
${PROJECT_SOURCE_DIR}/include/maxminddb_config.h)
add_library(maxminddb
src/maxminddb.c
src/data-pool.c
)
add_library(maxminddb::maxminddb ALIAS maxminddb)
set_target_properties(maxminddb PROPERTIES VERSION ${MAXMINDDB_SOVERSION})
target_compile_definitions(maxminddb PUBLIC PACKAGE_VERSION="${PROJECT_VERSION}")
if(NOT IS_BIG_ENDIAN)
target_compile_definitions(maxminddb PRIVATE MMDB_LITTLE_ENDIAN=1)
endif()
if(MSVC)
target_compile_definitions(maxminddb PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
if(WIN32)
target_link_libraries(maxminddb ws2_32)
if(BUILD_SHARED_LIBS)
set_target_properties(maxminddb PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
if(MSVC_STATIC_RUNTIME)
# On MSVC, when MSVC_STATIC_RUNTIME is ON, MT (Release) and MTd (Debug)
# run-time libraries will be used instead of MD/MDd. The default is OFF so
# MD/MDd are used when nothing related is passed.
#
# Adapted from https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#make-override-files
set(CMAKE_USER_MAKE_RULES_OVERRIDE
${CMAKE_CURRENT_SOURCE_DIR}/c_flag_overrides.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
${CMAKE_CURRENT_SOURCE_DIR}/cxx_flag_overrides.cmake)
endif()
endif()
target_include_directories(maxminddb PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
set(MAXMINDB_HEADERS
include/maxminddb.h
include/maxminddb_config.h
)
set_target_properties(maxminddb PROPERTIES PUBLIC_HEADER "${MAXMINDB_HEADERS}")
install(TARGETS maxminddb
EXPORT maxminddb)
# This is required to work with FetchContent
install(EXPORT maxminddb
FILE maxminddb-config.cmake
NAMESPACE maxminddb::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/maxminddb)
# We always want to build mmdblookup
add_subdirectory(bin)
if (BUILD_TESTING)
enable_testing()
add_subdirectory(t)
endif()
# Generate libmaxminddb.pc file for pkg-config
# Set the required variables as same with autotools
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix \${prefix})
set(libdir \${exec_prefix}/lib)
set(includedir \${prefix}/include)
set(PACKAGE_VERSION ${maxminddb_VERSION})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/libmaxminddb.pc.in
${CMAKE_CURRENT_BINARY_DIR}/src/libmaxminddb.pc
@ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/src/libmaxminddb.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

384
Changes.md Normal file
View File

@ -0,0 +1,384 @@
## 1.7.1 - 2022-09-30
* The external symbols test now only runs on Linux. It assumes a Linux
environment. Reported by Carlo Cabrera. GitHub #304.
## 1.7.0 - 2022-09-28
* `FD_CLOEXEC` is now set on platforms that do not support `O_CLOEXEC`.
Reported by rittneje. GitHub #273.
* When building with Visual Studio, you may now build a static runtime with
CMake by setting `MSVC_STATIC_RUNTIME` to `ON`. Pull request by Rafael
Santiago. GitHub #269.
* The CMake build now works on iOS. Pull request by SpaceIm. GitHub #271.
* The CMake build now uses the correct library directory on Linux systems
using alternate directory structures. Pull request by Satadru Pramanik.
GitHub #284.
* File size check now correctly compares the size to `SSIZE_MAX`. Reported
by marakew. GitHub #301.
## 1.6.0 - 2021-04-29
* This release includes several improvements to the CMake build. In
particular:
* C99 support is now properly enabled, fixing builds on older `gcc`
versions. Pull request by Jan Včelák. GitHub #257.
* `CMAKE_SHARED_LIBRARY_PREFIX` and `CMAKE_STATIC_LIBRARY_PREFIX` are
no longer explicitly set and now use the default values for the platform.
Pull request by Jan Včelák. GitHub #258.
* `target_include_directories` now works as expected. Pull request by Jan
Včelák. GitHub #259.
* DLLs are now installed on Windows when `libmaxminddb` is built as a
shared library. Pull request by Jan Včelák. GitHub #261.
* When built as a dynamic library on Windows, all symbols are now exported.
Pull request by Jan Včelák. GitHub #262.
## 1.5.2 - 2021-02-18
* With `libmaxminddb` on Windows and `mmdblookup` generally, there were
instances where the return value of `calloc` was not checked, which could
lead to issues in low memory situations or when resource limits had been
set. Reported by cve-reporting. GitHub #252.
## 1.5.1 - 2021-02-18
* The formatting of the manpages has been improved and the script that
generates them now supports `lowdown` in addition to `pandoc`. Pull request
by Faidon Liambotis. GitHub #248.
## 1.5.0 - 2021-01-05
* A CMake build script has been added for Windows builds. The Visual
Studio project files in `projects` are now considered deprecated and will
be removed in a future release.
## 1.4.3 - 2020-08-06
* On Windows, always call `CreateFileW` instead of `CreateFile`.
`CreateFile` could be mapped to `CreateFileA` and not work as expected.
Pull request by Sandu Liviu Catalin. GitHub #228.
* Fixed use of uninitialized memory in `dump_entry_data_list()` that could
cause a heap buffer overflow in `mmdblookup`. As part of this fix, most
uses of `malloc` were replaced with `calloc`. Reported by azhou. GitHub
#236.
## 1.4.2 - 2019-11-02
* The 1.4.0 release introduced a change that increased the size of `MMDB_s`,
unintentionally causing an ABI break. This release reverts the relevant
commit.
## 1.4.1 - 2019-11-01
* The man page links for function calls were not generated correctly in
1.4.0. This has been corrected.
## 1.4.0 - 2019-11-01
* A negative array index may now be used with `MMDB_get_value`,
`MMDB_vget_value`, and `MMDB_aget_value`. This specifies the element
from the end of the array. For instance, `-1` would refer to the
last element of the array. PR by Kyle Box. GitHub #205.
* On Windows, the file name passed to `MMDB_open` is now expected to be
UTF-8 encoded. This allows Unicode characters to be used in file names.
As part of this change, `mmdblookup` on Windows now converts its
arguments to UTF-8. PR by Gerald Combs. GitHub #189 & #191.
* Fix a memory leak that occurred when freeing an `MMDB_s` where the
database had no languages defined in the metadata. If you are using an
official MaxMind database, this leak does not affect you. Pull request
by Kókai Péter. GitHub #180.
* Add `--disable-binaries` option to `configure`. Pull request by Fabrice
Fontaine. GitHub #166.
* Previous releases incorrectly included `*.Po` files in the `t` directory.
This has been corrected. Reported by Daniel Macks. GitHub #168.
* The internal use of the `MMDB_s` now has the `const` modifier. Public
functions that accepted an `MMDB_s` as an argument now also declare it as
`const`. Pull request by Kurt Johnson. GitHub #199.
* `mmdblookup` now displays the prefix length for the record when using
the verbose flag. GitHub #172.
## 1.3.2 - 2018-01-17
* Allocate memory for `MMDB_entry_data_list_s` structs in separate chunks
rather than one large chunk. This simplifies accessing memory in
`MMDB_get_entry_data_list()` and increases performance. It builds on the
changes in 1.3.0 and 1.3.1.
* We no longer export `data_pool_*` symbols. These are internal functions
but we were previously exporting them. Pull request by Faidon Liambotis.
GitHub #162.
* Build with POSIX.1-2008 by default if the system supports it. This allows
use of `open()` with `O_CLOEXEC`. We retain support for systems that
provide only POSIX.1-2001.
* Open the database with the `O_CLOEXEC` flag if the system provides it.
This avoids cases where we could leak fds when called in multi-threaded
programs that `fork()` and `exec()`. Original report and PR by Brandon L
Black.
* Added a test to ensure we export only intended symbols (e.g. MMDB_*).
## 1.3.1 - 2017-11-24
* Fix build problems related to `rpl_malloc()`. Pull request by Rainer
Gerhards. GitHub #152.
* Fix a race to set and read data in a field on the `MMDB_s` struct
(`ipv4_start_node`). GitHub #153.
* Fix cases of invalid memory access when using
`MMDB_get_entry_data_list()`. This was introduced in 1.3.0 and occurred
when performing large lookups. GitHub #153.
## 1.3.0 - 2017-11-10
* Perform fewer memory allocations in `MMDB_get_entry_data_list()`. This
significantly improves its performance. GitHub #147.
* Fix `mmdblookup`'s build epoch reporting on some systems. Big endian
systems with a 32-bit `time_t` no longer show a database build date of
1970-01-01 00:00:00. Pull request by Rainer Jung. GitHub #143.
## 1.2.1 - 2017-05-15
* Use autoconf to check the system's endianness rather than trying to do this
with compiler-defined macros like `__BYTE_ORDER__`. Apparently this didn't
work properly on a Sparc system. GitHub #120.
* Several compiler warnings on Visual C++ were fixed. Pull request by Marcel
Raad. GitHub #130.
* Fix segmentation faults found in `MMDB_open()` using afl-fuzz. This
occurred on corrupt databases that had a data pointer large enough to
cause an integer overflow when doing bound checking. Reported by Ryan
Whitworth. GitHub #140.
* Add --disable-tests option to `configure`. Pull request by Fabrice
Fontaine. GitHub #136.
## 1.2.0 - 2016-03-23
* Four additional fields were added to the end of the `MMDB_search_node_s`
struct returned by `MMDB_read_node`. These fields allow the user to iterate
through the search tree without making undocumented assumptions about how
this library works internally and without knowing the specific details of
the database format. GitHub #110.
## 1.1.5 - 2016-03-20
* Previously, reading a database with a pointer in the metadata would cause an
`MMDB_INVALID_METADATA_ERROR` to be returned. This was due to an invalid
offset being used when calculating the pointer. The `data_section` and
`metadata_section` fields now both point to the beginning of the data
section. Previously, `data_section` pointed to the beginning of the data
separator. This will not affect anyone using only documented fields from
`MMDB_s`.
* `MMDB_lookup_sockaddr` will set `mmdb_error` to
`MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR` if an IPv6 `sockaddr` is looked up
in an IPv4-only database. Previously only `MMDB_lookup_string` would set
this error code.
* When resolving an address, this library now relies on `getaddrinfo` to
determine the address family rather than trying to guess it itself.
## 1.1.4 - 2016-01-06
* Packaging fixes. The 1.1.3 tarball release contained a lot of extra junk in
the t/ directory.
## 1.1.3 - 2016-01-05
* Added several additional checks to make sure that we don't attempt to read
past the end of the databases's data section. Implemented by Tobias
Stoeckmann. GitHub #103.
* When searching for the database metadata, there was a bug that caused the
code to think it had found valid metadata when none existed. In addition,
this could lead to an attempt to read past the end of the database
entirely. Finally, if there are multiple metadata markers in the database,
we treat the final one as the start of the metdata, instead of the first.
Implemented by Tobias Stoeckmann. GitHub #102.
* Don't attempt to mmap a file that is too large to be mmapped on the
system. Implemented by Tobias Stoeckmann. GitHub #101.
* Added a missing out of memory check when reading a file's
metadata. Implemented by Tobias Stoeckmann. GitHub #101.
* Added several additional checks to make sure that we never attempt to
`malloc` more than `SIZE_MAX` memory, which would lead to integer
overflow. This could only happen with pathological databases. Implemented by
Tobias Stoeckmann. GitHub #101.
## 1.1.2 - 2015-11-16
* IMPORTANT: This release includes a number of important security fixes. Among
these fixes is improved validation of the database metadata. Unfortunately,
MaxMind GeoIP2 and GeoLite2 databases created earlier than January 28, 2014
had an invalid data type for the `record_size` in the metadata. Previously
these databases worked on little endian machines with libmaxminddb but did
not work on big endian machines. Due to increased safety checks when reading
the file, these databases will no longer work on any platform. If you are
using one of these databases, we recommend that you upgrade to the latest
GeoLite2 or GeoIP2 database
* Added pkg-config support. If your system supports it, then running `make
install` now installs a `libmaxminddb.pc` file for pkgconfig. Implemented by
Jan Vcelak.
* Several segmentation faults found with afl-fuzz were fixed. These were
caused by missing bounds checking and missing data type verification checks.
* `MMDB_get_entry_data_list` will now fail on data structures with a depth
greater than 512 and data structures that are cyclic. This should not
affect any known MaxMind DB in production. All databases produced by
MaxMind have a depth of less than five.
## 1.1.1 - 2015-07-22
* Added `maxminddb-compat-util.h` as a source file to dist.
## 1.1.0 - 2015-07-21
* Previously, when there was an error in `MMDB_open()`, `errno` would
generally be overwritten during cleanup, preventing a useful value from
being returned to the caller. This was changed so that the `errno` value
from the function call that caused the error is restored before returning to
the caller. In particular, this is important for `MMDB_IO_ERROR` errors as
checking `errno` is often the only way to determine what actually failed.
* If `mmap()` fails due to running out of memory space, an
`MMDB_OUT_OF_MEMORY_ERROR` is now returned from `MMDB_open` rather than an
`MMDB_IO_ERROR`.
* On Windows, the `CreateFileMappingA()` handle was not properly closed if
opening the database succeeded. Fixed by Bly Hostetler. GitHub #75 & #76.
* On Windows, we were not checking the return value of `CreateFileMappingA()`
properly for errors. Fixed by Bly Hotetler. GitHub #78.
* Several warnings from Clang's scan-build were fixed. GitHub #86.
* All headers are now installed in `$(includedir)`. GitHub #89.
* We no longer install `maxminddb-compat-util.h`. This header was intended for
internal use only.
## 1.0.4 - 2015-01-02
* If you used a non-integer string as an array index when doing a lookup with
`MMDB_get_value()`, `MMDB_vget_value()`, or `MMDB_aget_value()`, the first
element of the array would be returned rather than an error. A
`MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR` error will now be returned.
GitHub #61.
* If a number larger than `LONG_MAX` was used in the same functions,
`LONG_MAX` would have been used in the lookup. Now a
`MMDB_INVALID_LOOKUP_PATH_ERROR` error will be returned.
* Visual Studio build files were added for unit tests and some compatibility
issues with the tests were fixed.
* Visual Studio project was updated to use property pages. Patch by Andre.
GitHub #69.
* A test failure in `t/compile_c++_t.pl` on new installs was fixed.
## 1.0.3 - 2014-12-02
* A memory and file handle leak on Win32 was fixed when getting the database
size fails. Patch by Federico G. Schwindt. GitHub PR #49.
* Documentation fix. Federico G. Schwindt. GitHub PR #50.
* Added Visual Studio build files and fixed incorrect CreateFileMappingA
usage. Patch by Andre. GitHub #52.
* The includes for the Windows header files were made lowercase in order to
match the actual file names on case-sensitive file systems. GitHub PR #57.
* Removed `realloc()` calls that caused warnings on Windows and generally
cleaned up memory allocation in `MMDB_vget_value()`. See relevant discussion
in GitHub #52.
* Added an `extern "C" { ... }` wrapper to maxminddb.h when compiling with a
C++ compiler. GitHub #55.
## 1.0.2 - 2014-09-22
* Fixed a number of small issues found by Coverity.
* When freeing the MMDB struct in `MMDB_close()` we make sure to set the
pointers to NULL after freeing the memory they point to. This makes it safe
to call `MMDB_close` more than once on the same `MMDB_s` struct
pointer. Before this change, calling this function twice on the same pointer
could cause the code to free memory that belonged to something else in the
process. Patch by Shuxin Yang. GitHub PR #41.
## 1.0.1 - 2014-09-03
* Added missing LICENSE and NOTICE files to distribution. No code changes.
## 1.0.0 - 2014-09-02
* Bumped version to 1.0.0. No code changes.
## 0.5.6 - 2014-07-21
* There was a leak in the `MMDB_open()` sub when it was called against a file
which did not contain any MMDB metadata. Reported by Federico
G. Schwindt. GitHub issue #36.
* Fixed an error that occurred when passing AI_V4MAPPED to `getaddrinfo()` on
FreeBSD. Apparently this macro is defined but doesn't work the way we
expected it to on that platform.
* Made sure to call `freeaddrinfo()` when a call to `getaddrinfo()` fails but
still allocated memory.
* Fixed a segfault in the tests that occurred on FreeBSD if we passed a NULL
value to `freeaddrinfo()`.
* Added a missing step to the README.md file for installing from our GitHub
repository. Patch by Yasith Fernando.
* Added instructions for installing via Homebrew. Patch by Yasith Fernando.
## 0.5.5 - 2014-03-11
* The previous tarball failed to compile because it was missing the
src/maxminddb-compat-util.h file. Reported by Günter Grodotzki. GitHub issue
#18.
## 0.5.4 - 2014-03-03
* Added support for compiling in the MinGW environment. Patch by Michael
Eisendle.
* Added const declarations to many spots in the public API. None of these
should require changes to existing code.
* Various documentation improvements.
* Changed the license to the Apache 2.0 license.
## 0.5.3 - 2013-12-23
* The internal value_for_key_as_uint16 method was returning a uint32_t instead
of a uint16_t. Reported by Robert Wells. GitHub issue #11.
* The ip_version member of the MMDB_metadata_s struct was a uint8_t, even
though the docs and spec said it should be a uint16_t. Reported by Robert
Wells. GitHub issue #11.
* The mmdblookup_t.pl test now reports that it needs IPC::Run3 to run (which
it always did, but it didn't tell you this). Patch by Elan Ruusamäe. GitHub
issue #10.
## 0.5.2 - 2013-11-20
* Running `make` from the tarball failed. This is now fixed.
## 0.5.1 - 2013-11-20
* Renamed MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA define to
MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR for consistency. Fixes github
issue #5. Reported by Albert Strasheim.
* Updated README.md to show git clone with --recursive flag so you get the
needed submodules. Fixes github issue #4. Reported by Ryan Peck.
* Fixed some bugs with the MMDB_get_*value functions when navigating a data
structure that included pointers. Fixes github issue #3. Reported by
bagadon.
* Fixed compilation problems on OSX and OpenBSD. We have tested this on OSX
and OpenBSD 5.4. Fixes github issue #6.
* Removed some unneeded memory allocations and added const to many variable
declarations. Based on patches by Timo Teräs. Github issue #8.
* Added a test that uses threads to check for thread safety issue in the
library.
* Distro tarball now includes man pages, tests, and test data

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

48
Makefile.am Normal file
View File

@ -0,0 +1,48 @@
include_HEADERS = include/maxminddb.h
nodist_include_HEADERS = include/maxminddb_config.h
SUBDIRS = \
src
if BINARIES
SUBDIRS += \
bin
endif
if TESTS
SUBDIRS += \
t
endif
EXTRA_DIST = doc Changes.md LICENSE NOTICE README.md projects/VS12 projects/VS12-tests \
CMakeLists.txt t/CMakeLists.txt bin/CMakeLists.txt \
include/maxminddb_config.h.cmake.in
dist-hook:
dev-bin/make-man-pages.pl $(distdir)
find $(distdir) -name '.git*' | xargs rm -fr
safedist: clean dist
tmpdir="$${TMPDIR-/tmp}/safedist-$$$$" \
&& mkdir "$$tmpdir" \
&& tar -xvf $(distdir).tar.gz --directory "$$tmpdir" \
&& $(am__cd) "$$tmpdir/$(distdir)" \
&& ./configure \
&& make -j 4 check
man1_MANS = man/man1/*.1
man3_MANS = man/man3/*.3
man/man1/*.1:
if [ ! -f man/man1/mmdblookup.1 ]; then mkdir -p man/man1 && touch man/man1/mmdblookup.1; fi
man/man3/*.3:
if [ ! -f man/man3/libmaxminddb.3 ]; then mkdir -p man/man3 && touch man/man3/libmaxminddb.3; fi
release:
dev-bin/make-release.sh
.PHONY: man/man1/*.1 man/man3/*.3 release

13
NOTICE Normal file
View File

@ -0,0 +1,13 @@
Copyright 2013-2022 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.

77
README.dev.md Normal file
View File

@ -0,0 +1,77 @@
# Releasing this library
We release by uploading the tarball to GitHub and uploading Ubuntu PPAs.
## Creating the release tarball
You may want to refer to the section about prerequisites.
* Check whether there are any open issues to fix while you're doing this.
* Update `Changes.md` to include specify the new version, today's date, and
list relevant changes. Commit this.
* Create a new branch off of the latest `main` for the release.
* Run `./dev-bin/release.sh` to update various files in the distro, our
GitHub pages, and creates a GitHub release with the tarball.
* Check the release looks good on both GitHub and launchpad.net.
* Make a pull request against `main` with the changes from the release
script.
## PPA
In order to upload a PPA, you have to create a launchpad.net account and
register a GPG key with that account. You also need to be added to the MaxMind
team. Ask in the dev channel for someone to add you. See
https://help.launchpad.net/Packaging/PPA for more details.
The PPA release script is at `dev-bin/ppa-release.sh`. Running it should
guide you though the release, although it may require some changes to run on
configurations different than Greg's machine.
Check whether any new Ubuntu versions need to be listed in this script
before running it.
You should run it from `main`.
## Homebrew (optional)
Releasing to Homebrew is no longer required as the formulas are easily
updated by the end-user using a built-in feature in the tool. These
directions remain in case there is a more significant change to the
build process that may require a non-trivial update to the formula or
in the case where we want the Homebrew version updated promptly for
some reason.
* Go to https://github.com/Homebrew/homebrew-core/edit/master/Formula/libmaxminddb.rb
* Edit the file to update the url and sha256. You can get the sha256 for the
tarball with the `sha256sum` command line utility.
* Make a commit with the summary `libmaxminddb <VERSION>`
* Submit a PR with the changes you just made.
# Prerequisites for releasing
* Required packages (Ubuntu Artful): vim git-core dput build-essential
autoconf automake libtool git-buildpackage libfile-slurp-perl pandoc
dirmngr libfile-slurp-tiny-perl libdatetime-perl debhelper dh-autoreconf
libipc-run3-perl libtest-output-perl devscripts
* Install [gh](https://github.com/cli/cli/releases).
* GitHub ssh key (e.g. in `~/.ssh/id_rsa`)
* Git config (e.g. `~/.gitconfig`)
* Import your GPG secret key (or create one if you don't have a suitable
one)
* `gpg --import /path/to/key`
* `gpg --edit-key KEYID` and trust it ultimately
* Ensure it shows with `gpg --list-secret-keys`
* You need to be invited to the launchpad.net MaxMind organization on your
launchpad.net account.
* You need your GPG key listed on your launchpad.net account
* You can add it in the web interface. It wants the output of
`gpg --fingerprint`.
* Part of the instructions involve having your key published on the
Ubuntu keyserver:
`gpg --keyserver keyserver.ubuntu.com --send-keys KEYID`
* You'll get an email with an encrypted payload that you need to decrypt
and follow the link to confirm it.
* Ensure `dch` knows your name and email. Refer to its man page for how to
tell it this. One way is to set the `DEBFULLNAME` and `DEBEMAIL`
environment variables. These should match your GPG key's name and email
exactly. This is what gets used in the Debian changelog as well as
defines what GPG key to use.

136
README.md Normal file
View File

@ -0,0 +1,136 @@
# About
The libmaxminddb library provides a C library for reading MaxMind DB files,
including the GeoIP2 databases from MaxMind. This is a custom binary format
designed to facilitate fast lookups of IP addresses while allowing for great
flexibility in the type of data associated with an address.
The MaxMind DB format is an open format. The spec is available at
https://maxmind.github.io/MaxMind-DB/. This spec is licensed under the
Creative Commons Attribution-ShareAlike 3.0 Unported License.
See https://dev.maxmind.com/ for more details about MaxMind's GeoIP2 products.
# License
This library is licensed under the Apache License, Version 2.
# Installation
## From a Named Release Tarball
**NOTE:** These instructions are for installation from the _named_ `.tar.gz`
tarballs on the [Releases](https://github.com/maxmind/libmaxminddb/releases)
page (e.g. `libmaxminddb-*.tar.gz`).
This code is known to work with GCC 4.4+ and clang 3.2+. It should also work
on other compilers that supports C99, POSIX.1-2001, and the `-fms-extensions
flag` (or equivalent). The latter is needed to allow an anonymous union in a
structure.
To install this code, run the following commands:
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig
You can skip the `make check` step but it's always good to know that tests are
passing on your platform.
The `configure` script takes the standard options to set where files are
installed such as `--prefix`, etc. See `./configure --help` for details.
If after installing, you receive an error that `libmaxminddb.so.0` is missing
you may need to add the `lib` directory in your `prefix` to your library path.
On most Linux distributions when using the default prefix (`/usr/local`), you
can do this by running the following commands:
$ sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf"
$ ldconfig
## From a GitHub "Source Code" Archive / Git Repo Clone (Achtung!)
**NOTE:** These instructions are for installation from the GitHub "Source
Code" archives also available on the
[Releases](https://github.com/maxmind/libmaxminddb/releases) page (e.g.
`X.Y.Z.zip` or `X.Y.Z.tar.gz`), as well as installation directly from a clone
of the [Git repo](https://github.com/maxmind/libmaxminddb). Installation from
these sources are possible but will present challenges to users not
comfortable with manual dependency resolution.
You will need `automake`, `autoconf`, and `libtool` installed
in addition to `make` and a compiler.
You can clone this repository and build it by running:
$ git clone --recursive https://github.com/maxmind/libmaxminddb
After cloning, run `./bootstrap` from the `libmaxminddb` directory and then
follow the instructions for installing from a named release tarball as
described above.
## Using CMake
We provide a CMake build script. This is primarily targeted at Windows users,
but it can be used in other circumstances where the Autotools script does not
work.
$ mkdir build && cd build
$ cmake ..
$ cmake --build .
$ ctest -V .
$ cmake --build . --target install
When building with Visual Studio, you may build a multithreaded (MT/MTd)
runtime library, using the `MSVC_STATIC_RUNTIME` setting:
$ cmake -DMSVC_STATIC_RUNTIME=ON -DBUILD_SHARED_LIBS=OFF ..
## On Ubuntu via PPA
MaxMind provides a PPA for recent version of Ubuntu. To add the PPA to your
APT sources, run:
$ sudo add-apt-repository ppa:maxmind/ppa
Then install the packages by running:
$ sudo apt update
$ sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
## On macOS via Homebrew or MacPorts
You can install libmaxminddb on macOS using [Homebrew](https://brew.sh):
$ brew install libmaxminddb
Or with [MacPorts](https://ports.macports.org/port/libmaxminddb):
$ sudo port install libmaxminddb
# Bug Reports
Please report bugs by filing an issue with our GitHub issue tracker at
https://github.com/maxmind/libmaxminddb/issues
# Creating a Release Tarball
Use `make safedist` to check the resulting tarball.
# Copyright and License
Copyright 2013-2022 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
https://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.

20
bin/CMakeLists.txt Normal file
View File

@ -0,0 +1,20 @@
# getopt is required by mmdblookup which is not available by default on Windows
# but available in mingw-64 toolchain by-default.
if(NOT MSVC)
add_executable(mmdblookup
mmdblookup.c
)
# Otherwise 'undefined reference to WinMain' linker error happen due to wmain()
if(MINGW)
target_link_options(mmdblookup PRIVATE "-municode")
endif()
target_link_libraries(mmdblookup maxminddb pthread)
install(
TARGETS mmdblookup
DESTINATION bin
)
endif()

14
bin/Makefile.am Normal file
View File

@ -0,0 +1,14 @@
include $(top_srcdir)/common.mk
AM_LDFLAGS = $(top_builddir)/src/libmaxminddb.la
bin_PROGRAMS = mmdblookup
if WINDOWS
AM_LDFLAGS += -municode
endif
if !WINDOWS
AM_CPPFLAGS += -pthread
AM_LDFLAGS += -pthread
endif

780
bin/mmdblookup.c Normal file
View File

@ -0,0 +1,780 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "maxminddb.h"
#include <errno.h>
#include <getopt.h>
#ifndef _WIN32
#include <pthread.h>
#endif
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#ifndef UNICODE
#define UNICODE
#endif
#include <malloc.h>
#else
#include <libgen.h>
#include <unistd.h>
#endif
static void usage(char *program, int exit_code, const char *error);
static const char **get_options(int argc,
char **argv,
char **mmdb_file,
char **ip_address,
int *verbose,
int *iterations,
int *lookup_path_length,
int *const thread_count,
char **const ip_file);
static MMDB_s open_or_die(const char *fname);
static void dump_meta(MMDB_s *mmdb);
static bool lookup_from_file(MMDB_s *const mmdb,
char const *const ip_file,
bool const dump);
static int lookup_and_print(MMDB_s *mmdb,
const char *ip_address,
const char **lookup_path,
int lookup_path_length,
bool verbose);
static int benchmark(MMDB_s *mmdb, int iterations);
static MMDB_lookup_result_s lookup_or_die(MMDB_s *mmdb, const char *ipstr);
static void random_ipv4(char *ip);
#ifndef _WIN32
// These aren't with the automatically generated prototypes as we'd lose the
// enclosing macros.
static bool start_threaded_benchmark(MMDB_s *const mmdb,
int const thread_count,
int const iterations);
static long double get_time(void);
static void *thread(void *arg);
#endif
#ifdef _WIN32
int wmain(int argc, wchar_t **wargv) {
// Convert our argument list from UTF-16 to UTF-8.
char **argv = (char **)calloc(argc, sizeof(char *));
if (!argv) {
fprintf(stderr, "calloc(): %s\n", strerror(errno));
exit(1);
}
for (int i = 0; i < argc; i++) {
int utf8_width;
char *utf8_string;
utf8_width =
WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL);
if (utf8_width < 1) {
fprintf(
stderr, "WideCharToMultiByte() failed: %d\n", GetLastError());
exit(1);
}
utf8_string = calloc(utf8_width, sizeof(char));
if (!utf8_string) {
fprintf(stderr, "calloc(): %s\n", strerror(errno));
exit(1);
}
if (WideCharToMultiByte(
CP_UTF8, 0, wargv[i], -1, utf8_string, utf8_width, NULL, NULL) <
1) {
fprintf(
stderr, "WideCharToMultiByte() failed: %d\n", GetLastError());
exit(1);
}
argv[i] = utf8_string;
}
#else // _WIN32
int main(int argc, char **argv) {
#endif // _WIN32
char *mmdb_file = NULL;
char *ip_address = NULL;
int verbose = 0;
int iterations = 0;
int lookup_path_length = 0;
int thread_count = 0;
char *ip_file = NULL;
const char **lookup_path = get_options(argc,
argv,
&mmdb_file,
&ip_address,
&verbose,
&iterations,
&lookup_path_length,
&thread_count,
&ip_file);
MMDB_s mmdb = open_or_die(mmdb_file);
if (verbose) {
dump_meta(&mmdb);
}
// The benchmarking and lookup from file modes are hidden features mainly
// intended for development right now. This means there are several flags
// that exist but are intentionally not mentioned in the usage or man page.
// The lookup from file mode may be useful to expose publicly in the usage,
// but we should have it respect the lookup_path functionality if we do so.
if (ip_file) {
free((void *)lookup_path);
if (!lookup_from_file(&mmdb, ip_file, verbose == 1)) {
MMDB_close(&mmdb);
return 1;
}
MMDB_close(&mmdb);
return 0;
}
if (0 == iterations) {
exit(lookup_and_print(
&mmdb, ip_address, lookup_path, lookup_path_length, verbose));
}
free((void *)lookup_path);
srand((unsigned int)time(NULL));
#ifndef _WIN32
if (thread_count > 0) {
if (!start_threaded_benchmark(&mmdb, thread_count, iterations)) {
MMDB_close(&mmdb);
exit(1);
}
MMDB_close(&mmdb);
exit(0);
}
#endif
exit(benchmark(&mmdb, iterations));
}
static void usage(char *program, int exit_code, const char *error) {
if (NULL != error) {
fprintf(stderr, "\n *ERROR: %s\n", error);
}
char *usage =
"\n"
" %s --file /path/to/file.mmdb --ip 1.2.3.4 [path to lookup]\n"
"\n"
" This application accepts the following options:\n"
"\n"
" --file (-f) The path to the MMDB file. Required.\n"
"\n"
" --ip (-i) The IP address to look up. Required.\n"
"\n"
" --verbose (-v) Turns on verbose output. Specifically, this "
"causes this\n"
" application to output the database metadata.\n"
"\n"
" --version Print the program's version number and exit.\n"
"\n"
" --help (-h -?) Show usage information.\n"
"\n"
" If an IP's data entry resolves to a map or array, you can provide\n"
" a lookup path to only show part of that data.\n"
"\n"
" For example, given a JSON structure like this:\n"
"\n"
" {\n"
" \"names\": {\n"
" \"en\": \"Germany\",\n"
" \"de\": \"Deutschland\"\n"
" },\n"
" \"cities\": [ \"Berlin\", \"Frankfurt\" ]\n"
" }\n"
"\n"
" You could look up just the English name by calling mmdblookup with "
"a lookup path of:\n"
"\n"
" mmdblookup --file ... --ip ... names en\n"
"\n"
" Or you could look up the second city in the list with:\n"
"\n"
" mmdblookup --file ... --ip ... cities 1\n"
"\n"
" Array numbering begins with zero (0).\n"
"\n"
" If you do not provide a path to lookup, all of the information for "
"a given IP\n"
" will be shown.\n"
"\n";
fprintf(stdout, usage, program);
exit(exit_code);
}
static const char **get_options(int argc,
char **argv,
char **mmdb_file,
char **ip_address,
int *verbose,
int *iterations,
int *lookup_path_length,
int *const thread_count,
char **const ip_file) {
static int help = 0;
static int version = 0;
#ifdef _WIN32
char *program = alloca(strlen(argv[0]));
_splitpath(argv[0], NULL, NULL, program, NULL);
_splitpath(argv[0], NULL, NULL, NULL, program + strlen(program));
#else
char *program = basename(argv[0]);
#endif
while (1) {
static struct option options[] = {
{"file", required_argument, 0, 'f'},
{"ip", required_argument, 0, 'i'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'n'},
{"benchmark", required_argument, 0, 'b'},
#ifndef _WIN32
{"threads", required_argument, 0, 't'},
#endif
{"ip-file", required_argument, 0, 'I'},
{"help", no_argument, 0, 'h'},
{"?", no_argument, 0, 1},
{0, 0, 0, 0}};
int opt_index;
#ifdef _WIN32
char const *const optstring = "f:i:b:I:vnh?";
#else
char const *const optstring = "f:i:b:t:I:vnh?";
#endif
int opt_char = getopt_long(argc, argv, optstring, options, &opt_index);
if (-1 == opt_char) {
break;
}
if ('f' == opt_char) {
*mmdb_file = optarg;
} else if ('i' == opt_char) {
*ip_address = optarg;
} else if ('v' == opt_char) {
*verbose = 1;
} else if ('n' == opt_char) {
version = 1;
} else if ('b' == opt_char) {
long const i = strtol(optarg, NULL, 10);
if (i > INT_MAX) {
usage(program, 1, "iterations exceeds maximum value");
}
*iterations = (int)i;
} else if ('h' == opt_char || '?' == opt_char) {
help = 1;
} else if (opt_char == 't') {
long const i = strtol(optarg, NULL, 10);
if (i > INT_MAX) {
usage(program, 1, "thread count exceeds maximum value");
}
*thread_count = (int)i;
} else if (opt_char == 'I') {
*ip_file = optarg;
}
}
if (help) {
usage(program, 0, NULL);
}
if (version) {
fprintf(stdout, "\n %s version %s\n\n", program, PACKAGE_VERSION);
exit(0);
}
if (NULL == *mmdb_file) {
usage(program, 1, "You must provide a filename with --file");
}
if (*ip_address == NULL && *iterations == 0 && !*ip_file) {
usage(program, 1, "You must provide an IP address with --ip");
}
const char **lookup_path =
calloc((size_t)(argc - optind) + 1, sizeof(const char *));
if (!lookup_path) {
fprintf(stderr, "calloc(): %s\n", strerror(errno));
exit(1);
}
int i;
for (i = 0; i < argc - optind; i++) {
lookup_path[i] = argv[i + optind];
(*lookup_path_length)++;
}
lookup_path[i] = NULL;
return lookup_path;
}
static MMDB_s open_or_die(const char *fname) {
MMDB_s mmdb;
int status = MMDB_open(fname, MMDB_MODE_MMAP, &mmdb);
if (MMDB_SUCCESS != status) {
fprintf(
stderr, "\n Can't open %s - %s\n", fname, MMDB_strerror(status));
if (MMDB_IO_ERROR == status) {
fprintf(stderr, " IO error: %s\n", strerror(errno));
}
fprintf(stderr, "\n");
exit(2);
}
return mmdb;
}
static void dump_meta(MMDB_s *mmdb) {
const char *meta_dump = "\n"
" Database metadata\n"
" Node count: %i\n"
" Record size: %i bits\n"
" IP version: IPv%i\n"
" Binary format: %i.%i\n"
" Build epoch: %llu (%s)\n"
" Type: %s\n"
" Languages: ";
char date[40];
const time_t epoch = (const time_t)mmdb->metadata.build_epoch;
strftime(date, 40, "%F %T UTC", gmtime(&epoch));
fprintf(stdout,
meta_dump,
mmdb->metadata.node_count,
mmdb->metadata.record_size,
mmdb->metadata.ip_version,
mmdb->metadata.binary_format_major_version,
mmdb->metadata.binary_format_minor_version,
mmdb->metadata.build_epoch,
date,
mmdb->metadata.database_type);
for (size_t i = 0; i < mmdb->metadata.languages.count; i++) {
fprintf(stdout, "%s", mmdb->metadata.languages.names[i]);
if (i < mmdb->metadata.languages.count - 1) {
fprintf(stdout, " ");
}
}
fprintf(stdout, "\n");
fprintf(stdout, " Description:\n");
for (size_t i = 0; i < mmdb->metadata.description.count; i++) {
fprintf(stdout,
" %s: %s\n",
mmdb->metadata.description.descriptions[i]->language,
mmdb->metadata.description.descriptions[i]->description);
}
fprintf(stdout, "\n");
}
// The input file should have one IP per line.
//
// We look up each IP.
//
// If dump is true, we dump the data for each IP to stderr. This is useful for
// comparison in that you can dump out the data for the IPs before and after
// making changes. It goes to stderr rather than stdout so that the report does
// not get included in what you will compare (since it will almost always be
// different).
//
// In addition to being useful for comparisons, this function provides a way to
// have a more deterministic set of lookups for benchmarking.
static bool lookup_from_file(MMDB_s *const mmdb,
char const *const ip_file,
bool const dump) {
FILE *const fh = fopen(ip_file, "r");
if (!fh) {
fprintf(stderr, "fopen(): %s: %s\n", ip_file, strerror(errno));
return false;
}
clock_t const clock_start = clock();
char buf[1024] = {0};
// I'd normally use uint64_t, but support for it is optional in C99.
unsigned long long i = 0;
while (1) {
if (fgets(buf, sizeof(buf), fh) == NULL) {
if (!feof(fh)) {
fprintf(stderr, "fgets(): %s\n", strerror(errno));
fclose(fh);
return false;
}
if (fclose(fh) != 0) {
fprintf(stderr, "fclose(): %s\n", strerror(errno));
return false;
}
break;
}
char *ptr = buf;
while (*ptr != '\0') {
if (*ptr == '\n') {
*ptr = '\0';
break;
}
ptr++;
}
if (strlen(buf) == 0) {
continue;
}
i++;
MMDB_lookup_result_s result = lookup_or_die(mmdb, buf);
if (!result.found_entry) {
continue;
}
MMDB_entry_data_list_s *entry_data_list = NULL;
int const status =
MMDB_get_entry_data_list(&result.entry, &entry_data_list);
if (status != MMDB_SUCCESS) {
fprintf(stderr,
"MMDB_get_entry_data_list(): %s\n",
MMDB_strerror(status));
fclose(fh);
MMDB_free_entry_data_list(entry_data_list);
return false;
}
if (!entry_data_list) {
fprintf(stderr, "entry_data_list is NULL\n");
fclose(fh);
return false;
}
if (dump) {
fprintf(stdout, "%s:\n", buf);
int const status2 =
MMDB_dump_entry_data_list(stderr, entry_data_list, 0);
if (status2 != MMDB_SUCCESS) {
fprintf(stderr,
"MMDB_dump_entry_data_list(): %s\n",
MMDB_strerror(status2));
fclose(fh);
MMDB_free_entry_data_list(entry_data_list);
return false;
}
}
MMDB_free_entry_data_list(entry_data_list);
}
clock_t const clock_diff = clock() - clock_start;
double const seconds = (double)clock_diff / CLOCKS_PER_SEC;
fprintf(
stdout,
"Looked up %llu addresses in %.2f seconds. %.2Lf lookups per second.\n",
i,
seconds,
(long double)i / seconds);
return true;
}
static int lookup_and_print(MMDB_s *mmdb,
const char *ip_address,
const char **lookup_path,
int lookup_path_length,
bool verbose) {
MMDB_lookup_result_s result = lookup_or_die(mmdb, ip_address);
MMDB_entry_data_list_s *entry_data_list = NULL;
int exit_code = 0;
if (verbose) {
fprintf(stdout, "\n Record prefix length: %d\n", result.netmask);
}
if (result.found_entry) {
int status;
if (lookup_path_length) {
MMDB_entry_data_s entry_data;
status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
if (MMDB_SUCCESS == status) {
if (entry_data.offset) {
MMDB_entry_s entry = {.mmdb = mmdb,
.offset = entry_data.offset};
status = MMDB_get_entry_data_list(&entry, &entry_data_list);
} else {
fprintf(stdout,
"\n No data was found at the lookup path you "
"provided\n\n");
}
}
} else {
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 = 5;
goto end;
}
if (NULL != entry_data_list) {
fprintf(stdout, "\n");
MMDB_dump_entry_data_list(stdout, entry_data_list, 2);
fprintf(stdout, "\n");
}
} else {
fprintf(stderr,
"\n Could not find an entry for this IP address (%s)\n\n",
ip_address);
exit_code = 6;
}
end:
MMDB_free_entry_data_list(entry_data_list);
MMDB_close(mmdb);
free((void *)lookup_path);
return exit_code;
}
static int benchmark(MMDB_s *mmdb, int iterations) {
char ip_address[16];
int exit_code = 0;
clock_t time = clock();
for (int i = 0; i < iterations; i++) {
random_ipv4(ip_address);
MMDB_lookup_result_s result = lookup_or_die(mmdb, ip_address);
MMDB_entry_data_list_s *entry_data_list = NULL;
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 = 5;
MMDB_free_entry_data_list(entry_data_list);
goto end;
}
}
MMDB_free_entry_data_list(entry_data_list);
}
time = clock() - time;
double seconds = ((double)time / CLOCKS_PER_SEC);
fprintf(stdout,
"\n Looked up %i addresses in %.2f seconds. %.2f lookups per "
"second.\n\n",
iterations,
seconds,
iterations / seconds);
end:
MMDB_close(mmdb);
return exit_code;
}
static MMDB_lookup_result_s lookup_or_die(MMDB_s *mmdb, const char *ipstr) {
int gai_error, mmdb_error;
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ipstr, &gai_error, &mmdb_error);
if (0 != gai_error) {
#ifdef _WIN32
char const *const strerr = gai_strerrorA(gai_error);
#else
char const *const strerr = gai_strerror(gai_error);
#endif
fprintf(stderr,
"\n Error from call to getaddrinfo for %s - %s\n\n",
ipstr,
strerr);
exit(3);
}
if (MMDB_SUCCESS != mmdb_error) {
fprintf(stderr,
"\n Got an error from the maxminddb library: %s\n\n",
MMDB_strerror(mmdb_error));
exit(4);
}
return result;
}
static void random_ipv4(char *ip) {
// rand() is perfectly fine for this use case
// coverity[dont_call]
int ip_int = rand();
uint8_t *bytes = (uint8_t *)&ip_int;
snprintf(ip,
16,
"%u.%u.%u.%u",
*bytes,
*(bytes + 1),
*(bytes + 2),
*(bytes + 3));
}
#ifndef _WIN32
struct thread_info {
pthread_t id;
int num;
MMDB_s *mmdb;
int iterations;
};
static bool start_threaded_benchmark(MMDB_s *const mmdb,
int const thread_count,
int const iterations) {
struct thread_info *const tinfo =
calloc((size_t)thread_count, sizeof(struct thread_info));
if (!tinfo) {
fprintf(stderr, "calloc(): %s\n", strerror(errno));
return false;
}
// Using clock() isn't appropriate for multiple threads. It's CPU time, not
// wall time.
long double const start_time = get_time();
if (start_time == -1) {
free(tinfo);
return false;
}
for (int i = 0; i < thread_count; i++) {
tinfo[i].num = i;
tinfo[i].mmdb = mmdb;
tinfo[i].iterations = iterations;
if (pthread_create(&tinfo[i].id, NULL, &thread, &tinfo[i]) != 0) {
fprintf(stderr, "pthread_create() failed\n");
free(tinfo);
return false;
}
}
for (int i = 0; i < thread_count; i++) {
if (pthread_join(tinfo[i].id, NULL) != 0) {
fprintf(stderr, "pthread_join() failed\n");
free(tinfo);
return false;
}
}
free(tinfo);
long double const end_time = get_time();
if (end_time == -1) {
return false;
}
long double const elapsed = end_time - start_time;
unsigned long long const total_ips =
(unsigned long long)(iterations * thread_count);
long double rate = total_ips;
if (elapsed != 0) {
rate = total_ips / elapsed;
}
fprintf(stdout,
"Looked up %llu addresses using %d threads in %.2Lf seconds. %.2Lf "
"lookups per second.\n",
total_ips,
thread_count,
elapsed,
rate);
return true;
}
static long double get_time(void) {
// clock_gettime() is not present on OSX until 10.12.
#ifdef HAVE_CLOCK_GETTIME
struct timespec tp = {
.tv_sec = 0,
.tv_nsec = 0,
};
clockid_t clk_id = CLOCK_REALTIME;
#ifdef _POSIX_MONOTONIC_CLOCK
clk_id = CLOCK_MONOTONIC;
#endif
if (clock_gettime(clk_id, &tp) != 0) {
fprintf(stderr, "clock_gettime(): %s\n", strerror(errno));
return -1;
}
return (long double)tp.tv_sec + ((float)tp.tv_nsec / 1e9);
#else
time_t t = time(NULL);
if (t == (time_t)-1) {
fprintf(stderr, "time(): %s\n", strerror(errno));
return -1;
}
return (long double)t;
#endif
}
static void *thread(void *arg) {
const struct thread_info *const tinfo = arg;
if (!tinfo) {
fprintf(stderr, "thread(): %s\n", strerror(EINVAL));
return NULL;
}
char ip_address[16] = {0};
for (int i = 0; i < tinfo->iterations; i++) {
memset(ip_address, 0, 16);
random_ipv4(ip_address);
MMDB_lookup_result_s result = lookup_or_die(tinfo->mmdb, ip_address);
if (!result.found_entry) {
continue;
}
MMDB_entry_data_list_s *entry_data_list = NULL;
int const status =
MMDB_get_entry_data_list(&result.entry, &entry_data_list);
if (status != MMDB_SUCCESS) {
fprintf(stderr,
"MMDB_get_entry_data_list(): %s\n",
MMDB_strerror(status));
MMDB_free_entry_data_list(entry_data_list);
return NULL;
}
if (!entry_data_list) {
fprintf(stderr, "entry_data_list is NULL\n");
return NULL;
}
MMDB_free_entry_data_list(entry_data_list);
}
return NULL;
}
#endif

21
bootstrap Executable file
View File

@ -0,0 +1,21 @@
#! /bin/sh
# make sure to use the installed libtool
if [ -f ltmain.sh ]; then
rm ltmain.sh
fi
autoreconf -fiv
###################################################
# the steps below may help with outdated toolsets
# disable dependency trackeing for OS X with multiply arch option's
# automake -i --gnu --add-missing
#aclocal \
#&& automake -i --gnu --add-missing \
#&& autoconf
#LIBTOOLIZE=$( which libtoolize glibtoolize | head -1 )
#$LIBTOOLIZE -f

7
c_flag_overrides.cmake Normal file
View File

@ -0,0 +1,7 @@
if(MSVC)
set(CMAKE_C_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
set(CMAKE_C_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG")
set(CMAKE_C_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
endif()

7
common.mk Normal file
View File

@ -0,0 +1,7 @@
if DEBUG
AM_CFLAGS=-O0 -g -Wall -Wextra
else
AM_CFLAGS=-O2 -g
endif
AM_CPPFLAGS = -I$(top_srcdir)/include

138
configure.ac Normal file
View File

@ -0,0 +1,138 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([libmaxminddb], [1.7.1], [support@maxmind.com])
AC_CONFIG_SRCDIR([include/maxminddb.h])
AC_CONFIG_HEADERS([config.h include/maxminddb_config.h])
PKG_PROG_PKG_CONFIG
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR], [AC_SUBST([pkgconfigdir], [${libdir}/pkgconfig])])
AC_CONFIG_FILES([src/libmaxminddb.pc])
LT_INIT
AM_INIT_AUTOMAKE(foreign m4_esyscmd([case `automake --version | head -n 1` in
*1.14*) echo subdir-objects;;
*1.11*);;
*) echo serial-tests;;
esac]))
AC_PROG_LIBTOOL
# Checks for programs.
AC_PROG_CC_C99
# Copied from http://stackoverflow.com/a/10682813/9832 and tweaked for C (as
# opposed to C++)
#
# AX_CHECK_CFLAGS(ADDITIONAL-CFLAGS, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND)
#
# checks whether the $(CC) compiler accepts the ADDITIONAL-CFLAGS
# if so, they are added to the CXXFLAGS
AC_DEFUN([AX_CHECK_CFLAGS],
[
AC_MSG_CHECKING([whether compiler accepts "$1"])
cat > conftest.c << EOF
int main(){
return 0;
}
EOF
if $CC $CFLAGS -o conftest.o conftest.c [$1] > /dev/null 2>&1
then
AC_MSG_RESULT([yes])
CFLAGS="${CFLAGS} [$1]"
[$2]
else
AC_MSG_RESULT([no])
[$3]
fi
])dnl AX_CHECK_CFLAGS
AX_CHECK_CFLAGS([-fms-extensions])
# We will add this back for non-debug builds in the common.mk file
CFLAGS=`echo ${CFLAGS} | sed 's/-O2//'`
CXXFLAGS=`echo ${CXXFLAGS} | sed 's/-O2//'`
# autoconf insists on giving us gnu99 if it's available
CC=`echo ${CC} | sed 's/-std=gnu99/-std=c99/'`
AC_C_RESTRICT
AC_CHECK_HEADERS([arpa/inet.h assert.h fcntl.h inttypes.h libgen.h math.h netdb.h netinet/in.h stdarg.h stdbool.h stdint.h stdio.h stdlib.h string.h sys/mman.h sys/socket.h sys/stat.h sys/time.h sys/types.h unistd.h])
# configure generates an invalid config for MinGW because of the type checks
# so we only run them on non MinGW-Systems. For MinGW we also need to link
# against ws2_32.
AC_CANONICAL_HOST
is_windows=false
case $host_os in
mingw*)
LDFLAGS="-lws2_32"
is_windows=true
;;
*)
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT8_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
;;
esac
AM_CONDITIONAL([WINDOWS], [test x$is_windows = xtrue])
# This check is backwards in order to make life easier for people writing
# extensions in other languages that link to this library. If they want to
# simply assume that they are using a newish compiler, they don't need to
# check for this type nor do they need to define anything on the CLI. They'll
# just get code that assumes this type exists.
AC_CHECK_TYPE(
[unsigned __int128],
[AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [0], [Missing the unsigned __int128 type])],
[AC_CHECK_TYPE(
[unsigned int __attribute__((mode(TI)))],
[AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [0], [Missing the unsigned __int128 type])
AC_DEFINE([MMDB_UINT128_USING_MODE], [1], [int128 types are available with __attribute__((mode(TI)))])],
[AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [1], [Missing the unsigned __int128 type])])])
AC_CHECK_TYPES([boolean])
AC_CHECK_FUNCS([clock_gettime open_memstream])
AC_C_BIGENDIAN(
[AC_DEFINE([MMDB_LITTLE_ENDIAN], [0], [System is big-endian])],
[AC_DEFINE([MMDB_LITTLE_ENDIAN], [1], [System is little-endian])])
AC_FUNC_MMAP
AC_SEARCH_LIBS([fabs], [m])
AC_SEARCH_LIBS([fabsf], [m])
AC_SEARCH_LIBS([getaddrinfo], [socket])
AC_ARG_ENABLE(
[debug],
[ --enable-debug Turn on debugging],
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],[debug=false])
AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])
AC_ARG_ENABLE([binaries],
AS_HELP_STRING([--enable-binaries], [Compilation of binaries code]),
[enable_binaries=${enableval}],
[enable_binaries=yes])
AM_CONDITIONAL([BINARIES], [test "${enable_binaries}" = "yes"])
AC_ARG_ENABLE([tests],
AS_HELP_STRING([--enable-tests], [Compilation of tests code]),
[enable_tests=${enableval}],
[enable_tests=yes])
AM_CONDITIONAL([TESTS], [test "${enable_tests}" = "yes"])
AC_CONFIG_FILES([Makefile
src/Makefile
bin/Makefile
t/Makefile])
AC_OUTPUT

6
cxx_flag_overrides.cmake Normal file
View File

@ -0,0 +1,6 @@
if(MSVC)
set(CMAKE_CXX_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
endif()

15
dev-bin/clang-format-all.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
format="clang-format -i -style=file"
for dir in bin include src t; do
c_files=`find $dir -maxdepth 1 -name '*.c'`
if [ "$c_files" != "" ]; then
$format $dir/*.c;
fi
h_files=`find $dir -maxdepth 1 -name '*.h'`
if [ "$h_files" != "" ]; then
$format $dir/*.h;
fi
done

99
dev-bin/make-man-pages.pl Executable file
View File

@ -0,0 +1,99 @@
#!/usr/bin/env perl
use strict;
use warnings;
use autodie qw( :all );
use FindBin qw( $Bin );
use File::Path qw( mkpath );
use File::Slurp qw( edit_file read_file );
use File::Which qw( which );
sub main {
my $target = shift || "$Bin/..";
my @translators = qw ( lowdown pandoc );
my $translator;
foreach my $p (@translators) {
if ( defined which($p) ) {
$translator = $p;
last;
}
}
unless ( defined $translator ) {
die "\n You must install one of "
. join( ', ', @translators )
. " in order to generate the man pages.\n\n";
}
_make_man( $translator, $target, 'libmaxminddb', 3 );
_make_lib_man_links($target);
_make_man( $translator, $target, 'mmdblookup', 1 );
}
sub _make_man {
my $translator = shift;
my $target = shift;
my $name = shift;
my $section = shift;
my $input = "$Bin/../doc/$name.md";
my $man_dir = "$target/man/man$section";
mkpath($man_dir);
my $output = "$man_dir/$name.$section";
if ( $translator eq 'pandoc' ) {
system(
'pandoc',
'-s',
'-f', 'markdown_mmd+backtick_code_blocks',
'-t', 'man',
'-M', "title:$name",
'-M', "section:$section",
$input,
'-o', $output,
);
_pandoc_postprocess($output);
}
elsif ( $translator eq 'lowdown' ) {
system(
'lowdown',
'-s',
'--out-no-smarty',
'-Tman',
'-M', "title:$name",
'-M', "section:$section",
$input,
'-o', $output,
);
}
}
sub _make_lib_man_links {
my $target = shift;
my $header = read_file("$Bin/../include/maxminddb.h");
for my $proto ( $header =~ /^ *extern.+?(MMDB_\w+)\(/gsm ) {
open my $fh, '>', "$target/man/man3/$proto.3";
print {$fh} ".so man3/libmaxminddb.3\n";
close $fh;
}
}
# AFAICT there's no way to control the indentation depth for code blocks with
# Pandoc.
sub _pandoc_postprocess {
my $file = shift;
edit_file(
sub {
s/^\.IP\n\.nf/.IP "" 4\n.nf/gm;
s/(Automatically generated by Pandoc)(.+)$/$1/m;
},
$file
);
}
main(shift);

53
dev-bin/ppa-release.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
set -e
set -x
set -u
DISTS=( groovy focal bionic xenial trusty )
VERSION=$(perl -MFile::Slurp::Tiny=read_file -MDateTime <<EOF
use v5.16;
my \$log = read_file(q{Changes.md});
\$log =~ /^## (\d+\.\d+\.\d+) - (\d{4}-\d{2}-\d{2})/;
die 'Release time is not today!' unless DateTime->now->ymd eq \$2;
say \$1;
EOF
)
RESULTS=/tmp/build-libmaxminddb-results/
SRCDIR="$RESULTS/libmaxminddb"
mkdir -p "$SRCDIR"
# gbp does weird things without a pristine checkout
git clone git@github.com:maxmind/libmaxminddb.git -b ubuntu-ppa $SRCDIR
pushd "$SRCDIR"
git merge "$VERSION"
for dist in "${DISTS[@]}"; do
dch -v "$VERSION-0+maxmind1~$dist" -D "$dist" -u low "New upstream release."
gbp buildpackage -S --git-ignore-new
git clean -xfd
git reset HEAD --hard
done
read -e -p "Release to PPA? (y/n)" SHOULD_RELEASE
if [ "$SHOULD_RELEASE" != "y" ]; then
echo "Aborting"
exit 1
fi
# Upload to launchpad
dput ppa:maxmind/ppa ../*source.changes
# Make the changelog up to date in git
dch -v "$VERSION-0+maxmind1" -D "${DISTS[0]}" -u low "New upstream release."
git add debian/changelog
git commit -m "Update debian/changelog for $VERSION"
git push

View File

@ -0,0 +1,54 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw( $Bin );
use Data::UUID;
use File::Slurp qw( read_file write_file );
use Path::Iterator::Rule;
sub main {
my $rule = Path::Iterator::Rule->new;
$rule->file->name(qr/_t.c$/);
my $ug = Data::UUID->new;
my $template = read_file("$Bin/../projects/test.vcxproj.template");
my @names;
for my $file ( $rule->all("$Bin/../t/") ) {
my ($name) = $file =~ /(\w*)_t.c$/;
next unless $name;
next if $name eq 'threads';
push @names, $name;
my $project = $template;
$project =~ s/%TESTNAME%/$name/g;
my $uuid = $ug->to_string( $ug->create );
$project =~ s/%UUID%/$uuid/g;
write_file( "$Bin/../projects/VS12-tests/$name.vcxproj", $project );
}
_modify_yml(@names);
}
sub _modify_yml {
my @names = @_;
my $exe_block = join "\n",
map { " - .\\projects\\VS12\\Debug\\test_${_}.exe" } @names;
my $file = "$Bin/../appveyor.yml";
my $config = read_file($file);
$config =~ s/(#EXES).*?(#ENDEXES)/$1\n$exe_block\n $2/s;
write_file( $file, $config );
}
main();

118
dev-bin/release.sh Executable file
View File

@ -0,0 +1,118 @@
#!/bin/bash
set -eu -o pipefail
changelog=$(cat Changes.md)
regex='## ([0-9]+\.[0-9]+\.[0-9]+) - ([0-9]{4}-[0-9]{2}-[0-9]{2})
((.|
)*)
'
if [[ ! $changelog =~ $regex ]]; then
echo "Could not find date line in change log!"
exit 1
fi
version="${BASH_REMATCH[1]}"
date="${BASH_REMATCH[2]}"
notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^## [0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')"
dist="libmaxminddb-$version.tar.gz"
if [[ "$date" != $(date +"%Y-%m-%d") ]]; then
echo "$date is not today!"
exit 1
fi
if [ -n "$(git status --porcelain)" ]; then
echo ". is not clean." >&2
exit 1
fi
old_version=$(perl -MFile::Slurp=read_file <<EOF
use v5.16;
my \$conf = read_file(q{configure.ac});
\$conf =~ /AC_INIT.+\[(\d+\.\d+\.\d+)\]/;
say \$1;
EOF
)
perl -MFile::Slurp=edit_file -e \
"edit_file { s/\Q$old_version/$version/g } \$_ for qw( configure.ac include/maxminddb.h CMakeLists.txt )"
if [ -n "$(git status --porcelain)" ]; then
git diff
read -e -p "Commit changes? " should_commit
if [ "$should_commit" != "y" ]; then
echo "Aborting"
exit 1
fi
git add configure.ac include/maxminddb.h CMakeLists.txt
git commit -m "Bumped version to $version"
fi
./bootstrap
./configure
make
make check
make clean
make safedist
if [ ! -d .gh-pages ]; then
echo "Checking out gh-pages in .gh-pages"
git clone -b gh-pages git@github.com:maxmind/libmaxminddb.git .gh-pages
pushd .gh-pages
else
echo "Updating .gh-pages"
pushd .gh-pages
git pull
fi
if [ -n "$(git status --porcelain)" ]; then
echo ".gh-pages is not clean" >&2
exit 1
fi
index=index.md
cat <<EOF > $index
---
layout: default
title: libmaxminddb - a library for working with MaxMind DB files
version: $version
---
EOF
cat ../doc/libmaxminddb.md >> $index
mmdblookup=mmdblookup.md
cat <<EOF > $mmdblookup
---
layout: default
title: mmdblookup - a utility to look up an IP address in a MaxMind DB file
version: $version
---
EOF
cat ../doc/mmdblookup.md >> $mmdblookup
git commit -m "Updated for $version" -a
read -p "Push to origin? (y/n) " should_push
if [ "$should_push" != "y" ]; then
echo "Aborting"
exit 1
fi
git push
popd
git push
gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$version" "$dist"

53
dev-bin/valgrind-all.pl Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env perl
# Note to run this you will probably want to build with ./configure
# --disable-shared. You don't want to valgrind the libtool script.
#
# Also make sure you compile the tests first (`make check').
use strict;
use warnings;
use File::Basename qw( basename );
use FindBin qw( $Bin );
use IPC::Run3;
my $top_dir = "$Bin/..";
my $output;
my @tests;
push @tests, glob "$top_dir/t/*_t";
push @tests, glob "$top_dir/t/*-t";
my @mmdblookup = (
"$top_dir/bin/mmdblookup",
'--file', "$top_dir/t/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb",
'--ip',
);
# We want IPv4 and IPv6 addresses - one of each that exists in the db and one
# that doesn't
my @ips = ( '1.1.1.1', '10.0.0.0', 'abcd::', '0900::' );
my @cmds = (
( map { [ @mmdblookup, $_ ] } @ips ),
( map { [$_] } @tests ),
);
for my $cmd (@cmds) {
my $output;
run3(
[ qw( valgrind -v --leak-check=full --show-leak-kinds=all -- ), @{$cmd} ],
\undef,
\$output,
\$output,
);
$output =~ s/^(?!=).*\n//mg;
my $marker = '-' x 60;
print $marker, "\n", ( join q{ }, basename( shift @{$cmd} ), @{$cmd} ),
"\n", $marker, "\n", $output,
"\n\n";
}

897
doc/libmaxminddb.md Normal file
View File

@ -0,0 +1,897 @@
# 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
https://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-2022 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
https://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)

103
doc/mmdblookup.md Normal file
View File

@ -0,0 +1,103 @@
# NAME
mmdblookup - a utility to look up an IP address in a MaxMind DB file
# SYNOPSIS
mmdblookup --file [FILE PATH] --ip [IP ADDRESS] [DATA PATH]
# DESCRIPTION
`mmdblookup` looks up an IP address in the specified MaxMind DB file. The
record for the IP address is displayed in a JSON-like structure with type
annotations.
If an IP's data entry resolves to a map or array, you can provide a lookup
path to only show part of that data.
For example, given a JSON structure like this:
```js
{
"names": {
"en": "Germany",
"de": "Deutschland"
},
"cities": [ "Berlin", "Frankfurt" ]
}
```
You could look up just the English name by calling mmdblookup with a lookup
path of:
```bash
mmdblookup --file ... --ip ... names en
```
Or you could look up the second city in the list with:
```bash
mmdblookup --file ... --ip ... cities 1
```
Array numbering begins with zero (0).
If you do not provide a path to lookup, all of the information for a given IP
will be shown.
# OPTIONS
This application accepts the following options:
-f, --file
: The path to the MMDB file. Required.
-i, --ip
: The IP address to look up. Required.
-v, --verbose
: Turns on verbose output. Specifically, this causes this
application to output the database metadata.
--version
: Print the program's version number and exit.
-h, -?, --help
: Show usage information.
# 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 utility was written by Boris Zentner (bzentner@maxmind.com) and Dave
Rolsky (drolsky@maxmind.com).
# COPYRIGHT AND LICENSE
Copyright 2013-2022 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
https://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
libmaxminddb(3)

258
include/maxminddb.h Normal file
View File

@ -0,0 +1,258 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MAXMINDDB_H
#define MAXMINDDB_H
/* Request POSIX.1-2008. However, we want to remain compatible with
* POSIX.1-2001 (since we have been historically and see no reason to drop
* compatibility). By requesting POSIX.1-2008, we can conditionally use
* features provided by that standard if the implementation provides it. We can
* check for what the implementation provides by checking the _POSIX_VERSION
* macro after including unistd.h. If a feature is in POSIX.1-2008 but not
* POSIX.1-2001, check that macro before using the feature (or check for the
* feature directly if possible). */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include "maxminddb_config.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
/* libmaxminddb package version from configure */
#define PACKAGE_VERSION "1.7.1"
typedef ADDRESS_FAMILY sa_family_t;
#if defined(_MSC_VER)
/* MSVC doesn't define signed size_t, copy it from configure */
#define ssize_t SSIZE_T
/* MSVC doesn't support restricted pointers */
#define restrict
#endif
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#define MMDB_DATA_TYPE_EXTENDED (0)
#define MMDB_DATA_TYPE_POINTER (1)
#define MMDB_DATA_TYPE_UTF8_STRING (2)
#define MMDB_DATA_TYPE_DOUBLE (3)
#define MMDB_DATA_TYPE_BYTES (4)
#define MMDB_DATA_TYPE_UINT16 (5)
#define MMDB_DATA_TYPE_UINT32 (6)
#define MMDB_DATA_TYPE_MAP (7)
#define MMDB_DATA_TYPE_INT32 (8)
#define MMDB_DATA_TYPE_UINT64 (9)
#define MMDB_DATA_TYPE_UINT128 (10)
#define MMDB_DATA_TYPE_ARRAY (11)
#define MMDB_DATA_TYPE_CONTAINER (12)
#define MMDB_DATA_TYPE_END_MARKER (13)
#define MMDB_DATA_TYPE_BOOLEAN (14)
#define MMDB_DATA_TYPE_FLOAT (15)
#define MMDB_RECORD_TYPE_SEARCH_NODE (0)
#define MMDB_RECORD_TYPE_EMPTY (1)
#define MMDB_RECORD_TYPE_DATA (2)
#define MMDB_RECORD_TYPE_INVALID (3)
/* flags for open */
#define MMDB_MODE_MMAP (1)
#define MMDB_MODE_MASK (7)
/* error codes */
#define MMDB_SUCCESS (0)
#define MMDB_FILE_OPEN_ERROR (1)
#define MMDB_CORRUPT_SEARCH_TREE_ERROR (2)
#define MMDB_INVALID_METADATA_ERROR (3)
#define MMDB_IO_ERROR (4)
#define MMDB_OUT_OF_MEMORY_ERROR (5)
#define MMDB_UNKNOWN_DATABASE_FORMAT_ERROR (6)
#define MMDB_INVALID_DATA_ERROR (7)
#define MMDB_INVALID_LOOKUP_PATH_ERROR (8)
#define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9)
#define MMDB_INVALID_NODE_NUMBER_ERROR (10)
#define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11)
#if !(MMDB_UINT128_IS_BYTE_ARRAY)
#if MMDB_UINT128_USING_MODE
typedef unsigned int mmdb_uint128_t __attribute__((__mode__(TI)));
#else
typedef unsigned __int128 mmdb_uint128_t;
#endif
#endif
/* This is a pointer into the data section for a given IP address lookup */
typedef struct MMDB_entry_s {
const struct MMDB_s *mmdb;
uint32_t offset;
} MMDB_entry_s;
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;
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t uint128[16];
#else
mmdb_uint128_t uint128;
#endif
bool boolean;
float float_value;
};
/* This is a 0 if a given entry cannot be found. This can only happen
* when a call to MMDB_(v)get_value() asks for hash keys or array
* indices that don't exist. */
uint32_t offset;
/* This is the next entry in the data section, but it's really only
* relevant for entries that part of a larger map or array
* struct. There's no good reason for an end user to look at this
* directly. */
uint32_t offset_to_next;
/* This is only valid for strings, utf8_strings or binary data */
uint32_t data_size;
/* This is an MMDB_DATA_TYPE_* constant */
uint32_t type;
} MMDB_entry_data_s;
/* This is the return type when someone asks for all the entry data in a map or
* array */
typedef struct MMDB_entry_data_list_s {
MMDB_entry_data_s entry_data;
struct MMDB_entry_data_list_s *next;
void *pool;
} MMDB_entry_data_list_s;
typedef struct MMDB_description_s {
const char *language;
const char *description;
} MMDB_description_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
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;
/* See above warning before adding fields */
} MMDB_metadata_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
typedef struct MMDB_ipv4_start_node_s {
uint16_t netmask;
uint32_t node_value;
/* See above warning before adding fields */
} MMDB_ipv4_start_node_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
typedef struct MMDB_s {
uint32_t flags;
const char *filename;
ssize_t file_size;
const uint8_t *file_content;
const uint8_t *data_section;
uint32_t data_section_size;
const uint8_t *metadata_section;
uint32_t metadata_section_size;
uint16_t full_record_byte_size;
uint16_t depth;
MMDB_ipv4_start_node_s ipv4_start_node;
MMDB_metadata_s metadata;
/* See above warning before adding fields */
} MMDB_s;
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;
extern int
MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb);
extern MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
const char *const ipstr,
int *const gai_error,
int *const mmdb_error);
extern MMDB_lookup_result_s
MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
const struct sockaddr *const sockaddr,
int *const mmdb_error);
extern int MMDB_read_node(const MMDB_s *const mmdb,
uint32_t node_number,
MMDB_search_node_s *const node);
extern int MMDB_get_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data,
...);
extern int MMDB_vget_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data,
va_list va_path);
extern int MMDB_aget_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data,
const char *const *const path);
extern int MMDB_get_metadata_as_entry_data_list(
const MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list);
extern int
MMDB_get_entry_data_list(MMDB_entry_s *start,
MMDB_entry_data_list_s **const entry_data_list);
extern void
MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list);
extern void MMDB_close(MMDB_s *const mmdb);
extern const char *MMDB_lib_version(void);
extern int
MMDB_dump_entry_data_list(FILE *const stream,
MMDB_entry_data_list_s *const entry_data_list,
int indent);
extern const char *MMDB_strerror(int error_code);
#endif /* MAXMINDDB_H */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,14 @@
#ifndef MAXMINDDB_CONFIG_H
#define MAXMINDDB_CONFIG_H
#ifndef MMDB_UINT128_USING_MODE
/* Define as 1 if we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
#cmakedefine MMDB_UINT128_USING_MODE @MMDB_UINT128_USING_MODE@
#endif
#ifndef MMDB_UINT128_IS_BYTE_ARRAY
/* Define as 1 if we don't have an unsigned __int128 type */
#cmakedefine MMDB_UINT128_IS_BYTE_ARRAY @MMDB_UINT128_IS_BYTE_ARRAY@
#endif
#endif /* MAXMINDDB_CONFIG_H */

View File

@ -0,0 +1,14 @@
#ifndef MAXMINDDB_CONFIG_H
#define MAXMINDDB_CONFIG_H
#ifndef MMDB_UINT128_USING_MODE
/* Define as 1 if we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
#define MMDB_UINT128_USING_MODE 0
#endif
#ifndef MMDB_UINT128_IS_BYTE_ARRAY
/* Define as 1 if we don't have an unsigned __int128 type */
#undef MMDB_UINT128_IS_BYTE_ARRAY
#endif
#endif /* MAXMINDDB_CONFIG_H */

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B19839F4-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>bad_pointers</RootNamespace>
<ProjectName>test_bad_pointers</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\bad_pointers_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1983C10-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>basic_lookup</RootNamespace>
<ProjectName>test_basic_lookup</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\basic_lookup_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1983E90-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>data_entry_list</RootNamespace>
<ProjectName>test_data_entry_list</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\data_entry_list_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B198400C-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>data_types</RootNamespace>
<ProjectName>test_data_types</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\data_types_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984188-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>dump</RootNamespace>
<ProjectName>test_dump</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\dump_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984480-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>get_value</RootNamespace>
<ProjectName>test_get_value</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\get_value_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984304-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>get_value_pointer_bug</RootNamespace>
<ProjectName>test_get_value_pointer_bug</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\get_value_pointer_bug_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B198466A-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ipv4_start_cache</RootNamespace>
<ProjectName>test_ipv4_start_cache</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\ipv4_start_cache_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984872-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ipv6_lookup_in_ipv4</RootNamespace>
<ProjectName>test_ipv6_lookup_in_ipv4</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\ipv6_lookup_in_ipv4_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libtap</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/Z7 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\t\libtap\tap.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\t\libtap\tap.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ConsoleApplication1</RootNamespace>
<ProjectName>test_maxminddb_test_helper</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\..\t\libtap\libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\t\maxminddb_test_helper.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\t\maxminddb_test_helper.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984C6E-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>metadata</RootNamespace>
<ProjectName>test_metadata</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\metadata_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B19849D0-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>metadata_pointers</RootNamespace>
<ProjectName>test_metadata_pointers</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\metadata_pointers_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B1984EC6-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>no_map_get_value</RootNamespace>
<ProjectName>test_no_map_get_value</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\no_map_get_value_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B198504C-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>read_node</RootNamespace>
<ProjectName>test_read_node</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\read_node_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ConsoleApplication1</RootNamespace>
<ProjectName>test_maxminddb_test_helper</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\t\maxminddb_test_helper.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\t\maxminddb_test_helper.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8E11E9FC-7B63-11E4-AE98-6B41E8A9DDB2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>threads</RootNamespace>
<ProjectName>test_threads</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\threads_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{B19851FA-376C-11E7-A95B-48C58C130AD6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>version</RootNamespace>
<ProjectName>test_version</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\version_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

64
projects/VS12/README.md Normal file
View File

@ -0,0 +1,64 @@
# Deprecated
*These files are deprecated and will be removed in a future release.
Please use CMake instead.*
# Project Notes
DO NOT modify project settings for each configuration and/or platform
on a per-project basis. Use property sheets to set shared configuration
properties. The rule of thumb - if you set same value for the same
property in more than one configuration or platform, you did it wrong.
## libmaxminddb.props
This is the base property sheet for libMaxMindDB project. It contains
settings that are shared between all configurations, such as compiler
warning level, not using link-time code generation, etc.
In order to minimize the number of property sheet files, this propery
sheet also contains settings for Win32 and Debug configurations, which
are overridden by the x64 and Release property sheets described below.
## libmaxminddb-release.props
This property sheet contains all Release settings and is shared between
Win32 and x64 release builds. It must be located higher than the base
property sheet in the property Manager window for each configuration
where it's used (i.e. Release|Win32 and Release|x64).
## libmaxminddb-x64.props
This property sheet contains all x64 settings and is shared between all
Debug and Release x64 configurations. It must be located higher than the
base property sheet in the property Manager window for each configuration
where it's used (i.e. Debug|x64 and Release|x64).
## Adding More Projects
If you want to add more projects into this solution, follow the same logic
and create their own property sheets. Do not use libmaxminddb property
sheets in those projects because it will interfere with their intermediate
directories. Instead, copy and rename libmaxminddb property sheets as a
starting point.
DO NOT add libmaxminddb.lib to the Additional Dependencies box of command
line tools or any other libraries you built, for that matter. This box is
only for standard Windows libraries. Instead, add libmaxminddb as a reference
to all command line tool projects. Do the same for any other library projects
you added to this solutionn.
For external 3rd-party .lib files, create a solution folder called Libraries
and add Debug, Debug64, Release, Release64 subfolders, then drag and drop all
versinos of .lib to their respective folders and use Exclude From Build in
each library file's property to assign them to the proper build confguration.
Unused libraries will be shown with a traffic stop sign in each configuration.
If you have a lot of projects, it might be easier to do this by editing .vcxproj
and .vcxproj.filters in a text editor.
# Tests
To use the tests, you must download the `libtap` and `maxmind-db` submodules.
This can be done by running `git submodule update --init --recursive` from
the Git checkout. Each test source file has a separate project. Once compiled,
the tests must be run from the base directory of the checkout.

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<OmitFramePointers>true</OmitFramePointers>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup>
<Lib>
<TargetMachine>MachineX64</TargetMachine>
</Lib>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(SolutionDir)$(Configuration)\obj\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<WarningLevel>Level3</WarningLevel>
<ExceptionHandling>false</ExceptionHandling>
<ProgramDataBaseFileName>$(OutDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
<Optimization>Disabled</Optimization>
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
<OmitFramePointers>false</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<PreBuildEvent>
<Command>if NOT EXIST (..\..\include\maxminddb_config.h) (
copy maxminddb_config.h ..\..\include\maxminddb_config.h
)</Command>
</PreBuildEvent>
<Lib>
<TargetMachine>MachineX86</TargetMachine>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -0,0 +1,150 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmaxminddb", "libmaxminddb.vcxproj", "{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_basic_lookup", "..\VS12-tests\basic_lookup.vcxproj", "{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_data_entry_list", "..\VS12-tests\data_entry_list.vcxproj", "{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_data_types", "..\VS12-tests\data_types.vcxproj", "{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_dump", "..\VS12-tests\dump.vcxproj", "{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_get_value", "..\VS12-tests\get_value.vcxproj", "{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_get_value_pointer_bug", "..\VS12-tests\get_value_pointer_bug.vcxproj", "{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_ipv4_start_cache", "..\VS12-tests\ipv4_start_cache.vcxproj", "{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_ipv6_lookup_in_ipv4", "..\VS12-tests\ipv6_lookup_in_ipv4.vcxproj", "{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtap", "..\VS12-tests\libtap.vcxproj", "{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_metadata", "..\VS12-tests\metadata.vcxproj", "{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_no_map_get_value", "..\VS12-tests\no_map_get_value.vcxproj", "{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_read_node", "..\VS12-tests\read_node.vcxproj", "{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_maxminddb_test_helper", "..\VS12-tests\shared.vcxproj", "{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_version", "..\VS12-tests\version.vcxproj", "{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_bad_pointers", "..\VS12-tests\bad_pointers.vcxproj", "{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_metadata_pointers", "..\VS12-tests\metadata_pointers.vcxproj", "{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|Win32.ActiveCfg = Debug|Win32
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|Win32.Build.0 = Debug|Win32
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|x64.ActiveCfg = Debug|x64
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|x64.Build.0 = Debug|x64
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|Win32.ActiveCfg = Release|Win32
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|Win32.Build.0 = Release|Win32
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|x64.ActiveCfg = Release|x64
{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|x64.Build.0 = Release|x64
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|Win32.ActiveCfg = Debug|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|Win32.Build.0 = Debug|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|x64.ActiveCfg = Debug|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|Win32.ActiveCfg = Release|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|Win32.Build.0 = Release|Win32
{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|x64.ActiveCfg = Release|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|Win32.ActiveCfg = Debug|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|Win32.Build.0 = Debug|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|x64.ActiveCfg = Debug|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|Win32.ActiveCfg = Release|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|Win32.Build.0 = Release|Win32
{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|x64.ActiveCfg = Release|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32
{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\maxminddb.c" />
<ClCompile Include="..\..\src\data-pool.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\maxminddb.h" />
<ClInclude Include="..\..\src\data-pool.h" />
</ItemGroup>
<ItemGroup>
<None Include="README" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libmaxminddb</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="libmaxminddb.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="libmaxminddb.props" />
<Import Project="libmaxminddb-x64.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="libmaxminddb.props" />
<Import Project="libmaxminddb-release.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="libmaxminddb.props" />
<Import Project="libmaxminddb-x64.props" />
<Import Project="libmaxminddb-release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>$(ProjectName)d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>$(ProjectName)d</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent />
<Lib />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent />
<Lib />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent />
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\maxminddb.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\data-pool.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\maxminddb.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\data-pool.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="README" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,14 @@
#ifndef MAXMINDDB_CONFIG_H
#define MAXMINDDB_CONFIG_H
#ifndef MMDB_UINT128_USING_MODE
/* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
#define MMDB_UINT128_USING_MODE 0
#endif
#ifndef MMDB_UINT128_IS_BYTE_ARRAY
/* Define as 1 if we don't have an unsigned __int128 type */
#define MMDB_UINT128_IS_BYTE_ARRAY 1
#endif
#endif /* MAXMINDDB_CONFIG_H */

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{%UUID%}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>%TESTNAME%</RootNamespace>
<ProjectName>test_%TESTNAME%</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(Configuration)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap;$(SolutionDir)\..\..\src</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\t\%TESTNAME%_t.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="libtap.vcxproj">
<Project>{4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa}</Project>
</ProjectReference>
<ProjectReference Include="..\VS12\libmaxminddb.vcxproj">
<Project>{82953bda-2960-4ada-a6d5-92e65ccb4a3d}</Project>
</ProjectReference>
<ProjectReference Include="maxminddb_test_helper.vcxproj">
<Project>{a8f568f6-5507-4ec2-a834-f2c0a3c635a5}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

29
src/Makefile.am Normal file
View File

@ -0,0 +1,29 @@
include $(top_srcdir)/common.mk
lib_LTLIBRARIES = libmaxminddb.la
libmaxminddb_la_SOURCES = maxminddb.c maxminddb-compat-util.h \
data-pool.c data-pool.h
libmaxminddb_la_LDFLAGS = -version-info 0:7:0 -export-symbols-regex '^MMDB_.*'
if WINDOWS
libmaxminddb_la_LDFLAGS += -no-undefined
endif
include_HEADERS = $(top_srcdir)/include/maxminddb.h
pkgconfig_DATA = libmaxminddb.pc
TESTS = test-data-pool
check_PROGRAMS = test-data-pool
test_data_pool_SOURCES = data-pool.c data-pool.h
test_data_pool_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/t -DTEST_DATA_POOL
test_data_pool_LDADD = $(top_srcdir)/t/libmmdbtest.la \
$(top_srcdir)/t/libtap/libtap.a
$(top_srcdir)/t/libmmdbtest.la:
$(MAKE) -C $(top_srcdir)/t libmmdbtest.la
$(top_srcdir)/t/libtap/libtap.a:
$(MAKE) -C $(top_srcdir)/t/libtap libtap.a

169
src/data-pool.c Normal file
View File

@ -0,0 +1,169 @@
#include "data-pool.h"
#include "maxminddb.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
static bool can_multiply(size_t const, size_t const, size_t const);
// Allocate an MMDB_data_pool_s. It initially has space for size
// MMDB_entry_data_list_s structs.
MMDB_data_pool_s *data_pool_new(size_t const size) {
MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s));
if (!pool) {
return NULL;
}
if (size == 0 ||
!can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) {
data_pool_destroy(pool);
return NULL;
}
pool->size = size;
pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s));
if (!pool->blocks[0]) {
data_pool_destroy(pool);
return NULL;
}
pool->blocks[0]->pool = pool;
pool->sizes[0] = size;
pool->block = pool->blocks[0];
return pool;
}
// Determine if we can multiply m*n. We can do this if the result will be below
// the given max. max will typically be SIZE_MAX.
//
// We want to know if we'll wrap around.
static bool can_multiply(size_t const max, size_t const m, size_t const n) {
if (m == 0) {
return false;
}
return n <= max / m;
}
// Clean up the data pool.
void data_pool_destroy(MMDB_data_pool_s *const pool) {
if (!pool) {
return;
}
for (size_t i = 0; i <= pool->index; i++) {
free(pool->blocks[i]);
}
free(pool);
}
// Claim a new struct from the pool. Doing this may cause the pool's size to
// grow.
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool) {
if (!pool) {
return NULL;
}
if (pool->used < pool->size) {
MMDB_entry_data_list_s *const element = pool->block + pool->used;
pool->used++;
return element;
}
// Take it from a new block of memory.
size_t const new_index = pool->index + 1;
if (new_index == DATA_POOL_NUM_BLOCKS) {
// See the comment about not growing this on DATA_POOL_NUM_BLOCKS.
return NULL;
}
if (!can_multiply(SIZE_MAX, pool->size, 2)) {
return NULL;
}
size_t const new_size = pool->size * 2;
if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) {
return NULL;
}
pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s));
if (!pool->blocks[new_index]) {
return NULL;
}
// We don't need to set this, but it's useful for introspection in tests.
pool->blocks[new_index]->pool = pool;
pool->index = new_index;
pool->block = pool->blocks[pool->index];
pool->size = new_size;
pool->sizes[pool->index] = pool->size;
MMDB_entry_data_list_s *const element = pool->block;
pool->used = 1;
return element;
}
// Turn the structs in the array-like pool into a linked list.
//
// Before calling this function, the list isn't linked up.
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool) {
if (!pool) {
return NULL;
}
if (pool->index == 0 && pool->used == 0) {
return NULL;
}
for (size_t i = 0; i <= pool->index; i++) {
MMDB_entry_data_list_s *const block = pool->blocks[i];
size_t size = pool->sizes[i];
if (i == pool->index) {
size = pool->used;
}
for (size_t j = 0; j < size - 1; j++) {
MMDB_entry_data_list_s *const cur = block + j;
cur->next = block + j + 1;
}
if (i < pool->index) {
MMDB_entry_data_list_s *const last = block + size - 1;
last->next = pool->blocks[i + 1];
}
}
return pool->blocks[0];
}
#ifdef TEST_DATA_POOL
#include <libtap/tap.h>
#include <maxminddb_test_helper.h>
static void test_can_multiply(void);
int main(void) {
plan(NO_PLAN);
test_can_multiply();
done_testing();
}
static void test_can_multiply(void) {
{ ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok"); }
{ ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok"); }
{
ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)),
"1024 entry_data_list_s's are okay");
}
}
#endif

52
src/data-pool.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef DATA_POOL_H
#define DATA_POOL_H
#include "maxminddb.h"
#include <stdbool.h>
#include <stddef.h>
// This should be large enough that we never need to grow the array of pointers
// to blocks. 32 is enough. Even starting out of with size 1 (1 struct), the
// 32nd element alone will provide 2**32 structs as we exponentially increase
// the number in each block. Being confident that we do not have to grow the
// array lets us avoid writing code to do that. That code would be risky as it
// would rarely be hit and likely not be well tested.
#define DATA_POOL_NUM_BLOCKS 32
// A pool of memory for MMDB_entry_data_list_s structs. This is so we can
// allocate multiple up front rather than one at a time for performance
// reasons.
//
// The order you add elements to it (by calling data_pool_alloc()) ends up as
// the order of the list.
//
// The memory only grows. There is no support for releasing an element you take
// back to the pool.
typedef struct MMDB_data_pool_s {
// Index of the current block we're allocating out of.
size_t index;
// The size of the current block, counting by structs.
size_t size;
// How many used in the current block, counting by structs.
size_t used;
// The current block we're allocating out of.
MMDB_entry_data_list_s *block;
// The size of each block.
size_t sizes[DATA_POOL_NUM_BLOCKS];
// An array of pointers to blocks of memory holding space for list
// elements.
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
} MMDB_data_pool_s;
MMDB_data_pool_s *data_pool_new(size_t const);
void data_pool_destroy(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const);
#endif

11
src/libmaxminddb.pc.in Normal file
View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@prefix@
libdir=@libdir@
includedir=@includedir@
Name: libmaxminddb
Description: C library for the MaxMind DB file format
URL: https://maxmind.github.io/libmaxminddb/
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lmaxminddb
Cflags: -I${includedir}

160
src/maxminddb-compat-util.h Normal file
View File

@ -0,0 +1,160 @@
#include <stdlib.h>
#include <string.h>
/* *INDENT-OFF* */
/* The memmem, strdup, and strndup functions were all copied from the
* FreeBSD source, along with the relevant copyright notice.
*
* It'd be nicer to simply use the functions available on the system if they
* exist, but there doesn't seem to be a good way to detect them without also
* defining things like _GNU_SOURCE, which we want to avoid, because then we
* end up _accidentally_ using GNU features without noticing, which then
* breaks on systems like OSX.
*
* C is fun! */
/* Applies to memmem implementation */
/*-
* Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static const void *
mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) {
const char *cur, *last;
const char *cl = (const char *)l;
const char *cs = (const char *)s;
/* we need something to compare */
if (l_len == 0 || s_len == 0)
return NULL;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, (int)*cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = cl + l_len - s_len;
for (cur = cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur;
return NULL;
}
/* Applies to strnlen implementation */
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static size_t mmdb_strnlen(const char *s, size_t maxlen) {
size_t len;
for (len = 0; len < maxlen; len++, s++) {
if (!*s)
break;
}
return (len);
}
/* Applies to strdup and strndup implementation */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static char *mmdb_strdup(const char *str) {
size_t len;
char *copy;
len = strlen(str) + 1;
if ((copy = malloc(len)) == NULL)
return (NULL);
memcpy(copy, str, len);
return (copy);
}
static char *mmdb_strndup(const char *str, size_t n) {
size_t len;
char *copy;
len = mmdb_strnlen(str, n);
if ((copy = malloc(len + 1)) == NULL)
return (NULL);
memcpy(copy, str, len);
copy[len] = '\0';
return (copy);
}
/* *INDENT-ON* */

2138
src/maxminddb.c Normal file

File diff suppressed because it is too large Load Diff

46
t/CMakeLists.txt Normal file
View File

@ -0,0 +1,46 @@
add_library(tap
libtap/tap.c
)
# test programs
set(TEST_TARGET_NAMES
bad_pointers_t
basic_lookup_t
data_entry_list_t
data-pool-t
data_types_t
dump_t
get_value_pointer_bug_t
get_value_t
ipv4_start_cache_t
ipv6_lookup_in_ipv4_t
metadata_pointers_t
metadata_t
no_map_get_value_t
read_node_t
version_t
)
if(UNIX) # or if (NOT WIN32)
list(APPEND TEST_TARGET_NAMES
bad_databases_t
threads_t
)
find_package(Threads)
endif()
foreach(TEST_TARGET_NAME ${TEST_TARGET_NAMES})
add_executable(${TEST_TARGET_NAME} ${TEST_TARGET_NAME}.c maxminddb_test_helper.c)
target_include_directories(${TEST_TARGET_NAME} PRIVATE ../src)
target_link_libraries(${TEST_TARGET_NAME} maxminddb tap)
if(UNIX)
target_link_libraries(${TEST_TARGET_NAME} m)
endif()
if (UNIX)
target_link_libraries(${TEST_TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
endif()
add_test( NAME ${TEST_TARGET_NAME} COMMAND ${TEST_TARGET_NAME} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/t)
endforeach()

31
t/Makefile.am Normal file
View File

@ -0,0 +1,31 @@
include $(top_srcdir)/common.mk
all-local:
cd libtap && $(MAKE) $(AM_MAKEFLAGS) all
clean-local:
cd libtap && $(MAKE) $(AM_MAKEFLAGS) clean
AM_LDFLAGS = $(top_builddir)/src/libmaxminddb.la
CFLAGS += -I$(top_srcdir)/src
noinst_LTLIBRARIES = libmmdbtest.la
libmmdbtest_la_SOURCES = maxminddb_test_helper.c maxminddb_test_helper.h
EXTRA_DIST = compile_c++_t.pl external_symbols_t.pl mmdblookup_t.pl \
libtap/COPYING libtap/INSTALL libtap/Makefile libtap/README.md \
libtap/tap.c libtap/tap.h maxmind-db
check_PROGRAMS = \
bad_pointers_t bad_databases_t basic_lookup_t data_entry_list_t \
data-pool-t data_types_t dump_t get_value_t get_value_pointer_bug_t \
ipv4_start_cache_t ipv6_lookup_in_ipv4_t metadata_t metadata_pointers_t \
no_map_get_value_t read_node_t threads_t version_t
data_pool_t_LDFLAGS = $(AM_LDFLAGS) -lm
data_pool_t_SOURCES = data-pool-t.c ../src/data-pool.c
threads_t_CFLAGS = $(CFLAGS) -pthread
TESTS = $(check_PROGRAMS) compile_c++_t.pl external_symbols_t.pl mmdblookup_t.pl
LDADD = libmmdbtest.la libtap/libtap.a

67
t/bad_databases_t.c Normal file
View File

@ -0,0 +1,67 @@
// This test currently does not work on Windows as nftw is
// not available.
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <libgen.h>
#include <unistd.h>
#include "maxminddb_test_helper.h"
int test_read(const char *path,
const struct stat *UNUSED(sbuf),
int flags,
struct FTW *UNUSED(ftw)) {
// Check if path is a regular file)
if (flags != FTW_F) {
return 0;
}
MMDB_s *mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s));
if (NULL == mmdb) {
BAIL_OUT("could not allocate memory for our MMDB_s struct");
}
int status = MMDB_open(path, MMDB_MODE_MMAP, mmdb);
if (status != MMDB_SUCCESS) {
ok(1, "received error when opening %s", path);
free(mmdb);
return 0;
}
int gai_error, mmdb_error;
MMDB_lookup_string(mmdb, "1.1.1.1", &gai_error, &mmdb_error);
if (gai_error != 0) {
BAIL_OUT("could not parse IP address");
}
cmp_ok(
mmdb_error, "!=", MMDB_SUCCESS, "opening %s returned an error", path);
MMDB_close(mmdb);
free(mmdb);
return 0;
}
int main(void) {
char *test_db_dir;
#ifdef _WIN32
test_db_dir = "../t/maxmind-db/bad-data";
#else
char cwd[500];
char *UNUSED(tmp) = getcwd(cwd, 500);
if (strcmp(basename(cwd), "t") == 0) {
test_db_dir = "./maxmind-db/bad-data";
} else {
test_db_dir = "./t/maxmind-db/bad-data";
}
#endif
plan(NO_PLAN);
if (nftw(test_db_dir, test_read, 10, FTW_PHYS) != 0) {
BAIL_OUT("nftw failed");
}
done_testing();
}

58
t/bad_pointers_t.c Normal file
View File

@ -0,0 +1,58 @@
#include "maxminddb_test_helper.h"
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-broken-pointers-24.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
{
const char *ip = "1.1.1.16";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
MMDB_entry_data_s entry_data;
int status = MMDB_get_value(&result.entry, &entry_data, NULL);
cmp_ok(status,
"==",
MMDB_INVALID_DATA_ERROR,
"MMDB_get_value returns MMDB_INVALID_DATA_ERROR for bad pointer "
"in data section");
MMDB_entry_data_list_s *entry_data_list;
status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
cmp_ok(status,
"==",
MMDB_INVALID_DATA_ERROR,
"MMDB_get_entry_data_list returns MMDB_INVALID_DATA_ERROR for "
"bad pointer in data section");
MMDB_free_entry_data_list(entry_data_list);
}
{
const char *ip = "1.1.1.32";
int gai_error, mmdb_error;
MMDB_lookup_result_s UNUSED(result) =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
cmp_ok(mmdb_error,
"==",
MMDB_CORRUPT_SEARCH_TREE_ERROR,
"MMDB_lookup_string sets mmdb_error to "
"MMDB_CORRUPT_SEARCH_TREE_ERROR when a search tree record "
"points outside the data section");
}
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

215
t/basic_lookup_t.c Normal file
View File

@ -0,0 +1,215 @@
#include "maxminddb_test_helper.h"
static void test_big_lookup(void);
/* These globals are gross but it's the easiest way to mix calling
* for_all_modes() and for_all_record_sizes() */
static int Current_Mode;
static const char *Current_Mode_Description;
void test_one_result(MMDB_s *mmdb,
MMDB_lookup_result_s result,
const char *ip,
const char *expect,
const char *function,
const char *filename,
const char *mode_desc) {
int is_ok = ok(result.found_entry,
"got a result for an IP in the database - %s - %s - %s - %s",
function,
ip,
filename,
mode_desc);
if (!is_ok) {
return;
}
MMDB_entry_data_s data =
data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "result{ip}", "ip", NULL);
char *string = mmdb_strndup(data.utf8_string, data.data_size);
char *real_expect;
if (mmdb->metadata.ip_version == 4 || strncmp(expect, "::", 2) == 0) {
real_expect = mmdb_strndup(expect, strlen(expect));
} else {
// When looking up IPv4 addresses in a mixed DB the result will be
// something like "::1.2.3.4", not just "1.2.3.4".
size_t maxlen = strlen(expect) + 3;
real_expect = malloc(maxlen);
if (!real_expect) {
BAIL_OUT("could not allocate memory");
}
snprintf(real_expect, maxlen, "::%s", expect);
}
is(string,
real_expect,
"found expected result for ip key - %s - %s - %s - %s",
function,
ip,
filename,
mode_desc);
free(real_expect);
free(string);
}
void test_one_ip(MMDB_s *mmdb,
const char *ip,
const char *expect,
const char *filename,
const char *mode_desc) {
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
test_one_result(
mmdb, result, ip, expect, "MMDB_lookup_string", filename, mode_desc);
result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc);
test_one_result(
mmdb, result, ip, expect, "MMDB_lookup_addrinfo", filename, mode_desc);
}
void run_ipX_tests(const char *filename,
const char **missing_ips,
int missing_ips_length,
const char *pairs[][2],
int pairs_rows) {
char *path = test_database_path(filename);
int mode = Current_Mode;
const char *mode_desc = Current_Mode_Description;
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
char desc_suffix[500];
snprintf(desc_suffix, 500, "%s - %s", filename, mode_desc);
for (int i = 0; i < missing_ips_length; i++) {
const char *ip = missing_ips[i];
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(!result.found_entry,
"no result entry struct returned for IP address not in the database "
"(string lookup) - %s - %s - %s",
ip,
filename,
mode_desc);
result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc);
ok(!result.found_entry,
"no result entry struct returned for IP address not in the database "
"(ipv4 lookup) - %s - %s - %s",
ip,
filename,
mode_desc);
}
for (int i = 0; i < pairs_rows; i += 1) {
const char *ip_to_lookup = pairs[i][0];
const char *expect = pairs[i][1];
test_one_ip(mmdb, ip_to_lookup, expect, filename, mode_desc);
}
MMDB_close(mmdb);
free(mmdb);
}
void run_ipv4_tests(int UNUSED(record_size),
const char *filename,
const char *UNUSED(ignored)) {
const char *pairs[9][2] = {
{"1.1.1.1", "1.1.1.1"},
{"1.1.1.2", "1.1.1.2"},
{"1.1.1.3", "1.1.1.2"},
{"1.1.1.7", "1.1.1.4"},
{"1.1.1.9", "1.1.1.8"},
{"1.1.1.15", "1.1.1.8"},
{"1.1.1.17", "1.1.1.16"},
{"1.1.1.31", "1.1.1.16"},
{"1.1.1.32", "1.1.1.32"},
};
const char *missing[1] = {"2.3.4.5"};
run_ipX_tests(filename, missing, 1, pairs, 9);
}
void run_ipv6_tests(int UNUSED(record_size),
const char *filename,
const char *UNUSED(ignored)) {
const char *pairs[9][2] = {
{"::1:ffff:ffff", "::1:ffff:ffff"},
{"::2:0:0", "::2:0:0"},
{"::2:0:1a", "::2:0:0"},
{"::2:0:40", "::2:0:40"},
{"::2:0:4f", "::2:0:40"},
{"::2:0:50", "::2:0:50"},
{"::2:0:52", "::2:0:50"},
{"::2:0:58", "::2:0:58"},
{"::2:0:59", "::2:0:58"},
};
const char *missing[2] = {"2.3.4.5", "::abcd"};
run_ipX_tests(filename, missing, 2, pairs, 9);
}
void all_record_sizes(int mode, const char *description) {
const char *ipv4_filename_fmts[] = {"MaxMind-DB-test-ipv4-%i.mmdb",
"MaxMind-DB-test-mixed-%i.mmdb"};
Current_Mode = mode;
Current_Mode_Description = description;
for (int i = 0; i < 2; i++) {
for_all_record_sizes(ipv4_filename_fmts[i], &run_ipv4_tests);
}
const char *ipv6_filename_fmts[] = {"MaxMind-DB-test-ipv6-%i.mmdb",
"MaxMind-DB-test-mixed-%i.mmdb"};
for (int i = 0; i < 2; i++) {
for_all_record_sizes(ipv6_filename_fmts[i], &run_ipv6_tests);
}
}
static void test_big_lookup(void) {
const char *const db_filename = "GeoIP2-Precision-Enterprise-Test.mmdb";
char *db_path = test_database_path(db_filename);
ok(db_path != NULL, "got database path");
MMDB_s *const mmdb = open_ok(db_path, MMDB_MODE_MMAP, "mmap mode");
ok(mmdb != NULL, "opened MMDB");
free(db_path);
int gai_err = 0, mmdb_err = 0;
const char *const ip_address = "81.2.69.160";
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ip_address, &gai_err, &mmdb_err);
ok(gai_err == 0, "no getaddrinfo error");
ok(mmdb_err == MMDB_SUCCESS, "no error from maxminddb library");
ok(result.found_entry, "found IP");
MMDB_entry_data_list_s *entry_data_list = NULL;
ok(MMDB_get_entry_data_list(&result.entry, &entry_data_list) ==
MMDB_SUCCESS,
"successfully looked up entry data list");
ok(entry_data_list != NULL, "got an entry_data_list");
MMDB_free_entry_data_list(entry_data_list);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&all_record_sizes);
test_big_lookup();
done_testing();
}

120
t/compile_c++_t.pl Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd qw( abs_path );
use FindBin qw( $Bin );
eval <<'EOF';
use Test::More 0.88;
use File::Temp qw( tempdir );
use IPC::Run3 qw( run3 );
EOF
if ($@) {
print
"1..0 # skip all tests skipped - these tests need the Test::More 0.88, File::Temp, and IPC::Run3 modules:\n";
print "$@";
exit 0;
}
my $test_db = "$Bin/maxmind-db/test-data/GeoIP2-City-Test.mmdb";
my $cpp_code = <<"EOF";
#include <maxminddb.h>
int main(int argc, char *argv[])
{
const char *fname = "$test_db";
MMDB_s mmdb;
if (MMDB_open(fname, MMDB_MODE_MMAP, &mmdb) != MMDB_SUCCESS) {
return 1;
}
MMDB_close(&mmdb);
return 0;
}
EOF
my $tempdir = tempdir(CLEANUP => 1 );
my $file = "$tempdir/open.cpp";
open my $fh, '>', $file or die $!;
print {$fh} $cpp_code or die $!;
close $fh or die $!;
my $exe = "$tempdir/open";
my $include_dir = abs_path("$Bin/../include");
my $lib_dir = abs_path("$Bin/../src/.libs");
my $cxx = $ENV{CXX} || 'c++';
my @cxxflags = $ENV{CXXFLAGS} ? ( split ' ', $ENV{CXXFLAGS} ) : ();
_test_cmd(
[
$cxx,
$file,
@cxxflags,
"-I$include_dir",
"-L$lib_dir",
"-lmaxminddb",
"-o$exe",
],
qr/^$/,
q{},
0,
'compile C++ program which links against libmaxminddb',
);
# DYLD_LIBRARY_PATH is for Mac OS X
$ENV{LD_LIBRARY_PATH} = $ENV{DYLD_LIBRARY_PATH} = $lib_dir;
_test_cmd(
[$exe],
qr/^$/,
q{},
0,
'compiled C++ program executes without errors'
);
done_testing();
sub _test_cmd {
my $cmd = shift;
my $expect_stdout = shift;
my $expect_stderr = shift;
my $expect_status = shift;
my $desc = shift;
my $stdout;
my $stderr;
run3(
$cmd,
\undef,
\$stdout,
\$stderr,
);
my $exit_status = $? >> 8;
# We don't need to retest that the help output shows up for all errors
if ( defined $expect_stdout ) {
like(
$stdout,
$expect_stdout,
"stdout for @{$cmd}"
);
}
if ( ref $expect_stderr ) {
like( $stderr, $expect_stderr, "stderr for @{$cmd}" );
}
else {
is( $stderr, $expect_stderr, "stderr for @{$cmd}" );
}
is(
$exit_status, $expect_status,
"exit status was $expect_status for @{$cmd}"
);
}

344
t/data-pool-t.c Normal file
View File

@ -0,0 +1,344 @@
#include "libtap/tap.h"
#include "maxminddb_test_helper.h"
#include <assert.h>
#include <data-pool.h>
#include <inttypes.h>
#include <math.h>
static void test_data_pool_new(void);
static void test_data_pool_destroy(void);
static void test_data_pool_alloc(void);
static void test_data_pool_to_list(void);
static bool create_and_check_list(size_t const, size_t const);
static void check_block_count(MMDB_entry_data_list_s const *const,
size_t const);
int main(void) {
plan(NO_PLAN);
test_data_pool_new();
test_data_pool_destroy();
test_data_pool_alloc();
test_data_pool_to_list();
done_testing();
}
static void test_data_pool_new(void) {
{
MMDB_data_pool_s *const pool = data_pool_new(0);
ok(!pool, "size 0 is not valid");
}
{
MMDB_data_pool_s *const pool = data_pool_new(SIZE_MAX - 10);
ok(!pool, "very large size is not valid");
}
{
MMDB_data_pool_s *const pool = data_pool_new(512);
ok(pool != NULL, "size 512 is valid");
cmp_ok(pool->size, "==", 512, "size is 512");
cmp_ok(pool->used, "==", 0, "used size is 0");
data_pool_destroy(pool);
}
}
static void test_data_pool_destroy(void) {
{ data_pool_destroy(NULL); }
{
MMDB_data_pool_s *const pool = data_pool_new(512);
ok(pool != NULL, "created pool");
data_pool_destroy(pool);
}
}
static void test_data_pool_alloc(void) {
{
MMDB_data_pool_s *const pool = data_pool_new(1);
ok(pool != NULL, "created pool");
cmp_ok(pool->used, "==", 0, "used size starts at 0");
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
ok(entry1 != NULL, "allocated first entry");
// Arbitrary so that we can recognize it.
entry1->entry_data.offset = (uint32_t)123;
cmp_ok(pool->size, "==", 1, "size is still 1");
cmp_ok(pool->used, "==", 1, "used size is 1 after taking one");
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
ok(entry2 != NULL, "got another entry");
ok(entry1 != entry2, "second entry is different from first entry");
cmp_ok(pool->size, "==", 2, "size is 2 (new block)");
cmp_ok(pool->used, "==", 1, "used size is 1 in current block");
ok(entry1->entry_data.offset == 123,
"accessing the original entry's memory is ok");
data_pool_destroy(pool);
}
{
size_t const initial_size = 10;
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
ok(pool != NULL, "created pool");
MMDB_entry_data_list_s *entry1 = NULL;
for (size_t i = 0; i < initial_size; i++) {
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
ok(entry != NULL, "got an entry");
// Give each a unique number so we can check it.
entry->entry_data.offset = (uint32_t)i;
if (i == 0) {
entry1 = entry;
}
}
cmp_ok(pool->size, "==", initial_size, "size is the initial size");
cmp_ok(pool->used, "==", initial_size, "used size is as expected");
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
ok(entry != NULL, "got an entry");
entry->entry_data.offset = (uint32_t)initial_size;
cmp_ok(
pool->size, "==", initial_size * 2, "size is the initial size*2");
cmp_ok(pool->used, "==", 1, "used size is as expected");
MMDB_entry_data_list_s *const list = data_pool_to_list(pool);
MMDB_entry_data_list_s *element = list;
for (size_t i = 0; i < initial_size + 1; i++) {
ok(element->entry_data.offset == (uint32_t)i,
"found offset %" PRIu32 ", should have %zu",
element->entry_data.offset,
i);
element = element->next;
}
ok(entry1->entry_data.offset == (uint32_t)0,
"accessing entry1's original memory is ok after growing the pool");
data_pool_destroy(pool);
}
}
static void test_data_pool_to_list(void) {
{
size_t const initial_size = 16;
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
ok(pool != NULL, "created pool");
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
ok(entry1 != NULL, "got an entry");
MMDB_entry_data_list_s *const list_one_element =
data_pool_to_list(pool);
ok(list_one_element != NULL, "got a list");
ok(list_one_element == entry1,
"list's first element is the first we retrieved");
ok(list_one_element->next == NULL, "list is one element in size");
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
ok(entry2 != NULL, "got another entry");
MMDB_entry_data_list_s *const list_two_elements =
data_pool_to_list(pool);
ok(list_two_elements != NULL, "got a list");
ok(list_two_elements == entry1,
"list's first element is the first we retrieved");
ok(list_two_elements->next != NULL, "list has a second element");
MMDB_entry_data_list_s *const second_element = list_two_elements->next;
ok(second_element == entry2,
"second item in list is second we retrieved");
ok(second_element->next == NULL, "list ends with the second element");
data_pool_destroy(pool);
}
{
size_t const initial_size = 1;
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
ok(pool != NULL, "created pool");
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
ok(entry1 != NULL, "got an entry");
MMDB_entry_data_list_s *const list_one_element =
data_pool_to_list(pool);
ok(list_one_element != NULL, "got a list");
ok(list_one_element == entry1,
"list's first element is the first we retrieved");
ok(list_one_element->next == NULL, "list ends with this element");
data_pool_destroy(pool);
}
{
size_t const initial_size = 2;
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
ok(pool != NULL, "created pool");
MMDB_entry_data_list_s *const entry1 = data_pool_alloc(pool);
ok(entry1 != NULL, "got an entry");
MMDB_entry_data_list_s *const entry2 = data_pool_alloc(pool);
ok(entry2 != NULL, "got an entry");
ok(entry1 != entry2, "second entry is different from the first");
MMDB_entry_data_list_s *const list_element1 = data_pool_to_list(pool);
ok(list_element1 != NULL, "got a list");
ok(list_element1 == entry1,
"list's first element is the first we retrieved");
MMDB_entry_data_list_s *const list_element2 = list_element1->next;
ok(list_element2 == entry2,
"second element is the second we retrieved");
ok(list_element2->next == NULL, "list ends with this element");
data_pool_destroy(pool);
}
{
diag("starting test: fill one block save for one spot");
ok(create_and_check_list(3, 2), "fill one block save for one spot");
}
{
diag("starting test: fill one block");
ok(create_and_check_list(3, 3), "fill one block");
}
{
diag(
"starting test: fill one block and use one spot in the next block");
ok(create_and_check_list(3, 3 + 1),
"fill one block and use one spot in the next block");
}
{
diag("starting test: fill two blocks save for one spot");
ok(create_and_check_list(3, 3 + 3 * 2 - 1),
"fill two blocks save for one spot");
}
{
diag("starting test: fill two blocks");
ok(create_and_check_list(3, 3 + 3 * 2), "fill two blocks");
}
{
diag("starting test: fill two blocks and use one spot in the next");
ok(create_and_check_list(3, 3 + 3 * 2 + 1),
"fill two blocks and use one spot in the next");
}
{
diag("starting test: fill three blocks save for one spot");
ok(create_and_check_list(3, 3 + 3 * 2 + 3 * 2 * 2 - 1),
"fill three blocks save for one spot");
}
{
diag("starting test: fill three blocks");
ok(create_and_check_list(3, 3 + 3 * 2 + 3 * 2 * 2),
"fill three blocks");
}
// It would be nice to have a larger number of these, but it's expensive to
// run many. We currently hardcode what this will be anyway, so varying
// this is not very interesting.
size_t const initial_sizes[] = {1, 2, 32, 64, 128, 256};
size_t const max_element_count = 4096;
for (size_t i = 0; i < sizeof(initial_sizes) / sizeof(initial_sizes[0]);
i++) {
size_t const initial_size = initial_sizes[i];
for (size_t element_count = 0; element_count < max_element_count;
element_count++) {
assert(create_and_check_list(initial_size, element_count));
}
}
}
// Use assert() rather than libtap as libtap is significantly slower and we run
// this frequently.
static bool create_and_check_list(size_t const initial_size,
size_t const element_count) {
MMDB_data_pool_s *const pool = data_pool_new(initial_size);
assert(pool != NULL);
assert(pool->used == 0);
// Hold on to the pointers as we initially see them so that we can check
// they are still valid after building the list.
MMDB_entry_data_list_s **const entry_array =
calloc(element_count, sizeof(MMDB_entry_data_list_s *));
assert(entry_array != NULL);
for (size_t i = 0; i < element_count; i++) {
MMDB_entry_data_list_s *const entry = data_pool_alloc(pool);
assert(entry != NULL);
entry->entry_data.offset = (uint32_t)i;
entry_array[i] = entry;
}
MMDB_entry_data_list_s *const list = data_pool_to_list(pool);
if (element_count == 0) {
assert(list == NULL);
data_pool_destroy(pool);
free(entry_array);
return true;
}
assert(list != NULL);
MMDB_entry_data_list_s *element = list;
for (size_t i = 0; i < element_count; i++) {
assert(element->entry_data.offset == (uint32_t)i);
assert(element == entry_array[i]);
element = element->next;
}
assert(element == NULL);
check_block_count(list, initial_size);
data_pool_destroy(pool);
free(entry_array);
return true;
}
// Use assert() rather than libtap as libtap is significantly slower and we run
// this frequently.
static void check_block_count(MMDB_entry_data_list_s const *const list,
size_t const initial_size) {
size_t got_block_count = 0;
size_t got_element_count = 0;
MMDB_entry_data_list_s const *element = list;
while (element) {
got_element_count++;
if (element->pool) {
got_block_count++;
}
element = element->next;
}
// Because <number of elements> = <initial size> * 2^(number of blocks)
double const a = ceil((double)got_element_count / (double)initial_size);
double const b = log2(a);
size_t const expected_block_count = ((size_t)b) + 1;
assert(got_block_count == expected_block_count);
}

429
t/data_entry_list_t.c Normal file
View File

@ -0,0 +1,429 @@
#include "maxminddb_test_helper.h"
MMDB_entry_data_list_s *
test_array_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *array = entry_data_list = entry_data_list->next;
cmp_ok(array->entry_data.type,
"==",
MMDB_DATA_TYPE_ARRAY,
"'array' key's value is an array");
cmp_ok(array->entry_data.data_size,
"==",
3,
"'array' key's value has 3 elements");
MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next;
cmp_ok(idx0->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"first array entry is a UINT32");
cmp_ok(idx0->entry_data.uint32, "==", 1, "first array entry value is 1");
MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next;
cmp_ok(idx1->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"second array entry is a UINT32");
cmp_ok(idx1->entry_data.uint32, "==", 2, "second array entry value is 2");
MMDB_entry_data_list_s *idx2 = entry_data_list = entry_data_list->next;
cmp_ok(idx2->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"third array entry is a UINT32");
cmp_ok(idx2->entry_data.uint32, "==", 3, "third array entry value is 3");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_boolean_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_BOOLEAN,
"'boolean' key's value is a boolean");
ok(value->entry_data.boolean, "'boolean' key's value is true");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_bytes_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_BYTES,
"'bytes' key's value is bytes");
uint8_t *bytes = malloc(value->entry_data.data_size);
if (NULL == bytes) {
BAIL_OUT("malloc failed");
}
memcpy(bytes, value->entry_data.bytes, value->entry_data.data_size);
uint8_t expect[] = {0x00, 0x00, 0x00, 0x2a};
ok(memcmp(bytes, expect, 4) == 0, "got expected value for bytes key");
free((void *)bytes);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_double_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_DOUBLE,
"'double' key's value is a double");
compare_double(value->entry_data.double_value, 42.123456);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_float_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_FLOAT,
"'float' key's value is a float");
compare_float(value->entry_data.float_value, 1.1F);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_int32_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_INT32,
"'int32' key's value is an int32");
int32_t expect = 1 << 28;
expect *= -1;
cmp_ok(value->entry_data.int32,
"==",
expect,
"got expected value for int32 key");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_arrayX_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *arrayX = entry_data_list = entry_data_list->next;
cmp_ok(arrayX->entry_data.type,
"==",
MMDB_DATA_TYPE_ARRAY,
"'map{mapX}{arrayX}' key's value is an array");
cmp_ok(arrayX->entry_data.data_size,
"==",
3,
"'map{mapX}{arrayX}' key's value has 3 elements");
MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next;
cmp_ok(idx0->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"first array entry is a UINT32");
cmp_ok(idx0->entry_data.uint32, "==", 7, "first array entry value is 7");
MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next;
cmp_ok(idx1->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"second array entry is a UINT32");
cmp_ok(idx1->entry_data.uint32, "==", 8, "second array entry value is 8");
MMDB_entry_data_list_s *idx2 = entry_data_list = entry_data_list->next;
cmp_ok(idx2->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"third array entry is a UINT32");
cmp_ok(idx2->entry_data.uint32, "==", 9, "third array entry value is 9");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_mapX_key_value_pair(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *mapX_key = entry_data_list = entry_data_list->next;
cmp_ok(mapX_key->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"found a map key in 'map{mapX}'");
char *mapX_key_name = dup_entry_string_or_bail(mapX_key->entry_data);
if (strcmp(mapX_key_name, "utf8_stringX") == 0) {
MMDB_entry_data_list_s *mapX_value = entry_data_list =
entry_data_list->next;
cmp_ok(mapX_value->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"'map{mapX}{utf8_stringX}' type is utf8_string");
char *utf8_stringX_value =
dup_entry_string_or_bail(mapX_value->entry_data);
ok(strcmp(utf8_stringX_value, "hello") == 0,
"map{mapX}{utf8_stringX} value is 'hello'");
free(utf8_stringX_value);
} else if (strcmp(mapX_key_name, "arrayX") == 0) {
entry_data_list = test_arrayX_value(entry_data_list);
} else {
ok(0, "unknown key found in map{mapX} - %s", mapX_key_name);
}
free(mapX_key_name);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_map_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *map = entry_data_list = entry_data_list->next;
cmp_ok(map->entry_data.type,
"==",
MMDB_DATA_TYPE_MAP,
"'map' key's value is a map");
cmp_ok(map->entry_data.data_size,
"==",
1,
"'map' key's value has 1 key/value pair");
MMDB_entry_data_list_s *map_key_1 = entry_data_list = entry_data_list->next;
cmp_ok(map_key_1->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"found a map key in 'map'");
char *map_key_1_name = dup_entry_string_or_bail(map_key_1->entry_data);
ok(strcmp(map_key_1_name, "mapX") == 0, "key name is mapX");
free(map_key_1_name);
MMDB_entry_data_list_s *mapX = entry_data_list = entry_data_list->next;
cmp_ok(mapX->entry_data.type,
"==",
MMDB_DATA_TYPE_MAP,
"'map{mapX}' key's value is a map");
cmp_ok(mapX->entry_data.data_size,
"==",
2,
"'map' key's value has 2 key/value pairs");
entry_data_list = test_mapX_key_value_pair(entry_data_list);
entry_data_list = test_mapX_key_value_pair(entry_data_list);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_uint128_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT128,
"'uint128' key's value is an uint128");
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t expect[16] = {0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
ok(memcmp(value->entry_data.uint128, expect, 16) == 0,
"uint128 field is 2**120");
#else
mmdb_uint128_t expect = 1;
expect <<= 120;
cmp_ok(value->entry_data.uint128, "==", expect, "uint128 field is 2**120");
#endif
return entry_data_list;
}
MMDB_entry_data_list_s *
test_uint16_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT16,
"'uint16' key's value is an uint16");
uint16_t expect = 100;
ok(value->entry_data.uint16 == expect, "uint16 field is 100");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_uint32_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"'uint32' key's value is an uint32");
uint32_t expect = 1 << 28;
cmp_ok(value->entry_data.uint32, "==", expect, "uint32 field is 100");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_uint64_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UINT64,
"'uint64' key's value is an uint64");
uint64_t expect = 1;
expect <<= 60;
cmp_ok(value->entry_data.uint64, "==", expect, "uint64 field is 2**60");
return entry_data_list;
}
MMDB_entry_data_list_s *
test_utf8_string_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"'utf8_string' key's value is a string");
char *utf8_string = dup_entry_string_or_bail(value->entry_data);
// This is hex for "unicode! ☯ - ♫" as bytes
char expect[19] = {0x75,
0x6e,
0x69,
0x63,
0x6f,
0x64,
0x65,
0x21,
0x20,
(char)0xe2,
(char)0x98,
(char)0xaf,
0x20,
0x2d,
0x20,
(char)0xe2,
(char)0x99,
(char)0xab,
0x00};
is(utf8_string, expect, "got expected value for utf8_string key");
free(utf8_string);
return entry_data_list;
}
void run_tests(int mode, const char *description) {
const char *filename = "MaxMind-DB-test-decoder.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, description);
free(path);
char *ip = "1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, description);
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) {
BAIL_OUT("MMDB_get_entry_data_list failed with %s",
MMDB_strerror(status));
} else {
cmp_ok(
status, "==", MMDB_SUCCESS, "MMDB_get_entry_data_list succeeded");
}
first = entry_data_list;
cmp_ok(entry_data_list->entry_data.type,
"==",
MMDB_DATA_TYPE_MAP,
"first entry in entry data list is a map");
cmp_ok(entry_data_list->entry_data.data_size,
"==",
12,
"first map in entry data list has 12 k/v pairs");
while (1) {
MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next;
if (!key) {
break;
}
cmp_ok(key->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"found a map key");
char *key_name = dup_entry_string_or_bail(key->entry_data);
if (strcmp(key_name, "array") == 0) {
entry_data_list = test_array_value(entry_data_list);
} else if (strcmp(key_name, "boolean") == 0) {
entry_data_list = test_boolean_value(entry_data_list);
} else if (strcmp(key_name, "bytes") == 0) {
entry_data_list = test_bytes_value(entry_data_list);
} else if (strcmp(key_name, "double") == 0) {
entry_data_list = test_double_value(entry_data_list);
} else if (strcmp(key_name, "float") == 0) {
entry_data_list = test_float_value(entry_data_list);
} else if (strcmp(key_name, "int32") == 0) {
entry_data_list = test_int32_value(entry_data_list);
} else if (strcmp(key_name, "map") == 0) {
entry_data_list = test_map_value(entry_data_list);
} else if (strcmp(key_name, "uint128") == 0) {
entry_data_list = test_uint128_value(entry_data_list);
} else if (strcmp(key_name, "uint16") == 0) {
entry_data_list = test_uint16_value(entry_data_list);
} else if (strcmp(key_name, "uint32") == 0) {
entry_data_list = test_uint32_value(entry_data_list);
} else if (strcmp(key_name, "uint64") == 0) {
entry_data_list = test_uint64_value(entry_data_list);
} else if (strcmp(key_name, "utf8_string") == 0) {
entry_data_list = test_utf8_string_value(entry_data_list);
} else {
ok(0, "unknown key found in map - %s", key_name);
}
free(key_name);
}
MMDB_free_entry_data_list(first);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

533
t/data_types_t.c Normal file
View File

@ -0,0 +1,533 @@
#include "maxminddb_test_helper.h"
void test_all_data_types(MMDB_lookup_result_s *result,
const char *ip,
const char *UNUSED(filename),
const char *mode_desc) {
{
char description[500];
snprintf(
description, 500, "utf8_string field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(result,
MMDB_DATA_TYPE_UTF8_STRING,
description,
"utf8_string",
NULL);
char *string = mmdb_strndup(data.utf8_string, data.data_size);
// This is hex for "unicode! ☯ - ♫" as bytes
char expect[19] = {0x75,
0x6e,
0x69,
0x63,
0x6f,
0x64,
0x65,
0x21,
0x20,
(char)0xe2,
(char)0x98,
(char)0xaf,
0x20,
0x2d,
0x20,
(char)0xe2,
(char)0x99,
(char)0xab,
0x00};
is(string, expect, "got expected utf8_string value");
free(string);
}
{
char description[500];
snprintf(description, 500, "double field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL);
compare_double(data.double_value, 42.123456);
}
{
char description[500];
snprintf(description, 500, "float field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL);
compare_float(data.float_value, 1.1F);
}
{
char description[500];
snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL);
uint8_t expect[] = {0x00, 0x00, 0x00, 0x2a};
ok(memcmp(data.bytes, expect, 4) == 0,
"bytes field has expected value");
}
{
char description[500];
snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL);
uint16_t expect = 100;
ok(data.uint16 == expect, "uint16 field is 100");
}
{
char description[500];
snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL);
uint32_t expect = 1 << 28;
cmp_ok(data.uint32, "==", expect, "uint32 field is 2**28");
}
{
char description[500];
snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL);
int32_t expect = 1 << 28;
expect *= -1;
cmp_ok(data.int32, "==", expect, "int32 field is -(2**28)");
}
{
char description[500];
snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL);
uint64_t expect = 1;
expect <<= 60;
cmp_ok(data.uint64, "==", expect, "uint64 field is 2**60");
}
{
char description[500];
snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(
result, MMDB_DATA_TYPE_UINT128, description, "uint128", NULL);
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t expect[16] = {0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 2**120");
#else
mmdb_uint128_t expect = 1;
expect <<= 120;
cmp_ok(data.uint128, "==", expect, "uint128 field is 2**120");
#endif
}
{
char description[500];
snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(
result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean", NULL);
cmp_ok(data.boolean, "==", true, "boolean field is true");
}
{
char description[500];
snprintf(description, 500, "array field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL);
ok(data.data_size == 3, "array field has 3 elements");
snprintf(description, 500, "array[0] for %s - %s", ip, mode_desc);
data = data_ok(
result, MMDB_DATA_TYPE_UINT32, description, "array", "0", NULL);
ok(data.uint32 == 1, "array[0] is 1");
snprintf(description, 500, "array[1] for %s - %s", ip, mode_desc);
data = data_ok(
result, MMDB_DATA_TYPE_UINT32, description, "array", "1", NULL);
ok(data.uint32 == 2, "array[1] is 1");
snprintf(description, 500, "array[2] for %s - %s", ip, mode_desc);
data = data_ok(
result, MMDB_DATA_TYPE_UINT32, description, "array", "2", NULL);
ok(data.uint32 == 3, "array[2] is 1");
}
{
char description[500];
snprintf(description, 500, "map field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL);
ok(data.data_size == 1, "map field has 1 element");
snprintf(description, 500, "map{mapX} for %s - %s", ip, mode_desc);
data = data_ok(
result, MMDB_DATA_TYPE_MAP, description, "map", "mapX", NULL);
ok(data.data_size == 2, "map{mapX} field has 2 elements");
snprintf(description,
500,
"map{mapX}{utf8_stringX} for %s - %s",
ip,
mode_desc);
data = data_ok(result,
MMDB_DATA_TYPE_UTF8_STRING,
description,
"map",
"mapX",
"utf8_stringX",
NULL);
char *string = mmdb_strndup(data.utf8_string, data.data_size);
is(string, "hello", "map{mapX}{utf8_stringX} is 'hello'");
free(string);
snprintf(
description, 500, "map{mapX}{arrayX} for %s - %s", ip, mode_desc);
data = data_ok(result,
MMDB_DATA_TYPE_ARRAY,
description,
"map",
"mapX",
"arrayX",
NULL);
ok(data.data_size == 3, "map{mapX}{arrayX} field has 3 elements");
snprintf(description,
500,
"map{mapX}{arrayX}[0] for %s - %s",
ip,
mode_desc);
data = data_ok(result,
MMDB_DATA_TYPE_UINT32,
description,
"map",
"mapX",
"arrayX",
"0",
NULL);
ok(data.uint32 == 7, "map{mapX}{arrayX}[0] is 7");
snprintf(description,
500,
"map{mapX}{arrayX}[1] for %s - %s",
ip,
mode_desc);
data = data_ok(result,
MMDB_DATA_TYPE_UINT32,
description,
"map",
"mapX",
"arrayX",
"1",
NULL);
ok(data.uint32 == 8, "map{mapX}{arrayX}[1] is 8");
snprintf(description,
500,
"map{mapX}{arrayX}[2] for %s - %s",
ip,
mode_desc);
data = data_ok(result,
MMDB_DATA_TYPE_UINT32,
description,
"map",
"mapX",
"arrayX",
"2",
NULL);
ok(data.uint32 == 9, "map{mapX}{arrayX}[2] is 9");
}
}
void test_all_data_types_as_zero(MMDB_lookup_result_s *result,
const char *ip,
const char *UNUSED(filename),
const char *mode_desc) {
{
char description[500];
snprintf(
description, 500, "utf8_string field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(result,
MMDB_DATA_TYPE_UTF8_STRING,
description,
"utf8_string",
NULL);
is(data.utf8_string, "", "got expected utf8_string value (NULL)");
}
{
char description[500];
snprintf(description, 500, "double field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL);
compare_double(data.double_value, 0.0);
}
{
char description[500];
snprintf(description, 500, "float field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL);
compare_float(data.float_value, 0.0F);
}
{
char description[500];
snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL);
ok(data.data_size == 0, "bytes field data_size is 0");
/* In C does it makes sense to write something like this?
uint8_t expect[0] = {};
ok(memcmp(data.bytes, expect, 0) == 0, "got expected bytes value
(NULL)"); */
}
{
char description[500];
snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL);
uint16_t expect = 0;
ok(data.uint16 == expect, "uint16 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL);
uint32_t expect = 0;
cmp_ok(data.uint32, "==", expect, "uint32 field is 0");
}
{
char description[500];
snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL);
int32_t expect = 0;
expect *= -1;
cmp_ok(data.int32, "==", expect, "int32 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL);
uint64_t expect = 0;
cmp_ok(data.uint64, "==", expect, "uint64 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(
result, MMDB_DATA_TYPE_UINT128, description, "uint128", NULL);
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t expect[16] = {0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 0");
#else
mmdb_uint128_t expect = 0;
cmp_ok(data.uint128, "==", expect, "uint128 field is 0");
#endif
}
{
char description[500];
snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data = data_ok(
result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean", NULL);
cmp_ok(data.boolean, "==", false, "boolean field is false");
}
{
char description[500];
snprintf(description, 500, "array field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL);
ok(data.data_size == 0, "array field has 0 elements");
}
{
char description[500];
snprintf(description, 500, "map field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL);
ok(data.data_size == 0, "map field has 0 elements");
}
}
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-decoder.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
// All of the remaining tests require an open mmdb
if (NULL == mmdb) {
diag("could not open %s - skipping remaining tests", path);
return;
}
free(path);
{
const char *ip = "not an ip";
int gai_error, mmdb_error;
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
cmp_ok(gai_error,
"==",
EAI_NONAME,
"MMDB_lookup populates getaddrinfo error properly - %s",
ip);
ok(!result.found_entry,
"no result entry struct returned for invalid IP address '%s'",
ip);
}
{
const char *ip = "e900::";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(!result.found_entry,
"no result entry struct returned for IP address not in the database "
"- %s - %s - %s",
ip,
filename,
mode_desc);
}
{
const char *ip = "::1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(result.found_entry,
"got a result entry struct for IP address in the database - %s - %s "
"- %s",
ip,
filename,
mode_desc);
cmp_ok(result.entry.offset,
">",
0,
"result.entry.offset > 0 for address in the database - %s - %s "
"- %s",
ip,
filename,
mode_desc);
test_all_data_types(&result, ip, filename, mode_desc);
}
{
const char *ip = "::4.5.6.7";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(result.found_entry,
"got a result entry struct for IP address in the database - %s - %s "
"- %s",
ip,
filename,
mode_desc);
cmp_ok(result.entry.offset,
">",
0,
"result.entry.offset > 0 for address in the database - %s - %s "
"- %s",
ip,
filename,
mode_desc);
test_all_data_types(&result, ip, filename, mode_desc);
}
{
const char *ip = "::0.0.0.0";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(result.found_entry,
"got a result entry struct for IP address in the database - %s - %s "
"- %s",
ip,
filename,
mode_desc);
test_all_data_types_as_zero(&result, ip, filename, mode_desc);
}
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

98
t/dump_t.c Normal file
View File

@ -0,0 +1,98 @@
#define _XOPEN_SOURCE 700
#include "maxminddb_test_helper.h"
#ifdef HAVE_OPEN_MEMSTREAM
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-decoder.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *ip = "1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
MMDB_entry_data_list_s *entry_data_list;
int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
ok(MMDB_SUCCESS == status, "MMDB_get_entry_data_list is successful");
char *dump_output;
size_t dump_size;
FILE *stream = open_memstream(&dump_output, &dump_size);
status = MMDB_dump_entry_data_list(stream, entry_data_list, 0);
fclose(stream);
MMDB_free_entry_data_list(entry_data_list);
ok(MMDB_SUCCESS == status,
"MMDB_dump_entry_data_list is successful - %s",
mode_desc);
cmp_ok(dump_size, ">", 0, "MMDB_dump produced output - %s", mode_desc);
char *expect[] = {"{",
" \"array\": ",
" [",
" 1 <uint32>",
" 2 <uint32>",
" 3 <uint32>",
" ]",
" \"boolean\": ",
" true <boolean>",
" \"bytes\": ",
" 0000002A <bytes>",
" \"double\": ",
" 42.123456 <double>",
" \"float\": ",
" 1.100000 <float>",
" \"int32\": ",
" -268435456 <int32>",
" \"map\": ",
" {",
" \"mapX\": ",
" {",
" \"arrayX\": ",
" [",
" 7 <uint32>",
" 8 <uint32>",
" 9 <uint32>",
" ]",
" \"utf8_stringX\": ",
" \"hello\" <utf8_string>",
" }",
" }",
" \"uint128\": ",
" 0x01000000000000000000000000000000 <uint128>",
" \"uint16\": ",
" 100 <uint16>",
" \"uint32\": ",
" 268435456 <uint32>",
" \"uint64\": ",
" 1152921504606846976 <uint64>",
" \"utf8_string\": ",
" \"unicode! ☯ - ♫\" <utf8_string>",
"}"};
for (int i = 0; i < 42; i++) {
ok((strstr(dump_output, expect[i]) != NULL),
"dump output contains expected line (%s) - %s",
expect[i],
mode_desc);
}
free(dump_output);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}
#else
int main(void) {
plan(SKIP_ALL, "This test requires the open_memstream() function");
}
#endif

114
t/external_symbols_t.pl Executable file
View File

@ -0,0 +1,114 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw( $Bin );
_skip_tests_if_not_linux();
_skip_tests_if_required_modules_are_not_present();
_skip_tests_if_nm_is_not_present();
_test_libs_external_symbols();
done_testing();
sub _skip_tests_if_not_linux {
return if $^O eq 'linux';
print "1..0 # skip all tests skipped - this test requires Linux.\n";
exit 0;
}
sub _skip_tests_if_required_modules_are_not_present {
eval <<'EOF';
use Test::More 0.88;
use IPC::Run3 qw( run3 );
EOF
if ($@) {
print
"1..0 # skip all tests skipped - these tests need the Test::More 0.88, IPC::Run3 modules:\n";
print "$@";
exit 0;
}
}
sub _skip_tests_if_nm_is_not_present {
run3(
[ 'nm', '-V' ],
\undef,
\undef,
\undef,
);
my $exit_status = $? >> 8;
if ($exit_status) {
print
"1..0 # skipp all tests skipped - this test requires the command line utility `nm`.\n";
exit 0;
}
}
sub _test_libs_external_symbols {
my @libs = _libs_to_test();
if (@libs) {
for my $lib (@libs) {
_test_lib_external_symbols($lib);
}
}
else {
fail('No libs were found to test');
}
}
sub _libs_to_test {
my $lib_dir = "$Bin/../src/.libs";
opendir my $dh, $lib_dir
or die "Failed to open the lib dir at $lib_dir for reading: $!\n";
my @libs = map { $lib_dir . q{/} . $_ }
grep { $_ =~ m/\.so$/ } readdir $dh;
closedir $dh;
return @libs;
}
sub _test_lib_external_symbols {
my $lib = shift;
my $stdout;
my $stderr;
run3(
[ 'nm', '-g', '--defined-only', $lib ],
\undef,
\$stdout,
\$stderr,
);
my $exit_status = $? >> 8;
ok( !$exit_status, 'nm returned a non-error status' )
or diag($stderr);
my @external_symbols = _extract_external_symbols($stdout);
is_deeply(
[ grep { $_ !~ m/^MMDB_/ } @external_symbols ],
[],
"$lib exports only MMDB_ symbols"
);
}
sub _extract_external_symbols {
my $nm_output = shift;
my @lines = split /\r\n|\r|\n/, $nm_output;
my @external_symbols;
for my $line (@lines) {
my @fields = split /\s+/, $line;
die "Unexpected nm output for line $line\n"
if @fields != 3;
push @external_symbols, $fields[2];
}
return @external_symbols;
}

View File

@ -0,0 +1,71 @@
#include "maxminddb_test_helper.h"
/* This test exercises a bug found in MMDB_get_value for certain types of
* nested data structures which contain pointers. See
* https://github.com/maxmind/libmaxminddb/issues/2 and
* https://github.com/maxmind/libmaxminddb/issues/3.
*
* There is also the potential for a similar bug when looking up a value by
* path in an array. This is not tested (yet) as we don't have the right test
* data for it.
*
* These tests are somewhat fragile since they depend on a specific data
* layout in the database. Ideally the test would check that this layout
* exists before checking to see if the lookups are correct.
*/
void test_one_ip(MMDB_s *mmdb,
const char *filename,
const char *mode_desc,
char *ip,
char *country_code) {
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
MMDB_entry_data_s entry_data = data_ok(&result,
MMDB_DATA_TYPE_UTF8_STRING,
"country{iso_code}",
"country",
"iso_code",
NULL);
if (ok(entry_data.has_data, "found data for country{iso_code}")) {
char *string =
mmdb_strndup(entry_data.utf8_string, entry_data.data_size);
if (!string) {
ok(0, "mmdb_strndup() call failed");
exit(1);
}
if (!ok(strcmp(string, country_code) == 0,
"iso_code is %s",
country_code)) {
diag(" value is %s", string);
}
free(string);
}
}
void run_tests(int mode, const char *mode_desc) {
const char *filename = "GeoIP2-City-Test.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
/* This exercises a bug where the entire top-level value is a pointer to
* another part of the data section. */
test_one_ip(mmdb, filename, mode_desc, "2001:218::", "JP");
/* This exercises a bug where one subnet's data shares part of the data
* with another subnet - in this case it is the "country" key (and others)
* in the top level map. We are testing that the "country" key's value is
* handled correctly. The value _should_ be a pointer to another map. */
test_one_ip(mmdb, filename, mode_desc, "81.2.69.160", "GB");
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

404
t/get_value_t.c Normal file
View File

@ -0,0 +1,404 @@
#include "maxminddb_test_helper.h"
void test_array_0_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - array[0]",
function);
ok(entry_data.has_data, "found a value for array[0]");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - array[0]");
cmp_ok(entry_data.uint32, "==", 1, "entry value is 1 - array[0]");
}
void test_array_2_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - array[2]",
function);
ok(entry_data.has_data, "found a value for array[2]");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - array[2]");
cmp_ok(entry_data.uint32, "==", 3, "entry value is 3 - array[2]");
}
void test_array_minus_3_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - array[-3]",
function);
ok(entry_data.has_data, "found a value for array[-3]");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - array[-3]");
cmp_ok(entry_data.uint32, "==", 1, "entry value is 1 - array[-3]");
}
void test_array_minus_1_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - array[-1]",
function);
ok(entry_data.has_data, "found a value for array[-1]");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - array[-1]");
cmp_ok(entry_data.uint32, "==", 3, "entry value is 3 - array[-1]");
}
int call_vget_value(MMDB_entry_s *entry, MMDB_entry_data_s *entry_data, ...) {
va_list keys;
va_start(keys, entry_data);
int status = MMDB_vget_value(entry, entry_data, keys);
va_end(keys);
return status;
}
void test_simple_structure(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-decoder.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *ip = "1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {"array", "0", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_array_0_result(status, entry_data, "MMDB_aget_value");
status = MMDB_get_value(&result.entry, &entry_data, "array", "0", NULL);
test_array_0_result(status, entry_data, "MMDB_get_value");
status =
call_vget_value(&result.entry, &entry_data, "array", "0", NULL);
test_array_0_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {"array", "2", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_array_2_result(status, entry_data, "MMDB_aget_value");
status = MMDB_get_value(&result.entry, &entry_data, "array", "2", NULL);
test_array_2_result(status, entry_data, "MMDB_get_value");
status =
call_vget_value(&result.entry, &entry_data, "array", "2", NULL);
test_array_2_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
int status =
MMDB_get_value(&result.entry, &entry_data, "array", "zero", NULL);
cmp_ok(status,
"==",
MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR,
"MMDB_get_value() returns error on non-integer array index");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {"array", "-1", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_array_minus_1_result(status, entry_data, "MMDB_aget_value");
status =
MMDB_get_value(&result.entry, &entry_data, "array", "-1", NULL);
test_array_minus_1_result(status, entry_data, "MMDB_get_value");
status =
call_vget_value(&result.entry, &entry_data, "array", "-1", NULL);
test_array_minus_1_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {"array", "-3", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_array_minus_3_result(status, entry_data, "MMDB_aget_value");
status =
MMDB_get_value(&result.entry, &entry_data, "array", "-3", NULL);
test_array_minus_3_result(status, entry_data, "MMDB_get_value");
status =
call_vget_value(&result.entry, &entry_data, "array", "-3", NULL);
test_array_minus_3_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
int status =
MMDB_get_value(&result.entry, &entry_data, "array", "-4", NULL);
cmp_ok(status,
"==",
MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR,
"MMDB_get_value() returns error on too large negative integer");
}
{
MMDB_entry_data_s entry_data;
int status = MMDB_get_value(
&result.entry, &entry_data, "array", "-18446744073709551616", NULL);
cmp_ok(
status,
"==",
MMDB_INVALID_LOOKUP_PATH_ERROR,
"MMDB_get_value() returns error on integer smaller than LONG_MIN");
}
{
MMDB_entry_data_s entry_data;
int status = MMDB_get_value(
&result.entry, &entry_data, "array", "18446744073709551616", NULL);
cmp_ok(
status,
"==",
MMDB_INVALID_LOOKUP_PATH_ERROR,
"MMDB_get_value() returns error on integer larger than LONG_MAX");
}
MMDB_close(mmdb);
free(mmdb);
}
void test_complex_map_a_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - map1{map2}{array}[0]{map3}{a}",
function);
ok(entry_data.has_data, "found a value for map1{map2}{array}[0]{map3}{a}");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - map1{map2}{array}[0]{map3}{a}");
cmp_ok(entry_data.uint32,
"==",
1,
"entry value is 1 - map1{map2}{array}[0]{map3}{a}");
}
void test_complex_map_c_result(int status,
MMDB_entry_data_s entry_data,
char *function) {
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for %s() is MMDB_SUCCESS - map1{map2}{array}[0]{map3}{c}",
function);
ok(entry_data.has_data, "found a value for map1{map2}{array}[0]{map3}{c}");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UINT32,
"returned entry type is uint32 - map1{map2}{array}[0]{map3}{c}");
cmp_ok(entry_data.uint32,
"==",
3,
"entry value is 3 - map1{map2}{array}[0]{map3}{c}");
}
void test_no_result(int status,
MMDB_entry_data_s entry_data,
char *function,
char *path_description) {
cmp_ok(status,
"==",
MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR,
"status for %s() is MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR - %s",
function,
path_description);
ok(!entry_data.has_data, "did not find a value for %s", path_description);
}
void test_nested_structure(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-nested.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *ip = "1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {
"map1", "map2", "array", "0", "map3", "a", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_complex_map_a_result(status, entry_data, "MMDB_aget_value");
status = MMDB_get_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"0",
"map3",
"a",
NULL);
test_complex_map_a_result(status, entry_data, "MMDB_get_value");
status = call_vget_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"0",
"map3",
"a",
NULL);
test_complex_map_a_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {
"map1", "map2", "array", "0", "map3", "c", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_complex_map_c_result(status, entry_data, "MMDB_aget_value");
status = MMDB_get_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"0",
"map3",
"c",
NULL);
test_complex_map_c_result(status, entry_data, "MMDB_get_value");
status = call_vget_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"0",
"map3",
"c",
NULL);
test_complex_map_c_result(status, entry_data, "MMDB_vget_value");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {
"map1", "map42", "array", "0", "map3", "c", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_no_result(status,
entry_data,
"MMDB_aget_value",
"map1{map42}{array}[0]{map3}{c}");
status = MMDB_get_value(&result.entry,
&entry_data,
"map1",
"map42",
"array",
"0",
"map3",
"c",
NULL);
test_no_result(status,
entry_data,
"MMDB_get_value",
"map1{map42}{array}[0]{map3}{c}");
status = call_vget_value(&result.entry,
&entry_data,
"map1",
"map42",
"array",
"0",
"map3",
"c",
NULL);
test_no_result(status,
entry_data,
"MMDB_vget_value",
"map1{map42}{array}[0]{map3}{c}");
}
{
MMDB_entry_data_s entry_data;
const char *lookup_path[] = {
"map1", "map2", "array", "9", "map3", "c", NULL};
int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path);
test_no_result(status,
entry_data,
"MMDB_aget_value",
"map1{map42}{array}[9]{map3}{c}");
status = MMDB_get_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"9",
"map3",
"c",
NULL);
test_no_result(status,
entry_data,
"MMDB_get_value",
"map1{map42}{array}[9]{map3}{c}");
status = call_vget_value(&result.entry,
&entry_data,
"map1",
"map2",
"array",
"9",
"map3",
"c",
NULL);
test_no_result(status,
entry_data,
"MMDB_vget_value",
"map1{map42}{array}[9]{map3}{c}");
}
MMDB_close(mmdb);
free(mmdb);
}
void run_tests(int mode, const char *mode_desc) {
test_simple_structure(mode, mode_desc);
test_nested_structure(mode, mode_desc);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

36
t/ipv4_start_cache_t.c Normal file
View File

@ -0,0 +1,36 @@
#include "maxminddb_test_helper.h"
void test_one_ip(MMDB_s *mmdb,
const char *ip,
const char *filename,
const char *mode_desc) {
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(result.found_entry,
"got a result for an IPv4 address included in a larger-than-IPv4 subnet "
"- %s - %s",
ip,
mode_desc);
data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "string value for IP", NULL);
}
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-no-ipv4-search-tree.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
test_one_ip(mmdb, "1.1.1.1", filename, mode_desc);
test_one_ip(mmdb, "255.255.255.255", filename, mode_desc);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

49
t/ipv6_lookup_in_ipv4_t.c Normal file
View File

@ -0,0 +1,49 @@
#include "maxminddb_test_helper.h"
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-ipv4-28.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *ip = "::abcd";
int gai_error, mmdb_error;
MMDB_lookup_result_s UNUSED(result) =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
cmp_ok(mmdb_error,
"==",
MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR,
"MMDB_lookup_string sets mmdb_error to "
"MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR when we try to look up an "
"IPv6 address in an IPv4-only database");
struct addrinfo hints = {.ai_family = AF_INET6, .ai_flags = AI_NUMERICHOST};
struct addrinfo *addresses;
gai_error = getaddrinfo(
"2001:db8:85a3:0:0:8a2e:370:7334", NULL, &hints, &addresses);
if (gai_error) {
BAIL_OUT("getaddrinfo failed: %s", gai_strerror(gai_error));
}
mmdb_error = 0;
MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
cmp_ok(mmdb_error,
"==",
MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR,
"MMDB_lookup_sockaddr sets mmdb_error to "
"MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR when we try to look up an "
"IPv6 address in an IPv4-only database");
freeaddrinfo(addresses);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

1
t/libtap Submodule

@ -0,0 +1 @@
Subproject commit 56e31231e0329b202c978c676e4a897c857c7a1f

1
t/maxmind-db Submodule

@ -0,0 +1 @@
Subproject commit 31a33b3c09ac53028216e82f3d8a6d33749a8df5

250
t/maxminddb_test_helper.c Normal file
View File

@ -0,0 +1,250 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#define _POSIX_C_SOURCE 200112L
#include <assert.h>
#include <stdarg.h>
#include <sys/types.h>
#include "maxminddb.h"
#include "maxminddb_test_helper.h"
#ifdef _WIN32
#include <io.h>
#else
#include <libgen.h>
#include <unistd.h>
#endif
void for_all_record_sizes(const char *filename_fmt,
void (*tests)(int record_size,
const char *filename,
const char *description)) {
int sizes[] = {24, 28, 32};
for (int i = 0; i < 3; i++) {
int size = sizes[i];
char filename[500];
// This warning seems ok to ignore here in the tests.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
snprintf(filename, 500, filename_fmt, size);
#pragma clang diagnostic pop
char description[14];
snprintf(description, 14, "%i bit record", size);
tests(size, filename, description);
}
}
void for_all_modes(void (*tests)(int mode, const char *description)) {
tests(MMDB_MODE_MMAP, "mmap mode");
}
char *test_database_path(const char *filename) {
char *test_db_dir;
#ifdef _WIN32
test_db_dir = "../t/maxmind-db/test-data";
#else
char cwd[500];
char *UNUSED(tmp) = getcwd(cwd, 500);
if (strcmp(basename(cwd), "t") == 0) {
test_db_dir = "./maxmind-db/test-data";
} else {
test_db_dir = "./t/maxmind-db/test-data";
}
#endif
char *path = malloc(500);
assert(NULL != path);
snprintf(path, 500, "%s/%s", test_db_dir, filename);
return path;
}
char *dup_entry_string_or_bail(MMDB_entry_data_s entry_data) {
char *string = mmdb_strndup(entry_data.utf8_string, entry_data.data_size);
if (NULL == string) {
BAIL_OUT("mmdb_strndup failed");
}
return string;
}
MMDB_s *open_ok(const char *db_file, int mode, const char *mode_desc) {
if (0 != access(db_file, R_OK)) {
BAIL_OUT("could not read the specified file - %s\nIf you are in a git "
"checkout try running 'git submodule update --init'",
db_file);
}
MMDB_s *mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s));
if (NULL == mmdb) {
BAIL_OUT("could not allocate memory for our MMDB_s struct");
}
int status = MMDB_open(db_file, (uint32_t)mode, mmdb);
int is_ok = ok(MMDB_SUCCESS == status,
"open %s status is success - %s",
db_file,
mode_desc);
if (!is_ok) {
diag("open status code = %d (%s)", status, MMDB_strerror(status));
free(mmdb);
return NULL;
}
is_ok = ok(mmdb->file_size > 0,
"mmdb struct has been set for %s - %s",
db_file,
mode_desc);
if (!is_ok) {
free(mmdb);
return NULL;
}
return mmdb;
}
MMDB_lookup_result_s lookup_string_ok(MMDB_s *mmdb,
const char *ip,
const char *file,
const char *mode_desc) {
int gai_error, mmdb_error;
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
test_lookup_errors(
gai_error, mmdb_error, "MMDB_lookup_string", ip, file, mode_desc);
return result;
}
MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb,
const char *ip,
const char *file,
const char *mode_desc) {
int ai_flags = AI_NUMERICHOST;
struct addrinfo hints = {.ai_socktype = SOCK_STREAM};
struct addrinfo *addresses = NULL;
if (ip[0] == ':') {
hints.ai_flags = ai_flags;
#if defined AI_V4MAPPED && !defined __FreeBSD__
hints.ai_flags |= AI_V4MAPPED;
#endif
hints.ai_family = AF_INET6;
} else {
hints.ai_flags = ai_flags;
hints.ai_family = AF_INET;
}
int gai_error = getaddrinfo(ip, NULL, &hints, &addresses);
int mmdb_error = 0;
MMDB_lookup_result_s result = {.found_entry = false};
if (gai_error == 0) {
result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
}
if (NULL != addresses) {
freeaddrinfo(addresses);
}
test_lookup_errors(
gai_error, mmdb_error, "MMDB_lookup_sockaddr", ip, file, mode_desc);
return result;
}
void test_lookup_errors(int gai_error,
int mmdb_error,
const char *function,
const char *ip,
const char *file,
const char *mode_desc) {
int is_ok = ok(0 == gai_error,
"no getaddrinfo error in call to %s for %s - %s - %s",
function,
ip,
file,
mode_desc);
if (!is_ok) {
diag("error from call to getaddrinfo for %s - %s",
ip,
gai_strerror(gai_error));
}
is_ok = ok(0 == mmdb_error,
"no MMDB error in call to %s for %s - %s - %s",
function,
ip,
file,
mode_desc);
if (!is_ok) {
diag("MMDB error - %s", MMDB_strerror(mmdb_error));
}
}
MMDB_entry_data_s data_ok(MMDB_lookup_result_s *result,
uint32_t expect_type,
const char *description,
...) {
va_list keys;
va_start(keys, description);
MMDB_entry_data_s data;
int status = MMDB_vget_value(&result->entry, &data, keys);
va_end(keys);
if (cmp_ok(status,
"==",
MMDB_SUCCESS,
"no error from call to MMDB_vget_value - %s",
description)) {
if (!cmp_ok((int)data.type,
"==",
(int)expect_type,
"got the expected data type - %s",
description)) {
diag(" data type value is %i but expected %i",
data.type,
expect_type);
}
} else {
diag(" error from MMDB_vget_value - %s", MMDB_strerror(status));
}
return data;
}
void compare_double(double got, double expect) {
double diff = fabs(got - expect);
int is_ok = ok(diff < 0.01, "double value was approximately %2.6f", expect);
if (!is_ok) {
diag(
" got %2.6f but expected %2.6f (diff = %2.6f)", got, expect, diff);
}
}
void compare_float(float got, float expect) {
float diff = fabsf(got - expect);
int is_ok = ok(diff < 0.01, "float value was approximately %2.1f", expect);
if (!is_ok) {
diag(
" got %2.4f but expected %2.1f (diff = %2.1f)", got, expect, diff);
}
}

72
t/maxminddb_test_helper.h Normal file
View File

@ -0,0 +1,72 @@
/* Some test files may require something newer */
#if !defined(_GNU_SOURCE) && !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "libtap/tap.h"
#include "maxminddb-compat-util.h"
#include "maxminddb.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define R_OK 4
#else
#include <netdb.h>
#endif
#if defined _MSC_VER && _MSC_VER < 1900
/* _snprintf has security issues, but I don't think it is worth
worrying about for the unit tests. */
#define snprintf _snprintf
#endif
#ifndef MMDB_TEST_HELPER_C
#define MMDB_TEST_HELPER_C (1)
#ifdef __GNUC__
#define UNUSED(x) UNUSED_##x __attribute__((__unused__))
#else
#define UNUSED
#endif
#define MAX_DESCRIPTION_LENGTH 500
extern void for_all_record_sizes(const char *filename_fmt,
void (*tests)(int record_size,
const char *filename,
const char *description));
extern void for_all_modes(void (*tests)(int mode, const char *description));
extern char *test_database_path(const char *filename);
extern char *dup_entry_string_or_bail(MMDB_entry_data_s entry_data);
extern MMDB_s *open_ok(const char *db_file, int mode, const char *mode_desc);
extern MMDB_lookup_result_s lookup_string_ok(MMDB_s *mmdb,
const char *ip,
const char *file,
const char *mode_desc);
extern MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb,
const char *ip,
const char *file,
const char *mode_desc);
extern void test_lookup_errors(int gai_error,
int mmdb_error,
const char *function,
const char *ip,
const char *file,
const char *mode_desc);
extern MMDB_entry_data_s data_ok(MMDB_lookup_result_s *result,
uint32_t expect_type,
const char *description,
...);
extern void compare_double(double got, double expect);
extern void compare_float(float got, float expect);
#endif

31
t/metadata_pointers_t.c Normal file
View File

@ -0,0 +1,31 @@
#include "maxminddb_test_helper.h"
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-metadata-pointers.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
char *repeated_string = "Lots of pointers in metadata";
is(mmdb->metadata.database_type,
repeated_string,
"decoded pointer database_type");
for (uint16_t i = 0; i < mmdb->metadata.description.count; i++) {
const char *language =
mmdb->metadata.description.descriptions[i]->language;
const char *description =
mmdb->metadata.description.descriptions[i]->description;
is(description, repeated_string, "%s description", language);
}
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

271
t/metadata_t.c Normal file
View File

@ -0,0 +1,271 @@
#include "maxminddb_test_helper.h"
void test_metadata(MMDB_s *mmdb, const char *mode_desc) {
cmp_ok(mmdb->metadata.node_count,
"==",
37,
"node_count is 37 - %s",
mode_desc);
cmp_ok(mmdb->metadata.record_size,
"==",
24,
"record_size is 24 - %s",
mode_desc);
cmp_ok(
mmdb->metadata.ip_version, "==", 4, "ip_version is 4 - %s", mode_desc);
is(mmdb->metadata.database_type,
"Test",
"database_type is Test - %s",
mode_desc);
// 2013-07-01T00:00:00Z
uint64_t expect_epoch = 1372636800;
int is_ok = cmp_ok(mmdb->metadata.build_epoch,
">=",
expect_epoch,
"build_epoch > %lli",
expect_epoch);
if (!is_ok) {
diag(" epoch is %lli", mmdb->metadata.build_epoch);
}
cmp_ok(mmdb->metadata.binary_format_major_version,
"==",
2,
"binary_format_major_version is 2 - %s",
mode_desc);
cmp_ok(mmdb->metadata.binary_format_minor_version,
"==",
0,
"binary_format_minor_version is 0 - %s",
mode_desc);
cmp_ok(mmdb->metadata.languages.count,
"==",
2,
"found 2 languages - %s",
mode_desc);
is(mmdb->metadata.languages.names[0],
"en",
"first language is en - %s",
mode_desc);
is(mmdb->metadata.languages.names[1],
"zh",
"second language is zh - %s",
mode_desc);
cmp_ok(mmdb->metadata.description.count,
"==",
2,
"found 2 descriptions - %s",
mode_desc);
for (uint16_t i = 0; i < mmdb->metadata.description.count; i++) {
const char *language =
mmdb->metadata.description.descriptions[i]->language;
const char *description =
mmdb->metadata.description.descriptions[i]->description;
if (strncmp(language, "en", 2) == 0) {
ok(1, "found en description");
is(description, "Test Database", "en description");
} else if (strncmp(language, "zh", 2) == 0) {
ok(1, "found zh description");
is(description, "Test Database Chinese", "zh description");
} else {
ok(0,
"found unknown description in unexpected language - %s",
language);
}
}
cmp_ok(mmdb->full_record_byte_size,
"==",
6,
"full_record_byte_size is 6 - %s",
mode_desc);
}
MMDB_entry_data_list_s *
test_languages_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *languages = entry_data_list = entry_data_list->next;
cmp_ok(languages->entry_data.type,
"==",
MMDB_DATA_TYPE_ARRAY,
"'languages' key's value is an array");
cmp_ok(languages->entry_data.data_size,
"==",
2,
"'languages' key's value has 2 elements");
MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next;
cmp_ok(idx0->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"first array entry is a UTF8_STRING");
char *lang0 = dup_entry_string_or_bail(idx0->entry_data);
is(lang0, "en", "first language is en");
free(lang0);
MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next;
cmp_ok(idx1->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"second array entry is a UTF8_STRING");
char *lang1 = dup_entry_string_or_bail(idx1->entry_data);
is(lang1, "zh", "second language is zh");
free(lang1);
return entry_data_list;
}
MMDB_entry_data_list_s *
test_description_value(MMDB_entry_data_list_s *entry_data_list) {
MMDB_entry_data_list_s *description = entry_data_list =
entry_data_list->next;
cmp_ok(description->entry_data.type,
"==",
MMDB_DATA_TYPE_MAP,
"'description' key's value is a map");
cmp_ok(description->entry_data.data_size,
"==",
2,
"'description' key's value has 2 key/value pairs");
for (int i = 0; i < 2; i++) {
MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next;
cmp_ok(key->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"found a map key in 'map'");
char *key_name = dup_entry_string_or_bail(key->entry_data);
MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
cmp_ok(value->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"map value is a UTF8_STRING");
char *description = dup_entry_string_or_bail(value->entry_data);
if (strcmp(key_name, "en") == 0) {
is(description,
"Test Database",
"en description == 'Test Database'");
} else if (strcmp(key_name, "zh") == 0) {
is(description,
"Test Database Chinese",
"zh description == 'Test Database Chinese'");
} else {
ok(0, "unknown key found in description map - %s", key_name);
}
free(key_name);
free(description);
}
return entry_data_list;
}
void test_metadata_as_data_entry_list(MMDB_s *mmdb, const char *mode_desc) {
MMDB_entry_data_list_s *entry_data_list, *first;
int status = MMDB_get_metadata_as_entry_data_list(mmdb, &entry_data_list);
first = entry_data_list;
cmp_ok(status,
"==",
MMDB_SUCCESS,
"get metadata as data_entry_list - %s",
mode_desc);
cmp_ok(first->entry_data.data_size,
"==",
9,
"metadata map has 9 key/value pairs");
while (1) {
MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next;
if (!key) {
break;
}
cmp_ok(key->entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"found a map key");
char *key_name = dup_entry_string_or_bail(key->entry_data);
if (strcmp(key_name, "node_count") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
cmp_ok(value->entry_data.uint32, "==", 37, "node_count == 37");
} else if (strcmp(key_name, "record_size") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
cmp_ok(value->entry_data.uint16, "==", 24, "record_size == 24");
} else if (strcmp(key_name, "ip_version") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
cmp_ok(value->entry_data.uint16, "==", 4, "ip_version == 4");
} else if (strcmp(key_name, "binary_format_major_version") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
cmp_ok(value->entry_data.uint16,
"==",
2,
"binary_format_major_version == 2");
} else if (strcmp(key_name, "binary_format_minor_version") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
cmp_ok(value->entry_data.uint16,
"==",
0,
"binary_format_minor_version == 0");
} else if (strcmp(key_name, "build_epoch") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
ok(value->entry_data.uint64 > 1373571901,
"build_epoch > 1373571901");
} else if (strcmp(key_name, "database_type") == 0) {
MMDB_entry_data_list_s *value = entry_data_list =
entry_data_list->next;
char *type = dup_entry_string_or_bail(value->entry_data);
is(type, "Test", "type == Test");
free(type);
} else if (strcmp(key_name, "languages") == 0) {
entry_data_list = test_languages_value(entry_data_list);
} else if (strcmp(key_name, "description") == 0) {
entry_data_list = test_description_value(entry_data_list);
} else {
ok(0, "unknown key found in metadata map - %s", key_name);
}
free(key_name);
}
MMDB_free_entry_data_list(first);
}
void run_tests(int mode, const char *mode_desc) {
const char *file = "MaxMind-DB-test-ipv4-24.mmdb";
char *path = test_database_path(file);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
// All of the remaining tests require an open mmdb
if (NULL == mmdb) {
diag("could not open %s - skipping remaining tests", path);
return;
}
free(path);
test_metadata(mmdb, mode_desc);
test_metadata_as_data_entry_list(mmdb, mode_desc);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

158
t/mmdblookup_t.pl Executable file
View File

@ -0,0 +1,158 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw( $Bin );
eval <<'EOF';
use Test::More 0.88;
use IPC::Run3 qw( run3 );
EOF
if ($@) {
print
"1..0 # skip all tests skipped - these tests need the Test::More 0.88, IPC::Run3 and Test::Output modules:\n";
print "$@";
exit 0;
}
my $mmdblookup = "$Bin/../bin/mmdblookup";
my $test_data_dir = "$Bin/maxmind-db/test-data";
{
ok( -x $mmdblookup, 'mmdblookup script is executable' );
}
for my $arg (qw( -h -? --help )) {
_test_stdout(
[$arg],
qr{mmdblookup --file.+This application accepts the following options:}s,
0,
"help output from $arg"
);
}
_test_both(
[],
qr{mmdblookup --file.+This application accepts the following options:}s,
qr{ERROR: You must provide a filename with --file},
1,
"help output with no CLI options"
);
_test_stderr(
[qw( --file foo )],
qr{ERROR: You must provide an IP address with --ip},
1,
'error when no --ip is given'
);
_test_stdout(
[qw( --version )],
qr/mmdblookup version \d+\.\d+\.\d+/,
0,
'output for --version'
);
_test_stdout(
['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216'],
qr/"en"\s*:\s*"Boxford"/,
0,
'output for 2.125.160.216'
);
_test_stdout(
['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216', '--verbose'],
qr/Database metadata.+"en"\s*:\s*"Boxford"/s,
0,
'verbose output for 2.125.160.216'
);
_test_stdout(
['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216', qw( location latitude )],
qr/^\s*51\.750000 <double>\s*$/s,
0,
'output for 2.125.160.216 with lookup path'
);
_test_stderr(
[ qw( --file this/path/better/not/exist.mmdb --ip 1.2.3.4 ) ],
qr{Can't open this/path/better/not/exist.mmdb}s,
2,
'error for file that does not exist'
);
_test_stderr(
['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', 'not-an-ip-address' ],
qr{Error from call to getaddrinfo for not-an-ip-address}s,
3,
'error for bad IP address'
);
_test_stderr(
['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '10.2.3.4' ],
qr{\QCould not find an entry for this IP address (10.2.3.4)}s,
6,
'error for bad PI address'
);
done_testing();
sub _test_stdout {
my $args = shift;
my $expect_stdout = shift;
my $expect_status = shift;
my $desc = shift;
_test_both( $args, $expect_stdout, q{}, $expect_status, $desc );
}
sub _test_stderr {
my $args = shift;
my $expect_stderr = shift;
my $expect_status = shift;
my $desc = shift;
_test_both( $args, undef, $expect_stderr, $expect_status, $desc );
}
sub _test_both {
my $args = shift;
my $expect_stdout = shift;
my $expect_stderr = shift;
my $expect_status = shift;
my $desc = shift;
my $stdout;
my $stderr;
run3(
[ $mmdblookup, @{$args} ],
\undef,
\$stdout,
\$stderr,
);
my $exit_status = $? >> 8;
# We don't need to retest that the help output shows up for all errors
if ( defined $expect_stdout ) {
like(
$stdout,
$expect_stdout,
"stdout for mmdblookup @{$args}"
);
}
if ( ref $expect_stderr ) {
like( $stderr, $expect_stderr, "stderr for mmdblookup @{$args}" );
}
else {
is( $stderr, $expect_stderr, "stderr for mmdblookup @{$args}" );
}
is(
$exit_status, $expect_status,
"exit status was $expect_status for mmdblookup @{$args}"
);
}

34
t/no_map_get_value_t.c Normal file
View File

@ -0,0 +1,34 @@
#include "maxminddb_test_helper.h"
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-string-value-entries.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *ip = "1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
MMDB_entry_data_s entry_data;
int status = MMDB_get_value(&result.entry, &entry_data, NULL);
cmp_ok(status,
"==",
MMDB_SUCCESS,
"status for MMDB_get_value() is MMDB_SUCCESS");
ok(entry_data.has_data, "found a value when varargs list is just NULL");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"returned entry type is utf8_string");
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

250
t/read_node_t.c Normal file
View File

@ -0,0 +1,250 @@
#include "maxminddb_test_helper.h"
void test_entry_data(MMDB_s *mmdb,
MMDB_entry_s *entry,
uint32_t node_number,
char *node_record) {
MMDB_entry_data_s entry_data;
int status = MMDB_get_value(entry, &entry_data, "ip", NULL);
cmp_ok(status, "==", MMDB_SUCCESS, "successful data lookup for node");
cmp_ok(entry_data.type,
"==",
MMDB_DATA_TYPE_UTF8_STRING,
"returned entry type is UTF8_STRING for %s record of node %i",
node_record,
node_number);
}
void run_read_node_tests(MMDB_s *mmdb,
const uint32_t tests[][5],
int test_count,
uint8_t record_size) {
for (int i = 0; i < test_count; i++) {
uint32_t node_number = tests[i][0];
MMDB_search_node_s node;
int status = MMDB_read_node(mmdb, node_number, &node);
if (MMDB_SUCCESS == status) {
cmp_ok(node.left_record,
"==",
tests[i][1],
"left record for node %i is %i - %i bit DB",
node_number,
tests[i][1],
record_size);
cmp_ok(node.left_record_type,
"==",
tests[i][2],
"left record type for node %i is %i",
node_number,
tests[i][2]);
if (node.left_record_type == MMDB_RECORD_TYPE_DATA) {
test_entry_data(
mmdb, &node.left_record_entry, node_number, "left");
}
cmp_ok(node.right_record,
"==",
tests[i][3],
"right record for node %i is %i - %i bit DB",
node_number,
tests[i][3],
record_size);
cmp_ok(node.right_record_type,
"==",
tests[i][4],
"right record type for node %i is %i",
node_number,
tests[i][4]);
if (node.right_record_type == MMDB_RECORD_TYPE_DATA) {
test_entry_data(
mmdb, &node.right_record_entry, node_number, "right");
}
} else {
diag("call to MMDB_read_node for node %i failed - %i bit DB",
node_number,
record_size);
}
}
}
void run_24_bit_record_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-mixed-24.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const uint32_t tests[7][5] = {
{0, 1, MMDB_RECORD_TYPE_SEARCH_NODE, 242, MMDB_RECORD_TYPE_EMPTY},
{
80,
81,
MMDB_RECORD_TYPE_SEARCH_NODE,
197,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
96,
97,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
103,
242,
MMDB_RECORD_TYPE_EMPTY,
104,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
127,
242,
MMDB_RECORD_TYPE_EMPTY,
315,
MMDB_RECORD_TYPE_DATA,
},
{
132,
329,
MMDB_RECORD_TYPE_DATA,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
241,
96,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
}};
run_read_node_tests(mmdb, tests, 7, 24);
MMDB_close(mmdb);
free(mmdb);
}
void run_28_bit_record_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-mixed-28.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const uint32_t tests[7][5] = {
{0, 1, MMDB_RECORD_TYPE_SEARCH_NODE, 242, MMDB_RECORD_TYPE_EMPTY},
{
80,
81,
MMDB_RECORD_TYPE_SEARCH_NODE,
197,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
96,
97,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
103,
242,
MMDB_RECORD_TYPE_EMPTY,
104,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
127,
242,
MMDB_RECORD_TYPE_EMPTY,
315,
MMDB_RECORD_TYPE_DATA,
},
{
132,
329,
MMDB_RECORD_TYPE_DATA,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
241,
96,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
}};
run_read_node_tests(mmdb, tests, 7, 28);
MMDB_close(mmdb);
free(mmdb);
}
void run_32_bit_record_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-mixed-32.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const uint32_t tests[7][5] = {
{0, 1, MMDB_RECORD_TYPE_SEARCH_NODE, 242, MMDB_RECORD_TYPE_EMPTY},
{
80,
81,
MMDB_RECORD_TYPE_SEARCH_NODE,
197,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
96,
97,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
103,
242,
MMDB_RECORD_TYPE_EMPTY,
104,
MMDB_RECORD_TYPE_SEARCH_NODE,
},
{
127,
242,
MMDB_RECORD_TYPE_EMPTY,
315,
MMDB_RECORD_TYPE_DATA,
},
{
132,
329,
MMDB_RECORD_TYPE_DATA,
242,
MMDB_RECORD_TYPE_EMPTY,
},
{
241,
96,
MMDB_RECORD_TYPE_SEARCH_NODE,
242,
MMDB_RECORD_TYPE_EMPTY,
}};
run_read_node_tests(mmdb, tests, 7, 32);
MMDB_close(mmdb);
free(mmdb);
}
void run_tests(int mode, const char *mode_desc) {
run_24_bit_record_tests(mode, mode_desc);
run_28_bit_record_tests(mode, mode_desc);
run_32_bit_record_tests(mode, mode_desc);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}

207
t/threads_t.c Normal file
View File

@ -0,0 +1,207 @@
#include "maxminddb_test_helper.h"
#include <pthread.h>
typedef struct thread_arg {
int thread_id;
MMDB_s *mmdb;
const char *ip_to_lookup;
} thread_arg_s;
typedef struct test_result {
const char *ip_looked_up;
int lookup_string_gai_error;
int lookup_string_mmdb_error;
int found_entry;
int get_value_status;
int data_type_ok;
char *data_value;
} test_result_s;
void test_one_ip(MMDB_s *mmdb, const char *ip, test_result_s *test_result) {
test_result->ip_looked_up = ip;
int gai_error = 0;
int mmdb_error = 0;
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
test_result->lookup_string_gai_error = gai_error;
if (gai_error) {
return;
}
test_result->lookup_string_mmdb_error = mmdb_error;
if (mmdb_error) {
return;
}
test_result->found_entry = result.found_entry;
if (!result.found_entry) {
return;
}
MMDB_entry_data_s data;
int status = MMDB_get_value(&result.entry, &data, "ip", NULL);
test_result->get_value_status = status;
if (status) {
return;
}
test_result->data_type_ok = data.type == MMDB_DATA_TYPE_UTF8_STRING;
if (!test_result->data_type_ok) {
return;
}
test_result->data_value = mmdb_strndup(data.utf8_string, data.data_size);
return;
}
void *run_one_thread(void *arg) {
thread_arg_s *thread_arg = (thread_arg_s *)arg;
MMDB_s *mmdb = thread_arg->mmdb;
const char *ip = thread_arg->ip_to_lookup;
test_result_s *result = malloc(sizeof(test_result_s));
if (!result) {
BAIL_OUT("could not allocate memory");
}
test_one_ip(mmdb, ip, result);
pthread_exit((void *)result);
}
void process_result(test_result_s *result,
const char *expect,
const char *mode_desc) {
int is_ok;
is_ok = ok(!result->lookup_string_gai_error,
"no getaddrinfo error for %s - %s",
result->ip_looked_up,
mode_desc);
if (!is_ok) {
return;
}
is_ok = ok(!result->lookup_string_mmdb_error,
"no mmdb error for %s - %s",
result->ip_looked_up,
mode_desc);
if (!is_ok) {
return;
}
is_ok = ok(result->found_entry,
"got a result for %s in the database - %s",
result->ip_looked_up,
mode_desc);
if (!is_ok) {
return;
}
is_ok = ok(!result->get_value_status,
"no error from MMDB_get_value for %s - %s",
result->ip_looked_up,
mode_desc);
if (!is_ok) {
return;
}
is_ok = ok(result->data_type_ok,
"MMDB_get_value found a utf8_string at 'ip' key for %s - %s",
result->ip_looked_up,
mode_desc);
if (!is_ok) {
return;
}
is(result->data_value,
expect,
"found expected result for 'ip' key for %s - %s",
result->ip_looked_up,
mode_desc);
}
void run_ipX_tests(MMDB_s *mmdb,
const char *pairs[][2],
int pairs_rows,
const char *mode_desc) {
pthread_t *threads = malloc((unsigned long)pairs_rows * sizeof(pthread_t));
struct thread_arg *thread_args =
malloc((unsigned long)pairs_rows * sizeof(struct thread_arg));
for (int i = 0; i < pairs_rows; i += 1) {
thread_args[i].thread_id = i;
thread_args[i].mmdb = mmdb;
thread_args[i].ip_to_lookup = pairs[i][0];
int error =
pthread_create(&threads[i], NULL, run_one_thread, &thread_args[i]);
if (error) {
BAIL_OUT("pthread_create failed");
}
}
for (int i = 0; i < pairs_rows; i += 1) {
void *thread_return;
int error = pthread_join(threads[i], &thread_return);
if (error) {
BAIL_OUT("pthread_join failed");
}
test_result_s *test_result = (test_result_s *)thread_return;
if (NULL != test_result) {
process_result(test_result, pairs[i][1], mode_desc);
if (test_result->data_type_ok) {
free(test_result->data_value);
}
free(test_result);
}
}
free(threads);
free(thread_args);
}
void run_tests(int mode, const char *mode_desc) {
const char *filename = "MaxMind-DB-test-mixed-32.mmdb";
char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
free(path);
const char *pairs[18][2] = {
{"1.1.1.1", "::1.1.1.1"},
{"1.1.1.2", "::1.1.1.2"},
{"1.1.1.3", "::1.1.1.2"},
{"1.1.1.7", "::1.1.1.4"},
{"1.1.1.9", "::1.1.1.8"},
{"1.1.1.15", "::1.1.1.8"},
{"1.1.1.17", "::1.1.1.16"},
{"1.1.1.31", "::1.1.1.16"},
{"1.1.1.32", "::1.1.1.32"},
{"::1:ffff:ffff", "::1:ffff:ffff"},
{"::2:0:0", "::2:0:0"},
{"::2:0:1a", "::2:0:0"},
{"::2:0:40", "::2:0:40"},
{"::2:0:4f", "::2:0:40"},
{"::2:0:50", "::2:0:50"},
{"::2:0:52", "::2:0:50"},
{"::2:0:58", "::2:0:58"},
{"::2:0:59", "::2:0:58"},
};
run_ipX_tests(mmdb, pairs, 18, mode_desc);
MMDB_close(mmdb);
free(mmdb);
}
int main(void) {
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
pthread_exit(NULL);
}

9
t/version_t.c Normal file
View File

@ -0,0 +1,9 @@
#include "maxminddb_test_helper.h"
int main(void) {
const char *version = MMDB_lib_version();
if (ok((version != NULL), "MMDB_lib_version exists")) {
is(version, PACKAGE_VERSION, "version is " PACKAGE_VERSION);
}
done_testing();
}