Tue Mar 2 17:32:49 2010

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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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.


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 90 of file chan_gtalk.c.

00090                         {
00091    AJI_CONNECT_STUN = 1,
00092    AJI_CONNECT_LOCAL = 2,
00093    AJI_CONNECT_RELAY = 3,
00094 };

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 85 of file chan_gtalk.c.

00085                     {
00086    AJI_PROTOCOL_UDP = 1,
00087    AJI_PROTOCOL_SSLTCP = 2,
00088 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2114 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2114 of file chan_gtalk.c.

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

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

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

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

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

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

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

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

01078 {
01079    iks *request, *session = NULL;
01080    int res = -1;
01081    char *lowerthem = NULL;
01082 
01083    request = iks_new("iq");
01084    if (request) {
01085       iks_insert_attrib(request, "type", "set");
01086       iks_insert_attrib(request, "from", p->us);
01087       iks_insert_attrib(request, "to", p->them);
01088       iks_insert_attrib(request, "id", client->connection->mid);
01089       ast_aji_increment_mid(client->connection->mid);
01090       session = iks_new("session");
01091       if (session) {
01092          iks_insert_attrib(session, "type", action);
01093          iks_insert_attrib(session, "id", p->sid);
01094          /* put the initiator attribute to lower case if we receive the call 
01095           * otherwise GoogleTalk won't establish the session */
01096          if (!p->initiator) {
01097                  char c;
01098             char *t = lowerthem = ast_strdupa(p->them);
01099             while (((c = *t) != '/') && (*t++ = tolower(c)));
01100          }
01101          iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01102          iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
01103          iks_insert_node(request, session);
01104          ast_aji_send(client->connection, request);
01105          res = 0;
01106       }
01107    }
01108 
01109    iks_delete(session);
01110    iks_delete(request);
01111 
01112    return res;
01113 }

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

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

01302 {
01303    struct gtalk_pvt *p = NULL, *tmp = NULL;
01304    struct aji_client *c = client->connection;
01305    struct gtalk_candidate *newcandidate = NULL;
01306    iks *traversenodes = NULL, *receipt = NULL;
01307    char *from;
01308 
01309    from = iks_find_attrib(pak->x,"to");
01310    if(!from)
01311       from = c->jid->full;
01312 
01313    for (tmp = client->p; tmp; tmp = tmp->next) {
01314       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01315          p = tmp;
01316          break;
01317       }
01318    }
01319 
01320    if (!p)
01321       return -1;
01322 
01323    traversenodes = pak->query;
01324    while(traversenodes) {
01325       if(!strcasecmp(iks_name(traversenodes), "session")) {
01326          traversenodes = iks_first_tag(traversenodes);
01327          continue;
01328       }
01329       if(!strcasecmp(iks_name(traversenodes), "transport")) {
01330          traversenodes = iks_first_tag(traversenodes);
01331          continue;
01332       }
01333       if(!strcasecmp(iks_name(traversenodes), "candidate")) {
01334          newcandidate = ast_calloc(1, sizeof(*newcandidate));
01335          if (!newcandidate)
01336             return 0;
01337          ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
01338                      sizeof(newcandidate->name));
01339          ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
01340                      sizeof(newcandidate->ip));
01341          newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01342          ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
01343                      sizeof(newcandidate->username));
01344          ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
01345                      sizeof(newcandidate->password));
01346          newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01347          if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
01348             newcandidate->protocol = AJI_PROTOCOL_UDP;
01349          if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
01350             newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01351       
01352          if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
01353             newcandidate->type = AJI_CONNECT_STUN;
01354          if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
01355             newcandidate->type = AJI_CONNECT_LOCAL;
01356          if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
01357             newcandidate->type = AJI_CONNECT_RELAY;
01358          ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
01359                      sizeof(newcandidate->network));
01360          newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
01361          newcandidate->next = NULL;
01362       
01363          newcandidate->next = p->theircandidates;
01364          p->theircandidates = newcandidate;
01365          p->laststun = 0;
01366          gtalk_update_stun(p->parent, p);
01367          newcandidate = NULL;
01368       }
01369       traversenodes = iks_next_tag(traversenodes);
01370    }
01371    
01372    receipt = iks_new("iq");
01373    iks_insert_attrib(receipt, "type", "result");
01374    iks_insert_attrib(receipt, "from", from);
01375    iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
01376    iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
01377    ast_aji_send(c, receipt);
01378 
01379    iks_delete(receipt);
01380 
01381    return 1;
01382 }

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

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

00909 {
00910    struct gtalk_pvt *tmp = NULL;
00911    struct aji_resource *resources = NULL;
00912    struct aji_buddy *buddy;
00913    char idroster[200];
00914    char *data, *exten = NULL;
00915 
00916    ast_debug(1, "The client is %s for alloc\n", client->name);
00917    if (!sid && !strchr(them, '/')) {   /* I started call! */
00918       if (!strcasecmp(client->name, "guest")) {
00919          buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00920          if (buddy)
00921             resources = buddy->resources;
00922       } else if (client->buddy)
00923          resources = client->buddy->resources;
00924       while (resources) {
00925          if (resources->cap->jingle) {
00926             break;
00927          }
00928          resources = resources->next;
00929       }
00930       if (resources)
00931          snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
00932       else {
00933          ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
00934          return NULL;
00935       }
00936    }
00937    if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00938       return NULL;
00939    }
00940 
00941    memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
00942 
00943    if (sid) {
00944       ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
00945       ast_copy_string(tmp->them, them, sizeof(tmp->them));
00946       ast_copy_string(tmp->us, us, sizeof(tmp->us));
00947    } else {
00948       snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
00949       ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
00950       ast_copy_string(tmp->us, us, sizeof(tmp->us));
00951       tmp->initiator = 1;
00952    }
00953    /* clear codecs */
00954    tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
00955    ast_rtp_pt_clear(tmp->rtp);
00956 
00957    /* add user configured codec capabilites */
00958    if (client->capability)
00959       tmp->capability = client->capability;
00960    else if (global_capability)
00961       tmp->capability = global_capability;
00962 
00963    tmp->parent = client;
00964    if (!tmp->rtp) {
00965       ast_log(LOG_WARNING, "Out of RTP sessions?\n");
00966       ast_free(tmp);
00967       return NULL;
00968    }
00969 
00970    /* Set CALLERID(name) to the full JID of the remote peer */
00971    ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
00972 
00973    if(strchr(tmp->us, '/')) {
00974       data = ast_strdupa(tmp->us);
00975       exten = strsep(&data, "/");
00976    } else
00977       exten = tmp->us;
00978    ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
00979    ast_mutex_init(&tmp->lock);
00980    ast_mutex_lock(&gtalklock);
00981    tmp->next = client->p;
00982    client->p = tmp;
00983    ast_mutex_unlock(&gtalklock);
00984    return tmp;
00985 }

static int gtalk_answer ( struct ast_channel ast  )  [static]

Definition at line 512 of file chan_gtalk.c.

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

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

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 1592 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, gtalk_pvt::parent, gtalk_pvt::ring, gtalk_pvt::ringrule, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.

01593 {
01594    struct gtalk_pvt *p = ast->tech_pvt;
01595 
01596    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01597       ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01598       return -1;
01599    }
01600 
01601    ast_setstate(ast, AST_STATE_RING);
01602    if (!p->ringrule) {
01603       ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01604       p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01605                      IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01606    } else
01607       ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01608 
01609    gtalk_invite(p, p->them, p->us, p->sid, 1);
01610    gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
01611 
01612    return 0;
01613 }

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

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

00773 {
00774    struct gtalk_candidate *tmp;
00775    struct aji_client *c = client->connection;
00776    struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00777    struct sockaddr_in sin;
00778    struct sockaddr_in dest;
00779    struct in_addr us;
00780    iks *iq, *gtalk, *candidate, *transport;
00781    char user[17], pass[17], preference[5], port[7];
00782    char *lowerfrom = NULL;
00783 
00784 
00785    iq = iks_new("iq");
00786    gtalk = iks_new("session");
00787    candidate = iks_new("candidate");
00788    transport = iks_new("transport");
00789    if (!iq || !gtalk || !candidate || !transport) {
00790       ast_log(LOG_ERROR, "Memory allocation error\n");
00791       goto safeout;
00792    }
00793    ours1 = ast_calloc(1, sizeof(*ours1));
00794    ours2 = ast_calloc(1, sizeof(*ours2));
00795    if (!ours1 || !ours2)
00796       goto safeout;
00797 
00798    iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
00799    iks_insert_node(iq, gtalk);
00800    iks_insert_node(gtalk,transport);
00801    iks_insert_node(transport, candidate);
00802 
00803    for (; p; p = p->next) {
00804       if (!strcasecmp(p->sid, sid))
00805          break;
00806    }
00807 
00808    if (!p) {
00809       ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00810       goto safeout;
00811    }
00812 
00813    ast_rtp_get_us(p->rtp, &sin);
00814    ast_find_ourip(&us, bindaddr);
00815    if (!strcmp(ast_inet_ntoa(us), "127.0.0.1")) {
00816       ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
00817    }
00818 
00819    /* Setup our gtalk candidates */
00820    ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00821    ours1->port = ntohs(sin.sin_port);
00822    ours1->preference = 1;
00823    snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00824    snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00825    ast_copy_string(ours1->username, user, sizeof(ours1->username));
00826    ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00827    ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
00828    ours1->protocol = AJI_PROTOCOL_UDP;
00829    ours1->type = AJI_CONNECT_LOCAL;
00830    ours1->generation = 0;
00831    p->ourcandidates = ours1;
00832 
00833    if (!ast_strlen_zero(externip)) {
00834       /* XXX We should really stun for this one not just go with externip XXX */
00835       snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00836       snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00837       ast_copy_string(ours2->username, user, sizeof(ours2->username));
00838       ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00839       ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00840       ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00841       ours2->port = ntohs(sin.sin_port);
00842       ours2->preference = 0.9;
00843       ours2->protocol = AJI_PROTOCOL_UDP;
00844       ours2->type = AJI_CONNECT_STUN;
00845       ours2->generation = 0;
00846       ours1->next = ours2;
00847       ours2 = NULL;
00848    }
00849    ours1 = NULL;
00850    dest.sin_addr = __ourip;
00851    dest.sin_port = sin.sin_port;
00852 
00853 
00854    for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00855       snprintf(port, sizeof(port), "%d", tmp->port);
00856       snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00857       iks_insert_attrib(iq, "from", to);
00858       iks_insert_attrib(iq, "to", from);
00859       iks_insert_attrib(iq, "type", "set");
00860       iks_insert_attrib(iq, "id", c->mid);
00861       ast_aji_increment_mid(c->mid);
00862       iks_insert_attrib(gtalk, "type", "transport-info");
00863       iks_insert_attrib(gtalk, "id", sid);
00864       /* put the initiator attribute to lower case if we receive the call 
00865        * otherwise GoogleTalk won't establish the session */
00866       if (!p->initiator) {
00867               char c;
00868          char *t = lowerfrom = ast_strdupa(from);
00869          while (((c = *t) != '/') && (*t++ = tolower(c)));
00870       }
00871       iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
00872       iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00873       iks_insert_attrib(candidate, "name", tmp->name);
00874       iks_insert_attrib(candidate, "address", tmp->ip);
00875       iks_insert_attrib(candidate, "port", port);
00876       iks_insert_attrib(candidate, "username", tmp->username);
00877       iks_insert_attrib(candidate, "password", tmp->password);
00878       iks_insert_attrib(candidate, "preference", preference);
00879       if (tmp->protocol == AJI_PROTOCOL_UDP)
00880          iks_insert_attrib(candidate, "protocol", "udp");
00881       if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00882          iks_insert_attrib(candidate, "protocol", "ssltcp");
00883       if (tmp->type == AJI_CONNECT_STUN)
00884          iks_insert_attrib(candidate, "type", "stun");
00885       if (tmp->type == AJI_CONNECT_LOCAL)
00886          iks_insert_attrib(candidate, "type", "local");
00887       if (tmp->type == AJI_CONNECT_RELAY)
00888          iks_insert_attrib(candidate, "type", "relay");
00889       iks_insert_attrib(candidate, "network", "0");
00890       iks_insert_attrib(candidate, "generation", "0");
00891       ast_aji_send(c, iq);
00892    }
00893    p->laststun = 0;
00894 
00895 safeout:
00896    if (ours1)
00897       ast_free(ours1);
00898    if (ours2)
00899       ast_free(ours2);
00900    iks_delete(iq);
00901    iks_delete(gtalk);
00902    iks_delete(candidate);
00903    iks_delete(transport);
00904 
00905    return 1;
00906 }

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

Referenced by gtalk_load_config().

01842 {
01843    struct aji_client *client;
01844 
01845    if (!member)
01846       ast_log(LOG_WARNING, "Out of memory.\n");
01847 
01848    ast_copy_string(member->name, label, sizeof(member->name));
01849    ast_copy_string(member->user, label, sizeof(member->user));
01850    ast_copy_string(member->context, context, sizeof(member->context));
01851    member->allowguest = allowguest;
01852    member->prefs = prefs;
01853    while (var) {
01854 #if 0
01855       struct gtalk_candidate *candidate = NULL;
01856 #endif
01857       if (!strcasecmp(var->name, "username"))
01858          ast_copy_string(member->user, var->value, sizeof(member->user));
01859       else if (!strcasecmp(var->name, "disallow"))
01860          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
01861       else if (!strcasecmp(var->name, "allow"))
01862          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
01863       else if (!strcasecmp(var->name, "context"))
01864          ast_copy_string(member->context, var->value, sizeof(member->context));
01865       else if (!strcasecmp(var->name, "parkinglot"))
01866          ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
01867 #if 0
01868       else if (!strcasecmp(var->name, "candidate")) {
01869          candidate = gtalk_create_candidate(var->value);
01870          if (candidate) {
01871             candidate->next = member->ourcandidates;
01872             member->ourcandidates = candidate;
01873          }
01874       }
01875 #endif
01876       else if (!strcasecmp(var->name, "connection")) {
01877          if ((client = ast_aji_get_client(var->value))) {
01878             member->connection = client;
01879             iks_filter_add_rule(client->f, gtalk_parser, member, 
01880                       IKS_RULE_TYPE, IKS_PAK_IQ, 
01881                       IKS_RULE_FROM_PARTIAL, member->user,
01882                       IKS_RULE_NS, "http://www.google.com/session",
01883                       IKS_RULE_DONE);
01884 
01885          } else {
01886             ast_log(LOG_ERROR, "connection referenced not found!\n");
01887             return 0;
01888          }
01889       }
01890       var = var->next;
01891    }
01892    if (member->connection && member->user)
01893       member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
01894    else {
01895       ast_log(LOG_ERROR, "No Connection or Username!\n");
01896    }
01897    return 1;
01898 }

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

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

01512 {
01513    struct gtalk_pvt *p = ast->tech_pvt;
01514    struct gtalk *client = p->parent;
01515    iks *iq, *gtalk, *dtmf;
01516    char buffer[2] = {digit, '\0'};
01517    char *lowerthem = NULL;
01518    iq = iks_new("iq");
01519    gtalk = iks_new("gtalk");
01520    dtmf = iks_new("dtmf");
01521    if(!iq || !gtalk || !dtmf) {
01522       iks_delete(iq);
01523       iks_delete(gtalk);
01524       iks_delete(dtmf);
01525       ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01526       return -1;
01527    }
01528 
01529    iks_insert_attrib(iq, "type", "set");
01530    iks_insert_attrib(iq, "to", p->them);
01531    iks_insert_attrib(iq, "from", p->us);
01532    iks_insert_attrib(iq, "id", client->connection->mid);
01533    ast_aji_increment_mid(client->connection->mid);
01534    iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01535    iks_insert_attrib(gtalk, "action", "session-info");
01536    /* put the initiator attribute to lower case if we receive the call 
01537     * otherwise GoogleTalk won't establish the session */
01538    if (!p->initiator) {
01539            char c;
01540            char *t = lowerthem = ast_strdupa(p->them);
01541            while (((c = *t) != '/') && (*t++ = tolower(c)));
01542    }
01543    iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
01544    iks_insert_attrib(gtalk, "sid", p->sid);
01545    iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01546    iks_insert_attrib(dtmf, "code", buffer);
01547    iks_insert_node(iq, gtalk);
01548    iks_insert_node(gtalk, dtmf);
01549 
01550    ast_mutex_lock(&p->lock);
01551    if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01552       iks_insert_attrib(dtmf, "action", "button-down");
01553    } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01554       iks_insert_attrib(dtmf, "action", "button-up");
01555    }
01556    ast_aji_send(client->connection, iq);
01557 
01558    iks_delete(iq);
01559    iks_delete(gtalk);
01560    iks_delete(dtmf);
01561    ast_mutex_unlock(&p->lock);
01562    return 0;
01563 }

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

Definition at line 1501 of file chan_gtalk.c.

References gtalk_digit().

01502 {
01503    return gtalk_digit(chan, digit, 0);
01504 }

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

Definition at line 1506 of file chan_gtalk.c.

References gtalk_digit().

01507 {
01508    return gtalk_digit(chan, digit, duration);
01509 }

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

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

01747 {
01748    switch (cmd) {
01749    case CLI_INIT:
01750       e->command = "gtalk reload";
01751       e->usage =
01752          "Usage: gtalk reload\n"
01753          "       Reload gtalk channel driver.\n";
01754       return NULL;
01755    case CLI_GENERATE:
01756       return NULL;
01757    }  
01758    
01759    ast_verbose("IT DOES WORK!\n");
01760    return CLI_SUCCESS;
01761 }

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

Definition at line 1467 of file chan_gtalk.c.

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

01468 {
01469    struct gtalk_pvt *p = newchan->tech_pvt;
01470    ast_mutex_lock(&p->lock);
01471 
01472    if ((p->owner != oldchan)) {
01473       ast_mutex_unlock(&p->lock);
01474       return -1;
01475    }
01476    if (p->owner == oldchan)
01477       p->owner = newchan;
01478    ast_mutex_unlock(&p->lock);
01479    return 0;
01480 }

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1115 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

01116 {
01117    struct gtalk_candidate *last;
01118    while (candidate) {
01119       last = candidate;
01120       candidate = candidate->next;
01121       ast_free(last);
01122    }
01123 }

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

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

01126 {
01127    struct gtalk_pvt *cur, *prev = NULL;
01128    cur = client->p;
01129    while (cur) {
01130       if (cur == p) {
01131          if (prev)
01132             prev->next = p->next;
01133          else
01134             client->p = p->next;
01135          break;
01136       }
01137       prev = cur;
01138       cur = cur->next;
01139    }
01140    if (p->ringrule)
01141       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01142    if (p->owner)
01143       ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01144    if (p->rtp)
01145       ast_rtp_destroy(p->rtp);
01146    if (p->vrtp)
01147       ast_rtp_destroy(p->vrtp);
01148    gtalk_free_candidates(p->theircandidates);
01149    ast_free(p);
01150 }

static int gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 544 of file chan_gtalk.c.

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

00545 {
00546    struct gtalk_pvt *p = chan->tech_pvt;
00547    return p->peercapability;
00548 }

static enum ast_rtp_get_result gtalk_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp **  rtp 
) [static]

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

00527 {
00528    struct gtalk_pvt *p = chan->tech_pvt;
00529    enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
00530 
00531    if (!p)
00532       return res;
00533 
00534    ast_mutex_lock(&p->lock);
00535    if (p->rtp){
00536       *rtp = p->rtp;
00537       res = AST_RTP_TRY_PARTIAL;
00538    }
00539    ast_mutex_unlock(&p->lock);
00540 
00541    return res;
00542 }

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

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

00680 {
00681    struct gtalk_pvt *tmp;
00682    iks *dtmfnode = NULL, *dtmfchild = NULL;
00683    char *dtmf;
00684    char *from;
00685    /* Make sure our new call doesn't exist yet */
00686    for (tmp = client->p; tmp; tmp = tmp->next) {
00687       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00688          break;
00689    }
00690    from = iks_find_attrib(pak->x, "to");
00691    if(!from)
00692       from = client->connection->jid->full;
00693 
00694 
00695    if (tmp) {
00696       if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00697          gtalk_response(client, from, pak,
00698                "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00699                "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00700          return -1;
00701       }
00702       if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00703          if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00704             if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00705                struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00706                f.subclass = dtmf[0];
00707                ast_queue_frame(tmp->owner, &f);
00708                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00709             } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00710                struct ast_frame f = {AST_FRAME_DTMF_END, };
00711                f.subclass = dtmf[0];
00712                ast_queue_frame(tmp->owner, &f);
00713                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00714             } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
00715                struct ast_frame f = {AST_FRAME_DTMF, };
00716                f.subclass = dtmf[0];
00717                ast_queue_frame(tmp->owner, &f);
00718                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00719             }
00720          }
00721       } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00722          if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00723             if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00724                if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00725                   struct ast_frame f = {AST_FRAME_DTMF_END, };
00726                   f.subclass = dtmf[0];
00727                   ast_queue_frame(tmp->owner, &f);
00728                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00729                } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00730                   struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00731                   f.subclass = dtmf[0];
00732                   ast_queue_frame(tmp->owner, &f);
00733                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00734                }
00735             }
00736          }
00737       }
00738       gtalk_response(client, from, pak, NULL, NULL);
00739       return 1;
00740    } else
00741       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00742 
00743    gtalk_response(client, from, pak, NULL, NULL);
00744    return 1;
00745 }

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1616 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, and ast_channel::tech_pvt.

Referenced by gtalk_newcall().

01617 {
01618    struct gtalk_pvt *p = ast->tech_pvt;
01619    struct gtalk *client;
01620 
01621    ast_mutex_lock(&p->lock);
01622    client = p->parent;
01623    p->owner = NULL;
01624    ast->tech_pvt = NULL;
01625    if (!p->alreadygone)
01626       gtalk_action(client, p, "terminate");
01627    ast_mutex_unlock(&p->lock);
01628 
01629    gtalk_free_pvt(client, p);
01630    ast_module_unref(ast_module_info->self);
01631 
01632    return 0;
01633 }

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

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

00748 {
00749    struct gtalk_pvt *tmp;
00750    char *from;
00751 
00752    ast_debug(1, "The client is %s\n", client->name);
00753    /* Make sure our new call doesn't exist yet */
00754    for (tmp = client->p; tmp; tmp = tmp->next) {
00755       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00756          break;
00757    }
00758    from = iks_find_attrib(pak->x, "to");
00759    if(!from)
00760       from = client->connection->jid->full;
00761 
00762    if (tmp) {
00763       tmp->alreadygone = 1;
00764       if (tmp->owner)
00765          ast_queue_hangup(tmp->owner);
00766    } else
00767       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00768    gtalk_response(client, from, pak, NULL, NULL);
00769    return 1;
00770 }

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

Definition at line 1482 of file chan_gtalk.c.

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

01483 {
01484    int res = 0;
01485 
01486    switch (condition) {
01487    case AST_CONTROL_HOLD:
01488       ast_moh_start(ast, data, NULL);
01489       break;
01490    case AST_CONTROL_UNHOLD:
01491       ast_moh_stop(ast);
01492       break;
01493    default:
01494       ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01495       res = -1;
01496    }
01497 
01498    return res;
01499 }

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

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

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

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

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

00458 {
00459    iks *iq, *session, *transport;
00460    char *lowerto = NULL;
00461 
00462    iq = iks_new("iq");
00463    session = iks_new("session");
00464    transport = iks_new("transport");
00465    if(!(iq && session && transport)) {
00466       iks_delete(iq);
00467       iks_delete(session);
00468       iks_delete(transport);
00469       ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
00470       return -1;
00471    }
00472    iks_insert_attrib(iq, "from", from);
00473    iks_insert_attrib(iq, "to", to);
00474    iks_insert_attrib(iq, "type", "set");
00475    iks_insert_attrib(iq, "id",p->parent->connection->mid);
00476    ast_aji_increment_mid(p->parent->connection->mid);
00477    iks_insert_attrib(session, "type", "transport-accept");
00478    iks_insert_attrib(session, "id", sid);
00479    /* put the initiator attribute to lower case if we receive the call 
00480     * otherwise GoogleTalk won't establish the session */
00481    if (!initiator) {
00482            char c;
00483       char *t = lowerto = ast_strdupa(to);
00484       while (((c = *t) != '/') && (*t++ = tolower(c)));
00485    }
00486    iks_insert_attrib(session, "initiator", initiator ? from : lowerto);
00487    iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
00488    iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
00489    iks_insert_node(iq,session);
00490    iks_insert_node(session,transport);
00491    ast_aji_send(p->parent->connection, iq);
00492 
00493    iks_delete(transport);
00494    iks_delete(session);
00495    iks_delete(iq);
00496    return 1;
00497 
00498 }

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

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

00656 {
00657    struct gtalk_pvt *tmp;
00658    char *from;
00659 
00660    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00661    /* find corresponding call */
00662    for (tmp = client->p; tmp; tmp = tmp->next) {
00663       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00664          break;
00665    }
00666 
00667    from = iks_find_attrib(pak->x, "to");
00668    if(!from)
00669       from = client->connection->jid->full;
00670 
00671    if (!tmp)
00672       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00673 
00674    /* answer 'iq' packet to let the remote peer know that we're alive */
00675    gtalk_response(client, from, pak, NULL, NULL);
00676    return 1;
00677 }

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

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

00603 {
00604    struct gtalk_pvt *tmp;
00605    char *from;
00606    iks *codec;
00607    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00608    int peernoncodeccapability;
00609 
00610    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00611    /* Make sure our new call doesn't exist yet */
00612    for (tmp = client->p; tmp; tmp = tmp->next) {
00613       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00614          break;
00615    }
00616 
00617    /* codec points to the first <payload-type/> tag */
00618    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00619    while (codec) {
00620       ast_rtp_set_m_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")));
00621       ast_rtp_set_rtpmap_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
00622       codec = iks_next_tag(codec);
00623    }
00624    
00625    /* Now gather all of the codecs that we are asked for */
00626    ast_rtp_get_current_formats(tmp->rtp, &tmp->peercapability, &peernoncodeccapability);
00627    
00628    /* at this point, we received an awser from the remote Gtalk client,
00629       which allows us to compare capabilities */
00630    tmp->jointcapability = tmp->capability & tmp->peercapability;
00631    if (!tmp->jointcapability) {
00632       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
00633          ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
00634          ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
00635       /* close session if capabilities don't match */
00636       ast_queue_hangup(tmp->owner);
00637 
00638       return -1;
00639 
00640    }  
00641    
00642    from = iks_find_attrib(pak->x, "to");
00643    if(!from)
00644       from = client->connection->jid->full;
00645 
00646    if (tmp) {
00647       if (tmp->owner)
00648          ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00649    } else
00650       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00651    gtalk_response(client, from, pak, NULL, NULL);
00652    return 1;
00653 }

static int gtalk_load_config ( void   )  [static]

Definition at line 1900 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, gtalk::connection, gtalk::context, context, global_jbconf, GOOGLE_CONFIG, gtalk_create_member(), gtalk_free_candidates(), gtalk_list, gtalk_member_destroy(), gtalk_parser(), hp, LOG_WARNING, gtalk::name, ast_variable::name, ast_variable::next, gtalk::parkinglot, parkinglot, gtalk::prefs, gtalk::user, ast_variable::value, and var.

Referenced by load_module().

01901 {
01902    char *cat = NULL;
01903    struct ast_config *cfg = NULL;
01904    char context[AST_MAX_CONTEXT];
01905    char parkinglot[AST_MAX_CONTEXT];
01906    int allowguest = 1;
01907    struct ast_variable *var;
01908    struct gtalk *member;
01909    struct ast_codec_pref prefs;
01910    struct aji_client_container *clients;
01911    struct gtalk_candidate *global_candidates = NULL;
01912    struct hostent *hp;
01913    struct ast_hostent ahp;
01914    struct ast_flags config_flags = { 0 };
01915 
01916    cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
01917    if (!cfg)
01918       return 0;
01919 
01920    /* Copy the default jb config over global_jbconf */
01921    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01922 
01923    cat = ast_category_browse(cfg, NULL);
01924    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
01925       /* handle jb conf */
01926       if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
01927          continue;
01928 
01929       if (!strcasecmp(var->name, "allowguest"))
01930          allowguest =
01931             (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
01932       else if (!strcasecmp(var->name, "disallow"))
01933          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
01934       else if (!strcasecmp(var->name, "allow"))
01935          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
01936       else if (!strcasecmp(var->name, "context"))
01937          ast_copy_string(context, var->value, sizeof(context));
01938       else if (!strcasecmp(var->name, "parkinglot"))
01939          ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
01940       else if (!strcasecmp(var->name, "bindaddr")) {
01941          if (!(hp = ast_gethostbyname(var->value, &ahp))) {
01942             ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
01943          } else {
01944             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
01945          }
01946       }
01947 /*  Idea to allow for custom candidates  */
01948 /*
01949       else if (!strcasecmp(var->name, "candidate")) {
01950          candidate = gtalk_create_candidate(var->value);
01951          if (candidate) {
01952             candidate->next = global_candidates;
01953             global_candidates = candidate;
01954          }
01955       }
01956 */
01957    }
01958    while (cat) {
01959       if (strcasecmp(cat, "general")) {
01960          var = ast_variable_browse(cfg, cat);
01961          member = ast_calloc(1, sizeof(*member));
01962          ASTOBJ_INIT(member);
01963          ASTOBJ_WRLOCK(member);
01964          if (!strcasecmp(cat, "guest")) {
01965             ast_copy_string(member->name, "guest", sizeof(member->name));
01966             ast_copy_string(member->user, "guest", sizeof(member->user));
01967             ast_copy_string(member->context, context, sizeof(member->context));
01968             ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
01969             member->allowguest = allowguest;
01970             member->prefs = prefs;
01971             while (var) {
01972                if (!strcasecmp(var->name, "disallow"))
01973                   ast_parse_allow_disallow(&member->prefs, &member->capability,
01974                                      var->value, 0);
01975                else if (!strcasecmp(var->name, "allow"))
01976                   ast_parse_allow_disallow(&member->prefs, &member->capability,
01977                                      var->value, 1);
01978                else if (!strcasecmp(var->name, "context"))
01979                   ast_copy_string(member->context, var->value,
01980                               sizeof(member->context));
01981                else if (!strcasecmp(var->name, "parkinglot"))
01982                   ast_copy_string(member->parkinglot, var->value,
01983                               sizeof(member->parkinglot));
01984 /*  Idea to allow for custom candidates  */
01985 /*
01986                else if (!strcasecmp(var->name, "candidate")) {
01987                   candidate = gtalk_create_candidate(var->value);
01988                   if (candidate) {
01989                      candidate->next = member->ourcandidates;
01990                      member->ourcandidates = candidate;
01991                   }
01992                }
01993 */
01994                var = var->next;
01995             }
01996             ASTOBJ_UNLOCK(member);
01997             clients = ast_aji_get_clients();
01998             if (clients) {
01999                ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02000                   ASTOBJ_WRLOCK(iterator);
02001                   ASTOBJ_WRLOCK(member);
02002                   member->connection = NULL;
02003                   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);
02004                   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);
02005                   ASTOBJ_UNLOCK(member);
02006                   ASTOBJ_UNLOCK(iterator);
02007                });
02008                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02009                ASTOBJ_UNREF(member, gtalk_member_destroy);
02010             } else {
02011                ASTOBJ_UNLOCK(member);
02012                ASTOBJ_UNREF(member, gtalk_member_destroy);
02013             }
02014          } else {
02015             ASTOBJ_UNLOCK(member);
02016             if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
02017                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02018             ASTOBJ_UNREF(member, gtalk_member_destroy);
02019          }
02020       }
02021       cat = ast_category_browse(cfg, cat);
02022    }
02023    gtalk_free_candidates(global_candidates);
02024    return 1;
02025 }

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 236 of file chan_gtalk.c.

References ast_free.

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

00237 {
00238    ast_free(obj);
00239 }

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 988 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_jbconf, ast_channel::hangupcause, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, 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, 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().

00989 {
00990    struct ast_channel *tmp;
00991    int fmt;
00992    int what;
00993    const char *n2;
00994 
00995    if (title)
00996       n2 = title;
00997    else
00998       n2 = i->us;
00999    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);
01000    if (!tmp) {
01001       ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01002       return NULL;
01003    }
01004    tmp->tech = &gtalk_tech;
01005 
01006    /* Select our native format based on codec preference until we receive
01007       something from another device to the contrary. */
01008    if (i->jointcapability)
01009       what = i->jointcapability;
01010    else if (i->capability)
01011       what = i->capability;
01012    else
01013       what = global_capability;
01014 
01015    /* Set Frame packetization */
01016    if (i->rtp)
01017       ast_rtp_codec_setpref(i->rtp, &i->prefs);
01018 
01019    tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
01020    fmt = ast_best_codec(tmp->nativeformats);
01021 
01022    if (i->rtp) {
01023       ast_rtp_setstun(i->rtp, 1);
01024       ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
01025       ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
01026    }
01027    if (i->vrtp) {
01028       ast_rtp_setstun(i->rtp, 1);
01029       ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
01030       ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
01031    }
01032    if (state == AST_STATE_RING)
01033       tmp->rings = 1;
01034    tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01035    tmp->writeformat = fmt;
01036    tmp->rawwriteformat = fmt;
01037    tmp->readformat = fmt;
01038    tmp->rawreadformat = fmt;
01039    tmp->tech_pvt = i;
01040 
01041    tmp->callgroup = client->callgroup;
01042    tmp->pickupgroup = client->pickupgroup;
01043    tmp->cid.cid_pres = client->callingpres;
01044    if (!ast_strlen_zero(client->accountcode))
01045       ast_string_field_set(tmp, accountcode, client->accountcode);
01046    if (client->amaflags)
01047       tmp->amaflags = client->amaflags;
01048    if (!ast_strlen_zero(client->language))
01049       ast_string_field_set(tmp, language, client->language);
01050    if (!ast_strlen_zero(client->musicclass))
01051       ast_string_field_set(tmp, musicclass, client->musicclass);
01052    if (!ast_strlen_zero(client->parkinglot))
01053       ast_string_field_set(tmp, parkinglot, client->parkinglot);
01054    i->owner = tmp;
01055    ast_module_ref(ast_module_info->self);
01056    ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01057    ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01058 
01059    if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
01060       tmp->cid.cid_dnid = ast_strdup(i->exten);
01061    tmp->priority = 1;
01062    if (i->rtp)
01063       ast_jb_configure(tmp, &global_jbconf);
01064    if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01065       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01066       tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01067       ast_hangup(tmp);
01068       tmp = NULL;
01069    } else {
01070       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01071          "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01072          i->owner ? i->owner->name : "", "Gtalk", i->sid);
01073    }
01074    return tmp;
01075 }

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

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

01154 {
01155    struct gtalk_pvt *p, *tmp = client->p;
01156    struct ast_channel *chan;
01157    int res;
01158    iks *codec;
01159    char *from = NULL;
01160    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01161    int peernoncodeccapability;
01162 
01163    /* Make sure our new call doesn't exist yet */
01164    from = iks_find_attrib(pak->x,"to");
01165    if(!from)
01166       from = client->connection->jid->full;
01167    
01168    while (tmp) {
01169       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01170          ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01171          gtalk_response(client, from, pak, "out-of-order", NULL);
01172          return -1;
01173       }
01174       tmp = tmp->next;
01175    }
01176 
01177    if (!strcasecmp(client->name, "guest")){
01178       /* the guest account is not tied to any configured XMPP client,
01179          let's set it now */
01180       client->connection = ast_aji_get_client(from);
01181       if (!client->connection) {
01182          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01183          return -1;
01184       }
01185    }
01186 
01187    p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
01188    if (!p) {
01189       ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01190       return -1;
01191    }
01192 
01193    chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
01194    if (!chan) {
01195       gtalk_free_pvt(client, p);
01196       return -1;
01197    }
01198 
01199    ast_mutex_lock(&p->lock);
01200    ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01201    if (iks_find_attrib(pak->query, "id")) {
01202       ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
01203             sizeof(p->sid));
01204    }
01205 
01206    /* codec points to the first <payload-type/> tag */   
01207    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
01208    
01209    while (codec) {
01210       ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
01211       ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
01212       codec = iks_next_tag(codec);
01213    }
01214    
01215    /* Now gather all of the codecs that we are asked for */
01216    ast_rtp_get_current_formats(p->rtp, &p->peercapability, &peernoncodeccapability);
01217    p->jointcapability = p->capability & p->peercapability;
01218    ast_mutex_unlock(&p->lock);
01219       
01220    ast_setstate(chan, AST_STATE_RING);
01221    if (!p->jointcapability) {
01222       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
01223          ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
01224          ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
01225       /* close session if capabilities don't match */
01226       gtalk_action(client, p, "reject");
01227       p->alreadygone = 1;
01228       gtalk_hangup(chan);
01229       ast_channel_free(chan);
01230       return -1;
01231    }  
01232 
01233    res = ast_pbx_start(chan);
01234    
01235    switch (res) {
01236    case AST_PBX_FAILED:
01237       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01238       gtalk_response(client, from, pak, "service-unavailable", NULL);
01239       break;
01240    case AST_PBX_CALL_LIMIT:
01241       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01242       gtalk_response(client, from, pak, "service-unavailable", NULL);
01243       break;
01244    case AST_PBX_SUCCESS:
01245       gtalk_response(client, from, pak, NULL, NULL);
01246       gtalk_invite_response(p, p->them, p->us,p->sid, 0);
01247       gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01248       /* nothing to do */
01249       break;
01250    }
01251 
01252    return 1;
01253 }

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

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

01764 {
01765    struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01766 
01767    if (iks_find_attrib(pak->x, "type") && !strcmp(iks_find_attrib (pak->x, "type"),"error")) {
01768       ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
01769    }
01770    else if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
01771       /* New call */
01772       gtalk_newcall(client, pak);
01773    } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
01774       ast_debug(3, "About to add candidate!\n");
01775       gtalk_add_candidate(client, pak);
01776       ast_debug(3, "Candidate Added!\n");
01777    } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
01778       gtalk_is_answered(client, pak);
01779    } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
01780       gtalk_is_accepted(client, pak);
01781    } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
01782       gtalk_handle_dtmf(client, pak);
01783    } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
01784       gtalk_hangup_farend(client, pak);
01785    } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
01786       gtalk_hangup_farend(client, pak);
01787    }
01788    ASTOBJ_UNREF(client, gtalk_member_destroy);
01789    return IKS_FILTER_EAT;
01790 }

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

Definition at line 1412 of file chan_gtalk.c.

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

01413 {
01414    struct ast_frame *fr;
01415    struct gtalk_pvt *p = ast->tech_pvt;
01416 
01417    ast_mutex_lock(&p->lock);
01418    fr = gtalk_rtp_read(ast, p);
01419    ast_mutex_unlock(&p->lock);
01420    return fr;
01421 }

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

Part of PBX interface.

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

01637 {
01638    struct gtalk_pvt *p = NULL;
01639    struct gtalk *client = NULL;
01640    char *sender = NULL, *to = NULL, *s = NULL;
01641    struct ast_channel *chan = NULL;
01642 
01643    if (data) {
01644       s = ast_strdupa(data);
01645       if (s) {
01646          sender = strsep(&s, "/");
01647          if (sender && (sender[0] != '\0'))
01648             to = strsep(&s, "/");
01649          if (!to) {
01650             ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01651             return NULL;
01652          }
01653       }
01654    }
01655 
01656    client = find_gtalk(to, sender);
01657    if (!client) {
01658       ast_log(LOG_WARNING, "Could not find recipient.\n");
01659       return NULL;
01660    }
01661    if (!strcasecmp(client->name, "guest")){
01662       /* the guest account is not tied to any configured XMPP client,
01663          let's set it now */
01664       client->connection = ast_aji_get_client(sender);
01665       if (!client->connection) {
01666          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01667          ASTOBJ_UNREF(client, gtalk_member_destroy);
01668          return NULL;
01669       }
01670    }
01671        
01672    ASTOBJ_WRLOCK(client);
01673    p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01674    if (p)
01675       chan = gtalk_new(client, p, AST_STATE_DOWN, to);
01676 
01677    ASTOBJ_UNLOCK(client);
01678    return chan;
01679 }

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

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

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

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

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

00501 {
00502    struct gtalk_pvt *p = data;
00503 
00504    if (p->ringrule)
00505       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00506    p->ringrule = NULL;
00507    if (p->owner)
00508       ast_queue_control(p->owner, AST_CONTROL_RINGING);
00509    return IKS_FILTER_EAT;
00510 }

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

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

01385 {
01386    struct ast_frame *f;
01387 
01388    if (!p->rtp)
01389       return &ast_null_frame;
01390    f = ast_rtp_read(p->rtp);
01391    gtalk_update_stun(p->parent, p);
01392    if (p->owner) {
01393       /* We already hold the channel lock */
01394       if (f->frametype == AST_FRAME_VOICE) {
01395          if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01396             ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
01397             p->owner->nativeformats =
01398                (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
01399             ast_set_read_format(p->owner, p->owner->readformat);
01400             ast_set_write_format(p->owner, p->owner->writeformat);
01401          }
01402 /*       if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
01403             f = ast_dsp_process(p->owner, p->vad, f);
01404             if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
01405                ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
01406               } */
01407       }
01408    }
01409    return f;
01410 }

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

Definition at line 1565 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01566 {
01567    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01568 
01569    return -1;
01570 }

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

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

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

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 1682 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, gtalk_pvt::next, gtalk_pvt::owner, ast_channel::readformat, gtalk_pvt::them, ast_cli_entry::usage, and ast_channel::writeformat.

01683 {
01684 #define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
01685    struct gtalk_pvt *p;
01686    struct ast_channel *chan;
01687    int numchans = 0;
01688    char them[AJI_MAX_JIDLEN];
01689    char *jid = NULL;
01690    char *resource = NULL;
01691 
01692    switch (cmd) {
01693    case CLI_INIT:
01694       e->command = "gtalk show channels";
01695       e->usage =
01696          "Usage: gtalk show channels\n"
01697          "       Shows current state of the Gtalk channels.\n";
01698       return NULL;
01699    case CLI_GENERATE:
01700       return NULL;
01701    }
01702 
01703    if (a->argc != 3)
01704       return CLI_SHOWUSAGE;
01705 
01706    ast_mutex_lock(&gtalklock);
01707    ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01708    ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
01709       ASTOBJ_WRLOCK(iterator);
01710       p = iterator->p;
01711       while(p) {
01712          chan = p->owner;
01713          ast_copy_string(them, p->them, sizeof(them));
01714          jid = them;
01715          resource = strchr(them, '/');
01716          if (!resource)
01717             resource = "None";
01718          else {
01719             *resource = '\0';
01720             resource ++;
01721          }
01722          if (chan)
01723             ast_cli(a->fd, FORMAT, 
01724                chan->name,
01725                jid,
01726                resource,
01727                ast_getformatname(chan->readformat),
01728                ast_getformatname(chan->writeformat)               
01729                );
01730          else 
01731             ast_log(LOG_WARNING, "No available channel\n");
01732          numchans ++;
01733          p = p->next;
01734       }
01735       ASTOBJ_UNLOCK(iterator);
01736    });
01737 
01738    ast_mutex_unlock(&gtalklock);
01739 
01740    ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01741    return CLI_SUCCESS;
01742 #undef FORMAT
01743 }

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

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

01256 {
01257    struct gtalk_candidate *tmp;
01258    struct hostent *hp;
01259    struct ast_hostent ahp;
01260    struct sockaddr_in sin;
01261    struct sockaddr_in aux;
01262 
01263    if (time(NULL) == p->laststun)
01264       return 0;
01265 
01266    tmp = p->theircandidates;
01267    p->laststun = time(NULL);
01268    while (tmp) {
01269       char username[256];
01270 
01271       /* Find the IP address of the host */
01272       hp = ast_gethostbyname(tmp->ip, &ahp);
01273       sin.sin_family = AF_INET;
01274       memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01275       sin.sin_port = htons(tmp->port);
01276       snprintf(username, sizeof(username), "%s%s", tmp->username,
01277           p->ourcandidates->username);
01278       
01279       /* Find out the result of the STUN */
01280       ast_rtp_get_peer(p->rtp, &aux);
01281 
01282       /* If the STUN result is different from the IP of the hostname,
01283          lock on the stun IP of the hostname advertised by the
01284          remote client */
01285       if (aux.sin_addr.s_addr && 
01286           aux.sin_addr.s_addr != sin.sin_addr.s_addr)
01287          ast_rtp_stun_request(p->rtp, &aux, username);
01288       else 
01289          ast_rtp_stun_request(p->rtp, &sin, username);
01290       
01291       if (aux.sin_addr.s_addr) {
01292          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);
01293          ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01294       }
01295 
01296       tmp = tmp->next;
01297    }
01298    return 1;
01299 }

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

Send frame to media channel (rtp).

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

01425 {
01426    struct gtalk_pvt *p = ast->tech_pvt;
01427    int res = 0;
01428 
01429    switch (frame->frametype) {
01430    case AST_FRAME_VOICE:
01431       if (!(frame->subclass & ast->nativeformats)) {
01432          ast_log(LOG_WARNING,
01433                "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01434                frame->subclass, ast->nativeformats, ast->readformat,
01435                ast->writeformat);
01436          return 0;
01437       }
01438       if (p) {
01439          ast_mutex_lock(&p->lock);
01440          if (p->rtp) {
01441             res = ast_rtp_write(p->rtp, frame);
01442          }
01443          ast_mutex_unlock(&p->lock);
01444       }
01445       break;
01446    case AST_FRAME_VIDEO:
01447       if (p) {
01448          ast_mutex_lock(&p->lock);
01449          if (p->vrtp) {
01450             res = ast_rtp_write(p->vrtp, frame);
01451          }
01452          ast_mutex_unlock(&p->lock);
01453       }
01454       break;
01455    case AST_FRAME_IMAGE:
01456       return 0;
01457       break;
01458    default:
01459       ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01460             frame->frametype);
01461       return 0;
01462    }
01463 
01464    return res;
01465 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

02029 {
02030    char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02031    free(jabber_loaded);
02032    if (!jabber_loaded) {
02033       /* If embedded, check for a different module name */
02034       jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02035       free(jabber_loaded);
02036       if (!jabber_loaded) {
02037          ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02038          return AST_MODULE_LOAD_DECLINE;
02039       }
02040    }
02041 
02042    ASTOBJ_CONTAINER_INIT(&gtalk_list);
02043    if (!gtalk_load_config()) {
02044       ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02045       return 0;
02046    }
02047 
02048    sched = sched_context_create();
02049    if (!sched) 
02050       ast_log(LOG_WARNING, "Unable to create schedule context\n");
02051 
02052    io = io_context_create();
02053    if (!io) 
02054       ast_log(LOG_WARNING, "Unable to create I/O context\n");
02055 
02056    if (ast_find_ourip(&__ourip, bindaddr)) {
02057       ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02058       return 0;
02059    }
02060 
02061    ast_rtp_proto_register(&gtalk_rtp);
02062    ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02063 
02064    /* Make sure we can register our channel type */
02065    if (ast_channel_register(&gtalk_tech)) {
02066       ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02067       return -1;
02068    }
02069    return 0;
02070 }

static int reload ( void   )  [static]

Reload module.

Definition at line 2073 of file chan_gtalk.c.

02074 {
02075    return 0;
02076 }

static int unload_module ( void   )  [static]

Unload the gtalk channel from Asterisk.

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

02080 {
02081    struct gtalk_pvt *privates = NULL;
02082    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02083    /* First, take us out of the channel loop */
02084    ast_channel_unregister(&gtalk_tech);
02085    ast_rtp_proto_unregister(&gtalk_rtp);
02086 
02087    if (!ast_mutex_lock(&gtalklock)) {
02088       /* Hangup all interfaces if they have an owner */
02089       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02090          ASTOBJ_WRLOCK(iterator);
02091          privates = iterator->p;
02092          while(privates) {
02093             if (privates->owner)
02094                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02095             privates = privates->next;
02096          }
02097          iterator->p = NULL;
02098          ASTOBJ_UNLOCK(iterator);
02099       });
02100       ast_mutex_unlock(&gtalklock);
02101    } else {
02102       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02103       return -1;
02104    }
02105    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02106    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02107    return 0;
02108 }


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2114 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 217 of file chan_gtalk.c.

Referenced by gtalk_create_candidates(), and load_module().

Definition at line 2114 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

The address we bind to

Definition at line 213 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]
char externip[16] [static]

Definition at line 232 of file chan_gtalk.c.

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

Definition at line 163 of file chan_gtalk.c.

struct ast_jb_conf global_jbconf [static]

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

struct gtalk_container gtalk_list [static]
struct ast_rtp_protocol gtalk_rtp [static]

RTP driver interface.

Definition at line 220 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 193 of file chan_gtalk.c.

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

Protect the interface list (of gtalk_pvt's)

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

struct sched_context* sched [static]

The scheduling context

Definition at line 215 of file chan_gtalk.c.


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1