]>
Commit | Line | Data |
---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/common/socketevtdispatch.cpp | |
3 | // Purpose: implements wxSocketEventDispatcher for platforms with no | |
4 | // socket events notification | |
5 | // Author: Angel Vidal | |
6 | // Modified by: | |
7 | // Created: 08.24.06 | |
8 | // RCS-ID: $Id$ | |
9 | // Copyright: (c) 2006 Angel vidal | |
10 | // License: wxWindows licence | |
11 | /////////////////////////////////////////////////////////////////////////////// | |
12 | ||
13 | // ============================================================================ | |
14 | // declarations | |
15 | // ============================================================================ | |
16 | ||
17 | // ---------------------------------------------------------------------------- | |
18 | // headers | |
19 | // ---------------------------------------------------------------------------- | |
20 | ||
21 | // for compilers that support precompilation, includes "wx.h". | |
22 | #include "wx/wxprec.h" | |
23 | ||
24 | #if wxUSE_SOCKETS | |
25 | ||
26 | #include "wx/private/socketevtdispatch.h" | |
27 | #include "wx/module.h" | |
28 | #include "wx/unix/private.h" | |
29 | #include "wx/gsocket.h" | |
30 | #include "wx/unix/gsockunx.h" | |
31 | ||
32 | #ifndef WX_PRECOMP | |
33 | #include "wx/hash.h" | |
34 | #endif | |
35 | ||
36 | #include <sys/time.h> | |
37 | #include <unistd.h> | |
38 | ||
39 | #ifdef HAVE_SYS_SELECT_H | |
40 | # include <sys/select.h> | |
41 | #endif | |
42 | ||
43 | // ============================================================================ | |
44 | // implementation | |
45 | // ============================================================================ | |
46 | ||
47 | // ---------------------------------------------------------------------------- | |
48 | // wxSocketEventDispatcherEntry | |
49 | // ---------------------------------------------------------------------------- | |
50 | ||
51 | class wxSocketEventDispatcherEntry: public wxObject | |
52 | { | |
53 | public: | |
54 | wxSocketEventDispatcherEntry() | |
55 | { | |
56 | m_fdInput = -1; m_fdOutput = -1; | |
57 | m_socket = NULL; | |
58 | } | |
59 | ||
60 | int m_fdInput; | |
61 | int m_fdOutput; | |
62 | GSocket* m_socket; | |
63 | }; | |
64 | ||
65 | // ---------------------------------------------------------------------------- | |
66 | // wxSocketEventDispatcher | |
67 | // ---------------------------------------------------------------------------- | |
68 | ||
69 | wxSocketEventDispatcher* wxSocketEventDispatcher::ms_instance = NULL; | |
70 | ||
71 | /* static */ | |
72 | wxSocketEventDispatcher& wxSocketEventDispatcher::Get() | |
73 | { | |
74 | if ( !ms_instance ) | |
75 | ms_instance = new wxSocketEventDispatcher; | |
76 | return *ms_instance; | |
77 | } | |
78 | ||
79 | wxSocketEventDispatcherEntry* wxSocketEventDispatcher::FindEntry(int fd) | |
80 | { | |
81 | wxSocketEventDispatcherEntry* entry = | |
82 | (wxSocketEventDispatcherEntry*) wxHashTable::Get(fd); | |
83 | return entry; | |
84 | } | |
85 | ||
86 | void | |
87 | wxSocketEventDispatcher::RegisterCallback(int fd, | |
88 | wxSocketEventDispatcherType socketType, | |
89 | GSocket* socket) | |
90 | { | |
91 | wxSocketEventDispatcherEntry* entry = FindEntry(fd); | |
92 | if (!entry) | |
93 | { | |
94 | entry = new wxSocketEventDispatcherEntry(); | |
95 | Put(fd, entry); | |
96 | } | |
97 | ||
98 | if (socketType == wxSocketEventDispatcherInput) | |
99 | entry->m_fdInput = fd; | |
100 | else | |
101 | entry->m_fdOutput = fd; | |
102 | ||
103 | entry->m_socket = socket; | |
104 | } | |
105 | ||
106 | void | |
107 | wxSocketEventDispatcher::UnregisterCallback(int fd, | |
108 | wxSocketEventDispatcherType socketType) | |
109 | { | |
110 | wxSocketEventDispatcherEntry* entry = FindEntry(fd); | |
111 | if (entry) | |
112 | { | |
113 | if (socketType == wxSocketEventDispatcherInput) | |
114 | entry->m_fdInput = -1; | |
115 | else | |
116 | entry->m_fdOutput = -1; | |
117 | ||
118 | if (entry->m_fdInput == -1 && entry->m_fdOutput == -1) | |
119 | { | |
120 | entry->m_socket = NULL; | |
121 | Delete(fd); | |
122 | delete entry; | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | int wxSocketEventDispatcher::FillSets(fd_set* readset, fd_set* writeset) | |
128 | { | |
129 | int max_fd = 0; | |
130 | ||
131 | wxFD_ZERO(readset); | |
132 | wxFD_ZERO(writeset); | |
133 | ||
134 | BeginFind(); | |
135 | wxHashTable::compatibility_iterator node = Next(); | |
136 | while (node) | |
137 | { | |
138 | wxSocketEventDispatcherEntry* entry = | |
139 | (wxSocketEventDispatcherEntry*) node->GetData(); | |
140 | ||
141 | if (entry->m_fdInput != -1) | |
142 | { | |
143 | wxFD_SET(entry->m_fdInput, readset); | |
144 | if (entry->m_fdInput > max_fd) | |
145 | max_fd = entry->m_fdInput; | |
146 | } | |
147 | ||
148 | if (entry->m_fdOutput != -1) | |
149 | { | |
150 | wxFD_SET(entry->m_fdOutput, writeset); | |
151 | if (entry->m_fdOutput > max_fd) | |
152 | max_fd = entry->m_fdOutput; | |
153 | } | |
154 | ||
155 | node = Next(); | |
156 | } | |
157 | ||
158 | return max_fd; | |
159 | } | |
160 | ||
161 | void wxSocketEventDispatcher::AddEvents(fd_set* readset, fd_set* writeset) | |
162 | { | |
163 | BeginFind(); | |
164 | wxHashTable::compatibility_iterator node = Next(); | |
165 | while (node) | |
166 | { | |
167 | // We have to store the next node here, because the event processing can | |
168 | // destroy the object before we call Next() | |
169 | ||
170 | wxHashTable::compatibility_iterator next_node = Next(); | |
171 | ||
172 | wxSocketEventDispatcherEntry* entry = | |
173 | (wxSocketEventDispatcherEntry*) node->GetData(); | |
174 | ||
175 | wxCHECK_RET(entry->m_socket, wxT("Critical: Processing a NULL socket in wxSocketEventDispatcher")); | |
176 | ||
177 | if (entry->m_fdInput != -1 && wxFD_ISSET(entry->m_fdInput, readset)) | |
178 | entry->m_socket->Detected_Read(); | |
179 | ||
180 | if (entry->m_fdOutput != -1 && wxFD_ISSET(entry->m_fdOutput, writeset)) | |
181 | entry->m_socket->Detected_Write();; | |
182 | ||
183 | node = next_node; | |
184 | } | |
185 | } | |
186 | ||
187 | void wxSocketEventDispatcher::RunLoop(int timeout) | |
188 | { | |
189 | struct timeval tv; | |
190 | tv.tv_sec = 0; | |
191 | tv.tv_usec = timeout; | |
192 | fd_set readset; | |
193 | fd_set writeset; | |
194 | ||
195 | int max_fd = FillSets( &readset, &writeset); | |
196 | if (select( max_fd+1, &readset, &writeset, NULL, &tv ) == 0) | |
197 | { | |
198 | // No socket input/output. Don't add events. | |
199 | return; | |
200 | } | |
201 | else | |
202 | { | |
203 | AddEvents(&readset, &writeset); | |
204 | } | |
205 | } | |
206 | ||
207 | // ---------------------------------------------------------------------------- | |
208 | // wxSocketEventDispatcherModule | |
209 | // ---------------------------------------------------------------------------- | |
210 | ||
211 | class wxSocketEventDispatcherModule: public wxModule | |
212 | { | |
213 | public: | |
214 | bool OnInit() { return true; } | |
215 | void OnExit() { wxDELETE(wxSocketEventDispatcher::ms_instance); } | |
216 | ||
217 | private: | |
218 | DECLARE_DYNAMIC_CLASS(wxSocketEventDispatcherModule) | |
219 | }; | |
220 | ||
221 | IMPLEMENT_DYNAMIC_CLASS(wxSocketEventDispatcherModule, wxModule) | |
222 | ||
223 | ||
224 | // ---------------------------------------------------------------------------- | |
225 | // GSocket interface | |
226 | // ---------------------------------------------------------------------------- | |
227 | ||
228 | bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop() | |
229 | { | |
230 | return true; | |
231 | } | |
232 | ||
233 | bool GSocketGUIFunctionsTableConcrete::OnInit(void) | |
234 | { | |
235 | return 1; | |
236 | } | |
237 | ||
238 | void GSocketGUIFunctionsTableConcrete::OnExit(void) | |
239 | { | |
240 | } | |
241 | ||
242 | bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket) | |
243 | { | |
244 | int *m_id; | |
245 | ||
246 | socket->m_gui_dependent = (char *)malloc(sizeof(int)*2); | |
247 | m_id = (int *)(socket->m_gui_dependent); | |
248 | ||
249 | m_id[0] = -1; | |
250 | m_id[1] = -1; | |
251 | ||
252 | return true; | |
253 | } | |
254 | ||
255 | void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket) | |
256 | { | |
257 | free(socket->m_gui_dependent); | |
258 | } | |
259 | ||
260 | void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket, | |
261 | GSocketEvent event) | |
262 | { | |
263 | int *m_id = (int *)(socket->m_gui_dependent); | |
264 | int c; | |
265 | ||
266 | if (socket->m_fd == -1) | |
267 | return; | |
268 | ||
269 | switch (event) | |
270 | { | |
271 | case GSOCK_LOST: /* fall-through */ | |
272 | case GSOCK_INPUT: c = 0; break; | |
273 | case GSOCK_OUTPUT: c = 1; break; | |
274 | case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; | |
275 | default: return; | |
276 | } | |
277 | ||
278 | #if 0 | |
279 | if (m_id[c] != -1) | |
280 | XtRemoveInput(m_id[c]); | |
281 | #endif /* 0 */ | |
282 | ||
283 | if (c == 0) | |
284 | { | |
285 | m_id[0] = socket->m_fd; | |
286 | ||
287 | wxSocketEventDispatcher::Get().RegisterCallback( | |
288 | socket->m_fd, wxSocketEventDispatcherInput, socket); | |
289 | } | |
290 | else | |
291 | { | |
292 | m_id[1] = socket->m_fd; | |
293 | ||
294 | wxSocketEventDispatcher::Get().RegisterCallback( | |
295 | socket->m_fd, wxSocketEventDispatcherOutput, socket); | |
296 | } | |
297 | } | |
298 | ||
299 | void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket, | |
300 | GSocketEvent event) | |
301 | { | |
302 | int *m_id = (int *)(socket->m_gui_dependent); | |
303 | int c; | |
304 | ||
305 | switch (event) | |
306 | { | |
307 | case GSOCK_LOST: /* fall-through */ | |
308 | case GSOCK_INPUT: c = 0; break; | |
309 | case GSOCK_OUTPUT: c = 1; break; | |
310 | case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; | |
311 | default: return; | |
312 | } | |
313 | ||
314 | if (m_id[c] != -1) | |
315 | { | |
316 | if (c == 0) | |
317 | wxSocketEventDispatcher::Get().UnregisterCallback( | |
318 | m_id[c], wxSocketEventDispatcherInput); | |
319 | else | |
320 | wxSocketEventDispatcher::Get().UnregisterCallback( | |
321 | m_id[c], wxSocketEventDispatcherOutput); | |
322 | } | |
323 | ||
324 | m_id[c] = -1; | |
325 | } | |
326 | ||
327 | void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket) | |
328 | { | |
329 | Install_Callback(socket, GSOCK_INPUT); | |
330 | Install_Callback(socket, GSOCK_OUTPUT); | |
331 | } | |
332 | ||
333 | void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket) | |
334 | { | |
335 | Uninstall_Callback(socket, GSOCK_INPUT); | |
336 | Uninstall_Callback(socket, GSOCK_OUTPUT); | |
337 | } | |
338 | ||
339 | #endif // wxUSE_SOCKETS |