1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
/* select() FD handling for GSM Daemon.
* (C) 2000-2006 by Harald Welte <laforge@gnumonks.org>
*
* Based on code originally written by myself for ulogd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <fcntl.h>
#include <common/linux_list.h>
#include "gsmd.h"
#include <gsmd/select.h>
static int maxfd = 0;
static LLIST_HEAD(gsmd_fds);
int gsmd_register_fd(struct gsmd_fd *fd)
{
int flags;
/* make FD nonblocking */
flags = fcntl(fd->fd, F_GETFL);
if (flags < 0)
return -1;
flags |= O_NONBLOCK;
flags = fcntl(fd->fd, F_SETFL, flags);
if (flags < 0)
return -1;
/* Register FD */
if (fd->fd > maxfd)
maxfd = fd->fd;
llist_add_tail(&fd->list, &gsmd_fds);
return 0;
}
void gsmd_unregister_fd(struct gsmd_fd *fd)
{
llist_del(&fd->list);
}
int gsmd_select_main()
{
struct gsmd_fd *ufd, *ufd2;
fd_set readset, writeset, exceptset;
int i;
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* prepare read and write fdsets */
llist_for_each_entry(ufd, &gsmd_fds, list) {
if (ufd->when & GSMD_FD_READ)
FD_SET(ufd->fd, &readset);
if (ufd->when & GSMD_FD_WRITE)
FD_SET(ufd->fd, &writeset);
if (ufd->when & GSMD_FD_EXCEPT)
FD_SET(ufd->fd, &exceptset);
}
i = select(maxfd+1, &readset, &writeset, &exceptset, NULL);
if (i > 0) {
/* call registered callback functions */
llist_for_each_entry_safe(ufd, ufd2, &gsmd_fds, list) {
int flags = 0;
if (FD_ISSET(ufd->fd, &readset))
flags |= GSMD_FD_READ;
if (FD_ISSET(ufd->fd, &writeset))
flags |= GSMD_FD_WRITE;
if (FD_ISSET(ufd->fd, &exceptset))
flags |= GSMD_FD_EXCEPT;
if (flags)
ufd->cb(ufd->fd, flags, ufd->data);
}
}
return i;
}
|