Mercurial > pidgin.yaz
annotate src/upnp.c @ 12116:e75ef7aa913e
[gaim-migrate @ 14416]
" This patch implements a replacement for the queuing
system from 1.x. It also obsoletes a previous patch
[#1338873] I submitted to prioritize the unseen states
in gtk conversations.
The attached envelope.png is ripped from the
msgunread.png already included in gaim. It should be
dropped in the pixmaps directory (Makefile.am is
updated accordingly in this patch).
The two separate queuing preferences from 1.x, queuing
messages while away and queuing all new messages (from
docklet), are replaced with a single 3-way preference
for conversations. The new preference is "Hide new IM
conversations". This preference can be set to never,
away and always.
When a gtk conversation is created, it may be placed in
a hidden conversation window instead of being placed
normally. This decision is based upon the preference
and possibly the away state of the account the
conversation is being created for. This *will* effect
conversations the user explicitly requests to be
created, so in these cases the caller must be sure to
present the conversation to the user, using
gaim_gtkconv_present_conversation(). This is done
already in gtkdialogs.c which handles creating
conversations requested by the user from gaim proper
(menus, double-clicking on budy in blist, etc.).
The main advantage to not queuing messages is that the
conversations exist, the message is written to the
conversation (and logged if appropriate) and the unseen
state is set on the conversation. This means no
additional features are needed to track whether there
are queued messages or not, just use the unseen state
on conversations.
Since conversations may not be visible (messages
"queued"), gaim proper needs some notification that
there are messages waiting. I opted for a menutray icon
that shows up when an im conversation has an unseen
message. Clicking this icon will focus (and show if
hidden) the first conversation with an unseen message.
This is essentially the same behavior of the docklet in
cvs right now, except that the icon is only visible
when there is a conversation with an unread message.
The api that is added is flexible enough to allow
either the docklet or the new blist menutray icon to be
visible for conversations of any/all types and for
unseen messages >= any state. Currently they are set to
only IM conversations and only unseen states >= TEXT
(system messages and no log messages will not trigger
blinking the docklet or showing the blist tray icon),
but these could be made preferences relatively easily
in the future. Other plugins could probably benefit as
well: gaim_gtk_conversations_get_first_unseen().
There is probably some limit to comment size, so I'll
stop rambling now. If anyone has more
questions/comments, catch me in #gaim, here or on
gaim-devel."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Wed, 16 Nov 2005 18:17:01 +0000 |
parents | f9c5480ad0ce |
children | 201be1b681a4 |
rev | line source |
---|---|
11195 | 1 /** |
2 * @file upnp.c UPnP Implementation | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 #include "internal.h" | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
26 #include "gaim.h" |
11195 | 27 |
28 #include "debug.h" | |
11391 | 29 #include "util.h" |
30 #include "proxy.h" | |
31 #include "xmlnode.h" | |
11195 | 32 #include "network.h" |
33 #include "eventloop.h" | |
34 #include "upnp.h" | |
35 | |
36 | |
37 /** | |
38 * Information on the httpResponse callback | |
39 */ | |
40 typedef struct | |
41 { | |
42 guint inpa; /* gaim_input_add handle */ | |
43 guint tima; /* gaim_timout_add handle */ | |
11391 | 44 gchar* sendBuffer; /* send data */ |
45 gchar* recvBuffer; /* response data */ | |
11195 | 46 guint totalSizeRecv; |
47 gboolean done; | |
48 | |
11391 | 49 } NetResponseData; |
11195 | 50 |
51 | |
52 /*************************************************************** | |
53 ** General Defines * | |
54 ****************************************************************/ | |
55 #define HTTP_OK "200 OK" | |
11391 | 56 #define DEFAULT_HTTP_PORT 80 |
57 #define MAX_PORT_SIZE 6 | |
58 #define SIZEOF_HTTP 7 /* size of "http://" string */ | |
11492 | 59 #define RECEIVE_TIMEOUT 10000 |
60 #define CONSECUTIVE_RECEIVE_TIMEOUT 500 | |
11195 | 61 #define DISCOVERY_TIMEOUT 1000 |
62 | |
63 | |
64 /*************************************************************** | |
65 ** Discovery/Description Defines * | |
66 ****************************************************************/ | |
67 #define NUM_UDP_ATTEMPTS 2 | |
68 | |
69 /* Address and port of an SSDP request used for discovery */ | |
70 #define HTTPMU_HOST_ADDRESS "239.255.255.250" | |
71 #define HTTPMU_HOST_PORT 1900 | |
72 | |
73 #define SEARCH_REQUEST_DEVICE "urn:schemas-upnp-org:service:" \ | |
11391 | 74 "%s" |
11195 | 75 |
76 #define SEARCH_REQUEST_STRING "M-SEARCH * HTTP/1.1\r\n" \ | |
77 "MX: 2\r\n" \ | |
78 "HOST: 239.255.255.250:1900\r\n" \ | |
79 "MAN: \"ssdp:discover\"\r\n" \ | |
80 "ST: urn:schemas-upnp-org:service:" \ | |
11391 | 81 "%s\r\n" \ |
11195 | 82 "\r\n" |
83 | |
11492 | 84 #define MAX_DISCOVERY_RECEIVE_SIZE 400 |
85 #define MAX_DESCRIPTION_RECEIVE_SIZE 7000 | |
11195 | 86 #define MAX_DESCRIPTION_HTTP_HEADER_SIZE 100 |
87 | |
88 | |
89 /****************************************************************** | |
90 ** Action Defines * | |
91 *******************************************************************/ | |
11391 | 92 #define HTTP_HEADER_ACTION "POST /%s HTTP/1.1\r\n" \ |
11195 | 93 "HOST: %s\r\n" \ |
94 "SOAPACTION: " \ | |
95 "\"urn:schemas-upnp-org:" \ | |
96 "service:%s#%s\"\r\n" \ | |
97 "CONTENT-TYPE: text/xml ; charset=\"utf-8\"\r\n"\ | |
11656
f9c5480ad0ce
[gaim-migrate @ 13940]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
98 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n" |
11195 | 99 |
100 #define SOAP_ACTION "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" \ | |
101 "<s:Envelope xmlns:s=" \ | |
102 "\"http://schemas.xmlsoap.org/soap/envelope/\" " \ | |
103 "s:encodingStyle=" \ | |
104 "\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" \ | |
105 "<s:Body>\r\n" \ | |
106 "<u:%s xmlns:u=" \ | |
107 "\"urn:schemas-upnp-org:service:%s\">\r\n%s" \ | |
108 "</u:%s>\r\n" \ | |
109 "</s:Body>\r\n" \ | |
110 "</s:Envelope>\r\n" | |
111 | |
112 #define PORT_MAPPING_LEASE_TIME "0" | |
113 #define PORT_MAPPING_DESCRIPTION "GAIM_UPNP_PORT_FORWARD" | |
114 | |
115 #define ADD_PORT_MAPPING_PARAMS "<NewRemoteHost></NewRemoteHost>\r\n" \ | |
116 "<NewExternalPort>%i</NewExternalPort>\r\n"\ | |
117 "<NewProtocol>%s</NewProtocol>\r\n" \ | |
118 "<NewInternalPort>%i</NewInternalPort>\r\n"\ | |
119 "<NewInternalClient>%s" \ | |
120 "</NewInternalClient>\r\n" \ | |
121 "<NewEnabled>1</NewEnabled>\r\n" \ | |
122 "<NewPortMappingDescription>" \ | |
123 PORT_MAPPING_DESCRIPTION \ | |
124 "</NewPortMappingDescription>\r\n" \ | |
125 "<NewLeaseDuration>" \ | |
126 PORT_MAPPING_LEASE_TIME \ | |
127 "</NewLeaseDuration>\r\n" | |
128 | |
129 #define DELETE_PORT_MAPPING_PARAMS "<NewRemoteHost></NewRemoteHost>\r\n" \ | |
130 "<NewExternalPort>%i" \ | |
131 "</NewExternalPort>\r\n" \ | |
132 "<NewProtocol>%s</NewProtocol>\r\n" | |
133 | |
134 | |
135 static void | |
136 gaim_upnp_timeout(gpointer data, | |
11213 | 137 gint source, |
11195 | 138 GaimInputCondition cond) |
139 { | |
11391 | 140 NetResponseData* nrd = data; |
11195 | 141 |
11391 | 142 gaim_input_remove(nrd->inpa); |
143 gaim_timeout_remove(nrd->tima); | |
11195 | 144 |
11391 | 145 if(nrd->totalSizeRecv == 0 && nrd->recvBuffer != NULL) { |
146 g_free(nrd->recvBuffer); | |
147 nrd->recvBuffer = NULL; | |
148 } else if(nrd->recvBuffer != NULL) { | |
149 nrd->recvBuffer[nrd->totalSizeRecv] = '\0'; | |
11195 | 150 } |
151 | |
11391 | 152 nrd->done = TRUE; |
11195 | 153 } |
154 | |
155 | |
156 static void | |
157 gaim_upnp_http_read(gpointer data, | |
158 gint sock, | |
159 GaimInputCondition cond) | |
160 { | |
161 int sizeRecv; | |
162 extern int errno; | |
11391 | 163 NetResponseData* nrd = data; |
11195 | 164 |
11391 | 165 sizeRecv = recv(sock, &(nrd->recvBuffer[nrd->totalSizeRecv]), |
11492 | 166 MAX_DESCRIPTION_RECEIVE_SIZE-nrd->totalSizeRecv, 0); |
11195 | 167 if(sizeRecv < 0 && errno != EINTR) { |
11391 | 168 gaim_debug_error("upnp", |
11195 | 169 "gaim_upnp_http_read(): recv < 0: %i!\n\n", errno); |
11391 | 170 g_free(nrd->recvBuffer); |
171 nrd->recvBuffer = NULL; | |
172 gaim_timeout_remove(nrd->tima); | |
173 gaim_input_remove(nrd->inpa); | |
174 nrd->done = TRUE; | |
11195 | 175 return; |
176 }else if(errno == EINTR) { | |
177 sizeRecv = 0; | |
178 } | |
11391 | 179 nrd->totalSizeRecv += sizeRecv; |
11195 | 180 |
181 if(sizeRecv == 0) { | |
11391 | 182 gaim_timeout_remove(nrd->tima); |
183 gaim_input_remove(nrd->inpa); | |
184 if(nrd->totalSizeRecv == 0) { | |
185 gaim_debug_error("upnp", | |
11195 | 186 "gaim_upnp_http_read(): totalSizeRecv == 0\n\n"); |
11391 | 187 g_free(nrd->recvBuffer); |
188 nrd->recvBuffer = NULL; | |
11195 | 189 } else { |
11391 | 190 nrd->recvBuffer[nrd->totalSizeRecv] = '\0'; |
11195 | 191 } |
11391 | 192 nrd->done = TRUE; |
11195 | 193 } else { |
11391 | 194 gaim_timeout_remove(nrd->tima); |
195 gaim_input_remove(nrd->inpa); | |
11492 | 196 nrd->tima = gaim_timeout_add(CONSECUTIVE_RECEIVE_TIMEOUT, |
11391 | 197 (GSourceFunc)gaim_upnp_timeout, nrd); |
198 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
199 gaim_upnp_http_read, nrd); | |
11195 | 200 } |
201 } | |
202 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
203 static void |
11391 | 204 gaim_upnp_http_send(gpointer data, |
205 gint sock, | |
206 GaimInputCondition cond) | |
11195 | 207 { |
11586 | 208 gsize sizeSent, totalSizeSent = 0; |
11195 | 209 extern int errno; |
11391 | 210 NetResponseData* nrd = data; |
11195 | 211 |
11391 | 212 gaim_timeout_remove(nrd->tima); |
213 while(totalSizeSent < strlen(nrd->sendBuffer)) { | |
11586 | 214 sizeSent = send(sock,(gchar*)(nrd->sendBuffer+totalSizeSent), |
11391 | 215 strlen(nrd->sendBuffer)-totalSizeSent,0); |
11195 | 216 if(sizeSent <= 0 && errno != EINTR) { |
11391 | 217 gaim_debug_error("upnp", |
11195 | 218 "gaim_upnp_http_request(): Failed In send\n\n"); |
11391 | 219 nrd->done = TRUE; |
220 g_free(nrd->recvBuffer); | |
221 nrd->recvBuffer = NULL; | |
11195 | 222 close(sock); |
11391 | 223 return; |
11195 | 224 }else if(errno == EINTR) { |
225 sizeSent = 0; | |
226 } | |
227 totalSizeSent += sizeSent; | |
228 } | |
229 | |
11492 | 230 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 231 (GSourceFunc)gaim_upnp_timeout, nrd); |
232 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
233 gaim_upnp_http_read, nrd); | |
234 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
235 g_main_context_iteration(NULL, TRUE); |
11195 | 236 } |
237 close(sock); | |
11391 | 238 } |
11195 | 239 |
11391 | 240 static gchar* |
241 gaim_upnp_http_request(const gchar* address, | |
242 int port, | |
243 gchar* httpRequest) | |
244 { | |
245 gchar* recvBuffer; | |
246 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
247 nrd->sendBuffer = httpRequest; | |
11492 | 248 nrd->recvBuffer = (gchar*)g_malloc(MAX_DESCRIPTION_RECEIVE_SIZE); |
11391 | 249 |
11492 | 250 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 251 (GSourceFunc)gaim_upnp_timeout, nrd); |
252 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
253 if(gaim_proxy_connect(NULL, address, port, |
11391 | 254 gaim_upnp_http_send, nrd)) { |
255 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
256 gaim_debug_error("upnp", "Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
11391 | 257 address, port, nrd->sendBuffer); |
258 | |
259 gaim_timeout_remove(nrd->tima); | |
260 g_free(nrd->recvBuffer); | |
261 nrd->recvBuffer = NULL; | |
262 } else { | |
263 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
264 g_main_context_iteration(NULL, TRUE); |
11391 | 265 } |
266 } | |
267 | |
268 recvBuffer = nrd->recvBuffer; | |
269 g_free(nrd); | |
270 | |
11195 | 271 return recvBuffer; |
272 } | |
273 | |
274 | |
275 | |
11391 | 276 static gboolean |
277 gaim_upnp_compare_device(const xmlnode* device, | |
278 const gchar* deviceType) | |
279 { | |
280 xmlnode* deviceTypeNode = xmlnode_get_child(device, "deviceType"); | |
281 if(deviceTypeNode == NULL) { | |
282 return FALSE; | |
283 } | |
284 return !g_ascii_strcasecmp(xmlnode_get_data(deviceTypeNode), deviceType); | |
285 } | |
11195 | 286 |
11391 | 287 |
288 static gboolean | |
289 gaim_upnp_compare_service(const xmlnode* service, | |
290 const gchar* serviceType) | |
11195 | 291 { |
11391 | 292 xmlnode* serviceTypeNode = xmlnode_get_child(service, "serviceType"); |
293 if(serviceTypeNode == NULL) { | |
294 return FALSE; | |
295 } | |
296 return !g_ascii_strcasecmp(xmlnode_get_data(serviceTypeNode), serviceType); | |
297 } | |
298 | |
299 | |
11195 | 300 |
11391 | 301 static gchar* |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
302 gaim_upnp_parse_description_response(const gchar* httpResponse, |
11391 | 303 const gchar* httpURL, |
304 const gchar* serviceType) | |
305 { | |
306 gchar* xmlRoot; | |
307 gchar* baseURL; | |
308 gchar* controlURL; | |
309 gchar* service; | |
310 xmlnode* xmlRootNode; | |
311 xmlnode* serviceTypeNode; | |
312 xmlnode* controlURLNode; | |
313 xmlnode* baseURLNode; | |
314 | |
315 /* make sure we have a valid http response */ | |
316 if(g_strstr_len(httpResponse, strlen(httpResponse), HTTP_OK) == NULL) { | |
317 gaim_debug_error("upnp", | |
11195 | 318 "parse_description_response(): Failed In HTTP_OK\n\n"); |
319 return NULL; | |
320 } | |
321 | |
11391 | 322 /* find the root of the xml document */ |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
323 if((xmlRoot = g_strstr_len(httpResponse, strlen(httpResponse), |
11391 | 324 "<root")) == NULL) { |
325 gaim_debug_error("upnp", | |
326 "parse_description_response(): Failed finding root\n\n"); | |
327 return NULL; | |
328 } | |
329 | |
330 /* create the xml root node */ | |
331 if((xmlRootNode = xmlnode_from_str(xmlRoot, -1)) == NULL) { | |
332 gaim_debug_error("upnp", | |
333 "parse_description_response(): Could not parse xml root node\n\n"); | |
11195 | 334 return NULL; |
335 } | |
11391 | 336 |
337 /* get the baseURL of the device */ | |
338 if((baseURLNode = xmlnode_get_child(xmlRootNode, | |
339 "URLBase")) != NULL) { | |
340 baseURL = g_strdup(xmlnode_get_data(baseURLNode)); | |
341 } else { | |
342 baseURL = g_strdup(httpURL); | |
343 } | |
344 | |
345 /* get the serviceType child that has the service type as it's data */ | |
346 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
347 /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 |
11391 | 348 and it's devicelist */ |
349 serviceTypeNode = xmlnode_get_child(xmlRootNode, "device"); | |
350 while(!gaim_upnp_compare_device(serviceTypeNode, | |
351 "urn:schemas-upnp-org:device:InternetGatewayDevice:1") && | |
352 serviceTypeNode != NULL) { | |
353 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
354 } | |
355 if(serviceTypeNode == NULL) { | |
356 gaim_debug_error("upnp", | |
357 "parse_description_response(): could not get serviceTypeNode 1\n\n"); | |
11195 | 358 return NULL; |
359 } | |
11391 | 360 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); |
361 if(serviceTypeNode == NULL) { | |
362 gaim_debug_error("upnp", | |
363 "parse_description_response(): could not get serviceTypeNode 2\n\n"); | |
11195 | 364 return NULL; |
365 } | |
366 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
367 /* get urn:schemas-upnp-org:device:WANDevice:1 |
11391 | 368 and it's devicelist */ |
369 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
370 while(!gaim_upnp_compare_device(serviceTypeNode, | |
371 "urn:schemas-upnp-org:device:WANDevice:1") && | |
372 serviceTypeNode != NULL) { | |
373 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
374 } | |
375 if(serviceTypeNode == NULL) { | |
376 gaim_debug_error("upnp", | |
377 "parse_description_response(): could not get serviceTypeNode 3\n\n"); | |
378 return NULL; | |
379 } | |
380 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); | |
381 if(serviceTypeNode == NULL) { | |
382 gaim_debug_error("upnp", | |
383 "parse_description_response(): could not get serviceTypeNode 4\n\n"); | |
384 return NULL; | |
385 } | |
11195 | 386 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
387 /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 |
11391 | 388 and it's servicelist */ |
389 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); | |
390 while(!gaim_upnp_compare_device(serviceTypeNode, | |
391 "urn:schemas-upnp-org:device:WANConnectionDevice:1") && | |
392 serviceTypeNode != NULL) { | |
393 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
394 } | |
395 if(serviceTypeNode == NULL) { | |
396 gaim_debug_error("upnp", | |
397 "parse_description_response(): could not get serviceTypeNode 5\n\n"); | |
11195 | 398 return NULL; |
399 } | |
11391 | 400 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "serviceList"); |
401 if(serviceTypeNode == NULL) { | |
402 gaim_debug_error("upnp", | |
403 "parse_description_response(): could not get serviceTypeNode 6\n\n"); | |
404 return NULL; | |
405 } | |
11195 | 406 |
11391 | 407 /* get the serviceType variable passed to this function */ |
408 service = g_strdup_printf(SEARCH_REQUEST_DEVICE, serviceType); | |
409 serviceTypeNode = xmlnode_get_child(serviceTypeNode, "service"); | |
410 while(!gaim_upnp_compare_service(serviceTypeNode, service) && | |
411 serviceTypeNode != NULL) { | |
412 serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); | |
11195 | 413 } |
414 | |
11391 | 415 g_free(service); |
416 if(serviceTypeNode == NULL) { | |
417 gaim_debug_error("upnp", | |
418 "parse_description_response(): could not get serviceTypeNode 7\n\n"); | |
419 return NULL; | |
420 } | |
421 | |
422 /* get the controlURL of the service */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
423 if((controlURLNode = xmlnode_get_child(serviceTypeNode, |
11391 | 424 "controlURL")) == NULL) { |
425 gaim_debug_error("upnp", | |
426 "parse_description_response(): Could not find controlURL\n\n"); | |
427 return NULL; | |
428 } | |
429 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
430 if(g_strstr_len(xmlnode_get_data(controlURLNode), |
11391 | 431 SIZEOF_HTTP, "http://") == NULL && |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
432 g_strstr_len(xmlnode_get_data(controlURLNode), |
11391 | 433 SIZEOF_HTTP, "HTTP://") == NULL) { |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
434 controlURL = g_strdup_printf("%s%s", baseURL, |
11391 | 435 xmlnode_get_data(controlURLNode)); |
11195 | 436 }else{ |
11391 | 437 controlURL = g_strdup(xmlnode_get_data(controlURLNode)); |
11195 | 438 } |
11391 | 439 g_free(baseURL); |
440 xmlnode_free(xmlRootNode); | |
11195 | 441 |
442 return controlURL; | |
443 } | |
444 | |
445 | |
11391 | 446 static gchar* |
447 gaim_upnp_parse_description(const gchar* descriptionURL, | |
448 const gchar* serviceType) | |
11195 | 449 { |
11391 | 450 gchar* fullURL; |
451 gchar* controlURL; | |
452 gchar* httpResponse; | |
453 gchar* httpRequest; | |
11195 | 454 |
11391 | 455 gchar* descriptionXMLAddress; |
456 gchar* descriptionAddressPort; | |
457 gchar* descriptionAddress; | |
458 gchar descriptionPort[MAX_PORT_SIZE]; | |
459 int port = 0; | |
11195 | 460 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
461 /* parse the 4 above variables out of the descriptionURL |
11195 | 462 example description URL: http://192.168.1.1:5678/rootDesc.xml */ |
463 | |
464 /* parse the url into address, port, path variables */ | |
11391 | 465 if(!gaim_url_parse(descriptionURL, &descriptionAddress, |
466 &port, &descriptionXMLAddress, NULL, NULL)) { | |
11195 | 467 return NULL; |
468 } | |
11391 | 469 if(port == 0 || port == -1) { |
470 port = DEFAULT_HTTP_PORT; | |
11195 | 471 } |
11391 | 472 g_ascii_dtostr(descriptionPort, MAX_PORT_SIZE, port); |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
473 descriptionAddressPort = g_strdup_printf("%s:%s", descriptionAddress, |
11391 | 474 descriptionPort); |
11195 | 475 |
11391 | 476 fullURL = g_strdup_printf("http://%s", descriptionAddressPort); |
11195 | 477 |
478 /* for example... | |
479 GET /rootDesc.xml HTTP/1.1\r\nHost: 192.168.1.1:5678\r\n\r\n */ | |
11391 | 480 httpRequest = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", |
481 descriptionXMLAddress, descriptionAddressPort); | |
11195 | 482 |
483 httpResponse = gaim_upnp_http_request(descriptionAddress, | |
484 port, httpRequest); | |
485 if(httpResponse == NULL) { | |
11391 | 486 gaim_debug_error("upnp", |
11195 | 487 "gaim_upnp_parse_description(): httpResponse is NULL\n\n"); |
11391 | 488 g_free(descriptionXMLAddress); |
489 g_free(descriptionAddress); | |
490 g_free(descriptionAddressPort); | |
491 g_free(httpRequest); | |
492 g_free(fullURL); | |
11195 | 493 return NULL; |
494 } | |
495 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
496 controlURL = gaim_upnp_parse_description_response(httpResponse, |
11391 | 497 fullURL, serviceType); |
11195 | 498 |
11391 | 499 g_free(descriptionXMLAddress); |
500 g_free(descriptionAddress); | |
501 g_free(descriptionAddressPort); | |
502 g_free(fullURL); | |
503 g_free(httpRequest); | |
504 g_free(httpResponse); | |
11195 | 505 |
506 if(controlURL == NULL) { | |
11391 | 507 gaim_debug_error("upnp", |
11195 | 508 "gaim_upnp_parse_description(): controlURL is NULL\n\n"); |
509 return NULL; | |
510 } | |
511 | |
512 return controlURL; | |
513 } | |
514 | |
515 | |
11391 | 516 static gchar* |
517 gaim_upnp_parse_discover_response(const gchar* buf, | |
518 unsigned int bufSize, | |
519 const gchar* serviceType) | |
11195 | 520 { |
11391 | 521 gchar* startDescURL; |
522 gchar* endDescURL; | |
523 gchar* descURL; | |
524 gchar* retVal; | |
11195 | 525 |
11391 | 526 if(g_strstr_len(buf, strlen(buf), HTTP_OK) == NULL) { |
527 gaim_debug_error("upnp", | |
11195 | 528 "parse_discover_response(): Failed In HTTP_OK\n\n"); |
529 return NULL; | |
530 } | |
531 | |
11391 | 532 if((startDescURL = g_strstr_len(buf, strlen(buf), "http://")) == NULL) { |
533 gaim_debug_error("upnp", | |
534 "parse_discover_response(): Failed In finding http://\n\n"); | |
11195 | 535 return NULL; |
536 } | |
537 | |
11391 | 538 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\r"); |
11195 | 539 if(endDescURL == NULL) { |
11391 | 540 endDescURL = g_strstr_len(startDescURL, strlen(startDescURL), "\n"); |
11195 | 541 if(endDescURL == NULL) { |
11391 | 542 gaim_debug_error("upnp", |
543 "parse_discover_response(): Failed In endDescURL\n\n"); | |
11195 | 544 return NULL; |
545 }else if(endDescURL == startDescURL) { | |
11391 | 546 gaim_debug_error("upnp", |
547 "parse_discover_response(): endDescURL == startDescURL\n\n"); | |
11195 | 548 return NULL; |
549 } | |
550 }else if(endDescURL == startDescURL) { | |
11391 | 551 gaim_debug_error("upnp", |
552 "parse_discover_response(): 2nd endDescURL == startDescURL\n\n"); | |
11195 | 553 return NULL; |
554 } | |
11391 | 555 descURL = g_strndup(startDescURL, endDescURL-startDescURL); |
11195 | 556 |
11391 | 557 retVal = gaim_upnp_parse_description(descURL, serviceType); |
558 g_free(descURL); | |
11195 | 559 return retVal; |
560 } | |
561 | |
562 | |
563 | |
564 static void | |
565 gaim_upnp_discover_udp_read(gpointer data, | |
566 gint sock, | |
567 GaimInputCondition cond) | |
568 { | |
569 unsigned int length; | |
570 extern int errno; | |
571 struct sockaddr_in from; | |
572 int sizeRecv; | |
11391 | 573 NetResponseData* nrd = data; |
11195 | 574 |
11391 | 575 gaim_timeout_remove(nrd->tima); |
11195 | 576 length = sizeof(struct sockaddr_in); |
577 | |
578 do { | |
11391 | 579 sizeRecv = recvfrom(sock, nrd->recvBuffer, |
11492 | 580 MAX_DISCOVERY_RECEIVE_SIZE, 0, |
11195 | 581 (struct sockaddr*)&from, &length); |
582 | |
583 if(sizeRecv > 0) { | |
11391 | 584 nrd->recvBuffer[sizeRecv] = '\0'; |
11195 | 585 }else if(errno != EINTR) { |
11391 | 586 g_free(nrd->recvBuffer); |
587 nrd->recvBuffer = NULL; | |
11195 | 588 } |
589 }while(errno == EINTR); | |
590 | |
11391 | 591 gaim_input_remove(nrd->inpa); |
592 nrd->done = TRUE; | |
11195 | 593 return; |
594 } | |
595 | |
596 | |
11213 | 597 |
11391 | 598 GaimUPnPControlInfo* |
11195 | 599 gaim_upnp_discover(void) |
600 { | |
11391 | 601 /* Socket Setup Variables */ |
11195 | 602 int sock, i; |
603 extern int errno; | |
604 struct sockaddr_in server; | |
11391 | 605 struct hostent* hp; |
11195 | 606 |
11391 | 607 /* UDP SEND VARIABLES */ |
608 gboolean sentSuccess, recvSuccess; | |
609 int sizeSent, totalSizeSent; | |
610 gchar wanIP[] = "WANIPConnection:1"; | |
611 gchar wanPPP[] = "WANPPPConnection:1"; | |
612 gchar* serviceToUse; | |
613 gchar* sendMessage = NULL; | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
614 |
11492 | 615 /* UDP RECEIVE VARIABLES */ |
11391 | 616 GaimUPnPControlInfo* controlInfo = g_malloc(sizeof(GaimUPnPControlInfo)); |
617 NetResponseData* nrd = g_malloc(sizeof(NetResponseData)); | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
618 |
11391 | 619 /* Set up the sockets */ |
11195 | 620 sock = socket(AF_INET, SOCK_DGRAM, 0); |
621 if (sock == -1) { | |
622 close(sock); | |
11391 | 623 gaim_debug_error("upnp", |
11195 | 624 "gaim_upnp_discover(): Failed In sock creation\n\n"); |
11391 | 625 g_free(nrd); |
626 g_free(controlInfo); | |
11195 | 627 return NULL; |
628 } | |
629 memset(&server, 0, sizeof(struct sockaddr)); | |
630 server.sin_family = AF_INET; | |
631 if((hp = gethostbyname(HTTPMU_HOST_ADDRESS)) == NULL) { | |
632 close(sock); | |
11391 | 633 gaim_debug_error("upnp", |
11195 | 634 "gaim_upnp_discover(): Failed In gethostbyname\n\n"); |
11391 | 635 g_free(nrd); |
636 g_free(controlInfo); | |
11195 | 637 return NULL; |
638 } | |
639 memcpy(&server.sin_addr, | |
640 hp->h_addr_list[0], | |
641 hp->h_length); | |
642 server.sin_port = htons(HTTPMU_HOST_PORT); | |
643 | |
644 /* because we are sending over UDP, if there is a failure | |
11391 | 645 we should retry the send NUM_UDP_ATTEMPTS times. Also, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
646 try different requests for WANIPConnection and |
11391 | 647 WANPPPConnection*/ |
11195 | 648 for(i = 0; i < NUM_UDP_ATTEMPTS; i++) { |
649 sentSuccess = TRUE; | |
650 recvSuccess = TRUE; | |
651 totalSizeSent = 0; | |
652 | |
11391 | 653 nrd->recvBuffer = NULL; |
654 nrd->totalSizeRecv = 0; | |
655 nrd->done = FALSE; | |
656 | |
657 if(sendMessage != NULL) { | |
658 g_free(sendMessage); | |
659 } | |
11213 | 660 |
11391 | 661 if(i%2 == 0) { |
662 serviceToUse = wanIP; | |
663 } else { | |
664 serviceToUse = wanPPP; | |
11213 | 665 } |
11391 | 666 sendMessage = g_strdup_printf(SEARCH_REQUEST_STRING, serviceToUse); |
667 | |
11492 | 668 nrd->recvBuffer = (char*)g_malloc(MAX_DISCOVERY_RECEIVE_SIZE); |
11213 | 669 |
11195 | 670 while(totalSizeSent < strlen(sendMessage)) { |
671 sizeSent = sendto(sock,(void*)&sendMessage[totalSizeSent], | |
672 strlen(&sendMessage[totalSizeSent]),0, | |
673 (struct sockaddr*)&server, | |
674 sizeof(struct sockaddr_in)); | |
675 if(sizeSent <= 0 && errno != EINTR) { | |
676 sentSuccess = FALSE; | |
677 break; | |
678 }else if(errno == EINTR) { | |
679 sizeSent = 0; | |
680 } | |
681 totalSizeSent += sizeSent; | |
682 } | |
683 | |
684 if(sentSuccess) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
685 nrd->tima = gaim_timeout_add(DISCOVERY_TIMEOUT, |
11391 | 686 (GSourceFunc)gaim_upnp_timeout, nrd); |
687 nrd->inpa = gaim_input_add(sock, GAIM_INPUT_READ, | |
688 gaim_upnp_discover_udp_read, nrd); | |
689 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
690 g_main_context_iteration(NULL, TRUE); |
11195 | 691 } |
11391 | 692 if(nrd->recvBuffer == NULL) { |
11195 | 693 recvSuccess = FALSE; |
694 } else { | |
695 /* parse the response, and see if it was a success */ | |
696 close(sock); | |
11391 | 697 if((controlInfo->controlURL= |
698 gaim_upnp_parse_discover_response(nrd->recvBuffer, | |
699 strlen(nrd->recvBuffer), | |
700 serviceToUse))==NULL) { | |
701 gaim_debug_error("upnp", | |
11195 | 702 "gaim_upnp_discover(): Failed In parse response\n\n"); |
11391 | 703 g_free(nrd->recvBuffer); |
704 g_free(nrd); | |
705 g_free(controlInfo); | |
11195 | 706 return NULL; |
707 } | |
11391 | 708 |
709 controlInfo->serviceType = g_strdup(serviceToUse); | |
11195 | 710 } |
711 } | |
712 | |
713 /* if sent success and recv successful, then break */ | |
714 if(sentSuccess && recvSuccess) { | |
715 i = NUM_UDP_ATTEMPTS; | |
716 } | |
717 } | |
11213 | 718 |
11391 | 719 if(nrd->recvBuffer != NULL) { |
720 g_free(nrd->recvBuffer); | |
11213 | 721 } |
11391 | 722 g_free(sendMessage); |
723 g_free(nrd); | |
11213 | 724 |
11195 | 725 if(!sentSuccess || !recvSuccess) { |
726 close(sock); | |
11391 | 727 gaim_debug_error("upnp", |
11195 | 728 "gaim_upnp_discover(): Failed In sent/recv success\n\n"); |
11391 | 729 g_free(controlInfo); |
11195 | 730 return NULL; |
731 } | |
732 | |
11391 | 733 return controlInfo; |
11195 | 734 } |
735 | |
736 | |
737 static char* | |
11391 | 738 gaim_upnp_generate_action_message_and_send(const GaimUPnPControlInfo* controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
739 const gchar* actionName, |
11391 | 740 const gchar* actionParams) |
11195 | 741 { |
11391 | 742 gchar* actionMessage; |
743 gchar* soapMessage; | |
744 gchar* totalSendMessage; | |
745 gchar* httpResponse; | |
11195 | 746 |
11391 | 747 gchar* pathOfControl; |
748 gchar* addressOfControl; | |
749 gchar* addressPortOfControl; | |
750 gchar portOfControl[MAX_PORT_SIZE]; | |
751 int port=0; | |
11195 | 752 |
753 /* set the soap message */ | |
11391 | 754 soapMessage = g_strdup_printf(SOAP_ACTION, actionName, |
755 controlInfo->serviceType, | |
756 actionParams, actionName); | |
11195 | 757 |
758 /* parse the url into address, port, path variables */ | |
11391 | 759 if(!gaim_url_parse(controlInfo->controlURL, &addressOfControl, |
760 &port, &pathOfControl, NULL, NULL)) { | |
761 gaim_debug_error("upnp", | |
11195 | 762 "generate_action_message_and_send(): Failed In Parse URL\n\n"); |
11391 | 763 g_free(soapMessage); |
11195 | 764 return NULL; |
765 } | |
11391 | 766 if(port == 0 || port == -1) { |
767 port = DEFAULT_HTTP_PORT; | |
768 } | |
769 g_ascii_dtostr(portOfControl, MAX_PORT_SIZE, port); | |
11195 | 770 |
771 /* set the addressPortOfControl variable which should have a | |
772 form like the following: 192.168.1.1:8000 */ | |
11391 | 773 addressPortOfControl = g_strdup_printf("%s:%s", |
774 addressOfControl, portOfControl); | |
11195 | 775 |
776 /* set the HTTP Header */ | |
11391 | 777 actionMessage = g_strdup_printf(HTTP_HEADER_ACTION, |
778 pathOfControl, addressPortOfControl, | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
779 controlInfo->serviceType, actionName, |
11391 | 780 strlen(soapMessage)); |
11195 | 781 |
782 /* append to the header the body */ | |
11391 | 783 totalSendMessage = g_strdup_printf("%s%s", actionMessage, soapMessage); |
11195 | 784 |
785 /* get the return of the http response */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
786 httpResponse = gaim_upnp_http_request(addressOfControl, |
11391 | 787 port, totalSendMessage); |
11195 | 788 if(httpResponse == NULL) { |
11391 | 789 gaim_debug_error("upnp", |
11195 | 790 "generate_action_message_and_send(): Failed In httpResponse\n\n"); |
791 } | |
792 | |
11391 | 793 g_free(actionMessage); |
794 g_free(soapMessage); | |
795 g_free(totalSendMessage); | |
796 g_free(pathOfControl); | |
797 g_free(addressOfControl); | |
798 g_free(addressPortOfControl); | |
11195 | 799 |
800 return httpResponse; | |
801 } | |
802 | |
803 | |
804 | |
805 | |
11391 | 806 gchar* |
807 gaim_upnp_get_public_ip(const GaimUPnPControlInfo* controlInfo) | |
11195 | 808 { |
11391 | 809 gchar* extIPAddress; |
810 gchar* httpResponse; | |
811 gchar actionName[] = "GetExternalIPAddress"; | |
812 gchar actionParams[] = ""; | |
813 gchar* temp, *temp2; | |
11195 | 814 |
11391 | 815 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
816 actionName, |
11195 | 817 actionParams); |
818 if(httpResponse == NULL) { | |
11391 | 819 gaim_debug_error("upnp", |
11195 | 820 "gaim_upnp_get_public_ip(): Failed In httpResponse\n\n"); |
821 return NULL; | |
822 } | |
823 | |
824 /* extract the ip, or see if there is an error */ | |
11391 | 825 if((temp = g_strstr_len(httpResponse, strlen(httpResponse), |
826 "<NewExternalIPAddress")) == NULL) { | |
827 gaim_debug_error("upnp", | |
11195 | 828 "gaim_upnp_get_public_ip(): Failed Finding <NewExternalIPAddress\n\n"); |
11391 | 829 g_free(httpResponse); |
11195 | 830 return NULL; |
831 } | |
11391 | 832 if((temp = g_strstr_len(temp, strlen(temp), ">")) == NULL) { |
833 gaim_debug_error("upnp", | |
11195 | 834 "gaim_upnp_get_public_ip(): Failed In Finding >\n\n"); |
11391 | 835 g_free(httpResponse); |
11195 | 836 return NULL; |
837 } | |
11391 | 838 if((temp2 = g_strstr_len(temp, strlen(temp), "<")) == NULL) { |
839 gaim_debug_error("upnp", | |
11195 | 840 "gaim_upnp_get_public_ip(): Failed In Finding <\n\n"); |
11391 | 841 g_free(httpResponse); |
11195 | 842 return NULL; |
843 } | |
11391 | 844 |
845 extIPAddress = g_strndup(&temp[1], (temp2-1)-temp); | |
11195 | 846 |
11391 | 847 g_free(httpResponse); |
848 | |
849 gaim_debug_info("upnp", "NAT Returned IP: %s\n", extIPAddress); | |
11195 | 850 return extIPAddress; |
851 } | |
852 | |
11391 | 853 static void |
854 gaim_upnp_get_local_system_ip(gpointer data, | |
855 gint sock, | |
856 GaimInputCondition cond) | |
857 { | |
858 NetResponseData* nrd = data; | |
11443
d9d60002065b
[gaim-migrate @ 13682]
Richard Laager <rlaager@wiktel.com>
parents:
11391
diff
changeset
|
859 nrd->recvBuffer = g_strdup(gaim_network_get_local_system_ip(sock)); |
11195 | 860 |
11391 | 861 gaim_timeout_remove(nrd->tima); |
862 nrd->done = TRUE; | |
11195 | 863 |
11391 | 864 close(sock); |
865 } | |
11195 | 866 |
11492 | 867 static gchar* |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
868 gaim_upnp_get_local_ip_address(const gchar* address) |
11391 | 869 { |
11492 | 870 gchar* ip; |
11391 | 871 gchar* pathOfControl; |
872 gchar* addressOfControl; | |
873 int port = 0; | |
874 NetResponseData* nrd = (NetResponseData*)g_malloc0(sizeof(NetResponseData)); | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
875 |
11391 | 876 if(!gaim_url_parse(address, &addressOfControl, |
877 &port, &pathOfControl, NULL, NULL)) { | |
878 gaim_debug_error("upnp", | |
11195 | 879 "get_local_ip_address(): Failed In Parse URL\n\n"); |
880 return NULL; | |
881 } | |
11391 | 882 if(port == 0 || port == -1) { |
883 port = DEFAULT_HTTP_PORT; | |
11195 | 884 } |
885 | |
11492 | 886 nrd->tima = gaim_timeout_add(RECEIVE_TIMEOUT, |
11391 | 887 (GSourceFunc)gaim_upnp_timeout, nrd); |
888 | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
889 if(gaim_proxy_connect(NULL, addressOfControl, port, |
11391 | 890 gaim_upnp_get_local_system_ip, nrd)) { |
11195 | 891 |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
892 gaim_debug_error("upnp", "Get Local IP Connect Failed: Address: %s @@@ Port %d @@@ Request %s\n\n", |
11391 | 893 address, port, nrd->sendBuffer); |
894 | |
895 gaim_timeout_remove(nrd->tima); | |
896 } else { | |
897 while (!nrd->done) { | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
898 g_main_context_iteration(NULL, TRUE); |
11391 | 899 } |
11195 | 900 } |
901 | |
11391 | 902 ip = nrd->recvBuffer; |
903 g_free(nrd); | |
11195 | 904 |
11391 | 905 gaim_debug_info("upnp", "local ip: %s\n", ip); |
906 | |
11195 | 907 return ip; |
908 } | |
909 | |
910 | |
911 | |
912 gboolean | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
913 gaim_upnp_set_port_mapping(const GaimUPnPControlInfo* controlInfo, |
11391 | 914 unsigned short portMap, |
915 const gchar* protocol) | |
11195 | 916 { |
11391 | 917 gchar* httpResponse; |
918 gchar actionName[] = "AddPortMapping"; | |
919 gchar* actionParams; | |
11492 | 920 gchar* internalIP; |
11195 | 921 |
922 /* get the internal IP */ | |
11391 | 923 if((internalIP = gaim_upnp_get_local_ip_address(controlInfo->controlURL)) |
924 == NULL) { | |
925 gaim_debug_error("upnp", | |
11195 | 926 "gaim_upnp_set_port_mapping(): couldn't get local ip\n\n"); |
927 return FALSE; | |
928 } | |
929 | |
930 /* make the portMappingParams variable */ | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
931 actionParams = g_strdup_printf(ADD_PORT_MAPPING_PARAMS, portMap, |
11391 | 932 protocol, portMap, internalIP); |
11195 | 933 |
11391 | 934 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
935 actionName, |
11195 | 936 actionParams); |
937 if(httpResponse == NULL) { | |
11391 | 938 gaim_debug_error("upnp", |
11195 | 939 "gaim_upnp_set_port_mapping(): Failed In httpResponse\n\n"); |
11391 | 940 g_free(actionParams); |
11492 | 941 g_free(internalIP); |
11195 | 942 return FALSE; |
943 } | |
944 | |
945 /* determine if port mapping was a success */ | |
946 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
11391 | 947 gaim_debug_error("upnp", |
11195 | 948 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
11391 | 949 g_free(actionParams); |
950 g_free(httpResponse); | |
11492 | 951 g_free(internalIP); |
11195 | 952 return FALSE; |
953 } | |
954 | |
11391 | 955 g_free(actionParams); |
956 g_free(httpResponse); | |
957 | |
958 gaim_debug_info("upnp", "NAT Added Port Forward On Port: %d: To IP: %s\n", portMap, internalIP); | |
11492 | 959 g_free(internalIP); |
11195 | 960 return TRUE; |
961 } | |
962 | |
963 | |
964 gboolean | |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
965 gaim_upnp_remove_port_mapping(const GaimUPnPControlInfo* controlInfo, |
11391 | 966 unsigned short portMap, |
967 const char* protocol) | |
11195 | 968 { |
11391 | 969 gchar* httpResponse; |
970 gchar actionName[] = "DeletePortMapping"; | |
971 gchar* actionParams; | |
11195 | 972 |
973 /* make the portMappingParams variable */ | |
11391 | 974 actionParams = g_strdup_printf(DELETE_PORT_MAPPING_PARAMS, |
975 portMap, protocol); | |
11195 | 976 |
11391 | 977 httpResponse = gaim_upnp_generate_action_message_and_send(controlInfo, |
11566
7897207b522d
[gaim-migrate @ 13832]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11492
diff
changeset
|
978 actionName, |
11195 | 979 actionParams); |
980 | |
981 if(httpResponse == NULL) { | |
11391 | 982 gaim_debug_error("upnp", |
983 "gaim_upnp_remove_port_mapping(): Failed In httpResponse\n\n"); | |
984 g_free(actionParams); | |
11195 | 985 return FALSE; |
986 } | |
987 | |
988 /* determine if port mapping was a success */ | |
989 if(strstr(httpResponse, HTTP_OK) == NULL) { | |
11391 | 990 gaim_debug_error("upnp", |
11195 | 991 "gaim_upnp_set_port_mapping(): Failed HTTP_OK\n\n%s\n\n", httpResponse); |
11391 | 992 g_free(actionParams); |
993 g_free(httpResponse); | |
11195 | 994 return FALSE; |
995 } | |
996 | |
11391 | 997 g_free(actionParams); |
998 g_free(httpResponse); | |
999 | |
1000 gaim_debug_info("upnp", "NAT Removed Port Forward On Port: %d\n", portMap); | |
11195 | 1001 return TRUE; |
1002 } |