1 | /* |
1 | /* |
2 | * select.C: select(2) socket engine. |
2 | * select.C: select(2) socket engine. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
4 | * |
4 | * |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
6 | */ |
6 | */ |
7 | |
7 | |
8 | static char const rcsid[] = "$Id: select.C,v 1.3 2007/07/21 13:23:22 pippijn Exp $"; |
8 | static char const rcsid[] = "$Id: select.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $"; |
9 | |
9 | |
10 | #include "atheme.h" |
10 | #include "atheme.h" |
11 | #include "internal.h" |
11 | #include "internal.h" |
|
|
12 | #include "datastream.h" |
12 | |
13 | |
13 | extern list_t connection_list; /* this lives in connection.c */ |
|
|
14 | fd_set readfds, writefds; |
14 | fd_set readfds, writefds; |
15 | |
15 | |
16 | /* |
16 | /* |
17 | * init_socket_queues() |
17 | * init_socket_queues() |
18 | * |
18 | * |
… | |
… | |
44 | * registered sockets are prepared for the select() loop. |
44 | * registered sockets are prepared for the select() loop. |
45 | */ |
45 | */ |
46 | static void |
46 | static void |
47 | update_select_sets (void) |
47 | update_select_sets (void) |
48 | { |
48 | { |
49 | node_t *n; |
49 | connection_vector::iterator it = connlist.begin (); |
|
|
50 | connection_vector::iterator et = connlist.end (); |
50 | connection_t *cptr; |
51 | connection_t *cptr; |
51 | |
52 | |
52 | FD_ZERO (&readfds); |
53 | FD_ZERO (&readfds); |
53 | FD_ZERO (&writefds); |
54 | FD_ZERO (&writefds); |
54 | |
55 | |
55 | LIST_FOREACH (n, connection_list.head) |
56 | while (it != et) |
56 | { |
57 | { |
57 | cptr = n->data; |
58 | cptr = *it; |
|
|
59 | |
|
|
60 | if (CF_IS_CONNECTING (cptr)) |
|
|
61 | FD_SET (cptr->fd, &writefds); |
|
|
62 | |
|
|
63 | else if (CF_IS_LISTENING (cptr)) |
|
|
64 | FD_SET (cptr->fd, &readfds); |
58 | |
65 | |
59 | if (CF_IS_CONNECTING (cptr)) |
66 | if (sendq_nonempty (cptr)) |
60 | FD_SET (cptr->fd, &writefds); |
67 | FD_SET (cptr->fd, &writefds); |
|
|
68 | |
|
|
69 | else |
|
|
70 | FD_SET (cptr->fd, &readfds); |
61 | |
71 | |
62 | else if (CF_IS_LISTENING (cptr)) |
72 | ++it; |
63 | FD_SET (cptr->fd, &readfds); |
|
|
64 | |
|
|
65 | if (sendq_nonempty (cptr)) |
|
|
66 | FD_SET (cptr->fd, &writefds); |
|
|
67 | |
|
|
68 | else |
|
|
69 | FD_SET (cptr->fd, &readfds); |
|
|
70 | } |
73 | } |
71 | } |
74 | } |
72 | |
75 | |
73 | /* |
76 | /* |
74 | * connection_select() |
77 | * connection_select() |
75 | * |
78 | * |
… | |
… | |
84 | */ |
87 | */ |
85 | void |
88 | void |
86 | connection_select (time_t delay) |
89 | connection_select (time_t delay) |
87 | { |
90 | { |
88 | int sr; |
91 | int sr; |
89 | node_t *n, *tn; |
92 | connection_vector::iterator it = connlist.begin (); |
|
|
93 | connection_vector::iterator et = connlist.end (); |
90 | connection_t *cptr; |
94 | connection_t *cptr; |
91 | struct timeval to; |
95 | timeval to; |
92 | |
96 | |
93 | update_select_sets (); |
97 | update_select_sets (); |
94 | to.tv_sec = 0; |
98 | to.tv_sec = 0; |
95 | to.tv_usec = delay; |
99 | to.tv_usec = delay; |
96 | |
100 | |
97 | if ((sr = select (claro_state.maxfd + 1, &readfds, &writefds, NULL, &to)) > 0) |
101 | if ((sr = select (system_state.maxfd + 1, &readfds, &writefds, NULL, &to)) > 0) |
98 | { |
102 | { |
99 | /* Iterate twice, so we don't touch freed memory if |
103 | /* Iterate twice, so we don't touch freed memory if |
100 | * a connection is closed. |
104 | * a connection is closed. |
101 | * -- jilles */ |
105 | * -- jilles */ |
102 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
106 | while (it != et) |
103 | { |
107 | { |
104 | cptr = n->data; |
108 | cptr = *it; |
|
|
109 | |
|
|
110 | if (FD_ISSET (cptr->fd, &writefds)) |
|
|
111 | { |
|
|
112 | if (CF_IS_CONNECTING (cptr)) |
|
|
113 | cptr.callback.connected (cptr); |
|
|
114 | else |
|
|
115 | cptr->write_handler (cptr); |
|
|
116 | } |
105 | |
117 | |
106 | if (FD_ISSET (cptr->fd, &writefds)) |
118 | ++it; |
107 | { |
119 | } |
108 | if (CF_IS_CONNECTING (cptr)) |
|
|
109 | hook_call_event ("connected", cptr); |
|
|
110 | else |
|
|
111 | cptr->write_handler (cptr); |
|
|
112 | } |
|
|
113 | } |
120 | |
|
|
121 | for (it = connlist.begin (), et = connlist.end (); it != et; ++it) |
|
|
122 | { |
|
|
123 | cptr = *it; |
|
|
124 | |
|
|
125 | if (FD_ISSET (cptr->fd, &readfds)) |
|
|
126 | { |
|
|
127 | cptr->read_handler (cptr); |
|
|
128 | } |
|
|
129 | } |
114 | |
130 | |
115 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
131 | for (it = connlist.begin (), et = connlist.end (); it != et; ++it) |
116 | { |
132 | { |
117 | cptr = n->data; |
133 | cptr = *it; |
118 | |
134 | if (cptr->flags & CF_DEAD) |
119 | if (FD_ISSET (cptr->fd, &readfds)) |
135 | connection_close (cptr); |
120 | { |
|
|
121 | cptr->read_handler (cptr); |
|
|
122 | } |
|
|
123 | } |
136 | } |
124 | |
|
|
125 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
|
|
126 | { |
|
|
127 | cptr = n->data; |
|
|
128 | if (cptr->flags & CF_DEAD) |
|
|
129 | connection_close (cptr); |
|
|
130 | } |
|
|
131 | } |
137 | } |
132 | else |
138 | else |
133 | { |
139 | { |
134 | if (sr == 0) |
140 | if (sr == 0) |
135 | { |
141 | { |