Coverage Report

Created: 2025-12-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}