]> git.ipfire.org Git - people/ms/libloc.git/blame - src/lua/database.c
lua: Create a simple iterator for all networks
[people/ms/libloc.git] / src / lua / database.c
CommitLineData
7eaabd10
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2024 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <string.h>
19
20#include <lua.h>
21#include <lauxlib.h>
22
23#include <libloc/database.h>
24
25#include "location.h"
77ee9330 26#include "as.h"
031bae06 27#include "compat.h"
49463375 28#include "country.h"
7eaabd10 29#include "database.h"
9fac2ef2 30#include "network.h"
7eaabd10
MT
31
32typedef struct database {
33 struct loc_database* db;
34} Database;
35
36static Database* luaL_checkdatabase(lua_State* L, int i) {
37 void* userdata = luaL_checkudata(L, i, "location.Database");
38
39 // Throw an error if the argument doesn't match
40 luaL_argcheck(L, userdata, i, "Database expected");
41
42 return (Database*)userdata;
43}
44
45static int Database_open(lua_State* L) {
46 const char* path = NULL;
47 FILE* f = NULL;
48 int r;
49
50 // Fetch the path
51 path = luaL_checkstring(L, 1);
52
53 // Allocate a new object
54 Database* self = (Database*)lua_newuserdata(L, sizeof(*self));
55
56 // Set metatable
57 luaL_setmetatable(L, "location.Database");
58
59 // Open the database file
60 f = fopen(path, "r");
61 if (!f)
62 return luaL_error(L, "Could not open %s: %s\n", path, strerror(errno));
63
64 // Open the database
65 r = loc_database_new(ctx, &self->db, f);
66
67 // Close the file descriptor
68 fclose(f);
69
70 // Check for errors
71 if (r)
72 return luaL_error(L, "Could not open database %s: %s\n", path, strerror(errno));
73
74 return 1;
75}
76
75448a02 77static int Database_gc(lua_State* L) {
3b06229b 78 Database* self = luaL_checkdatabase(L, 1);
7eaabd10 79
3b06229b
MT
80 // Free database
81 if (self->db) {
7eaabd10 82 loc_database_unref(self->db);
3b06229b
MT
83 self->db = NULL;
84 }
85
86 return 0;
87}
88
ba81f732
MT
89// Description
90
91static int Database_get_description(lua_State* L) {
92 Database* self = luaL_checkdatabase(L, 1);
93
94 // Push the description
95 lua_pushstring(L, loc_database_get_description(self->db));
96
97 return 1;
98}
99
100// License
101
102static int Database_get_license(lua_State* L) {
103 Database* self = luaL_checkdatabase(L, 1);
104
105 // Push the license
106 lua_pushstring(L, loc_database_get_license(self->db));
107
108 return 1;
109}
110
111static int Database_get_vendor(lua_State* L) {
112 Database* self = luaL_checkdatabase(L, 1);
113
114 // Push the vendor
115 lua_pushstring(L, loc_database_get_vendor(self->db));
116
117 return 1;
118}
119
77ee9330
MT
120static int Database_get_as(lua_State* L) {
121 struct loc_as* as = NULL;
122 int r;
123
124 Database* self = luaL_checkdatabase(L, 1);
125
126 // Fetch number
127 uint32_t asn = luaL_checknumber(L, 2);
128
129 // Fetch the AS
130 r = loc_database_get_as(self->db, &as, asn);
131 if (r) {
132 lua_pushnil(L);
133 return 1;
134 }
135
136 // Create a new AS object
137 r = create_as(L, as);
138 loc_as_unref(as);
139
140 return r;
141}
142
49463375
MT
143static int Database_get_country(lua_State* L) {
144 struct loc_country* country = NULL;
145 int r;
146
147 Database* self = luaL_checkdatabase(L, 1);
148
149 // Fetch code
150 const char* code = luaL_checkstring(L, 2);
151
152 // Fetch the country
153 r = loc_database_get_country(self->db, &country, code);
154 if (r) {
155 lua_pushnil(L);
156 return 1;
157 }
158
159 // Create a new country object
160 r = create_country(L, country);
161 loc_country_unref(country);
162
163 return r;
164}
165
7eaabd10
MT
166static int Database_lookup(lua_State* L) {
167 struct loc_network* network = NULL;
168 int r;
169
b49c59d2 170 Database* self = luaL_checkdatabase(L, 1);
7eaabd10
MT
171
172 // Require a string
b49c59d2 173 const char* address = luaL_checkstring(L, 2);
7eaabd10
MT
174
175 // Perform lookup
176 r = loc_database_lookup_from_string(self->db, address, &network);
88908fd4
MT
177 if (r) {
178 switch (errno) {
179 // Return nil if the network was not found
180 case ENOENT:
181 lua_pushnil(L);
182 return 1;
183
184 default:
185 return luaL_error(L, "Could not lookup address %s: %s\n", address, strerror(errno));
186 }
187 }
7eaabd10 188
9fac2ef2
MT
189 // Create a network object
190 r = create_network(L, network);
7eaabd10
MT
191 loc_network_unref(network);
192
9fac2ef2 193 return r;
7eaabd10
MT
194}
195
24fce3a8
MT
196static int Database_verify(lua_State* L) {
197 FILE* f = NULL;
198 int r;
199
200 Database* self = luaL_checkdatabase(L, 1);
201
202 // Fetch path to key
203 const char* key = luaL_checkstring(L, 2);
204
205 // Open the keyfile
206 f = fopen(key, "r");
207 if (!f)
208 return luaL_error(L, "Could not open key %s: %s\n", key, strerror(errno));
209
210 // Verify!
211 r = loc_database_verify(self->db, f);
212 fclose(f);
213
214 // Push result onto the stack
215 lua_pushboolean(L, (r == 0));
216
217 return 1;
218}
219
cbc4c6a7
MT
220static int Database_next_network(lua_State* L) {
221 struct loc_network* network = NULL;
222 int r;
223
224 struct loc_database_enumerator* e = lua_touserdata(L, lua_upvalueindex(1));
225
226 // Fetch the next network
227 r = loc_database_enumerator_next_network(e, &network);
228 if (r)
229 return luaL_error(L, "Could not fetch network: %s\n", strerror(errno));
230
231 // If we have received no network, we have reached the end
232 if (!network) {
233 lua_pushnil(L);
234 return 1;
235 }
236
237 // Create a network object
238 r = create_network(L, network);
239 loc_network_unref(network);
240
241 return r;
242}
243
244static int Database_list_networks(lua_State* L) {
245 struct loc_database_enumerator* e = NULL;
246 int r;
247
248 Database* self = luaL_checkdatabase(L, 1);
249
250 // Create a new enumerator
251 r = loc_database_enumerator_new(&e, self->db, LOC_DB_ENUMERATE_NETWORKS, 0);
252 if (r)
253 return luaL_error(L, "Could not create enumerator: %s\n", strerror(errno));
254
255 // Push the enumerator onto the stack
256 lua_pushlightuserdata(L, e);
257
258 // Push the closure onto the stack
259 lua_pushcclosure(L, Database_next_network, 1);
260
261 return 1;
262}
263
7eaabd10 264static const struct luaL_Reg database_functions[] = {
77ee9330 265 { "get_as", Database_get_as },
ba81f732 266 { "get_description", Database_get_description },
49463375 267 { "get_country", Database_get_country },
ba81f732
MT
268 { "get_license", Database_get_license },
269 { "get_vendor", Database_get_vendor },
7eaabd10
MT
270 { "open", Database_open },
271 { "lookup", Database_lookup },
cbc4c6a7 272 { "list_networks", Database_list_networks },
24fce3a8 273 { "verify", Database_verify },
e1c9275c 274 { "__gc", Database_gc },
7eaabd10
MT
275 { NULL, NULL },
276};
277
278int register_database(lua_State* L) {
e914e3ca 279 return register_class(L, "location.Database", database_functions);
7eaabd10 280}