2 * @file miranda-network.c
6 * Copyright (C) 2010-2016 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
28 #include "newpluginapi.h"
29 #include "m_protosvc.h"
30 #include "m_protoint.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 struct sipe_backend_listendata
{
48 sipe_listen_start_cb listen_cb
;
49 sipe_client_connected_cb connect_cb
;
51 unsigned short port_min
;
52 unsigned short port_max
;
58 /* Private. For locking only */
65 client_connected_cb_async(void *data
)
67 struct sipe_backend_listendata
*ldata
= (struct sipe_backend_listendata
*)data
;
69 SIPE_DEBUG_INFO("[CN:%08x] About to call real connect callback", ldata
);
71 if (ldata
->connect_cb
)
72 ldata
->connect_cb((struct sipe_backend_fd
*)ldata
->fd
, ldata
->data
);
74 /* Can't close the handle before the SetEvent or we'll deadlock */
75 SetEvent(ldata
->hDoneEvent
);
76 /* MS_NETLIB_CLOSEHANDLE doesn't come back until the accept thread
77 is done. That in turn doesn't end until the pfnNewConnectionV2
78 function comes back. So we know that client_connected_callback
79 will be done and it's safe to free ldata here. */
80 CallService(MS_NETLIB_CLOSEHANDLE
,(WPARAM
)ldata
->boundport
,0);
84 static void client_connected_callback(HANDLE hNewConnection
, DWORD dwRemoteIP
, void *data
)
86 struct sipe_backend_listendata
*ldata
= (struct sipe_backend_listendata
*)data
;
88 SIPE_DEBUG_INFO("[CN:%08x] Remote connection from <%08x>", ldata
, dwRemoteIP
);
90 ldata
->fd
= hNewConnection
;
91 ldata
->hDoneEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
92 CallFunctionAsync(client_connected_cb_async
, ldata
);
93 WaitForSingleObject(ldata
->hDoneEvent
, INFINITE
);
94 CloseHandle(ldata
->hDoneEvent
);
99 listen_cb_async(void *data
)
101 struct sipe_backend_listendata
*ldata
= (struct sipe_backend_listendata
*)data
;
102 ldata
->listen_cb(ldata
->port
, ldata
->data
);
103 SetEvent(ldata
->hDoneEventL
);
106 static unsigned __stdcall
listen_callback(void* data
)
108 NETLIBBIND nlb
= {0};
109 NETLIBUSERSETTINGS nls
= {0};
111 struct sipe_backend_listendata
*ldata
= (struct sipe_backend_listendata
*)data
;
113 nls
.cbSize
= sizeof(NETLIBUSERSETTINGS
);
114 CallService(MS_NETLIB_GETUSERSETTINGS
, (WPARAM
)sipe_miranda_incoming_netlibuser
, (LPARAM
)&nls
);
115 nls
.specifyIncomingPorts
= 1;
116 nls
.szIncomingPorts
= mir_alloc(20);
117 mir_snprintf( nls
.szIncomingPorts
, 20, "%d-%d", ldata
->port_min
, ldata
->port_max
);
118 CallService(MS_NETLIB_SETUSERSETTINGS
, (WPARAM
)sipe_miranda_incoming_netlibuser
, (LPARAM
)&nls
);
120 nlb
.cbSize
= sizeof(NETLIBBIND
);
121 nlb
.pfnNewConnectionV2
= client_connected_callback
;
123 SetLastError(ERROR_INVALID_PARAMETER
); // this must be here - NetLib does not set any error :((
125 ldata
->boundport
= (HANDLE
)CallService(MS_NETLIB_BINDPORT
, (WPARAM
)sipe_miranda_incoming_netlibuser
, (LPARAM
)&nlb
);
126 ldata
->port
= nlb
.wPort
;
128 sipe_miranda_getGlobalWord("iptype", &iptype
);
129 if (iptype
== SIPE_MIRANDA_IP_PROG
)
132 DWORD bytesread
= sizeof(rc
);
133 gchar
*cmd
= sipe_miranda_getGlobalString("ipprog");
134 gchar
*cmdline
= g_strdup_printf("%s listen %d", cmd
, nlb
.wPort
);
137 if (!sipe_miranda_cmd(cmdline
, rc
, &bytesread
))
139 SIPE_DEBUG_INFO("Could not run child program <%s> (%d)", cmdline
, GetLastError());
143 if (ldata
->listen_cb
)
145 ldata
->hDoneEventL
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
146 CallFunctionAsync(listen_cb_async
, ldata
);
147 WaitForSingleObject(ldata
->hDoneEventL
, INFINITE
);
148 CloseHandle(ldata
->hDoneEventL
);
154 struct sipe_backend_listendata
*
155 sipe_backend_network_listen_range(unsigned short port_min
,
156 unsigned short port_max
,
157 sipe_listen_start_cb listen_cb
,
158 sipe_client_connected_cb connect_cb
,
161 struct sipe_backend_listendata
*ldata
;
162 ldata
= g_new0(struct sipe_backend_listendata
, 1);
164 ldata
->listen_cb
= listen_cb
;
165 ldata
->connect_cb
= connect_cb
;
167 ldata
->port_min
= port_min
;
168 ldata
->port_max
= port_max
;
170 CloseHandle((HANDLE
) mir_forkthreadex( listen_callback
, ldata
, 65536, NULL
));
175 void sipe_backend_network_listen_cancel(struct sipe_backend_listendata
*ldata
)
180 struct sipe_backend_fd
*
181 sipe_backend_fd_from_int(int fd
)
188 sipe_backend_fd_is_valid(struct sipe_backend_fd
*fd
)
193 void sipe_backend_fd_free(struct sipe_backend_fd
*fd
)
195 /* N/A; sipe_backend_fd is the actual HANDLE */