From 6a85db4cec6b8bce1041380da13de52d7b5c3a8b Mon Sep 17 00:00:00 2001 From: "Vadim A. Misbakh-Soloviov" Date: Sat, 23 Jul 2016 01:27:40 +0700 Subject: [PATCH] ISP + NetSpeed (Rework of #3 to speedup merging). Fixed #3 --- AUTHORS | 1 + rockspec/lua-geoip-scm-1.rockspec | 20 +++ src/database.h | 2 + src/isp.c | 232 +++++++++++++++++++++++++++++ src/netspeed.c | 234 ++++++++++++++++++++++++++++++ test/test.lua | 3 +- test/test_isp.lua | 56 +++++++ test/test_netspeed.lua | 56 +++++++ 8 files changed, 603 insertions(+), 1 deletion(-) create mode 100644 src/isp.c create mode 100644 src/netspeed.c create mode 100644 test/test_isp.lua create mode 100644 test/test_netspeed.lua diff --git a/AUTHORS b/AUTHORS index eb7fbb9..9eec8a8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,3 +11,4 @@ Lorenzo Pistone Mike Trinkala Vadim A. Misbakh-Soloviov Marcin Deranek +Dimitrij Denissenko diff --git a/rockspec/lua-geoip-scm-1.rockspec b/rockspec/lua-geoip-scm-1.rockspec index 9611fb0..2b6aa48 100644 --- a/rockspec/lua-geoip-scm-1.rockspec +++ b/rockspec/lua-geoip-scm-1.rockspec @@ -50,6 +50,26 @@ build = { "src/" }, libraries = { "GeoIP" } + }, + ["geoip.isp"] = { + sources = { + "src/database.c", + "src/isp.c" + }, + incdirs = { + "src/" + }, + libraries = { "GeoIP" } + }, + ["geoip.netspeed"] = { + sources = { + "src/database.c", + "src/netspeed.c" + }, + incdirs = { + "src/" + }, + libraries = { "GeoIP" } } } } diff --git a/src/database.h b/src/database.h index bc83769..bb078e6 100644 --- a/src/database.h +++ b/src/database.h @@ -8,6 +8,8 @@ #define LUAGEOIP_COUNTRY_MT "lua-geoip.db.country" #define LUAGEOIP_CITY_MT "lua-geoip.db.city" +#define LUAGEOIP_ISP_MT "lua-geoip.db.isp" +#define LUAGEOIP_NETSPEED_MT "lua-geoip.db.netspeed" int luageoip_common_open_db( lua_State * L, diff --git a/src/isp.c b/src/isp.c new file mode 100644 index 0000000..81b09c1 --- /dev/null +++ b/src/isp.c @@ -0,0 +1,232 @@ +/* + * isp.c: + * Lua bindings for MaxMind's GeoIP library. + * Abstracts accessors to the ISP database: + * https://www.maxmind.com/en/isp. + * See copyright information in file COPYRIGHT. +*/ + +#include "lua-geoip.h" +#include "database.h" + +#define LUAGEOIP_ISP_VERSION "lua-geoip.isp 0.1.0" +#define LUAGEOIP_ISP_COPYRIGHT "Copyright (C) 2013, lua-geoip authors" +#define LUAGEOIP_ISP_DESCRIPTION \ + "Bindings for MaxMind's GeoIP library (ISP database)" + +static GeoIP * check_isp_db(lua_State * L, int idx) +{ + int type = 0; + luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata( + L, + idx, + LUAGEOIP_ISP_MT + ); + if (pDB == NULL) + { + lua_pushstring(L, "lua-geoip error: isp db is null"); + return NULL; + } + + if (pDB->pGeoIP == NULL) + { + lua_pushstring(L, "lua-geoip error: attempted to use closed isp db"); + return NULL; + } + + type = GeoIP_database_edition(pDB->pGeoIP); + if ( + type != GEOIP_ISP_EDITION && + type != GEOIP_ISP_EDITION_V6 + ) + { + lua_pushstring(L, "lua-geoip error: object is not an isp db"); + return NULL; + } + + return pDB->pGeoIP; +} + +static int push_isp_info(lua_State * L, char *orgName) +{ + if (orgName == NULL) + { + lua_pushnil(L); + lua_pushliteral(L, "not found"); + return 2; + } + + lua_newtable(L); + lua_pushstring(L, orgName); + lua_setfield(L, -2, "isp_name"); + + return 1; +} + +static int lisp_query_by_name(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + const char * name = luaL_checkstring(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_isp_info(L, GeoIP_org_by_name(pGeoIP, name)); +} + +static int lisp_query_by_addr(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + const char * addr = luaL_checkstring(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_isp_info(L, GeoIP_org_by_addr(pGeoIP, addr)); +} + +static int lisp_query_by_ipnum(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + lua_Integer ipnum = luaL_checkinteger(L, 2); /* Hoping that value would fit */ + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_isp_info(L, GeoIP_org_by_ipnum(pGeoIP, ipnum)); +} + +static int lisp_charset(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + lua_pushinteger(L, GeoIP_charset(pGeoIP)); + + return 1; +} + +static int lisp_set_charset(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + int charset = luaL_checkint(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + GeoIP_set_charset(pGeoIP, charset); + + return 0; +} + +static int lisp_close(lua_State * L) +{ + luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata(L, 1, LUAGEOIP_ISP_MT); + + if (pDB && pDB->pGeoIP != NULL) + { + GeoIP_delete(pDB->pGeoIP); + pDB->pGeoIP = NULL; + } + + return 0; +} + +#define lisp_gc lisp_close + +static int lisp_tostring(lua_State * L) +{ + GeoIP * pGeoIP = check_isp_db(L, 1); + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + lua_pushstring(L, GeoIP_database_info(pGeoIP)); + + return 1; +} + +static const luaL_reg M[] = +{ + { "query_by_name", lisp_query_by_name }, + { "query_by_addr", lisp_query_by_addr }, + { "query_by_ipnum", lisp_query_by_ipnum }, + { "charset", lisp_charset }, + { "set_charset", lisp_set_charset }, + { "close", lisp_close }, + { "__gc", lisp_gc }, + { "__tostring", lisp_tostring }, + + { NULL, NULL } +}; + +/* Error message capture code inspired by code by Wolfgang Oertl. */ +static int lisp_open(lua_State * L) +{ + static const int allowed_types[] = + { + GEOIP_ISP_EDITION, + GEOIP_ISP_EDITION_V6 + }; + + return luageoip_common_open_db( + L, + M, + GEOIP_ISP_EDITION, + GEOIP_MEMORY_CACHE, + LUAGEOIP_ISP_MT, + GEOIP_INDEX_CACHE, /* not allowed */ + 2, + allowed_types + ); +} + +/* Lua module API */ +static const struct luaL_reg R[] = +{ + { "open", lisp_open }, + + { NULL, NULL } +}; + +#ifdef __cplusplus +extern "C" { +#endif + +LUALIB_API int luaopen_geoip_isp(lua_State * L) +{ + /* + * Register module + */ + luaL_register(L, "geoip.isp", R); + + /* + * Register module information + */ + lua_pushliteral(L, LUAGEOIP_ISP_VERSION); + lua_setfield(L, -2, "_VERSION"); + + lua_pushliteral(L, LUAGEOIP_ISP_COPYRIGHT); + lua_setfield(L, -2, "_COPYRIGHT"); + + lua_pushliteral(L, LUAGEOIP_ISP_DESCRIPTION); + lua_setfield(L, -2, "_DESCRIPTION"); + + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/netspeed.c b/src/netspeed.c new file mode 100644 index 0000000..ecaa4f7 --- /dev/null +++ b/src/netspeed.c @@ -0,0 +1,234 @@ +/* + * netspeed.c: + * Lua bindings for MaxMind's GeoIP library. + * Abstracts accessors to the NetSpeed database: + * https://www.maxmind.com/en/netspeed. + * See copyright information in file COPYRIGHT. +*/ + +#include "lua-geoip.h" +#include "database.h" + +#define LUAGEOIP_NETSPEED_VERSION "lua-geoip.netspeed 0.1.0" +#define LUAGEOIP_NETSPEED_COPYRIGHT "Copyright (C) 2013, lua-geoip authors" +#define LUAGEOIP_NETSPEED_DESCRIPTION \ + "Bindings for MaxMind's GeoIP library (netspeed database)" + +static GeoIP * check_netspeed_db(lua_State * L, int idx) +{ + int type = 0; + luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata( + L, + idx, + LUAGEOIP_NETSPEED_MT + ); + if (pDB == NULL) + { + lua_pushstring(L, "lua-geoip error: netspeed db is null"); + return NULL; + } + + if (pDB->pGeoIP == NULL) + { + lua_pushstring(L, "lua-geoip error: attempted to use closed netspeed db"); + return NULL; + } + + type = GeoIP_database_edition(pDB->pGeoIP); + if ( + type != GEOIP_NETSPEED_EDITION && + type != GEOIP_NETSPEED_EDITION_REV1 && + type != GEOIP_NETSPEED_EDITION_REV1_V6 + ) + { + lua_pushstring(L, "lua-geoip error: object is not an netspeed db"); + return NULL; + } + + return pDB->pGeoIP; +} + +static int push_netspeed_info(lua_State * L, char *orgName) +{ + if (orgName == NULL) + { + lua_pushnil(L); + lua_pushliteral(L, "not found"); + return 2; + } + + lua_newtable(L); + lua_pushstring(L, orgName); + lua_setfield(L, -2, "net_speed"); + + return 1; +} + +static int lnetspeed_query_by_name(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + const char * name = luaL_checkstring(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_netspeed_info(L, GeoIP_org_by_name(pGeoIP, name)); +} + +static int lnetspeed_query_by_addr(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + const char * addr = luaL_checkstring(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_netspeed_info(L, GeoIP_org_by_addr(pGeoIP, addr)); +} + +static int lnetspeed_query_by_ipnum(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + lua_Integer ipnum = luaL_checkinteger(L, 2); /* Hoping that value would fit */ + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + return push_netspeed_info(L, GeoIP_org_by_ipnum(pGeoIP, ipnum)); +} + +static int lnetspeed_charset(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + lua_pushinteger(L, GeoIP_charset(pGeoIP)); + + return 1; +} + +static int lnetspeed_set_charset(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + int charset = luaL_checkint(L, 2); + + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + GeoIP_set_charset(pGeoIP, charset); + + return 0; +} + +static int lnetspeed_close(lua_State * L) +{ + luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata(L, 1, LUAGEOIP_NETSPEED_MT); + + if (pDB && pDB->pGeoIP != NULL) + { + GeoIP_delete(pDB->pGeoIP); + pDB->pGeoIP = NULL; + } + + return 0; +} + +#define lnetspeed_gc lnetspeed_close + +static int lnetspeed_tostring(lua_State * L) +{ + GeoIP * pGeoIP = check_netspeed_db(L, 1); + if (pGeoIP == NULL) + { + return lua_error(L); /* Error message already on stack */ + } + + lua_pushstring(L, GeoIP_database_info(pGeoIP)); + + return 1; +} + +static const luaL_reg M[] = +{ + { "query_by_name", lnetspeed_query_by_name }, + { "query_by_addr", lnetspeed_query_by_addr }, + { "query_by_ipnum", lnetspeed_query_by_ipnum }, + { "charset", lnetspeed_charset }, + { "set_charset", lnetspeed_set_charset }, + { "close", lnetspeed_close }, + { "__gc", lnetspeed_gc }, + { "__tostring", lnetspeed_tostring }, + + { NULL, NULL } +}; + +/* Error message capture code inspired by code by Wolfgang Oertl. */ +static int lnetspeed_open(lua_State * L) +{ + static const int allowed_types[] = + { + GEOIP_NETSPEED_EDITION, + GEOIP_NETSPEED_EDITION_REV1, + GEOIP_NETSPEED_EDITION_REV1_V6 + }; + + return luageoip_common_open_db( + L, + M, + GEOIP_NETSPEED_EDITION_REV1, + GEOIP_MEMORY_CACHE, + LUAGEOIP_NETSPEED_MT, + GEOIP_INDEX_CACHE, /* not allowed */ + 3, + allowed_types + ); +} + +/* Lua module API */ +static const struct luaL_reg R[] = +{ + { "open", lnetspeed_open }, + + { NULL, NULL } +}; + +#ifdef __cplusplus +extern "C" { +#endif + +LUALIB_API int luaopen_geoip_netspeed(lua_State * L) +{ + /* + * Register module + */ + luaL_register(L, "geoip.netspeed", R); + + /* + * Register module information + */ + lua_pushliteral(L, LUAGEOIP_NETSPEED_VERSION); + lua_setfield(L, -2, "_VERSION"); + + lua_pushliteral(L, LUAGEOIP_NETSPEED_COPYRIGHT); + lua_setfield(L, -2, "_COPYRIGHT"); + + lua_pushliteral(L, LUAGEOIP_NETSPEED_DESCRIPTION); + lua_setfield(L, -2, "_DESCRIPTION"); + + return 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/test.lua b/test/test.lua index 905a17c..8753e9d 100644 --- a/test/test.lua +++ b/test/test.lua @@ -75,7 +75,8 @@ do geoip.MMAP_CACHE; } - for _, flag in ipairs(flags) do + for i = 1, #flags do + local flag = flags[i] if flag ~= geoip.INDEX_CACHE then assert(geoip_country.open(nil, flag)):close() assert(geoip_country.open(geoip_country_filename, flag)):close() diff --git a/test/test_isp.lua b/test/test_isp.lua new file mode 100644 index 0000000..8d3f1aa --- /dev/null +++ b/test/test_isp.lua @@ -0,0 +1,56 @@ +-- TODO: Scrap these hacks and write a proper test suite. + +pcall(require, 'luarocks.require') + +local subject = require 'geoip.isp' +local filename = select(1, ...) or "./GeoIPISP.dat" + +print("TESTING lua-geoip.isp") +print("") +print("VERSION: ", assert(subject._VERSION)) +print("DESCRIPTION: ", assert(subject._DESCRIPTION)) +print("COPYRIGHT: ", assert(subject._COPYRIGHT)) +print("") + +-- Check that required files exist +assert(io.open(filename, "r")):close() + +do + assert(subject.open("./BADFILENAME") == nil) +end + +do + local flags = { + geoip.STANDARD; + geoip.MEMORY_CACHE; + geoip.CHECK_CACHE; + geoip.INDEX_CACHE; + geoip.MMAP_CACHE; + } + + for i = 1, #flags do + assert(subject.open(filename, flags[i])):close() + end +end + +do + local geodb = assert(subject.open(filename)) + geodb:close() + geodb:close() +end + +do + local geodb = assert(subject.open(filename)) + local check_isp = function(db, method, arg) + local res = assert(db[method](db, arg)) + assert(res["isp_name"]) + end + + check_isp(geodb, "query_by_name", "google-public-dns-a.google.com") + check_isp(geodb, "query_by_addr", "8.8.8.8") + check_isp(geodb, "query_by_ipnum", 134744072) -- 8.8.8.8 + geodb:close() +end + +print("") +print("OK") diff --git a/test/test_netspeed.lua b/test/test_netspeed.lua new file mode 100644 index 0000000..0154ecb --- /dev/null +++ b/test/test_netspeed.lua @@ -0,0 +1,56 @@ +-- TODO: Scrap these hacks and write a proper test suite. + +pcall(require, 'luarocks.require') + +local subject = require 'geoip.netspeed' +local filename = select(1, ...) or "./GeoIPNetSpeed.dat" + +print("TESTING lua-geoip.netspeed") +print("") +print("VERSION: ", assert(subject._VERSION)) +print("DESCRIPTION: ", assert(subject._DESCRIPTION)) +print("COPYRIGHT: ", assert(subject._COPYRIGHT)) +print("") + +-- Check that required files exist +assert(io.open(filename, "r")):close() + +do + assert(subject.open("./BADFILENAME") == nil) +end + +do + local flags = { + geoip.STANDARD; + geoip.MEMORY_CACHE; + geoip.CHECK_CACHE; + geoip.INDEX_CACHE; + geoip.MMAP_CACHE; + } + + for i = 1, #flags do + assert(subject.open(filename, flags[i])):close() + end +end + +do + local geodb = assert(subject.open(filename)) + geodb:close() + geodb:close() +end + +do + local geodb = assert(subject.open(filename)) + local check_netspeed = function(db, method, arg) + local res = assert(db[method](db, arg)) + assert(res["net_speed"]) + end + + check_netspeed(geodb, "query_by_name", "google-public-dns-a.google.com") + check_netspeed(geodb, "query_by_addr", "8.8.8.8") + check_netspeed(geodb, "query_by_ipnum", 134744072) -- 8.8.8.8 + geodb:close() +end + +print("") +print("OK")