]>
Commit | Line | Data |
---|---|---|
20da5c89 JM |
1 | /* |
2 | * Python bindings for wpa_ctrl (wpa_supplicant/hostapd control interface) | |
3 | * Copyright (c) 2013, Jouni Malinen <j@w1.fi> | |
4 | * | |
5 | * This software may be distributed under the terms of the BSD license. | |
6 | * See README for more details. | |
7 | */ | |
8 | ||
9 | #include <Python.h> | |
10 | #include <structmember.h> | |
11 | ||
12 | #include "wpa_ctrl.h" | |
13 | ||
14 | ||
15 | struct wpaspy_obj { | |
16 | PyObject_HEAD | |
17 | struct wpa_ctrl *ctrl; | |
18 | int attached; | |
19 | }; | |
20 | ||
21 | static PyObject *wpaspy_error; | |
22 | ||
23 | ||
24 | static int wpaspy_open(struct wpaspy_obj *self, PyObject *args) | |
25 | { | |
26 | const char *path; | |
27 | ||
28 | if (!PyArg_ParseTuple(args, "s", &path)) | |
29 | return -1; | |
30 | self->ctrl = wpa_ctrl_open(path); | |
31 | if (self->ctrl == NULL) | |
32 | return -1; | |
33 | self->attached = 0; | |
34 | return 0; | |
35 | } | |
36 | ||
37 | ||
38 | static void wpaspy_close(struct wpaspy_obj *self) | |
39 | { | |
40 | if (self->ctrl) { | |
41 | if (self->attached) | |
42 | wpa_ctrl_detach(self->ctrl); | |
43 | wpa_ctrl_close(self->ctrl); | |
44 | self->ctrl = NULL; | |
45 | } | |
46 | ||
47 | if (self->ob_type) | |
48 | self->ob_type->tp_free((PyObject *) self); | |
49 | } | |
50 | ||
51 | ||
52 | static PyObject * wpaspy_request(struct wpaspy_obj *self, PyObject *args) | |
53 | { | |
54 | const char *cmd; | |
55 | char buf[4096]; | |
56 | size_t buflen; | |
57 | int ret; | |
58 | ||
59 | if (!PyArg_ParseTuple(args, "s", &cmd)) | |
60 | return NULL; | |
61 | ||
62 | buflen = sizeof(buf) - 1; | |
63 | ret = wpa_ctrl_request(self->ctrl, cmd, strlen(cmd), buf, &buflen, | |
64 | NULL); | |
65 | if (ret == -2) { | |
66 | PyErr_SetString(wpaspy_error, "Request timed out"); | |
67 | return NULL; | |
68 | } | |
69 | if (ret) { | |
70 | PyErr_SetString(wpaspy_error, "Request failed"); | |
71 | return NULL; | |
72 | } | |
73 | ||
74 | buf[buflen] = '\0'; | |
75 | return Py_BuildValue("s", buf); | |
76 | } | |
77 | ||
78 | ||
79 | static PyObject * wpaspy_attach(struct wpaspy_obj *self) | |
80 | { | |
81 | int ret; | |
82 | ||
83 | if (self->attached) | |
84 | Py_RETURN_NONE; | |
85 | ||
86 | ret = wpa_ctrl_attach(self->ctrl); | |
87 | if (ret) { | |
88 | PyErr_SetString(wpaspy_error, "Attach failed"); | |
89 | return NULL; | |
90 | } | |
91 | Py_RETURN_NONE; | |
92 | } | |
93 | ||
94 | ||
95 | static PyObject * wpaspy_detach(struct wpaspy_obj *self) | |
96 | { | |
97 | int ret; | |
98 | ||
99 | if (!self->attached) | |
100 | Py_RETURN_NONE; | |
101 | ||
102 | ret = wpa_ctrl_detach(self->ctrl); | |
103 | if (ret) { | |
104 | PyErr_SetString(wpaspy_error, "Detach failed"); | |
105 | return NULL; | |
106 | } | |
107 | Py_RETURN_NONE; | |
108 | } | |
109 | ||
110 | ||
111 | static PyObject * wpaspy_pending(struct wpaspy_obj *self) | |
112 | { | |
113 | switch (wpa_ctrl_pending(self->ctrl)) { | |
114 | case 1: | |
115 | Py_RETURN_TRUE; | |
116 | case 0: | |
117 | Py_RETURN_FALSE; | |
118 | default: | |
119 | PyErr_SetString(wpaspy_error, "wpa_ctrl_pending failed"); | |
120 | break; | |
121 | } | |
122 | ||
123 | return NULL; | |
124 | } | |
125 | ||
126 | ||
127 | static PyObject * wpaspy_recv(struct wpaspy_obj *self) | |
128 | { | |
129 | int ret; | |
130 | char buf[4096]; | |
131 | size_t buflen; | |
132 | ||
133 | buflen = sizeof(buf) - 1; | |
134 | Py_BEGIN_ALLOW_THREADS | |
135 | ret = wpa_ctrl_recv(self->ctrl, buf, &buflen); | |
136 | Py_END_ALLOW_THREADS | |
137 | ||
138 | if (ret) { | |
139 | PyErr_SetString(wpaspy_error, "wpa_ctrl_recv failed"); | |
140 | return NULL; | |
141 | } | |
142 | ||
143 | buf[buflen] = '\0'; | |
144 | return Py_BuildValue("s", buf); | |
145 | } | |
146 | ||
147 | ||
148 | static PyMethodDef wpaspy_methods[] = { | |
149 | { | |
150 | "request", (PyCFunction) wpaspy_request, METH_VARARGS, | |
151 | "Send a control interface command and return response" | |
152 | }, | |
153 | { | |
154 | "attach", (PyCFunction) wpaspy_attach, METH_NOARGS, | |
155 | "Attach as an event monitor" | |
156 | }, | |
157 | { | |
158 | "detach", (PyCFunction) wpaspy_detach, METH_NOARGS, | |
159 | "Detach an event monitor" | |
160 | }, | |
161 | { | |
162 | "pending", (PyCFunction) wpaspy_pending, METH_NOARGS, | |
163 | "Check whether any events are pending" | |
164 | }, | |
165 | { | |
166 | "recv", (PyCFunction) wpaspy_recv, METH_NOARGS, | |
167 | "Received pending event" | |
168 | }, | |
169 | { NULL, NULL, 0, NULL } | |
170 | }; | |
171 | ||
172 | static PyMemberDef wpaspy_members[] = { | |
173 | { | |
174 | "attached", T_INT, offsetof(struct wpaspy_obj, attached), | |
175 | READONLY, | |
176 | "Whether instance is attached as event monitor" | |
177 | }, | |
178 | { NULL } | |
179 | }; | |
180 | ||
181 | static PyTypeObject wpaspy_ctrl = { | |
182 | PyObject_HEAD_INIT(NULL) | |
183 | .tp_name = "wpaspy.Ctrl", | |
184 | .tp_basicsize = sizeof(struct wpaspy_obj), | |
185 | .tp_getattro = PyObject_GenericGetAttr, | |
186 | .tp_setattro = PyObject_GenericSetAttr, | |
187 | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, | |
188 | .tp_methods = wpaspy_methods, | |
189 | .tp_members = wpaspy_members, | |
190 | .tp_init = (initproc) wpaspy_open, | |
191 | .tp_dealloc = (destructor) wpaspy_close, | |
192 | .tp_new = PyType_GenericNew, | |
193 | }; | |
194 | ||
195 | ||
196 | static PyMethodDef module_methods[] = { | |
197 | { NULL, NULL, 0, NULL } | |
198 | }; | |
199 | ||
200 | ||
201 | PyMODINIT_FUNC initwpaspy(void) | |
202 | { | |
203 | PyObject *mod; | |
204 | ||
205 | PyType_Ready(&wpaspy_ctrl); | |
206 | mod = Py_InitModule("wpaspy", module_methods); | |
207 | wpaspy_error = PyErr_NewException("wpaspy.error", NULL, NULL); | |
208 | ||
209 | Py_INCREF(&wpaspy_ctrl); | |
210 | Py_INCREF(wpaspy_error); | |
211 | ||
212 | PyModule_AddObject(mod, "Ctrl", (PyObject *) &wpaspy_ctrl); | |
213 | PyModule_AddObject(mod, "error", wpaspy_error); | |
214 | } |