/src/pidgin/libpurple/protocols/jabber/google/jingleinfo.c
Line | Count | Source |
1 | | /** |
2 | | * Purple is the legal property of its developers, whose names are too numerous |
3 | | * to list here. Please refer to the COPYRIGHT file distributed with this |
4 | | * source distribution. |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
19 | | */ |
20 | | |
21 | | #include "internal.h" |
22 | | #include "debug.h" |
23 | | #include "jingleinfo.h" |
24 | | |
25 | | static void |
26 | | jabber_google_stun_lookup_cb(GSList *hosts, gpointer data, |
27 | | const char *error_message) |
28 | 0 | { |
29 | 0 | JabberStream *js = (JabberStream *) data; |
30 | |
|
31 | 0 | if (error_message) { |
32 | 0 | purple_debug_error("jabber", "Google STUN lookup failed: %s\n", |
33 | 0 | error_message); |
34 | 0 | g_slist_free(hosts); |
35 | 0 | js->stun_query = NULL; |
36 | 0 | return; |
37 | 0 | } |
38 | | |
39 | 0 | if (hosts && g_slist_next(hosts)) { |
40 | 0 | struct sockaddr *addr = g_slist_next(hosts)->data; |
41 | 0 | char dst[INET6_ADDRSTRLEN]; |
42 | 0 | int port; |
43 | |
|
44 | 0 | if (addr->sa_family == AF_INET6) { |
45 | 0 | inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr, |
46 | 0 | dst, sizeof(dst)); |
47 | 0 | port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); |
48 | 0 | } else { |
49 | 0 | inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr, |
50 | 0 | dst, sizeof(dst)); |
51 | 0 | port = ntohs(((struct sockaddr_in *) addr)->sin_port); |
52 | 0 | } |
53 | |
|
54 | 0 | if (js->stun_ip) |
55 | 0 | g_free(js->stun_ip); |
56 | 0 | js->stun_ip = g_strdup(dst); |
57 | 0 | js->stun_port = port; |
58 | |
|
59 | 0 | purple_debug_info("jabber", "set Google STUN IP/port address: " |
60 | 0 | "%s:%d\n", dst, port); |
61 | | |
62 | | /* unmark ongoing query */ |
63 | 0 | js->stun_query = NULL; |
64 | 0 | } |
65 | |
|
66 | 0 | while (hosts != NULL) { |
67 | 0 | hosts = g_slist_delete_link(hosts, hosts); |
68 | | /* Free the address */ |
69 | 0 | g_free(hosts->data); |
70 | 0 | hosts = g_slist_delete_link(hosts, hosts); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | static void |
75 | | jabber_google_jingle_info_common(JabberStream *js, const char *from, |
76 | | JabberIqType type, xmlnode *query) |
77 | 0 | { |
78 | 0 | const xmlnode *stun = xmlnode_get_child(query, "stun"); |
79 | 0 | const xmlnode *relay = xmlnode_get_child(query, "relay"); |
80 | 0 | gchar *my_bare_jid; |
81 | | |
82 | | /* |
83 | | * Make sure that random people aren't sending us STUN servers. Per |
84 | | * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these |
85 | | * stanzas are stamped from our bare JID. |
86 | | */ |
87 | 0 | if (from) { |
88 | 0 | my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); |
89 | 0 | if (!purple_strequal(from, my_bare_jid)) { |
90 | 0 | purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n", |
91 | 0 | from); |
92 | 0 | g_free(my_bare_jid); |
93 | 0 | return; |
94 | 0 | } |
95 | | |
96 | 0 | g_free(my_bare_jid); |
97 | 0 | } |
98 | | |
99 | 0 | if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET) |
100 | 0 | return; |
101 | | |
102 | 0 | purple_debug_info("jabber", "got google:jingleinfo\n"); |
103 | |
|
104 | 0 | if (stun) { |
105 | 0 | xmlnode *server = xmlnode_get_child(stun, "server"); |
106 | |
|
107 | 0 | if (server) { |
108 | 0 | const gchar *host = xmlnode_get_attrib(server, "host"); |
109 | 0 | const gchar *udp = xmlnode_get_attrib(server, "udp"); |
110 | |
|
111 | 0 | if (host && udp) { |
112 | 0 | PurpleAccount *account; |
113 | 0 | int port = atoi(udp); |
114 | | /* if there, would already be an ongoing query, |
115 | | cancel it */ |
116 | 0 | if (js->stun_query) |
117 | 0 | purple_dnsquery_destroy(js->stun_query); |
118 | |
|
119 | 0 | account = purple_connection_get_account(js->gc); |
120 | 0 | js->stun_query = purple_dnsquery_a_account(account, host, port, |
121 | 0 | jabber_google_stun_lookup_cb, js); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | |
|
126 | 0 | if (relay) { |
127 | 0 | xmlnode *token = xmlnode_get_child(relay, "token"); |
128 | 0 | xmlnode *server = xmlnode_get_child(relay, "server"); |
129 | |
|
130 | 0 | if (token) { |
131 | 0 | gchar *relay_token = xmlnode_get_data(token); |
132 | | |
133 | | /* we let js own the string returned from xmlnode_get_data */ |
134 | 0 | js->google_relay_token = relay_token; |
135 | 0 | } |
136 | |
|
137 | 0 | if (server) { |
138 | 0 | js->google_relay_host = |
139 | 0 | g_strdup(xmlnode_get_attrib(server, "host")); |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | static void |
145 | | jabber_google_jingle_info_cb(JabberStream *js, const char *from, |
146 | | JabberIqType type, const char *id, |
147 | | xmlnode *packet, gpointer data) |
148 | 0 | { |
149 | 0 | xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", |
150 | 0 | NS_GOOGLE_JINGLE_INFO); |
151 | |
|
152 | 0 | if (query) |
153 | 0 | jabber_google_jingle_info_common(js, from, type, query); |
154 | 0 | else |
155 | 0 | purple_debug_warning("jabber", "Got invalid google:jingleinfo\n"); |
156 | 0 | } |
157 | | |
158 | | void |
159 | | jabber_google_handle_jingle_info(JabberStream *js, const char *from, |
160 | | JabberIqType type, const char *id, |
161 | | xmlnode *child) |
162 | 0 | { |
163 | 0 | jabber_google_jingle_info_common(js, from, type, child); |
164 | 0 | } |
165 | | |
166 | | void |
167 | | jabber_google_send_jingle_info(JabberStream *js) |
168 | 0 | { |
169 | 0 | JabberIq *jingle_info = |
170 | 0 | jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO); |
171 | |
|
172 | 0 | jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb, |
173 | | NULL); |
174 | 0 | purple_debug_info("jabber", "sending google:jingleinfo query\n"); |
175 | 0 | jabber_iq_send(jingle_info); |
176 | 0 | } |