Fix #3580212: Connection drops after a few hours
[siplcs.git] / src / miranda / miranda-network.c
blob085ba5485dae8f9400c438e87ba81b69a25338f2
1 /**
2 * @file miranda-network.c
4 * pidgin-sipe
6 * Copyright (C) 2010-12 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
23 #include <windows.h>
24 #include <stdio.h>
26 #include <glib.h>
28 #include "newpluginapi.h"
29 #include "m_protosvc.h"
30 #include "m_protoint.h"
31 #include "m_system.h"
32 #include "m_netlib.h"
34 #include "sipe-common.h"
35 #include "sipe-core.h"
36 #include "sipe-backend.h"
37 #include "miranda-private.h"
39 extern HANDLE sipe_miranda_incoming_netlibuser;
41 const gchar *sipe_miranda_get_local_ip(void)
43 struct hostent *localHost = gethostbyname("");
44 return inet_ntoa(*(struct in_addr *)*localHost->h_addr_list);
47 const gchar *sipe_backend_network_ip_address(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public)
49 static gchar ip[60] = "\0";
50 WORD iptype;
52 sipe_miranda_getGlobalWord("iptype", &iptype);
54 if (iptype == SIPE_MIRANDA_IP_LOCAL)
56 struct hostent *localHost = gethostbyname("");
57 gchar *localIP = inet_ntoa(*(struct in_addr *)*localHost->h_addr_list);
58 strncpy(ip, localIP, 60);
59 SIPE_DEBUG_INFO("Local ip is <%s>", ip);
60 } else if (iptype == SIPE_MIRANDA_IP_MANUAL) {
61 gchar *tmp = sipe_miranda_getGlobalString("public_ip");
62 SIPE_DEBUG_INFO("Retrieving public ip option: <%s>", tmp);
63 strncpy(ip, tmp, 60);
64 mir_free(tmp);
65 } else {
66 DWORD bytesread = sizeof(ip);
67 gchar *cmd = sipe_miranda_getGlobalString("ipprog");
68 gchar *cmdline = g_strdup_printf("%s ip", cmd);
70 mir_free(cmd);
71 SIPE_DEBUG_INFO("Running command to retrieve ip: <%s>", cmdline);
72 if (!sipe_miranda_cmd(cmdline, ip, &bytesread))
74 SIPE_DEBUG_INFO("Could not run child program <%s> (%d)", cmdline, GetLastError());
75 g_free(cmdline);
76 return "0.0.0.0";
79 g_free(cmdline);
80 return ip;
84 return ip;
87 struct sipe_backend_listendata {
88 sipe_listen_start_cb listen_cb;
89 sipe_client_connected_cb connect_cb;
90 gpointer data;
91 unsigned short port_min;
92 unsigned short port_max;
94 HANDLE boundport;
95 HANDLE fd;
96 WORD port;
98 /* Private. For locking only */
99 HANDLE hDoneEvent;
100 HANDLE hDoneEventL;
104 static void __stdcall
105 client_connected_cb_async(void *data)
107 struct sipe_backend_listendata *ldata = (struct sipe_backend_listendata *)data;
109 SIPE_DEBUG_INFO("[CN:%08x] About to call real connect callback", ldata);
111 if (ldata->connect_cb)
112 ldata->connect_cb((struct sipe_backend_fd *)ldata->fd, ldata->data);
114 /* Can't close the handle before the SetEvent or we'll deadlock */
115 SetEvent(ldata->hDoneEvent);
116 /* MS_NETLIB_CLOSEHANDLE doesn't come back until the accept thread
117 is done. That in turn doesn't end until the pfnNewConnectionV2
118 function comes back. So we know that client_connected_callback
119 will be done and it's safe to free ldata here. */
120 CallService(MS_NETLIB_CLOSEHANDLE,(WPARAM)ldata->boundport,0);
121 g_free(ldata);
124 static void client_connected_callback(HANDLE hNewConnection, DWORD dwRemoteIP, void *data)
126 struct sipe_backend_listendata *ldata = (struct sipe_backend_listendata *)data;
128 SIPE_DEBUG_INFO("[CN:%08x] Remote connection from <%08x>", ldata, dwRemoteIP);
130 ldata->fd = hNewConnection;
131 ldata->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
132 CallFunctionAsync(client_connected_cb_async, ldata);
133 WaitForSingleObject(ldata->hDoneEvent, INFINITE);
134 CloseHandle(ldata->hDoneEvent);
138 static void __stdcall
139 listen_cb_async(void *data)
141 struct sipe_backend_listendata *ldata = (struct sipe_backend_listendata *)data;
142 ldata->listen_cb(ldata->port, ldata->data);
143 SetEvent(ldata->hDoneEventL);
146 static unsigned __stdcall listen_callback(void* data)
148 NETLIBBIND nlb = {0};
149 NETLIBUSERSETTINGS nls = {0};
150 WORD iptype;
151 struct sipe_backend_listendata *ldata = (struct sipe_backend_listendata *)data;
153 nls.cbSize = sizeof(NETLIBUSERSETTINGS);
154 CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)sipe_miranda_incoming_netlibuser, (LPARAM)&nls);
155 nls.specifyIncomingPorts = 1;
156 nls.szIncomingPorts = mir_alloc(20);
157 mir_snprintf( nls.szIncomingPorts, 20, "%d-%d", ldata->port_min, ldata->port_max);
158 CallService(MS_NETLIB_SETUSERSETTINGS, (WPARAM)sipe_miranda_incoming_netlibuser, (LPARAM)&nls);
160 nlb.cbSize = sizeof(NETLIBBIND);
161 nlb.pfnNewConnectionV2 = client_connected_callback;
162 nlb.pExtra = ldata;
163 SetLastError(ERROR_INVALID_PARAMETER); // this must be here - NetLib does not set any error :((
165 ldata->boundport = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)sipe_miranda_incoming_netlibuser, (LPARAM)&nlb);
166 ldata->port = nlb.wPort;
168 sipe_miranda_getGlobalWord("iptype", &iptype);
169 if (iptype == SIPE_MIRANDA_IP_PROG)
171 gchar rc[20];
172 DWORD bytesread = sizeof(rc);
173 gchar *cmd = sipe_miranda_getGlobalString("ipprog");
174 gchar *cmdline = g_strdup_printf("%s listen %d", cmd, nlb.wPort);
175 mir_free(cmd);
177 if (!sipe_miranda_cmd(cmdline, rc, &bytesread))
179 SIPE_DEBUG_INFO("Could not run child program <%s> (%d)", cmdline, GetLastError());
183 if (ldata->listen_cb)
185 ldata->hDoneEventL = CreateEvent(NULL, FALSE, FALSE, NULL);
186 CallFunctionAsync(listen_cb_async, ldata);
187 WaitForSingleObject(ldata->hDoneEventL, INFINITE);
188 CloseHandle(ldata->hDoneEventL);
191 return 0;
194 struct sipe_backend_listendata *
195 sipe_backend_network_listen_range(unsigned short port_min,
196 unsigned short port_max,
197 sipe_listen_start_cb listen_cb,
198 sipe_client_connected_cb connect_cb,
199 gpointer data)
201 struct sipe_backend_listendata *ldata;
202 ldata = g_new0(struct sipe_backend_listendata, 1);
204 ldata->listen_cb = listen_cb;
205 ldata->connect_cb = connect_cb;
206 ldata->data = data;
207 ldata->port_min = port_min;
208 ldata->port_max = port_max;
210 CloseHandle((HANDLE) mir_forkthreadex( listen_callback, ldata, 65536, NULL ));
212 return ldata;
215 void sipe_backend_network_listen_cancel(struct sipe_backend_listendata *ldata)
217 _NIF();
220 gboolean
221 sipe_backend_fd_is_valid(struct sipe_backend_fd *fd)
223 return (fd != NULL);
226 void sipe_backend_fd_free(struct sipe_backend_fd *fd)
228 /* N/A; sipe_backend_fd is the actual HANDLE */
232 Local Variables:
233 mode: c
234 c-file-style: "bsd"
235 indent-tabs-mode: t
236 tab-width: 8
237 End: