From 0736871cc67ba6c234bfefc6d87a567ad48df510 Mon Sep 17 00:00:00 2001 From: David Vossel Date: Mon, 11 Oct 2010 21:39:37 +0000 Subject: Merged revisions 291192 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r291192 | dvossel | 2010-10-11 16:38:39 -0500 (Mon, 11 Oct 2010) | 19 lines Gtalk enhancements and general code cleanup. This patch includes several chan_gtalk enhancements. Two new gtalk.conf options have been added, externip and stunadd. Setting externip allows us to manually specify what the external IP address is outside of a NAT environment. Setting the stunaddr option to a valid stun server allows for that external ip to be retrieved via a STUN server automatically. This external IP is then advertised during call setup as a possible candidate. I have also attempted to clean up chan_gtalk's code so it meets our coding guidelines. During this cleanup I noticed several things that need to be done in the code and made a TODO section at the top of the file. ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@291193 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_gtalk.c | 264 +++++++++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 134 deletions(-) (limited to 'channels/chan_gtalk.c') diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index 1aad3fbc2..1d6b1556d 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -25,6 +25,10 @@ * \brief Gtalk Channel Driver, until google/libjingle works with jingle spec * * \ingroup channel_drivers + * + * ********** General TODO:s + * \todo Support config reloading. + * \todo Fix native bridging. */ /*** MODULEINFO @@ -33,6 +37,7 @@ openssl ***/ + #include "asterisk.h" ASTERISK_FILE_VERSION(__FILE__, "$Revision$") @@ -193,8 +198,10 @@ static int gtalk_indicate(struct ast_channel *ast, int condition, const void *da static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid); -static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); +static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p); +/* static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); */ static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); +static int gtalk_update_externip(void); /*! \brief PBX interface structure for channel registration */ static const struct ast_channel_tech gtalk_tech = { @@ -228,11 +235,12 @@ static struct io_context *io; /*!< The IO context */ static struct in_addr __ourip; static struct ast_cli_entry gtalk_cli[] = { - AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"), +/* AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"), XXX TODO reloads are not possible yet. */ AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"), }; static char externip[16]; +static struct sockaddr_in stunaddr; /*!< the stun server we get the externip from */ static struct gtalk_container gtalk_list; @@ -631,7 +639,7 @@ static int gtalk_is_answered(struct gtalk *client, ikspak *pak) } } - if (tmp == 0) { + if (!tmp) { ast_log(LOG_WARNING, "Could not find session in iq\n"); return -1; } @@ -662,14 +670,14 @@ static int gtalk_is_answered(struct gtalk *client, ikspak *pak) } from = iks_find_attrib(pak->x, "to"); - if(!from) + if (!from) { from = client->connection->jid->full; + } - if (tmp) { - if (tmp->owner) - ast_queue_control(tmp->owner, AST_CONTROL_ANSWER); - } else - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); + if (tmp->owner) { + ast_queue_control(tmp->owner, AST_CONTROL_ANSWER); + } + gtalk_update_stun(tmp->parent, tmp); gtalk_response(client, from, pak, NULL, NULL); return 1; } @@ -682,16 +690,21 @@ static int gtalk_is_accepted(struct gtalk *client, ikspak *pak) ast_log(LOG_DEBUG, "The client is %s\n", client->name); /* find corresponding call */ for (tmp = client->p; tmp; tmp = tmp->next) { - if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) + if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { break; + } } from = iks_find_attrib(pak->x, "to"); - if(!from) + if (!from) { from = client->connection->jid->full; + } - if (!tmp) - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); + if (tmp) { + gtalk_update_stun(tmp->parent, tmp); + } else { + ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n"); + } /* answer 'iq' packet to let the remote peer know that we're alive */ gtalk_response(client, from, pak, NULL, NULL); @@ -710,9 +723,9 @@ static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak) break; } from = iks_find_attrib(pak->x, "to"); - if(!from) + if (!from) { from = client->connection->jid->full; - + } if (tmp) { if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) { @@ -759,8 +772,9 @@ static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak) } gtalk_response(client, from, pak, NULL, NULL); return 1; - } else + } else { ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); + } gtalk_response(client, from, pak, NULL, NULL); return 1; @@ -778,15 +792,18 @@ static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak) break; } from = iks_find_attrib(pak->x, "to"); - if(!from) + if (!from) { from = client->connection->jid->full; + } if (tmp) { tmp->alreadygone = 1; - if (tmp->owner) + if (tmp->owner) { ast_queue_hangup(tmp->owner); - } else - ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); + } + } else { + ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n"); + } gtalk_response(client, from, pak, NULL, NULL); return 1; } @@ -799,13 +816,11 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch struct sockaddr_in sin = { 0, }; struct ast_sockaddr sin_tmp; struct ast_sockaddr bindaddr_tmp; - struct sockaddr_in dest; struct ast_sockaddr us; iks *iq, *gtalk, *candidate, *transport; char user[17], pass[17], preference[5], port[7]; char *lowerfrom = NULL; - iq = iks_new("iq"); gtalk = iks_new("session"); candidate = iks_new("candidate"); @@ -821,12 +836,14 @@ 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,transport); iks_insert_node(gtalk,candidate); } + for (; p; p = p->next) { if (!strcasecmp(p->sid, sid)) break; @@ -860,10 +877,11 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch ours1->generation = 0; p->ourcandidates = ours1; + /* XXX this is a blocking action. We send a STUN request to the server + * and wait for the response. If blocking here is a problem the STUN requests/responses + * for the externip may need to be done differently. */ + gtalk_update_externip(); if (!ast_strlen_zero(externip)) { - /* XXX We should really stun for this one not just go with externip XXX */ - snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random()); - snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random()); ast_copy_string(ours2->username, user, sizeof(ours2->username)); ast_copy_string(ours2->password, pass, sizeof(ours2->password)); ast_copy_string(ours2->ip, externip, sizeof(ours2->ip)); @@ -877,9 +895,6 @@ static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, ch ours2 = NULL; } ours1 = NULL; - dest.sin_addr = __ourip; - dest.sin_port = sin.sin_port; - for (tmp = p->ourcandidates; tmp; tmp = tmp->next) { snprintf(port, sizeof(port), "%d", tmp->port); @@ -1227,7 +1242,7 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) /* Make sure our new call doesn't exist yet */ from = iks_find_attrib(pak->x,"to"); - if(!from) { + if (!from) { from = client->connection->jid->full; } @@ -1333,6 +1348,45 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) return 1; } +static int gtalk_update_externip(void) +{ + int sock; + char *newaddr; + struct sockaddr_in answer = { 0, }; + struct sockaddr_in *dst; + struct ast_sockaddr tmp_dst; + + if (!stunaddr.sin_addr.s_addr) { + return -1; + } + dst = &stunaddr; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno)); + return -1; + } + + ast_sockaddr_from_sin(&tmp_dst, dst); + if (ast_connect(sock, &tmp_dst) != 0) { + ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst)); + close(sock); + return -1; + } + + if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) { + close(sock); + return -1; + } + + newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr)); + memcpy(externip, newaddr, sizeof(externip)); + + close(sock); + return 0; + +} + static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p) { struct gtalk_candidate *tmp; @@ -1363,8 +1417,8 @@ static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p) ast_sockaddr_to_sin(&aux_tmp, &aux); /* If the STUN result is different from the IP of the hostname, - lock on the stun IP of the hostname advertised by the - remote client */ + * lock on the stun IP of the hostname advertised by the + * remote client */ if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) { ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username); } else { @@ -1390,8 +1444,9 @@ static int gtalk_add_candidate(struct gtalk *client, ikspak *pak) char *from; from = iks_find_attrib(pak->x,"to"); - if(!from) + if (!from) { from = c->jid->full; + } for (tmp = client->p; tmp; tmp = tmp->next) { if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid)) { @@ -1472,8 +1527,9 @@ static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pv { struct ast_frame *f; - if (!p->rtp) + if (!p->rtp) { return &ast_null_frame; + } f = ast_rtp_instance_read(p->rtp, 0); gtalk_update_stun(p->parent, p); if (p->owner) { @@ -1486,11 +1542,11 @@ static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pv ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); } -/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { + /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { f = ast_dsp_process(p->owner, p->vad, f); if (option_debug && f && (f->frametype == AST_FRAME_DTMF)) ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass); - } */ + } */ } } return f; @@ -1668,8 +1724,8 @@ static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duratio ast_aji_increment_mid(client->connection->mid); iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk"); iks_insert_attrib(gtalk, "action", "session-info"); - /* put the initiator attribute to lower case if we receive the call - * otherwise GoogleTalk won't establish the session */ + // put the initiator attribute to lower case if we receive the call + // otherwise GoogleTalk won't establish the session if (!p->initiator) { char c; char *t = lowerthem = ast_strdupa(p->them); @@ -1758,8 +1814,9 @@ static int gtalk_hangup(struct ast_channel *ast) client = p->parent; p->owner = NULL; ast->tech_pvt = NULL; - if (!p->alreadygone) + if (!p->alreadygone) { gtalk_action(client, p, "terminate"); + } ast_mutex_unlock(&p->lock); gtalk_free_pvt(client, p); @@ -1878,7 +1935,9 @@ static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl #undef FORMAT } -/*! \brief CLI command "gtalk reload" */ +/*! \brief CLI command "gtalk reload" + * \todo XXX TODO make this work. */ +#if 0 static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { switch (cmd) { @@ -1895,6 +1954,7 @@ static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_verbose("IT DOES WORK!\n"); return CLI_SUCCESS; } +#endif static int gtalk_parser(void *data, ikspak *pak) { @@ -1929,53 +1989,6 @@ static int gtalk_parser(void *data, ikspak *pak) return IKS_FILTER_EAT; } -/* Not using this anymore probably take out soon -static struct gtalk_candidate *gtalk_create_candidate(char *args) -{ - char *name, *type, *preference, *protocol; - struct gtalk_candidate *res; - res = ast_calloc(1, sizeof(*res)); - if (args) - name = args; - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - preference = args; - } - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - protocol = args; - } - if ((args = strchr(args, ','))) { - *args = '\0'; - args++; - type = args; - } - if (name) - ast_copy_string(res->name, name, sizeof(res->name)); - if (preference) { - res->preference = atof(preference); - } - if (protocol) { - if (!strcasecmp("udp", protocol)) - res->protocol = AJI_PROTOCOL_UDP; - if (!strcasecmp("ssltcp", protocol)) - res->protocol = AJI_PROTOCOL_SSLTCP; - } - if (type) { - if (!strcasecmp("stun", type)) - res->type = AJI_CONNECT_STUN; - if (!strcasecmp("local", type)) - res->type = AJI_CONNECT_LOCAL; - if (!strcasecmp("relay", type)) - res->type = AJI_CONNECT_RELAY; - } - - return res; -} -*/ - static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest, struct ast_codec_pref prefs, char *context, struct gtalk *member) @@ -1991,9 +2004,6 @@ static int gtalk_create_member(char *label, struct ast_variable *var, int allowg member->allowguest = allowguest; member->prefs = prefs; while (var) { -#if 0 - struct gtalk_candidate *candidate = NULL; -#endif if (!strcasecmp(var->name, "username")) ast_copy_string(member->user, var->value, sizeof(member->user)); else if (!strcasecmp(var->name, "disallow")) @@ -2004,15 +2014,6 @@ static int gtalk_create_member(char *label, struct ast_variable *var, int allowg ast_copy_string(member->context, var->value, sizeof(member->context)); else if (!strcasecmp(var->name, "parkinglot")) ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot)); -#if 0 - else if (!strcasecmp(var->name, "candidate")) { - candidate = gtalk_create_candidate(var->value); - if (candidate) { - candidate->next = member->ourcandidates; - member->ourcandidates = candidate; - } - } -#endif else if (!strcasecmp(var->name, "connection")) { if ((client = ast_aji_get_client(var->value))) { member->connection = client; @@ -2021,7 +2022,6 @@ static int gtalk_create_member(char *label, struct ast_variable *var, int allowg IKS_RULE_FROM_PARTIAL, member->user, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE); - } else { ast_log(LOG_ERROR, "connection referenced not found!\n"); return 0; @@ -2064,40 +2064,39 @@ static int gtalk_load_config(void) /* Copy the default jb config over global_jbconf */ memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); + /* set defaults */ + memset(&stunaddr, 0, sizeof(stunaddr)); + cat = ast_category_browse(cfg, NULL); for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { /* handle jb conf */ if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) continue; - if (!strcasecmp(var->name, "allowguest")) - allowguest = - (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0; - else if (!strcasecmp(var->name, "disallow")) + if (!strcasecmp(var->name, "allowguest")) { + allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0; + } else if (!strcasecmp(var->name, "disallow")) { ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0); - else if (!strcasecmp(var->name, "allow")) + } else if (!strcasecmp(var->name, "allow")) { ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1); - else if (!strcasecmp(var->name, "context")) + } else if (!strcasecmp(var->name, "context")) { ast_copy_string(context, var->value, sizeof(context)); - else if (!strcasecmp(var->name, "parkinglot")) + } else if (!strcasecmp(var->name, "externip")) { + ast_copy_string(externip, var->value, sizeof(externip)); + } else if (!strcasecmp(var->name, "parkinglot")) { ast_copy_string(parkinglot, var->value, sizeof(parkinglot)); - else if (!strcasecmp(var->name, "bindaddr")) { + } else if (!strcasecmp(var->name, "bindaddr")) { if (!(hp = ast_gethostbyname(var->value, &ahp))) { ast_log(LOG_WARNING, "Invalid address: %s\n", var->value); } else { memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); } - } -/* Idea to allow for custom candidates */ -/* - else if (!strcasecmp(var->name, "candidate")) { - candidate = gtalk_create_candidate(var->value); - if (candidate) { - candidate->next = global_candidates; - global_candidates = candidate; + } else if (!strcasecmp(var->name, "stunaddr")) { + stunaddr.sin_port = htons(STANDARD_STUN_PORT); + if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) { + ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value); } } -*/ } while (cat) { if (strcasecmp(cat, "general")) { @@ -2113,28 +2112,19 @@ static int gtalk_load_config(void) member->allowguest = allowguest; member->prefs = prefs; while (var) { - if (!strcasecmp(var->name, "disallow")) + if (!strcasecmp(var->name, "disallow")) { ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0); - else if (!strcasecmp(var->name, "allow")) + } else if (!strcasecmp(var->name, "allow")) { ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1); - else if (!strcasecmp(var->name, "context")) + } else if (!strcasecmp(var->name, "context")) { ast_copy_string(member->context, var->value, sizeof(member->context)); - else if (!strcasecmp(var->name, "parkinglot")) + } else if (!strcasecmp(var->name, "parkinglot")) { ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot)); -/* Idea to allow for custom candidates */ -/* - else if (!strcasecmp(var->name, "candidate")) { - candidate = gtalk_create_candidate(var->value); - if (candidate) { - candidate->next = member->ourcandidates; - member->ourcandidates = candidate; - } } -*/ var = var->next; } ASTOBJ_UNLOCK(member); @@ -2164,6 +2154,8 @@ static int gtalk_load_config(void) } cat = ast_category_browse(cfg, cat); } + + gtalk_update_externip(); gtalk_free_candidates(global_candidates); return 1; } @@ -2193,12 +2185,14 @@ static int load_module(void) } sched = sched_context_create(); - if (!sched) + if (!sched) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); + } io = io_context_create(); - if (!io) + if (!io) { ast_log(LOG_WARNING, "Unable to create I/O context\n"); + } ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp)) { @@ -2218,12 +2212,14 @@ static int load_module(void) return 0; } -/*! \brief Reload module */ +/*! \brief Reload module + * \todo XXX TODO make this work. */ +#if 0 static int reload(void) { return 0; } - +#endif /*! \brief Unload the gtalk channel from Asterisk */ static int unload_module(void) { @@ -2259,6 +2255,6 @@ static int unload_module(void) AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gtalk Channel Driver", .load = load_module, .unload = unload_module, - .reload = reload, + /* .reload = reload, */ .load_pri = AST_MODPRI_CHANNEL_DRIVER, ); -- cgit v1.2.3