Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / wpaspy / wpaspy.c
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 }