diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_gtalk.c | 225 |
1 files changed, 92 insertions, 133 deletions
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index 36ef90307..05d493a00 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -100,14 +100,6 @@ enum gtalk_connect_type { 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 @@ struct gtalk_pvt { 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 @@ static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, in 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); @@ -467,49 +455,6 @@ static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, in 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) { struct gtalk_pvt *p = data; @@ -597,8 +542,8 @@ static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const c 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 @@ static int gtalk_is_answered(struct gtalk *client, ikspak *pak) /* 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 @@ static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak) 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 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch 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 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch 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 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch 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 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch 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 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const 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 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const } 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 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const 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 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const 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 @@ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const 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 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) 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 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) 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 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) 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 @@ static int gtalk_add_candidate(struct gtalk *client, ikspak *pak) } 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 @@ static int gtalk_indicate(struct ast_channel *ast, int condition, const void *da 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 @@ static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *dat 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 @@ static int gtalk_call(struct ast_channel *ast, char *dest, int timeout) 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 @@ static struct ast_channel *gtalk_request(const char *type, format_t format, cons 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 @@ static int load_module(void) } 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 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver" .unload = unload_module, /* .reload = reload, */ .load_pri = AST_MODPRI_CHANNEL_DRIVER, - ); + ); |