]> git.ipfire.org Git - people/ms/libloc.git/blob - src/python/database.c
python: Raise proper error when database does not exist
[people/ms/libloc.git] / src / python / database.c
1 /*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 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 <Python.h>
18
19 #include <loc/libloc.h>
20 #include <loc/database.h>
21
22 #include "locationmodule.h"
23 #include "as.h"
24 #include "database.h"
25 #include "network.h"
26
27 static PyObject* Database_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
28 DatabaseObject* self = (DatabaseObject*)type->tp_alloc(type, 0);
29
30 return (PyObject*)self;
31 }
32
33 static void Database_dealloc(DatabaseObject* self) {
34 if (self->db)
35 loc_database_unref(self->db);
36
37 if (self->path)
38 free(self->path);
39
40 Py_TYPE(self)->tp_free((PyObject* )self);
41 }
42
43 static int Database_init(DatabaseObject* self, PyObject* args, PyObject* kwargs) {
44 const char* path = NULL;
45
46 if (!PyArg_ParseTuple(args, "s", &path))
47 return -1;
48
49 self->path = strdup(path);
50
51 // Open the file for reading
52 FILE* f = fopen(self->path, "r");
53 if (!f) {
54 PyErr_SetFromErrno(PyExc_IOError);
55 return -1;
56 }
57
58 // Load the database
59 int r = loc_database_new(loc_ctx, &self->db, f);
60 fclose(f);
61
62 // Return on any errors
63 if (r)
64 return -1;
65
66 return 0;
67 }
68
69 static PyObject* Database_repr(DatabaseObject* self) {
70 return PyUnicode_FromFormat("<Database %s>", self->path);
71 }
72
73 static PyObject* Database_get_description(DatabaseObject* self) {
74 const char* description = loc_database_get_description(self->db);
75
76 return PyUnicode_FromString(description);
77 }
78
79 static PyObject* Database_get_vendor(DatabaseObject* self) {
80 const char* vendor = loc_database_get_vendor(self->db);
81
82 return PyUnicode_FromString(vendor);
83 }
84
85 static PyObject* Database_get_license(DatabaseObject* self) {
86 const char* license = loc_database_get_license(self->db);
87
88 return PyUnicode_FromString(license);
89 }
90
91 static PyObject* Database_get_created_at(DatabaseObject* self) {
92 time_t created_at = loc_database_created_at(self->db);
93
94 return PyLong_FromLong(created_at);
95 }
96
97 static PyObject* Database_get_as(DatabaseObject* self, PyObject* args) {
98 struct loc_as* as = NULL;
99 uint32_t number = 0;
100
101 if (!PyArg_ParseTuple(args, "i", &number))
102 return NULL;
103
104 // Try to retrieve the AS
105 int r = loc_database_get_as(self->db, &as, number);
106
107 // We got an AS
108 if (r == 0) {
109 PyObject* obj = new_as(&ASType, as);
110 loc_as_unref(as);
111
112 return obj;
113
114 // Nothing found
115 } else if (r == 1) {
116 Py_RETURN_NONE;
117 }
118
119 // Unexpected error
120 return NULL;
121 }
122
123 static PyObject* Database_lookup(DatabaseObject* self, PyObject* args) {
124 struct loc_network* network = NULL;
125 const char* address = NULL;
126
127 if (!PyArg_ParseTuple(args, "s", &address))
128 return NULL;
129
130 // Try to retrieve a matching network
131 int r = loc_database_lookup_from_string(self->db, address, &network);
132
133 // We got a network
134 if (r == 0) {
135 PyObject* obj = new_network(&NetworkType, network);
136 loc_network_unref(network);
137
138 return obj;
139
140 // Nothing found
141 } else if (r == 1) {
142 Py_RETURN_NONE;
143
144 // Invalid input
145 } else if (r == -EINVAL) {
146 PyErr_Format(PyExc_ValueError, "Invalid IP address: %s", address);
147 return NULL;
148 }
149
150 // Unexpected error
151 return NULL;
152 }
153
154 static PyObject* new_database_enumerator(PyTypeObject* type, struct loc_database_enumerator* enumerator) {
155 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
156 if (self) {
157 self->enumerator = loc_database_enumerator_ref(enumerator);
158 }
159
160 return (PyObject*)self;
161 }
162
163 static PyObject* Database_search_as(DatabaseObject* self, PyObject* args) {
164 const char* string = NULL;
165
166 if (!PyArg_ParseTuple(args, "s", &string))
167 return NULL;
168
169 struct loc_database_enumerator* enumerator;
170
171 int r = loc_database_enumerator_new(&enumerator, self->db);
172 if (r) {
173 PyErr_SetFromErrno(PyExc_SystemError);
174 return NULL;
175 }
176
177 // Search string we are searching for
178 loc_database_enumerator_set_string(enumerator, string);
179
180 PyObject* obj = new_database_enumerator(&DatabaseEnumeratorType, enumerator);
181 loc_database_enumerator_unref(enumerator);
182
183 return obj;
184 }
185
186 static struct PyMethodDef Database_methods[] = {
187 {
188 "get_as",
189 (PyCFunction)Database_get_as,
190 METH_VARARGS,
191 NULL,
192 },
193 {
194 "lookup",
195 (PyCFunction)Database_lookup,
196 METH_VARARGS,
197 NULL,
198 },
199 {
200 "search_as",
201 (PyCFunction)Database_search_as,
202 METH_VARARGS,
203 NULL,
204 },
205 { NULL },
206 };
207
208 static struct PyGetSetDef Database_getsetters[] = {
209 {
210 "created_at",
211 (getter)Database_get_created_at,
212 NULL,
213 NULL,
214 NULL,
215 },
216 {
217 "description",
218 (getter)Database_get_description,
219 NULL,
220 NULL,
221 NULL,
222 },
223 {
224 "license",
225 (getter)Database_get_license,
226 NULL,
227 NULL,
228 NULL,
229 },
230 {
231 "vendor",
232 (getter)Database_get_vendor,
233 NULL,
234 NULL,
235 NULL,
236 },
237 { NULL },
238 };
239
240 PyTypeObject DatabaseType = {
241 PyVarObject_HEAD_INIT(NULL, 0)
242 tp_name: "location.Database",
243 tp_basicsize: sizeof(DatabaseObject),
244 tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
245 tp_new: Database_new,
246 tp_dealloc: (destructor)Database_dealloc,
247 tp_init: (initproc)Database_init,
248 tp_doc: "Database object",
249 tp_methods: Database_methods,
250 tp_getset: Database_getsetters,
251 tp_repr: (reprfunc)Database_repr,
252 };
253
254 static PyObject* DatabaseEnumerator_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
255 DatabaseEnumeratorObject* self = (DatabaseEnumeratorObject*)type->tp_alloc(type, 0);
256
257 return (PyObject*)self;
258 }
259
260 static void DatabaseEnumerator_dealloc(DatabaseEnumeratorObject* self) {
261 loc_database_enumerator_unref(self->enumerator);
262
263 Py_TYPE(self)->tp_free((PyObject* )self);
264 }
265
266 static PyObject* DatabaseEnumerator_next(DatabaseEnumeratorObject* self) {
267 struct loc_as* as = loc_database_enumerator_next_as(self->enumerator);
268 if (as) {
269 PyObject* obj = new_as(&ASType, as);
270 loc_as_unref(as);
271
272 return obj;
273 }
274
275 // Nothing found, that means the end
276 PyErr_SetNone(PyExc_StopIteration);
277 return NULL;
278 }
279
280 PyTypeObject DatabaseEnumeratorType = {
281 PyVarObject_HEAD_INIT(NULL, 0)
282 tp_name: "location.DatabaseEnumerator",
283 tp_basicsize: sizeof(DatabaseEnumeratorObject),
284 tp_flags: Py_TPFLAGS_DEFAULT,
285 tp_alloc: PyType_GenericAlloc,
286 tp_new: DatabaseEnumerator_new,
287 tp_dealloc: (destructor)DatabaseEnumerator_dealloc,
288 tp_iter: PyObject_SelfIter,
289 tp_iternext: (iternextfunc)DatabaseEnumerator_next,
290 };