]> git.ipfire.org Git - location/libloc.git/blob - src/lua/database.c
importer: Drop EDROP as it has been merged into DROP
[location/libloc.git] / src / lua / database.c
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"
26 #include "as.h"
27 #include "compat.h"
28 #include "country.h"
29 #include "database.h"
30 #include "network.h"
31
32 typedef struct database {
33 struct loc_database* db;
34 } Database;
35
36 static 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
45 static 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
77 static int Database_gc(lua_State* L) {
78 Database* self = luaL_checkdatabase(L, 1);
79
80 // Free database
81 if (self->db) {
82 loc_database_unref(self->db);
83 self->db = NULL;
84 }
85
86 return 0;
87 }
88
89 // Created At
90
91 static int Database_created_at(lua_State* L) {
92 Database* self = luaL_checkdatabase(L, 1);
93
94 // Fetch the time
95 time_t created_at = loc_database_created_at(self->db);
96
97 // Push the time onto the stack
98 lua_pushnumber(L, created_at);
99
100 return 1;
101 }
102
103 // Description
104
105 static int Database_get_description(lua_State* L) {
106 Database* self = luaL_checkdatabase(L, 1);
107
108 // Push the description
109 lua_pushstring(L, loc_database_get_description(self->db));
110
111 return 1;
112 }
113
114 // License
115
116 static int Database_get_license(lua_State* L) {
117 Database* self = luaL_checkdatabase(L, 1);
118
119 // Push the license
120 lua_pushstring(L, loc_database_get_license(self->db));
121
122 return 1;
123 }
124
125 static int Database_get_vendor(lua_State* L) {
126 Database* self = luaL_checkdatabase(L, 1);
127
128 // Push the vendor
129 lua_pushstring(L, loc_database_get_vendor(self->db));
130
131 return 1;
132 }
133
134 static int Database_get_as(lua_State* L) {
135 struct loc_as* as = NULL;
136 int r;
137
138 Database* self = luaL_checkdatabase(L, 1);
139
140 // Fetch number
141 uint32_t asn = luaL_checknumber(L, 2);
142
143 // Fetch the AS
144 r = loc_database_get_as(self->db, &as, asn);
145 if (r) {
146 lua_pushnil(L);
147 return 1;
148 }
149
150 // Create a new AS object
151 r = create_as(L, as);
152 loc_as_unref(as);
153
154 return r;
155 }
156
157 static int Database_get_country(lua_State* L) {
158 struct loc_country* country = NULL;
159 int r;
160
161 Database* self = luaL_checkdatabase(L, 1);
162
163 // Fetch code
164 const char* code = luaL_checkstring(L, 2);
165
166 // Fetch the country
167 r = loc_database_get_country(self->db, &country, code);
168 if (r) {
169 lua_pushnil(L);
170 return 1;
171 }
172
173 // Create a new country object
174 r = create_country(L, country);
175 loc_country_unref(country);
176
177 return r;
178 }
179
180 static int Database_lookup(lua_State* L) {
181 struct loc_network* network = NULL;
182 int r;
183
184 Database* self = luaL_checkdatabase(L, 1);
185
186 // Require a string
187 const char* address = luaL_checkstring(L, 2);
188
189 // Perform lookup
190 r = loc_database_lookup_from_string(self->db, address, &network);
191 if (r) {
192 switch (errno) {
193 // Return nil if the network was not found
194 case ENOENT:
195 lua_pushnil(L);
196 return 1;
197
198 default:
199 return luaL_error(L, "Could not lookup address %s: %s\n", address, strerror(errno));
200 }
201 }
202
203 // Create a network object
204 r = create_network(L, network);
205 loc_network_unref(network);
206
207 return r;
208 }
209
210 static int Database_verify(lua_State* L) {
211 FILE* f = NULL;
212 int r;
213
214 Database* self = luaL_checkdatabase(L, 1);
215
216 // Fetch path to key
217 const char* key = luaL_checkstring(L, 2);
218
219 // Open the keyfile
220 f = fopen(key, "r");
221 if (!f)
222 return luaL_error(L, "Could not open key %s: %s\n", key, strerror(errno));
223
224 // Verify!
225 r = loc_database_verify(self->db, f);
226 fclose(f);
227
228 // Push result onto the stack
229 lua_pushboolean(L, (r == 0));
230
231 return 1;
232 }
233
234 typedef struct enumerator {
235 struct loc_database_enumerator* e;
236 } DatabaseEnumerator;
237
238 static DatabaseEnumerator* luaL_checkdatabaseenumerator(lua_State* L, int i) {
239 void* userdata = luaL_checkudata(L, i, "location.DatabaseEnumerator");
240
241 // Throw an error if the argument doesn't match
242 luaL_argcheck(L, userdata, i, "DatabaseEnumerator expected");
243
244 return (DatabaseEnumerator*)userdata;
245 }
246
247 static int DatabaseEnumerator_gc(lua_State* L) {
248 DatabaseEnumerator* self = luaL_checkdatabaseenumerator(L, 1);
249
250 if (self->e) {
251 loc_database_enumerator_unref(self->e);
252 self->e = NULL;
253 }
254
255 return 0;
256 }
257
258 static int DatabaseEnumerator_next_network(lua_State* L) {
259 struct loc_network* network = NULL;
260 int r;
261
262 DatabaseEnumerator* self = luaL_checkdatabaseenumerator(L, lua_upvalueindex(1));
263
264 // Fetch the next network
265 r = loc_database_enumerator_next_network(self->e, &network);
266 if (r)
267 return luaL_error(L, "Could not fetch network: %s\n", strerror(errno));
268
269 // If we have received no network, we have reached the end
270 if (!network) {
271 lua_pushnil(L);
272 return 1;
273 }
274
275 // Create a network object
276 r = create_network(L, network);
277 loc_network_unref(network);
278
279 return r;
280 }
281
282 static int Database_list_networks(lua_State* L) {
283 DatabaseEnumerator* e = NULL;
284 int r;
285
286 Database* self = luaL_checkdatabase(L, 1);
287
288 // Allocate a new enumerator
289 e = lua_newuserdata(L, sizeof(*e));
290 luaL_setmetatable(L, "location.DatabaseEnumerator");
291
292 // Create a new enumerator
293 r = loc_database_enumerator_new(&e->e, self->db, LOC_DB_ENUMERATE_NETWORKS, 0);
294 if (r)
295 return luaL_error(L, "Could not create enumerator: %s\n", strerror(errno));
296
297 // Push the closure onto the stack
298 lua_pushcclosure(L, DatabaseEnumerator_next_network, 1);
299
300 return 1;
301 }
302
303 static const struct luaL_Reg database_functions[] = {
304 { "created_at", Database_created_at },
305 { "get_as", Database_get_as },
306 { "get_description", Database_get_description },
307 { "get_country", Database_get_country },
308 { "get_license", Database_get_license },
309 { "get_vendor", Database_get_vendor },
310 { "open", Database_open },
311 { "lookup", Database_lookup },
312 { "list_networks", Database_list_networks },
313 { "verify", Database_verify },
314 { "__gc", Database_gc },
315 { NULL, NULL },
316 };
317
318 int register_database(lua_State* L) {
319 return register_class(L, "location.Database", database_functions);
320 }
321
322 static const struct luaL_Reg database_enumerator_functions[] = {
323 { "__gc", DatabaseEnumerator_gc },
324 { NULL, NULL },
325 };
326
327 int register_database_enumerator(lua_State* L) {
328 return register_class(L, "location.DatabaseEnumerator", database_enumerator_functions);
329 }