Wed Oct 28 13:32:01 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_engine.h"
#include "asterisk/stun.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/stringfields.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astobj.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/jabber.h"

Include 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_glue_result gtalk_get_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance **instance)
static int gtalk_handle_dtmf (struct gtalk *client, ikspak *pak)
static int gtalk_hangup (struct ast_channel *ast)
 Hangup a call through the gtalk proxy channel.
static int gtalk_hangup_farend (struct gtalk *client, ikspak *pak)
static int gtalk_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static int gtalk_invite (struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
static int gtalk_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, const char *linkedid)
 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, const struct ast_channel *requestor, void *data, int *cause)
 Part of PBX interface.
static int gtalk_response (struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
static int gtalk_ringing_ack (void *data, ikspak *pak)
static struct ast_framegtalk_rtp_read (struct ast_channel *ast, struct gtalk_pvt *p)
static int gtalk_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int gtalk_sendtext (struct ast_channel *ast, const char *text)
static int gtalk_set_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active)
static char * gtalk_show_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command "gtalk show channels".
static int gtalk_update_stun (struct gtalk *client, struct gtalk_pvt *p)
static int gtalk_write (struct ast_channel *ast, struct ast_frame *frame)
 Send frame to media channel (rtp).
static int load_module (void)
 Load module into PBX, register channel.
static int reload (void)
 Reload module.
static int unload_module (void)
 Unload the gtalk channel from Asterisk.

Variables

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

Referenced by gtalk_load_config(), and load_module().

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

Definition at line 73 of file chan_gtalk.c.

Referenced by gtalk_create_candidates().


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 91 of file chan_gtalk.c.

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

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 86 of file chan_gtalk.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2140 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2140 of file chan_gtalk.c.

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

Definition at line 263 of file chan_gtalk.c.

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

Referenced by gtalk_invite(), and jingle_accept_call().

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

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

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

00232 {
00233    struct gtalk *gtalk = NULL;
00234    char *domain = NULL , *s = NULL;
00235 
00236    if (strchr(connection, '@')) {
00237       s = ast_strdupa(connection);
00238       domain = strsep(&s, "@");
00239       ast_verbose("OOOOH domain = %s\n", domain);
00240    }
00241    gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
00242    if (!gtalk && strchr(name, '@'))
00243       gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
00244 
00245    if (!gtalk) {           
00246       /* guest call */
00247       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
00248          ASTOBJ_RDLOCK(iterator);
00249          if (!strcasecmp(iterator->name, "guest")) {
00250             gtalk = iterator;
00251          }
00252          ASTOBJ_UNLOCK(iterator);
00253 
00254          if (gtalk)
00255             break;
00256       });
00257 
00258    }
00259    return gtalk;
00260 }

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

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

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

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

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

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

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

Definition at line 906 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_codecs_payloads_clear(), ast_rtp_instance_get_codecs(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_RTCP, 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().

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

static int gtalk_answer ( struct ast_channel ast  )  [static]

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

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

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

01615 {
01616    struct gtalk_pvt *p = ast->tech_pvt;
01617 
01618    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01619       ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01620       return -1;
01621    }
01622 
01623    ast_setstate(ast, AST_STATE_RING);
01624    if (!p->ringrule) {
01625       ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01626       p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01627                      IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01628    } else
01629       ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01630 
01631    gtalk_invite(p, p->them, p->us, p->sid, 1);
01632    gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
01633 
01634    return 0;
01635 }

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

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

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

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

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

Referenced by gtalk_load_config().

01864 {
01865    struct aji_client *client;
01866 
01867    if (!member)
01868       ast_log(LOG_WARNING, "Out of memory.\n");
01869 
01870    ast_copy_string(member->name, label, sizeof(member->name));
01871    ast_copy_string(member->user, label, sizeof(member->user));
01872    ast_copy_string(member->context, context, sizeof(member->context));
01873    member->allowguest = allowguest;
01874    member->prefs = prefs;
01875    while (var) {
01876 #if 0
01877       struct gtalk_candidate *candidate = NULL;
01878 #endif
01879       if (!strcasecmp(var->name, "username"))
01880          ast_copy_string(member->user, var->value, sizeof(member->user));
01881       else if (!strcasecmp(var->name, "disallow"))
01882          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
01883       else if (!strcasecmp(var->name, "allow"))
01884          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
01885       else if (!strcasecmp(var->name, "context"))
01886          ast_copy_string(member->context, var->value, sizeof(member->context));
01887       else if (!strcasecmp(var->name, "parkinglot"))
01888          ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
01889 #if 0
01890       else if (!strcasecmp(var->name, "candidate")) {
01891          candidate = gtalk_create_candidate(var->value);
01892          if (candidate) {
01893             candidate->next = member->ourcandidates;
01894             member->ourcandidates = candidate;
01895          }
01896       }
01897 #endif
01898       else if (!strcasecmp(var->name, "connection")) {
01899          if ((client = ast_aji_get_client(var->value))) {
01900             member->connection = client;
01901             iks_filter_add_rule(client->f, gtalk_parser, member, 
01902                       IKS_RULE_TYPE, IKS_PAK_IQ, 
01903                       IKS_RULE_FROM_PARTIAL, member->user,
01904                       IKS_RULE_NS, "http://www.google.com/session",
01905                       IKS_RULE_DONE);
01906 
01907          } else {
01908             ast_log(LOG_ERROR, "connection referenced not found!\n");
01909             return 0;
01910          }
01911       }
01912       var = var->next;
01913    }
01914    if (member->connection && member->user)
01915       member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
01916    else {
01917       ast_log(LOG_ERROR, "No Connection or Username!\n");
01918    }
01919    return 1;
01920 }

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

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

01534 {
01535    struct gtalk_pvt *p = ast->tech_pvt;
01536    struct gtalk *client = p->parent;
01537    iks *iq, *gtalk, *dtmf;
01538    char buffer[2] = {digit, '\0'};
01539    char *lowerthem = NULL;
01540    iq = iks_new("iq");
01541    gtalk = iks_new("gtalk");
01542    dtmf = iks_new("dtmf");
01543    if(!iq || !gtalk || !dtmf) {
01544       iks_delete(iq);
01545       iks_delete(gtalk);
01546       iks_delete(dtmf);
01547       ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01548       return -1;
01549    }
01550 
01551    iks_insert_attrib(iq, "type", "set");
01552    iks_insert_attrib(iq, "to", p->them);
01553    iks_insert_attrib(iq, "from", p->us);
01554    iks_insert_attrib(iq, "id", client->connection->mid);
01555    ast_aji_increment_mid(client->connection->mid);
01556    iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01557    iks_insert_attrib(gtalk, "action", "session-info");
01558    /* put the initiator attribute to lower case if we receive the call 
01559     * otherwise GoogleTalk won't establish the session */
01560    if (!p->initiator) {
01561            char c;
01562            char *t = lowerthem = ast_strdupa(p->them);
01563            while (((c = *t) != '/') && (*t++ = tolower(c)));
01564    }
01565    iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem);
01566    iks_insert_attrib(gtalk, "sid", p->sid);
01567    iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01568    iks_insert_attrib(dtmf, "code", buffer);
01569    iks_insert_node(iq, gtalk);
01570    iks_insert_node(gtalk, dtmf);
01571 
01572    ast_mutex_lock(&p->lock);
01573    if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
01574       iks_insert_attrib(dtmf, "action", "button-down");
01575    } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) {
01576       iks_insert_attrib(dtmf, "action", "button-up");
01577    }
01578    ast_aji_send(client->connection, iq);
01579 
01580    iks_delete(iq);
01581    iks_delete(gtalk);
01582    iks_delete(dtmf);
01583    ast_mutex_unlock(&p->lock);
01584    return 0;
01585 }

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

Definition at line 1523 of file chan_gtalk.c.

References gtalk_digit().

01524 {
01525    return gtalk_digit(chan, digit, 0);
01526 }

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

Definition at line 1528 of file chan_gtalk.c.

References gtalk_digit().

01529 {
01530    return gtalk_digit(chan, digit, duration);
01531 }

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

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

01769 {
01770    switch (cmd) {
01771    case CLI_INIT:
01772       e->command = "gtalk reload";
01773       e->usage =
01774          "Usage: gtalk reload\n"
01775          "       Reload gtalk channel driver.\n";
01776       return NULL;
01777    case CLI_GENERATE:
01778       return NULL;
01779    }  
01780    
01781    ast_verbose("IT DOES WORK!\n");
01782    return CLI_SUCCESS;
01783 }

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

Definition at line 1470 of file chan_gtalk.c.

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

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

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1118 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

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

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

Definition at line 1128 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

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

static int gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 535 of file chan_gtalk.c.

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

00536 {
00537    struct gtalk_pvt *p = chan->tech_pvt;
00538    return p->peercapability;
00539 }

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

Definition at line 516 of file chan_gtalk.c.

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

00517 {
00518    struct gtalk_pvt *p = chan->tech_pvt;
00519    enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
00520 
00521    if (!p)
00522       return res;
00523 
00524    ast_mutex_lock(&p->lock);
00525    if (p->rtp){
00526       ao2_ref(p->rtp, +1);
00527       *instance = p->rtp;
00528       res = AST_RTP_GLUE_RESULT_LOCAL;
00529    }
00530    ast_mutex_unlock(&p->lock);
00531 
00532    return res;
00533 }

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

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

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

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

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

01639 {
01640    struct gtalk_pvt *p = ast->tech_pvt;
01641    struct gtalk *client;
01642 
01643    ast_mutex_lock(&p->lock);
01644    client = p->parent;
01645    p->owner = NULL;
01646    ast->tech_pvt = NULL;
01647    if (!p->alreadygone)
01648       gtalk_action(client, p, "terminate");
01649    ast_mutex_unlock(&p->lock);
01650 
01651    gtalk_free_pvt(client, p);
01652    ast_module_unref(ast_module_info->self);
01653 
01654    return 0;
01655 }

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

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

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

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

Definition at line 1485 of file chan_gtalk.c.

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 600 of file chan_gtalk.c.

References AST_CONTROL_ANSWER, ast_getformatname_multiple(), ast_log(), ast_queue_control(), ast_queue_hangup(), ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), gtalk_pvt::capability, gtalk::connection, gtalk_response(), 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().

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

static int gtalk_load_config ( void   )  [static]

Definition at line 1922 of file chan_gtalk.c.

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

Referenced by load_module().

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

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 226 of file chan_gtalk.c.

References ast_free.

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

00227 {
00228    ast_free(obj);
00229 }

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

Start new gtalk channel.

Definition at line 991 of file chan_gtalk.c.

References accountcode, gtalk::accountcode, ast_channel::adsicpe, ast_channel::amaflags, gtalk::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc, ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), AST_FORMAT_VIDEO_MASK, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_random(), ast_rtp_codecs_packetization_set(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_STUN, AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, ast_channel::cid, ast_callerid::cid_dnid, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_callerid::cid_pres, ast_channel::context, gtalk::context, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_jbconf, ast_channel::hangupcause, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_channel::nativeformats, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, gtalk_pvt::sid, ast_channel::tech, ast_channel::tech_pvt, gtalk_pvt::us, gtalk_pvt::vrtp, and ast_channel::writeformat.

Referenced by gtalk_newcall(), and gtalk_request().

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

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

Definition at line 1156 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_aji_get_client(), ast_channel_release(), ast_copy_string(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, 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().

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

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

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

01786 {
01787    struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01788 
01789    if (iks_find_attrib(pak->x, "type") && !strcmp(iks_find_attrib (pak->x, "type"),"error")) {
01790       ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
01791    }
01792    else if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
01793       /* New call */
01794       gtalk_newcall(client, pak);
01795    } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
01796       ast_debug(3, "About to add candidate!\n");
01797       gtalk_add_candidate(client, pak);
01798       ast_debug(3, "Candidate Added!\n");
01799    } else if (iks_find_with_attrib(pak->x, "session", "type", "accept")) {
01800       gtalk_is_answered(client, pak);
01801    } else if (iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
01802       gtalk_is_accepted(client, pak);
01803    } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
01804       gtalk_handle_dtmf(client, pak);
01805    } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
01806       gtalk_hangup_farend(client, pak);
01807    } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
01808       gtalk_hangup_farend(client, pak);
01809    }
01810    ASTOBJ_UNREF(client, gtalk_member_destroy);
01811    return IKS_FILTER_EAT;
01812 }

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

Definition at line 1415 of file chan_gtalk.c.

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

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

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

Part of PBX interface.

Definition at line 1658 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, ast_channel::linkedid, LOG_ERROR, LOG_WARNING, gtalk::name, s, strsep(), and gtalk::user.

01659 {
01660    struct gtalk_pvt *p = NULL;
01661    struct gtalk *client = NULL;
01662    char *sender = NULL, *to = NULL, *s = NULL;
01663    struct ast_channel *chan = NULL;
01664 
01665    if (data) {
01666       s = ast_strdupa(data);
01667       if (s) {
01668          sender = strsep(&s, "/");
01669          if (sender && (sender[0] != '\0'))
01670             to = strsep(&s, "/");
01671          if (!to) {
01672             ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01673             return NULL;
01674          }
01675       }
01676    }
01677 
01678    client = find_gtalk(to, sender);
01679    if (!client) {
01680       ast_log(LOG_WARNING, "Could not find recipient.\n");
01681       return NULL;
01682    }
01683    if (!strcasecmp(client->name, "guest")){
01684       /* the guest account is not tied to any configured XMPP client,
01685          let's set it now */
01686       client->connection = ast_aji_get_client(sender);
01687       if (!client->connection) {
01688          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01689          ASTOBJ_UNREF(client, gtalk_member_destroy);
01690          return NULL;
01691       }
01692    }
01693        
01694    ASTOBJ_WRLOCK(client);
01695    p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01696    if (p)
01697       chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL);
01698 
01699    ASTOBJ_UNLOCK(client);
01700    return chan;
01701 }

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

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

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

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

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

00491 {
00492    struct gtalk_pvt *p = data;
00493 
00494    if (p->ringrule)
00495       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00496    p->ringrule = NULL;
00497    if (p->owner)
00498       ast_queue_control(p->owner, AST_CONTROL_RINGING);
00499    return IKS_FILTER_EAT;
00500 }

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

Definition at line 1387 of file chan_gtalk.c.

References ast_debug, AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_FRAME_VOICE, ast_null_frame, ast_rtp_instance_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().

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

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

Definition at line 1587 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01588 {
01589    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01590 
01591    return -1;
01592 }

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

Definition at line 1504 of file chan_gtalk.c.

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

01505 {
01506    int res = 0;
01507    struct aji_client *client = NULL;
01508    struct gtalk_pvt *p = chan->tech_pvt;
01509 
01510    if (!p->parent) {
01511       ast_log(LOG_ERROR, "Parent channel not found\n");
01512       return -1;
01513    }
01514    if (!p->parent->connection) {
01515       ast_log(LOG_ERROR, "XMPP client not found\n");
01516       return -1;
01517    }
01518    client = p->parent->connection;
01519    res = ast_aji_send_chat(client, p->them, text);
01520    return res;
01521 }

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

Definition at line 541 of file chan_gtalk.c.

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

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

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

01705 {
01706 #define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
01707    struct gtalk_pvt *p;
01708    struct ast_channel *chan;
01709    int numchans = 0;
01710    char them[AJI_MAX_JIDLEN];
01711    char *jid = NULL;
01712    char *resource = NULL;
01713 
01714    switch (cmd) {
01715    case CLI_INIT:
01716       e->command = "gtalk show channels";
01717       e->usage =
01718          "Usage: gtalk show channels\n"
01719          "       Shows current state of the Gtalk channels.\n";
01720       return NULL;
01721    case CLI_GENERATE:
01722       return NULL;
01723    }
01724 
01725    if (a->argc != 3)
01726       return CLI_SHOWUSAGE;
01727 
01728    ast_mutex_lock(&gtalklock);
01729    ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01730    ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
01731       ASTOBJ_WRLOCK(iterator);
01732       p = iterator->p;
01733       while(p) {
01734          chan = p->owner;
01735          ast_copy_string(them, p->them, sizeof(them));
01736          jid = them;
01737          resource = strchr(them, '/');
01738          if (!resource)
01739             resource = "None";
01740          else {
01741             *resource = '\0';
01742             resource ++;
01743          }
01744          if (chan)
01745             ast_cli(a->fd, FORMAT, 
01746                chan->name,
01747                jid,
01748                resource,
01749                ast_getformatname(chan->readformat),
01750                ast_getformatname(chan->writeformat)               
01751                );
01752          else 
01753             ast_log(LOG_WARNING, "No available channel\n");
01754          numchans ++;
01755          p = p->next;
01756       }
01757       ASTOBJ_UNLOCK(iterator);
01758    });
01759 
01760    ast_mutex_unlock(&gtalklock);
01761 
01762    ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01763    return CLI_SUCCESS;
01764 #undef FORMAT
01765 }

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

Definition at line 1258 of file chan_gtalk.c.

References ast_debug, ast_gethostbyname(), ast_inet_ntoa(), ast_rtp_instance_get_remote_address(), ast_rtp_instance_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().

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

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

Send frame to media channel (rtp).

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

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

static int load_module ( void   )  [static]

Load module into PBX, register channel.

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

02055 {
02056    char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02057    free(jabber_loaded);
02058    if (!jabber_loaded) {
02059       /* If embedded, check for a different module name */
02060       jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02061       free(jabber_loaded);
02062       if (!jabber_loaded) {
02063          ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02064          return AST_MODULE_LOAD_DECLINE;
02065       }
02066    }
02067 
02068    ASTOBJ_CONTAINER_INIT(&gtalk_list);
02069    if (!gtalk_load_config()) {
02070       ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02071       return 0;
02072    }
02073 
02074    sched = sched_context_create();
02075    if (!sched) 
02076       ast_log(LOG_WARNING, "Unable to create schedule context\n");
02077 
02078    io = io_context_create();
02079    if (!io) 
02080       ast_log(LOG_WARNING, "Unable to create I/O context\n");
02081 
02082    if (ast_find_ourip(&__ourip, bindaddr)) {
02083       ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02084       return 0;
02085    }
02086 
02087    ast_rtp_glue_register(&gtalk_rtp_glue);
02088    ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02089 
02090    /* Make sure we can register our channel type */
02091    if (ast_channel_register(&gtalk_tech)) {
02092       ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02093       return -1;
02094    }
02095    return 0;
02096 }

static int reload ( void   )  [static]

Reload module.

Definition at line 2099 of file chan_gtalk.c.

02100 {
02101    return 0;
02102 }

static int unload_module ( void   )  [static]

Unload the gtalk channel from Asterisk.

Definition at line 2105 of file chan_gtalk.c.

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

02106 {
02107    struct gtalk_pvt *privates = NULL;
02108    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02109    /* First, take us out of the channel loop */
02110    ast_channel_unregister(&gtalk_tech);
02111    ast_rtp_glue_unregister(&gtalk_rtp_glue);
02112 
02113    if (!ast_mutex_lock(&gtalklock)) {
02114       /* Hangup all interfaces if they have an owner */
02115       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02116          ASTOBJ_WRLOCK(iterator);
02117          privates = iterator->p;
02118          while(privates) {
02119             if (privates->owner)
02120                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02121             privates = privates->next;
02122          }
02123          iterator->p = NULL;
02124          ASTOBJ_UNLOCK(iterator);
02125       });
02126       ast_mutex_unlock(&gtalklock);
02127    } else {
02128       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02129       return -1;
02130    }
02131    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02132    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02133    return 0;
02134 }


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

struct in_addr __ourip [static]

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

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

Definition at line 162 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 222 of file chan_gtalk.c.

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

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

Definition at line 164 of file chan_gtalk.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 84 of file chan_gtalk.c.

struct ast_cli_entry gtalk_cli[] [static]

Initial value:

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

Definition at line 217 of file chan_gtalk.c.

struct gtalk_container gtalk_list [static]

struct ast_rtp_glue gtalk_rtp_glue [static]

Definition at line 561 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 190 of file chan_gtalk.c.

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

Protect the interface list (of gtalk_pvt's)

Definition at line 166 of file chan_gtalk.c.

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

struct io_context* io [static]

The IO context

Definition at line 214 of file chan_gtalk.c.

struct sched_context* sched [static]

The scheduling context

Definition at line 213 of file chan_gtalk.c.


Generated on Wed Oct 28 13:32:01 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6