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