]> git.ipfire.org Git - people/ms/libloc.git/blob - src/python/network.c
11f672bca6daaeee724cc81a3f8bcd99d70386b1
[people/ms/libloc.git] / src / python / network.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 <errno.h>
20
21 #include <loc/libloc.h>
22 #include <loc/network.h>
23
24 #include "locationmodule.h"
25 #include "network.h"
26
27 static PyObject* PyList_FromNetworkList(struct loc_network_list* networks) {
28 PyObject* list = PyList_New(0);
29 if (!networks)
30 return list;
31
32 while (!loc_network_list_empty(networks)) {
33 struct loc_network* network = loc_network_list_pop(networks);
34
35 PyObject* n = new_network(&NetworkType, network);
36 PyList_Append(list, n);
37
38 loc_network_unref(network);
39 Py_DECREF(n);
40 }
41
42 return list;
43 }
44
45 PyObject* new_network(PyTypeObject* type, struct loc_network* network) {
46 NetworkObject* self = (NetworkObject*)type->tp_alloc(type, 0);
47 if (self) {
48 self->network = loc_network_ref(network);
49 }
50
51 return (PyObject*)self;
52 }
53
54 static PyObject* Network_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
55 NetworkObject* self = (NetworkObject*)type->tp_alloc(type, 0);
56
57 return (PyObject*)self;
58 }
59
60 static void Network_dealloc(NetworkObject* self) {
61 if (self->network)
62 loc_network_unref(self->network);
63
64 Py_TYPE(self)->tp_free((PyObject* )self);
65 }
66
67 static int Network_init(NetworkObject* self, PyObject* args, PyObject* kwargs) {
68 const char* network = NULL;
69
70 if (!PyArg_ParseTuple(args, "s", &network))
71 return -1;
72
73 // Load the Network
74 int r = loc_network_new_from_string(loc_ctx, &self->network, network);
75 if (r) {
76 PyErr_Format(PyExc_ValueError, "Invalid network: %s", network);
77 return -1;
78 }
79
80 return 0;
81 }
82
83 static PyObject* Network_repr(NetworkObject* self) {
84 char* network = loc_network_str(self->network);
85
86 PyObject* obj = PyUnicode_FromFormat("<location.Network %s>", network);
87 free(network);
88
89 return obj;
90 }
91
92 static PyObject* Network_str(NetworkObject* self) {
93 char* network = loc_network_str(self->network);
94
95 PyObject* obj = PyUnicode_FromString(network);
96 free(network);
97
98 return obj;
99 }
100
101 static PyObject* Network_get_country_code(NetworkObject* self) {
102 const char* country_code = loc_network_get_country_code(self->network);
103
104 return PyUnicode_FromString(country_code);
105 }
106
107 static int Network_set_country_code(NetworkObject* self, PyObject* value) {
108 const char* country_code = PyUnicode_AsUTF8(value);
109
110 int r = loc_network_set_country_code(self->network, country_code);
111 if (r) {
112 if (r == -EINVAL)
113 PyErr_Format(PyExc_ValueError,
114 "Invalid country code: %s", country_code);
115
116 return -1;
117 }
118
119 return 0;
120 }
121
122 static PyObject* Network_get_asn(NetworkObject* self) {
123 uint32_t asn = loc_network_get_asn(self->network);
124
125 if (asn)
126 return PyLong_FromLong(asn);
127
128 Py_RETURN_NONE;
129 }
130
131 static int Network_set_asn(NetworkObject* self, PyObject* value) {
132 long int asn = PyLong_AsLong(value);
133
134 // Check if the ASN is within the valid range
135 if (asn <= 0 || asn > UINT32_MAX) {
136 PyErr_Format(PyExc_ValueError, "Invalid ASN %ld", asn);
137 return -1;
138 }
139
140 int r = loc_network_set_asn(self->network, asn);
141 if (r)
142 return -1;
143
144 return 0;
145 }
146
147 static PyObject* Network_has_flag(NetworkObject* self, PyObject* args) {
148 enum loc_network_flags flag = 0;
149
150 if (!PyArg_ParseTuple(args, "i", &flag))
151 return NULL;
152
153 if (loc_network_has_flag(self->network, flag))
154 Py_RETURN_TRUE;
155
156 Py_RETURN_FALSE;
157 }
158
159 static PyObject* Network_set_flag(NetworkObject* self, PyObject* args) {
160 enum loc_network_flags flag = 0;
161
162 if (!PyArg_ParseTuple(args, "i", &flag))
163 return NULL;
164
165 int r = loc_network_set_flag(self->network, flag);
166
167 if (r) {
168 // What exception to throw here?
169 return NULL;
170 }
171
172 Py_RETURN_NONE;
173 }
174
175 static PyObject* Network_exclude(NetworkObject* self, PyObject* args) {
176 NetworkObject* other = NULL;
177
178 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
179 return NULL;
180
181 struct loc_network_list* list = loc_network_exclude(self->network, other->network);
182
183 // Convert to Python objects
184 PyObject* obj = PyList_FromNetworkList(list);
185 loc_network_list_unref(list);
186
187 return obj;
188 }
189
190 static PyObject* Network_is_subnet_of(NetworkObject* self, PyObject* args) {
191 NetworkObject* other = NULL;
192
193 if (!PyArg_ParseTuple(args, "O!", &NetworkType, &other))
194 return NULL;
195
196 if (loc_network_is_subnet_of(self->network, other->network))
197 Py_RETURN_TRUE;
198
199 Py_RETURN_FALSE;
200 }
201
202 static PyObject* Network_get_family(NetworkObject* self) {
203 int family = loc_network_address_family(self->network);
204
205 return PyLong_FromLong(family);
206 }
207
208 static PyObject* Network_get_first_address(NetworkObject* self) {
209 char* address = loc_network_format_first_address(self->network);
210
211 PyObject* obj = PyUnicode_FromString(address);
212 free(address);
213
214 return obj;
215 }
216
217 static PyObject* Network_get_last_address(NetworkObject* self) {
218 char* address = loc_network_format_last_address(self->network);
219
220 PyObject* obj = PyUnicode_FromString(address);
221 free(address);
222
223 return obj;
224 }
225
226 static struct PyMethodDef Network_methods[] = {
227 {
228 "exclude",
229 (PyCFunction)Network_exclude,
230 METH_VARARGS,
231 NULL,
232 },
233 {
234 "has_flag",
235 (PyCFunction)Network_has_flag,
236 METH_VARARGS,
237 NULL,
238 },
239 {
240 "is_subnet_of",
241 (PyCFunction)Network_is_subnet_of,
242 METH_VARARGS,
243 NULL,
244 },
245 {
246 "set_flag",
247 (PyCFunction)Network_set_flag,
248 METH_VARARGS,
249 NULL,
250 },
251 { NULL },
252 };
253
254 static struct PyGetSetDef Network_getsetters[] = {
255 {
256 "asn",
257 (getter)Network_get_asn,
258 (setter)Network_set_asn,
259 NULL,
260 NULL,
261 },
262 {
263 "country_code",
264 (getter)Network_get_country_code,
265 (setter)Network_set_country_code,
266 NULL,
267 NULL,
268 },
269 {
270 "family",
271 (getter)Network_get_family,
272 NULL,
273 NULL,
274 NULL,
275 },
276 {
277 "first_address",
278 (getter)Network_get_first_address,
279 NULL,
280 NULL,
281 NULL,
282 },
283 {
284 "last_address",
285 (getter)Network_get_last_address,
286 NULL,
287 NULL,
288 NULL,
289 },
290 { NULL },
291 };
292
293 PyTypeObject NetworkType = {
294 PyVarObject_HEAD_INIT(NULL, 0)
295 .tp_name = "location.Network",
296 .tp_basicsize = sizeof(NetworkObject),
297 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
298 .tp_new = Network_new,
299 .tp_dealloc = (destructor)Network_dealloc,
300 .tp_init = (initproc)Network_init,
301 .tp_doc = "Network object",
302 .tp_methods = Network_methods,
303 .tp_getset = Network_getsetters,
304 .tp_repr = (reprfunc)Network_repr,
305 .tp_str = (reprfunc)Network_str,
306 };