BUGFIX : move upwards type definitions to avoid compilation errors
[wifihood] / wifiscand / wifiscand.c
1
2 #include <iwlib.h>
3
4 #ifdef HAVE_LIBOSSO
5 #include <libosso.h>
6 #else
7 #include <glib.h>
8 #include <dbus/dbus.h>
9
10 #define OSSO_OK 0
11 #define OSSO_ERROR 1
12
13 #define osso_context_t DBusConnection
14 typedef struct osso_rpc_t_values {
15   int i;
16   char *s;
17   } osso_rpc_t_values;
18 typedef struct osso_rpc_t {
19   int type;
20   osso_rpc_t_values value;
21   } osso_rpc_t;
22 #endif
23
24 #define WIFISCAND_VERSION_STRING  "1.1"
25
26 #define OSSO_NAME    "wifiscan"
27 #define OSSO_SERVICE "org.javiplx."OSSO_NAME
28 #define OSSO_OBJECT  "/org/javiplx/"OSSO_NAME
29 #define OSSO_IFACE   "org.javiplx."OSSO_NAME
30
31
32 typedef struct {
33         char          mac[18];
34         int           rssi;
35         int           noise;
36 } ScanInfo;
37
38
39 /* --------------------------------------------------------------------------- WirelessInterface */
40 typedef struct {
41         wireless_info info;
42         char*         ifname;
43         int           sock;
44 } WirelessInterface;
45
46 /* ------------------------------------------------------------------ WirelessInterface_ScanItem */
47
48 static int WirelessInterface_ScanItem(struct iw_event* event, ScanInfo **scaninfo) {
49
50         switch(event->cmd) {
51                                   
52                 case SIOCGIWAP: {
53
54                         *scaninfo = (ScanInfo*) malloc( sizeof(ScanInfo) );
55                         memset(*scaninfo, 0, sizeof(ScanInfo) );
56
57                         iw_ether_ntop( (const struct ether_addr*)(event->u.ap_addr.sa_data), (*scaninfo)->mac);
58                         return 1;
59                 }
60
61                 case IWEVQUAL: {
62                         (*scaninfo)->rssi = event->u.qual.level - 0x100;
63                         return 0;
64                 }
65
66                 default: {
67                          return 0;
68                  }
69         }
70 }
71
72 /* ---------------------------------------------------------------------- */
73
74 void* makeScan(WirelessInterface* coso, gchar *message) {
75         struct iwreq          wrq;
76         unsigned char* buffer     = NULL;
77         int            buflen     = IW_SCAN_MAX_DATA;
78         iwrange        range;
79         int            has_range;
80         struct timeval        tv;
81         int            timeout    = 10000000;
82
83         ScanInfo        **scan = NULL;
84
85         has_range = (iw_get_range_info(coso->sock, coso->ifname, &range) >= 0);
86
87         tv.tv_sec          = 0;
88         tv.tv_usec         = 250000;
89         wrq.u.data.pointer = NULL;
90         wrq.u.data.flags   = 0;
91         wrq.u.data.length  = 0;
92
93         if(iw_set_ext(coso->sock, coso->ifname, SIOCSIWSCAN, &wrq) < 0) {
94                 if(errno != EPERM) {
95                         message = "Interface doesn't support scanning";
96                         return NULL;
97                 }
98                 tv.tv_usec = 0;
99         }
100         timeout -= tv.tv_usec;
101
102         while(1) {
103                 fd_set rfds;
104                 int    last_fd;
105                 int    ret;
106
107                 FD_ZERO(&rfds);
108                 last_fd = -1;
109
110                 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
111
112                 if(ret < 0) {
113                         if(errno == EAGAIN || errno == EINTR) continue;
114                         
115                         else {
116                                 message = "Unknown scanning error";
117                                 return NULL;
118                         }
119                 }
120
121                 if(!ret) {
122                         unsigned char* newbuf;
123
124                         realloc:
125                         newbuf = (unsigned char*) realloc(buffer, buflen);
126                         
127                         if(!newbuf) {
128                                 if(buffer) free(buffer);
129                                 message = "Memory allocation failure in scan";
130                                 return NULL;
131                         }
132                         
133                         buffer = newbuf;
134
135                         wrq.u.data.pointer = buffer;
136                         wrq.u.data.flags   = 0;
137                         wrq.u.data.length  = buflen;
138                         
139                         if(iw_get_ext(coso->sock, coso->ifname, SIOCGIWSCAN, &wrq) < 0) {
140                                 if((errno == E2BIG)) {
141                                         if(wrq.u.data.length > buflen) buflen = wrq.u.data.length;
142                                         else buflen *= 2;
143
144                                         goto realloc;
145                                 }
146
147                                 if(errno == EAGAIN) {
148                                         tv.tv_sec   = 0;
149                                         tv.tv_usec  = 100000;
150                                         timeout    -= tv.tv_usec;
151                                         
152                                         if(timeout > 0) continue;
153                                 }
154
155                                 free(buffer);
156                                 
157                                 message = "Unable to read scan data";
158
159                                 return NULL;
160                         }
161                         
162                         else break;
163                 }
164         }
165
166
167         if(wrq.u.data.length)   {
168                 struct iw_event      iwe;
169                 stream_descr stream;
170                 int          ret;
171                 void*    scan_dict = NULL;
172                 
173                 iw_init_event_stream(&stream, (char*)(buffer), wrq.u.data.length);
174                 
175                 scan = (ScanInfo**) malloc( 25 * sizeof(ScanInfo *) );
176                 memset(scan, 0, 25 * sizeof(ScanInfo *) );
177                 *scan = NULL;
178                 int i;
179                 for (i=0; i<25; i++) *(scan+i) = NULL;
180
181                 i = 0;
182                 ScanInfo *sc = NULL;
183                 do {
184                         ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
185                 
186                         if(ret > 0) {
187                                 int sr = WirelessInterface_ScanItem(&iwe, &sc);
188                                 if(sr && i<25) {
189                                         *(scan+i) = sc;
190                                         i++;
191                                 }
192                         }
193                 }
194                 
195                 while(ret > 0);
196
197         } else {
198                 message = "Unknown error";
199                 free(buffer);
200                 return NULL;
201         }
202
203         free(buffer);
204         return scan;
205 }
206
207 static void refresh(WirelessInterface* coso) {
208         struct iwreq wrq;
209         
210         iw_get_basic_config(coso->sock, coso->ifname, &(coso->info.b));
211         iw_get_range_info(coso->sock, coso->ifname, &(coso->info.range));
212
213         iw_get_ext(coso->sock, coso->ifname, SIOCGIWRATE, &wrq);
214         memcpy(&(coso->info.bitrate), &wrq.u.bitrate, sizeof(iwparam));
215
216         iw_get_ext(coso->sock, coso->ifname, SIOCGIWAP, &wrq);
217         memcpy(&(coso->info.ap_addr), &wrq.u.ap_addr, sizeof (sockaddr));
218
219         iw_get_stats(
220                 coso->sock, coso->ifname, &(coso->info.stats), 
221                 &(coso->info.range), coso->info.has_range
222         );
223 }
224
225 /* Application UI data struct */
226 typedef struct _AppData AppData;
227 struct _AppData {
228     WirelessInterface iface;
229     osso_context_t *osso_context;
230 };
231
232 #ifdef HAVE_LIBOSSO
233 static GMainLoop *event_loop = NULL;
234 #endif
235 static short int start_flags = 0;
236
237 /* Callback for normal D-BUS messages */
238 gint dbus_req_handler(const gchar * interface, const gchar * method,
239                       GArray * arguments, gpointer data,
240                       osso_rpc_t * retval)
241 {
242     AppData *appdata;
243     appdata = (AppData *) data;
244
245     retval->type = DBUS_TYPE_STRING;
246     retval->value.s = (gchar*) malloc( sizeof(gchar *) );
247     retval->value.s[0] = '\0';
248
249     if ( strcmp(method,"wakeup")==0 ) {
250         retval->value.s = (gchar *) realloc(retval->value.s,16*sizeof(gchar *));
251         snprintf(retval->value.s,16,"WifiScand ready");
252         return OSSO_OK;
253     }
254
255     if ( strcmp(method,"start")==0 ) {
256
257         if( (appdata->iface.sock=iw_sockets_open()) < 0) {
258             retval->value.s = (gchar *) realloc(retval->value.s,33*sizeof(gchar *));
259             snprintf(retval->value.s,33,"Failure in socket initialization");
260             return OSSO_ERROR;
261         }
262
263         struct ifreq frq;
264         strncpy(frq.ifr_name, appdata->iface.ifname, IFNAMSIZ);
265         if(ioctl(appdata->iface.sock, SIOCGIFFLAGS, &frq)) {
266             retval->value.s = (gchar *) realloc(retval->value.s,28*sizeof(gchar *));
267             snprintf(retval->value.s,28,"Cannot get interface status");
268             return OSSO_ERROR;
269         }
270
271         start_flags = frq.ifr_flags;
272         frq.ifr_flags |= IFF_UP | IFF_RUNNING;
273
274         if(ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq)) {
275             retval->value.s = (gchar *) realloc(retval->value.s,27*sizeof(gchar *));
276             snprintf(retval->value.s,27,"Cannot set interface state");
277             return OSSO_ERROR;
278         }
279
280         refresh(&appdata->iface);
281         retval->value.s = (gchar *) realloc(retval->value.s,22*sizeof(gchar *));
282         snprintf(retval->value.s,22,"Interface initialized");
283         return OSSO_OK;
284     }
285
286     if ( strcmp(method,"stop")==0 ) {
287         struct ifreq frq;
288         strncpy(frq.ifr_name, appdata->iface.ifname, IFNAMSIZ);
289         if(!ioctl(appdata->iface.sock, SIOCGIFFLAGS, &frq)) {
290             frq.ifr_flags = start_flags;
291             if(!ioctl(appdata->iface.sock, SIOCSIFFLAGS, &frq))
292                 refresh(&appdata->iface);
293         }
294         iw_sockets_close(appdata->iface.sock);
295         appdata->iface.sock = 0;
296 #ifdef HAVE_LIBOSSO
297         osso_deinitialize(appdata->osso_context);
298 #else
299         dbus_deinitialize(appdata->osso_context);
300 #endif
301         /* Instead of exiting, signaling finish to main loop could be better
302         retval->value.s = (gchar *) realloc(retval->value.s,34*sizeof(gchar *));
303         snprintf(retval->value.s,34,"Interface moved to original state");
304         */
305         exit(0);
306     }
307
308     if ( strcmp(method,"scan")==0 ) {
309
310         ScanInfo **scan = (ScanInfo **) makeScan(&appdata->iface,retval->value.s);
311         if(scan == NULL) {
312             retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
313             snprintf(retval->value.s,64,"ERROR");
314             return OSSO_ERROR;
315         }
316
317         int i;
318         for (i=0; i<25&&*(scan+i)!=NULL; i++) {
319             ScanInfo* sc = *(scan+i);
320             retval->value.s = (gchar *) realloc(retval->value.s,23*(i+1)*sizeof(gchar *));
321             if ( retval->value.s == NULL ) {
322                 retval->value.s = "Error allocating memory";
323                 return OSSO_ERROR;
324             }
325             sprintf(retval->value.s+strlen(retval->value.s),"%s:%d ",sc->mac,sc->rssi);
326         }
327
328         retval->value.s[strlen(retval->value.s)-1]  = '\0';
329         return OSSO_OK;
330     }
331
332     retval->value.s = (gchar *) realloc(retval->value.s,64*sizeof(gchar *));
333     snprintf(retval->value.s,64,"Unknown method");
334     return OSSO_ERROR;
335 }
336
337 #ifndef HAVE_LIBOSSO
338 static DBusObjectPathVTable *vtable = NULL;
339
340 int dbus_set_cb_f( DBusConnection *context,
341                 const char *service, const char *object,
342                 const char *interface, void *handler, // FIXME : Set proper type for handler
343                 void *user_data) {
344
345         /* First, we prepare the complex dbus handler structures */
346         DBusObjectPathVTable *vtable = malloc( sizeof(DBusObjectPathVTable) );
347         memset(vtable , '\0', sizeof(DBusObjectPathVTable) );
348         vtable->message_function = (DBusObjectPathMessageFunction) handler; // FIXME : Aqui va el nuevo handler/wrapper
349
350         if (!dbus_connection_register_fallback(context, object, vtable, user_data)) {
351                 return OSSO_ERROR;
352                 }
353
354         DBusError error;
355         dbus_error_init(&error);
356
357         dbus_bus_request_name (context, service, 0, &error);
358         if ( dbus_error_is_set(&error) ) {
359                 dbus_error_free (&error);
360                 return OSSO_ERROR;
361                 }
362
363         dbus_error_free (&error);
364         return OSSO_OK;
365 }
366
367 void dbus_deinitialize( DBusConnection *context ) {
368         free(vtable); vtable = NULL;
369         dbus_connection_unref(context);
370         dbus_shutdown();
371 }
372
373 static DBusHandlerResult handler_wrapper (DBusConnection  *connection,
374                    DBusMessage     *message,
375                    void            *data) {
376
377         gint retcode;
378         osso_rpc_t *retval = malloc(sizeof(osso_rpc_t));
379
380         if ( dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ) {
381                 retcode = dbus_req_handler(dbus_message_get_interface(message),
382                                 dbus_message_get_member(message),
383                                 NULL, data, retval);
384
385                 if ( retval->value.s != NULL ) {
386                         DBusMessage *reply = dbus_message_new_method_return (message);
387                         if (reply == NULL)
388                                 exit(0);
389                         if (!dbus_message_append_args (reply, DBUS_TYPE_STRING, &retval->value.s, DBUS_TYPE_INVALID))
390                                 exit(0);
391                         if (!dbus_connection_send (connection, reply, NULL))
392                                 exit(0);
393                         dbus_message_unref (reply);
394                         }
395
396                 }
397
398         return DBUS_HANDLER_RESULT_HANDLED;
399 }
400
401 #endif
402
403 int main( void ) {
404
405         osso_context_t *osso_context;
406 #ifndef HAVE_LIBOSSO
407         DBusError error;
408 #endif
409
410         /* Initialize maemo application */
411 #ifdef HAVE_LIBOSSO
412         osso_context = osso_initialize(OSSO_NAME, WIFISCAND_VERSION_STRING, TRUE, NULL);
413 #else
414         dbus_error_init(&error);
415         osso_context = dbus_bus_get(DBUS_BUS_STARTER, &error);
416 #endif
417
418         /* Check that initialization was ok */
419         if (osso_context == NULL) {
420 #ifndef HAVE_LIBOSSO
421                 fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", error.message);
422                 dbus_error_free (&error);
423 #endif
424                 exit(OSSO_ERROR);
425                 }
426
427         /* Create AppData */
428         AppData *appdata;
429         appdata = g_new0(AppData, 1);
430         appdata->osso_context = osso_context;
431
432         memset(&(appdata->iface.info), 0, sizeof(wireless_info));
433         appdata->iface.ifname = "wlan0";
434         appdata->iface.sock   = 0;
435
436         /* Add handler for hello D-BUS messages */
437 #ifdef HAVE_LIBOSSO
438         osso_return_t result = osso_rpc_set_cb_f(osso_context, OSSO_SERVICE, OSSO_OBJECT, OSSO_IFACE, dbus_req_handler, appdata);
439 #else
440         int result = dbus_set_cb_f(osso_context, OSSO_SERVICE, OSSO_OBJECT, OSSO_IFACE, handler_wrapper, appdata);
441 #endif
442
443         if (result != OSSO_OK) {
444 #ifdef HAVE_LIBOSSO
445                 osso_system_note_infoprint(appdata->osso_context, "Failure while setting OSSO callback", NULL);
446 #endif
447                 return OSSO_ERROR;
448         }
449
450         /* INITIALIZATION FINISH */
451
452 #ifdef HAVE_LIBOSSO
453         event_loop = g_main_loop_new(NULL, FALSE);
454         g_main_loop_run(event_loop);
455 #else
456         while (dbus_connection_read_write_dispatch (osso_context, -1)) {}
457 #endif
458
459         /* Deinitialize OSSO */
460 #ifdef HAVE_LIBOSSO
461         osso_deinitialize(osso_context);
462 #else
463         dbus_deinitialize(osso_context);
464 #endif
465
466         exit(0);
467 }
468