Wed Oct 28 11:45:53 2009

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 const struct
ast_module_info
ast_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.


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 90 of file chan_gtalk.c.

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

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 85 of file chan_gtalk.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2102 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2102 of file chan_gtalk.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int gtalk_answer ( struct ast_channel ast  )  [static]

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

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

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 1589 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.

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

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

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

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

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 1836 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::prefs, gtalk::user, and ast_variable::value.

Referenced by gtalk_load_config().

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

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

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

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

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

Definition at line 1498 of file chan_gtalk.c.

References gtalk_digit().

01499 {
01500    return gtalk_digit(chan, digit, 0);
01501 }

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

Definition at line 1503 of file chan_gtalk.c.

References gtalk_digit().

01504 {
01505    return gtalk_digit(chan, digit, duration);
01506 }

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

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

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

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

Definition at line 1464 of file chan_gtalk.c.

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

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

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1112 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

01113 {
01114    struct gtalk_candidate *last;
01115    while (candidate) {
01116       last = candidate;
01117       candidate = candidate->next;
01118       ast_free(last);
01119    }
01120 }

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

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

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

static int gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 543 of file chan_gtalk.c.

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

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

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

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

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

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

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

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

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

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

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

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

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

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

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

Definition at line 1479 of file chan_gtalk.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int gtalk_load_config ( void   )  [static]

Definition at line 1895 of file chan_gtalk.c.

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

Referenced by load_module().

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

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 235 of file chan_gtalk.c.

References ast_free.

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

00236 {
00237    ast_free(obj);
00238 }

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 987 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, 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().

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

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

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

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

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

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

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

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

Definition at line 1409 of file chan_gtalk.c.

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

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

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

Part of PBX interface.

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 1562 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01563 {
01564    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01565 
01566    return -1;
01567 }

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

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

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

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 1679 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.

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

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

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

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

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

Send frame to media channel (rtp).

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

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

static int reload ( void   )  [static]

Reload module.

Definition at line 2061 of file chan_gtalk.c.

02062 {
02063    return 0;
02064 }

static int unload_module ( void   )  [static]

Unload the gtalk channel from Asterisk.

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

02068 {
02069    struct gtalk_pvt *privates = NULL;
02070    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02071    /* First, take us out of the channel loop */
02072    ast_channel_unregister(&gtalk_tech);
02073    ast_rtp_proto_unregister(&gtalk_rtp);
02074 
02075    if (!ast_mutex_lock(&gtalklock)) {
02076       /* Hangup all interfaces if they have an owner */
02077       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02078          ASTOBJ_WRLOCK(iterator);
02079          privates = iterator->p;
02080          while(privates) {
02081             if (privates->owner)
02082                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02083             privates = privates->next;
02084          }
02085          iterator->p = NULL;
02086          ASTOBJ_UNLOCK(iterator);
02087       });
02088       ast_mutex_unlock(&gtalklock);
02089    } else {
02090       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02091       return -1;
02092    }
02093    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02094    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02095    return 0;
02096 }


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

struct in_addr __ourip [static]

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2102 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]

char externip[16] [static]

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

struct ast_jb_conf global_jbconf [static]

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

struct gtalk_container gtalk_list [static]

struct ast_rtp_protocol gtalk_rtp [static]

RTP driver interface.

Definition at line 219 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 192 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 164 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 215 of file chan_gtalk.c.

struct sched_context* sched [static]

The scheduling context

Definition at line 214 of file chan_gtalk.c.


Generated on Wed Oct 28 11:45:53 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6