1 | /* |
1 | /* |
2 | * poll.C: poll(2) socket engine. |
2 | * poll.C: poll(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: poll.C,v 1.3 2007/07/21 13:23:22 pippijn Exp $"; |
8 | static char const rcsid[] = "$Id: poll.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $"; |
9 | |
9 | |
10 | #include <sys/poll.h> |
10 | #include <sys/poll.h> |
11 | |
11 | |
12 | #include "atheme.h" |
12 | #include "atheme.h" |
13 | #include "internal.h" |
13 | #include "internal.h" |
14 | #include "datastream.h" |
14 | #include "datastream.h" |
15 | |
|
|
16 | extern list_t connection_list; /* this lives in connection.c */ |
|
|
17 | |
15 | |
18 | /* |
16 | /* |
19 | * linux does not provide POLLWRNORM by default, and we're not _XOPEN_SOURCE. |
17 | * linux does not provide POLLWRNORM by default, and we're not _XOPEN_SOURCE. |
20 | * so.... we have to do this crap below. |
18 | * so.... we have to do this crap below. |
21 | */ |
19 | */ |
… | |
… | |
24 | #endif |
22 | #endif |
25 | #ifndef POLLWRNORM |
23 | #ifndef POLLWRNORM |
26 | #define POLLWRNORM POLLOUT |
24 | #define POLLWRNORM POLLOUT |
27 | #endif |
25 | #endif |
28 | |
26 | |
29 | struct pollfd pollfds[FD_SETSIZE]; /* XXX We need a define indicating MAXCONN. */ |
27 | pollfd pollfds[FD_SETSIZE]; /* XXX We need a define indicating MAXCONN. */ |
30 | |
28 | |
31 | /* |
29 | /* |
32 | * init_socket_queues() |
30 | * init_socket_queues() |
33 | * |
31 | * |
34 | * inputs: |
32 | * inputs: |
… | |
… | |
41 | * when using select, we don't need to do anything here. |
39 | * when using select, we don't need to do anything here. |
42 | */ |
40 | */ |
43 | void |
41 | void |
44 | init_socket_queues (void) |
42 | init_socket_queues (void) |
45 | { |
43 | { |
46 | memset (&pollfds, 0, sizeof (struct pollfd) * FD_SETSIZE); |
44 | memset (&pollfds, 0, sizeof (pollfd) * FD_SETSIZE); |
47 | } |
45 | } |
48 | |
46 | |
49 | /* |
47 | /* |
50 | * update_poll_fds() |
48 | * update_poll_fds() |
51 | * |
49 | * |
… | |
… | |
59 | * registered sockets are prepared for the poll() loop. |
57 | * registered sockets are prepared for the poll() loop. |
60 | */ |
58 | */ |
61 | static void |
59 | static void |
62 | update_poll_fds (void) |
60 | update_poll_fds (void) |
63 | { |
61 | { |
64 | node_t *n; |
62 | connection_vector::iterator it = connlist.begin (); |
65 | connection_t *cptr; |
63 | connection_vector::iterator et = connlist.end (); |
66 | int slot = 0; |
64 | int slot = 0; |
67 | |
65 | |
68 | LIST_FOREACH (n, connection_list.head) |
66 | while (it != et) |
69 | { |
67 | { |
70 | cptr = static_cast<connection_t *> (n->data); |
68 | connection_t *cptr = *it; |
71 | |
69 | |
72 | cptr->pollslot = slot; |
70 | cptr->pollslot = slot; |
73 | |
71 | |
74 | if (CF_IS_CONNECTING (cptr) || sendq_nonempty (cptr)) |
72 | if (CF_IS_CONNECTING (cptr) || sendq_nonempty (cptr)) |
75 | { |
73 | { |
76 | pollfds[slot].fd = cptr->fd; |
74 | pollfds[slot].fd = cptr->fd; |
77 | pollfds[slot].events |= POLLWRNORM; |
75 | pollfds[slot].events |= POLLWRNORM; |
78 | pollfds[slot].revents = 0; |
76 | pollfds[slot].revents = 0; |
79 | } |
77 | } |
80 | else |
78 | else |
81 | { |
79 | { |
82 | pollfds[slot].fd = cptr->fd; |
80 | pollfds[slot].fd = cptr->fd; |
83 | pollfds[slot].events |= POLLRDNORM; |
81 | pollfds[slot].events |= POLLRDNORM; |
84 | pollfds[slot].revents = 0; |
82 | pollfds[slot].revents = 0; |
85 | } |
83 | } |
86 | slot++; |
84 | slot++; |
|
|
85 | ++it; |
87 | } |
86 | } |
88 | } |
87 | } |
89 | |
88 | |
90 | /* |
89 | /* |
91 | * connection_select() |
90 | * connection_select() |
92 | * |
91 | * |
… | |
… | |
101 | */ |
100 | */ |
102 | void |
101 | void |
103 | connection_select (time_t delay) |
102 | connection_select (time_t delay) |
104 | { |
103 | { |
105 | int sr; |
104 | int sr; |
106 | node_t *n, *tn; |
105 | connection_vector::iterator it = connlist.begin (); |
107 | connection_t *cptr; |
106 | connection_vector::iterator et = connlist.end (); |
108 | int slot; |
107 | int slot; |
109 | |
108 | |
110 | update_poll_fds (); |
109 | update_poll_fds (); |
111 | |
110 | |
112 | if ((sr = poll (pollfds, connection_list.count, delay / 100)) > 0) |
111 | if ((sr = poll (pollfds, connlist.size (), delay / 100)) > 0) |
113 | { |
112 | { |
114 | /* Iterate twice, so we don't touch freed memory if |
113 | /* Iterate twice, so we don't touch freed memory if |
115 | * a connection is closed. |
114 | * a connection is closed. |
116 | * -- jilles */ |
115 | * -- jilles */ |
117 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
116 | while (it != et) |
118 | { |
117 | { |
119 | cptr = static_cast<connection_t *> (n->data); |
118 | connection_t *cptr = *it; |
|
|
119 | ++it; // increment here or continue will cause an endless loop |
120 | slot = cptr->pollslot; |
120 | slot = cptr->pollslot; |
121 | |
121 | |
122 | if (pollfds[slot].revents == 0) |
122 | if (pollfds[slot].revents == 0) |
123 | continue; |
123 | continue; |
124 | |
124 | |
125 | if (pollfds[slot].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) |
125 | if (pollfds[slot].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) |
126 | { |
126 | { |
127 | pollfds[slot].events &= ~(POLLRDNORM | POLLIN | POLLHUP | POLLERR); |
127 | pollfds[slot].events &= ~(POLLRDNORM | POLLIN | POLLHUP | POLLERR); |
128 | cptr->read_handler (cptr); |
128 | cptr->read_handler (cptr); |
129 | } |
129 | } |
|
|
130 | } |
130 | } |
131 | |
131 | |
132 | for (it = connlist.begin (), et = connlist.end (); it != et; ++it) |
132 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
|
|
133 | { |
133 | { |
134 | cptr = static_cast<connection_t *> (n->data); |
134 | connection_t *cptr = *it; |
135 | slot = cptr->pollslot; |
135 | slot = cptr->pollslot; |
136 | |
136 | |
137 | if (pollfds[slot].revents == 0) |
137 | if (pollfds[slot].revents == 0) |
138 | continue; |
138 | continue; |
139 | if (pollfds[slot].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) |
139 | if (pollfds[slot].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) |
140 | { |
140 | { |
141 | pollfds[slot].events &= ~(POLLWRNORM | POLLOUT | POLLHUP | POLLERR); |
141 | pollfds[slot].events &= ~(POLLWRNORM | POLLOUT | POLLHUP | POLLERR); |
142 | if (CF_IS_CONNECTING (cptr)) |
142 | if (CF_IS_CONNECTING (cptr)) |
143 | hook_call_event ("connected", cptr); |
143 | cptr->callback.connected (cptr); |
144 | else |
144 | else |
145 | cptr->write_handler (cptr); |
145 | cptr->write_handler (cptr); |
146 | } |
146 | } |
|
|
147 | } |
147 | } |
148 | |
148 | |
149 | for (it = connlist.begin (), et = connlist.end (); it != et; ++it) |
149 | LIST_FOREACH_SAFE (n, tn, connection_list.head) |
|
|
150 | { |
150 | { |
151 | cptr = static_cast<connection_t *> (n->data); |
151 | connection_t *cptr = *it; |
152 | if (cptr->flags & CF_DEAD) |
152 | if (cptr->flags & CF_DEAD) |
153 | connection_close (cptr); |
153 | connection_close (cptr); |
154 | } |
154 | } |
155 | } |
155 | } |
156 | } |
156 | } |
157 | |
|
|
158 | /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs |
|
|
159 | * vim:ts=8 |
|
|
160 | * vim:sw=8 |
|
|
161 | * vim:noexpandtab |
|
|
162 | */ |
|
|