~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/utils/eloop.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Event loop based on select() loop
3
 
 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 2 as
7
 
 * published by the Free Software Foundation.
8
 
 *
9
 
 * Alternatively, this software may be distributed under the terms of BSD
10
 
 * license.
11
 
 *
12
 
 * See README and COPYING for more details.
13
 
 */
14
 
 
15
 
#include "includes.h"
16
 
 
17
 
#include "common.h"
18
 
#include "eloop.h"
19
 
 
20
 
 
21
 
struct eloop_sock {
22
 
        int sock;
23
 
        void *eloop_data;
24
 
        void *user_data;
25
 
        eloop_sock_handler handler;
26
 
};
27
 
 
28
 
struct eloop_timeout {
29
 
        struct os_time time;
30
 
        void *eloop_data;
31
 
        void *user_data;
32
 
        eloop_timeout_handler handler;
33
 
        struct eloop_timeout *next;
34
 
};
35
 
 
36
 
struct eloop_signal {
37
 
        int sig;
38
 
        void *user_data;
39
 
        eloop_signal_handler handler;
40
 
        int signaled;
41
 
};
42
 
 
43
 
struct eloop_sock_table {
44
 
        int count;
45
 
        struct eloop_sock *table;
46
 
        int changed;
47
 
};
48
 
 
49
 
struct eloop_data {
50
 
        void *user_data;
51
 
 
52
 
        int max_sock;
53
 
 
54
 
        struct eloop_sock_table readers;
55
 
        struct eloop_sock_table writers;
56
 
        struct eloop_sock_table exceptions;
57
 
 
58
 
        struct eloop_timeout *timeout;
59
 
 
60
 
        int signal_count;
61
 
        struct eloop_signal *signals;
62
 
        int signaled;
63
 
        int pending_terminate;
64
 
 
65
 
        int terminate;
66
 
        int reader_table_changed;
67
 
};
68
 
 
69
 
static struct eloop_data eloop;
70
 
 
71
 
 
72
 
int eloop_init(void *user_data)
73
 
{
74
 
        os_memset(&eloop, 0, sizeof(eloop));
75
 
        eloop.user_data = user_data;
76
 
        return 0;
77
 
}
78
 
 
79
 
 
80
 
static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
81
 
                                     int sock, eloop_sock_handler handler,
82
 
                                     void *eloop_data, void *user_data)
83
 
{
84
 
        struct eloop_sock *tmp;
85
 
 
86
 
        if (table == NULL)
87
 
                return -1;
88
 
 
89
 
        tmp = (struct eloop_sock *)
90
 
                os_realloc(table->table,
91
 
                           (table->count + 1) * sizeof(struct eloop_sock));
92
 
        if (tmp == NULL)
93
 
                return -1;
94
 
 
95
 
        tmp[table->count].sock = sock;
96
 
        tmp[table->count].eloop_data = eloop_data;
97
 
        tmp[table->count].user_data = user_data;
98
 
        tmp[table->count].handler = handler;
99
 
        table->count++;
100
 
        table->table = tmp;
101
 
        if (sock > eloop.max_sock)
102
 
                eloop.max_sock = sock;
103
 
        table->changed = 1;
104
 
 
105
 
        return 0;
106
 
}
107
 
 
108
 
 
109
 
static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
110
 
                                         int sock)
111
 
{
112
 
        int i;
113
 
 
114
 
        if (table == NULL || table->table == NULL || table->count == 0)
115
 
                return;
116
 
 
117
 
        for (i = 0; i < table->count; i++) {
118
 
                if (table->table[i].sock == sock)
119
 
                        break;
120
 
        }
121
 
        if (i == table->count)
122
 
                return;
123
 
        if (i != table->count - 1) {
124
 
                os_memmove(&table->table[i], &table->table[i + 1],
125
 
                           (table->count - i - 1) *
126
 
                           sizeof(struct eloop_sock));
127
 
        }
128
 
        table->count--;
129
 
        table->changed = 1;
130
 
}
131
 
 
132
 
 
133
 
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
134
 
                                     fd_set *fds)
135
 
{
136
 
        int i;
137
 
 
138
 
        FD_ZERO(fds);
139
 
 
140
 
        if (table->table == NULL)
141
 
                return;
142
 
 
143
 
        for (i = 0; i < table->count; i++)
144
 
                FD_SET(table->table[i].sock, fds);
145
 
}
146
 
 
147
 
 
148
 
static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
149
 
                                      fd_set *fds)
150
 
{
151
 
        int i;
152
 
 
153
 
        if (table == NULL || table->table == NULL)
154
 
                return;
155
 
 
156
 
        table->changed = 0;
157
 
        for (i = 0; i < table->count; i++) {
158
 
                if (FD_ISSET(table->table[i].sock, fds)) {
159
 
                        table->table[i].handler(table->table[i].sock,
160
 
                                                table->table[i].eloop_data,
161
 
                                                table->table[i].user_data);
162
 
                        if (table->changed)
163
 
                                break;
164
 
                }
165
 
        }
166
 
}
167
 
 
168
 
 
169
 
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170
 
{
171
 
        if (table) {
172
 
                int i;
173
 
                for (i = 0; i < table->count && table->table; i++) {
174
 
                        printf("ELOOP: remaining socket: sock=%d "
175
 
                               "eloop_data=%p user_data=%p handler=%p\n",
176
 
                               table->table[i].sock,
177
 
                               table->table[i].eloop_data,
178
 
                               table->table[i].user_data,
179
 
                               table->table[i].handler);
180
 
                }
181
 
                os_free(table->table);
182
 
        }
183
 
}
184
 
 
185
 
 
186
 
int eloop_register_read_sock(int sock, eloop_sock_handler handler,
187
 
                             void *eloop_data, void *user_data)
188
 
{
189
 
        return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
190
 
                                   eloop_data, user_data);
191
 
}
192
 
 
193
 
 
194
 
void eloop_unregister_read_sock(int sock)
195
 
{
196
 
        eloop_unregister_sock(sock, EVENT_TYPE_READ);
197
 
}
198
 
 
199
 
 
200
 
static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
201
 
{
202
 
        switch (type) {
203
 
        case EVENT_TYPE_READ:
204
 
                return &eloop.readers;
205
 
        case EVENT_TYPE_WRITE:
206
 
                return &eloop.writers;
207
 
        case EVENT_TYPE_EXCEPTION:
208
 
                return &eloop.exceptions;
209
 
        }
210
 
 
211
 
        return NULL;
212
 
}
213
 
 
214
 
 
215
 
int eloop_register_sock(int sock, eloop_event_type type,
216
 
                        eloop_sock_handler handler,
217
 
                        void *eloop_data, void *user_data)
218
 
{
219
 
        struct eloop_sock_table *table;
220
 
 
221
 
        table = eloop_get_sock_table(type);
222
 
        return eloop_sock_table_add_sock(table, sock, handler,
223
 
                                         eloop_data, user_data);
224
 
}
225
 
 
226
 
 
227
 
void eloop_unregister_sock(int sock, eloop_event_type type)
228
 
{
229
 
        struct eloop_sock_table *table;
230
 
 
231
 
        table = eloop_get_sock_table(type);
232
 
        eloop_sock_table_remove_sock(table, sock);
233
 
}
234
 
 
235
 
 
236
 
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
237
 
                           eloop_timeout_handler handler,
238
 
                           void *eloop_data, void *user_data)
239
 
{
240
 
        struct eloop_timeout *timeout, *tmp, *prev;
241
 
 
242
 
        timeout = os_malloc(sizeof(*timeout));
243
 
        if (timeout == NULL)
244
 
                return -1;
245
 
        os_get_time(&timeout->time);
246
 
        timeout->time.sec += secs;
247
 
        timeout->time.usec += usecs;
248
 
        while (timeout->time.usec >= 1000000) {
249
 
                timeout->time.sec++;
250
 
                timeout->time.usec -= 1000000;
251
 
        }
252
 
        timeout->eloop_data = eloop_data;
253
 
        timeout->user_data = user_data;
254
 
        timeout->handler = handler;
255
 
        timeout->next = NULL;
256
 
 
257
 
        if (eloop.timeout == NULL) {
258
 
                eloop.timeout = timeout;
259
 
                return 0;
260
 
        }
261
 
 
262
 
        prev = NULL;
263
 
        tmp = eloop.timeout;
264
 
        while (tmp != NULL) {
265
 
                if (os_time_before(&timeout->time, &tmp->time))
266
 
                        break;
267
 
                prev = tmp;
268
 
                tmp = tmp->next;
269
 
        }
270
 
 
271
 
        if (prev == NULL) {
272
 
                timeout->next = eloop.timeout;
273
 
                eloop.timeout = timeout;
274
 
        } else {
275
 
                timeout->next = prev->next;
276
 
                prev->next = timeout;
277
 
        }
278
 
 
279
 
        return 0;
280
 
}
281
 
 
282
 
 
283
 
int eloop_cancel_timeout(eloop_timeout_handler handler,
284
 
                         void *eloop_data, void *user_data)
285
 
{
286
 
        struct eloop_timeout *timeout, *prev, *next;
287
 
        int removed = 0;
288
 
 
289
 
        prev = NULL;
290
 
        timeout = eloop.timeout;
291
 
        while (timeout != NULL) {
292
 
                next = timeout->next;
293
 
 
294
 
                if (timeout->handler == handler &&
295
 
                    (timeout->eloop_data == eloop_data ||
296
 
                     eloop_data == ELOOP_ALL_CTX) &&
297
 
                    (timeout->user_data == user_data ||
298
 
                     user_data == ELOOP_ALL_CTX)) {
299
 
                        if (prev == NULL)
300
 
                                eloop.timeout = next;
301
 
                        else
302
 
                                prev->next = next;
303
 
                        os_free(timeout);
304
 
                        removed++;
305
 
                } else
306
 
                        prev = timeout;
307
 
 
308
 
                timeout = next;
309
 
        }
310
 
 
311
 
        return removed;
312
 
}
313
 
 
314
 
 
315
 
#ifndef CONFIG_NATIVE_WINDOWS
316
 
static void eloop_handle_alarm(int sig)
317
 
{
318
 
        fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
319
 
                "seconds. Looks like there\n"
320
 
                "is a bug that ends up in a busy loop that "
321
 
                "prevents clean shutdown.\n"
322
 
                "Killing program forcefully.\n");
323
 
        exit(1);
324
 
}
325
 
#endif /* CONFIG_NATIVE_WINDOWS */
326
 
 
327
 
 
328
 
static void eloop_handle_signal(int sig)
329
 
{
330
 
        int i;
331
 
 
332
 
#ifndef CONFIG_NATIVE_WINDOWS
333
 
        if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
334
 
                /* Use SIGALRM to break out from potential busy loops that
335
 
                 * would not allow the program to be killed. */
336
 
                eloop.pending_terminate = 1;
337
 
                signal(SIGALRM, eloop_handle_alarm);
338
 
                alarm(2);
339
 
        }
340
 
#endif /* CONFIG_NATIVE_WINDOWS */
341
 
 
342
 
        eloop.signaled++;
343
 
        for (i = 0; i < eloop.signal_count; i++) {
344
 
                if (eloop.signals[i].sig == sig) {
345
 
                        eloop.signals[i].signaled++;
346
 
                        break;
347
 
                }
348
 
        }
349
 
}
350
 
 
351
 
 
352
 
static void eloop_process_pending_signals(void)
353
 
{
354
 
        int i;
355
 
 
356
 
        if (eloop.signaled == 0)
357
 
                return;
358
 
        eloop.signaled = 0;
359
 
 
360
 
        if (eloop.pending_terminate) {
361
 
#ifndef CONFIG_NATIVE_WINDOWS
362
 
                alarm(0);
363
 
#endif /* CONFIG_NATIVE_WINDOWS */
364
 
                eloop.pending_terminate = 0;
365
 
        }
366
 
 
367
 
        for (i = 0; i < eloop.signal_count; i++) {
368
 
                if (eloop.signals[i].signaled) {
369
 
                        eloop.signals[i].signaled = 0;
370
 
                        eloop.signals[i].handler(eloop.signals[i].sig,
371
 
                                                 eloop.user_data,
372
 
                                                 eloop.signals[i].user_data);
373
 
                }
374
 
        }
375
 
}
376
 
 
377
 
 
378
 
int eloop_register_signal(int sig, eloop_signal_handler handler,
379
 
                          void *user_data)
380
 
{
381
 
        struct eloop_signal *tmp;
382
 
 
383
 
        tmp = (struct eloop_signal *)
384
 
                os_realloc(eloop.signals,
385
 
                           (eloop.signal_count + 1) *
386
 
                           sizeof(struct eloop_signal));
387
 
        if (tmp == NULL)
388
 
                return -1;
389
 
 
390
 
        tmp[eloop.signal_count].sig = sig;
391
 
        tmp[eloop.signal_count].user_data = user_data;
392
 
        tmp[eloop.signal_count].handler = handler;
393
 
        tmp[eloop.signal_count].signaled = 0;
394
 
        eloop.signal_count++;
395
 
        eloop.signals = tmp;
396
 
        signal(sig, eloop_handle_signal);
397
 
 
398
 
        return 0;
399
 
}
400
 
 
401
 
 
402
 
int eloop_register_signal_terminate(eloop_signal_handler handler,
403
 
                                    void *user_data)
404
 
{
405
 
        int ret = eloop_register_signal(SIGINT, handler, user_data);
406
 
        if (ret == 0)
407
 
                ret = eloop_register_signal(SIGTERM, handler, user_data);
408
 
        return ret;
409
 
}
410
 
 
411
 
 
412
 
int eloop_register_signal_reconfig(eloop_signal_handler handler,
413
 
                                   void *user_data)
414
 
{
415
 
#ifdef CONFIG_NATIVE_WINDOWS
416
 
        return 0;
417
 
#else /* CONFIG_NATIVE_WINDOWS */
418
 
        return eloop_register_signal(SIGHUP, handler, user_data);
419
 
#endif /* CONFIG_NATIVE_WINDOWS */
420
 
}
421
 
 
422
 
 
423
 
void eloop_run(void)
424
 
{
425
 
        fd_set *rfds, *wfds, *efds;
426
 
        int res;
427
 
        struct timeval _tv;
428
 
        struct os_time tv, now;
429
 
 
430
 
        rfds = os_malloc(sizeof(*rfds));
431
 
        wfds = os_malloc(sizeof(*wfds));
432
 
        efds = os_malloc(sizeof(*efds));
433
 
        if (rfds == NULL || wfds == NULL || efds == NULL) {
434
 
                printf("eloop_run - malloc failed\n");
435
 
                goto out;
436
 
        }
437
 
 
438
 
        while (!eloop.terminate &&
439
 
               (eloop.timeout || eloop.readers.count > 0 ||
440
 
                eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
441
 
                if (eloop.timeout) {
442
 
                        os_get_time(&now);
443
 
                        if (os_time_before(&now, &eloop.timeout->time))
444
 
                                os_time_sub(&eloop.timeout->time, &now, &tv);
445
 
                        else
446
 
                                tv.sec = tv.usec = 0;
447
 
#if 0
448
 
                        printf("next timeout in %lu.%06lu sec\n",
449
 
                               tv.sec, tv.usec);
450
 
#endif
451
 
                        _tv.tv_sec = tv.sec;
452
 
                        _tv.tv_usec = tv.usec;
453
 
                }
454
 
 
455
 
                eloop_sock_table_set_fds(&eloop.readers, rfds);
456
 
                eloop_sock_table_set_fds(&eloop.writers, wfds);
457
 
                eloop_sock_table_set_fds(&eloop.exceptions, efds);
458
 
                res = select(eloop.max_sock + 1, rfds, wfds, efds,
459
 
                             eloop.timeout ? &_tv : NULL);
460
 
                if (res < 0 && errno != EINTR && errno != 0) {
461
 
                        perror("select");
462
 
                        goto out;
463
 
                }
464
 
                eloop_process_pending_signals();
465
 
 
466
 
                /* check if some registered timeouts have occurred */
467
 
                if (eloop.timeout) {
468
 
                        struct eloop_timeout *tmp;
469
 
 
470
 
                        os_get_time(&now);
471
 
                        if (!os_time_before(&now, &eloop.timeout->time)) {
472
 
                                tmp = eloop.timeout;
473
 
                                eloop.timeout = eloop.timeout->next;
474
 
                                tmp->handler(tmp->eloop_data,
475
 
                                             tmp->user_data);
476
 
                                os_free(tmp);
477
 
                        }
478
 
 
479
 
                }
480
 
 
481
 
                if (res <= 0)
482
 
                        continue;
483
 
 
484
 
                eloop_sock_table_dispatch(&eloop.readers, rfds);
485
 
                eloop_sock_table_dispatch(&eloop.writers, wfds);
486
 
                eloop_sock_table_dispatch(&eloop.exceptions, efds);
487
 
        }
488
 
 
489
 
out:
490
 
        os_free(rfds);
491
 
        os_free(wfds);
492
 
        os_free(efds);
493
 
}
494
 
 
495
 
 
496
 
void eloop_terminate(void)
497
 
{
498
 
        eloop.terminate = 1;
499
 
}
500
 
 
501
 
 
502
 
void eloop_destroy(void)
503
 
{
504
 
        struct eloop_timeout *timeout, *prev;
505
 
        struct os_time now;
506
 
 
507
 
        timeout = eloop.timeout;
508
 
        if (timeout)
509
 
                os_get_time(&now);
510
 
        while (timeout != NULL) {
511
 
                int sec, usec;
512
 
                prev = timeout;
513
 
                timeout = timeout->next;
514
 
                sec = prev->time.sec - now.sec;
515
 
                usec = prev->time.usec - now.usec;
516
 
                if (prev->time.usec < now.usec) {
517
 
                        sec--;
518
 
                        usec += 1000000;
519
 
                }
520
 
                printf("ELOOP: remaining timeout: %d.%06d eloop_data=%p "
521
 
                       "user_data=%p handler=%p\n",
522
 
                       sec, usec, prev->eloop_data, prev->user_data,
523
 
                       prev->handler);
524
 
                os_free(prev);
525
 
        }
526
 
        eloop_sock_table_destroy(&eloop.readers);
527
 
        eloop_sock_table_destroy(&eloop.writers);
528
 
        eloop_sock_table_destroy(&eloop.exceptions);
529
 
        os_free(eloop.signals);
530
 
}
531
 
 
532
 
 
533
 
int eloop_terminated(void)
534
 
{
535
 
        return eloop.terminate;
536
 
}
537
 
 
538
 
 
539
 
void eloop_wait_for_read_sock(int sock)
540
 
{
541
 
        fd_set rfds;
542
 
 
543
 
        if (sock < 0)
544
 
                return;
545
 
 
546
 
        FD_ZERO(&rfds);
547
 
        FD_SET(sock, &rfds);
548
 
        select(sock + 1, &rfds, NULL, NULL, NULL);
549
 
}
550
 
 
551
 
 
552
 
void * eloop_get_user_data(void)
553
 
{
554
 
        return eloop.user_data;
555
 
}