[svn-commits] dvossel: branch 1.8 r291827 - /branches/1.8/channels/chan_gtalk.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Thu Oct 14 16:27:46 CDT 2010
Author: dvossel
Date: Thu Oct 14 16:27:42 2010
New Revision: 291827
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=291827
Log:
Safer xml parsing, treat all clients the same, and better local candidate selection.
The gtalk channel driver was doing several unsafe operations
in regards to how it parsed incoming XML messages. I have cleaned
that code up so it should be much safer now.
We now treat all clients types the same. We have no reason to
distinguish between GMAIL and GOOGLE VOICE clients anymore because
they all work the same way.
I also modified how the local ip is found. If no bindaddress is provided
in the config file, we attempt to determine the local ip we
would use to connect to google.com. If that fails, then
we fall back to the ast_find_ourip() function as a last resort.
Using the new method makes it much less likely that we would ever
advertise a local RTP candidate as a loopback address.
Modified:
branches/1.8/channels/chan_gtalk.c
Modified: branches/1.8/channels/chan_gtalk.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_gtalk.c?view=diff&rev=291827&r1=291826&r2=291827
==============================================================================
--- branches/1.8/channels/chan_gtalk.c (original)
+++ branches/1.8/channels/chan_gtalk.c Thu Oct 14 16:27:42 2010
@@ -100,14 +100,6 @@
AJI_CONNECT_RELAY = 3,
};
-enum gtalk_client_type {
- AJI_CLIENT_UNKNOWN,
- AJI_CLIENT_GTALK, /*!< Remote client type is GoogleTalk */
- AJI_CLIENT_GMAIL, /*!< Remote client type is Gmail */
- AJI_CLIENT_GOOGLE_VOICE,/*!< Remote client type is Google Voice*/
-
-};
-
struct gtalk_pvt {
ast_mutex_t lock; /*!< Channel private lock */
time_t laststun;
@@ -118,7 +110,6 @@
char ring[10]; /*!< Message ID of ring */
iksrule *ringrule; /*!< Rule for matching RING request */
int initiator; /*!< If we're the initiator */
- enum gtalk_client_type ctype;
int alreadygone;
int capability;
struct ast_codec_pref prefs;
@@ -452,9 +443,6 @@
iks_insert_attrib(gtalk, "id", sid);
iks_insert_node(iq, gtalk);
iks_insert_node(gtalk, dcodecs);
- if (p->ctype != AJI_CLIENT_GOOGLE_VOICE) {
- iks_insert_node(gtalk, transport);
- }
iks_insert_node(dcodecs, payload_telephone);
ast_aji_send(client->connection, iq);
@@ -465,49 +453,6 @@
iks_delete(gtalk);
iks_delete(iq);
return 1;
-}
-
-static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator)
-{
- iks *iq, *session, *transport;
- char *lowerto = NULL;
-
- iq = iks_new("iq");
- session = iks_new("session");
- transport = iks_new("transport");
- if(!(iq && session && transport)) {
- iks_delete(iq);
- iks_delete(session);
- iks_delete(transport);
- ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
- return -1;
- }
- iks_insert_attrib(iq, "from", from);
- iks_insert_attrib(iq, "to", to);
- iks_insert_attrib(iq, "type", "set");
- iks_insert_attrib(iq, "id",p->parent->connection->mid);
- ast_aji_increment_mid(p->parent->connection->mid);
- iks_insert_attrib(session, "type", "transport-accept");
- iks_insert_attrib(session, "id", sid);
- /* put the initiator attribute to lower case if we receive the call
- * otherwise GoogleTalk won't establish the session */
- if (!initiator) {
- char c;
- char *t = lowerto = ast_strdupa(to);
- while (((c = *t) != '/') && (*t++ = tolower(c)));
- }
- iks_insert_attrib(session, "initiator", initiator ? from : lowerto);
- iks_insert_attrib(session, "xmlns", GOOGLE_NS);
- iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
- iks_insert_node(iq,session);
- iks_insert_node(session,transport);
- ast_aji_send(p->parent->connection, iq);
-
- iks_delete(transport);
- iks_delete(session);
- iks_delete(iq);
- return 1;
-
}
static int gtalk_ringing_ack(void *data, ikspak *pak)
@@ -597,8 +542,8 @@
if (response) {
iks_insert_attrib(response, "type", "result");
iks_insert_attrib(response, "from", from);
- iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
- iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
+ iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
+ iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
if (reasonstr) {
error = iks_new("error");
if (error) {
@@ -647,8 +592,24 @@
/* codec points to the first <payload-type/> tag */
codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
while (codec) {
- ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp, atoi(iks_find_attrib(codec, "id")));
- ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+ char *codec_id = iks_find_attrib(codec, "id");
+ char *codec_name = iks_find_attrib(codec, "name");
+ if (!codec_id || !codec_name) {
+ codec = iks_next_tag(codec);
+ continue;
+ }
+
+ ast_rtp_codecs_payloads_set_m_type(
+ ast_rtp_instance_get_codecs(tmp->rtp),
+ tmp->rtp,
+ atoi(codec_id));
+ ast_rtp_codecs_payloads_set_rtpmap_type(
+ ast_rtp_instance_get_codecs(tmp->rtp),
+ tmp->rtp,
+ atoi(codec_id),
+ "audio",
+ codec_name,
+ 0);
codec = iks_next_tag(codec);
}
@@ -810,6 +771,34 @@
return 1;
}
+static int gtalk_get_local_ip(struct ast_sockaddr *ourip)
+{
+ struct ast_sockaddr root;
+ struct ast_sockaddr bindaddr_tmp;
+ struct ast_sockaddr *addrs;
+ int addrs_cnt;
+
+ /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
+ ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
+ if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
+ ast_sockaddr_copy(ourip, &bindaddr_tmp);
+ return 0;
+ }
+
+ /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
+ * If you can't resolve google.com from your network, then this module is useless for you anyway. */
+ if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
+ ast_sockaddr_copy(&root, &addrs[0]);
+ ast_free(addrs);
+ if (!ast_ouraddrfor(&root, ourip)) {
+ return 0;
+ }
+ }
+
+ /* As a last resort, use this function to find our local address. */
+ return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
+}
+
static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
{
struct gtalk_candidate *tmp;
@@ -817,7 +806,6 @@
struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
struct sockaddr_in sin = { 0, };
struct ast_sockaddr sin_tmp;
- struct ast_sockaddr bindaddr_tmp;
struct ast_sockaddr us;
iks *iq, *gtalk, *candidate, *transport;
char user[17], pass[17], preference[5], port[7];
@@ -838,13 +826,8 @@
iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
iks_insert_node(iq, gtalk);
-
- if (p->ctype == AJI_CLIENT_GMAIL) {
- iks_insert_node(gtalk,candidate);
- } else {
- iks_insert_node(gtalk,candidate);
- iks_insert_node(gtalk,transport);
- }
+ iks_insert_node(gtalk,candidate);
+ iks_insert_node(gtalk,transport);
for (; p; p = p->next) {
if (!strcasecmp(p->sid, sid))
@@ -858,8 +841,9 @@
ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
ast_sockaddr_to_sin(&sin_tmp, &sin);
- ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
- ast_find_ourip(&us, &bindaddr_tmp, AF_INET);
+
+ gtalk_get_local_ip(&us);
+
if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
}
@@ -906,18 +890,7 @@
iks_insert_attrib(iq, "type", "set");
iks_insert_attrib(iq, "id", c->mid);
ast_aji_increment_mid(c->mid);
- switch (p->ctype) {
- case AJI_CLIENT_GTALK:
- iks_insert_attrib(gtalk, "type", "transport-info");
- break;
- case AJI_CLIENT_GMAIL:
- iks_insert_attrib(gtalk, "type", "candidates");
- break;
- default:
- ast_log(LOG_WARNING, "Client type is unknown\n");
- iks_insert_attrib(gtalk, "type", "candidates");
- break;
- }
+ iks_insert_attrib(gtalk, "type", "candidates");
iks_insert_attrib(gtalk, "id", sid);
/* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */
@@ -971,7 +944,6 @@
char idroster[200];
char *data, *exten = NULL;
struct ast_sockaddr bindaddr_tmp;
- enum gtalk_client_type ctype = AJI_CLIENT_UNKNOWN;
ast_debug(1, "The client is %s for alloc\n", client->name);
if (!sid && !strchr(them, '/')) { /* I started call! */
@@ -992,12 +964,8 @@
}
if (resources) {
snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
- if (strstr(resources->resource, "gmail")) {
- ctype = AJI_CLIENT_GMAIL;
- }
} else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
snprintf(idroster, sizeof(idroster), "%s/srvres", them);
- ctype = AJI_CLIENT_GOOGLE_VOICE;
} else {
ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
return NULL;
@@ -1006,8 +974,6 @@
if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
return NULL;
}
- /* set client type to unknown until we have more info */
- tmp->ctype = ctype;
memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
@@ -1036,10 +1002,11 @@
ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
/* add user configured codec capabilites */
- if (client->capability)
+ if (client->capability) {
tmp->capability = client->capability;
- else if (global_capability)
+ } else if (global_capability) {
tmp->capability = global_capability;
+ }
tmp->parent = client;
if (!tmp->rtp) {
@@ -1054,8 +1021,9 @@
if(strchr(tmp->us, '/')) {
data = ast_strdupa(tmp->us);
exten = strsep(&data, "/");
- } else
+ } else {
exten = tmp->us;
+ }
ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
ast_mutex_init(&tmp->lock);
ast_mutex_lock(>alklock);
@@ -1280,14 +1248,6 @@
return -1;
}
- /* if the node name of the query contains a semicolon, the remote peer
- * is a gmail type client. If not, treat it as a regular GoogleTalk
- * client */
- if (strchr(iks_name(pak->query), ':')) {
- p->ctype = AJI_CLIENT_GMAIL;
- } else {
- p->ctype = AJI_CLIENT_GTALK;
- }
chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
if (!chan) {
gtalk_free_pvt(client, p);
@@ -1308,12 +1268,30 @@
codec = iks_next_tag(codec);
continue;
}
- if (!strcmp(iks_name(codec), "vid:payload-type") && p->vrtp) {
- ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->vrtp), p->vrtp, atoi(codec_id));
- ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->vrtp), p->vrtp, atoi(codec_id), "video", codec_name, 0);
+ if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
+ ast_rtp_codecs_payloads_set_m_type(
+ ast_rtp_instance_get_codecs(p->vrtp),
+ p->vrtp,
+ atoi(codec_id));
+ ast_rtp_codecs_payloads_set_rtpmap_type(
+ ast_rtp_instance_get_codecs(p->vrtp),
+ p->vrtp,
+ atoi(codec_id),
+ "video",
+ codec_name,
+ 0);
} else {
- ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(codec_id));
- ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(codec_id), "audio", codec_name, 0);
+ ast_rtp_codecs_payloads_set_m_type(
+ ast_rtp_instance_get_codecs(p->rtp),
+ p->rtp,
+ atoi(codec_id));
+ ast_rtp_codecs_payloads_set_rtpmap_type(
+ ast_rtp_instance_get_codecs(p->rtp),
+ p->rtp,
+ atoi(codec_id),
+ "audio",
+ codec_name,
+ 0);
}
codec = iks_next_tag(codec);
}
@@ -1349,9 +1327,6 @@
break;
case AST_PBX_SUCCESS:
gtalk_response(client, from, pak, NULL, NULL);
- if (p->ctype == AJI_CLIENT_GTALK) {
- gtalk_invite_response(p, p->them, p->us,p->sid, 0);
- }
gtalk_create_candidates(client, p, p->sid, p->them, p->us);
/* nothing to do */
break;
@@ -1477,15 +1452,15 @@
}
traversenodes = pak->query;
while(traversenodes) {
- if(!strcasecmp(iks_name(traversenodes), "session")) {
+ if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
traversenodes = iks_first_tag(traversenodes);
continue;
}
- if(!strcasecmp(iks_name(traversenodes), "ses:session")) {
+ if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
traversenodes = iks_child(traversenodes);
continue;
}
- if(!strcasecmp(iks_name(traversenodes), "candidate") || !strcasecmp(iks_name(traversenodes), "ses:candidate")) {
+ if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
newcandidate = ast_calloc(1, sizeof(*newcandidate));
if (!newcandidate)
return 0;
@@ -1655,7 +1630,7 @@
ast_moh_stop(ast);
break;
default:
- ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
+ ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
res = -1;
}
@@ -1779,24 +1754,6 @@
return -1;
}
-/* Not in use right now.
-static int gtalk_auto_congest(void *nothing)
-{
- struct gtalk_pvt *p = nothing;
-
- ast_mutex_lock(&p->lock);
- if (p->owner) {
- if (!ast_channel_trylock(p->owner)) {
- ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- ast_channel_unlock(p->owner);
- }
- }
- ast_mutex_unlock(&p->lock);
- return 0;
-}
-*/
-
/*!\brief Initiate new call, part of PBX interface
* dest is the dial string */
static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
@@ -1813,8 +1770,9 @@
ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
IKS_RULE_ID, p->ring, IKS_RULE_DONE);
- } else
+ } else {
ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
+ }
gtalk_invite(p, p->them, p->us, p->sid, 1);
gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
@@ -1855,8 +1813,9 @@
s = ast_strdupa(data);
if (s) {
sender = strsep(&s, "/");
- if (sender && (sender[0] != '\0'))
+ if (sender && (sender[0] != '\0')) {
to = strsep(&s, "/");
+ }
if (!to) {
ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
return NULL;
@@ -2217,7 +2176,7 @@
}
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
- if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp, AF_INET)) {
+ if (gtalk_get_local_ip(&ourip_tmp)) {
ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
return 0;
}
@@ -2279,4 +2238,4 @@
.unload = unload_module,
/* .reload = reload, */
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
- );
+ );
More information about the svn-commits
mailing list