Mon Mar 19 11:30:38 2012

Asterisk developer's documentation


chan_gtalk.c File Reference

Gtalk Channel Driver, until google/libjingle works with jingle spec. More...

#include "asterisk.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include <iksemel.h>
#include <pthread.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/stun.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/stringfields.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astobj.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/jabber.h"
#include "asterisk/jingle.h"

Go to the source code of this file.

Data Structures

struct  gtalk
struct  gtalk_candidate
struct  gtalk_container
struct  gtalk_pvt

Defines

#define FORMAT   "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
#define GOOGLE_CONFIG   "gtalk.conf"

Enumerations

enum  gtalk_connect_type { AJI_CONNECT_STUN = 1, AJI_CONNECT_LOCAL = 2, AJI_CONNECT_RELAY = 3 }
enum  gtalk_protocol { AJI_PROTOCOL_UDP = 1, AJI_PROTOCOL_SSLTCP = 2 }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int add_codec_to_answer (const struct gtalk_pvt *p, int codec, iks *dcodecs)
static struct gtalkfind_gtalk (char *name, char *connection)
static int gtalk_action (struct gtalk *client, struct gtalk_pvt *p, const char *action)
static int gtalk_add_candidate (struct gtalk *client, ikspak *pak)
static struct gtalk_pvtgtalk_alloc (struct gtalk *client, const char *us, const char *them, const char *sid)
static int gtalk_answer (struct ast_channel *ast)
static int gtalk_call (struct ast_channel *ast, char *dest, int timeout)
 Initiate new call, part of PBX interface dest is the dial string.
static int gtalk_create_candidates (struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
static int gtalk_create_member (char *label, struct ast_variable *var, int allowguest, struct ast_codec_pref prefs, char *context, struct gtalk *member)
static int gtalk_digit_begin (struct ast_channel *ast, char digit)
static int gtalk_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
static int gtalk_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static void gtalk_free_candidates (struct gtalk_candidate *candidate)
static void gtalk_free_pvt (struct gtalk *client, struct gtalk_pvt *p)
static format_t gtalk_get_codec (struct ast_channel *chan)
static int gtalk_get_local_ip (struct ast_sockaddr *ourip)
static enum ast_rtp_glue_result gtalk_get_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance **instance)
static int gtalk_handle_dtmf (struct gtalk *client, ikspak *pak)
static int gtalk_hangup (struct ast_channel *ast)
 Hangup a call through the gtalk proxy channel.
static int gtalk_hangup_farend (struct gtalk *client, ikspak *pak)
static int gtalk_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static int gtalk_invite (struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
static int gtalk_is_accepted (struct gtalk *client, ikspak *pak)
static int gtalk_is_answered (struct gtalk *client, ikspak *pak)
static int gtalk_load_config (void)
static void gtalk_member_destroy (struct gtalk *obj)
static struct ast_channelgtalk_new (struct gtalk *client, struct gtalk_pvt *i, int state, const char *title, const char *linkedid)
 Start new gtalk channel.
static int gtalk_newcall (struct gtalk *client, ikspak *pak)
static int gtalk_parser (void *data, ikspak *pak)
 CLI command "gtalk reload".
static struct ast_framegtalk_read (struct ast_channel *ast)
static struct ast_channelgtalk_request (const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
 Part of PBX interface.
static int gtalk_response (struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
static int gtalk_ringing_ack (void *data, ikspak *pak)
static struct ast_framegtalk_rtp_read (struct ast_channel *ast, struct gtalk_pvt *p)
static int gtalk_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int gtalk_sendtext (struct ast_channel *ast, const char *text)
static int gtalk_set_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, format_t codecs, int nat_active)
static char * gtalk_show_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command "gtalk show channels".
static int gtalk_update_externip (void)
static int gtalk_update_stun (struct gtalk *client, struct gtalk_pvt *p)
static int gtalk_write (struct ast_channel *ast, struct ast_frame *frame)
 Send frame to media channel (rtp).
static int load_module (void)
 Load module into PBX, register channel.
static int unload_module (void)
 Reload module Unload the gtalk channel from Asterisk.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Gtalk Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
static struct in_addr __ourip
static struct ast_module_infoast_module_info = &__mod_info
static struct sockaddr_in bindaddr = { 0, }
static struct ast_jb_conf default_jbconf
static const char desc [] = "Gtalk Channel"
static char externip [16]
static format_t global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263
static struct ast_jb_conf global_jbconf
static struct ast_cli_entry gtalk_cli []
static struct gtalk_container gtalk_list
static struct ast_rtp_glue gtalk_rtp_glue
static struct ast_channel_tech gtalk_tech
 PBX interface structure for channel registration.
static ast_mutex_t gtalklock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static struct io_contextio
static struct sched_contextsched
static struct sockaddr_in stunaddr


Detailed Description

Gtalk Channel Driver, until google/libjingle works with jingle spec.

Author:
Matt O'Gorman <mogorman@digium.com>

Philippe Sultan <philippe.sultan@gmail.com>

********** General TODO:s
Todo:
Support config reloading.

Fix native bridging.

Definition in file chan_gtalk.c.


Define Documentation

#define FORMAT   "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"

#define GOOGLE_CONFIG   "gtalk.conf"

Definition at line 80 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and load_module().


Enumeration Type Documentation

enum gtalk_connect_type

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 98 of file chan_gtalk.c.

00098                         {
00099    AJI_CONNECT_STUN = 1,
00100    AJI_CONNECT_LOCAL = 2,
00101    AJI_CONNECT_RELAY = 3,
00102 };

enum gtalk_protocol

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 93 of file chan_gtalk.c.

00093                     {
00094    AJI_PROTOCOL_UDP = 1,
00095    AJI_PROTOCOL_SSLTCP = 2,
00096 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2300 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2300 of file chan_gtalk.c.

static int add_codec_to_answer ( const struct gtalk_pvt p,
int  codec,
iks *  dcodecs 
) [static]

Definition at line 278 of file chan_gtalk.c.

References ast_getformatname(), ast_log(), format, and LOG_WARNING.

Referenced by gtalk_invite(), and jingle_accept_call().

00279 {
00280    int res = 0;
00281    char *format = ast_getformatname(codec);
00282 
00283    if (!strcasecmp("ulaw", format)) {
00284       iks *payload_eg711u, *payload_pcmu;
00285       payload_pcmu = iks_new("payload-type");
00286       payload_eg711u = iks_new("payload-type");
00287 
00288       if(!payload_eg711u || !payload_pcmu) {
00289          iks_delete(payload_pcmu);
00290          iks_delete(payload_eg711u);
00291          ast_log(LOG_WARNING,"Failed to allocate iks node");
00292          return -1;
00293       }
00294       iks_insert_attrib(payload_pcmu, "id", "0");
00295       iks_insert_attrib(payload_pcmu, "name", "PCMU");
00296       iks_insert_attrib(payload_pcmu, "clockrate","8000");
00297       iks_insert_attrib(payload_pcmu, "bitrate","64000");
00298       iks_insert_attrib(payload_eg711u, "id", "100");
00299       iks_insert_attrib(payload_eg711u, "name", "EG711U");
00300       iks_insert_attrib(payload_eg711u, "clockrate","8000");
00301       iks_insert_attrib(payload_eg711u, "bitrate","64000");
00302       iks_insert_node(dcodecs, payload_pcmu);
00303       iks_insert_node(dcodecs, payload_eg711u);
00304       res ++;
00305    }
00306    if (!strcasecmp("alaw", format)) {
00307       iks *payload_eg711a, *payload_pcma;
00308       payload_pcma = iks_new("payload-type");
00309       payload_eg711a = iks_new("payload-type");
00310       if(!payload_eg711a || !payload_pcma) {
00311          iks_delete(payload_eg711a);
00312          iks_delete(payload_pcma);
00313          ast_log(LOG_WARNING,"Failed to allocate iks node");
00314          return -1;
00315       }
00316       iks_insert_attrib(payload_pcma, "id", "8");
00317       iks_insert_attrib(payload_pcma, "name", "PCMA");
00318       iks_insert_attrib(payload_pcma, "clockrate","8000");
00319       iks_insert_attrib(payload_pcma, "bitrate","64000");
00320       payload_eg711a = iks_new("payload-type");
00321       iks_insert_attrib(payload_eg711a, "id", "101");
00322       iks_insert_attrib(payload_eg711a, "name", "EG711A");
00323       iks_insert_attrib(payload_eg711a, "clockrate","8000");
00324       iks_insert_attrib(payload_eg711a, "bitrate","64000");
00325       iks_insert_node(dcodecs, payload_pcma);
00326       iks_insert_node(dcodecs, payload_eg711a);
00327       res ++;
00328    }
00329    if (!strcasecmp("ilbc", format)) {
00330       iks *payload_ilbc = iks_new("payload-type");
00331       if(!payload_ilbc) {
00332          ast_log(LOG_WARNING,"Failed to allocate iks node");
00333          return -1;
00334       }
00335       iks_insert_attrib(payload_ilbc, "id", "97");
00336       iks_insert_attrib(payload_ilbc, "name", "iLBC");
00337       iks_insert_attrib(payload_ilbc, "clockrate","8000");
00338       iks_insert_attrib(payload_ilbc, "bitrate","13300");
00339       iks_insert_node(dcodecs, payload_ilbc);
00340       res ++;
00341    }
00342    if (!strcasecmp("g723", format)) {
00343       iks *payload_g723 = iks_new("payload-type");
00344       if(!payload_g723) {
00345          ast_log(LOG_WARNING,"Failed to allocate iks node");
00346          return -1;
00347       }
00348       iks_insert_attrib(payload_g723, "id", "4");
00349       iks_insert_attrib(payload_g723, "name", "G723");
00350       iks_insert_attrib(payload_g723, "clockrate","8000");
00351       iks_insert_attrib(payload_g723, "bitrate","6300");
00352       iks_insert_node(dcodecs, payload_g723);
00353       res ++;
00354    }
00355    if (!strcasecmp("speex", format)) {
00356       iks *payload_speex = iks_new("payload-type");
00357       if(!payload_speex) {
00358          ast_log(LOG_WARNING,"Failed to allocate iks node");
00359          return -1;
00360       }
00361       iks_insert_attrib(payload_speex, "id", "110");
00362       iks_insert_attrib(payload_speex, "name", "speex");
00363       iks_insert_attrib(payload_speex, "clockrate","8000");
00364       iks_insert_attrib(payload_speex, "bitrate","11000");
00365       iks_insert_node(dcodecs, payload_speex);
00366       res++;
00367    }
00368    if (!strcasecmp("gsm", format)) {
00369       iks *payload_gsm = iks_new("payload-type");
00370       if(!payload_gsm) {
00371          ast_log(LOG_WARNING,"Failed to allocate iks node");
00372          return -1;
00373       }
00374       iks_insert_attrib(payload_gsm, "id", "103");
00375       iks_insert_attrib(payload_gsm, "name", "gsm");
00376       iks_insert_node(dcodecs, payload_gsm);
00377       res++;
00378    }
00379 
00380    return res;
00381 }

static struct gtalk* find_gtalk ( char *  name,
char *  connection 
) [static]

Definition at line 246 of file chan_gtalk.c.

References ast_strdupa, ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_FIND_FULL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, gtalk_list, and strsep().

Referenced by gtalk_request().

00247 {
00248    struct gtalk *gtalk = NULL;
00249    char *domain = NULL , *s = NULL;
00250 
00251    if (strchr(connection, '@')) {
00252       s = ast_strdupa(connection);
00253       domain = strsep(&s, "@");
00254       ast_verbose("OOOOH domain = %s\n", domain);
00255    }
00256    gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
00257    if (!gtalk && strchr(name, '@'))
00258       gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
00259 
00260    if (!gtalk) {
00261       /* guest call */
00262       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
00263          ASTOBJ_RDLOCK(iterator);
00264          if (!strcasecmp(iterator->name, "guest")) {
00265             gtalk = iterator;
00266          }
00267          ASTOBJ_UNLOCK(iterator);
00268 
00269          if (gtalk)
00270             break;
00271       });
00272 
00273    }
00274    return gtalk;
00275 }

static int gtalk_action ( struct gtalk client,
struct gtalk_pvt p,
const char *  action 
) [static]

Definition at line 1171 of file chan_gtalk.c.

References ast_aji_increment_mid(), ast_aji_send(), ast_strdupa, gtalk::connection, GOOGLE_NS, gtalk_pvt::initiator, aji_client::mid, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_hangup(), and gtalk_newcall().

01172 {
01173    iks *request, *session = NULL;
01174    int res = -1;
01175    char *lowerthem = NULL;
01176 
01177    request = iks_new("iq");
01178    if (request) {
01179       iks_insert_attrib(request, "type", "set");
01180       iks_insert_attrib(request, "from", p->us);
01181       iks_insert_attrib(request, "to", p->them);
01182       iks_insert_attrib(request, "id", client->connection->mid);
01183       ast_aji_increment_mid(client->connection->mid);
01184       session = iks_new("session");
01185       if (session) {
01186          iks_insert_attrib(session, "type", action);
01187          iks_insert_attrib(session, "id", p->sid);
01188          /* put the initiator attribute to lower case if we receive the call
01189           * otherwise GoogleTalk won't establish the session */
01190          if (!p->initiator) {
01191                  char c;
01192             char *t = lowerthem = ast_strdupa(p->them);
01193             while (((c = *t) != '/') && (*t++ = tolower(c)));
01194          }
01195          iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01196          iks_insert_attrib(session, "xmlns", GOOGLE_NS);
01197          iks_insert_node(request, session);
01198          ast_aji_send(client->connection, request);
01199          res = 0;
01200       }
01201    }
01202 
01203    iks_delete(session);
01204    iks_delete(request);
01205 
01206    return res;
01207 }

static int gtalk_add_candidate ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 1476 of file chan_gtalk.c.

References AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_send(), ast_calloc, ast_copy_string(), gtalk::connection, gtalk_update_stun(), aji_client::jid, gtalk_pvt::laststun, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_candidate::receipt, S_OR, and gtalk_pvt::theircandidates.

Referenced by gtalk_parser().

01477 {
01478    struct gtalk_pvt *p = NULL, *tmp = NULL;
01479    struct aji_client *c = client->connection;
01480    struct gtalk_candidate *newcandidate = NULL;
01481    iks *traversenodes = NULL, *receipt = NULL;
01482    char *from;
01483 
01484    from = iks_find_attrib(pak->x,"to");
01485    if (!from) {
01486       from = c->jid->full;
01487    }
01488 
01489    for (tmp = client->p; tmp; tmp = tmp->next) {
01490       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01491          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01492          p = tmp;
01493          break;
01494       }
01495    }
01496 
01497    if (!p) {
01498       return -1;
01499    }
01500    traversenodes = pak->query;
01501    while(traversenodes) {
01502       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
01503          traversenodes = iks_first_tag(traversenodes);
01504          continue;
01505       }
01506       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
01507          traversenodes = iks_child(traversenodes);
01508          continue;
01509       }
01510       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
01511          newcandidate = ast_calloc(1, sizeof(*newcandidate));
01512          if (!newcandidate)
01513             return 0;
01514          ast_copy_string(newcandidate->name,
01515             S_OR(iks_find_attrib(traversenodes, "name"), ""),
01516             sizeof(newcandidate->name));
01517          ast_copy_string(newcandidate->ip,
01518             S_OR(iks_find_attrib(traversenodes, "address"), ""),
01519             sizeof(newcandidate->ip));
01520          newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01521          ast_copy_string(newcandidate->username,
01522             S_OR(iks_find_attrib(traversenodes, "username"), ""),
01523             sizeof(newcandidate->username));
01524          ast_copy_string(newcandidate->password,
01525             S_OR(iks_find_attrib(traversenodes, "password"), ""),
01526             sizeof(newcandidate->password));
01527          newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01528          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
01529             newcandidate->protocol = AJI_PROTOCOL_UDP;
01530          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
01531             newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01532 
01533          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
01534             newcandidate->type = AJI_CONNECT_STUN;
01535          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
01536             newcandidate->type = AJI_CONNECT_LOCAL;
01537          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
01538             newcandidate->type = AJI_CONNECT_RELAY;
01539          ast_copy_string(newcandidate->network,
01540             S_OR(iks_find_attrib(traversenodes, "network"), ""),
01541             sizeof(newcandidate->network));
01542          newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
01543          newcandidate->next = NULL;
01544 
01545          newcandidate->next = p->theircandidates;
01546          p->theircandidates = newcandidate;
01547          p->laststun = 0;
01548          gtalk_update_stun(p->parent, p);
01549          newcandidate = NULL;
01550       }
01551       traversenodes = iks_next_tag(traversenodes);
01552    }
01553 
01554    receipt = iks_new("iq");
01555    iks_insert_attrib(receipt, "type", "result");
01556    iks_insert_attrib(receipt, "from", from);
01557    iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
01558    iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
01559    ast_aji_send(c, receipt);
01560 
01561    iks_delete(receipt);
01562 
01563    return 1;
01564 }

static struct gtalk_pvt * gtalk_alloc ( struct gtalk client,
const char *  us,
const char *  them,
const char *  sid 
) [static]

Definition at line 977 of file chan_gtalk.c.

References ast_aji_buddy_destroy(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_random(), ast_rtp_codecs_payloads_clear(), AST_RTP_DTMF_MODE_RFC2833, ast_rtp_instance_dtmf_mode_set(), ast_rtp_instance_get_codecs(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_DTMF, AST_RTP_PROPERTY_RTCP, AST_RTP_PROPERTY_STUN, ast_sockaddr_from_sin, ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, bindaddr, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk::capability, gtalk::connection, exten, global_capability, gtalklock, aji_version::jingle, LOG_ERROR, LOG_WARNING, gtalk::name, aji_resource::next, gtalk::p, gtalk::prefs, aji_resource::resource, aji_buddy::resources, and strsep().

Referenced by gtalk_newcall(), and gtalk_request().

00978 {
00979    struct gtalk_pvt *tmp = NULL;
00980    struct aji_resource *resources = NULL;
00981    struct aji_buddy *buddy = NULL;
00982    char idroster[200];
00983    char *data, *exten = NULL;
00984    struct ast_sockaddr bindaddr_tmp;
00985 
00986    ast_debug(1, "The client is %s for alloc\n", client->name);
00987    if (!sid && !strchr(them, '/')) {   /* I started call! */
00988       if (!strcasecmp(client->name, "guest")) {
00989          buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00990          if (buddy) {
00991             resources = buddy->resources;
00992          }
00993       } else if (client->buddy) {
00994          resources = client->buddy->resources;
00995       }
00996 
00997       while (resources) {
00998          if (resources->cap->jingle) {
00999             break;
01000          }
01001          resources = resources->next;
01002       }
01003       if (resources) {
01004          snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
01005       } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
01006          snprintf(idroster, sizeof(idroster), "%s", them);
01007       } else {
01008          ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
01009          if (buddy) {
01010             ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01011          }
01012          return NULL;
01013       }
01014       if (buddy) {
01015          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01016       }
01017    }
01018    if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
01019       return NULL;
01020    }
01021 
01022    memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
01023 
01024    if (sid) {
01025       ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
01026       ast_copy_string(tmp->them, them, sizeof(tmp->them));
01027       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01028    } else {
01029       snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
01030       ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
01031       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01032       tmp->initiator = 1;
01033    }
01034    /* clear codecs */
01035    bindaddr.sin_family = AF_INET;
01036    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
01037    if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
01038      ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
01039      ast_free(tmp);
01040      return NULL;
01041    }
01042    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
01043    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
01044    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
01045    ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
01046    ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
01047 
01048    /* add user configured codec capabilites */
01049    if (client->capability) {
01050       tmp->capability = client->capability;
01051    } else if (global_capability) {
01052       tmp->capability = global_capability;
01053    }
01054 
01055    tmp->parent = client;
01056    if (!tmp->rtp) {
01057       ast_log(LOG_WARNING, "Out of RTP sessions?\n");
01058       ast_free(tmp);
01059       return NULL;
01060    }
01061 
01062    /* Set CALLERID(name) to the full JID of the remote peer */
01063    ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
01064 
01065    if(strchr(tmp->us, '/')) {
01066       data = ast_strdupa(tmp->us);
01067       exten = strsep(&data, "/");
01068    } else {
01069       exten = tmp->us;
01070    }
01071    ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
01072    ast_mutex_init(&tmp->lock);
01073    ast_mutex_lock(&gtalklock);
01074    tmp->next = client->p;
01075    client->p = tmp;
01076    ast_mutex_unlock(&gtalklock);
01077    return tmp;
01078 }

static int gtalk_answer ( struct ast_channel ast  )  [static]

Definition at line 508 of file chan_gtalk.c.

References ast_debug, ast_mutex_lock, ast_mutex_unlock, EVENT_FLAG_SYSTEM, gtalk_invite(), gtalk_pvt::lock, manager_event, ast_channel::name, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.

00509 {
00510    struct gtalk_pvt *p = ast->tech_pvt;
00511    int res = 0;
00512 
00513    ast_debug(1, "Answer!\n");
00514    ast_mutex_lock(&p->lock);
00515    gtalk_invite(p, p->them, p->us,p->sid, 0);
00516    manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
00517       ast->name, "GTALK", p->sid);
00518    ast_mutex_unlock(&p->lock);
00519    return res;
00520 }

static int gtalk_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Initiate new call, part of PBX interface dest is the dial string.

Definition at line 1806 of file chan_gtalk.c.

References ast_channel::_state, ast_copy_string(), ast_log(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RING, gtalk::connection, aji_client::f, gtalk_invite(), gtalk_ringing_ack(), LOG_WARNING, aji_client::mid, ast_channel::name, gtalk_pvt::parent, gtalk_pvt::ring, gtalk_pvt::ringrule, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.

01807 {
01808    struct gtalk_pvt *p = ast->tech_pvt;
01809 
01810    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01811       ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01812       return -1;
01813    }
01814 
01815    ast_setstate(ast, AST_STATE_RING);
01816    if (!p->ringrule) {
01817       ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01818       p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01819                      IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01820    } else {
01821       ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01822    }
01823 
01824    gtalk_invite(p, p->them, p->us, p->sid, 1);
01825 
01826    return 0;
01827 }

static int gtalk_create_candidates ( struct gtalk client,
struct gtalk_pvt p,
char *  sid,
char *  from,
char *  to 
) [static]

Definition at line 840 of file chan_gtalk.c.

References AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_free, ast_log(), ast_random(), ast_rtp_instance_get_local_address(), ast_sockaddr_stringify_addr(), ast_sockaddr_to_sin, ast_strdupa, ast_strlen_zero(), gtalk::connection, externip, GOOGLE_NS, GOOGLE_TRANSPORT_NS, gtalk_get_local_ip(), gtalk_update_externip(), gtalk_pvt::initiator, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_client::mid, gtalk_candidate::name, gtalk_candidate::next, gtalk_pvt::next, gtalk_pvt::ourcandidates, pass, gtalk_candidate::password, gtalk_candidate::port, gtalk_candidate::preference, gtalk_candidate::protocol, gtalk_pvt::rtp, gtalk_pvt::sid, gtalk_candidate::type, and gtalk_candidate::username.

Referenced by gtalk_newcall(), and gtalk_ringing_ack().

00841 {
00842    struct gtalk_candidate *tmp;
00843    struct aji_client *c = client->connection;
00844    struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00845    struct sockaddr_in sin = { 0, };
00846    struct ast_sockaddr sin_tmp;
00847    struct ast_sockaddr us;
00848    iks *iq, *gtalk, *candidate, *transport;
00849    char user[17], pass[17], preference[5], port[7];
00850    char *lowerfrom = NULL;
00851 
00852    iq = iks_new("iq");
00853    gtalk = iks_new("session");
00854    candidate = iks_new("candidate");
00855    transport = iks_new("transport");
00856    if (!iq || !gtalk || !candidate || !transport) {
00857       ast_log(LOG_ERROR, "Memory allocation error\n");
00858       goto safeout;
00859    }
00860    ours1 = ast_calloc(1, sizeof(*ours1));
00861    ours2 = ast_calloc(1, sizeof(*ours2));
00862    if (!ours1 || !ours2)
00863       goto safeout;
00864 
00865    iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
00866    iks_insert_node(iq, gtalk);
00867    iks_insert_node(gtalk,candidate);
00868    iks_insert_node(gtalk,transport);
00869 
00870    for (; p; p = p->next) {
00871       if (!strcasecmp(p->sid, sid))
00872          break;
00873    }
00874 
00875    if (!p) {
00876       ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00877       goto safeout;
00878    }
00879 
00880    ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
00881    ast_sockaddr_to_sin(&sin_tmp, &sin);
00882 
00883    gtalk_get_local_ip(&us);
00884 
00885    if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
00886       ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
00887    }
00888 
00889    /* Setup our gtalk candidates */
00890    ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00891    ours1->port = ntohs(sin.sin_port);
00892    ours1->preference = 1;
00893    snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00894    snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00895    ast_copy_string(ours1->username, user, sizeof(ours1->username));
00896    ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00897    ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
00898          sizeof(ours1->ip));
00899    ours1->protocol = AJI_PROTOCOL_UDP;
00900    ours1->type = AJI_CONNECT_LOCAL;
00901    ours1->generation = 0;
00902    p->ourcandidates = ours1;
00903 
00904    /* XXX this is a blocking action.  We send a STUN request to the server
00905     * and wait for the response.  If blocking here is a problem the STUN requests/responses
00906     * for the externip may need to be done differently. */
00907    gtalk_update_externip();
00908    if (!ast_strlen_zero(externip)) {
00909       ast_copy_string(ours2->username, user, sizeof(ours2->username));
00910       ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00911       ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00912       ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00913       ours2->port = ntohs(sin.sin_port);
00914       ours2->preference = 0.9;
00915       ours2->protocol = AJI_PROTOCOL_UDP;
00916       ours2->type = AJI_CONNECT_STUN;
00917       ours2->generation = 0;
00918       ours1->next = ours2;
00919       ours2 = NULL;
00920    }
00921    ours1 = NULL;
00922 
00923    for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00924       snprintf(port, sizeof(port), "%d", tmp->port);
00925       snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00926       iks_insert_attrib(iq, "from", to);
00927       iks_insert_attrib(iq, "to", from);
00928       iks_insert_attrib(iq, "type", "set");
00929       iks_insert_attrib(iq, "id", c->mid);
00930       ast_aji_increment_mid(c->mid);
00931       iks_insert_attrib(gtalk, "type", "candidates");
00932       iks_insert_attrib(gtalk, "id", sid);
00933       /* put the initiator attribute to lower case if we receive the call
00934        * otherwise GoogleTalk won't establish the session */
00935       if (!p->initiator) {
00936               char c;
00937          char *t = lowerfrom = ast_strdupa(from);
00938          while (((c = *t) != '/') && (*t++ = tolower(c)));
00939       }
00940       iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
00941       iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00942       iks_insert_attrib(candidate, "name", tmp->name);
00943       iks_insert_attrib(candidate, "address", tmp->ip);
00944       iks_insert_attrib(candidate, "port", port);
00945       iks_insert_attrib(candidate, "username", tmp->username);
00946       iks_insert_attrib(candidate, "password", tmp->password);
00947       iks_insert_attrib(candidate, "preference", preference);
00948       if (tmp->protocol == AJI_PROTOCOL_UDP)
00949          iks_insert_attrib(candidate, "protocol", "udp");
00950       if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00951          iks_insert_attrib(candidate, "protocol", "ssltcp");
00952       if (tmp->type == AJI_CONNECT_STUN)
00953          iks_insert_attrib(candidate, "type", "stun");
00954       if (tmp->type == AJI_CONNECT_LOCAL)
00955          iks_insert_attrib(candidate, "type", "local");
00956       if (tmp->type == AJI_CONNECT_RELAY)
00957          iks_insert_attrib(candidate, "type", "relay");
00958       iks_insert_attrib(candidate, "network", "0");
00959       iks_insert_attrib(candidate, "generation", "0");
00960       ast_aji_send(c, iq);
00961    }
00962    p->laststun = 0;
00963 
00964 safeout:
00965    if (ours1)
00966       ast_free(ours1);
00967    if (ours2)
00968       ast_free(ours2);
00969    iks_delete(iq);
00970    iks_delete(gtalk);
00971    iks_delete(candidate);
00972    iks_delete(transport);
00973 
00974    return 1;
00975 }

static int gtalk_create_member ( char *  label,
struct ast_variable var,
int  allowguest,
struct ast_codec_pref  prefs,
char *  context,
struct gtalk member 
) [static]

Definition at line 2028 of file chan_gtalk.c.

References gtalk::allowguest, ast_aji_get_client(), ast_copy_string(), ast_log(), ast_parse_allow_disallow(), ASTOBJ_CONTAINER_FIND, aji_client::buddies, gtalk::buddy, gtalk::capability, gtalk::connection, gtalk::context, aji_client::f, GOOGLE_NS, gtalk_parser(), LOG_ERROR, LOG_WARNING, gtalk::name, gtalk::parkinglot, prefs, gtalk::prefs, gtalk::user, and var.

02031 {
02032    struct aji_client *client;
02033 
02034    if (!member)
02035       ast_log(LOG_WARNING, "Out of memory.\n");
02036 
02037    ast_copy_string(member->name, label, sizeof(member->name));
02038    ast_copy_string(member->user, label, sizeof(member->user));
02039    ast_copy_string(member->context, context, sizeof(member->context));
02040    member->allowguest = allowguest;
02041    member->prefs = prefs;
02042    while (var) {
02043       if (!strcasecmp(var->name, "username"))
02044          ast_copy_string(member->user, var->value, sizeof(member->user));
02045       else if (!strcasecmp(var->name, "disallow"))
02046          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
02047       else if (!strcasecmp(var->name, "allow"))
02048          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
02049       else if (!strcasecmp(var->name, "context"))
02050          ast_copy_string(member->context, var->value, sizeof(member->context));
02051       else if (!strcasecmp(var->name, "parkinglot"))
02052          ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
02053       else if (!strcasecmp(var->name, "connection")) {
02054          if ((client = ast_aji_get_client(var->value))) {
02055             member->connection = client;
02056             iks_filter_add_rule(client->f, gtalk_parser, member,
02057                       IKS_RULE_TYPE, IKS_PAK_IQ,
02058                       IKS_RULE_FROM_PARTIAL, member->user,
02059                       IKS_RULE_NS, GOOGLE_NS,
02060                       IKS_RULE_DONE);
02061          } else {
02062             ast_log(LOG_ERROR, "connection referenced not found!\n");
02063             return 0;
02064          }
02065       }
02066       var = var->next;
02067    }
02068    if (member->connection && member->user)
02069       member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
02070    else {
02071       ast_log(LOG_ERROR, "No Connection or Username!\n");
02072    }
02073    return 1;
02074 }

static int gtalk_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 1706 of file chan_gtalk.c.

References ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_begin(), gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.

01707 {
01708    struct gtalk_pvt *p = chan->tech_pvt;
01709    int res = 0;
01710 
01711    ast_mutex_lock(&p->lock);
01712    if (p->rtp) {
01713       ast_rtp_instance_dtmf_begin(p->rtp, digit);
01714    } else {
01715       res = -1;
01716    }
01717    ast_mutex_unlock(&p->lock);
01718 
01719    return res;
01720 }

static int gtalk_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 1722 of file chan_gtalk.c.

References ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_end_with_duration(), gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.

01723 {
01724    struct gtalk_pvt *p = chan->tech_pvt;
01725    int res = 0;
01726 
01727    ast_mutex_lock(&p->lock);
01728    if (p->rtp) {
01729       ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
01730    } else {
01731       res = -1;
01732    }
01733    ast_mutex_unlock(&p->lock);
01734 
01735    return res;
01736 }

static int gtalk_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 1653 of file chan_gtalk.c.

References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, gtalk_pvt::owner, and ast_channel::tech_pvt.

01654 {
01655    struct gtalk_pvt *p = newchan->tech_pvt;
01656    ast_mutex_lock(&p->lock);
01657 
01658    if ((p->owner != oldchan)) {
01659       ast_mutex_unlock(&p->lock);
01660       return -1;
01661    }
01662    if (p->owner == oldchan)
01663       p->owner = newchan;
01664    ast_mutex_unlock(&p->lock);
01665    return 0;
01666 }

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1209 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt().

01210 {
01211    struct gtalk_candidate *last;
01212    while (candidate) {
01213       last = candidate;
01214       candidate = candidate->next;
01215       ast_free(last);
01216    }
01217 }

static void gtalk_free_pvt ( struct gtalk client,
struct gtalk_pvt p 
) [static]

Definition at line 1219 of file chan_gtalk.c.

References ast_free, ast_log(), ast_rtp_instance_destroy(), gtalk::connection, aji_client::f, gtalk_free_candidates(), LOG_WARNING, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::ringrule, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_pvt::vrtp.

Referenced by gtalk_hangup(), and gtalk_newcall().

01220 {
01221    struct gtalk_pvt *cur, *prev = NULL;
01222    cur = client->p;
01223    while (cur) {
01224       if (cur == p) {
01225          if (prev)
01226             prev->next = p->next;
01227          else
01228             client->p = p->next;
01229          break;
01230       }
01231       prev = cur;
01232       cur = cur->next;
01233    }
01234    if (p->ringrule)
01235       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01236    if (p->owner)
01237       ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01238    if (p->rtp)
01239       ast_rtp_instance_destroy(p->rtp);
01240    if (p->vrtp)
01241       ast_rtp_instance_destroy(p->vrtp);
01242    gtalk_free_candidates(p->theircandidates);
01243    ast_free(p);
01244 }

static format_t gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 541 of file chan_gtalk.c.

References gtalk_pvt::peercapability, and ast_channel::tech_pvt.

00542 {
00543    struct gtalk_pvt *p = chan->tech_pvt;
00544    return p->peercapability;
00545 }

static int gtalk_get_local_ip ( struct ast_sockaddr ourip  )  [static]

Definition at line 812 of file chan_gtalk.c.

References ast_find_ourip(), ast_free, ast_ouraddrfor(), ast_sockaddr_copy(), ast_sockaddr_from_sin, ast_sockaddr_is_any(), ast_sockaddr_resolve(), bindaddr, and PARSE_PORT_FORBID.

Referenced by gtalk_create_candidates(), and load_module().

00813 {
00814    struct ast_sockaddr root;
00815    struct ast_sockaddr bindaddr_tmp;
00816    struct ast_sockaddr *addrs;
00817    int addrs_cnt;
00818 
00819    /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
00820    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
00821    if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
00822       ast_sockaddr_copy(ourip, &bindaddr_tmp);
00823       return 0;
00824    }
00825 
00826    /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
00827     * If you can't resolve google.com from your network, then this module is useless for you anyway. */
00828    if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
00829       ast_sockaddr_copy(&root, &addrs[0]);
00830       ast_free(addrs);
00831       if (!ast_ouraddrfor(&root, ourip)) {
00832          return 0;
00833       }
00834    }
00835 
00836    /* As a last resort, use this function to find our local address. */
00837    return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
00838 }

static enum ast_rtp_glue_result gtalk_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance **  instance 
) [static]

Definition at line 522 of file chan_gtalk.c.

References ao2_ref, ast_mutex_lock, ast_mutex_unlock, AST_RTP_GLUE_RESULT_FORBID, AST_RTP_GLUE_RESULT_LOCAL, gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.

00523 {
00524    struct gtalk_pvt *p = chan->tech_pvt;
00525    enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
00526 
00527    if (!p)
00528       return res;
00529 
00530    ast_mutex_lock(&p->lock);
00531    if (p->rtp){
00532       ao2_ref(p->rtp, +1);
00533       *instance = p->rtp;
00534       res = AST_RTP_GLUE_RESULT_LOCAL;
00535    }
00536    ast_mutex_unlock(&p->lock);
00537 
00538    return res;
00539 }

static int gtalk_handle_dtmf ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 713 of file chan_gtalk.c.

References AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_log(), ast_queue_frame(), ast_verbose, gtalk::connection, f, gtalk_response(), aji_client::jid, LOG_NOTICE, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00714 {
00715    struct gtalk_pvt *tmp;
00716    iks *dtmfnode = NULL, *dtmfchild = NULL;
00717    char *dtmf;
00718    char *from;
00719    /* Make sure our new call doesn't exist yet */
00720    for (tmp = client->p; tmp; tmp = tmp->next) {
00721       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00722          break;
00723    }
00724    from = iks_find_attrib(pak->x, "to");
00725    if (!from) {
00726       from = client->connection->jid->full;
00727    }
00728 
00729    if (tmp) {
00730       if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00731          gtalk_response(client, from, pak,
00732                "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00733                "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00734          return -1;
00735       }
00736       if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00737          if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00738             if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00739                struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00740                f.subclass.integer = dtmf[0];
00741                ast_queue_frame(tmp->owner, &f);
00742                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00743             } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00744                struct ast_frame f = {AST_FRAME_DTMF_END, };
00745                f.subclass.integer = dtmf[0];
00746                ast_queue_frame(tmp->owner, &f);
00747                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00748             } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
00749                struct ast_frame f = {AST_FRAME_DTMF, };
00750                f.subclass.integer = dtmf[0];
00751                ast_queue_frame(tmp->owner, &f);
00752                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00753             }
00754          }
00755       } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00756          if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00757             if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00758                if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00759                   struct ast_frame f = {AST_FRAME_DTMF_END, };
00760                   f.subclass.integer = dtmf[0];
00761                   ast_queue_frame(tmp->owner, &f);
00762                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00763                } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00764                   struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00765                   f.subclass.integer = dtmf[0];
00766                   ast_queue_frame(tmp->owner, &f);
00767                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00768                }
00769             }
00770          }
00771       }
00772       gtalk_response(client, from, pak, NULL, NULL);
00773       return 1;
00774    } else {
00775       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00776    }
00777 
00778    gtalk_response(client, from, pak, NULL, NULL);
00779    return 1;
00780 }

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1830 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_module_unref(), ast_mutex_lock, ast_mutex_unlock, gtalk_action(), gtalk_free_pvt(), gtalk_pvt::lock, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, and ast_channel::tech_pvt.

Referenced by gtalk_newcall().

01831 {
01832    struct gtalk_pvt *p = ast->tech_pvt;
01833    struct gtalk *client;
01834 
01835    ast_mutex_lock(&p->lock);
01836    client = p->parent;
01837    p->owner = NULL;
01838    ast->tech_pvt = NULL;
01839    if (!p->alreadygone) {
01840       gtalk_action(client, p, "terminate");
01841    }
01842    ast_mutex_unlock(&p->lock);
01843 
01844    gtalk_free_pvt(client, p);
01845    ast_module_unref(ast_module_info->self);
01846 
01847    return 0;
01848 }

static int gtalk_hangup_farend ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 782 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_debug, ast_log(), ast_queue_hangup(), gtalk::connection, gtalk_response(), aji_client::jid, LOG_NOTICE, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00783 {
00784    struct gtalk_pvt *tmp;
00785    char *from;
00786 
00787    ast_debug(1, "The client is %s\n", client->name);
00788    /* Make sure our new call doesn't exist yet */
00789    for (tmp = client->p; tmp; tmp = tmp->next) {
00790       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
00791          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
00792          break;
00793       }
00794    }
00795    from = iks_find_attrib(pak->x, "to");
00796    if (!from) {
00797       from = client->connection->jid->full;
00798    }
00799 
00800    if (tmp) {
00801       tmp->alreadygone = 1;
00802       if (tmp->owner) {
00803          ast_queue_hangup(tmp->owner);
00804       }
00805    } else {
00806       ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
00807    }
00808    gtalk_response(client, from, pak, NULL, NULL);
00809    return 1;
00810 }

static int gtalk_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 1668 of file chan_gtalk.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, ast_moh_start(), and ast_moh_stop().

01669 {
01670    int res = 0;
01671 
01672    switch (condition) {
01673    case AST_CONTROL_HOLD:
01674       ast_moh_start(ast, data, NULL);
01675       break;
01676    case AST_CONTROL_UNHOLD:
01677       ast_moh_stop(ast);
01678       break;
01679    default:
01680       ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
01681       res = -1;
01682    }
01683 
01684    return res;
01685 }

static int gtalk_invite ( struct gtalk_pvt p,
char *  to,
char *  from,
char *  sid,
int  initiator 
) [static]

Definition at line 383 of file chan_gtalk.c.

References add_codec_to_answer(), ast_aji_increment_mid(), ast_aji_send(), ast_codec_pref_index(), ast_log(), ast_strdupa, gtalk::capability, gtalk::connection, GOOGLE_AUDIO_NS, GOOGLE_NS, GOOGLE_TRANSPORT_NS, LOG_ERROR, aji_client::mid, gtalk::p, gtalk_pvt::parent, and gtalk::prefs.

Referenced by gtalk_answer(), gtalk_call(), and gtalk_ringing_ack().

00384 {
00385    struct gtalk *client = p->parent;
00386    iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00387    int x;
00388    int pref_codec = 0;
00389    int alreadysent = 0;
00390    int codecs_num = 0;
00391    char *lowerto = NULL;
00392 
00393    iq = iks_new("iq");
00394    gtalk = iks_new("session");
00395    dcodecs = iks_new("description");
00396    transport = iks_new("transport");
00397    payload_telephone = iks_new("payload-type");
00398    if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
00399       iks_delete(iq);
00400       iks_delete(gtalk);
00401       iks_delete(dcodecs);
00402       iks_delete(transport);
00403       iks_delete(payload_telephone);
00404 
00405       ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00406       return 0;
00407    }
00408    iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
00409    iks_insert_attrib(dcodecs, "xml:lang", "en");
00410 
00411    for (x = 0; x < 64; x++) {
00412       if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
00413          break;
00414       if (!(client->capability & pref_codec))
00415          continue;
00416       if (alreadysent & pref_codec)
00417          continue;
00418       codecs_num = add_codec_to_answer(p, pref_codec, dcodecs);
00419       alreadysent |= pref_codec;
00420    }
00421 
00422    if (codecs_num) {
00423       /* only propose DTMF within an audio session */
00424       iks_insert_attrib(payload_telephone, "id", "101");
00425       iks_insert_attrib(payload_telephone, "name", "telephone-event");
00426       iks_insert_attrib(payload_telephone, "clockrate", "8000");
00427    }
00428    iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
00429 
00430    iks_insert_attrib(iq, "type", "set");
00431    iks_insert_attrib(iq, "to", to);
00432    iks_insert_attrib(iq, "from", from);
00433    iks_insert_attrib(iq, "id", client->connection->mid);
00434    ast_aji_increment_mid(client->connection->mid);
00435 
00436    iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00437    iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00438    /* put the initiator attribute to lower case if we receive the call
00439     * otherwise GoogleTalk won't establish the session */
00440    if (!initiator) {
00441            char c;
00442            char *t = lowerto = ast_strdupa(to);
00443       while (((c = *t) != '/') && (*t++ = tolower(c)));
00444    }
00445    iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
00446    iks_insert_attrib(gtalk, "id", sid);
00447    iks_insert_node(iq, gtalk);
00448    iks_insert_node(gtalk, dcodecs);
00449    iks_insert_node(dcodecs, payload_telephone);
00450 
00451    ast_aji_send(client->connection, iq);
00452 
00453    iks_delete(payload_telephone);
00454    iks_delete(transport);
00455    iks_delete(dcodecs);
00456    iks_delete(gtalk);
00457    iks_delete(iq);
00458    return 1;
00459 }

static int gtalk_is_accepted ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 684 of file chan_gtalk.c.

References ast_log(), gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, LOG_DEBUG, LOG_NOTICE, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00685 {
00686    struct gtalk_pvt *tmp;
00687    char *from;
00688 
00689    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00690    /* find corresponding call */
00691    for (tmp = client->p; tmp; tmp = tmp->next) {
00692       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00693          break;
00694       }
00695    }
00696 
00697    from = iks_find_attrib(pak->x, "to");
00698    if (!from) {
00699       from = client->connection->jid->full;
00700    }
00701 
00702    if (tmp) {
00703       gtalk_update_stun(tmp->parent, tmp);
00704    } else {
00705       ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
00706    }
00707 
00708    /* answer 'iq' packet to let the remote peer know that we're alive */
00709    gtalk_response(client, from, pak, NULL, NULL);
00710    return 1;
00711 }

static int gtalk_is_answered ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 606 of file chan_gtalk.c.

References AST_CONTROL_ANSWER, ast_getformatname_multiple(), ast_log(), ast_queue_control(), ast_queue_hangup(), ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), gtalk_pvt::capability, gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, gtalk_pvt::jointcapability, LOG_DEBUG, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercapability, gtalk_pvt::rtp, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00607 {
00608    struct gtalk_pvt *tmp = NULL;
00609    char *from;
00610    iks *codec;
00611    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00612    int peernoncodeccapability;
00613 
00614    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00615 
00616    /* Make sure our new call does exist */
00617    for (tmp = client->p; tmp; tmp = tmp->next) {
00618       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00619          break;
00620       } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
00621          break;
00622       }
00623    }
00624 
00625    if (!tmp) {
00626       ast_log(LOG_WARNING, "Could not find session in iq\n");
00627       return -1;
00628    }
00629 
00630    /* codec points to the first <payload-type/> tag */
00631    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00632    while (codec) {
00633       char *codec_id = iks_find_attrib(codec, "id");
00634       char *codec_name = iks_find_attrib(codec, "name");
00635       if (!codec_id || !codec_name) {
00636          codec = iks_next_tag(codec);
00637          continue;
00638       }
00639 
00640       ast_rtp_codecs_payloads_set_m_type(
00641          ast_rtp_instance_get_codecs(tmp->rtp),
00642          tmp->rtp,
00643          atoi(codec_id));
00644       ast_rtp_codecs_payloads_set_rtpmap_type(
00645          ast_rtp_instance_get_codecs(tmp->rtp),
00646          tmp->rtp,
00647          atoi(codec_id),
00648          "audio",
00649          codec_name,
00650          0);
00651       codec = iks_next_tag(codec);
00652    }
00653 
00654    /* Now gather all of the codecs that we are asked for */
00655    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability);
00656 
00657    /* at this point, we received an awser from the remote Gtalk client,
00658       which allows us to compare capabilities */
00659    tmp->jointcapability = tmp->capability & tmp->peercapability;
00660    if (!tmp->jointcapability) {
00661       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
00662          ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
00663          ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
00664       /* close session if capabilities don't match */
00665       ast_queue_hangup(tmp->owner);
00666 
00667       return -1;
00668 
00669    }
00670 
00671    from = iks_find_attrib(pak->x, "to");
00672    if (!from) {
00673       from = client->connection->jid->full;
00674    }
00675 
00676    if (tmp->owner) {
00677       ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00678    }
00679    gtalk_update_stun(tmp->parent, tmp);
00680    gtalk_response(client, from, pak, NULL, NULL);
00681    return 1;
00682 }

static int gtalk_load_config ( void   )  [static]

Definition at line 2076 of file chan_gtalk.c.

References ahp, ast_category_browse(), ast_config_load, ast_jb_read_conf(), ast_log(), AST_MAX_CONTEXT, ast_parse_allow_disallow(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clients, config_flags, CONFIG_STATUS_FILEINVALID, context, default_jbconf, global_capability, global_jbconf, GOOGLE_CONFIG, hp, LOG_ERROR, parkinglot, prefs, stunaddr, and var.

Referenced by load_module().

02077 {
02078    char *cat = NULL;
02079    struct ast_config *cfg = NULL;
02080    char context[AST_MAX_CONTEXT];
02081    char parkinglot[AST_MAX_CONTEXT];
02082    int allowguest = 1;
02083    struct ast_variable *var;
02084    struct gtalk *member;
02085    struct ast_codec_pref prefs;
02086    struct aji_client_container *clients;
02087    struct gtalk_candidate *global_candidates = NULL;
02088    struct hostent *hp;
02089    struct ast_hostent ahp;
02090    struct ast_flags config_flags = { 0 };
02091 
02092    cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
02093    if (!cfg) {
02094       return 0;
02095    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02096       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", GOOGLE_CONFIG);
02097       return 0;
02098    }
02099 
02100    /* Copy the default jb config over global_jbconf */
02101    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02102 
02103    /* set defaults */
02104    memset(&stunaddr, 0, sizeof(stunaddr));
02105 
02106    cat = ast_category_browse(cfg, NULL);
02107    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02108       /* handle jb conf */
02109       if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
02110          continue;
02111 
02112       if (!strcasecmp(var->name, "allowguest")) {
02113          allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
02114       } else if (!strcasecmp(var->name, "disallow")) {
02115          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
02116       } else if (!strcasecmp(var->name, "allow")) {
02117          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
02118       } else if (!strcasecmp(var->name, "context")) {
02119          ast_copy_string(context, var->value, sizeof(context));
02120       } else if (!strcasecmp(var->name, "externip")) {
02121          ast_copy_string(externip, var->value, sizeof(externip));
02122       } else if (!strcasecmp(var->name, "parkinglot")) {
02123          ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
02124       } else if (!strcasecmp(var->name, "bindaddr")) {
02125          if (!(hp = ast_gethostbyname(var->value, &ahp))) {
02126             ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
02127          } else {
02128             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
02129          }
02130       } else if (!strcasecmp(var->name, "stunaddr")) {
02131          stunaddr.sin_port = htons(STANDARD_STUN_PORT);
02132          if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
02133             ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
02134          }
02135       }
02136    }
02137    while (cat) {
02138       if (strcasecmp(cat, "general")) {
02139          var = ast_variable_browse(cfg, cat);
02140          member = ast_calloc(1, sizeof(*member));
02141          ASTOBJ_INIT(member);
02142          ASTOBJ_WRLOCK(member);
02143          if (!strcasecmp(cat, "guest")) {
02144             ast_copy_string(member->name, "guest", sizeof(member->name));
02145             ast_copy_string(member->user, "guest", sizeof(member->user));
02146             ast_copy_string(member->context, context, sizeof(member->context));
02147             ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
02148             member->allowguest = allowguest;
02149             member->prefs = prefs;
02150             while (var) {
02151                if (!strcasecmp(var->name, "disallow")) {
02152                   ast_parse_allow_disallow(&member->prefs, &member->capability,
02153                                      var->value, 0);
02154                } else if (!strcasecmp(var->name, "allow")) {
02155                   ast_parse_allow_disallow(&member->prefs, &member->capability,
02156                                      var->value, 1);
02157                } else if (!strcasecmp(var->name, "context")) {
02158                   ast_copy_string(member->context, var->value,
02159                               sizeof(member->context));
02160                } else if (!strcasecmp(var->name, "parkinglot")) {
02161                   ast_copy_string(member->parkinglot, var->value,
02162                               sizeof(member->parkinglot));
02163                }
02164                var = var->next;
02165             }
02166             ASTOBJ_UNLOCK(member);
02167             clients = ast_aji_get_clients();
02168             if (clients) {
02169                ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02170                   ASTOBJ_WRLOCK(iterator);
02171                   ASTOBJ_WRLOCK(member);
02172                   if (member->connection) {
02173                      ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
02174                   }
02175                   member->connection = NULL;
02176                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
02177                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
02178                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE);
02179                   ASTOBJ_UNLOCK(member);
02180                   ASTOBJ_UNLOCK(iterator);
02181                });
02182                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02183                ASTOBJ_UNREF(member, gtalk_member_destroy);
02184             } else {
02185                ASTOBJ_UNLOCK(member);
02186                ASTOBJ_UNREF(member, gtalk_member_destroy);
02187             }
02188          } else {
02189             ASTOBJ_UNLOCK(member);
02190             if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
02191                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02192             ASTOBJ_UNREF(member, gtalk_member_destroy);
02193          }
02194       }
02195       cat = ast_category_browse(cfg, cat);
02196    }
02197 
02198    gtalk_update_externip();
02199    gtalk_free_candidates(global_candidates);
02200    return 1;
02201 }

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 241 of file chan_gtalk.c.

References ast_free.

Referenced by gtalk_parser(), gtalk_request(), and unload_module().

00242 {
00243    ast_free(obj);
00244 }

static struct ast_channel* gtalk_new ( struct gtalk client,
struct gtalk_pvt i,
int  state,
const char *  title,
const char *  linkedid 
) [static]

Start new gtalk channel.

Definition at line 1081 of file chan_gtalk.c.

References accountcode, gtalk::accountcode, ast_channel::adsicpe, ast_channel::amaflags, gtalk::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc, ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), AST_FORMAT_VIDEO_MASK, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_random(), ast_rtp_codecs_packetization_set(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::caller, gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_channel::context, gtalk::context, ast_channel::dialed, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_capability, global_jbconf, gtalk_tech, ast_channel::hangupcause, ast_party_caller::id, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_party_id::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_party_number::presentation, ast_party_name::presentation, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, gtalk_pvt::sid, ast_party_dialed::str, ast_channel::tech, ast_channel::tech_pvt, gtalk_pvt::us, gtalk_pvt::vrtp, and ast_channel::writeformat.

Referenced by gtalk_newcall(), and gtalk_request().

01082 {
01083    struct ast_channel *tmp;
01084    int fmt;
01085    int what;
01086    const char *n2;
01087 
01088    if (title)
01089       n2 = title;
01090    else
01091       n2 = i->us;
01092    tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
01093    if (!tmp) {
01094       ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01095       return NULL;
01096    }
01097    tmp->tech = &gtalk_tech;
01098 
01099    /* Select our native format based on codec preference until we receive
01100       something from another device to the contrary. */
01101    if (i->jointcapability)
01102       what = i->jointcapability;
01103    else if (i->capability)
01104       what = i->capability;
01105    else
01106       what = global_capability;
01107 
01108    /* Set Frame packetization */
01109    if (i->rtp) {
01110       ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
01111    }
01112 
01113    tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
01114    fmt = ast_best_codec(tmp->nativeformats);
01115 
01116    if (i->rtp) {
01117       ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
01118       ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
01119    }
01120    if (i->vrtp) {
01121       ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
01122       ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
01123    }
01124    if (state == AST_STATE_RING)
01125       tmp->rings = 1;
01126    tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01127    tmp->writeformat = fmt;
01128    tmp->rawwriteformat = fmt;
01129    tmp->readformat = fmt;
01130    tmp->rawreadformat = fmt;
01131    tmp->tech_pvt = i;
01132 
01133    tmp->callgroup = client->callgroup;
01134    tmp->pickupgroup = client->pickupgroup;
01135    tmp->caller.id.name.presentation = client->callingpres;
01136    tmp->caller.id.number.presentation = client->callingpres;
01137    if (!ast_strlen_zero(client->accountcode))
01138       ast_string_field_set(tmp, accountcode, client->accountcode);
01139    if (client->amaflags)
01140       tmp->amaflags = client->amaflags;
01141    if (!ast_strlen_zero(client->language))
01142       ast_string_field_set(tmp, language, client->language);
01143    if (!ast_strlen_zero(client->musicclass))
01144       ast_string_field_set(tmp, musicclass, client->musicclass);
01145    if (!ast_strlen_zero(client->parkinglot))
01146       ast_string_field_set(tmp, parkinglot, client->parkinglot);
01147    i->owner = tmp;
01148    ast_module_ref(ast_module_info->self);
01149    ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01150    ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01151 
01152    if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
01153       tmp->dialed.number.str = ast_strdup(i->exten);
01154    }
01155    tmp->priority = 1;
01156    if (i->rtp)
01157       ast_jb_configure(tmp, &global_jbconf);
01158    if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01159       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01160       tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01161       ast_hangup(tmp);
01162       tmp = NULL;
01163    } else {
01164       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01165          "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01166          i->owner ? i->owner->name : "", "Gtalk", i->sid);
01167    }
01168    return tmp;
01169 }

static int gtalk_newcall ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 1247 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_aji_client_destroy(), ast_aji_get_client(), ast_channel_release(), ast_copy_string(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, ASTOBJ_UNREF, gtalk_pvt::capability, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_new(), gtalk_response(), aji_client::jid, gtalk_pvt::jointcapability, gtalk_pvt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::peercapability, gtalk_pvt::rtp, S_OR, gtalk_pvt::sid, gtalk_pvt::them, gtalk_pvt::us, and gtalk_pvt::vrtp.

Referenced by gtalk_parser().

01248 {
01249    struct gtalk_pvt *p, *tmp = client->p;
01250    struct ast_channel *chan;
01251    int res;
01252    iks *codec;
01253    char *from = NULL;
01254    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01255    int peernoncodeccapability;
01256    char *sid;
01257 
01258    /* Make sure our new call doesn't exist yet */
01259    from = iks_find_attrib(pak->x,"to");
01260    if (!from) {
01261       from = client->connection->jid->full;
01262    }
01263 
01264    while (tmp) {
01265       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01266          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01267          ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01268          gtalk_response(client, from, pak, "out-of-order", NULL);
01269          return -1;
01270       }
01271       tmp = tmp->next;
01272    }
01273 
01274    if (!strcasecmp(client->name, "guest")){
01275       /* the guest account is not tied to any configured XMPP client,
01276          let's set it now */
01277       if (client->connection) {
01278          ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01279       }
01280       client->connection = ast_aji_get_client(from);
01281       if (!client->connection) {
01282          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01283          return -1;
01284       }
01285    }
01286 
01287    if (!(sid = iks_find_attrib(pak->query, "id"))) {
01288       ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
01289       return -1;
01290    }
01291 
01292    p = gtalk_alloc(client, from, pak->from->full, sid);
01293    if (!p) {
01294       ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01295       return -1;
01296    }
01297 
01298    chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
01299    if (!chan) {
01300       gtalk_free_pvt(client, p);
01301       return -1;
01302    }
01303 
01304    ast_mutex_lock(&p->lock);
01305    ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01306    ast_copy_string(p->sid, sid, sizeof(p->sid));
01307 
01308    /* codec points to the first <payload-type/> tag */
01309    codec = iks_first_tag(iks_first_tag(pak->query));
01310 
01311    while (codec) {
01312       char *codec_id = iks_find_attrib(codec, "id");
01313       char *codec_name = iks_find_attrib(codec, "name");
01314       if (!codec_id || !codec_name) {
01315          codec = iks_next_tag(codec);
01316          continue;
01317       }
01318       if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
01319          ast_rtp_codecs_payloads_set_m_type(
01320             ast_rtp_instance_get_codecs(p->vrtp),
01321             p->vrtp,
01322             atoi(codec_id));
01323          ast_rtp_codecs_payloads_set_rtpmap_type(
01324             ast_rtp_instance_get_codecs(p->vrtp),
01325             p->vrtp,
01326             atoi(codec_id),
01327             "video",
01328             codec_name,
01329             0);
01330       } else {
01331          ast_rtp_codecs_payloads_set_m_type(
01332             ast_rtp_instance_get_codecs(p->rtp),
01333             p->rtp,
01334             atoi(codec_id));
01335          ast_rtp_codecs_payloads_set_rtpmap_type(
01336             ast_rtp_instance_get_codecs(p->rtp),
01337             p->rtp,
01338             atoi(codec_id),
01339             "audio",
01340             codec_name,
01341             0);
01342       }
01343       codec = iks_next_tag(codec);
01344    }
01345 
01346    /* Now gather all of the codecs that we are asked for */
01347    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), &p->peercapability, &peernoncodeccapability);
01348    p->jointcapability = p->capability & p->peercapability;
01349    ast_mutex_unlock(&p->lock);
01350 
01351    ast_setstate(chan, AST_STATE_RING);
01352    if (!p->jointcapability) {
01353       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
01354          ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
01355          ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
01356       /* close session if capabilities don't match */
01357       gtalk_action(client, p, "reject");
01358       p->alreadygone = 1;
01359       gtalk_hangup(chan);
01360       ast_channel_release(chan);
01361       return -1;
01362    }
01363 
01364    res = ast_pbx_start(chan);
01365 
01366    switch (res) {
01367    case AST_PBX_FAILED:
01368       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01369       gtalk_response(client, from, pak, "service-unavailable", NULL);
01370       break;
01371    case AST_PBX_CALL_LIMIT:
01372       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01373       gtalk_response(client, from, pak, "service-unavailable", NULL);
01374       break;
01375    case AST_PBX_SUCCESS:
01376       gtalk_response(client, from, pak, NULL, NULL);
01377       gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01378       /* nothing to do */
01379       break;
01380    }
01381 
01382    return 1;
01383 }

static int gtalk_parser ( void *  data,
ikspak *  pak 
) [static]

CLI command "gtalk reload".

Todo:
XXX TODO make this work.

Definition at line 1985 of file chan_gtalk.c.

References ast_debug, ast_log(), ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, gtalk_add_candidate(), gtalk_handle_dtmf(), gtalk_hangup_farend(), gtalk_is_accepted(), gtalk_is_answered(), gtalk_member_destroy(), gtalk_newcall(), LOG_NOTICE, LOG_WARNING, and S_OR.

Referenced by gtalk_create_member().

01986 {
01987    struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01988    int res;
01989    iks *tmp;
01990 
01991    if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
01992       ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
01993       pak->query = tmp;
01994    }
01995 
01996    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
01997       ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
01998    }
01999 
02000    if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
02001       ast_log(LOG_NOTICE, "No attribute \"type\" found.  Ignoring message.\n");
02002    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
02003       /* New call */
02004       gtalk_newcall(client, pak);
02005    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
02006       ast_debug(3, "About to add candidate!\n");
02007       res = gtalk_add_candidate(client, pak);
02008       if (!res) {
02009          ast_log(LOG_WARNING, "Could not add any candidate\n");
02010       } else {
02011          ast_debug(3, "Candidate Added!\n");
02012       }
02013    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
02014       gtalk_is_answered(client, pak);
02015    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
02016       gtalk_is_accepted(client, pak);
02017    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
02018       gtalk_handle_dtmf(client, pak);
02019    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
02020       gtalk_hangup_farend(client, pak);
02021    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
02022       gtalk_hangup_farend(client, pak);
02023    }
02024    ASTOBJ_UNREF(client, gtalk_member_destroy);
02025    return IKS_FILTER_EAT;
02026 }

static struct ast_frame * gtalk_read ( struct ast_channel ast  )  [static]

Definition at line 1595 of file chan_gtalk.c.

References ast_mutex_lock, ast_mutex_unlock, gtalk_rtp_read(), gtalk_pvt::lock, and ast_channel::tech_pvt.

01596 {
01597    struct ast_frame *fr;
01598    struct gtalk_pvt *p = ast->tech_pvt;
01599 
01600    ast_mutex_lock(&p->lock);
01601    fr = gtalk_rtp_read(ast, p);
01602    ast_mutex_unlock(&p->lock);
01603    return fr;
01604 }

static struct ast_channel * gtalk_request ( const char *  type,
format_t  format,
const struct ast_channel requestor,
void *  data,
int *  cause 
) [static]

Part of PBX interface.

Definition at line 1851 of file chan_gtalk.c.

References ast_aji_client_destroy(), ast_aji_get_client(), ast_log(), AST_STATE_DOWN, ast_strdupa, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, gtalk::connection, find_gtalk(), gtalk_alloc(), gtalk_member_destroy(), gtalk_new(), aji_client::jid, ast_channel::linkedid, LOG_ERROR, LOG_WARNING, gtalk::name, strsep(), and gtalk::user.

01852 {
01853    struct gtalk_pvt *p = NULL;
01854    struct gtalk *client = NULL;
01855    char *sender = NULL, *to = NULL, *s = NULL;
01856    struct ast_channel *chan = NULL;
01857 
01858    if (data) {
01859       s = ast_strdupa(data);
01860       if (s) {
01861          sender = strsep(&s, "/");
01862          if (sender && (sender[0] != '\0')) {
01863             to = strsep(&s, "/");
01864          }
01865          if (!to) {
01866             ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01867             return NULL;
01868          }
01869       }
01870    }
01871 
01872    client = find_gtalk(to, sender);
01873    if (!client) {
01874       ast_log(LOG_WARNING, "Could not find recipient.\n");
01875       return NULL;
01876    }
01877    if (!strcasecmp(client->name, "guest")){
01878       /* the guest account is not tied to any configured XMPP client,
01879          let's set it now */
01880       if (client->connection) {
01881          ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01882       }
01883       client->connection = ast_aji_get_client(sender);
01884       if (!client->connection) {
01885          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01886          ASTOBJ_UNREF(client, gtalk_member_destroy);
01887          return NULL;
01888       }
01889    }
01890 
01891    ASTOBJ_WRLOCK(client);
01892    p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01893    if (p) {
01894       chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL);
01895    }
01896    ASTOBJ_UNLOCK(client);
01897    return chan;
01898 }

static int gtalk_response ( struct gtalk client,
char *  from,
ikspak *  pak,
const char *  reasonstr,
const char *  reasonstr2 
) [static]

Definition at line 574 of file chan_gtalk.c.

References ast_aji_send(), gtalk::connection, and S_OR.

Referenced by gtalk_handle_dtmf(), gtalk_hangup_farend(), gtalk_is_accepted(), gtalk_is_answered(), and gtalk_newcall().

00575 {
00576    iks *response = NULL, *error = NULL, *reason = NULL;
00577    int res = -1;
00578 
00579    response = iks_new("iq");
00580    if (response) {
00581       iks_insert_attrib(response, "type", "result");
00582       iks_insert_attrib(response, "from", from);
00583       iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
00584       iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
00585       if (reasonstr) {
00586          error = iks_new("error");
00587          if (error) {
00588             iks_insert_attrib(error, "type", "cancel");
00589             reason = iks_new(reasonstr);
00590             if (reason)
00591                iks_insert_node(error, reason);
00592             iks_insert_node(response, error);
00593          }
00594       }
00595       ast_aji_send(client->connection, response);
00596       res = 0;
00597    }
00598 
00599    iks_delete(reason);
00600    iks_delete(error);
00601    iks_delete(response);
00602 
00603    return res;
00604 }

static int gtalk_ringing_ack ( void *  data,
ikspak *  pak 
) [static]

Definition at line 461 of file chan_gtalk.c.

References AST_CONTROL_RINGING, ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_create_candidates(), gtalk_invite(), gtalk_pvt::lock, LOG_DEBUG, name, gtalk_pvt::owner, gtalk_pvt::parent, gtalk_pvt::ringrule, S_OR, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_call().

00462 {
00463    struct gtalk_pvt *p = data;
00464    struct ast_channel *owner;
00465 
00466    ast_mutex_lock(&p->lock);
00467 
00468    if (p->ringrule) {
00469       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00470    }
00471    p->ringrule = NULL;
00472 
00473    /* this may be a redirect */
00474    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
00475       char *name = NULL;
00476       char *redirect = NULL;
00477       iks *traversenodes = NULL;
00478       traversenodes = pak->query;
00479       while (traversenodes) {
00480          if (!(name = iks_name(traversenodes))) {
00481             break;
00482          }
00483          if (!strcasecmp(name, "error") &&
00484             ((redirect = iks_find_cdata(traversenodes, "redirect")) ||
00485               (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
00486             (redirect = strstr(redirect, "xmpp:"))) {
00487             redirect += 5;
00488             ast_log(LOG_DEBUG, "redirect %s\n", redirect);
00489             ast_copy_string(p->them, redirect, sizeof(p->them));
00490 
00491             gtalk_invite(p, p->them, p->us, p->sid, 1);
00492             break;
00493          }
00494          traversenodes = iks_next_tag(traversenodes);
00495       }
00496    }
00497    gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
00498    owner = p->owner;
00499    ast_mutex_unlock(&p->lock);
00500 
00501    if (owner) {
00502       ast_queue_control(owner, AST_CONTROL_RINGING);
00503    }
00504 
00505    return IKS_FILTER_EAT;
00506 }

static struct ast_frame* gtalk_rtp_read ( struct ast_channel ast,
struct gtalk_pvt p 
) [static]

Definition at line 1566 of file chan_gtalk.c.

References ast_debug, AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_FRAME_VOICE, ast_getformatname(), ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), f, gtalk_update_stun(), ast_channel::nativeformats, gtalk_pvt::owner, gtalk_pvt::parent, ast_channel::readformat, gtalk_pvt::rtp, and ast_channel::writeformat.

Referenced by gtalk_read().

01567 {
01568    struct ast_frame *f;
01569 
01570    if (!p->rtp) {
01571       return &ast_null_frame;
01572    }
01573    f = ast_rtp_instance_read(p->rtp, 0);
01574    gtalk_update_stun(p->parent, p);
01575    if (p->owner) {
01576       /* We already hold the channel lock */
01577       if (f->frametype == AST_FRAME_VOICE) {
01578          if (f->subclass.codec != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01579             ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
01580             p->owner->nativeformats =
01581                (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass.codec;
01582             ast_set_read_format(p->owner, p->owner->readformat);
01583             ast_set_write_format(p->owner, p->owner->writeformat);
01584          }
01585          /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
01586             f = ast_dsp_process(p->owner, p->vad, f);
01587             if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
01588                ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
01589            } */
01590       }
01591    }
01592    return f;
01593 }

static int gtalk_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
) [static]

Definition at line 1797 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01798 {
01799    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01800 
01801    return -1;
01802 }

static int gtalk_sendtext ( struct ast_channel ast,
const char *  text 
) [static]

Definition at line 1687 of file chan_gtalk.c.

References ast_aji_send_chat(), ast_log(), gtalk::connection, LOG_ERROR, gtalk_pvt::parent, ast_channel::tech_pvt, and gtalk_pvt::them.

01688 {
01689    int res = 0;
01690    struct aji_client *client = NULL;
01691    struct gtalk_pvt *p = chan->tech_pvt;
01692 
01693    if (!p->parent) {
01694       ast_log(LOG_ERROR, "Parent channel not found\n");
01695       return -1;
01696    }
01697    if (!p->parent->connection) {
01698       ast_log(LOG_ERROR, "XMPP client not found\n");
01699       return -1;
01700    }
01701    client = p->parent->connection;
01702    res = ast_aji_send_chat(client, p->them, text);
01703    return res;
01704 }

static int gtalk_set_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance rtp,
struct ast_rtp_instance vrtp,
struct ast_rtp_instance trtp,
format_t  codecs,
int  nat_active 
) [static]

Definition at line 547 of file chan_gtalk.c.

References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, and ast_channel::tech_pvt.

00548 {
00549    struct gtalk_pvt *p;
00550 
00551    p = chan->tech_pvt;
00552    if (!p)
00553       return -1;
00554    ast_mutex_lock(&p->lock);
00555 
00556 /* if (rtp)
00557       ast_rtp_get_peer(rtp, &p->redirip);
00558    else
00559       memset(&p->redirip, 0, sizeof(p->redirip));
00560    p->redircodecs = codecs; */
00561 
00562    /* Reset lastrtprx timer */
00563    ast_mutex_unlock(&p->lock);
00564    return 0;
00565 }

static char * gtalk_show_channels ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command "gtalk show channels".

Definition at line 1901 of file chan_gtalk.c.

References AJI_MAX_JIDLEN, ast_cli_args::argc, ast_cli(), ast_copy_string(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, gtalk_list, gtalklock, LOG_WARNING, ast_channel::name, gtalk_pvt::next, gtalk_pvt::owner, ast_channel::readformat, gtalk_pvt::them, ast_cli_entry::usage, and ast_channel::writeformat.

01902 {
01903 #define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
01904    struct gtalk_pvt *p;
01905    struct ast_channel *chan;
01906    int numchans = 0;
01907    char them[AJI_MAX_JIDLEN];
01908    char *jid = NULL;
01909    char *resource = NULL;
01910 
01911    switch (cmd) {
01912    case CLI_INIT:
01913       e->command = "gtalk show channels";
01914       e->usage =
01915          "Usage: gtalk show channels\n"
01916          "       Shows current state of the Gtalk channels.\n";
01917       return NULL;
01918    case CLI_GENERATE:
01919       return NULL;
01920    }
01921 
01922    if (a->argc != 3)
01923       return CLI_SHOWUSAGE;
01924 
01925    ast_mutex_lock(&gtalklock);
01926    ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01927    ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
01928       ASTOBJ_WRLOCK(iterator);
01929       p = iterator->p;
01930       while(p) {
01931          chan = p->owner;
01932          ast_copy_string(them, p->them, sizeof(them));
01933          jid = them;
01934          resource = strchr(them, '/');
01935          if (!resource)
01936             resource = "None";
01937          else {
01938             *resource = '\0';
01939             resource ++;
01940          }
01941          if (chan)
01942             ast_cli(a->fd, FORMAT,
01943                chan->name,
01944                jid,
01945                resource,
01946                ast_getformatname(chan->readformat),
01947                ast_getformatname(chan->writeformat)
01948                );
01949          else
01950             ast_log(LOG_WARNING, "No available channel\n");
01951          numchans ++;
01952          p = p->next;
01953       }
01954       ASTOBJ_UNLOCK(iterator);
01955    });
01956 
01957    ast_mutex_unlock(&gtalklock);
01958 
01959    ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01960    return CLI_SUCCESS;
01961 #undef FORMAT
01962 }

static int gtalk_update_externip ( void   )  [static]

Definition at line 1385 of file chan_gtalk.c.

References ast_connect(), ast_inet_ntoa(), ast_log(), ast_sockaddr_from_sin, ast_sockaddr_stringify(), ast_strdupa, ast_stun_request(), errno, externip, LOG_WARNING, and stunaddr.

Referenced by gtalk_create_candidates().

01386 {
01387    int sock;
01388    char *newaddr;
01389    struct sockaddr_in answer = { 0, };
01390    struct sockaddr_in *dst;
01391    struct ast_sockaddr tmp_dst;
01392 
01393    if (!stunaddr.sin_addr.s_addr) {
01394       return -1;
01395    }
01396    dst = &stunaddr;
01397 
01398    sock = socket(AF_INET, SOCK_DGRAM, 0);
01399    if (sock < 0) {
01400       ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
01401       return -1;
01402    }
01403 
01404    ast_sockaddr_from_sin(&tmp_dst, dst);
01405    if (ast_connect(sock, &tmp_dst) != 0) {
01406       ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
01407       close(sock);
01408       return -1;
01409    }
01410 
01411    if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
01412       close(sock);
01413       return -1;
01414    }
01415 
01416    newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
01417    memcpy(externip, newaddr, sizeof(externip));
01418 
01419    close(sock);
01420    return 0;
01421 
01422 }

static int gtalk_update_stun ( struct gtalk client,
struct gtalk_pvt p 
) [static]

Definition at line 1424 of file chan_gtalk.c.

References ahp, ast_debug, ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_instance_get_remote_address(), ast_rtp_instance_stun_request(), ast_sockaddr_from_sin, ast_sockaddr_to_sin, hp, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_WARNING, gtalk_candidate::next, gtalk_pvt::ourcandidates, gtalk_candidate::port, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_candidate::username.

Referenced by gtalk_add_candidate(), gtalk_is_accepted(), gtalk_is_answered(), and gtalk_rtp_read().

01425 {
01426    struct gtalk_candidate *tmp;
01427    struct hostent *hp;
01428    struct ast_hostent ahp;
01429    struct sockaddr_in sin = { 0, };
01430    struct sockaddr_in aux = { 0, };
01431    struct ast_sockaddr sin_tmp;
01432    struct ast_sockaddr aux_tmp;
01433 
01434    if (time(NULL) == p->laststun)
01435       return 0;
01436 
01437    tmp = p->theircandidates;
01438    p->laststun = time(NULL);
01439    while (tmp) {
01440       char username[256];
01441 
01442       /* Find the IP address of the host */
01443       if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
01444          ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
01445          tmp = tmp->next;
01446          continue;
01447       }
01448       sin.sin_family = AF_INET;
01449       memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01450       sin.sin_port = htons(tmp->port);
01451       snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
01452 
01453       /* Find out the result of the STUN */
01454       ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
01455       ast_sockaddr_to_sin(&aux_tmp, &aux);
01456 
01457       /* If the STUN result is different from the IP of the hostname,
01458        * lock on the stun IP of the hostname advertised by the
01459        * remote client */
01460       if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
01461          ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
01462       } else {
01463          ast_sockaddr_from_sin(&sin_tmp, &sin);
01464          ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
01465       }
01466       if (aux.sin_addr.s_addr) {
01467          ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01468          ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01469       }
01470 
01471       tmp = tmp->next;
01472    }
01473    return 1;
01474 }

static int gtalk_write ( struct ast_channel ast,
struct ast_frame f 
) [static]

Send frame to media channel (rtp).

Definition at line 1607 of file chan_gtalk.c.

References AST_FRAME_IMAGE, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_frame_subclass::codec, ast_frame::frametype, gtalk_pvt::lock, LOG_WARNING, ast_channel::nativeformats, ast_channel::readformat, gtalk_pvt::rtp, ast_frame::subclass, ast_channel::tech_pvt, gtalk_pvt::vrtp, and ast_channel::writeformat.

01608 {
01609    struct gtalk_pvt *p = ast->tech_pvt;
01610    int res = 0;
01611    char buf[256];
01612 
01613    switch (frame->frametype) {
01614    case AST_FRAME_VOICE:
01615       if (!(frame->subclass.codec & ast->nativeformats)) {
01616          ast_log(LOG_WARNING,
01617                "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01618                ast_getformatname(frame->subclass.codec),
01619                ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
01620                ast_getformatname(ast->readformat),
01621                ast_getformatname(ast->writeformat));
01622          return 0;
01623       }
01624       if (p) {
01625          ast_mutex_lock(&p->lock);
01626          if (p->rtp) {
01627             res = ast_rtp_instance_write(p->rtp, frame);
01628          }
01629          ast_mutex_unlock(&p->lock);
01630       }
01631       break;
01632    case AST_FRAME_VIDEO:
01633       if (p) {
01634          ast_mutex_lock(&p->lock);
01635          if (p->vrtp) {
01636             res = ast_rtp_instance_write(p->vrtp, frame);
01637          }
01638          ast_mutex_unlock(&p->lock);
01639       }
01640       break;
01641    case AST_FRAME_IMAGE:
01642       return 0;
01643       break;
01644    default:
01645       ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01646             frame->frametype);
01647       return 0;
01648    }
01649 
01650    return res;
01651 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 2204 of file chan_gtalk.c.

References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_glue_register, ast_sockaddr_from_sin, ast_sockaddr_ipv4(), ASTOBJ_CONTAINER_INIT, bindaddr, free, GOOGLE_CONFIG, gtalk_cli, gtalk_get_local_ip(), gtalk_list, gtalk_load_config(), gtalk_rtp_glue, gtalk_tech, io, io_context_create(), LOG_ERROR, LOG_WARNING, sched_context_create(), and ast_channel_tech::type.

02205 {
02206    struct ast_sockaddr bindaddr_tmp;
02207    struct ast_sockaddr ourip_tmp;
02208 
02209    char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02210    free(jabber_loaded);
02211    if (!jabber_loaded) {
02212       /* If embedded, check for a different module name */
02213       jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02214       free(jabber_loaded);
02215       if (!jabber_loaded) {
02216          ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02217          return AST_MODULE_LOAD_DECLINE;
02218       }
02219    }
02220 
02221    ASTOBJ_CONTAINER_INIT(&gtalk_list);
02222    if (!gtalk_load_config()) {
02223       ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02224       return 0;
02225    }
02226 
02227    sched = sched_context_create();
02228    if (!sched) {
02229       ast_log(LOG_WARNING, "Unable to create schedule context\n");
02230    }
02231 
02232    io = io_context_create();
02233    if (!io) {
02234       ast_log(LOG_WARNING, "Unable to create I/O context\n");
02235    }
02236 
02237    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02238    if (gtalk_get_local_ip(&ourip_tmp)) {
02239       ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02240       return 0;
02241    }
02242    __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
02243 
02244    ast_rtp_glue_register(&gtalk_rtp_glue);
02245    ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02246 
02247    /* Make sure we can register our channel type */
02248    if (ast_channel_register(&gtalk_tech)) {
02249       ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02250       return -1;
02251    }
02252    return 0;
02253 }

static int unload_module ( void   )  [static]

Reload module Unload the gtalk channel from Asterisk.

Definition at line 2264 of file chan_gtalk.c.

References ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_glue_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, gtalk_cli, gtalk_list, gtalk_member_destroy(), gtalk_rtp_glue, gtalk_tech, gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.

02265 {
02266    struct gtalk_pvt *privates = NULL;
02267    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02268    /* First, take us out of the channel loop */
02269    ast_channel_unregister(&gtalk_tech);
02270    ast_rtp_glue_unregister(&gtalk_rtp_glue);
02271 
02272    if (!ast_mutex_lock(&gtalklock)) {
02273       /* Hangup all interfaces if they have an owner */
02274       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02275          ASTOBJ_WRLOCK(iterator);
02276          privates = iterator->p;
02277          while(privates) {
02278             if (privates->owner)
02279                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02280             privates = privates->next;
02281          }
02282          iterator->p = NULL;
02283          ASTOBJ_UNLOCK(iterator);
02284       });
02285       ast_mutex_unlock(&gtalklock);
02286    } else {
02287       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02288       return -1;
02289    }
02290    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02291    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02292    return 0;
02293 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Gtalk Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 2300 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 229 of file chan_gtalk.c.

Referenced by find_subchannel_and_lock(), and load_module().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2300 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

The address we bind to

Definition at line 225 of file chan_gtalk.c.

Referenced by __sip_subscribe_mwi_do(), ast_find_ourip(), ast_sip_ouraddrfor(), build_peer(), create_addr(), dialog_initialize_rtp(), gtalk_alloc(), gtalk_get_local_ip(), initialize_udptl(), jingle_alloc(), jingle_create_candidates(), jingle_load_config(), load_module(), proxy_update(), realtime_peer_by_name(), reload_config(), sip_show_settings(), sipsock_read(), start_rtp(), and transmit_register().

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 83 of file chan_gtalk.c.

const char desc[] = "Gtalk Channel" [static]

Definition at line 169 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 236 of file chan_gtalk.c.

Referenced by gtalk_create_candidates(), gtalk_update_externip(), jingle_create_candidates(), and jingle_load_config().

format_t global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263 [static]

Definition at line 171 of file chan_gtalk.c.

Referenced by gtalk_alloc(), gtalk_load_config(), gtalk_new(), jingle_load_config(), and jingle_new().

struct ast_jb_conf global_jbconf [static]

Definition at line 91 of file chan_gtalk.c.

struct ast_cli_entry gtalk_cli[] [static]

Initial value:

 {

   { .handler =  gtalk_show_channels , .summary =  "Show GoogleTalk channels" ,__VA_ARGS__ },
}

Definition at line 231 of file chan_gtalk.c.

Referenced by load_module(), and unload_module().

struct gtalk_container gtalk_list [static]

Definition at line 239 of file chan_gtalk.c.

Referenced by find_gtalk(), gtalk_show_channels(), load_module(), and unload_module().

struct ast_rtp_glue gtalk_rtp_glue [static]

Definition at line 567 of file chan_gtalk.c.

Referenced by load_module(), and unload_module().

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 201 of file chan_gtalk.c.

Referenced by gtalk_new(), load_module(), and unload_module().

ast_mutex_t gtalklock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Protect the interface list (of gtalk_pvt's)

Definition at line 173 of file chan_gtalk.c.

Referenced by gtalk_alloc(), gtalk_show_channels(), and unload_module().

struct io_context* io [static]

The IO context

Definition at line 228 of file chan_gtalk.c.

Referenced by ast_expr(), ast_str_expr(), do_monitor(), initialize_udptl(), load_module(), network_thread(), peer_set_srcaddr(), reload(), set_config(), and unload_module().

struct sched_context* sched [static]

The scheduling context

Definition at line 227 of file chan_gtalk.c.

Referenced by __attempt_transmit(), __find_callno(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __unload_module(), ack_trans(), ast_rtp_instance_new(), auth_fail(), build_peer(), create_esc_entry(), delete_users(), destroy_event(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_monitor(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), esc_entry_destructor(), handle_command_response(), handle_dump_sched(), iax2_ack_registry(), iax2_call(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_hangup(), iax2_key_rotate(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_change_event_cb(), network_thread(), populate_addr(), precache_trans(), qualify_peer(), reg_source_db(), sched_delay_remove(), schedule_calendar_event(), schedule_delivery(), sip_cc_agent_start_offer_timer(), sip_cc_agent_stop_offer_timer(), sip_cc_monitor_cancel_available_timer(), sip_cc_monitor_request_cc(), socket_process(), start_rtp(), stun_start_monitor(), stun_stop_monitor(), transmit_frame(), unlink_peer(), unload_module(), update_jbsched(), and update_registry().

struct sockaddr_in stunaddr [static]

the stun server we get the externip from

Definition at line 237 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and gtalk_update_externip().


Generated on Mon Mar 19 11:30:39 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7