Fri Jul 15 2011 12:00:04

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.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 dependency graph for chan_gtalk.c:

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"
#define GOOGLE_NS   "http://www.google.com/session"

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 (struct ast_channel *ast, char digit, unsigned int duration)
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 char * gtalk_do_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command "gtalk reload".
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 int gtalk_get_codec (struct ast_channel *chan)
static enum ast_rtp_get_result gtalk_get_rtp_peer (struct ast_channel *chan, struct ast_rtp **rtp)
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_invite_response (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)
 Start new gtalk channel.
static int gtalk_newcall (struct gtalk *client, ikspak *pak)
static int gtalk_parser (void *data, ikspak *pak)
static struct ast_framegtalk_read (struct ast_channel *ast)
static struct ast_channelgtalk_request (const char *type, int format, 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_set_rtp_peer (struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int 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_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 reload (void)
 Reload module.
static int unload_module (void)
 Unload the gtalk channel from Asterisk.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
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 int 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_protocol gtalk_rtp
 RTP driver interface.
static struct ast_channel_tech gtalk_tech
 PBX interface structure for channel registration.
static ast_mutex_t gtalklock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static struct io_contextio
static struct sched_contextsched

Detailed Description

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

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

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 70 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and load_module().

#define GOOGLE_NS   "http://www.google.com/session"

Definition at line 72 of file chan_gtalk.c.

Referenced by gtalk_create_candidates().


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 91 of file chan_gtalk.c.

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 86 of file chan_gtalk.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 2119 of file chan_gtalk.c.

static void __unreg_module ( void  ) [static]

Definition at line 2119 of file chan_gtalk.c.

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

Definition at line 274 of file chan_gtalk.c.

References ast_getformatname(), ast_log(), ast_rtp_lookup_code(), format, LOG_WARNING, and gtalk_pvt::rtp.

Referenced by gtalk_invite().

{
   int res = 0;
   char *format = ast_getformatname(codec);

   if (!strcasecmp("ulaw", format)) {
      iks *payload_eg711u, *payload_pcmu;
      payload_pcmu = iks_new("payload-type");
      payload_eg711u = iks_new("payload-type");
   
      if(!payload_eg711u || !payload_pcmu) {
         iks_delete(payload_pcmu);
         iks_delete(payload_eg711u);
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_pcmu, "id", "0");
      iks_insert_attrib(payload_pcmu, "name", "PCMU");
      iks_insert_attrib(payload_pcmu, "clockrate","8000");
      iks_insert_attrib(payload_pcmu, "bitrate","64000");
      iks_insert_attrib(payload_eg711u, "id", "100");
      iks_insert_attrib(payload_eg711u, "name", "EG711U");
      iks_insert_attrib(payload_eg711u, "clockrate","8000");
      iks_insert_attrib(payload_eg711u, "bitrate","64000");
      iks_insert_node(dcodecs, payload_pcmu);
      iks_insert_node(dcodecs, payload_eg711u);
      res ++;
   }
   if (!strcasecmp("alaw", format)) {
      iks *payload_eg711a, *payload_pcma;
      payload_pcma = iks_new("payload-type");
      payload_eg711a = iks_new("payload-type");
      if(!payload_eg711a || !payload_pcma) {
         iks_delete(payload_eg711a);
         iks_delete(payload_pcma);
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_pcma, "id", "8");
      iks_insert_attrib(payload_pcma, "name", "PCMA");
      iks_insert_attrib(payload_pcma, "clockrate","8000");
      iks_insert_attrib(payload_pcma, "bitrate","64000");
      payload_eg711a = iks_new("payload-type");
      iks_insert_attrib(payload_eg711a, "id", "101");
      iks_insert_attrib(payload_eg711a, "name", "EG711A");
      iks_insert_attrib(payload_eg711a, "clockrate","8000");
      iks_insert_attrib(payload_eg711a, "bitrate","64000");
      iks_insert_node(dcodecs, payload_pcma);
      iks_insert_node(dcodecs, payload_eg711a);
      res ++;
   }
   if (!strcasecmp("ilbc", format)) {
      iks *payload_ilbc = iks_new("payload-type");
      if(!payload_ilbc) {
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_ilbc, "id", "97");
      iks_insert_attrib(payload_ilbc, "name", "iLBC");
      iks_insert_attrib(payload_ilbc, "clockrate","8000");
      iks_insert_attrib(payload_ilbc, "bitrate","13300");
      iks_insert_node(dcodecs, payload_ilbc);
      res ++;
   }
   if (!strcasecmp("g723", format)) {
      iks *payload_g723 = iks_new("payload-type");
      if(!payload_g723) {
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_g723, "id", "4");
      iks_insert_attrib(payload_g723, "name", "G723");
      iks_insert_attrib(payload_g723, "clockrate","8000");
      iks_insert_attrib(payload_g723, "bitrate","6300");
      iks_insert_node(dcodecs, payload_g723);
      res ++;
   }
   if (!strcasecmp("speex", format)) {
      iks *payload_speex = iks_new("payload-type");
      if(!payload_speex) {
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_speex, "id", "110");
      iks_insert_attrib(payload_speex, "name", "speex");
      iks_insert_attrib(payload_speex, "clockrate","8000");
      iks_insert_attrib(payload_speex, "bitrate","11000");
      iks_insert_node(dcodecs, payload_speex);
      res++;
   }
   if (!strcasecmp("gsm", format)) {
      iks *payload_gsm = iks_new("payload-type");
      if(!payload_gsm) {
         ast_log(LOG_WARNING,"Failed to allocate iks node");
         return -1;
      }
      iks_insert_attrib(payload_gsm, "id", "103");
      iks_insert_attrib(payload_gsm, "name", "gsm");
      iks_insert_node(dcodecs, payload_gsm);
      res++;
   }
   ast_rtp_lookup_code(p->rtp, 1, codec);
   return res;
}
static struct gtalk* find_gtalk ( char *  name,
char *  connection 
) [static, read]

Definition at line 242 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, s, and strsep().

Referenced by gtalk_request().

{
   struct gtalk *gtalk = NULL;
   char *domain = NULL , *s = NULL;

   if (strchr(connection, '@')) {
      s = ast_strdupa(connection);
      domain = strsep(&s, "@");
      ast_verbose("OOOOH domain = %s\n", domain);
   }
   gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
   if (!gtalk && strchr(name, '@'))
      gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);

   if (!gtalk) {           
      /* guest call */
      ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
         ASTOBJ_RDLOCK(iterator);
         if (!strcasecmp(iterator->name, "guest")) {
            gtalk = iterator;
         }
         ASTOBJ_UNLOCK(iterator);

         if (gtalk)
            break;
      });

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

Definition at line 1078 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

{
   iks *request, *session = NULL;
   int res = -1;
   char *lowerthem = NULL;

   request = iks_new("iq");
   if (request) {
      iks_insert_attrib(request, "type", "set");
      iks_insert_attrib(request, "from", p->us);
      iks_insert_attrib(request, "to", p->them);
      iks_insert_attrib(request, "id", client->connection->mid);
      ast_aji_increment_mid(client->connection->mid);
      session = iks_new("session");
      if (session) {
         iks_insert_attrib(session, "type", action);
         iks_insert_attrib(session, "id", p->sid);
         /* put the initiator attribute to lower case if we receive the call 
          * otherwise GoogleTalk won't establish the session */
         if (!p->initiator) {
                 char c;
            char *t = lowerthem = ast_strdupa(p->them);
            while (((c = *t) != '/') && (*t++ = tolower(c)));
         }
         iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
         iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
         iks_insert_node(request, session);
         ast_aji_send(client->connection, request);
         res = 0;
      }
   }

   iks_delete(session);
   iks_delete(request);

   return res;
}
static int gtalk_add_candidate ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 1302 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_candidate::generation, gtalk_update_stun(), gtalk_candidate::ip, aji_client::jid, gtalk_pvt::laststun, gtalk_candidate::name, gtalk_candidate::network, gtalk_candidate::next, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_candidate::password, gtalk_candidate::port, gtalk_candidate::preference, gtalk_candidate::protocol, gtalk_candidate::receipt, gtalk_pvt::theircandidates, gtalk_candidate::type, and gtalk_candidate::username.

Referenced by gtalk_parser().

{
   struct gtalk_pvt *p = NULL, *tmp = NULL;
   struct aji_client *c = client->connection;
   struct gtalk_candidate *newcandidate = NULL;
   iks *traversenodes = NULL, *receipt = NULL;
   char *from;

   from = iks_find_attrib(pak->x,"to");
   if(!from)
      from = c->jid->full;

   for (tmp = client->p; tmp; tmp = tmp->next) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
         p = tmp;
         break;
      }
   }

   if (!p)
      return -1;

   traversenodes = pak->query;
   while(traversenodes) {
      if(!strcasecmp(iks_name(traversenodes), "session")) {
         traversenodes = iks_first_tag(traversenodes);
         continue;
      }
      if(!strcasecmp(iks_name(traversenodes), "transport")) {
         traversenodes = iks_first_tag(traversenodes);
         continue;
      }
      if(!strcasecmp(iks_name(traversenodes), "candidate")) {
         newcandidate = ast_calloc(1, sizeof(*newcandidate));
         if (!newcandidate)
            return 0;
         ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
                     sizeof(newcandidate->name));
         ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
                     sizeof(newcandidate->ip));
         newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
         ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
                     sizeof(newcandidate->username));
         ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
                     sizeof(newcandidate->password));
         newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
         if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
            newcandidate->protocol = AJI_PROTOCOL_UDP;
         if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
            newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
      
         if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
            newcandidate->type = AJI_CONNECT_STUN;
         if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
            newcandidate->type = AJI_CONNECT_LOCAL;
         if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
            newcandidate->type = AJI_CONNECT_RELAY;
         ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
                     sizeof(newcandidate->network));
         newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
         newcandidate->next = NULL;
      
         newcandidate->next = p->theircandidates;
         p->theircandidates = newcandidate;
         p->laststun = 0;
         gtalk_update_stun(p->parent, p);
         newcandidate = NULL;
      }
      traversenodes = iks_next_tag(traversenodes);
   }
   
   receipt = iks_new("iq");
   iks_insert_attrib(receipt, "type", "result");
   iks_insert_attrib(receipt, "from", from);
   iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
   iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
   ast_aji_send(c, receipt);

   iks_delete(receipt);

   return 1;
}
static struct gtalk_pvt * gtalk_alloc ( struct gtalk client,
const char *  us,
const char *  them,
const char *  sid 
) [static, read]

Definition at line 909 of file chan_gtalk.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_rtp_new_with_bindaddr(), ast_rtp_pt_clear(), ast_strdupa, ASTOBJ_CONTAINER_FIND, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk_pvt::capability, gtalk::capability, gtalk_pvt::cid_name, gtalk::connection, gtalk_pvt::exten, exten, global_capability, gtalklock, gtalk_pvt::initiator, aji_version::jingle, gtalk_pvt::lock, LOG_ERROR, LOG_WARNING, gtalk::name, gtalk_pvt::next, aji_resource::next, gtalk::p, gtalk_pvt::parent, gtalk::prefs, gtalk_pvt::prefs, aji_resource::resource, aji_buddy::resources, gtalk_pvt::rtp, gtalk_pvt::sid, strsep(), gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_newcall(), and gtalk_request().

{
   struct gtalk_pvt *tmp = NULL;
   struct aji_resource *resources = NULL;
   struct aji_buddy *buddy;
   char idroster[200];
   char *data, *exten = NULL;

   ast_debug(1, "The client is %s for alloc\n", client->name);
   if (!sid && !strchr(them, '/')) {   /* I started call! */
      if (!strcasecmp(client->name, "guest")) {
         buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
         if (buddy)
            resources = buddy->resources;
      } else if (client->buddy)
         resources = client->buddy->resources;
      while (resources) {
         if (resources->cap->jingle) {
            break;
         }
         resources = resources->next;
      }
      if (resources)
         snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
      else {
         ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
         return NULL;
      }
   }
   if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
      return NULL;
   }

   memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));

   if (sid) {
      ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
      ast_copy_string(tmp->them, them, sizeof(tmp->them));
      ast_copy_string(tmp->us, us, sizeof(tmp->us));
   } else {
      snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
      ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
      ast_copy_string(tmp->us, us, sizeof(tmp->us));
      tmp->initiator = 1;
   }
   /* clear codecs */
   tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
   ast_rtp_pt_clear(tmp->rtp);

   /* add user configured codec capabilites */
   if (client->capability)
      tmp->capability = client->capability;
   else if (global_capability)
      tmp->capability = global_capability;

   tmp->parent = client;
   if (!tmp->rtp) {
      ast_log(LOG_WARNING, "Out of RTP sessions?\n");
      ast_free(tmp);
      return NULL;
   }

   /* Set CALLERID(name) to the full JID of the remote peer */
   ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));

   if(strchr(tmp->us, '/')) {
      data = ast_strdupa(tmp->us);
      exten = strsep(&data, "/");
   } else
      exten = tmp->us;
   ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
   ast_mutex_init(&tmp->lock);
   ast_mutex_lock(&gtalklock);
   tmp->next = client->p;
   client->p = tmp;
   ast_mutex_unlock(&gtalklock);
   return tmp;
}
static int gtalk_answer ( struct ast_channel ast) [static]

Definition at line 513 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.

{
   struct gtalk_pvt *p = ast->tech_pvt;
   int res = 0;
   
   ast_debug(1, "Answer!\n");
   ast_mutex_lock(&p->lock);
   gtalk_invite(p, p->them, p->us,p->sid, 0);
   manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
      ast->name, "GTALK", p->sid);
   ast_mutex_unlock(&p->lock);
   return res;
}
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 1593 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_create_candidates(), 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.

{
   struct gtalk_pvt *p = ast->tech_pvt;

   if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
      ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
      return -1;
   }

   ast_setstate(ast, AST_STATE_RING);
   if (!p->ringrule) {
      ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
      p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
                     IKS_RULE_ID, p->ring, IKS_RULE_DONE);
   } else
      ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");

   gtalk_invite(p, p->them, p->us, p->sid, 1);
   gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);

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

Definition at line 773 of file chan_gtalk.c.

References __ourip, 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_find_ourip(), ast_free, ast_inet_ntoa(), ast_log(), ast_random(), ast_rtp_get_us(), ast_strdupa, ast_strlen_zero(), gtalk::connection, gtalk_candidate::generation, GOOGLE_NS, 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_call(), and gtalk_newcall().

{
   struct gtalk_candidate *tmp;
   struct aji_client *c = client->connection;
   struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
   struct sockaddr_in sin;
   struct sockaddr_in dest;
   struct in_addr us;
   iks *iq, *gtalk, *candidate, *transport;
   char user[17], pass[17], preference[5], port[7];
   char *lowerfrom = NULL;


   iq = iks_new("iq");
   gtalk = iks_new("session");
   candidate = iks_new("candidate");
   transport = iks_new("transport");
   if (!iq || !gtalk || !candidate || !transport) {
      ast_log(LOG_ERROR, "Memory allocation error\n");
      goto safeout;
   }
   ours1 = ast_calloc(1, sizeof(*ours1));
   ours2 = ast_calloc(1, sizeof(*ours2));
   if (!ours1 || !ours2)
      goto safeout;

   iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
   iks_insert_node(iq, gtalk);
   iks_insert_node(gtalk,transport);
   iks_insert_node(transport, candidate);

   for (; p; p = p->next) {
      if (!strcasecmp(p->sid, sid))
         break;
   }

   if (!p) {
      ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
      goto safeout;
   }

   ast_rtp_get_us(p->rtp, &sin);
   ast_find_ourip(&us, bindaddr);
   if (!strcmp(ast_inet_ntoa(us), "127.0.0.1")) {
      ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
   }

   /* Setup our gtalk candidates */
   ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
   ours1->port = ntohs(sin.sin_port);
   ours1->preference = 1;
   snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
   snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
   ast_copy_string(ours1->username, user, sizeof(ours1->username));
   ast_copy_string(ours1->password, pass, sizeof(ours1->password));
   ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
   ours1->protocol = AJI_PROTOCOL_UDP;
   ours1->type = AJI_CONNECT_LOCAL;
   ours1->generation = 0;
   p->ourcandidates = ours1;

   if (!ast_strlen_zero(externip)) {
      /* XXX We should really stun for this one not just go with externip XXX */
      snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
      snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
      ast_copy_string(ours2->username, user, sizeof(ours2->username));
      ast_copy_string(ours2->password, pass, sizeof(ours2->password));
      ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
      ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
      ours2->port = ntohs(sin.sin_port);
      ours2->preference = 0.9;
      ours2->protocol = AJI_PROTOCOL_UDP;
      ours2->type = AJI_CONNECT_STUN;
      ours2->generation = 0;
      ours1->next = ours2;
      ours2 = NULL;
   }
   ours1 = NULL;
   dest.sin_addr = __ourip;
   dest.sin_port = sin.sin_port;


   for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
      snprintf(port, sizeof(port), "%d", tmp->port);
      snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
      iks_insert_attrib(iq, "from", to);
      iks_insert_attrib(iq, "to", from);
      iks_insert_attrib(iq, "type", "set");
      iks_insert_attrib(iq, "id", c->mid);
      ast_aji_increment_mid(c->mid);
      iks_insert_attrib(gtalk, "type", "transport-info");
      iks_insert_attrib(gtalk, "id", sid);
      /* put the initiator attribute to lower case if we receive the call 
       * otherwise GoogleTalk won't establish the session */
      if (!p->initiator) {
              char c;
         char *t = lowerfrom = ast_strdupa(from);
         while (((c = *t) != '/') && (*t++ = tolower(c)));
      }
      iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
      iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
      iks_insert_attrib(candidate, "name", tmp->name);
      iks_insert_attrib(candidate, "address", tmp->ip);
      iks_insert_attrib(candidate, "port", port);
      iks_insert_attrib(candidate, "username", tmp->username);
      iks_insert_attrib(candidate, "password", tmp->password);
      iks_insert_attrib(candidate, "preference", preference);
      if (tmp->protocol == AJI_PROTOCOL_UDP)
         iks_insert_attrib(candidate, "protocol", "udp");
      if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
         iks_insert_attrib(candidate, "protocol", "ssltcp");
      if (tmp->type == AJI_CONNECT_STUN)
         iks_insert_attrib(candidate, "type", "stun");
      if (tmp->type == AJI_CONNECT_LOCAL)
         iks_insert_attrib(candidate, "type", "local");
      if (tmp->type == AJI_CONNECT_RELAY)
         iks_insert_attrib(candidate, "type", "relay");
      iks_insert_attrib(candidate, "network", "0");
      iks_insert_attrib(candidate, "generation", "0");
      ast_aji_send(c, iq);
   }
   p->laststun = 0;

safeout:
   if (ours1)
      ast_free(ours1);
   if (ours2)
      ast_free(ours2);
   iks_delete(iq);
   iks_delete(gtalk);
   iks_delete(candidate);
   iks_delete(transport);

   return 1;
}
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 1840 of file chan_gtalk.c.

References aji_client::allowguest, 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, gtalk_parser(), LOG_ERROR, LOG_WARNING, ast_variable::name, gtalk::name, ast_variable::next, gtalk_candidate::next, gtalk::parkinglot, prefs, gtalk::prefs, gtalk::user, and ast_variable::value.

Referenced by gtalk_load_config().

{
   struct aji_client *client;

   if (!member)
      ast_log(LOG_WARNING, "Out of memory.\n");

   ast_copy_string(member->name, label, sizeof(member->name));
   ast_copy_string(member->user, label, sizeof(member->user));
   ast_copy_string(member->context, context, sizeof(member->context));
   member->allowguest = allowguest;
   member->prefs = prefs;
   while (var) {
#if 0
      struct gtalk_candidate *candidate = NULL;
#endif
      if (!strcasecmp(var->name, "username"))
         ast_copy_string(member->user, var->value, sizeof(member->user));
      else if (!strcasecmp(var->name, "disallow"))
         ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
      else if (!strcasecmp(var->name, "allow"))
         ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
      else if (!strcasecmp(var->name, "context"))
         ast_copy_string(member->context, var->value, sizeof(member->context));
      else if (!strcasecmp(var->name, "parkinglot"))
         ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
#if 0
      else if (!strcasecmp(var->name, "candidate")) {
         candidate = gtalk_create_candidate(var->value);
         if (candidate) {
            candidate->next = member->ourcandidates;
            member->ourcandidates = candidate;
         }
      }
#endif
      else if (!strcasecmp(var->name, "connection")) {
         if ((client = ast_aji_get_client(var->value))) {
            member->connection = client;
            iks_filter_add_rule(client->f, gtalk_parser, member, 
                      IKS_RULE_TYPE, IKS_PAK_IQ, 
                      IKS_RULE_FROM_PARTIAL, member->user,
                      IKS_RULE_NS, "http://www.google.com/session",
                      IKS_RULE_DONE);

         } else {
            ast_log(LOG_ERROR, "connection referenced not found!\n");
            return 0;
         }
      }
      var = var->next;
   }
   if (member->connection && member->user)
      member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
   else {
      ast_log(LOG_ERROR, "No Connection or Username!\n");
   }
   return 1;
}
static int gtalk_digit ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 1512 of file chan_gtalk.c.

References ast_aji_increment_mid(), ast_aji_send(), AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, gtalk::connection, ast_channel::dtmff, ast_frame::frametype, gtalk_pvt::initiator, gtalk_pvt::lock, LOG_ERROR, aji_client::mid, gtalk_pvt::parent, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_digit_begin(), and gtalk_digit_end().

{
   struct gtalk_pvt *p = ast->tech_pvt;
   struct gtalk *client = p->parent;
   iks *iq, *gtalk, *dtmf;
   char buffer[2] = {digit, '\0'};
   char *lowerthem = NULL;
   iq = iks_new("iq");
   gtalk = iks_new("gtalk");
   dtmf = iks_new("dtmf");
   if(!iq || !gtalk || !dtmf) {
      iks_delete(iq);
      iks_delete(gtalk);
      iks_delete(dtmf);
      ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
      return -1;
   }

   iks_insert_attrib(iq, "type", "set");
   iks_insert_attrib(iq, "to", p->them);
   iks_insert_attrib(iq, "from", p->us);
   iks_insert_attrib(iq, "id", client->connection->mid);
   ast_aji_increment_mid(client->connection->mid);
   iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
   iks_insert_attrib(gtalk, "action", "session-info");
   /* put the initiator attribute to lower case if we receive the call 
    * otherwise GoogleTalk won't establish the session */
   if (!p->initiator) {
           char c;
           char *t = lowerthem = ast_strdupa(p->them);
           while (((c = *t) != '/') && (*t++ = tolower(c)));
   }
   iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
   iks_insert_attrib(gtalk, "sid", p->sid);
   iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
   iks_insert_attrib(dtmf, "code", buffer);
   iks_insert_node(iq, gtalk);
   iks_insert_node(gtalk, dtmf);

   ast_mutex_lock(&p->lock);
   if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
      iks_insert_attrib(dtmf, "action", "button-down");
   } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
      iks_insert_attrib(dtmf, "action", "button-up");
   }
   ast_aji_send(client->connection, iq);

   iks_delete(iq);
   iks_delete(gtalk);
   iks_delete(dtmf);
   ast_mutex_unlock(&p->lock);
   return 0;
}
static int gtalk_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 1502 of file chan_gtalk.c.

References gtalk_digit().

{
   return gtalk_digit(chan, digit, 0);
}
static int gtalk_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 1507 of file chan_gtalk.c.

References gtalk_digit().

{
   return gtalk_digit(chan, digit, duration);
}
static char * gtalk_do_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command "gtalk reload".

Definition at line 1747 of file chan_gtalk.c.

References ast_verbose(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "gtalk reload";
      e->usage =
         "Usage: gtalk reload\n"
         "       Reload gtalk channel driver.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }  
   
   ast_verbose("IT DOES WORK!\n");
   return CLI_SUCCESS;
}
static int gtalk_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 1468 of file chan_gtalk.c.

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

{
   struct gtalk_pvt *p = newchan->tech_pvt;
   ast_mutex_lock(&p->lock);

   if ((p->owner != oldchan)) {
      ast_mutex_unlock(&p->lock);
      return -1;
   }
   if (p->owner == oldchan)
      p->owner = newchan;
   ast_mutex_unlock(&p->lock);
   return 0;
}
static void gtalk_free_candidates ( struct gtalk_candidate candidate) [static]

Definition at line 1116 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

{
   struct gtalk_candidate *last;
   while (candidate) {
      last = candidate;
      candidate = candidate->next;
      ast_free(last);
   }
}
static void gtalk_free_pvt ( struct gtalk client,
struct gtalk_pvt p 
) [static]

Definition at line 1126 of file chan_gtalk.c.

References ast_free, ast_log(), ast_rtp_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().

{
   struct gtalk_pvt *cur, *prev = NULL;
   cur = client->p;
   while (cur) {
      if (cur == p) {
         if (prev)
            prev->next = p->next;
         else
            client->p = p->next;
         break;
      }
      prev = cur;
      cur = cur->next;
   }
   if (p->ringrule)
      iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
   if (p->owner)
      ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
   if (p->rtp)
      ast_rtp_destroy(p->rtp);
   if (p->vrtp)
      ast_rtp_destroy(p->vrtp);
   gtalk_free_candidates(p->theircandidates);
   ast_free(p);
}
static int gtalk_get_codec ( struct ast_channel chan) [static]

Definition at line 545 of file chan_gtalk.c.

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

{
   struct gtalk_pvt *p = chan->tech_pvt;
   return p->peercapability;
}
static enum ast_rtp_get_result gtalk_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp **  rtp 
) [static]

Definition at line 527 of file chan_gtalk.c.

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

{
   struct gtalk_pvt *p = chan->tech_pvt;
   enum ast_rtp_get_result res = AST_RTP_GET_FAILED;

   if (!p)
      return res;

   ast_mutex_lock(&p->lock);
   if (p->rtp){
      *rtp = p->rtp;
      res = AST_RTP_TRY_PARTIAL;
   }
   ast_mutex_unlock(&p->lock);

   return res;
}
static int gtalk_handle_dtmf ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 680 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, gtalk_response(), aji_client::jid, LOG_NOTICE, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::sid, and ast_frame::subclass.

Referenced by gtalk_parser().

{
   struct gtalk_pvt *tmp;
   iks *dtmfnode = NULL, *dtmfchild = NULL;
   char *dtmf;
   char *from;
   /* Make sure our new call doesn't exist yet */
   for (tmp = client->p; tmp; tmp = tmp->next) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
         break;
   }
   from = iks_find_attrib(pak->x, "to");
   if(!from)
      from = client->connection->jid->full;


   if (tmp) {
      if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
         gtalk_response(client, from, pak,
               "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
               "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
         return -1;
      }
      if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
         if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
            if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
               struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
               f.subclass = dtmf[0];
               ast_queue_frame(tmp->owner, &f);
               ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
            } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
               struct ast_frame f = {AST_FRAME_DTMF_END, };
               f.subclass = dtmf[0];
               ast_queue_frame(tmp->owner, &f);
               ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
            } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
               struct ast_frame f = {AST_FRAME_DTMF, };
               f.subclass = dtmf[0];
               ast_queue_frame(tmp->owner, &f);
               ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
            }
         }
      } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
         if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
            if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
               if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
                  struct ast_frame f = {AST_FRAME_DTMF_END, };
                  f.subclass = dtmf[0];
                  ast_queue_frame(tmp->owner, &f);
                  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
               } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
                  struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
                  f.subclass = dtmf[0];
                  ast_queue_frame(tmp->owner, &f);
                  ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
               }
            }
         }
      }
      gtalk_response(client, from, pak, NULL, NULL);
      return 1;
   } else
      ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");

   gtalk_response(client, from, pak, NULL, NULL);
   return 1;
}
static int gtalk_hangup ( struct ast_channel ast) [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1617 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_pvt::parent, ast_module_info::self, and ast_channel::tech_pvt.

Referenced by gtalk_newcall().

{
   struct gtalk_pvt *p = ast->tech_pvt;
   struct gtalk *client;

   ast_mutex_lock(&p->lock);
   client = p->parent;
   p->owner = NULL;
   ast->tech_pvt = NULL;
   if (!p->alreadygone)
      gtalk_action(client, p, "terminate");
   ast_mutex_unlock(&p->lock);

   gtalk_free_pvt(client, p);
   ast_module_unref(ast_module_info->self);

   return 0;
}
static int gtalk_hangup_farend ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 748 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().

{
   struct gtalk_pvt *tmp;
   char *from;

   ast_debug(1, "The client is %s\n", client->name);
   /* Make sure our new call doesn't exist yet */
   for (tmp = client->p; tmp; tmp = tmp->next) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
         break;
   }
   from = iks_find_attrib(pak->x, "to");
   if(!from)
      from = client->connection->jid->full;

   if (tmp) {
      tmp->alreadygone = 1;
      if (tmp->owner)
         ast_queue_hangup(tmp->owner);
   } else
      ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
   gtalk_response(client, from, pak, NULL, NULL);
   return 1;
}
static int gtalk_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 1483 of file chan_gtalk.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), and LOG_NOTICE.

{
   int res = 0;

   switch (condition) {
   case AST_CONTROL_HOLD:
      ast_moh_start(ast, data, NULL);
      break;
   case AST_CONTROL_UNHOLD:
      ast_moh_stop(ast);
      break;
   default:
      ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
      res = -1;
   }

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

Definition at line 379 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, LOG_ERROR, aji_client::mid, gtalk_pvt::parent, and gtalk::prefs.

Referenced by gtalk_answer(), and gtalk_call().

{
   struct gtalk *client = p->parent;
   iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
   int x;
   int pref_codec = 0;
   int alreadysent = 0;
   int codecs_num = 0;
   char *lowerto = NULL;

   iq = iks_new("iq");
   gtalk = iks_new("session");
   dcodecs = iks_new("description");
   transport = iks_new("transport");
   payload_telephone = iks_new("payload-type");
   if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
      iks_delete(iq);
      iks_delete(gtalk);
      iks_delete(dcodecs);
      iks_delete(transport);
      iks_delete(payload_telephone);
      
      ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
      return 0;
   }
   iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone");
   iks_insert_attrib(dcodecs, "xml:lang", "en");

   for (x = 0; x < 32; x++) {
      if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
         break;
      if (!(client->capability & pref_codec))
         continue;
      if (alreadysent & pref_codec)
         continue;
      codecs_num = add_codec_to_answer(p, pref_codec, dcodecs);
      alreadysent |= pref_codec;
   }
   
   if (codecs_num) {
      /* only propose DTMF within an audio session */
      iks_insert_attrib(payload_telephone, "id", "106");
      iks_insert_attrib(payload_telephone, "name", "telephone-event");
      iks_insert_attrib(payload_telephone, "clockrate", "8000");
   }
   iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p");
   
   iks_insert_attrib(iq, "type", "set");
   iks_insert_attrib(iq, "to", to);
   iks_insert_attrib(iq, "from", from);
   iks_insert_attrib(iq, "id", client->connection->mid);
   ast_aji_increment_mid(client->connection->mid);

   iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session");
   iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
   /* put the initiator attribute to lower case if we receive the call 
    * otherwise GoogleTalk won't establish the session */
   if (!initiator) {
           char c;
           char *t = lowerto = ast_strdupa(to);
      while (((c = *t) != '/') && (*t++ = tolower(c)));
   }
   iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
   iks_insert_attrib(gtalk, "id", sid);
   iks_insert_node(iq, gtalk);
   iks_insert_node(gtalk, dcodecs);
   iks_insert_node(gtalk, transport);
   iks_insert_node(dcodecs, payload_telephone);

   ast_aji_send(client->connection, iq);

   iks_delete(payload_telephone);
   iks_delete(transport);
   iks_delete(dcodecs);
   iks_delete(gtalk);
   iks_delete(iq);
   return 1;
}
static int gtalk_invite_response ( struct gtalk_pvt p,
char *  to,
char *  from,
char *  sid,
int  initiator 
) [static]

Definition at line 458 of file chan_gtalk.c.

References ast_aji_increment_mid(), ast_aji_send(), ast_log(), ast_strdupa, gtalk::connection, LOG_ERROR, aji_client::mid, and gtalk_pvt::parent.

Referenced by gtalk_newcall().

{
   iks *iq, *session, *transport;
   char *lowerto = NULL;

   iq = iks_new("iq");
   session = iks_new("session");
   transport = iks_new("transport");
   if(!(iq && session && transport)) {
      iks_delete(iq);
      iks_delete(session);
      iks_delete(transport);
      ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
      return -1;
   }
   iks_insert_attrib(iq, "from", from);
   iks_insert_attrib(iq, "to", to);
   iks_insert_attrib(iq, "type", "set");
   iks_insert_attrib(iq, "id",p->parent->connection->mid);
   ast_aji_increment_mid(p->parent->connection->mid);
   iks_insert_attrib(session, "type", "transport-accept");
   iks_insert_attrib(session, "id", sid);
   /* put the initiator attribute to lower case if we receive the call 
    * otherwise GoogleTalk won't establish the session */
   if (!initiator) {
           char c;
      char *t = lowerto = ast_strdupa(to);
      while (((c = *t) != '/') && (*t++ = tolower(c)));
   }
   iks_insert_attrib(session, "initiator", initiator ? from : lowerto);
   iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
   iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
   iks_insert_node(iq,session);
   iks_insert_node(session,transport);
   ast_aji_send(p->parent->connection, iq);

   iks_delete(transport);
   iks_delete(session);
   iks_delete(iq);
   return 1;

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

Definition at line 656 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

{
   struct gtalk_pvt *tmp;
   char *from;

   ast_log(LOG_DEBUG, "The client is %s\n", client->name);
   /* find corresponding call */
   for (tmp = client->p; tmp; tmp = tmp->next) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
         break;
   }

   from = iks_find_attrib(pak->x, "to");
   if(!from)
      from = client->connection->jid->full;

   if (!tmp)
      ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");

   /* answer 'iq' packet to let the remote peer know that we're alive */
   gtalk_response(client, from, pak, NULL, NULL);
   return 1;
}
static int gtalk_is_answered ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 603 of file chan_gtalk.c.

References AST_CONTROL_ANSWER, ast_getformatname_multiple(), ast_log(), ast_queue_control(), ast_queue_hangup(), ast_rtp_get_current_formats(), ast_rtp_set_m_type(), ast_rtp_set_rtpmap_type(), gtalk_pvt::capability, gtalk::connection, gtalk_response(), aji_client::jid, gtalk_pvt::jointcapability, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::peercapability, gtalk_pvt::rtp, and gtalk_pvt::sid.

Referenced by gtalk_parser().

{
   struct gtalk_pvt *tmp;
   char *from;
   iks *codec;
   char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
   int peernoncodeccapability;

   ast_log(LOG_DEBUG, "The client is %s\n", client->name);
   /* Make sure our new call doesn't exist yet */
   for (tmp = client->p; tmp; tmp = tmp->next) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
         break;
   }

   /* codec points to the first <payload-type/> tag */
   codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
   while (codec) {
      ast_rtp_set_m_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")));
      ast_rtp_set_rtpmap_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
      codec = iks_next_tag(codec);
   }
   
   /* Now gather all of the codecs that we are asked for */
   ast_rtp_get_current_formats(tmp->rtp, &tmp->peercapability, &peernoncodeccapability);
   
   /* at this point, we received an awser from the remote Gtalk client,
      which allows us to compare capabilities */
   tmp->jointcapability = tmp->capability & tmp->peercapability;
   if (!tmp->jointcapability) {
      ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
         ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
         ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
      /* close session if capabilities don't match */
      ast_queue_hangup(tmp->owner);

      return -1;

   }  
   
   from = iks_find_attrib(pak->x, "to");
   if(!from)
      from = client->connection->jid->full;

   if (tmp) {
      if (tmp->owner)
         ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
   } else
      ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
   gtalk_response(client, from, pak, NULL, NULL);
   return 1;
}
static int gtalk_load_config ( void  ) [static]

Definition at line 1901 of file chan_gtalk.c.

References gtalk::allowguest, ast_aji_get_clients(), ast_calloc, ast_category_browse(), ast_config_load, ast_copy_string(), ast_gethostbyname(), ast_jb_read_conf(), ast_log(), AST_MAX_CONTEXT, ast_parse_allow_disallow(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, gtalk::capability, clients, CONFIG_STATUS_FILEINVALID, gtalk::connection, gtalk::context, context, global_jbconf, GOOGLE_CONFIG, gtalk_create_member(), gtalk_free_candidates(), gtalk_list, gtalk_member_destroy(), gtalk_parser(), hp, LOG_ERROR, LOG_WARNING, gtalk::name, ast_variable::name, ast_variable::next, gtalk::parkinglot, parkinglot, prefs, gtalk::prefs, gtalk::user, ast_variable::value, and var.

Referenced by load_module().

{
   char *cat = NULL;
   struct ast_config *cfg = NULL;
   char context[AST_MAX_CONTEXT];
   char parkinglot[AST_MAX_CONTEXT];
   int allowguest = 1;
   struct ast_variable *var;
   struct gtalk *member;
   struct ast_codec_pref prefs;
   struct aji_client_container *clients;
   struct gtalk_candidate *global_candidates = NULL;
   struct hostent *hp;
   struct ast_hostent ahp;
   struct ast_flags config_flags = { 0 };

   cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
   if (!cfg) {
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", GOOGLE_CONFIG);
      return 0;
   }

   /* Copy the default jb config over global_jbconf */
   memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

   cat = ast_category_browse(cfg, NULL);
   for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
      /* handle jb conf */
      if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
         continue;

      if (!strcasecmp(var->name, "allowguest"))
         allowguest =
            (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
      else if (!strcasecmp(var->name, "disallow"))
         ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
      else if (!strcasecmp(var->name, "allow"))
         ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
      else if (!strcasecmp(var->name, "context"))
         ast_copy_string(context, var->value, sizeof(context));
      else if (!strcasecmp(var->name, "parkinglot"))
         ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
      else if (!strcasecmp(var->name, "bindaddr")) {
         if (!(hp = ast_gethostbyname(var->value, &ahp))) {
            ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
         } else {
            memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
         }
      }
/*  Idea to allow for custom candidates  */
/*
      else if (!strcasecmp(var->name, "candidate")) {
         candidate = gtalk_create_candidate(var->value);
         if (candidate) {
            candidate->next = global_candidates;
            global_candidates = candidate;
         }
      }
*/
   }
   while (cat) {
      if (strcasecmp(cat, "general")) {
         var = ast_variable_browse(cfg, cat);
         member = ast_calloc(1, sizeof(*member));
         ASTOBJ_INIT(member);
         ASTOBJ_WRLOCK(member);
         if (!strcasecmp(cat, "guest")) {
            ast_copy_string(member->name, "guest", sizeof(member->name));
            ast_copy_string(member->user, "guest", sizeof(member->user));
            ast_copy_string(member->context, context, sizeof(member->context));
            ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
            member->allowguest = allowguest;
            member->prefs = prefs;
            while (var) {
               if (!strcasecmp(var->name, "disallow"))
                  ast_parse_allow_disallow(&member->prefs, &member->capability,
                                     var->value, 0);
               else if (!strcasecmp(var->name, "allow"))
                  ast_parse_allow_disallow(&member->prefs, &member->capability,
                                     var->value, 1);
               else if (!strcasecmp(var->name, "context"))
                  ast_copy_string(member->context, var->value,
                              sizeof(member->context));
               else if (!strcasecmp(var->name, "parkinglot"))
                  ast_copy_string(member->parkinglot, var->value,
                              sizeof(member->parkinglot));
/*  Idea to allow for custom candidates  */
/*
               else if (!strcasecmp(var->name, "candidate")) {
                  candidate = gtalk_create_candidate(var->value);
                  if (candidate) {
                     candidate->next = member->ourcandidates;
                     member->ourcandidates = candidate;
                  }
               }
*/
               var = var->next;
            }
            ASTOBJ_UNLOCK(member);
            clients = ast_aji_get_clients();
            if (clients) {
               ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
                  ASTOBJ_WRLOCK(iterator);
                  ASTOBJ_WRLOCK(member);
                  member->connection = NULL;
                  iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://www.google.com/session", IKS_RULE_DONE);
                  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);
                  ASTOBJ_UNLOCK(member);
                  ASTOBJ_UNLOCK(iterator);
               });
               ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
               ASTOBJ_UNREF(member, gtalk_member_destroy);
            } else {
               ASTOBJ_UNLOCK(member);
               ASTOBJ_UNREF(member, gtalk_member_destroy);
            }
         } else {
            ASTOBJ_UNLOCK(member);
            if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
               ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
            ASTOBJ_UNREF(member, gtalk_member_destroy);
         }
      }
      cat = ast_category_browse(cfg, cat);
   }
   gtalk_free_candidates(global_candidates);
   return 1;
}
static void gtalk_member_destroy ( struct gtalk obj) [static]

Definition at line 237 of file chan_gtalk.c.

References ast_free.

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

{
   ast_free(obj);
}
static struct ast_channel* gtalk_new ( struct gtalk client,
struct gtalk_pvt i,
int  state,
const char *  title 
) [static, read]

Start new gtalk channel.

Definition at line 989 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_rtcp_fd(), ast_rtp_codec_setpref(), ast_rtp_fd(), ast_rtp_setstun(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, ast_channel::cid, ast_callerid::cid_dnid, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_callerid::cid_pres, ast_channel::context, gtalk::context, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_capability, global_jbconf, gtalk_tech, ast_channel::hangupcause, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_channel::nativeformats, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, ast_module_info::self, gtalk_pvt::sid, ast_channel::tech, ast_channel::tech_pvt, gtalk_pvt::us, gtalk_pvt::vrtp, and ast_channel::writeformat.

Referenced by gtalk_newcall(), and gtalk_request().

{
   struct ast_channel *tmp;
   int fmt;
   int what;
   const char *n2;

   if (title)
      n2 = title;
   else
      n2 = i->us;
   tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
   if (!tmp) {
      ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
      return NULL;
   }
   tmp->tech = &gtalk_tech;

   /* Select our native format based on codec preference until we receive
      something from another device to the contrary. */
   if (i->jointcapability)
      what = i->jointcapability;
   else if (i->capability)
      what = i->capability;
   else
      what = global_capability;

   /* Set Frame packetization */
   if (i->rtp)
      ast_rtp_codec_setpref(i->rtp, &i->prefs);

   tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
   fmt = ast_best_codec(tmp->nativeformats);

   if (i->rtp) {
      ast_rtp_setstun(i->rtp, 1);
      ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
      ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
   }
   if (i->vrtp) {
      ast_rtp_setstun(i->rtp, 1);
      ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
      ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
   }
   if (state == AST_STATE_RING)
      tmp->rings = 1;
   tmp->adsicpe = AST_ADSI_UNAVAILABLE;
   tmp->writeformat = fmt;
   tmp->rawwriteformat = fmt;
   tmp->readformat = fmt;
   tmp->rawreadformat = fmt;
   tmp->tech_pvt = i;

   tmp->callgroup = client->callgroup;
   tmp->pickupgroup = client->pickupgroup;
   tmp->cid.cid_pres = client->callingpres;
   if (!ast_strlen_zero(client->accountcode))
      ast_string_field_set(tmp, accountcode, client->accountcode);
   if (client->amaflags)
      tmp->amaflags = client->amaflags;
   if (!ast_strlen_zero(client->language))
      ast_string_field_set(tmp, language, client->language);
   if (!ast_strlen_zero(client->musicclass))
      ast_string_field_set(tmp, musicclass, client->musicclass);
   if (!ast_strlen_zero(client->parkinglot))
      ast_string_field_set(tmp, parkinglot, client->parkinglot);
   i->owner = tmp;
   ast_module_ref(ast_module_info->self);
   ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
   ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));

   if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
      tmp->cid.cid_dnid = ast_strdup(i->exten);
   tmp->priority = 1;
   if (i->rtp)
      ast_jb_configure(tmp, &global_jbconf);
   if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
      ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
      tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
      ast_hangup(tmp);
      tmp = NULL;
   } else {
      manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
         "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
         i->owner ? i->owner->name : "", "Gtalk", i->sid);
   }
   return tmp;
}
static int gtalk_newcall ( struct gtalk client,
ikspak *  pak 
) [static]

Definition at line 1154 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_aji_get_client(), ast_channel_free(), 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_get_current_formats(), ast_rtp_set_m_type(), ast_rtp_set_rtpmap_type(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, gtalk_pvt::capability, chan, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_invite_response(), 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, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_parser().

{
   struct gtalk_pvt *p, *tmp = client->p;
   struct ast_channel *chan;
   int res;
   iks *codec;
   char *from = NULL;
   char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
   int peernoncodeccapability;

   /* Make sure our new call doesn't exist yet */
   from = iks_find_attrib(pak->x,"to");
   if(!from)
      from = client->connection->jid->full;
   
   while (tmp) {
      if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
         ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
         gtalk_response(client, from, pak, "out-of-order", NULL);
         return -1;
      }
      tmp = tmp->next;
   }

   if (!strcasecmp(client->name, "guest")){
      /* the guest account is not tied to any configured XMPP client,
         let's set it now */
      client->connection = ast_aji_get_client(from);
      if (!client->connection) {
         ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
         return -1;
      }
   }

   p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
   if (!p) {
      ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
      return -1;
   }

   chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
   if (!chan) {
      gtalk_free_pvt(client, p);
      return -1;
   }

   ast_mutex_lock(&p->lock);
   ast_copy_string(p->them, pak->from->full, sizeof(p->them));
   if (iks_find_attrib(pak->query, "id")) {
      ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
            sizeof(p->sid));
   }

   /* codec points to the first <payload-type/> tag */   
   codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
   
   while (codec) {
      ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
      ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
      codec = iks_next_tag(codec);
   }
   
   /* Now gather all of the codecs that we are asked for */
   ast_rtp_get_current_formats(p->rtp, &p->peercapability, &peernoncodeccapability);
   p->jointcapability = p->capability & p->peercapability;
   ast_mutex_unlock(&p->lock);
      
   ast_setstate(chan, AST_STATE_RING);
   if (!p->jointcapability) {
      ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
         ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
         ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
      /* close session if capabilities don't match */
      gtalk_action(client, p, "reject");
      p->alreadygone = 1;
      gtalk_hangup(chan);
      ast_channel_free(chan);
      return -1;
   }  

   res = ast_pbx_start(chan);
   
   switch (res) {
   case AST_PBX_FAILED:
      ast_log(LOG_WARNING, "Failed to start PBX :(\n");
      gtalk_response(client, from, pak, "service-unavailable", NULL);
      break;
   case AST_PBX_CALL_LIMIT:
      ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
      gtalk_response(client, from, pak, "service-unavailable", NULL);
      break;
   case AST_PBX_SUCCESS:
      gtalk_response(client, from, pak, NULL, NULL);
      gtalk_invite_response(p, p->them, p->us,p->sid, 0);
      gtalk_create_candidates(client, p, p->sid, p->them, p->us);
      /* nothing to do */
      break;
   }

   return 1;
}
static int gtalk_parser ( void *  data,
ikspak *  pak 
) [static]

Definition at line 1764 of file chan_gtalk.c.

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

Referenced by gtalk_create_member(), and gtalk_load_config().

{
   struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);

   if (iks_find_attrib(pak->x, "type") && !strcmp(iks_find_attrib (pak->x, "type"),"error")) {
      ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
   }
   else if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
      /* New call */
      gtalk_newcall(client, pak);
   } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
      ast_debug(3, "About to add candidate!\n");
      gtalk_add_candidate(client, pak);
      ast_debug(3, "Candidate Added!\n");
   } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
      gtalk_is_answered(client, pak);
   } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
      gtalk_is_accepted(client, pak);
   } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
      gtalk_handle_dtmf(client, pak);
   } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
      gtalk_hangup_farend(client, pak);
   } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
      gtalk_hangup_farend(client, pak);
   }
   ASTOBJ_UNREF(client, gtalk_member_destroy);
   return IKS_FILTER_EAT;
}
static struct ast_frame * gtalk_read ( struct ast_channel ast) [static, read]

Definition at line 1413 of file chan_gtalk.c.

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

{
   struct ast_frame *fr;
   struct gtalk_pvt *p = ast->tech_pvt;

   ast_mutex_lock(&p->lock);
   fr = gtalk_rtp_read(ast, p);
   ast_mutex_unlock(&p->lock);
   return fr;
}
static struct ast_channel * gtalk_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Part of PBX interface.

Definition at line 1637 of file chan_gtalk.c.

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

{
   struct gtalk_pvt *p = NULL;
   struct gtalk *client = NULL;
   char *sender = NULL, *to = NULL, *s = NULL;
   struct ast_channel *chan = NULL;

   if (data) {
      s = ast_strdupa(data);
      if (s) {
         sender = strsep(&s, "/");
         if (sender && (sender[0] != '\0'))
            to = strsep(&s, "/");
         if (!to) {
            ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
            return NULL;
         }
      }
   }

   client = find_gtalk(to, sender);
   if (!client) {
      ast_log(LOG_WARNING, "Could not find recipient.\n");
      return NULL;
   }
   if (!strcasecmp(client->name, "guest")){
      /* the guest account is not tied to any configured XMPP client,
         let's set it now */
      client->connection = ast_aji_get_client(sender);
      if (!client->connection) {
         ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
         ASTOBJ_UNREF(client, gtalk_member_destroy);
         return NULL;
      }
   }
       
   ASTOBJ_WRLOCK(client);
   p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
   if (p)
      chan = gtalk_new(client, p, AST_STATE_DOWN, to);

   ASTOBJ_UNLOCK(client);
   return chan;
}
static int gtalk_response ( struct gtalk client,
char *  from,
ikspak *  pak,
const char *  reasonstr,
const char *  reasonstr2 
) [static]

Definition at line 571 of file chan_gtalk.c.

References ast_aji_send(), and gtalk::connection.

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

{
   iks *response = NULL, *error = NULL, *reason = NULL;
   int res = -1;

   response = iks_new("iq");
   if (response) {
      iks_insert_attrib(response, "type", "result");
      iks_insert_attrib(response, "from", from);
      iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
      iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
      if (reasonstr) {
         error = iks_new("error");
         if (error) {
            iks_insert_attrib(error, "type", "cancel");
            reason = iks_new(reasonstr);
            if (reason)
               iks_insert_node(error, reason);
            iks_insert_node(response, error);
         }
      }
      ast_aji_send(client->connection, response);
      res = 0;
   }

   iks_delete(reason);
   iks_delete(error);
   iks_delete(response);

   return res;
}
static int gtalk_ringing_ack ( void *  data,
ikspak *  pak 
) [static]

Definition at line 501 of file chan_gtalk.c.

References AST_CONTROL_RINGING, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_pvt::owner, gtalk_pvt::parent, and gtalk_pvt::ringrule.

Referenced by gtalk_call().

{
   struct gtalk_pvt *p = data;

   if (p->ringrule)
      iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
   p->ringrule = NULL;
   if (p->owner)
      ast_queue_control(p->owner, AST_CONTROL_RINGING);
   return IKS_FILTER_EAT;
}
static struct ast_frame* gtalk_rtp_read ( struct ast_channel ast,
struct gtalk_pvt p 
) [static, read]

Definition at line 1385 of file chan_gtalk.c.

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

Referenced by gtalk_read().

{
   struct ast_frame *f;

   if (!p->rtp)
      return &ast_null_frame;
   f = ast_rtp_read(p->rtp);
   gtalk_update_stun(p->parent, p);
   if (p->owner) {
      /* We already hold the channel lock */
      if (f->frametype == AST_FRAME_VOICE) {
         if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
            ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
            p->owner->nativeformats =
               (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
            ast_set_read_format(p->owner, p->owner->readformat);
            ast_set_write_format(p->owner, p->owner->writeformat);
         }
/*       if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
            f = ast_dsp_process(p->owner, p->vad, f);
            if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
               ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
              } */
      }
   }
   return f;
}
static int gtalk_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
) [static]

Definition at line 1566 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

{
   ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");

   return -1;
}
static int gtalk_set_rtp_peer ( struct ast_channel chan,
struct ast_rtp rtp,
struct ast_rtp vrtp,
struct ast_rtp trtp,
int  codecs,
int  nat_active 
) [static]

Definition at line 551 of file chan_gtalk.c.

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

{
   struct gtalk_pvt *p;

   p = chan->tech_pvt;
   if (!p)
      return -1;
   ast_mutex_lock(&p->lock);

/* if (rtp)
      ast_rtp_get_peer(rtp, &p->redirip);
   else
      memset(&p->redirip, 0, sizeof(p->redirip));
   p->redircodecs = codecs; */

   /* Reset lastrtprx timer */
   ast_mutex_unlock(&p->lock);
   return 0;
}
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 1683 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, chan, 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.

{
#define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
   struct gtalk_pvt *p;
   struct ast_channel *chan;
   int numchans = 0;
   char them[AJI_MAX_JIDLEN];
   char *jid = NULL;
   char *resource = NULL;

   switch (cmd) {
   case CLI_INIT:
      e->command = "gtalk show channels";
      e->usage =
         "Usage: gtalk show channels\n"
         "       Shows current state of the Gtalk channels.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3)
      return CLI_SHOWUSAGE;

   ast_mutex_lock(&gtalklock);
   ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
   ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
      ASTOBJ_WRLOCK(iterator);
      p = iterator->p;
      while(p) {
         chan = p->owner;
         ast_copy_string(them, p->them, sizeof(them));
         jid = them;
         resource = strchr(them, '/');
         if (!resource)
            resource = "None";
         else {
            *resource = '\0';
            resource ++;
         }
         if (chan)
            ast_cli(a->fd, FORMAT, 
               chan->name,
               jid,
               resource,
               ast_getformatname(chan->readformat),
               ast_getformatname(chan->writeformat)               
               );
         else 
            ast_log(LOG_WARNING, "No available channel\n");
         numchans ++;
         p = p->next;
      }
      ASTOBJ_UNLOCK(iterator);
   });

   ast_mutex_unlock(&gtalklock);

   ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
   return CLI_SUCCESS;
#undef FORMAT
}
static int gtalk_update_stun ( struct gtalk client,
struct gtalk_pvt p 
) [static]

Definition at line 1256 of file chan_gtalk.c.

References ast_debug, ast_gethostbyname(), ast_inet_ntoa(), ast_rtp_get_peer(), ast_rtp_stun_request(), hp, gtalk_candidate::ip, gtalk_pvt::laststun, gtalk_candidate::next, gtalk_pvt::ourcandidates, gtalk_candidate::port, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_candidate::username.

Referenced by gtalk_add_candidate(), and gtalk_rtp_read().

{
   struct gtalk_candidate *tmp;
   struct hostent *hp;
   struct ast_hostent ahp;
   struct sockaddr_in sin;
   struct sockaddr_in aux;

   if (time(NULL) == p->laststun)
      return 0;

   tmp = p->theircandidates;
   p->laststun = time(NULL);
   while (tmp) {
      char username[256];

      /* Find the IP address of the host */
      hp = ast_gethostbyname(tmp->ip, &ahp);
      sin.sin_family = AF_INET;
      memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
      sin.sin_port = htons(tmp->port);
      snprintf(username, sizeof(username), "%s%s", tmp->username,
          p->ourcandidates->username);
      
      /* Find out the result of the STUN */
      ast_rtp_get_peer(p->rtp, &aux);

      /* If the STUN result is different from the IP of the hostname,
         lock on the stun IP of the hostname advertised by the
         remote client */
      if (aux.sin_addr.s_addr && 
          aux.sin_addr.s_addr != sin.sin_addr.s_addr)
         ast_rtp_stun_request(p->rtp, &aux, username);
      else 
         ast_rtp_stun_request(p->rtp, &sin, username);
      
      if (aux.sin_addr.s_addr) {
         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);
         ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
      }

      tmp = tmp->next;
   }
   return 1;
}
static int gtalk_write ( struct ast_channel ast,
struct ast_frame f 
) [static]

Send frame to media channel (rtp)

Definition at line 1425 of file chan_gtalk.c.

References AST_FRAME_IMAGE, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_write(), 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.

{
   struct gtalk_pvt *p = ast->tech_pvt;
   int res = 0;

   switch (frame->frametype) {
   case AST_FRAME_VOICE:
      if (!(frame->subclass & ast->nativeformats)) {
         ast_log(LOG_WARNING,
               "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
               frame->subclass, ast->nativeformats, ast->readformat,
               ast->writeformat);
         return 0;
      }
      if (p) {
         ast_mutex_lock(&p->lock);
         if (p->rtp) {
            res = ast_rtp_write(p->rtp, frame);
         }
         ast_mutex_unlock(&p->lock);
      }
      break;
   case AST_FRAME_VIDEO:
      if (p) {
         ast_mutex_lock(&p->lock);
         if (p->vrtp) {
            res = ast_rtp_write(p->vrtp, frame);
         }
         ast_mutex_unlock(&p->lock);
      }
      break;
   case AST_FRAME_IMAGE:
      return 0;
      break;
   default:
      ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
            frame->frametype);
      return 0;
   }

   return res;
}
static int load_module ( void  ) [static]

Load module into PBX, register channel.

Definition at line 2033 of file chan_gtalk.c.

References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_find_ourip(), ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_proto_register(), ASTOBJ_CONTAINER_INIT, free, GOOGLE_CONFIG, gtalk_list, gtalk_load_config(), io_context_create(), LOG_ERROR, LOG_WARNING, sched_context_create(), and ast_channel_tech::type.

{
   char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
   free(jabber_loaded);
   if (!jabber_loaded) {
      /* If embedded, check for a different module name */
      jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
      free(jabber_loaded);
      if (!jabber_loaded) {
         ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
         return AST_MODULE_LOAD_DECLINE;
      }
   }

   ASTOBJ_CONTAINER_INIT(&gtalk_list);
   if (!gtalk_load_config()) {
      ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
      return 0;
   }

   sched = sched_context_create();
   if (!sched) 
      ast_log(LOG_WARNING, "Unable to create schedule context\n");

   io = io_context_create();
   if (!io) 
      ast_log(LOG_WARNING, "Unable to create I/O context\n");

   if (ast_find_ourip(&__ourip, bindaddr)) {
      ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
      return 0;
   }

   ast_rtp_proto_register(&gtalk_rtp);
   ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));

   /* Make sure we can register our channel type */
   if (ast_channel_register(&gtalk_tech)) {
      ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
      return -1;
   }
   return 0;
}
static int reload ( void  ) [static]

Reload module.

Definition at line 2078 of file chan_gtalk.c.

{
   return 0;
}
static int unload_module ( void  ) [static]

Unload the gtalk channel from Asterisk.

Definition at line 2084 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_proto_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, gtalk_list, gtalk_member_destroy(), gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.

{
   struct gtalk_pvt *privates = NULL;
   ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
   /* First, take us out of the channel loop */
   ast_channel_unregister(&gtalk_tech);
   ast_rtp_proto_unregister(&gtalk_rtp);

   if (!ast_mutex_lock(&gtalklock)) {
      /* Hangup all interfaces if they have an owner */
      ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
         ASTOBJ_WRLOCK(iterator);
         privates = iterator->p;
         while(privates) {
            if (privates->owner)
               ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
            privates = privates->next;
         }
         iterator->p = NULL;
         ASTOBJ_UNLOCK(iterator);
      });
      ast_mutex_unlock(&gtalklock);
   } else {
      ast_log(LOG_WARNING, "Unable to lock the monitor\n");
      return -1;
   }
   ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
   ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
   return 0;
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2119 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 218 of file chan_gtalk.c.

Referenced by gtalk_create_candidates(), and load_module().

Definition at line 2119 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

The address we bind to

Definition at line 214 of file chan_gtalk.c.

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 76 of file chan_gtalk.c.

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

Definition at line 162 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 233 of file chan_gtalk.c.

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

Definition at line 164 of file chan_gtalk.c.

Referenced by gtalk_alloc(), and gtalk_new().

struct ast_jb_conf global_jbconf [static]

Definition at line 84 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and gtalk_new().

struct ast_cli_entry gtalk_cli[] [static]
Initial value:
 {
   AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"),
   AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
}

Definition at line 228 of file chan_gtalk.c.

struct ast_rtp_protocol gtalk_rtp [static]

RTP driver interface.

Definition at line 221 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 194 of file chan_gtalk.c.

Referenced by gtalk_new().

ast_mutex_t gtalklock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Protect the interface list (of gtalk_pvt's)

Definition at line 166 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 217 of file chan_gtalk.c.

Referenced by ast_rtp_new_with_bindaddr(), and ast_udptl_new_with_bindaddr().

struct sched_context* sched [static]

The scheduling context

Definition at line 216 of file chan_gtalk.c.

Referenced by ast_rtp_new_with_bindaddr(), and ast_udptl_new_with_bindaddr().