]> git.ipfire.org Git - people/ms/libloc.git/blame - src/lua/database.c
lua: Cleanup any database iterators
[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
42173573
MT
220typedef struct enumerator {
221 struct loc_database_enumerator* e;
222} DatabaseEnumerator;
223
224static DatabaseEnumerator* luaL_checkdatabaseenumerator(lua_State* L, int i) {
225 void* userdata = luaL_checkudata(L, i, "location.DatabaseEnumerator");
226
227 // Throw an error if the argument doesn't match
228 luaL_argcheck(L, userdata, i, "DatabaseEnumerator expected");
229
230 return (DatabaseEnumerator*)userdata;
231}
232
233static int DatabaseEnumerator_gc(lua_State* L) {
234 DatabaseEnumerator* self = luaL_checkdatabaseenumerator(L, 1);
235
236 if (self->e) {
237 loc_database_enumerator_unref(self->e);
238 self->e = NULL;
239 }
240
241 return 0;
242}
243
244static int DatabaseEnumerator_next_network(lua_State* L) {
cbc4c6a7
MT
245 struct loc_network* network = NULL;
246 int r;
247
42173573 248 DatabaseEnumerator* self = luaL_checkdatabaseenumerator(L, lua_upvalueindex(1));
cbc4c6a7
MT
249
250 // Fetch the next network
42173573 251 r = loc_database_enumerator_next_network(self->e, &network);
cbc4c6a7
MT
252 if (r)
253 return luaL_error(L, "Could not fetch network: %s\n", strerror(errno));
254
255 // If we have received no network, we have reached the end
256 if (!network) {
257 lua_pushnil(L);
258 return 1;
259 }
260
261 // Create a network object
262 r = create_network(L, network);
263 loc_network_unref(network);
264
265 return r;
266}
267
268static int Database_list_networks(lua_State* L) {
42173573 269 DatabaseEnumerator* e = NULL;
cbc4c6a7
MT
270 int r;
271
272 Database* self = luaL_checkdatabase(L, 1);
273
42173573
MT
274 // Allocate a new enumerator
275 e = lua_newuserdata(L, sizeof(*e));
276 luaL_setmetatable(L, "location.DatabaseEnumerator");
277
cbc4c6a7 278 // Create a new enumerator
42173573 279 r = loc_database_enumerator_new(&e->e, self->db, LOC_DB_ENUMERATE_NETWORKS, 0);
cbc4c6a7
MT
280 if (r)
281 return luaL_error(L, "Could not create enumerator: %s\n", strerror(errno));
282
cbc4c6a7 283 // Push the closure onto the stack
42173573 284 lua_pushcclosure(L, DatabaseEnumerator_next_network, 1);
cbc4c6a7
MT
285
286 return 1;
287}
288
7eaabd10 289static const struct luaL_Reg database_functions[] = {
77ee9330 290 { "get_as", Database_get_as },
ba81f732 291 { "get_description", Database_get_description },
49463375 292 { "get_country", Database_get_country },
ba81f732
MT
293 { "get_license", Database_get_license },
294 { "get_vendor", Database_get_vendor },
7eaabd10
MT
295 { "open", Database_open },
296 { "lookup", Database_lookup },
cbc4c6a7 297 { "list_networks", Database_list_networks },
24fce3a8 298 { "verify", Database_verify },
e1c9275c 299 { "__gc", Database_gc },
7eaabd10
MT
300 { NULL, NULL },
301};
302
303int register_database(lua_State* L) {
e914e3ca 304 return register_class(L, "location.Database", database_functions);
7eaabd10 305}
42173573
MT
306
307static const struct luaL_Reg database_enumerator_functions[] = {
308 { "__gc", DatabaseEnumerator_gc },
309 { NULL, NULL },
310};
311
312int register_database_enumerator(lua_State* L) {
313 return register_class(L, "location.DatabaseEnumerator", database_enumerator_functions);
314}