diff --git a/.gitignore b/.gitignore index d08b96b..e33da2b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,4 @@ *.o *.so -GeoIP.dat -GeoLiteCity.dat - +Geo*.dat 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 a193b89..d5b0036 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..30dc700 --- /dev/null +++ b/src/isp.c @@ -0,0 +1,229 @@ +/* +* isp.c: Bindings for MaxMind's GeoIP library +* 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..0c1ebfc --- /dev/null +++ b/src/netspeed.c @@ -0,0 +1,231 @@ +/* +* netspeed.c: Bindings for MaxMind's GeoIP library +* 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_isp.lua b/test/test_isp.lua new file mode 100644 index 0000000..dbb83d2 --- /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 _, flag in ipairs(flags) do + assert(subject.open(filename, flag)):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..dfe5c57 --- /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 _, flag in ipairs(flags) do + assert(subject.open(filename, flag)):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")