Thu Oct 11 06:48:14 2012

Asterisk developer's documentation


chan_gtalk.c File Reference

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

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

Include dependency graph for chan_gtalk.c:

Go to the source code of this file.

Data Structures

struct  gtalk
struct  gtalk_candidate
struct  gtalk_container
struct  gtalk_pvt

Defines

#define FORMAT   "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
#define GOOGLE_CONFIG   "gtalk.conf"
#define GOOGLE_NS   "http://www.google.com/session"

Enumerations

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

Functions

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

Variables

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


Detailed Description

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

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

Definition in file chan_gtalk.c.


Define Documentation

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

#define GOOGLE_CONFIG   "gtalk.conf"

Definition at line 70 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and load_module().

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

Definition at line 72 of file chan_gtalk.c.

Referenced by gtalk_create_candidates().


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 91 of file chan_gtalk.c.

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

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 86 of file chan_gtalk.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2119 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2119 of file chan_gtalk.c.

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

Definition at line 274 of file chan_gtalk.c.

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

Referenced by gtalk_invite(), and jingle_accept_call().

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

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

Definition at line 242 of file chan_gtalk.c.

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

Referenced by gtalk_request().

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

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

Definition at line 1078 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

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

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

Definition at line 1302 of file chan_gtalk.c.

References AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_send(), ast_calloc, ast_copy_string(), gtalk::connection, gtalk_candidate::generation, gtalk_update_stun(), gtalk_candidate::ip, aji_client::jid, gtalk_pvt::laststun, gtalk_candidate::name, gtalk_candidate::network, gtalk_candidate::next, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_candidate::password, gtalk_candidate::port, gtalk_candidate::preference, gtalk_candidate::protocol, gtalk_candidate::receipt, gtalk_pvt::theircandidates, gtalk_candidate::type, and gtalk_candidate::username.

Referenced by gtalk_parser().

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

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

Definition at line 909 of file chan_gtalk.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_rtp_new_with_bindaddr(), ast_rtp_pt_clear(), ast_strdupa, ASTOBJ_CONTAINER_FIND, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk_pvt::capability, gtalk::capability, gtalk_pvt::cid_name, gtalk::connection, gtalk_pvt::exten, exten, 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().

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

static int gtalk_answer ( struct ast_channel ast  )  [static]

Definition at line 513 of file chan_gtalk.c.

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

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

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

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

Definition at line 1593 of file chan_gtalk.c.

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

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

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

Definition at line 773 of file chan_gtalk.c.

References __ourip, AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_find_ourip(), ast_free, ast_inet_ntoa(), ast_log(), ast_random(), ast_rtp_get_us(), ast_strdupa, ast_strlen_zero(), gtalk::connection, gtalk_candidate::generation, GOOGLE_NS, gtalk_pvt::initiator, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_client::mid, gtalk_candidate::name, gtalk_candidate::next, gtalk_pvt::next, gtalk_pvt::ourcandidates, pass, gtalk_candidate::password, gtalk_candidate::port, gtalk_candidate::preference, gtalk_candidate::protocol, gtalk_pvt::rtp, gtalk_pvt::sid, gtalk_candidate::type, and gtalk_candidate::username.

Referenced by gtalk_call(), and gtalk_newcall().

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

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

Definition at line 1840 of file chan_gtalk.c.

References 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().

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

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

Definition at line 1512 of file chan_gtalk.c.

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

Referenced by gtalk_digit_begin(), and gtalk_digit_end().

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

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

Definition at line 1502 of file chan_gtalk.c.

References gtalk_digit().

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

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

Definition at line 1507 of file chan_gtalk.c.

References gtalk_digit().

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

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

CLI command "gtalk reload".

Definition at line 1747 of file chan_gtalk.c.

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

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

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

Definition at line 1468 of file chan_gtalk.c.

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

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

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1116 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

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

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

Definition at line 1126 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

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

static int gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 545 of file chan_gtalk.c.

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

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

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

Definition at line 527 of file chan_gtalk.c.

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

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

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

Definition at line 680 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

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

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1617 of file chan_gtalk.c.

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

Referenced by gtalk_newcall().

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

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

Definition at line 748 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

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

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

Definition at line 1483 of file chan_gtalk.c.

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

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

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

Definition at line 379 of file chan_gtalk.c.

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

Referenced by gtalk_answer(), and gtalk_call().

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

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

Definition at line 458 of file chan_gtalk.c.

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

Referenced by gtalk_newcall().

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

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

Definition at line 656 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

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

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

Definition at line 603 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

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

static int gtalk_load_config ( void   )  [static]

Definition at line 1901 of file chan_gtalk.c.

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

Referenced by load_module().

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

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 237 of file chan_gtalk.c.

References ast_free.

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

00238 {
00239    ast_free(obj);
00240 }

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

Start new gtalk channel.

Definition at line 989 of file chan_gtalk.c.

References accountcode, gtalk::accountcode, ast_channel::adsicpe, ast_channel::amaflags, gtalk::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc, ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), AST_FORMAT_VIDEO_MASK, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_random(), ast_rtcp_fd(), ast_rtp_codec_setpref(), ast_rtp_fd(), ast_rtp_setstun(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, ast_channel::cid, ast_callerid::cid_dnid, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_callerid::cid_pres, ast_channel::context, gtalk::context, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_jbconf, ast_channel::hangupcause, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_channel::nativeformats, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, 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().

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

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

Definition at line 1154 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_aji_get_client(), ast_channel_free(), ast_copy_string(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_rtp_get_current_formats(), ast_rtp_set_m_type(), ast_rtp_set_rtpmap_type(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, gtalk_pvt::capability, chan, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_invite_response(), gtalk_new(), gtalk_response(), aji_client::jid, gtalk_pvt::jointcapability, gtalk_pvt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::peercapability, gtalk_pvt::rtp, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_parser().

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

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

Definition at line 1764 of file chan_gtalk.c.

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

Referenced by gtalk_create_member(), and gtalk_load_config().

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

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

Definition at line 1413 of file chan_gtalk.c.

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

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

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

Part of PBX interface.

Definition at line 1637 of file chan_gtalk.c.

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

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

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

Definition at line 571 of file chan_gtalk.c.

References ast_aji_send(), and gtalk::connection.

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

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

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

Definition at line 501 of file chan_gtalk.c.

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

Referenced by gtalk_call().

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

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

Definition at line 1385 of file chan_gtalk.c.

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

Referenced by gtalk_read().

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

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

Definition at line 1566 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

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

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

Definition at line 551 of file chan_gtalk.c.

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

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

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

CLI command "gtalk show channels".

Definition at line 1683 of file chan_gtalk.c.

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

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

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

Definition at line 1256 of file chan_gtalk.c.

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

Referenced by gtalk_add_candidate(), and gtalk_rtp_read().

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

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

Send frame to media channel (rtp).

Definition at line 1425 of file chan_gtalk.c.

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 2033 of file chan_gtalk.c.

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

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

static int reload ( void   )  [static]

Reload module.

Definition at line 2078 of file chan_gtalk.c.

02079 {
02080    return 0;
02081 }

static int unload_module ( void   )  [static]

Unload the gtalk channel from Asterisk.

Definition at line 2084 of file chan_gtalk.c.

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

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


Variable Documentation

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

Definition at line 2119 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 2119 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 76 of file chan_gtalk.c.

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

Definition at line 162 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 233 of file chan_gtalk.c.

Referenced by ast_sip_ouraddrfor(), reload_config(), and sip_show_settings().

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

Definition at line 164 of file chan_gtalk.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 84 of file chan_gtalk.c.

struct ast_cli_entry gtalk_cli[] [static]

Initial value:

 {
   AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"),
   AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
}

Definition at line 228 of file chan_gtalk.c.

struct gtalk_container gtalk_list [static]

struct ast_rtp_protocol gtalk_rtp [static]

RTP driver interface.

Definition at line 221 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 194 of file chan_gtalk.c.

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

Protect the interface list (of gtalk_pvt's)

Definition at line 166 of file chan_gtalk.c.

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

struct io_context* io [static]

The IO context

Definition at line 217 of file chan_gtalk.c.

struct sched_context* sched [static]

The scheduling context

Definition at line 216 of file chan_gtalk.c.


Generated on Thu Oct 11 06:48:14 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6