Sat Feb 11 06:34:32 2012

Asterisk developer's documentation


chan_gtalk.c File Reference

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

#include "asterisk.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include <iksemel.h>
#include <pthread.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp_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"
#include "asterisk/features.h"

Include dependency graph for chan_gtalk.c:

Go to the source code of this file.

Data Structures

struct  gtalk
struct  gtalk_candidate
struct  gtalk_container
struct  gtalk_pvt

Defines

#define FORMAT   " %-25.20s %-15.30s\n"
#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, struct ast_format *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, const 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 void gtalk_get_codec (struct ast_channel *chan, struct ast_format_cap *result)
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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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, const struct ast_format_cap *cap, 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 char * gtalk_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 List global settings for the GoogleTalk channel.
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.

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 = AST_BUILDOPT_SUM, .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 const int DEFAULT_ALLOWGUEST = 1
static const char DEFAULT_CONTEXT [] = "default"
static struct ast_jb_conf default_jbconf
static const char desc [] = "Gtalk Channel"
static char externip [16]
static int global_allowguest
static struct ast_format_capglobal_capability
static char global_context [AST_MAX_CONTEXT]
static struct ast_jb_conf global_jbconf
static char global_parkinglot [AST_MAX_CONTEXT]
static int global_stunaddr
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 = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static struct io_contextio
static struct ast_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.
Todo:
Fix native bridging.

Definition in file chan_gtalk.c.


Define Documentation

#define FORMAT   " %-25.20s %-15.30s\n"

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

#define GOOGLE_CONFIG   "gtalk.conf"

Definition at line 80 of file chan_gtalk.c.

Referenced by gtalk_load_config(), and load_module().


Enumeration Type Documentation

Enumerator:
AJI_CONNECT_STUN 
AJI_CONNECT_LOCAL 
AJI_CONNECT_RELAY 

Definition at line 98 of file chan_gtalk.c.

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

Enumerator:
AJI_PROTOCOL_UDP 
AJI_PROTOCOL_SSLTCP 

Definition at line 93 of file chan_gtalk.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2407 of file chan_gtalk.c.

static void __unreg_module ( void   )  [static]

Definition at line 2407 of file chan_gtalk.c.

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

Definition at line 294 of file chan_gtalk.c.

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

Referenced by gtalk_invite(), and jingle_accept_call().

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

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

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

00263 {
00264    struct gtalk *gtalk = NULL;
00265    char *domain = NULL , *s = NULL;
00266 
00267    if (strchr(connection, '@')) {
00268       s = ast_strdupa(connection);
00269       domain = strsep(&s, "@");
00270       ast_verbose("OOOOH domain = %s\n", domain);
00271    }
00272    gtalk = ASTOBJ_CONTAINER_FIND(&gtalk_list, name);
00273    if (!gtalk && strchr(name, '@'))
00274       gtalk = ASTOBJ_CONTAINER_FIND_FULL(&gtalk_list, name, user,,, strcasecmp);
00275 
00276    if (!gtalk) {
00277       /* guest call */
00278       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
00279          ASTOBJ_RDLOCK(iterator);
00280          if (!strcasecmp(iterator->name, "guest")) {
00281             gtalk = iterator;
00282          }
00283          ASTOBJ_UNLOCK(iterator);
00284 
00285          if (gtalk)
00286             break;
00287       });
00288 
00289    }
00290    return gtalk;
00291 }

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

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

01218 {
01219    iks *request, *session = NULL;
01220    int res = -1;
01221    char *lowerthem = NULL;
01222 
01223    request = iks_new("iq");
01224    if (request) {
01225       iks_insert_attrib(request, "type", "set");
01226       iks_insert_attrib(request, "from", p->us);
01227       iks_insert_attrib(request, "to", p->them);
01228       iks_insert_attrib(request, "id", client->connection->mid);
01229       ast_aji_increment_mid(client->connection->mid);
01230       session = iks_new("session");
01231       if (session) {
01232          iks_insert_attrib(session, "type", action);
01233          iks_insert_attrib(session, "id", p->sid);
01234          /* put the initiator attribute to lower case if we receive the call
01235           * otherwise GoogleTalk won't establish the session */
01236          if (!p->initiator) {
01237                  char c;
01238             char *t = lowerthem = ast_strdupa(p->them);
01239             while (((c = *t) != '/') && (*t++ = tolower(c)));
01240          }
01241          iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
01242          iks_insert_attrib(session, "xmlns", GOOGLE_NS);
01243          iks_insert_node(request, session);
01244          ast_aji_send(client->connection, request);
01245          res = 0;
01246       }
01247    }
01248 
01249    iks_delete(session);
01250    iks_delete(request);
01251 
01252    return res;
01253 }

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

Definition at line 1525 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

01526 {
01527    struct gtalk_pvt *p = NULL, *tmp = NULL;
01528    struct aji_client *c = client->connection;
01529    struct gtalk_candidate *newcandidate = NULL;
01530    iks *traversenodes = NULL, *receipt = NULL;
01531    char *from;
01532 
01533    from = iks_find_attrib(pak->x,"to");
01534    if (!from) {
01535       from = c->jid->full;
01536    }
01537 
01538    for (tmp = client->p; tmp; tmp = tmp->next) {
01539       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01540          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01541          p = tmp;
01542          break;
01543       }
01544    }
01545 
01546    if (!p) {
01547       return -1;
01548    }
01549    traversenodes = pak->query;
01550    while(traversenodes) {
01551       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
01552          traversenodes = iks_first_tag(traversenodes);
01553          continue;
01554       }
01555       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
01556          traversenodes = iks_child(traversenodes);
01557          continue;
01558       }
01559       if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
01560          newcandidate = ast_calloc(1, sizeof(*newcandidate));
01561          if (!newcandidate)
01562             return 0;
01563          ast_copy_string(newcandidate->name,
01564             S_OR(iks_find_attrib(traversenodes, "name"), ""),
01565             sizeof(newcandidate->name));
01566          ast_copy_string(newcandidate->ip,
01567             S_OR(iks_find_attrib(traversenodes, "address"), ""),
01568             sizeof(newcandidate->ip));
01569          newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01570          ast_copy_string(newcandidate->username,
01571             S_OR(iks_find_attrib(traversenodes, "username"), ""),
01572             sizeof(newcandidate->username));
01573          ast_copy_string(newcandidate->password,
01574             S_OR(iks_find_attrib(traversenodes, "password"), ""),
01575             sizeof(newcandidate->password));
01576          newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01577          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
01578             newcandidate->protocol = AJI_PROTOCOL_UDP;
01579          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
01580             newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01581 
01582          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
01583             newcandidate->type = AJI_CONNECT_STUN;
01584          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
01585             newcandidate->type = AJI_CONNECT_LOCAL;
01586          if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
01587             newcandidate->type = AJI_CONNECT_RELAY;
01588          ast_copy_string(newcandidate->network,
01589             S_OR(iks_find_attrib(traversenodes, "network"), ""),
01590             sizeof(newcandidate->network));
01591          newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
01592          newcandidate->next = NULL;
01593 
01594          newcandidate->next = p->theircandidates;
01595          p->theircandidates = newcandidate;
01596          p->laststun = 0;
01597          gtalk_update_stun(p->parent, p);
01598          newcandidate = NULL;
01599       }
01600       traversenodes = iks_next_tag(traversenodes);
01601    }
01602 
01603    receipt = iks_new("iq");
01604    iks_insert_attrib(receipt, "type", "result");
01605    iks_insert_attrib(receipt, "from", from);
01606    iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
01607    iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
01608    ast_aji_send(c, receipt);
01609 
01610    iks_delete(receipt);
01611 
01612    return 1;
01613 }

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

Definition at line 1002 of file chan_gtalk.c.

References ast_aji_buddy_destroy(), ast_calloc, ast_copy_string(), ast_debug, ast_format_cap_alloc_nolock(), ast_format_cap_copy(), ast_format_cap_destroy(), ast_format_cap_is_empty(), 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, ASTOBJ_UNREF, aji_client::buddies, gtalk::buddy, gtalk::cap, gtalk_pvt::cap, aji_resource::cap, gtalk_pvt::cid_name, gtalk::connection, gtalk_pvt::exten, exten, gtalklock, gtalk_pvt::initiator, aji_version::jingle, gtalk_pvt::jointcap, gtalk_pvt::lock, LOG_ERROR, LOG_WARNING, gtalk::name, gtalk_pvt::next, aji_resource::next, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercap, gtalk::prefs, gtalk_pvt::prefs, aji_resource::resource, aji_buddy::resources, gtalk_pvt::rtp, gtalk_pvt::sid, strsep(), gtalk_pvt::them, and gtalk_pvt::us.

Referenced by gtalk_newcall(), and gtalk_request().

01003 {
01004    struct gtalk_pvt *tmp = NULL;
01005    struct aji_resource *resources = NULL;
01006    struct aji_buddy *buddy = NULL;
01007    char idroster[200];
01008    char *data, *exten = NULL;
01009    struct ast_sockaddr bindaddr_tmp;
01010 
01011    ast_debug(1, "The client is %s for alloc\n", client->name);
01012    if (!sid && !strchr(them, '/')) {   /* I started call! */
01013       if (!strcasecmp(client->name, "guest")) {
01014          buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
01015          if (buddy) {
01016             resources = buddy->resources;
01017          }
01018       } else if (client->buddy) {
01019          resources = client->buddy->resources;
01020       }
01021 
01022       while (resources) {
01023          if (resources->cap->jingle) {
01024             break;
01025          }
01026          resources = resources->next;
01027       }
01028       if (resources) {
01029          snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
01030       } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
01031          snprintf(idroster, sizeof(idroster), "%s", them);
01032       } else {
01033          ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
01034          if (buddy) {
01035             ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01036          }
01037          return NULL;
01038       }
01039       if (buddy) {
01040          ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01041       }
01042    }
01043    if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
01044       return NULL;
01045    }
01046    tmp->cap = ast_format_cap_alloc_nolock();
01047    tmp->jointcap = ast_format_cap_alloc_nolock();
01048    tmp->peercap = ast_format_cap_alloc_nolock();
01049    if (!tmp->jointcap || !tmp->peercap || !tmp->cap) {
01050       tmp->cap = ast_format_cap_destroy(tmp->cap);
01051       tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
01052       tmp->peercap = ast_format_cap_destroy(tmp->peercap);
01053       ast_free(tmp);
01054       return NULL;
01055    }
01056 
01057    memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
01058 
01059    if (sid) {
01060       ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
01061       ast_copy_string(tmp->them, them, sizeof(tmp->them));
01062       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01063    } else {
01064       snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
01065       ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
01066       ast_copy_string(tmp->us, us, sizeof(tmp->us));
01067       tmp->initiator = 1;
01068    }
01069    /* clear codecs */
01070    bindaddr.sin_family = AF_INET;
01071    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
01072    if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
01073      ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
01074      ast_free(tmp);
01075      return NULL;
01076    }
01077    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
01078    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
01079    ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
01080    ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
01081    ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
01082 
01083    /* add user configured codec capabilites */
01084    if (!(ast_format_cap_is_empty(client->cap))) {
01085       ast_format_cap_copy(tmp->cap, client->cap);
01086    } else if (!(ast_format_cap_is_empty(global_capability))) {
01087       ast_format_cap_copy(tmp->cap, global_capability);
01088    }
01089 
01090    tmp->parent = client;
01091    if (!tmp->rtp) {
01092       ast_log(LOG_WARNING, "Out of RTP sessions?\n");
01093       ast_free(tmp);
01094       return NULL;
01095    }
01096 
01097    /* Set CALLERID(name) to the full JID of the remote peer */
01098    ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
01099 
01100    if(strchr(tmp->us, '/')) {
01101       data = ast_strdupa(tmp->us);
01102       exten = strsep(&data, "/");
01103    } else {
01104       exten = tmp->us;
01105    }
01106    ast_copy_string(tmp->exten,  exten, sizeof(tmp->exten));
01107    ast_mutex_init(&tmp->lock);
01108    ast_mutex_lock(&gtalklock);
01109    tmp->next = client->p;
01110    client->p = tmp;
01111    ast_mutex_unlock(&gtalklock);
01112    return tmp;
01113 }

static int gtalk_answer ( struct ast_channel ast  )  [static]

Definition at line 531 of file chan_gtalk.c.

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

00532 {
00533    struct gtalk_pvt *p = ast->tech_pvt;
00534    int res = 0;
00535 
00536    ast_debug(1, "Answer!\n");
00537    ast_mutex_lock(&p->lock);
00538    gtalk_invite(p, p->them, p->us,p->sid, 0);
00539    manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
00540       ast_channel_name(ast), "GTALK", p->sid);
00541    ast_mutex_unlock(&p->lock);
00542    return res;
00543 }

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

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

Definition at line 1855 of file chan_gtalk.c.

References ast_channel::_state, ast_channel_name(), 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, gtalk_pvt::parent, gtalk_pvt::ring, gtalk_pvt::ringrule, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.

01856 {
01857    struct gtalk_pvt *p = ast->tech_pvt;
01858 
01859    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01860       ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
01861       return -1;
01862    }
01863 
01864    ast_setstate(ast, AST_STATE_RING);
01865    if (!p->ringrule) {
01866       ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01867       p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01868                      IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01869    } else {
01870       ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01871    }
01872 
01873    gtalk_invite(p, p->them, p->us, p->sid, 1);
01874 
01875    return 0;
01876 }

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

Definition at line 865 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, gtalk_candidate::generation, 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().

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

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 2113 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::cap, gtalk::connection, gtalk::context, aji_client::f, GOOGLE_NS, gtalk_parser(), LOG_ERROR, LOG_WARNING, ast_variable::name, gtalk::name, ast_variable::next, gtalk::parkinglot, gtalk::prefs, gtalk::user, and ast_variable::value.

Referenced by gtalk_load_config().

02116 {
02117    struct aji_client *client;
02118 
02119    if (!member)
02120       ast_log(LOG_WARNING, "Out of memory.\n");
02121 
02122    ast_copy_string(member->name, label, sizeof(member->name));
02123    ast_copy_string(member->user, label, sizeof(member->user));
02124    ast_copy_string(member->context, context, sizeof(member->context));
02125    member->allowguest = allowguest;
02126    member->prefs = prefs;
02127    while (var) {
02128       if (!strcasecmp(var->name, "username"))
02129          ast_copy_string(member->user, var->value, sizeof(member->user));
02130       else if (!strcasecmp(var->name, "disallow"))
02131          ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
02132       else if (!strcasecmp(var->name, "allow"))
02133          ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
02134       else if (!strcasecmp(var->name, "context"))
02135          ast_copy_string(member->context, var->value, sizeof(member->context));
02136       else if (!strcasecmp(var->name, "parkinglot"))
02137          ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
02138       else if (!strcasecmp(var->name, "connection")) {
02139          if ((client = ast_aji_get_client(var->value))) {
02140             member->connection = client;
02141             iks_filter_add_rule(client->f, gtalk_parser, member,
02142                       IKS_RULE_TYPE, IKS_PAK_IQ,
02143                       IKS_RULE_FROM_PARTIAL, member->user,
02144                       IKS_RULE_NS, GOOGLE_NS,
02145                       IKS_RULE_DONE);
02146          } else {
02147             ast_log(LOG_ERROR, "connection referenced not found!\n");
02148             return 0;
02149          }
02150       }
02151       var = var->next;
02152    }
02153    if (member->connection && member->user)
02154       member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
02155    else {
02156       ast_log(LOG_ERROR, "No Connection or Username!\n");
02157    }
02158    return 1;
02159 }

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

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

01756 {
01757    struct gtalk_pvt *p = chan->tech_pvt;
01758    int res = 0;
01759 
01760    ast_mutex_lock(&p->lock);
01761    if (p->rtp) {
01762       ast_rtp_instance_dtmf_begin(p->rtp, digit);
01763    } else {
01764       res = -1;
01765    }
01766    ast_mutex_unlock(&p->lock);
01767 
01768    return res;
01769 }

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

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

01772 {
01773    struct gtalk_pvt *p = chan->tech_pvt;
01774    int res = 0;
01775 
01776    ast_mutex_lock(&p->lock);
01777    if (p->rtp) {
01778       ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
01779    } else {
01780       res = -1;
01781    }
01782    ast_mutex_unlock(&p->lock);
01783 
01784    return res;
01785 }

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

Definition at line 1702 of file chan_gtalk.c.

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

01703 {
01704    struct gtalk_pvt *p = newchan->tech_pvt;
01705    ast_mutex_lock(&p->lock);
01706 
01707    if ((p->owner != oldchan)) {
01708       ast_mutex_unlock(&p->lock);
01709       return -1;
01710    }
01711    if (p->owner == oldchan)
01712       p->owner = newchan;
01713    ast_mutex_unlock(&p->lock);
01714    return 0;
01715 }

static void gtalk_free_candidates ( struct gtalk_candidate candidate  )  [static]

Definition at line 1255 of file chan_gtalk.c.

References ast_free, last, and gtalk_candidate::next.

Referenced by gtalk_free_pvt(), and gtalk_load_config().

01256 {
01257    struct gtalk_candidate *last;
01258    while (candidate) {
01259       last = candidate;
01260       candidate = candidate->next;
01261       ast_free(last);
01262    }
01263 }

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

Definition at line 1265 of file chan_gtalk.c.

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

Referenced by gtalk_hangup(), and gtalk_newcall().

01266 {
01267    struct gtalk_pvt *cur, *prev = NULL;
01268    cur = client->p;
01269    while (cur) {
01270       if (cur == p) {
01271          if (prev)
01272             prev->next = p->next;
01273          else
01274             client->p = p->next;
01275          break;
01276       }
01277       prev = cur;
01278       cur = cur->next;
01279    }
01280    if (p->ringrule)
01281       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01282    if (p->owner)
01283       ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01284    if (p->rtp)
01285       ast_rtp_instance_destroy(p->rtp);
01286    if (p->vrtp)
01287       ast_rtp_instance_destroy(p->vrtp);
01288    gtalk_free_candidates(p->theircandidates);
01289    p->cap = ast_format_cap_destroy(p->cap);
01290    p->jointcap = ast_format_cap_destroy(p->jointcap);
01291    p->peercap = ast_format_cap_destroy(p->peercap);
01292    ast_free(p);
01293 }

static void gtalk_get_codec ( struct ast_channel chan,
struct ast_format_cap result 
) [static]

Definition at line 564 of file chan_gtalk.c.

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

00565 {
00566    struct gtalk_pvt *p = chan->tech_pvt;
00567    ast_mutex_lock(&p->lock);
00568    ast_format_cap_copy(result, p->peercap);
00569    ast_mutex_unlock(&p->lock);
00570 }

static int gtalk_get_local_ip ( struct ast_sockaddr ourip  )  [static]

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

Referenced by gtalk_create_candidates(), and load_module().

00838 {
00839    struct ast_sockaddr root;
00840    struct ast_sockaddr bindaddr_tmp;
00841    struct ast_sockaddr *addrs;
00842    int addrs_cnt;
00843 
00844    /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
00845    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
00846    if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
00847       ast_sockaddr_copy(ourip, &bindaddr_tmp);
00848       return 0;
00849    }
00850 
00851    /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
00852     * If you can't resolve google.com from your network, then this module is useless for you anyway. */
00853    if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
00854       ast_sockaddr_copy(&root, &addrs[0]);
00855       ast_free(addrs);
00856       if (!ast_ouraddrfor(&root, ourip)) {
00857          return 0;
00858       }
00859    }
00860 
00861    /* As a last resort, use this function to find our local address. */
00862    return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
00863 }

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

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

00546 {
00547    struct gtalk_pvt *p = chan->tech_pvt;
00548    enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
00549 
00550    if (!p)
00551       return res;
00552 
00553    ast_mutex_lock(&p->lock);
00554    if (p->rtp){
00555       ao2_ref(p->rtp, +1);
00556       *instance = p->rtp;
00557       res = AST_RTP_GLUE_RESULT_LOCAL;
00558    }
00559    ast_mutex_unlock(&p->lock);
00560 
00561    return res;
00562 }

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

Definition at line 738 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

00739 {
00740    struct gtalk_pvt *tmp;
00741    iks *dtmfnode = NULL, *dtmfchild = NULL;
00742    char *dtmf;
00743    char *from;
00744    /* Make sure our new call doesn't exist yet */
00745    for (tmp = client->p; tmp; tmp = tmp->next) {
00746       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
00747          break;
00748    }
00749    from = iks_find_attrib(pak->x, "to");
00750    if (!from) {
00751       from = client->connection->jid->full;
00752    }
00753 
00754    if (tmp) {
00755       if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00756          gtalk_response(client, from, pak,
00757                "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00758                "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00759          return -1;
00760       }
00761       if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00762          if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00763             if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00764                struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00765                f.subclass.integer = dtmf[0];
00766                ast_queue_frame(tmp->owner, &f);
00767                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00768             } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00769                struct ast_frame f = {AST_FRAME_DTMF_END, };
00770                f.subclass.integer = dtmf[0];
00771                ast_queue_frame(tmp->owner, &f);
00772                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00773             } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
00774                struct ast_frame f = {AST_FRAME_DTMF, };
00775                f.subclass.integer = dtmf[0];
00776                ast_queue_frame(tmp->owner, &f);
00777                ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00778             }
00779          }
00780       } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
00781          if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
00782             if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
00783                if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
00784                   struct ast_frame f = {AST_FRAME_DTMF_END, };
00785                   f.subclass.integer = dtmf[0];
00786                   ast_queue_frame(tmp->owner, &f);
00787                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00788                } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
00789                   struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00790                   f.subclass.integer = dtmf[0];
00791                   ast_queue_frame(tmp->owner, &f);
00792                   ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
00793                }
00794             }
00795          }
00796       }
00797       gtalk_response(client, from, pak, NULL, NULL);
00798       return 1;
00799    } else {
00800       ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00801    }
00802 
00803    gtalk_response(client, from, pak, NULL, NULL);
00804    return 1;
00805 }

static int gtalk_hangup ( struct ast_channel ast  )  [static]

Hangup a call through the gtalk proxy channel.

Definition at line 1879 of file chan_gtalk.c.

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

Referenced by gtalk_newcall().

01880 {
01881    struct gtalk_pvt *p = ast->tech_pvt;
01882    struct gtalk *client;
01883 
01884    ast_mutex_lock(&p->lock);
01885    client = p->parent;
01886    p->owner = NULL;
01887    ast->tech_pvt = NULL;
01888    if (!p->alreadygone) {
01889       gtalk_action(client, p, "terminate");
01890    }
01891    ast_mutex_unlock(&p->lock);
01892 
01893    gtalk_free_pvt(client, p);
01894    ast_module_unref(ast_module_info->self);
01895 
01896    return 0;
01897 }

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

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

00808 {
00809    struct gtalk_pvt *tmp;
00810    char *from;
00811 
00812    ast_debug(1, "The client is %s\n", client->name);
00813    /* Make sure our new call doesn't exist yet */
00814    for (tmp = client->p; tmp; tmp = tmp->next) {
00815       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
00816          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
00817          break;
00818       }
00819    }
00820    from = iks_find_attrib(pak->x, "to");
00821    if (!from) {
00822       from = client->connection->jid->full;
00823    }
00824 
00825    if (tmp) {
00826       tmp->alreadygone = 1;
00827       if (tmp->owner) {
00828          ast_queue_hangup(tmp->owner);
00829       }
00830    } else {
00831       ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
00832    }
00833    gtalk_response(client, from, pak, NULL, NULL);
00834    return 1;
00835 }

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

Definition at line 1717 of file chan_gtalk.c.

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

01718 {
01719    int res = 0;
01720 
01721    switch (condition) {
01722    case AST_CONTROL_HOLD:
01723       ast_moh_start(ast, data, NULL);
01724       break;
01725    case AST_CONTROL_UNHOLD:
01726       ast_moh_stop(ast);
01727       break;
01728    default:
01729       ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
01730       res = -1;
01731    }
01732 
01733    return res;
01734 }

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

Definition at line 399 of file chan_gtalk.c.

References add_codec_to_answer(), ast_aji_increment_mid(), ast_aji_send(), ast_codec_pref_index(), AST_CODEC_PREF_SIZE, ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_cap_iscompatible(), ast_log(), ast_strdupa, gtalk::cap, gtalk::connection, GOOGLE_AUDIO_NS, GOOGLE_NS, GOOGLE_TRANSPORT_NS, LOG_ERROR, aji_client::mid, gtalk_pvt::parent, and gtalk::prefs.

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

00400 {
00401    struct gtalk *client = p->parent;
00402    iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00403    int x;
00404    struct ast_format_cap *alreadysent;
00405    int codecs_num = 0;
00406    char *lowerto = NULL;
00407    struct ast_format tmpfmt;
00408 
00409    iq = iks_new("iq");
00410    gtalk = iks_new("session");
00411    dcodecs = iks_new("description");
00412    transport = iks_new("transport");
00413    payload_telephone = iks_new("payload-type");
00414    if (!(iq && gtalk && dcodecs && transport && payload_telephone)) {
00415       iks_delete(iq);
00416       iks_delete(gtalk);
00417       iks_delete(dcodecs);
00418       iks_delete(transport);
00419       iks_delete(payload_telephone);
00420 
00421       ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00422       return 0;
00423    }
00424    iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
00425    iks_insert_attrib(dcodecs, "xml:lang", "en");
00426 
00427    if (!(alreadysent = ast_format_cap_alloc_nolock())) {
00428       return 0;
00429    }
00430    for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
00431       if (!(ast_codec_pref_index(&client->prefs, x, &tmpfmt))) {
00432          break;
00433       }
00434       if (!(ast_format_cap_iscompatible(client->cap, &tmpfmt))) {
00435          continue;
00436       }
00437       if (ast_format_cap_iscompatible(alreadysent, &tmpfmt)) {
00438          continue;
00439       }
00440       codecs_num = add_codec_to_answer(p, &tmpfmt, dcodecs);
00441       ast_format_cap_add(alreadysent, &tmpfmt);
00442    }
00443    alreadysent = ast_format_cap_destroy(alreadysent);
00444 
00445    if (codecs_num) {
00446       /* only propose DTMF within an audio session */
00447       iks_insert_attrib(payload_telephone, "id", "101");
00448       iks_insert_attrib(payload_telephone, "name", "telephone-event");
00449       iks_insert_attrib(payload_telephone, "clockrate", "8000");
00450    }
00451    iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
00452 
00453    iks_insert_attrib(iq, "type", "set");
00454    iks_insert_attrib(iq, "to", to);
00455    iks_insert_attrib(iq, "from", from);
00456    iks_insert_attrib(iq, "id", client->connection->mid);
00457    ast_aji_increment_mid(client->connection->mid);
00458 
00459    iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00460    iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00461    /* put the initiator attribute to lower case if we receive the call
00462     * otherwise GoogleTalk won't establish the session */
00463    if (!initiator) {
00464            char c;
00465            char *t = lowerto = ast_strdupa(to);
00466       while (((c = *t) != '/') && (*t++ = tolower(c)));
00467    }
00468    iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
00469    iks_insert_attrib(gtalk, "id", sid);
00470    iks_insert_node(iq, gtalk);
00471    iks_insert_node(gtalk, dcodecs);
00472    iks_insert_node(dcodecs, payload_telephone);
00473 
00474    ast_aji_send(client->connection, iq);
00475 
00476    iks_delete(payload_telephone);
00477    iks_delete(transport);
00478    iks_delete(dcodecs);
00479    iks_delete(gtalk);
00480    iks_delete(iq);
00481    return 1;
00482 }

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

Definition at line 709 of file chan_gtalk.c.

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

Referenced by gtalk_parser().

00710 {
00711    struct gtalk_pvt *tmp;
00712    char *from;
00713 
00714    ast_debug(1, "The client is %s\n", client->name);
00715    /* find corresponding call */
00716    for (tmp = client->p; tmp; tmp = tmp->next) {
00717       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00718          break;
00719       }
00720    }
00721 
00722    from = iks_find_attrib(pak->x, "to");
00723    if (!from) {
00724       from = client->connection->jid->full;
00725    }
00726 
00727    if (tmp) {
00728       gtalk_update_stun(tmp->parent, tmp);
00729    } else {
00730       ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
00731    }
00732 
00733    /* answer 'iq' packet to let the remote peer know that we're alive */
00734    gtalk_response(client, from, pak, NULL, NULL);
00735    return 1;
00736 }

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

Definition at line 631 of file chan_gtalk.c.

References AST_CONTROL_ANSWER, ast_debug, ast_format_cap_is_empty(), ast_format_cap_joint_copy(), 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::cap, gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, gtalk_pvt::jointcap, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercap, gtalk_pvt::rtp, and gtalk_pvt::sid.

Referenced by gtalk_parser().

00632 {
00633    struct gtalk_pvt *tmp = NULL;
00634    char *from;
00635    iks *codec;
00636    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
00637    int peernoncodeccapability;
00638 
00639    ast_debug(1, "The client is %s\n", client->name);
00640 
00641    /* Make sure our new call does exist */
00642    for (tmp = client->p; tmp; tmp = tmp->next) {
00643       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
00644          break;
00645       } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
00646          break;
00647       }
00648    }
00649 
00650    if (!tmp) {
00651       ast_log(LOG_WARNING, "Could not find session in iq\n");
00652       return -1;
00653    }
00654 
00655    /* codec points to the first <payload-type/> tag */
00656    codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
00657    while (codec) {
00658       char *codec_id = iks_find_attrib(codec, "id");
00659       char *codec_name = iks_find_attrib(codec, "name");
00660       if (!codec_id || !codec_name) {
00661          codec = iks_next_tag(codec);
00662          continue;
00663       }
00664 
00665       ast_rtp_codecs_payloads_set_m_type(
00666          ast_rtp_instance_get_codecs(tmp->rtp),
00667          tmp->rtp,
00668          atoi(codec_id));
00669       ast_rtp_codecs_payloads_set_rtpmap_type(
00670          ast_rtp_instance_get_codecs(tmp->rtp),
00671          tmp->rtp,
00672          atoi(codec_id),
00673          "audio",
00674          codec_name,
00675          0);
00676       codec = iks_next_tag(codec);
00677    }
00678 
00679    /* Now gather all of the codecs that we are asked for */
00680    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), tmp->peercap, &peernoncodeccapability);
00681 
00682    /* at this point, we received an answer from the remote Gtalk client,
00683       which allows us to compare capabilities */
00684    ast_format_cap_joint_copy(tmp->cap, tmp->peercap, tmp->jointcap);
00685    if (ast_format_cap_is_empty(tmp->jointcap)) {
00686       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->cap),
00687          ast_getformatname_multiple(s2, BUFSIZ, tmp->peercap),
00688          ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcap));
00689       /* close session if capabilities don't match */
00690       ast_queue_hangup(tmp->owner);
00691 
00692       return -1;
00693 
00694    }
00695 
00696    from = iks_find_attrib(pak->x, "to");
00697    if (!from) {
00698       from = client->connection->jid->full;
00699    }
00700 
00701    if (tmp->owner) {
00702       ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00703    }
00704    gtalk_update_stun(tmp->parent, tmp);
00705    gtalk_response(client, from, pak, NULL, NULL);
00706    return 1;
00707 }

static int gtalk_load_config ( void   )  [static]

Definition at line 2161 of file chan_gtalk.c.

References gtalk::allowguest, ast_aji_client_destroy(), ast_aji_get_clients(), ast_calloc, ast_category_browse(), ast_config_load, ast_copy_string(), ast_format_cap_alloc_nolock(), ast_gethostbyname(), ast_jb_read_conf(), ast_log(), ast_parse_allow_disallow(), ast_parse_arg(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, gtalk::cap, clients, CONFIG_STATUS_FILEINVALID, gtalk::connection, gtalk::context, DEFAULT_PARKINGLOT, global_jbconf, GOOGLE_CONFIG, GOOGLE_JINGLE_NS, GOOGLE_NS, gtalk_create_member(), gtalk_free_candidates(), gtalk_list, gtalk_member_destroy(), gtalk_parser(), gtalk_update_externip(), hp, LOG_ERROR, LOG_WARNING, gtalk::name, ast_variable::name, ast_variable::next, gtalk::parkinglot, PARSE_INADDR, gtalk::prefs, STANDARD_STUN_PORT, stunaddr, gtalk::user, ast_variable::value, and var.

Referenced by load_module().

02162 {
02163    char *cat = NULL;
02164    struct ast_config *cfg = NULL;
02165    struct ast_variable *var;
02166    struct gtalk *member;
02167    struct ast_codec_pref prefs;
02168    struct aji_client_container *clients;
02169    struct gtalk_candidate *global_candidates = NULL;
02170    struct hostent *hp;
02171    struct ast_hostent ahp;
02172    struct ast_flags config_flags = { 0 };
02173 
02174    cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
02175    if (!cfg) {
02176       return 0;
02177    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02178       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", GOOGLE_CONFIG);
02179       return 0;
02180    }
02181 
02182    /* Copy the default jb config over global_jbconf */
02183    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02184 
02185    /* set defaults */
02186    memset(&prefs, 0, sizeof(prefs));
02187    memset(&stunaddr, 0, sizeof(stunaddr));
02188    global_stunaddr = 0;
02189    global_allowguest = DEFAULT_ALLOWGUEST;
02190    ast_copy_string(global_context, DEFAULT_CONTEXT, sizeof(global_context));
02191    ast_copy_string(global_parkinglot, DEFAULT_PARKINGLOT, sizeof(global_parkinglot));
02192 
02193    cat = ast_category_browse(cfg, NULL);
02194    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02195       /* handle jb conf */
02196       if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) {
02197          continue;
02198       }
02199 
02200       if (!strcasecmp(var->name, "allowguest")) {
02201          global_allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
02202       } else if (!strcasecmp(var->name, "disallow")) {
02203          ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
02204       } else if (!strcasecmp(var->name, "allow")) {
02205          ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
02206       } else if (!strcasecmp(var->name, "context")) {
02207          ast_copy_string(global_context, var->value, sizeof(global_context));
02208       } else if (!strcasecmp(var->name, "externip")) {
02209          ast_copy_string(externip, var->value, sizeof(externip));
02210       } else if (!strcasecmp(var->name, "parkinglot")) {
02211          ast_copy_string(global_parkinglot, var->value, sizeof(global_parkinglot));
02212       } else if (!strcasecmp(var->name, "bindaddr")) {
02213          if (!(hp = ast_gethostbyname(var->value, &ahp))) {
02214             ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
02215          } else {
02216             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
02217          }
02218       } else if (!strcasecmp(var->name, "stunaddr")) {
02219          stunaddr.sin_port = htons(STANDARD_STUN_PORT);
02220          global_stunaddr = 1;
02221          if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
02222             ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
02223          }
02224       }
02225    }
02226    while (cat) {
02227       if (strcasecmp(cat, "general")) {
02228          var = ast_variable_browse(cfg, cat);
02229          member = ast_calloc(1, sizeof(*member));
02230          ASTOBJ_INIT(member);
02231          ASTOBJ_WRLOCK(member);
02232          member->cap = ast_format_cap_alloc_nolock();
02233          if (!strcasecmp(cat, "guest")) {
02234             ast_copy_string(member->name, "guest", sizeof(member->name));
02235             ast_copy_string(member->user, "guest", sizeof(member->user));
02236             ast_copy_string(member->context, global_context, sizeof(member->context));
02237             ast_copy_string(member->parkinglot, global_parkinglot, sizeof(member->parkinglot));
02238             member->allowguest = global_allowguest;
02239             member->prefs = prefs;
02240             while (var) {
02241                if (!strcasecmp(var->name, "disallow")) {
02242                   ast_parse_allow_disallow(&member->prefs, member->cap,
02243                                      var->value, 0);
02244                } else if (!strcasecmp(var->name, "allow")) {
02245                   ast_parse_allow_disallow(&member->prefs, member->cap,
02246                                      var->value, 1);
02247                } else if (!strcasecmp(var->name, "context")) {
02248                   ast_copy_string(member->context, var->value,
02249                               sizeof(member->context));
02250                } else if (!strcasecmp(var->name, "parkinglot")) {
02251                   ast_copy_string(member->parkinglot, var->value,
02252                               sizeof(member->parkinglot));
02253                }
02254                var = var->next;
02255             }
02256             ASTOBJ_UNLOCK(member);
02257             clients = ast_aji_get_clients();
02258             if (clients) {
02259                ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
02260                   ASTOBJ_WRLOCK(iterator);
02261                   ASTOBJ_WRLOCK(member);
02262                   if (member->connection) {
02263                      ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
02264                   }
02265                   member->connection = NULL;
02266                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
02267                   iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
02268                   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);
02269                   ASTOBJ_UNLOCK(member);
02270                   ASTOBJ_UNLOCK(iterator);
02271                });
02272                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02273                ASTOBJ_UNREF(member, gtalk_member_destroy);
02274             } else {
02275                ASTOBJ_UNLOCK(member);
02276                ASTOBJ_UNREF(member, gtalk_member_destroy);
02277             }
02278          } else {
02279             ASTOBJ_UNLOCK(member);
02280             if (gtalk_create_member(cat, var, global_allowguest, prefs, global_context, member)) {
02281                ASTOBJ_CONTAINER_LINK(&gtalk_list, member);
02282             }
02283             ASTOBJ_UNREF(member, gtalk_member_destroy);
02284          }
02285       }
02286       cat = ast_category_browse(cfg, cat);
02287    }
02288 
02289    gtalk_update_externip();
02290    gtalk_free_candidates(global_candidates);
02291    return 1;
02292 }

static void gtalk_member_destroy ( struct gtalk obj  )  [static]

Definition at line 248 of file chan_gtalk.c.

References ast_aji_buddy_destroy(), ast_aji_client_destroy(), ast_format_cap_destroy(), ast_free, ASTOBJ_UNREF, gtalk::buddy, gtalk::cap, and gtalk::connection.

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

00249 {
00250    obj->cap = ast_format_cap_destroy(obj->cap);
00251    if (obj->connection) {
00252       ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
00253    }
00254    if (obj->buddy) {
00255       ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
00256    }
00257    ast_free(obj);
00258 }

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

Start new gtalk channel.

Definition at line 1116 of file chan_gtalk.c.

References 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_name(), ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), ast_format_cap_add(), ast_format_cap_is_empty(), ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), ast_format_copy(), AST_FORMAT_GET_TYPE, AST_FORMAT_TYPE_VIDEO, 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_strlen_zero(), ast_channel::caller, gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::cap, 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_jbconf, ast_channel::hangupcause, ast_party_caller::id, ast_format::id, gtalk_pvt::jointcap, gtalk::language, LOG_WARNING, manager_event, gtalk::musicclass, ast_party_id::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, gtalk_pvt::owner, 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().

01117 {
01118    struct ast_channel *tmp;
01119    const char *n2;
01120    struct ast_format_cap *what; /* used as SHALLOW COPY DO NOT DESTROY */
01121    struct ast_format tmpfmt;
01122 
01123    if (title)
01124       n2 = title;
01125    else
01126       n2 = i->us;
01127    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);
01128    if (!tmp) {
01129       ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
01130       return NULL;
01131    }
01132    tmp->tech = &gtalk_tech;
01133 
01134    /* Select our native format based on codec preference until we receive
01135       something from another device to the contrary. */
01136    if (!(ast_format_cap_is_empty(i->jointcap))) {
01137       what = i->jointcap;
01138    } else if (i->cap) {
01139       what = i->cap;
01140    } else {
01141       what = global_capability;
01142    }
01143 
01144    /* Set Frame packetization */
01145    if (i->rtp) {
01146       ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
01147    }
01148 
01149    ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
01150    ast_format_cap_add(tmp->nativeformats, &tmpfmt);
01151 
01152    ast_format_cap_iter_start(i->jointcap);
01153    while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
01154       if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
01155          ast_format_cap_add(tmp->nativeformats, &tmpfmt);
01156       }
01157    }
01158    ast_format_cap_iter_end(i->jointcap);
01159 
01160    if (i->rtp) {
01161       ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
01162       ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
01163    }
01164    if (i->vrtp) {
01165       ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
01166       ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
01167    }
01168    if (state == AST_STATE_RING)
01169       tmp->rings = 1;
01170    tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01171 
01172    ast_best_codec(tmp->nativeformats, &tmpfmt);
01173    ast_format_copy(&tmp->writeformat, &tmpfmt);
01174    ast_format_copy(&tmp->rawwriteformat, &tmpfmt);
01175    ast_format_copy(&tmp->readformat, &tmpfmt);
01176    ast_format_copy(&tmp->rawreadformat, &tmpfmt);
01177    tmp->tech_pvt = i;
01178 
01179    tmp->callgroup = client->callgroup;
01180    tmp->pickupgroup = client->pickupgroup;
01181    tmp->caller.id.name.presentation = client->callingpres;
01182    tmp->caller.id.number.presentation = client->callingpres;
01183    if (!ast_strlen_zero(client->accountcode))
01184       ast_channel_accountcode_set(tmp, client->accountcode);
01185    if (client->amaflags)
01186       tmp->amaflags = client->amaflags;
01187    if (!ast_strlen_zero(client->language))
01188       ast_channel_language_set(tmp, client->language);
01189    if (!ast_strlen_zero(client->musicclass))
01190       ast_channel_musicclass_set(tmp, client->musicclass);
01191    if (!ast_strlen_zero(client->parkinglot))
01192       ast_channel_parkinglot_set(tmp, client->parkinglot);
01193    i->owner = tmp;
01194    ast_module_ref(ast_module_info->self);
01195    ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
01196    ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01197 
01198    if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
01199       tmp->dialed.number.str = ast_strdup(i->exten);
01200    }
01201    tmp->priority = 1;
01202    if (i->rtp)
01203       ast_jb_configure(tmp, &global_jbconf);
01204    if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
01205       ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
01206       tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
01207       ast_hangup(tmp);
01208       tmp = NULL;
01209    } else {
01210       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
01211          "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
01212          i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
01213    }
01214    return tmp;
01215 }

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

Definition at line 1296 of file chan_gtalk.c.

References gtalk_pvt::alreadygone, ast_aji_client_destroy(), ast_aji_get_client(), ast_channel_release(), ast_copy_string(), ast_format_cap_is_empty(), ast_format_cap_joint_copy(), 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, ASTOBJ_UNREF, gtalk_pvt::cap, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_new(), gtalk_response(), aji_client::jid, gtalk_pvt::jointcap, gtalk_pvt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::peercap, gtalk_pvt::rtp, S_OR, gtalk_pvt::sid, gtalk_pvt::them, gtalk_pvt::us, and gtalk_pvt::vrtp.

Referenced by gtalk_parser().

01297 {
01298    struct gtalk_pvt *p, *tmp = client->p;
01299    struct ast_channel *chan;
01300    int res;
01301    iks *codec;
01302    char *from = NULL;
01303    char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
01304    int peernoncodeccapability;
01305    char *sid;
01306 
01307    /* Make sure our new call doesn't exist yet */
01308    from = iks_find_attrib(pak->x,"to");
01309    if (!from) {
01310       from = client->connection->jid->full;
01311    }
01312 
01313    while (tmp) {
01314       if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
01315          (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
01316          ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01317          gtalk_response(client, from, pak, "out-of-order", NULL);
01318          return -1;
01319       }
01320       tmp = tmp->next;
01321    }
01322 
01323    if (!strcasecmp(client->name, "guest")){
01324       /* the guest account is not tied to any configured XMPP client,
01325          let's set it now */
01326       if (client->connection) {
01327          ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01328       }
01329       client->connection = ast_aji_get_client(from);
01330       if (!client->connection) {
01331          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
01332          return -1;
01333       }
01334    }
01335 
01336    if (!(sid = iks_find_attrib(pak->query, "id"))) {
01337       ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
01338       return -1;
01339    }
01340 
01341    p = gtalk_alloc(client, from, pak->from->full, sid);
01342    if (!p) {
01343       ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01344       return -1;
01345    }
01346 
01347    chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
01348    if (!chan) {
01349       gtalk_free_pvt(client, p);
01350       return -1;
01351    }
01352 
01353    ast_mutex_lock(&p->lock);
01354    ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01355    ast_copy_string(p->sid, sid, sizeof(p->sid));
01356 
01357    /* codec points to the first <payload-type/> tag */
01358    codec = iks_first_tag(iks_first_tag(pak->query));
01359 
01360    while (codec) {
01361       char *codec_id = iks_find_attrib(codec, "id");
01362       char *codec_name = iks_find_attrib(codec, "name");
01363       if (!codec_id || !codec_name) {
01364          codec = iks_next_tag(codec);
01365          continue;
01366       }
01367       if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
01368          ast_rtp_codecs_payloads_set_m_type(
01369             ast_rtp_instance_get_codecs(p->vrtp),
01370             p->vrtp,
01371             atoi(codec_id));
01372          ast_rtp_codecs_payloads_set_rtpmap_type(
01373             ast_rtp_instance_get_codecs(p->vrtp),
01374             p->vrtp,
01375             atoi(codec_id),
01376             "video",
01377             codec_name,
01378             0);
01379       } else {
01380          ast_rtp_codecs_payloads_set_m_type(
01381             ast_rtp_instance_get_codecs(p->rtp),
01382             p->rtp,
01383             atoi(codec_id));
01384          ast_rtp_codecs_payloads_set_rtpmap_type(
01385             ast_rtp_instance_get_codecs(p->rtp),
01386             p->rtp,
01387             atoi(codec_id),
01388             "audio",
01389             codec_name,
01390             0);
01391       }
01392       codec = iks_next_tag(codec);
01393    }
01394 
01395    /* Now gather all of the codecs that we are asked for */
01396    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), p->peercap, &peernoncodeccapability);
01397    ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap);
01398    ast_mutex_unlock(&p->lock);
01399 
01400    ast_setstate(chan, AST_STATE_RING);
01401    if (ast_format_cap_is_empty(p->jointcap)) {
01402       ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap),
01403          ast_getformatname_multiple(s2, BUFSIZ, p->peercap),
01404          ast_getformatname_multiple(s3, BUFSIZ, p->jointcap));
01405       /* close session if capabilities don't match */
01406       gtalk_action(client, p, "reject");
01407       p->alreadygone = 1;
01408       gtalk_hangup(chan);
01409       ast_channel_release(chan);
01410       return -1;
01411    }
01412 
01413    res = ast_pbx_start(chan);
01414 
01415    switch (res) {
01416    case AST_PBX_FAILED:
01417       ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01418       gtalk_response(client, from, pak, "service-unavailable", NULL);
01419       break;
01420    case AST_PBX_CALL_LIMIT:
01421       ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01422       gtalk_response(client, from, pak, "service-unavailable", NULL);
01423       break;
01424    case AST_PBX_SUCCESS:
01425       gtalk_response(client, from, pak, NULL, NULL);
01426       gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01427       /* nothing to do */
01428       break;
01429    }
01430 
01431    return 1;
01432 }

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

CLI command "gtalk reload".

Todo:
XXX TODO make this work.

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

02071 {
02072    struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
02073    int res;
02074    iks *tmp;
02075 
02076    if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
02077       ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
02078       pak->query = tmp;
02079    }
02080 
02081    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
02082       ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
02083    }
02084 
02085    if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
02086       ast_log(LOG_NOTICE, "No attribute \"type\" found.  Ignoring message.\n");
02087    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
02088       /* New call */
02089       gtalk_newcall(client, pak);
02090    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
02091       ast_debug(3, "About to add candidate!\n");
02092       res = gtalk_add_candidate(client, pak);
02093       if (!res) {
02094          ast_log(LOG_WARNING, "Could not add any candidate\n");
02095       } else {
02096          ast_debug(3, "Candidate Added!\n");
02097       }
02098    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
02099       gtalk_is_answered(client, pak);
02100    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
02101       gtalk_is_accepted(client, pak);
02102    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
02103       gtalk_handle_dtmf(client, pak);
02104    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
02105       gtalk_hangup_farend(client, pak);
02106    } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
02107       gtalk_hangup_farend(client, pak);
02108    }
02109    ASTOBJ_UNREF(client, gtalk_member_destroy);
02110    return IKS_FILTER_EAT;
02111 }

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

Definition at line 1644 of file chan_gtalk.c.

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

01645 {
01646    struct ast_frame *fr;
01647    struct gtalk_pvt *p = ast->tech_pvt;
01648 
01649    ast_mutex_lock(&p->lock);
01650    fr = gtalk_rtp_read(ast, p);
01651    ast_mutex_unlock(&p->lock);
01652    return fr;
01653 }

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

Part of PBX interface.

Definition at line 1900 of file chan_gtalk.c.

References ast_aji_client_destroy(), ast_aji_get_client(), ast_channel_linkedid(), 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, LOG_ERROR, LOG_WARNING, gtalk::name, strsep(), and gtalk::user.

01901 {
01902    struct gtalk_pvt *p = NULL;
01903    struct gtalk *client = NULL;
01904    char *sender = NULL, *to = NULL, *s = NULL;
01905    struct ast_channel *chan = NULL;
01906 
01907    if (data) {
01908       s = ast_strdupa(data);
01909       if (s) {
01910          sender = strsep(&s, "/");
01911          if (sender && (sender[0] != '\0')) {
01912             to = strsep(&s, "/");
01913          }
01914          if (!to) {
01915             ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", data);
01916             return NULL;
01917          }
01918       }
01919    }
01920 
01921    client = find_gtalk(to, sender);
01922    if (!client) {
01923       ast_log(LOG_WARNING, "Could not find recipient.\n");
01924       return NULL;
01925    }
01926    if (!strcasecmp(client->name, "guest")){
01927       /* the guest account is not tied to any configured XMPP client,
01928          let's set it now */
01929       if (client->connection) {
01930          ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
01931       }
01932       client->connection = ast_aji_get_client(sender);
01933       if (!client->connection) {
01934          ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
01935          ASTOBJ_UNREF(client, gtalk_member_destroy);
01936          return NULL;
01937       }
01938    }
01939 
01940    ASTOBJ_WRLOCK(client);
01941    p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01942    if (p) {
01943       chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
01944    }
01945    ASTOBJ_UNLOCK(client);
01946    return chan;
01947 }

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

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

00600 {
00601    iks *response = NULL, *error = NULL, *reason = NULL;
00602    int res = -1;
00603 
00604    response = iks_new("iq");
00605    if (response) {
00606       iks_insert_attrib(response, "type", "result");
00607       iks_insert_attrib(response, "from", from);
00608       iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
00609       iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
00610       if (reasonstr) {
00611          error = iks_new("error");
00612          if (error) {
00613             iks_insert_attrib(error, "type", "cancel");
00614             reason = iks_new(reasonstr);
00615             if (reason)
00616                iks_insert_node(error, reason);
00617             iks_insert_node(response, error);
00618          }
00619       }
00620       ast_aji_send(client->connection, response);
00621       res = 0;
00622    }
00623 
00624    iks_delete(reason);
00625    iks_delete(error);
00626    iks_delete(response);
00627 
00628    return res;
00629 }

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

Definition at line 484 of file chan_gtalk.c.

References AST_CONTROL_RINGING, ast_copy_string(), ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_create_candidates(), gtalk_invite(), gtalk_pvt::lock, 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().

00485 {
00486    struct gtalk_pvt *p = data;
00487    struct ast_channel *owner;
00488 
00489    ast_mutex_lock(&p->lock);
00490 
00491    if (p->ringrule) {
00492       iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00493    }
00494    p->ringrule = NULL;
00495 
00496    /* this may be a redirect */
00497    if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
00498       char *name = NULL;
00499       char *redirect = NULL;
00500       iks *traversenodes = NULL;
00501       traversenodes = pak->query;
00502       while (traversenodes) {
00503          if (!(name = iks_name(traversenodes))) {
00504             break;
00505          }
00506          if (!strcasecmp(name, "error") &&
00507             ((redirect = iks_find_cdata(traversenodes, "redirect")) ||
00508               (redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
00509             (redirect = strstr(redirect, "xmpp:"))) {
00510             redirect += 5;
00511             ast_debug(1, "redirect %s\n", redirect);
00512             ast_copy_string(p->them, redirect, sizeof(p->them));
00513 
00514             gtalk_invite(p, p->them, p->us, p->sid, 1);
00515             break;
00516          }
00517          traversenodes = iks_next_tag(traversenodes);
00518       }
00519    }
00520    gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
00521    owner = p->owner;
00522    ast_mutex_unlock(&p->lock);
00523 
00524    if (owner) {
00525       ast_queue_control(owner, AST_CONTROL_RINGING);
00526    }
00527 
00528    return IKS_FILTER_EAT;
00529 }

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

Definition at line 1615 of file chan_gtalk.c.

References ast_debug, ast_format_cap_add(), ast_format_cap_iscompatible(), ast_format_cap_remove_bytype(), AST_FORMAT_TYPE_AUDIO, AST_FRAME_VOICE, ast_getformatname(), ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), f, ast_frame_subclass::format, ast_frame::frametype, gtalk_update_stun(), ast_channel::nativeformats, gtalk_pvt::owner, gtalk_pvt::parent, ast_channel::readformat, gtalk_pvt::rtp, ast_frame::subclass, and ast_channel::writeformat.

Referenced by gtalk_read().

01616 {
01617    struct ast_frame *f;
01618 
01619    if (!p->rtp) {
01620       return &ast_null_frame;
01621    }
01622    f = ast_rtp_instance_read(p->rtp, 0);
01623    gtalk_update_stun(p->parent, p);
01624    if (p->owner) {
01625       /* We already hold the channel lock */
01626       if (f->frametype == AST_FRAME_VOICE) {
01627          if (!ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format)) {
01628             ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
01629             ast_format_cap_remove_bytype(p->owner->nativeformats, AST_FORMAT_TYPE_AUDIO);
01630             ast_format_cap_add(p->owner->nativeformats, &f->subclass.format);
01631             ast_set_read_format(p->owner, &p->owner->readformat);
01632             ast_set_write_format(p->owner, &p->owner->writeformat);
01633          }
01634          /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
01635             f = ast_dsp_process(p->owner, p->vad, f);
01636             if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
01637                ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
01638            } */
01639       }
01640    }
01641    return f;
01642 }

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

Definition at line 1846 of file chan_gtalk.c.

References ast_log(), and LOG_NOTICE.

01847 {
01848    ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01849 
01850    return -1;
01851 }

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

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

01737 {
01738    int res = 0;
01739    struct aji_client *client = NULL;
01740    struct gtalk_pvt *p = chan->tech_pvt;
01741 
01742    if (!p->parent) {
01743       ast_log(LOG_ERROR, "Parent channel not found\n");
01744       return -1;
01745    }
01746    if (!p->parent->connection) {
01747       ast_log(LOG_ERROR, "XMPP client not found\n");
01748       return -1;
01749    }
01750    client = p->parent->connection;
01751    res = ast_aji_send_chat(client, p->them, text);
01752    return res;
01753 }

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,
const struct ast_format_cap cap,
int  nat_active 
) [static]

Definition at line 572 of file chan_gtalk.c.

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

00573 {
00574    struct gtalk_pvt *p;
00575 
00576    p = chan->tech_pvt;
00577    if (!p)
00578       return -1;
00579    ast_mutex_lock(&p->lock);
00580 
00581 /* if (rtp)
00582       ast_rtp_get_peer(rtp, &p->redirip);
00583    else
00584       memset(&p->redirip, 0, sizeof(p->redirip));
00585    p->redircodecs = codecs; */
00586 
00587    /* Reset lastrtprx timer */
00588    ast_mutex_unlock(&p->lock);
00589    return 0;
00590 }

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

References AJI_MAX_JIDLEN, ast_cli_args::argc, ast_channel_name(), 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, gtalk_pvt::next, gtalk_pvt::owner, ast_channel::readformat, gtalk_pvt::them, ast_cli_entry::usage, and ast_channel::writeformat.

01951 {
01952 #define FORMAT  "%-30.30s  %-30.30s  %-15.15s  %-5.5s %-5.5s \n"
01953    struct gtalk_pvt *p;
01954    struct ast_channel *chan;
01955    int numchans = 0;
01956    char them[AJI_MAX_JIDLEN];
01957    char *jid = NULL;
01958    char *resource = NULL;
01959 
01960    switch (cmd) {
01961    case CLI_INIT:
01962       e->command = "gtalk show channels";
01963       e->usage =
01964          "Usage: gtalk show channels\n"
01965          "       Shows current state of the Gtalk channels.\n";
01966       return NULL;
01967    case CLI_GENERATE:
01968       return NULL;
01969    }
01970 
01971    if (a->argc != 3)
01972       return CLI_SHOWUSAGE;
01973 
01974    ast_mutex_lock(&gtalklock);
01975    ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
01976    ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
01977       ASTOBJ_WRLOCK(iterator);
01978       p = iterator->p;
01979       while(p) {
01980          chan = p->owner;
01981          ast_copy_string(them, p->them, sizeof(them));
01982          jid = them;
01983          resource = strchr(them, '/');
01984          if (!resource)
01985             resource = "None";
01986          else {
01987             *resource = '\0';
01988             resource ++;
01989          }
01990          if (chan)
01991             ast_cli(a->fd, FORMAT,
01992                ast_channel_name(chan),
01993                jid,
01994                resource,
01995                ast_getformatname(&chan->readformat),
01996                ast_getformatname(&chan->writeformat)
01997                );
01998          else
01999             ast_log(LOG_WARNING, "No available channel\n");
02000          numchans ++;
02001          p = p->next;
02002       }
02003       ASTOBJ_UNLOCK(iterator);
02004    });
02005 
02006    ast_mutex_unlock(&gtalklock);
02007 
02008    ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
02009    return CLI_SUCCESS;
02010 #undef FORMAT
02011 }

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

List global settings for the GoogleTalk channel.

Definition at line 2014 of file chan_gtalk.c.

References ast_cli_args::argc, ast_cli(), AST_CLI_YESNO, ast_getformatname_multiple(), ast_inet_ntoa(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, S_OR, stunaddr, and ast_cli_entry::usage.

02015 {
02016    char codec_buf[BUFSIZ];
02017    switch (cmd) {
02018    case CLI_INIT:
02019       e->command = "gtalk show settings";
02020       e->usage =
02021          "Usage: gtalk show settings\n"
02022          "       Provides detailed list of the configuration on the GoogleTalk channel.\n";
02023       return NULL;
02024    case CLI_GENERATE:
02025       return NULL;
02026    }
02027 
02028    if (a->argc != 3) {
02029       return CLI_SHOWUSAGE;
02030    }
02031 
02032 #define FORMAT "  %-25.20s  %-15.30s\n"
02033 
02034    ast_cli(a->fd, "\nGlobal Settings:\n");
02035    ast_cli(a->fd, "----------------\n");
02036    ast_cli(a->fd, FORMAT, "UDP Bindaddress:", ast_inet_ntoa(bindaddr.sin_addr));
02037    ast_cli(a->fd, FORMAT, "Stun Address:", global_stunaddr != 0 ? ast_inet_ntoa(stunaddr.sin_addr) : "Disabled");
02038    ast_cli(a->fd, FORMAT, "External IP:", S_OR(externip, "Disabled"));
02039    ast_cli(a->fd, FORMAT, "Context:", global_context);
02040    ast_cli(a->fd, FORMAT, "Codecs:", ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, global_capability));
02041    ast_cli(a->fd, FORMAT, "Parking Lot:", global_parkinglot);
02042    ast_cli(a->fd, FORMAT, "Allow Guest:", AST_CLI_YESNO(global_allowguest));
02043    ast_cli(a->fd, "\n----\n");
02044 
02045    return CLI_SUCCESS;
02046 #undef FORMAT
02047 }

static int gtalk_update_externip ( void   )  [static]

Definition at line 1434 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, LOG_WARNING, and stunaddr.

Referenced by gtalk_create_candidates(), and gtalk_load_config().

01435 {
01436    int sock;
01437    char *newaddr;
01438    struct sockaddr_in answer = { 0, };
01439    struct sockaddr_in *dst;
01440    struct ast_sockaddr tmp_dst;
01441 
01442    if (!stunaddr.sin_addr.s_addr) {
01443       return -1;
01444    }
01445    dst = &stunaddr;
01446 
01447    sock = socket(AF_INET, SOCK_DGRAM, 0);
01448    if (sock < 0) {
01449       ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
01450       return -1;
01451    }
01452 
01453    ast_sockaddr_from_sin(&tmp_dst, dst);
01454    if (ast_connect(sock, &tmp_dst) != 0) {
01455       ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
01456       close(sock);
01457       return -1;
01458    }
01459 
01460    if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
01461       close(sock);
01462       return -1;
01463    }
01464 
01465    newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
01466    memcpy(externip, newaddr, sizeof(externip));
01467 
01468    close(sock);
01469    return 0;
01470 
01471 }

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

Definition at line 1473 of file chan_gtalk.c.

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

01474 {
01475    struct gtalk_candidate *tmp;
01476    struct hostent *hp;
01477    struct ast_hostent ahp;
01478    struct sockaddr_in sin = { 0, };
01479    struct sockaddr_in aux = { 0, };
01480    struct ast_sockaddr sin_tmp;
01481    struct ast_sockaddr aux_tmp;
01482 
01483    if (time(NULL) == p->laststun)
01484       return 0;
01485 
01486    tmp = p->theircandidates;
01487    p->laststun = time(NULL);
01488    while (tmp) {
01489       char username[256];
01490 
01491       /* Find the IP address of the host */
01492       if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
01493          ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
01494          tmp = tmp->next;
01495          continue;
01496       }
01497       sin.sin_family = AF_INET;
01498       memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01499       sin.sin_port = htons(tmp->port);
01500       snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
01501 
01502       /* Find out the result of the STUN */
01503       ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
01504       ast_sockaddr_to_sin(&aux_tmp, &aux);
01505 
01506       /* If the STUN result is different from the IP of the hostname,
01507        * lock on the stun IP of the hostname advertised by the
01508        * remote client */
01509       if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
01510          ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
01511       } else {
01512          ast_sockaddr_from_sin(&sin_tmp, &sin);
01513          ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
01514       }
01515       if (aux.sin_addr.s_addr) {
01516          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);
01517          ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
01518       }
01519 
01520       tmp = tmp->next;
01521    }
01522    return 1;
01523 }

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

Send frame to media channel (rtp).

Definition at line 1656 of file chan_gtalk.c.

References ast_format_cap_iscompatible(), 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::format, 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.

01657 {
01658    struct gtalk_pvt *p = ast->tech_pvt;
01659    int res = 0;
01660    char buf[256];
01661 
01662    switch (frame->frametype) {
01663    case AST_FRAME_VOICE:
01664       if (!(ast_format_cap_iscompatible(ast->nativeformats, &frame->subclass.format))) {
01665          ast_log(LOG_WARNING,
01666                "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01667                ast_getformatname(&frame->subclass.format),
01668                ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
01669                ast_getformatname(&ast->readformat),
01670                ast_getformatname(&ast->writeformat));
01671          return 0;
01672       }
01673       if (p) {
01674          ast_mutex_lock(&p->lock);
01675          if (p->rtp) {
01676             res = ast_rtp_instance_write(p->rtp, frame);
01677          }
01678          ast_mutex_unlock(&p->lock);
01679       }
01680       break;
01681    case AST_FRAME_VIDEO:
01682       if (p) {
01683          ast_mutex_lock(&p->lock);
01684          if (p->vrtp) {
01685             res = ast_rtp_instance_write(p->vrtp, frame);
01686          }
01687          ast_mutex_unlock(&p->lock);
01688       }
01689       break;
01690    case AST_FRAME_IMAGE:
01691       return 0;
01692       break;
01693    default:
01694       ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01695             frame->frametype);
01696       return 0;
01697    }
01698 
01699    return res;
01700 }

static int load_module ( void   )  [static]

Load module into PBX, register channel.

Definition at line 2295 of file chan_gtalk.c.

References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), AST_FORMAT_ALAW, ast_format_cap_add(), ast_format_cap_add_all_by_type(), ast_format_cap_alloc(), AST_FORMAT_GSM, AST_FORMAT_H263, ast_format_set(), AST_FORMAT_TYPE_AUDIO, AST_FORMAT_ULAW, ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_glue_register, ast_sched_context_create(), ast_sockaddr_from_sin, ast_sockaddr_ipv4(), ASTOBJ_CONTAINER_INIT, ast_channel_tech::capabilities, free, GOOGLE_CONFIG, gtalk_get_local_ip(), gtalk_list, gtalk_load_config(), io_context_create(), LOG_ERROR, LOG_WARNING, and ast_channel_tech::type.

02296 {
02297    struct ast_sockaddr bindaddr_tmp;
02298    struct ast_sockaddr ourip_tmp;
02299    char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
02300    struct ast_format tmpfmt;
02301 
02302    if (!(gtalk_tech.capabilities = ast_format_cap_alloc())) {
02303       return AST_MODULE_LOAD_DECLINE;
02304    }
02305    if (!(global_capability = ast_format_cap_alloc())) {
02306       return AST_MODULE_LOAD_DECLINE;
02307    }
02308 
02309    ast_format_cap_add_all_by_type(gtalk_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
02310    ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
02311    ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
02312    ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
02313    ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
02314 
02315    free(jabber_loaded);
02316    if (!jabber_loaded) {
02317       /* If embedded, check for a different module name */
02318       jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
02319       free(jabber_loaded);
02320       if (!jabber_loaded) {
02321          ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
02322          return AST_MODULE_LOAD_DECLINE;
02323       }
02324    }
02325 
02326    ASTOBJ_CONTAINER_INIT(&gtalk_list);
02327    if (!gtalk_load_config()) {
02328       ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
02329       return 0;
02330    }
02331 
02332    sched = ast_sched_context_create();
02333    if (!sched) {
02334       ast_log(LOG_WARNING, "Unable to create schedule context\n");
02335    }
02336 
02337    io = io_context_create();
02338    if (!io) {
02339       ast_log(LOG_WARNING, "Unable to create I/O context\n");
02340    }
02341 
02342    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02343    if (gtalk_get_local_ip(&ourip_tmp)) {
02344       ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
02345       return 0;
02346    }
02347    __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
02348 
02349    ast_rtp_glue_register(&gtalk_rtp_glue);
02350    ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02351 
02352    /* Make sure we can register our channel type */
02353    if (ast_channel_register(&gtalk_tech)) {
02354       ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
02355       return -1;
02356    }
02357    return 0;
02358 }

static int unload_module ( void   )  [static]

Reload module.

Todo:
XXX TODO make this work.
Unload the gtalk channel from Asterisk

Definition at line 2369 of file chan_gtalk.c.

References ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_format_cap_destroy(), 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, ast_channel_tech::capabilities, gtalk_list, gtalk_member_destroy(), gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.

02370 {
02371    struct gtalk_pvt *privates = NULL;
02372    ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
02373    /* First, take us out of the channel loop */
02374    ast_channel_unregister(&gtalk_tech);
02375    ast_rtp_glue_unregister(&gtalk_rtp_glue);
02376 
02377    if (!ast_mutex_lock(&gtalklock)) {
02378       /* Hangup all interfaces if they have an owner */
02379       ASTOBJ_CONTAINER_TRAVERSE(&gtalk_list, 1, {
02380          ASTOBJ_WRLOCK(iterator);
02381          privates = iterator->p;
02382          while(privates) {
02383             if (privates->owner)
02384                ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
02385             privates = privates->next;
02386          }
02387          iterator->p = NULL;
02388          ASTOBJ_UNLOCK(iterator);
02389       });
02390       ast_mutex_unlock(&gtalklock);
02391    } else {
02392       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02393       return -1;
02394    }
02395    ASTOBJ_CONTAINER_DESTROYALL(&gtalk_list, gtalk_member_destroy);
02396    ASTOBJ_CONTAINER_DESTROY(&gtalk_list);
02397    global_capability = ast_format_cap_destroy(global_capability);
02398    gtalk_tech.capabilities = ast_format_cap_destroy(gtalk_tech.capabilities);
02399    return 0;
02400 }


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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static]

Definition at line 2407 of file chan_gtalk.c.

struct in_addr __ourip [static]

Definition at line 2407 of file chan_gtalk.c.

struct sockaddr_in bindaddr = { 0, } [static]

const int DEFAULT_ALLOWGUEST = 1 [static]

Definition at line 171 of file chan_gtalk.c.

Referenced by reload_config().

const char DEFAULT_CONTEXT[] = "default" [static]

Definition at line 170 of file chan_gtalk.c.

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 83 of file chan_gtalk.c.

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

Definition at line 169 of file chan_gtalk.c.

char externip[16] [static]

Definition at line 239 of file chan_gtalk.c.

int global_allowguest [static]

Definition at line 242 of file chan_gtalk.c.

Definition at line 173 of file chan_gtalk.c.

char global_context[AST_MAX_CONTEXT] [static]

Definition at line 240 of file chan_gtalk.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 91 of file chan_gtalk.c.

char global_parkinglot[AST_MAX_CONTEXT] [static]

Definition at line 241 of file chan_gtalk.c.

int global_stunaddr [static]

Definition at line 244 of file chan_gtalk.c.

struct ast_cli_entry gtalk_cli[] [static]

Initial value:

 {

   AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
   AST_CLI_DEFINE(gtalk_show_settings, "Show GoogleTalk global settings"),
}

Definition at line 233 of file chan_gtalk.c.

struct gtalk_container gtalk_list [static]

struct ast_rtp_glue gtalk_rtp_glue [static]

Definition at line 592 of file chan_gtalk.c.

struct ast_channel_tech gtalk_tech [static]

PBX interface structure for channel registration.

Definition at line 204 of file chan_gtalk.c.

ast_mutex_t gtalklock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Protect the interface list (of gtalk_pvt's)

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

struct ast_sched_context* sched [static]

The scheduling context

Definition at line 229 of file chan_gtalk.c.

struct sockaddr_in stunaddr [static]

the stun server we get the externip from

Definition at line 243 of file chan_gtalk.c.

Referenced by gtalk_load_config(), gtalk_show_settings(), and gtalk_update_externip().


Generated on Sat Feb 11 06:34:32 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6