Fix #278: 488 error after libnice upgrade
[siplcs.git] / src / miranda / miranda-input.c
blob803deccce9405b8ca60e9d35cc811a381382ed6a
1 /**
2 * @file miranda-input.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <windows.h>
23 #include <stdio.h>
25 #include <glib.h>
27 #include "sipe-backend.h"
29 #include "newpluginapi.h"
30 #include "m_protosvc.h"
31 #include "m_protoint.h"
32 #include "m_netlib.h"
33 #include "miranda-private.h"
35 #define ENTRY_SIG 0x88442211
37 static NETLIBSELECTEX m_select = {0};
38 static GHashTable *m_readhash = NULL;
39 static GHashTable *m_writehash = NULL;
40 static GList *m_entries = NULL;
42 typedef struct sipe_miranda_sel_entry
44 int sig;
45 HANDLE fd;
46 sipe_miranda_input_function func;
47 gpointer user_data;
48 gboolean async;
50 /* Private. For locking only */
51 HANDLE hDoneEvent;
52 gint source;
53 sipe_miranda_input_condition cond;
56 static void __stdcall
57 input_cb_async(void *data)
59 struct sipe_miranda_sel_entry *entry = (struct sipe_miranda_sel_entry*)data;
60 if (entry->fd == NULL)
62 SIPE_DEBUG_INFO("[IE:%08x] Entry already removed. Not calling read/write function", entry);
63 } else {
64 SIPE_DEBUG_INFO("[IE:%08x] Calling real read/write function", entry);
65 entry->func(entry->user_data, entry->source, entry->cond);
67 SetEvent(entry->hDoneEvent);
70 static unsigned __stdcall
71 inputloop(void* data)
73 int cnt;
74 struct sipe_miranda_sel_entry *entry;
75 INT_PTR lstRes;
77 m_select.cbSize = sizeof(m_select);
78 m_select.dwTimeout = 6000;
80 while( m_select.hReadConns[0] || m_select.hWriteConns[0])
82 int rc=0;
83 int wc=0;
84 for ( rc=0 ; m_select.hReadConns[rc] ; rc++ );
85 for ( wc=0 ; m_select.hWriteConns[wc] ; wc++ );
87 SIPE_DEBUG_INFO("About to run select on <%d> read and <%d> write", rc, wc);
88 lstRes = CallService(MS_NETLIB_SELECTEX, 0, (LPARAM)&m_select);
90 if (lstRes < 0)
92 SIPE_DEBUG_INFO_NOFORMAT("Connection failed while waiting.");
93 break;
95 else if (lstRes == 0)
97 SIPE_DEBUG_INFO_NOFORMAT("Select Timeout.");
99 else
101 SIPE_DEBUG_INFO_NOFORMAT("Back from select");
103 for ( cnt=0 ; m_select.hReadConns[cnt] ; cnt++ )
105 DWORD wr;
106 if (!m_select.hReadStatus[cnt]) continue;
107 SIPE_DEBUG_INFO("FD at position <%d> ready to read.", cnt);
108 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_readhash, (gconstpointer)m_select.hReadConns[cnt]);
109 if (!entry)
111 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no read handler found.");
112 continue;
114 SIPE_DEBUG_INFO("[IE:%08x] About to call read function.", entry);
115 entry->source = (gint)m_select.hReadConns[cnt];
116 entry->cond = SIPE_MIRANDA_INPUT_READ;
117 entry->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
118 if (entry->async)
120 CallFunctionAsync(input_cb_async, entry);
121 wr = WaitForSingleObject(entry->hDoneEvent, INFINITE);
122 } else {
123 input_cb_async(entry);
125 CloseHandle(entry->hDoneEvent);
126 SIPE_DEBUG_INFO("[IE:%08x] read function returned.", entry);
129 for ( cnt=0 ; m_select.hWriteConns[cnt] ; cnt++ )
131 if (!m_select.hWriteStatus[cnt]) continue;
132 SIPE_DEBUG_INFO("FD at position <%d> ready to write.", cnt);
133 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_writehash, (gconstpointer)m_select.hWriteConns[cnt]);
134 if (!entry)
136 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no write handler found.");
137 continue;
139 SIPE_DEBUG_INFO("[IE:%08x] About to call write function.", entry);
140 entry->source = (gint)m_select.hWriteConns[cnt];
141 entry->cond = SIPE_MIRANDA_INPUT_WRITE;
142 entry->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
143 if (entry->async)
145 CallFunctionAsync(input_cb_async, entry);
146 WaitForSingleObject(entry->hDoneEvent, INFINITE);
147 } else {
148 input_cb_async(entry);
150 CloseHandle(entry->hDoneEvent);
151 SIPE_DEBUG_INFO("[IE:%08x] write function returned.", entry);
155 /* Free all removed entries */
156 while (m_entries) g_list_delete_link(m_entries, g_list_last(m_entries));
159 return 0;
162 struct sipe_miranda_sel_entry*
163 sipe_miranda_input_add(HANDLE fd, sipe_miranda_input_condition cond, sipe_miranda_input_function func, gpointer user_data)
165 int rcnt = 0;
166 int wcnt = 0;
167 struct sipe_miranda_sel_entry *entry;
169 if (!m_readhash)
170 m_readhash = g_hash_table_new(NULL, NULL);
172 if (!m_writehash)
173 m_writehash = g_hash_table_new(NULL, NULL);
175 if ((cond != SIPE_MIRANDA_INPUT_READ) && (cond != SIPE_MIRANDA_INPUT_WRITE))
177 SIPE_DEBUG_INFO("Invalid input condition <%d> cond.", cond);
178 return 0;
181 entry = g_new0(struct sipe_miranda_sel_entry,1);
182 entry->sig = ENTRY_SIG;
183 entry->func = func;
184 entry->user_data = user_data;
185 entry->fd = fd;
186 entry->async = FALSE;
188 if (cond == SIPE_MIRANDA_INPUT_READ)
190 for ( wcnt=0 ; m_select.hWriteConns[wcnt] ; wcnt++ );
191 for ( rcnt=0 ; m_select.hReadConns[rcnt] && m_select.hReadConns[rcnt]!=(HANDLE)fd ; rcnt++ );
192 g_hash_table_replace( m_readhash, (gpointer)fd, entry );
193 m_select.hReadStatus[rcnt] = FALSE;
194 m_select.hReadConns[rcnt] = (HANDLE)fd;
196 else if (cond == SIPE_MIRANDA_INPUT_WRITE)
198 for ( rcnt=0 ; m_select.hReadConns[rcnt] ; rcnt++ );
199 for ( wcnt=0 ; m_select.hWriteConns[wcnt] && m_select.hWriteConns[wcnt]!=(HANDLE)fd ; wcnt++ );
200 g_hash_table_replace( m_writehash, (gpointer)fd, entry );
201 m_select.hWriteStatus[rcnt] = FALSE;
202 m_select.hWriteConns[rcnt] = (HANDLE)fd;
205 if (!(rcnt+wcnt))
206 CloseHandle((HANDLE) mir_forkthreadex( inputloop, NULL, 8192, NULL ));
208 SIPE_DEBUG_INFO_NOFORMAT("Added input handler.");
209 return entry;
212 gboolean
213 sipe_miranda_input_remove(struct sipe_miranda_sel_entry *entry)
215 int cnt;
217 if (!entry)
219 SIPE_DEBUG_INFO_NOFORMAT("Not a valid entry. NULL.");
220 return FALSE;
223 if (entry->sig != ENTRY_SIG)
225 SIPE_DEBUG_INFO("Not a valid entry. Sig is <%08x>.", entry->sig);
226 return FALSE;
229 if (g_hash_table_lookup(m_readhash, (gconstpointer)entry->fd) == entry)
231 for ( cnt=0 ; m_select.hReadConns[cnt] && m_select.hReadConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
232 for ( ; m_select.hReadConns[cnt] ; cnt++ ) m_select.hReadConns[cnt] = m_select.hReadConns[cnt+1];
233 g_hash_table_remove(m_readhash, (gconstpointer)entry->fd);
236 if (g_hash_table_lookup(m_writehash, (gconstpointer)entry->fd) == entry)
238 for ( cnt=0 ; m_select.hWriteConns[cnt] && m_select.hWriteConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
239 for ( ; m_select.hWriteConns[cnt] ; cnt++ ) m_select.hWriteConns[cnt] = m_select.hWriteConns[cnt+1];
240 g_hash_table_remove(m_writehash, (gconstpointer)entry->fd);
243 /* Set fd to NULL so we won't try to call the callback if we're
244 currently waiting to get back to the main thread */
245 entry->fd = NULL;
247 /* Add it to the list of entries that can be freed after the next select
248 * loop in the thread that's handling the actual select
250 g_list_append( m_entries, entry );
252 return TRUE;
258 Local Variables:
259 mode: c
260 c-file-style: "bsd"
261 indent-tabs-mode: t
262 tab-width: 8
263 End: