Wed Apr 6 11:29:55 2011

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 "asterisk/jingle.h"

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"

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_begin (struct ast_channel *ast, char digit)
static int gtalk_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
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 format_t gtalk_get_codec (struct ast_channel *chan)
static int gtalk_get_local_ip (struct ast_sockaddr *ourip)
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_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)
 CLI command "gtalk reload".
static struct ast_framegtalk_read (struct ast_channel *ast)
static struct ast_channelgtalk_request (const char *type, format_t 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, format_t 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_externip (void)
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 unload_module (void)
 Reload module Unload the gtalk channel from Asterisk.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, }
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 format_t 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 = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP }
static struct io_contextio
static struct sched_contextsched
static struct sockaddr_in stunaddr


Detailed Description

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

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

Philippe Sultan <philippe.sultan@gmail.com>

********** General TODO:s
Todo:
Support config reloading.

Fix native bridging.

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

Referenced by gtalk_load_config(), and load_module().


Enumeration Type Documentation

enum gtalk_connect_type

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 97 of file chan_gtalk.c.

00097                         {
00098    AJI_CONNECT_STUN = 1,
00099    AJI_CONNECT_LOCAL = 2,
00100    AJI_CONNECT_RELAY = 3,
00101 };

enum gtalk_protocol

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 92 of file chan_gtalk.c.

00092                     {
00093    AJI_PROTOCOL_UDP = 1,
00094    AJI_PROTOCOL_SSLTCP = 2,
00095 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2276 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2276 of file chan_gtalk.c.

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

Definition at line 277 of file chan_gtalk.c.

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

Referenced by gtalk_invite(), and jingle_accept_call().

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

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

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

Referenced by gtalk_request().

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

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

Definition at line 1163 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

01164 {
01165    iks *request, *session = NULL;
01166    int res = -1;
01167    char *lowerthem = NULL;
01168 
01169    request = iks_new("iq");
01170    if (request) {
01171       iks_insert_attrib(request, "type", "set");
01172       iks_insert_attrib(request, "from", p->us);
01173       iks_insert_attrib(request, "to", p->them);
01174       iks_insert_attrib(request, "id", client->connection->mid);
01175       ast_aji_increment_mid(client->connection->mid);
01176       session = iks_new("session");
01177       if (session) {
01178          iks_insert_attrib(session, "type", action);
01179          iks_insert_attrib(session, "id", p->sid);
01180          /* put the initiator attribute to lower case if we receive the call
01181           * otherwise GoogleTalk won't establish the session */
01182          if (!p->initiator) {
01183                  char c;
01184             char *t = lowerthem = ast_strdupa(p->them);
01185             while (((c = *t) != '/') && (*t++ = tolower(c)));
01186          }
01187          iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01188          iks_insert_attrib(session, "xmlns", GOOGLE_NS);
01189          iks_insert_node(request, session);
01190          ast_aji_send(client->connection, request);
01191          res = 0;
01192       }
01193    }
01194 
01195    iks_delete(session);
01196    iks_delete(request);
01197 
01198    return res;
01199 }

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

Definition at line 1465 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_update_stun(), aji_client::jid, gtalk_pvt::laststun, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_candidate::receipt, S_OR, and gtalk_pvt::theircandidates.

Referenced by gtalk_parser().

01466 {
01467    struct gtalk_pvt *p = NULL, *tmp = NULL;
01468    struct aji_client *c = client->connection;
01469    struct gtalk_candidate *newcandidate = NULL;
01470    iks *traversenodes = NULL, *receipt = NULL;
01471    char *from;
01472 
01473    from = iks_find_attrib(pak->x,"to");
01474    if (!from) {
01475       from = c->jid->full;
01476    }
01477 
01478    for (tmp = client->p; tmp; tmp = tmp->next) {
01479       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01480          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01481          p = tmp;
01482          break;
01483       }
01484    }
01485 
01486    if (!p) {
01487       return -1;
01488    }
01489    traversenodes = pak->query;
01490    while(traversenodes) {
01491       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
01492          traversenodes = iks_first_tag(traversenodes);
01493          continue;
01494       }
01495       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
01496          traversenodes = iks_child(traversenodes);
01497          continue;
01498       }
01499       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
01500          newcandidate = ast_calloc(1, sizeof(*newcandidate));
01501          if (!newcandidate)
01502             return 0;
01503          ast_copy_string(newcandidate->name,
01504             S_OR(iks_find_attrib(traversenodes, "name"), ""),
01505             sizeof(newcandidate->name));
01506          ast_copy_string(newcandidate->ip,
01507             S_OR(iks_find_attrib(traversenodes, "address"), ""),
01508             sizeof(newcandidate->ip));
01509          newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01510          ast_copy_string(newcandidate->username,
01511             S_OR(iks_find_attrib(traversenodes, "username"), ""),
01512             sizeof(newcandidate->username));
01513          ast_copy_string(newcandidate->password,
01514             S_OR(iks_find_attrib(traversenodes, "password"), ""),
01515             sizeof(newcandidate->password));
01516          newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01517          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
01518             newcandidate->protocol = AJI_PROTOCOL_UDP;
01519          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
01520             newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01521 
01522          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
01523             newcandidate->type = AJI_CONNECT_STUN;
01524          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
01525             newcandidate->type = AJI_CONNECT_LOCAL;
01526          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
01527             newcandidate->type = AJI_CONNECT_RELAY;
01528          ast_copy_string(newcandidate->network,
01529             S_OR(iks_find_attrib(traversenodes, "network"), ""),
01530             sizeof(newcandidate->network));
01531          newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
01532          newcandidate->next = NULL;
01533 
01534          newcandidate->next = p->theircandidates;
01535          p->theircandidates = newcandidate;
01536          p->laststun = 0;
01537          gtalk_update_stun(p->parent, p);
01538          newcandidate = NULL;
01539       }
01540       traversenodes = iks_next_tag(traversenodes);
01541    }
01542 
01543    receipt = iks_new("iq");
01544    iks_insert_attrib(receipt, "type", "result");
01545    iks_insert_attrib(receipt, "from", from);
01546    iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
01547    iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
01548    ast_aji_send(c, receipt);
01549 
01550    iks_delete(receipt);
01551 
01552    return 1;
01553 }

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

Definition at line 975 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_DTMF_MODE_RFC2833, ast_rtp_instance_dtmf_mode_set(), ast_rtp_instance_get_codecs(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_DTMF, AST_RTP_PROPERTY_RTCP, AST_RTP_PROPERTY_STUN, ast_sockaddr_from_sin, ast_strdupa, ASTOBJ_CONTAINER_FIND, bindaddr, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk::capability, gtalk::connection, exten, global_capability, gtalklock, aji_version::jingle, LOG_ERROR, LOG_WARNING, gtalk::name, aji_resource::next, gtalk::p, gtalk::prefs, aji_resource::resource, aji_buddy::resources, and strsep().

Referenced by gtalk_newcall(), and gtalk_request().

00976 {
00977    struct gtalk_pvt *tmp = NULL;
00978    struct aji_resource *resources = NULL;
00979    struct aji_buddy *buddy;
00980    char idroster[200];
00981    char *data, *exten = NULL;
00982    struct ast_sockaddr bindaddr_tmp;
00983 
00984    ast_debug(1, "The client is %s for alloc\n", client->name);
00985    if (!sid && !strchr(them, '/')) {   /* I started call! */
00986       if (!strcasecmp(client->name, "guest")) {
00987          buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00988          if (buddy) {
00989             resources = buddy->resources;
00990          }
00991       } else if (client->buddy) {
00992          resources = client->buddy->resources;
00993       }
00994 
00995       while (resources) {
00996          if (resources->cap->jingle) {
00997             break;
00998          }
00999          resources = resources->next;
01000       }
01001       if (resources) {
01002          snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
01003       } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
01004          snprintf(idroster, sizeof(idroster), "%s", them);
01005       } else {
01006          ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
01007          return NULL;
01008       }
01009    }
01010    if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
01011       return NULL;
01012    }
01013 
01014    memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
01015 
01016    if (sid) {
01017       ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
01018       ast_copy_string(tmp->them, them, sizeof(tmp->them));
01019       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01020    } else {
01021       snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
01022       ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
01023       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01024       tmp->initiator = 1;
01025    }
01026    /* clear codecs */
01027    bindaddr.sin_family = AF_INET;
01028    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
01029    if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
01030      ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
01031      ast_free(tmp);
01032      return NULL;
01033    }
01034    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
01035    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
01036    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
01037    ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
01038    ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
01039 
01040    /* add user configured codec capabilites */
01041    if (client->capability) {
01042       tmp->capability = client->capability;
01043    } else if (global_capability) {
01044       tmp->capability = global_capability;
01045    }
01046 
01047    tmp->parent = client;
01048    if (!tmp->rtp) {
01049       ast_log(LOG_WARNING, "Out of RTP sessions?\n");
01050       ast_free(tmp);
01051       return NULL;
01052    }
01053 
01054    /* Set CALLERID(name) to the full JID of the remote peer */
01055    ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
01056 
01057    if(strchr(tmp->us, '/')) {
01058       data = ast_strdupa(tmp->us);
01059       exten = strsep(&data, "/");
01060    } else {
01061       exten = tmp->us;
01062    }
01063    ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
01064    ast_mutex_init(&tmp->lock);
01065    ast_mutex_lock(&gtalklock);
01066    tmp->next = client->p;
01067    client->p = tmp;
01068    ast_mutex_unlock(&gtalklock);
01069    return tmp;
01070 }

static int gtalk_answer ( struct ast_channel ast  )  [static]

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

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

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 1795 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_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.

01796 {
01797    struct gtalk_pvt *p = ast->tech_pvt;
01798 
01799    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01800       ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01801       return -1;
01802    }
01803 
01804    ast_setstate(ast, AST_STATE_RING);
01805    if (!p->ringrule) {
01806       ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01807       p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01808                      IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01809    } else {
01810       ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01811    }
01812 
01813    gtalk_invite(p, p->them, p->us, p->sid, 1);
01814 
01815    return 0;
01816 }

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

Definition at line 838 of file chan_gtalk.c.

References 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_free, ast_log(), ast_random(), ast_rtp_instance_get_local_address(), ast_sockaddr_stringify_addr(), ast_sockaddr_to_sin, ast_strdupa, ast_strlen_zero(), gtalk::connection, externip, GOOGLE_NS, GOOGLE_TRANSPORT_NS, gtalk_get_local_ip(), gtalk_update_externip(), 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_newcall(), and gtalk_ringing_ack().

00839 {
00840    struct gtalk_candidate *tmp;
00841    struct aji_client *c = client->connection;
00842    struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00843    struct sockaddr_in sin = { 0, };
00844    struct ast_sockaddr sin_tmp;
00845    struct ast_sockaddr us;
00846    iks *iq, *gtalk, *candidate, *transport;
00847    char user[17], pass[17], preference[5], port[7];
00848    char *lowerfrom = NULL;
00849 
00850    iq = iks_new("iq");
00851    gtalk = iks_new("session");
00852    candidate = iks_new("candidate");
00853    transport = iks_new("transport");
00854    if (!iq || !gtalk || !candidate || !transport) {
00855       ast_log(LOG_ERROR, "Memory allocation error\n");
00856       goto safeout;
00857    }
00858    ours1 = ast_calloc(1, sizeof(*ours1));
00859    ours2 = ast_calloc(1, sizeof(*ours2));
00860    if (!ours1 || !ours2)
00861       goto safeout;
00862 
00863    iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
00864    iks_insert_node(iq, gtalk);
00865    iks_insert_node(gtalk,candidate);
00866    iks_insert_node(gtalk,transport);
00867 
00868    for (; p; p = p->next) {
00869       if (!strcasecmp(p->sid, sid))
00870          break;
00871    }
00872 
00873    if (!p) {
00874       ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00875       goto safeout;
00876    }
00877 
00878    ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
00879    ast_sockaddr_to_sin(&sin_tmp, &sin);
00880 
00881    gtalk_get_local_ip(&us);
00882 
00883    if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
00884       ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
00885    }
00886 
00887    /* Setup our gtalk candidates */
00888    ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00889    ours1->port = ntohs(sin.sin_port);
00890    ours1->preference = 1;
00891    snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00892    snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00893    ast_copy_string(ours1->username, user, sizeof(ours1->username));
00894    ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00895    ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
00896          sizeof(ours1->ip));
00897    ours1->protocol = AJI_PROTOCOL_UDP;
00898    ours1->type = AJI_CONNECT_LOCAL;
00899    ours1->generation = 0;
00900    p->ourcandidates = ours1;
00901 
00902    /* XXX this is a blocking action.  We send a STUN request to the server
00903     * and wait for the response.  If blocking here is a problem the STUN requests/responses
00904     * for the externip may need to be done differently. */
00905    gtalk_update_externip();
00906    if (!ast_strlen_zero(externip)) {
00907       ast_copy_string(ours2->username, user, sizeof(ours2->username));
00908       ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00909       ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00910       ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00911       ours2->port = ntohs(sin.sin_port);
00912       ours2->preference = 0.9;
00913       ours2->protocol = AJI_PROTOCOL_UDP;
00914       ours2->type = AJI_CONNECT_STUN;
00915       ours2->generation = 0;
00916       ours1->next = ours2;
00917       ours2 = NULL;
00918    }
00919    ours1 = NULL;
00920 
00921    for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00922       snprintf(port, sizeof(port), "%d", tmp->port);
00923       snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00924       iks_insert_attrib(iq, "from", to);
00925       iks_insert_attrib(iq, "to", from);
00926       iks_insert_attrib(iq, "type", "set");
00927       iks_insert_attrib(iq, "id", c->mid);
00928       ast_aji_increment_mid(c->mid);
00929       iks_insert_attrib(gtalk, "type", "candidates");
00930       iks_insert_attrib(gtalk, "id", sid);
00931       /* put the initiator attribute to lower case if we receive the call
00932        * otherwise GoogleTalk won't establish the session */
00933       if (!p->initiator) {
00934               char c;
00935          char *t = lowerfrom = ast_strdupa(from);
00936          while (((c = *t) != '/') && (*t++ = tolower(c)));
00937       }
00938       iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
00939       iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00940       iks_insert_attrib(candidate, "name", tmp->name);
00941       iks_insert_attrib(candidate, "address", tmp->ip);
00942       iks_insert_attrib(candidate, "port", port);
00943       iks_insert_attrib(candidate, "username", tmp->username);
00944       iks_insert_attrib(candidate, "password", tmp->password);
00945       iks_insert_attrib(candidate, "preference", preference);
00946       if (tmp->protocol == AJI_PROTOCOL_UDP)
00947          iks_insert_attrib(candidate, "protocol", "udp");
00948       if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00949          iks_insert_attrib(candidate, "protocol", "ssltcp");
00950       if (tmp->type == AJI_CONNECT_STUN)
00951          iks_insert_attrib(candidate, "type", "stun");
00952       if (tmp->type == AJI_CONNECT_LOCAL)
00953          iks_insert_attrib(candidate, "type", "local");
00954       if (tmp->type == AJI_CONNECT_RELAY)
00955          iks_insert_attrib(candidate, "type", "relay");
00956       iks_insert_attrib(candidate, "network", "0");
00957       iks_insert_attrib(candidate, "generation", "0");
00958       ast_aji_send(c, iq);
00959    }
00960    p->laststun = 0;
00961 
00962 safeout:
00963    if (ours1)
00964       ast_free(ours1);
00965    if (ours2)
00966       ast_free(ours2);
00967    iks_delete(iq);
00968    iks_delete(gtalk);
00969    iks_delete(candidate);
00970    iks_delete(transport);
00971 
00972    return 1;
00973 }

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 2008 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, GOOGLE_NS, gtalk_parser(), LOG_ERROR, LOG_WARNING, gtalk::name, gtalk::parkinglot, prefs, gtalk::prefs, gtalk::user, and var.

02011 {
02012    struct aji_client *client;
02013 
02014    if (!member)
02015       ast_log(LOG_WARNING, "Out of memory.\n");
02016 
02017    ast_copy_string(member->name, label, sizeof(member->name));
02018    ast_copy_string(member->user, label, sizeof(member->user));
02019    ast_copy_string(member->context, context, sizeof(member->context));
02020    member->allowguest = allowguest;
02021    member->prefs = prefs;
02022    while (var) {
02023       if (!strcasecmp(var->name, "username"))
02024          ast_copy_string(member->user, var->value, sizeof(member->user));
02025       else if (!strcasecmp(var->name, "disallow"))
02026          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
02027       else if (!strcasecmp(var->name, "allow"))
02028          ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
02029       else if (!strcasecmp(var->name, "context"))
02030          ast_copy_string(member->context, var->value, sizeof(member->context));
02031       else if (!strcasecmp(var->name, "parkinglot"))
02032          ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
02033       else if (!strcasecmp(var->name, "connection")) {
02034          if ((client = ast_aji_get_client(var->value))) {
02035             member->connection = client;
02036             iks_filter_add_rule(client->f, gtalk_parser, member,
02037                       IKS_RULE_TYPE, IKS_PAK_IQ,
02038                       IKS_RULE_FROM_PARTIAL, member->user,
02039                       IKS_RULE_NS, GOOGLE_NS,
02040                       IKS_RULE_DONE);
02041          } else {
02042             ast_log(LOG_ERROR, "connection referenced not found!\n");
02043             return 0;
02044          }
02045       }
02046       var = var->next;
02047    }
02048    if (member->connection && member->user)
02049       member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
02050    else {
02051       ast_log(LOG_ERROR, "No Connection or Username!\n");
02052    }
02053    return 1;
02054 }

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

Definition at line 1695 of file chan_gtalk.c.

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

01696 {
01697    struct gtalk_pvt *p = chan->tech_pvt;
01698    int res = 0;
01699 
01700    ast_mutex_lock(&p->lock);
01701    if (p->rtp) {
01702       ast_rtp_instance_dtmf_begin(p->rtp, digit);
01703    } else {
01704       res = -1;
01705    }
01706    ast_mutex_unlock(&p->lock);
01707 
01708    return res;
01709 }

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

Definition at line 1711 of file chan_gtalk.c.

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

01712 {
01713    struct gtalk_pvt *p = chan->tech_pvt;
01714    int res = 0;
01715 
01716    ast_mutex_lock(&p->lock);
01717    if (p->rtp) {
01718       ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
01719    } else {
01720       res = -1;
01721    }
01722    ast_mutex_unlock(&p->lock);
01723 
01724    return res;
01725 }

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

Definition at line 1642 of file chan_gtalk.c.

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

01643 {
01644    struct gtalk_pvt *p = newchan->tech_pvt;
01645    ast_mutex_lock(&p->lock);
01646 
01647    if ((p->owner != oldchan)) {
01648       ast_mutex_unlock(&p->lock);
01649       return -1;
01650    }
01651    if (p->owner == oldchan)
01652       p->owner = newchan;
01653    ast_mutex_unlock(&p->lock);
01654    return 0;
01655 }

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1201 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt().

01202 {
01203    struct gtalk_candidate *last;
01204    while (candidate) {
01205       last = candidate;
01206       candidate = candidate->next;
01207       ast_free(last);
01208    }
01209 }

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

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

01212 {
01213    struct gtalk_pvt *cur, *prev = NULL;
01214    cur = client->p;
01215    while (cur) {
01216       if (cur == p) {
01217          if (prev)
01218             prev->next = p->next;
01219          else
01220             client->p = p->next;
01221          break;
01222       }
01223       prev = cur;
01224       cur = cur->next;
01225    }
01226    if (p->ringrule)
01227       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01228    if (p->owner)
01229       ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01230    if (p->rtp)
01231       ast_rtp_instance_destroy(p->rtp);
01232    if (p->vrtp)
01233       ast_rtp_instance_destroy(p->vrtp);
01234    gtalk_free_candidates(p->theircandidates);
01235    ast_free(p);
01236 }

static format_t gtalk_get_codec ( struct ast_channel chan  )  [static]

Definition at line 539 of file chan_gtalk.c.

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

00540 {
00541    struct gtalk_pvt *p = chan->tech_pvt;
00542    return p->peercapability;
00543 }

static int gtalk_get_local_ip ( struct ast_sockaddr ourip  )  [static]

Definition at line 810 of file chan_gtalk.c.

References ast_find_ourip(), ast_free, ast_ouraddrfor(), ast_sockaddr_copy(), ast_sockaddr_from_sin, ast_sockaddr_is_any(), ast_sockaddr_resolve(), bindaddr, and PARSE_PORT_FORBID.

Referenced by gtalk_create_candidates(), and load_module().

00811 {
00812    struct ast_sockaddr root;
00813    struct ast_sockaddr bindaddr_tmp;
00814    struct ast_sockaddr *addrs;
00815    int addrs_cnt;
00816 
00817    /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
00818    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
00819    if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
00820       ast_sockaddr_copy(ourip, &bindaddr_tmp);
00821       return 0;
00822    }
00823 
00824    /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
00825     * If you can't resolve google.com from your network, then this module is useless for you anyway. */
00826    if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
00827       ast_sockaddr_copy(&root, &addrs[0]);
00828       ast_free(addrs);
00829       if (!ast_ouraddrfor(&root, ourip)) {
00830          return 0;
00831       }
00832    }
00833 
00834    /* As a last resort, use this function to find our local address. */
00835    return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
00836 }

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

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

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

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

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

Referenced by gtalk_parser().

00712 {
00713    struct gtalk_pvt *tmp;
00714    iks *dtmfnode = NULL, *dtmfchild = NULL;
00715    char *dtmf;
00716    char *from;
00717    /* Make sure our new call doesn't exist yet */
00718    for (tmp = client->p; tmp; tmp = tmp->next) {
00719       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00720          break;
00721    }
00722    from = iks_find_attrib(pak->x, "to");
00723    if (!from) {
00724       from = client->connection->jid->full;
00725    }
00726 
00727    if (tmp) {
00728       if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00729          gtalk_response(client, from, pak,
00730                "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00731                "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00732          return -1;
00733       }
00734       if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00735          if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00736             if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00737                struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00738                f.subclass.integer = dtmf[0];
00739                ast_queue_frame(tmp->owner, &f);
00740                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00741             } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00742                struct ast_frame f = {AST_FRAME_DTMF_END, };
00743                f.subclass.integer = dtmf[0];
00744                ast_queue_frame(tmp->owner, &f);
00745                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00746             } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
00747                struct ast_frame f = {AST_FRAME_DTMF, };
00748                f.subclass.integer = dtmf[0];
00749                ast_queue_frame(tmp->owner, &f);
00750                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00751             }
00752          }
00753       } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00754          if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00755             if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00756                if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00757                   struct ast_frame f = {AST_FRAME_DTMF_END, };
00758                   f.subclass.integer = dtmf[0];
00759                   ast_queue_frame(tmp->owner, &f);
00760                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00761                } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00762                   struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00763                   f.subclass.integer = dtmf[0];
00764                   ast_queue_frame(tmp->owner, &f);
00765                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00766                }
00767             }
00768          }
00769       }
00770       gtalk_response(client, from, pak, NULL, NULL);
00771       return 1;
00772    } else {
00773       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00774    }
00775 
00776    gtalk_response(client, from, pak, NULL, NULL);
00777    return 1;
00778 }

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1819 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::p, gtalk_pvt::parent, and ast_channel::tech_pvt.

Referenced by gtalk_newcall().

01820 {
01821    struct gtalk_pvt *p = ast->tech_pvt;
01822    struct gtalk *client;
01823 
01824    ast_mutex_lock(&p->lock);
01825    client = p->parent;
01826    p->owner = NULL;
01827    ast->tech_pvt = NULL;
01828    if (!p->alreadygone) {
01829       gtalk_action(client, p, "terminate");
01830    }
01831    ast_mutex_unlock(&p->lock);
01832 
01833    gtalk_free_pvt(client, p);
01834    ast_module_unref(ast_module_info->self);
01835 
01836    return 0;
01837 }

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

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

00781 {
00782    struct gtalk_pvt *tmp;
00783    char *from;
00784 
00785    ast_debug(1, "The client is %s\n", client->name);
00786    /* Make sure our new call doesn't exist yet */
00787    for (tmp = client->p; tmp; tmp = tmp->next) {
00788       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
00789          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
00790          break;
00791       }
00792    }
00793    from = iks_find_attrib(pak->x, "to");
00794    if (!from) {
00795       from = client->connection->jid->full;
00796    }
00797 
00798    if (tmp) {
00799       tmp->alreadygone = 1;
00800       if (tmp->owner) {
00801          ast_queue_hangup(tmp->owner);
00802       }
00803    } else {
00804       ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
00805    }
00806    gtalk_response(client, from, pak, NULL, NULL);
00807    return 1;
00808 }

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

Definition at line 1657 of file chan_gtalk.c.

References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, ast_moh_start(), and ast_moh_stop().

01658 {
01659    int res = 0;
01660 
01661    switch (condition) {
01662    case AST_CONTROL_HOLD:
01663       ast_moh_start(ast, data, NULL);
01664       break;
01665    case AST_CONTROL_UNHOLD:
01666       ast_moh_stop(ast);
01667       break;
01668    default:
01669       ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
01670       res = -1;
01671    }
01672 
01673    return res;
01674 }

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

Definition at line 382 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, GOOGLE_AUDIO_NS, GOOGLE_NS, GOOGLE_TRANSPORT_NS, LOG_ERROR, aji_client::mid, gtalk::p, gtalk_pvt::parent, and gtalk::prefs.

Referenced by gtalk_answer(), gtalk_call(), and gtalk_ringing_ack().

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

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

Definition at line 682 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

00683 {
00684    struct gtalk_pvt *tmp;
00685    char *from;
00686 
00687    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00688    /* find corresponding call */
00689    for (tmp = client->p; tmp; tmp = tmp->next) {
00690       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00691          break;
00692       }
00693    }
00694 
00695    from = iks_find_attrib(pak->x, "to");
00696    if (!from) {
00697       from = client->connection->jid->full;
00698    }
00699 
00700    if (tmp) {
00701       gtalk_update_stun(tmp->parent, tmp);
00702    } else {
00703       ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
00704    }
00705 
00706    /* answer 'iq' packet to let the remote peer know that we're alive */
00707    gtalk_response(client, from, pak, NULL, NULL);
00708    return 1;
00709 }

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

Definition at line 604 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(), gtalk_update_stun(), aji_client::jid, gtalk_pvt::jointcapability, LOG_DEBUG, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercapability, gtalk_pvt::rtp, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00605 {
00606    struct gtalk_pvt *tmp = NULL;
00607    char *from;
00608    iks *codec;
00609    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00610    int peernoncodeccapability;
00611 
00612    ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00613 
00614    /* Make sure our new call does exist */
00615    for (tmp = client->p; tmp; tmp = tmp->next) {
00616       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00617          break;
00618       } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
00619          break;
00620       }
00621    }
00622 
00623    if (!tmp) {
00624       ast_log(LOG_WARNING, "Could not find session in iq\n");
00625       return -1;
00626    }
00627 
00628    /* codec points to the first <payload-type/> tag */
00629    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00630    while (codec) {
00631       char *codec_id = iks_find_attrib(codec, "id");
00632       char *codec_name = iks_find_attrib(codec, "name");
00633       if (!codec_id || !codec_name) {
00634          codec = iks_next_tag(codec);
00635          continue;
00636       }
00637 
00638       ast_rtp_codecs_payloads_set_m_type(
00639          ast_rtp_instance_get_codecs(tmp->rtp),
00640          tmp->rtp,
00641          atoi(codec_id));
00642       ast_rtp_codecs_payloads_set_rtpmap_type(
00643          ast_rtp_instance_get_codecs(tmp->rtp),
00644          tmp->rtp,
00645          atoi(codec_id),
00646          "audio",
00647          codec_name,
00648          0);
00649       codec = iks_next_tag(codec);
00650    }
00651 
00652    /* Now gather all of the codecs that we are asked for */
00653    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability);
00654 
00655    /* at this point, we received an awser from the remote Gtalk client,
00656       which allows us to compare capabilities */
00657    tmp->jointcapability = tmp->capability & tmp->peercapability;
00658    if (!tmp->jointcapability) {
00659       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
00660          ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
00661          ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
00662       /* close session if capabilities don't match */
00663       ast_queue_hangup(tmp->owner);
00664 
00665       return -1;
00666 
00667    }
00668 
00669    from = iks_find_attrib(pak->x, "to");
00670    if (!from) {
00671       from = client->connection->jid->full;
00672    }
00673 
00674    if (tmp->owner) {
00675       ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00676    }
00677    gtalk_update_stun(tmp->parent, tmp);
00678    gtalk_response(client, from, pak, NULL, NULL);
00679    return 1;
00680 }

static int gtalk_load_config ( void   )  [static]

Definition at line 2056 of file chan_gtalk.c.

References ahp, ast_category_browse(), ast_config_load, ast_jb_read_conf(), ast_log(), AST_MAX_CONTEXT, ast_parse_allow_disallow(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clients, config_flags, CONFIG_STATUS_FILEINVALID, context, default_jbconf, global_capability, global_jbconf, GOOGLE_CONFIG, hp, LOG_ERROR, parkinglot, prefs, stunaddr, and var.

Referenced by load_module().

02057 {
02058    char *cat = NULL;
02059    struct ast_config *cfg = NULL;
02060    char context[AST_MAX_CONTEXT];
02061    char parkinglot[AST_MAX_CONTEXT];
02062    int allowguest = 1;
02063    struct ast_variable *var;
02064    struct gtalk *member;
02065    struct ast_codec_pref prefs;
02066    struct aji_client_container *clients;
02067    struct gtalk_candidate *global_candidates = NULL;
02068    struct hostent *hp;
02069    struct ast_hostent ahp;
02070    struct ast_flags config_flags = { 0 };
02071 
02072    cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
02073    if (!cfg) {
02074       return 0;
02075    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02076       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", GOOGLE_CONFIG);
02077       return 0;
02078    }
02079 
02080    /* Copy the default jb config over global_jbconf */
02081    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02082 
02083    /* set defaults */
02084    memset(&stunaddr, 0, sizeof(stunaddr));
02085 
02086    cat = ast_category_browse(cfg, NULL);
02087    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02088       /* handle jb conf */
02089       if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
02090          continue;
02091 
02092       if (!strcasecmp(var->name, "allowguest")) {
02093          allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
02094       } else if (!strcasecmp(var->name, "disallow")) {
02095          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
02096       } else if (!strcasecmp(var->name, "allow")) {
02097          ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
02098       } else if (!strcasecmp(var->name, "context")) {
02099          ast_copy_string(context, var->value, sizeof(context));
02100       } else if (!strcasecmp(var->name, "externip")) {
02101          ast_copy_string(externip, var->value, sizeof(externip));
02102       } else if (!strcasecmp(var->name, "parkinglot")) {
02103          ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
02104       } else if (!strcasecmp(var->name, "bindaddr")) {
02105          if (!(hp = ast_gethostbyname(var->value, &ahp))) {
02106             ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
02107          } else {
02108             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
02109          }
02110       } else if (!strcasecmp(var->name, "stunaddr")) {
02111          stunaddr.sin_port = htons(STANDARD_STUN_PORT);
02112          if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
02113             ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
02114          }
02115       }
02116    }
02117    while (cat) {
02118       if (strcasecmp(cat, "general")) {
02119          var = ast_variable_browse(cfg, cat);
02120          member = ast_calloc(1, sizeof(*member));
02121          ASTOBJ_INIT(member);
02122          ASTOBJ_WRLOCK(member);
02123          if (!strcasecmp(cat, "guest")) {
02124             ast_copy_string(member->name, "guest", sizeof(member->name));
02125             ast_copy_string(member->user, "guest", sizeof(member->user));
02126             ast_copy_string(member->context, context, sizeof(member->context));
02127             ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
02128             member->allowguest = allowguest;
02129             member->prefs = prefs;
02130             while (var) {
02131                if (!strcasecmp(var->name, "disallow")) {
02132                   ast_parse_allow_disallow(&member->prefs, &member->capability,
02133                                      var->value, 0);
02134                } else if (!strcasecmp(var->name, "allow")) {
02135                   ast_parse_allow_disallow(&member->prefs, &member->capability,
02136                                      var->value, 1);
02137                } else if (!strcasecmp(var->name, "context")) {
02138                   ast_copy_string(member->context, var->value,
02139                               sizeof(member->context));
02140                } else if (!strcasecmp(var->name, "parkinglot")) {
02141                   ast_copy_string(member->parkinglot, var->value,
02142                               sizeof(member->parkinglot));
02143                }
02144                var = var->next;
02145             }
02146             ASTOBJ_UNLOCK(member);
02147             clients = ast_aji_get_clients();
02148             if (clients) {
02149                ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02150                   ASTOBJ_WRLOCK(iterator);
02151                   ASTOBJ_WRLOCK(member);
02152                   member->connection = NULL;
02153                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
02154                   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);
02155                   ASTOBJ_UNLOCK(member);
02156                   ASTOBJ_UNLOCK(iterator);
02157                });
02158                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02159                ASTOBJ_UNREF(member, gtalk_member_destroy);
02160             } else {
02161                ASTOBJ_UNLOCK(member);
02162                ASTOBJ_UNREF(member, gtalk_member_destroy);
02163             }
02164          } else {
02165             ASTOBJ_UNLOCK(member);
02166             if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
02167                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02168             ASTOBJ_UNREF(member, gtalk_member_destroy);
02169          }
02170       }
02171       cat = ast_category_browse(cfg, cat);
02172    }
02173 
02174    gtalk_update_externip();
02175    gtalk_free_candidates(global_candidates);
02176    return 1;
02177 }

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 240 of file chan_gtalk.c.

References ast_free.

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

00241 {
00242    ast_free(obj);
00243 }

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

Start new gtalk channel.

Definition at line 1073 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_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::caller, gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_channel::context, gtalk::context, ast_channel::dialed, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_capability, global_jbconf, gtalk_tech, ast_channel::hangupcause, ast_party_caller::id, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_party_id::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_party_number::presentation, ast_party_name::presentation, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, gtalk_pvt::sid, ast_party_dialed::str, ast_channel::tech, ast_channel::tech_pvt, gtalk_pvt::us, gtalk_pvt::vrtp, and ast_channel::writeformat.

Referenced by gtalk_newcall(), and gtalk_request().

01074 {
01075    struct ast_channel *tmp;
01076    int fmt;
01077    int what;
01078    const char *n2;
01079 
01080    if (title)
01081       n2 = title;
01082    else
01083       n2 = i->us;
01084    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);
01085    if (!tmp) {
01086       ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01087       return NULL;
01088    }
01089    tmp->tech = &gtalk_tech;
01090 
01091    /* Select our native format based on codec preference until we receive
01092       something from another device to the contrary. */
01093    if (i->jointcapability)
01094       what = i->jointcapability;
01095    else if (i->capability)
01096       what = i->capability;
01097    else
01098       what = global_capability;
01099 
01100    /* Set Frame packetization */
01101    if (i->rtp) {
01102       ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
01103    }
01104 
01105    tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
01106    fmt = ast_best_codec(tmp->nativeformats);
01107 
01108    if (i->rtp) {
01109       ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
01110       ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
01111    }
01112    if (i->vrtp) {
01113       ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
01114       ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
01115    }
01116    if (state == AST_STATE_RING)
01117       tmp->rings = 1;
01118    tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01119    tmp->writeformat = fmt;
01120    tmp->rawwriteformat = fmt;
01121    tmp->readformat = fmt;
01122    tmp->rawreadformat = fmt;
01123    tmp->tech_pvt = i;
01124 
01125    tmp->callgroup = client->callgroup;
01126    tmp->pickupgroup = client->pickupgroup;
01127    tmp->caller.id.name.presentation = client->callingpres;
01128    tmp->caller.id.number.presentation = client->callingpres;
01129    if (!ast_strlen_zero(client->accountcode))
01130       ast_string_field_set(tmp, accountcode, client->accountcode);
01131    if (client->amaflags)
01132       tmp->amaflags = client->amaflags;
01133    if (!ast_strlen_zero(client->language))
01134       ast_string_field_set(tmp, language, client->language);
01135    if (!ast_strlen_zero(client->musicclass))
01136       ast_string_field_set(tmp, musicclass, client->musicclass);
01137    if (!ast_strlen_zero(client->parkinglot))
01138       ast_string_field_set(tmp, parkinglot, client->parkinglot);
01139    i->owner = tmp;
01140    ast_module_ref(ast_module_info->self);
01141    ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01142    ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01143 
01144    if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
01145       tmp->dialed.number.str = ast_strdup(i->exten);
01146    }
01147    tmp->priority = 1;
01148    if (i->rtp)
01149       ast_jb_configure(tmp, &global_jbconf);
01150    if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01151       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01152       tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01153       ast_hangup(tmp);
01154       tmp = NULL;
01155    } else {
01156       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01157          "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01158          i->owner ? i->owner->name : "", "Gtalk", i->sid);
01159    }
01160    return tmp;
01161 }

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

Definition at line 1239 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, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), 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, S_OR, gtalk_pvt::sid, gtalk_pvt::them, gtalk_pvt::us, and gtalk_pvt::vrtp.

Referenced by gtalk_parser().

01240 {
01241    struct gtalk_pvt *p, *tmp = client->p;
01242    struct ast_channel *chan;
01243    int res;
01244    iks *codec;
01245    char *from = NULL;
01246    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01247    int peernoncodeccapability;
01248    char *sid;
01249 
01250    /* Make sure our new call doesn't exist yet */
01251    from = iks_find_attrib(pak->x,"to");
01252    if (!from) {
01253       from = client->connection->jid->full;
01254    }
01255 
01256    while (tmp) {
01257       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01258          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01259          ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01260          gtalk_response(client, from, pak, "out-of-order", NULL);
01261          return -1;
01262       }
01263       tmp = tmp->next;
01264    }
01265 
01266    if (!strcasecmp(client->name, "guest")){
01267       /* the guest account is not tied to any configured XMPP client,
01268          let's set it now */
01269       client->connection = ast_aji_get_client(from);
01270       if (!client->connection) {
01271          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01272          return -1;
01273       }
01274    }
01275 
01276    if (!(sid = iks_find_attrib(pak->query, "id"))) {
01277       ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
01278       return -1;
01279    }
01280 
01281    p = gtalk_alloc(client, from, pak->from->full, sid);
01282    if (!p) {
01283       ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01284       return -1;
01285    }
01286 
01287    chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
01288    if (!chan) {
01289       gtalk_free_pvt(client, p);
01290       return -1;
01291    }
01292 
01293    ast_mutex_lock(&p->lock);
01294    ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01295    ast_copy_string(p->sid, sid, sizeof(p->sid));
01296 
01297    /* codec points to the first <payload-type/> tag */
01298    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
01299 
01300    while (codec) {
01301       char *codec_id = iks_find_attrib(codec, "id");
01302       char *codec_name = iks_find_attrib(codec, "name");
01303       if (!codec_id || !codec_name) {
01304          codec = iks_next_tag(codec);
01305          continue;
01306       }
01307       if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
01308          ast_rtp_codecs_payloads_set_m_type(
01309             ast_rtp_instance_get_codecs(p->vrtp),
01310             p->vrtp,
01311             atoi(codec_id));
01312          ast_rtp_codecs_payloads_set_rtpmap_type(
01313             ast_rtp_instance_get_codecs(p->vrtp),
01314             p->vrtp,
01315             atoi(codec_id),
01316             "video",
01317             codec_name,
01318             0);
01319       } else {
01320          ast_rtp_codecs_payloads_set_m_type(
01321             ast_rtp_instance_get_codecs(p->rtp),
01322             p->rtp,
01323             atoi(codec_id));
01324          ast_rtp_codecs_payloads_set_rtpmap_type(
01325             ast_rtp_instance_get_codecs(p->rtp),
01326             p->rtp,
01327             atoi(codec_id),
01328             "audio",
01329             codec_name,
01330             0);
01331       }
01332       codec = iks_next_tag(codec);
01333    }
01334 
01335    /* Now gather all of the codecs that we are asked for */
01336    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), &p->peercapability, &peernoncodeccapability);
01337    p->jointcapability = p->capability & p->peercapability;
01338    ast_mutex_unlock(&p->lock);
01339 
01340    ast_setstate(chan, AST_STATE_RING);
01341    if (!p->jointcapability) {
01342       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
01343          ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
01344          ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
01345       /* close session if capabilities don't match */
01346       gtalk_action(client, p, "reject");
01347       p->alreadygone = 1;
01348       gtalk_hangup(chan);
01349       ast_channel_release(chan);
01350       return -1;
01351    }
01352 
01353    res = ast_pbx_start(chan);
01354 
01355    switch (res) {
01356    case AST_PBX_FAILED:
01357       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01358       gtalk_response(client, from, pak, "service-unavailable", NULL);
01359       break;
01360    case AST_PBX_CALL_LIMIT:
01361       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01362       gtalk_response(client, from, pak, "service-unavailable", NULL);
01363       break;
01364    case AST_PBX_SUCCESS:
01365       gtalk_response(client, from, pak, NULL, NULL);
01366       gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01367       /* nothing to do */
01368       break;
01369    }
01370 
01371    return 1;
01372 }

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

CLI command "gtalk reload".

Todo:
XXX TODO make this work.

Definition at line 1971 of file chan_gtalk.c.

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

Referenced by gtalk_create_member().

01972 {
01973    struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01974    int res;
01975 
01976    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
01977       ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
01978    }
01979 
01980    if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
01981       ast_log(LOG_NOTICE, "No attribute \"type\" found.  Ignoring message.\n");
01982    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
01983       /* New call */
01984       gtalk_newcall(client, pak);
01985    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
01986       ast_debug(3, "About to add candidate!\n");
01987       res = gtalk_add_candidate(client, pak);
01988       if (!res) {
01989          ast_log(LOG_WARNING, "Could not add any candidate\n");
01990       } else {
01991          ast_debug(3, "Candidate Added!\n");
01992       }
01993    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
01994       gtalk_is_answered(client, pak);
01995    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
01996       gtalk_is_accepted(client, pak);
01997    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
01998       gtalk_handle_dtmf(client, pak);
01999    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
02000       gtalk_hangup_farend(client, pak);
02001    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
02002       gtalk_hangup_farend(client, pak);
02003    }
02004    ASTOBJ_UNREF(client, gtalk_member_destroy);
02005    return IKS_FILTER_EAT;
02006 }

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

Definition at line 1584 of file chan_gtalk.c.

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

01585 {
01586    struct ast_frame *fr;
01587    struct gtalk_pvt *p = ast->tech_pvt;
01588 
01589    ast_mutex_lock(&p->lock);
01590    fr = gtalk_rtp_read(ast, p);
01591    ast_mutex_unlock(&p->lock);
01592    return fr;
01593 }

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

Part of PBX interface.

Definition at line 1840 of file chan_gtalk.c.

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

01841 {
01842    struct gtalk_pvt *p = NULL;
01843    struct gtalk *client = NULL;
01844    char *sender = NULL, *to = NULL, *s = NULL;
01845    struct ast_channel *chan = NULL;
01846 
01847    if (data) {
01848       s = ast_strdupa(data);
01849       if (s) {
01850          sender = strsep(&s, "/");
01851          if (sender && (sender[0] != '\0')) {
01852             to = strsep(&s, "/");
01853          }
01854          if (!to) {
01855             ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01856             return NULL;
01857          }
01858       }
01859    }
01860 
01861    client = find_gtalk(to, sender);
01862    if (!client) {
01863       ast_log(LOG_WARNING, "Could not find recipient.\n");
01864       return NULL;
01865    }
01866    if (!strcasecmp(client->name, "guest")){
01867       /* the guest account is not tied to any configured XMPP client,
01868          let's set it now */
01869       client->connection = ast_aji_get_client(sender);
01870       if (!client->connection) {
01871          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01872          ASTOBJ_UNREF(client, gtalk_member_destroy);
01873          return NULL;
01874       }
01875    }
01876 
01877    ASTOBJ_WRLOCK(client);
01878    p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01879    if (p) {
01880       chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL);
01881    }
01882    ASTOBJ_UNLOCK(client);
01883    return chan;
01884 }

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

Definition at line 572 of file chan_gtalk.c.

References ast_aji_send(), gtalk::connection, and S_OR.

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

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

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

Definition at line 460 of file chan_gtalk.c.

References AST_CONTROL_RINGING, ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_create_candidates(), gtalk_invite(), gtalk_pvt::lock, LOG_DEBUG, name, gtalk_pvt::owner, gtalk_pvt::parent, gtalk_pvt::ringrule, S_OR, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_call().

00461 {
00462    struct gtalk_pvt *p = data;
00463    struct ast_channel *owner;
00464 
00465    ast_mutex_lock(&p->lock);
00466 
00467    if (p->ringrule) {
00468       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00469    }
00470    p->ringrule = NULL;
00471 
00472    /* this may be a redirect */
00473    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
00474       char *name = NULL;
00475       char *redirect = NULL;
00476       iks *traversenodes = NULL;
00477       traversenodes = pak->query;
00478       while (traversenodes) {
00479          if (!(name = iks_name(traversenodes))) {
00480             break;
00481          }
00482          if (!strcasecmp(name, "error") &&
00483             (redirect = iks_find_cdata(traversenodes, "redirect")) &&
00484             (redirect = strstr(redirect, "xmpp:"))) {
00485             redirect += 5;
00486             ast_log(LOG_DEBUG, "redirect %s\n", redirect);
00487             ast_copy_string(p->them, redirect, sizeof(p->them));
00488 
00489             gtalk_invite(p, p->them, p->us, p->sid, 1);
00490             break;
00491          }
00492          traversenodes = iks_next_tag(traversenodes);
00493       }
00494    }
00495    gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
00496    owner = p->owner;
00497    ast_mutex_unlock(&p->lock);
00498 
00499    if (owner) {
00500       ast_queue_control(owner, AST_CONTROL_RINGING);
00501    }
00502 
00503    return IKS_FILTER_EAT;
00504 }

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

Definition at line 1555 of file chan_gtalk.c.

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

Referenced by gtalk_read().

01556 {
01557    struct ast_frame *f;
01558 
01559    if (!p->rtp) {
01560       return &ast_null_frame;
01561    }
01562    f = ast_rtp_instance_read(p->rtp, 0);
01563    gtalk_update_stun(p->parent, p);
01564    if (p->owner) {
01565       /* We already hold the channel lock */
01566       if (f->frametype == AST_FRAME_VOICE) {
01567          if (f->subclass.codec != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01568             ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
01569             p->owner->nativeformats =
01570                (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass.codec;
01571             ast_set_read_format(p->owner, p->owner->readformat);
01572             ast_set_write_format(p->owner, p->owner->writeformat);
01573          }
01574          /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
01575             f = ast_dsp_process(p->owner, p->vad, f);
01576             if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
01577                ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
01578            } */
01579       }
01580    }
01581    return f;
01582 }

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

Definition at line 1786 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01787 {
01788    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01789 
01790    return -1;
01791 }

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

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

01677 {
01678    int res = 0;
01679    struct aji_client *client = NULL;
01680    struct gtalk_pvt *p = chan->tech_pvt;
01681 
01682    if (!p->parent) {
01683       ast_log(LOG_ERROR, "Parent channel not found\n");
01684       return -1;
01685    }
01686    if (!p->parent->connection) {
01687       ast_log(LOG_ERROR, "XMPP client not found\n");
01688       return -1;
01689    }
01690    client = p->parent->connection;
01691    res = ast_aji_send_chat(client, p->them, text);
01692    return res;
01693 }

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,
format_t  codecs,
int  nat_active 
) [static]

Definition at line 545 of file chan_gtalk.c.

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

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

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 1887 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, 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.

01888 {
01889 #define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
01890    struct gtalk_pvt *p;
01891    struct ast_channel *chan;
01892    int numchans = 0;
01893    char them[AJI_MAX_JIDLEN];
01894    char *jid = NULL;
01895    char *resource = NULL;
01896 
01897    switch (cmd) {
01898    case CLI_INIT:
01899       e->command = "gtalk show channels";
01900       e->usage =
01901          "Usage: gtalk show channels\n"
01902          "       Shows current state of the Gtalk channels.\n";
01903       return NULL;
01904    case CLI_GENERATE:
01905       return NULL;
01906    }
01907 
01908    if (a->argc != 3)
01909       return CLI_SHOWUSAGE;
01910 
01911    ast_mutex_lock(&gtalklock);
01912    ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01913    ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
01914       ASTOBJ_WRLOCK(iterator);
01915       p = iterator->p;
01916       while(p) {
01917          chan = p->owner;
01918          ast_copy_string(them, p->them, sizeof(them));
01919          jid = them;
01920          resource = strchr(them, '/');
01921          if (!resource)
01922             resource = "None";
01923          else {
01924             *resource = '\0';
01925             resource ++;
01926          }
01927          if (chan)
01928             ast_cli(a->fd, FORMAT,
01929                chan->name,
01930                jid,
01931                resource,
01932                ast_getformatname(chan->readformat),
01933                ast_getformatname(chan->writeformat)
01934                );
01935          else
01936             ast_log(LOG_WARNING, "No available channel\n");
01937          numchans ++;
01938          p = p->next;
01939       }
01940       ASTOBJ_UNLOCK(iterator);
01941    });
01942 
01943    ast_mutex_unlock(&gtalklock);
01944 
01945    ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
01946    return CLI_SUCCESS;
01947 #undef FORMAT
01948 }

static int gtalk_update_externip ( void   )  [static]

Definition at line 1374 of file chan_gtalk.c.

References ast_connect(), ast_inet_ntoa(), ast_log(), ast_sockaddr_from_sin, ast_sockaddr_stringify(), ast_strdupa, ast_stun_request(), errno, externip, LOG_WARNING, and stunaddr.

Referenced by gtalk_create_candidates().

01375 {
01376    int sock;
01377    char *newaddr;
01378    struct sockaddr_in answer = { 0, };
01379    struct sockaddr_in *dst;
01380    struct ast_sockaddr tmp_dst;
01381 
01382    if (!stunaddr.sin_addr.s_addr) {
01383       return -1;
01384    }
01385    dst = &stunaddr;
01386 
01387    sock = socket(AF_INET, SOCK_DGRAM, 0);
01388    if (sock < 0) {
01389       ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
01390       return -1;
01391    }
01392 
01393    ast_sockaddr_from_sin(&tmp_dst, dst);
01394    if (ast_connect(sock, &tmp_dst) != 0) {
01395       ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
01396       close(sock);
01397       return -1;
01398    }
01399 
01400    if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
01401       close(sock);
01402       return -1;
01403    }
01404 
01405    newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
01406    memcpy(externip, newaddr, sizeof(externip));
01407 
01408    close(sock);
01409    return 0;
01410 
01411 }

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

Definition at line 1413 of file chan_gtalk.c.

References ahp, ast_debug, ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_instance_get_remote_address(), ast_rtp_instance_stun_request(), ast_sockaddr_from_sin, ast_sockaddr_to_sin, hp, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_WARNING, gtalk_candidate::next, gtalk_pvt::ourcandidates, gtalk_candidate::port, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_candidate::username.

Referenced by gtalk_add_candidate(), gtalk_is_accepted(), gtalk_is_answered(), and gtalk_rtp_read().

01414 {
01415    struct gtalk_candidate *tmp;
01416    struct hostent *hp;
01417    struct ast_hostent ahp;
01418    struct sockaddr_in sin = { 0, };
01419    struct sockaddr_in aux = { 0, };
01420    struct ast_sockaddr sin_tmp;
01421    struct ast_sockaddr aux_tmp;
01422 
01423    if (time(NULL) == p->laststun)
01424       return 0;
01425 
01426    tmp = p->theircandidates;
01427    p->laststun = time(NULL);
01428    while (tmp) {
01429       char username[256];
01430 
01431       /* Find the IP address of the host */
01432       if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
01433          ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
01434          tmp = tmp->next;
01435          continue;
01436       }
01437       sin.sin_family = AF_INET;
01438       memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01439       sin.sin_port = htons(tmp->port);
01440       snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
01441 
01442       /* Find out the result of the STUN */
01443       ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
01444       ast_sockaddr_to_sin(&aux_tmp, &aux);
01445 
01446       /* If the STUN result is different from the IP of the hostname,
01447        * lock on the stun IP of the hostname advertised by the
01448        * remote client */
01449       if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
01450          ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
01451       } else {
01452          ast_sockaddr_from_sin(&sin_tmp, &sin);
01453          ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
01454       }
01455       if (aux.sin_addr.s_addr) {
01456          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);
01457          ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01458       }
01459 
01460       tmp = tmp->next;
01461    }
01462    return 1;
01463 }

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

Send frame to media channel (rtp).

Definition at line 1596 of file chan_gtalk.c.

References AST_FRAME_IMAGE, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_frame_subclass::codec, 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.

01597 {
01598    struct gtalk_pvt *p = ast->tech_pvt;
01599    int res = 0;
01600    char buf[256];
01601 
01602    switch (frame->frametype) {
01603    case AST_FRAME_VOICE:
01604       if (!(frame->subclass.codec & ast->nativeformats)) {
01605          ast_log(LOG_WARNING,
01606                "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01607                ast_getformatname(frame->subclass.codec),
01608                ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
01609                ast_getformatname(ast->readformat),
01610                ast_getformatname(ast->writeformat));
01611          return 0;
01612       }
01613       if (p) {
01614          ast_mutex_lock(&p->lock);
01615          if (p->rtp) {
01616             res = ast_rtp_instance_write(p->rtp, frame);
01617          }
01618          ast_mutex_unlock(&p->lock);
01619       }
01620       break;
01621    case AST_FRAME_VIDEO:
01622       if (p) {
01623          ast_mutex_lock(&p->lock);
01624          if (p->vrtp) {
01625             res = ast_rtp_instance_write(p->vrtp, frame);
01626          }
01627          ast_mutex_unlock(&p->lock);
01628       }
01629       break;
01630    case AST_FRAME_IMAGE:
01631       return 0;
01632       break;
01633    default:
01634       ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01635             frame->frametype);
01636       return 0;
01637    }
01638 
01639    return res;
01640 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 2180 of file chan_gtalk.c.

References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_glue_register, ast_sockaddr_from_sin, ast_sockaddr_ipv4(), ASTOBJ_CONTAINER_INIT, bindaddr, free, GOOGLE_CONFIG, gtalk_cli, gtalk_get_local_ip(), gtalk_list, gtalk_load_config(), gtalk_rtp_glue, gtalk_tech, io, io_context_create(), LOG_ERROR, LOG_WARNING, sched_context_create(), and ast_channel_tech::type.

02181 {
02182    struct ast_sockaddr bindaddr_tmp;
02183    struct ast_sockaddr ourip_tmp;
02184 
02185    char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02186    free(jabber_loaded);
02187    if (!jabber_loaded) {
02188       /* If embedded, check for a different module name */
02189       jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02190       free(jabber_loaded);
02191       if (!jabber_loaded) {
02192          ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02193          return AST_MODULE_LOAD_DECLINE;
02194       }
02195    }
02196 
02197    ASTOBJ_CONTAINER_INIT(&gtalk_list);
02198    if (!gtalk_load_config()) {
02199       ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02200       return 0;
02201    }
02202 
02203    sched = sched_context_create();
02204    if (!sched) {
02205       ast_log(LOG_WARNING, "Unable to create schedule context\n");
02206    }
02207 
02208    io = io_context_create();
02209    if (!io) {
02210       ast_log(LOG_WARNING, "Unable to create I/O context\n");
02211    }
02212 
02213    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02214    if (gtalk_get_local_ip(&ourip_tmp)) {
02215       ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02216       return 0;
02217    }
02218    __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
02219 
02220    ast_rtp_glue_register(&gtalk_rtp_glue);
02221    ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02222 
02223    /* Make sure we can register our channel type */
02224    if (ast_channel_register(&gtalk_tech)) {
02225       ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02226       return -1;
02227    }
02228    return 0;
02229 }

static int unload_module ( void   )  [static]

Reload module Unload the gtalk channel from Asterisk.

Definition at line 2240 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_cli, gtalk_list, gtalk_member_destroy(), gtalk_rtp_glue, gtalk_tech, gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.

02241 {
02242    struct gtalk_pvt *privates = NULL;
02243    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02244    /* First, take us out of the channel loop */
02245    ast_channel_unregister(&gtalk_tech);
02246    ast_rtp_glue_unregister(&gtalk_rtp_glue);
02247 
02248    if (!ast_mutex_lock(&gtalklock)) {
02249       /* Hangup all interfaces if they have an owner */
02250       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02251          ASTOBJ_WRLOCK(iterator);
02252          privates = iterator->p;
02253          while(privates) {
02254             if (privates->owner)
02255                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02256             privates = privates->next;
02257          }
02258          iterator->p = NULL;
02259          ASTOBJ_UNLOCK(iterator);
02260       });
02261       ast_mutex_unlock(&gtalklock);
02262    } else {
02263       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02264       return -1;
02265    }
02266    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02267    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02268    return 0;
02269 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 2276 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 228 of file chan_gtalk.c.

Referenced by find_subchannel_and_lock(), jingle_create_candidates(), and load_module().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2276 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

The address we bind to

Definition at line 224 of file chan_gtalk.c.

Referenced by __sip_subscribe_mwi_do(), ast_find_ourip(), ast_sip_ouraddrfor(), build_peer(), create_addr(), create_addr_from_peer(), dialog_initialize_rtp(), gtalk_alloc(), gtalk_get_local_ip(), handle_request_invite(), jingle_alloc(), jingle_create_candidates(), jingle_load_config(), load_module(), proxy_update(), realtime_peer(), reload_config(), sip_alloc(), sip_show_settings(), sipsock_read(), start_rtp(), and transmit_register().

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 82 of file chan_gtalk.c.

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

Definition at line 168 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 235 of file chan_gtalk.c.

Referenced by gtalk_create_candidates(), gtalk_update_externip(), jingle_create_candidates(), and jingle_load_config().

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

Definition at line 170 of file chan_gtalk.c.

Referenced by gtalk_alloc(), gtalk_load_config(), gtalk_new(), jingle_load_config(), and jingle_new().

struct ast_jb_conf global_jbconf [static]

Definition at line 90 of file chan_gtalk.c.

struct ast_cli_entry gtalk_cli[] [static]

Initial value:

 {

   { .handler =  gtalk_show_channels , .summary =  "Show GoogleTalk channels" ,__VA_ARGS__ },
}

Definition at line 230 of file chan_gtalk.c.

Referenced by load_module(), and unload_module().

struct gtalk_container gtalk_list [static]

Definition at line 238 of file chan_gtalk.c.

Referenced by find_gtalk(), gtalk_show_channels(), load_module(), and unload_module().

struct ast_rtp_glue gtalk_rtp_glue [static]

Definition at line 565 of file chan_gtalk.c.

Referenced by load_module(), and unload_module().

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 200 of file chan_gtalk.c.

Referenced by gtalk_new(), load_module(), and unload_module().

ast_mutex_t gtalklock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } [static]

Protect the interface list (of gtalk_pvt's)

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

Referenced by ast_expr(), ast_str_expr(), create_addr_from_peer(), do_monitor(), handle_request_invite(), load_module(), network_thread(), peer_set_srcaddr(), reload(), set_config(), sip_alloc(), and unload_module().

struct sched_context* sched [static]

The scheduling context

Definition at line 226 of file chan_gtalk.c.

Referenced by __attempt_transmit(), __find_callno(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __unload_module(), ack_trans(), ast_rtp_instance_new(), auth_fail(), build_peer(), create_esc_entry(), delete_users(), destroy_event(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_monitor(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), esc_entry_destructor(), handle_command_response(), handle_dump_sched(), iax2_ack_registry(), iax2_call(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_hangup(), iax2_key_rotate(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_change_event_cb(), network_thread(), populate_addr(), precache_trans(), qualify_peer(), reg_source_db(), sched_delay_remove(), schedule_calendar_event(), schedule_delivery(), sip_cc_agent_start_offer_timer(), sip_cc_agent_stop_offer_timer(), sip_cc_monitor_cancel_available_timer(), sip_cc_monitor_request_cc(), socket_process(), start_rtp(), stun_start_monitor(), stun_stop_monitor(), transmit_frame(), unlink_peer(), unload_module(), update_jbsched(), and update_registry().

struct sockaddr_in stunaddr [static]

the stun server we get the externip from

Definition at line 236 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and gtalk_update_externip().


Generated on Wed Apr 6 11:29:56 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7