Gtalk Channel Driver, until google/libjingle works with jingle spec. More...
#include "asterisk.h"#include <sys/socket.h>#include <fcntl.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/signal.h>#include <iksemel.h>#include <pthread.h>#include <ctype.h>#include "asterisk/lock.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/module.h"#include "asterisk/pbx.h"#include "asterisk/sched.h"#include "asterisk/io.h"#include "asterisk/rtp_engine.h"#include "asterisk/stun.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/file.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/musiconhold.h"#include "asterisk/manager.h"#include "asterisk/stringfields.h"#include "asterisk/utils.h"#include "asterisk/causes.h"#include "asterisk/astobj.h"#include "asterisk/abstract_jb.h"#include "asterisk/jabber.h"#include "asterisk/jingle.h"
Go to the source code of this file.
Data Structures | |
| struct | gtalk |
| struct | gtalk_candidate |
| struct | gtalk_container |
| struct | gtalk_pvt |
Defines | |
| #define | FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n" |
| #define | GOOGLE_CONFIG "gtalk.conf" |
Enumerations | |
| enum | gtalk_connect_type { AJI_CONNECT_STUN = 1, AJI_CONNECT_LOCAL = 2, AJI_CONNECT_RELAY = 3 } |
| enum | gtalk_protocol { AJI_PROTOCOL_UDP = 1, AJI_PROTOCOL_SSLTCP = 2 } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | add_codec_to_answer (const struct gtalk_pvt *p, int codec, iks *dcodecs) |
| static struct gtalk * | find_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_pvt * | gtalk_alloc (struct gtalk *client, const char *us, const char *them, const char *sid) |
| static int | gtalk_answer (struct ast_channel *ast) |
| static int | gtalk_call (struct ast_channel *ast, char *dest, int timeout) |
| Initiate new call, part of PBX interface dest is the dial string. | |
| static int | gtalk_create_candidates (struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to) |
| static int | gtalk_create_member (char *label, struct ast_variable *var, int allowguest, struct ast_codec_pref prefs, char *context, struct gtalk *member) |
| static int | gtalk_digit_begin (struct ast_channel *ast, char digit) |
| static int | gtalk_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | gtalk_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static void | gtalk_free_candidates (struct gtalk_candidate *candidate) |
| static void | gtalk_free_pvt (struct gtalk *client, struct gtalk_pvt *p) |
| static format_t | gtalk_get_codec (struct ast_channel *chan) |
| static int | gtalk_get_local_ip (struct ast_sockaddr *ourip) |
| static enum ast_rtp_glue_result | gtalk_get_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance **instance) |
| static int | gtalk_handle_dtmf (struct gtalk *client, ikspak *pak) |
| static int | gtalk_hangup (struct ast_channel *ast) |
| Hangup a call through the gtalk proxy channel. | |
| static int | gtalk_hangup_farend (struct gtalk *client, ikspak *pak) |
| static int | gtalk_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
| static int | gtalk_invite (struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator) |
| static int | gtalk_is_accepted (struct gtalk *client, ikspak *pak) |
| static int | gtalk_is_answered (struct gtalk *client, ikspak *pak) |
| static int | gtalk_load_config (void) |
| static void | gtalk_member_destroy (struct gtalk *obj) |
| static struct ast_channel * | gtalk_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_frame * | gtalk_read (struct ast_channel *ast) |
| static struct ast_channel * | gtalk_request (const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause) |
| Part of PBX interface. | |
| static int | gtalk_response (struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2) |
| static int | gtalk_ringing_ack (void *data, ikspak *pak) |
| static struct ast_frame * | gtalk_rtp_read (struct ast_channel *ast, struct gtalk_pvt *p) |
| static int | gtalk_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
| static int | gtalk_sendtext (struct ast_channel *ast, const char *text) |
| static int | gtalk_set_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, format_t codecs, int nat_active) |
| static char * | gtalk_show_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command "gtalk show channels". | |
| static int | gtalk_update_externip (void) |
| static int | gtalk_update_stun (struct gtalk *client, struct gtalk_pvt *p) |
| static int | gtalk_write (struct ast_channel *ast, struct ast_frame *frame) |
| Send frame to media channel (rtp) | |
| static int | load_module (void) |
| Load module into PBX, register channel. | |
| static int | unload_module (void) |
| Reload module. | |
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_info * | ast_module_info = &__mod_info |
| static struct sockaddr_in | bindaddr = { 0, } |
| static struct ast_jb_conf | default_jbconf |
| static const char | desc [] = "Gtalk Channel" |
| static char | externip [16] |
| static format_t | global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263 |
| static struct ast_jb_conf | global_jbconf |
| static struct ast_cli_entry | gtalk_cli [] |
| static struct gtalk_container | gtalk_list |
| static struct ast_rtp_glue | gtalk_rtp_glue |
| static struct ast_channel_tech | gtalk_tech |
| PBX interface structure for channel registration. | |
| static ast_mutex_t | gtalklock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
| static struct io_context * | io |
| static struct sched_context * | sched |
| static struct sockaddr_in | stunaddr |
Gtalk Channel Driver, until google/libjingle works with jingle spec.
********** General TODO:s
Support config reloading.
Fix native bridging.
Definition in file chan_gtalk.c.
| #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().
| enum gtalk_connect_type |
Definition at line 98 of file chan_gtalk.c.
{
AJI_CONNECT_STUN = 1,
AJI_CONNECT_LOCAL = 2,
AJI_CONNECT_RELAY = 3,
};
| enum gtalk_protocol |
Definition at line 93 of file chan_gtalk.c.
{
AJI_PROTOCOL_UDP = 1,
AJI_PROTOCOL_SSLTCP = 2,
};
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2300 of file chan_gtalk.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2300 of file chan_gtalk.c.
| static int add_codec_to_answer | ( | const struct gtalk_pvt * | p, |
| int | codec, | ||
| iks * | dcodecs | ||
| ) | [static] |
Definition at line 278 of file chan_gtalk.c.
References ast_getformatname(), ast_log(), format, and LOG_WARNING.
Referenced by gtalk_invite().
{
int res = 0;
char *format = ast_getformatname(codec);
if (!strcasecmp("ulaw", format)) {
iks *payload_eg711u, *payload_pcmu;
payload_pcmu = iks_new("payload-type");
payload_eg711u = iks_new("payload-type");
if(!payload_eg711u || !payload_pcmu) {
iks_delete(payload_pcmu);
iks_delete(payload_eg711u);
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_pcmu, "id", "0");
iks_insert_attrib(payload_pcmu, "name", "PCMU");
iks_insert_attrib(payload_pcmu, "clockrate","8000");
iks_insert_attrib(payload_pcmu, "bitrate","64000");
iks_insert_attrib(payload_eg711u, "id", "100");
iks_insert_attrib(payload_eg711u, "name", "EG711U");
iks_insert_attrib(payload_eg711u, "clockrate","8000");
iks_insert_attrib(payload_eg711u, "bitrate","64000");
iks_insert_node(dcodecs, payload_pcmu);
iks_insert_node(dcodecs, payload_eg711u);
res ++;
}
if (!strcasecmp("alaw", format)) {
iks *payload_eg711a, *payload_pcma;
payload_pcma = iks_new("payload-type");
payload_eg711a = iks_new("payload-type");
if(!payload_eg711a || !payload_pcma) {
iks_delete(payload_eg711a);
iks_delete(payload_pcma);
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_pcma, "id", "8");
iks_insert_attrib(payload_pcma, "name", "PCMA");
iks_insert_attrib(payload_pcma, "clockrate","8000");
iks_insert_attrib(payload_pcma, "bitrate","64000");
payload_eg711a = iks_new("payload-type");
iks_insert_attrib(payload_eg711a, "id", "101");
iks_insert_attrib(payload_eg711a, "name", "EG711A");
iks_insert_attrib(payload_eg711a, "clockrate","8000");
iks_insert_attrib(payload_eg711a, "bitrate","64000");
iks_insert_node(dcodecs, payload_pcma);
iks_insert_node(dcodecs, payload_eg711a);
res ++;
}
if (!strcasecmp("ilbc", format)) {
iks *payload_ilbc = iks_new("payload-type");
if(!payload_ilbc) {
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_ilbc, "id", "97");
iks_insert_attrib(payload_ilbc, "name", "iLBC");
iks_insert_attrib(payload_ilbc, "clockrate","8000");
iks_insert_attrib(payload_ilbc, "bitrate","13300");
iks_insert_node(dcodecs, payload_ilbc);
res ++;
}
if (!strcasecmp("g723", format)) {
iks *payload_g723 = iks_new("payload-type");
if(!payload_g723) {
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_g723, "id", "4");
iks_insert_attrib(payload_g723, "name", "G723");
iks_insert_attrib(payload_g723, "clockrate","8000");
iks_insert_attrib(payload_g723, "bitrate","6300");
iks_insert_node(dcodecs, payload_g723);
res ++;
}
if (!strcasecmp("speex", format)) {
iks *payload_speex = iks_new("payload-type");
if(!payload_speex) {
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_speex, "id", "110");
iks_insert_attrib(payload_speex, "name", "speex");
iks_insert_attrib(payload_speex, "clockrate","8000");
iks_insert_attrib(payload_speex, "bitrate","11000");
iks_insert_node(dcodecs, payload_speex);
res++;
}
if (!strcasecmp("gsm", format)) {
iks *payload_gsm = iks_new("payload-type");
if(!payload_gsm) {
ast_log(LOG_WARNING,"Failed to allocate iks node");
return -1;
}
iks_insert_attrib(payload_gsm, "id", "103");
iks_insert_attrib(payload_gsm, "name", "gsm");
iks_insert_node(dcodecs, payload_gsm);
res++;
}
return res;
}
| static struct gtalk* find_gtalk | ( | char * | name, |
| char * | connection | ||
| ) | [static, read] |
Definition at line 246 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().
{
struct gtalk *gtalk = NULL;
char *domain = NULL , *s = NULL;
if (strchr(connection, '@')) {
s = ast_strdupa(connection);
domain = strsep(&s, "@");
ast_verbose("OOOOH domain = %s\n", domain);
}
gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
if (!gtalk && strchr(name, '@'))
gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
if (!gtalk) {
/* guest call */
ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
ASTOBJ_RDLOCK(iterator);
if (!strcasecmp(iterator->name, "guest")) {
gtalk = iterator;
}
ASTOBJ_UNLOCK(iterator);
if (gtalk)
break;
});
}
return gtalk;
}
| static int gtalk_action | ( | struct gtalk * | client, |
| struct gtalk_pvt * | p, | ||
| const char * | action | ||
| ) | [static] |
Definition at line 1171 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().
{
iks *request, *session = NULL;
int res = -1;
char *lowerthem = NULL;
request = iks_new("iq");
if (request) {
iks_insert_attrib(request, "type", "set");
iks_insert_attrib(request, "from", p->us);
iks_insert_attrib(request, "to", p->them);
iks_insert_attrib(request, "id", client->connection->mid);
ast_aji_increment_mid(client->connection->mid);
session = iks_new("session");
if (session) {
iks_insert_attrib(session, "type", action);
iks_insert_attrib(session, "id", p->sid);
/* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */
if (!p->initiator) {
char c;
char *t = lowerthem = ast_strdupa(p->them);
while (((c = *t) != '/') && (*t++ = tolower(c)));
}
iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem);
iks_insert_attrib(session, "xmlns", GOOGLE_NS);
iks_insert_node(request, session);
ast_aji_send(client->connection, request);
res = 0;
}
}
iks_delete(session);
iks_delete(request);
return res;
}
| static int gtalk_add_candidate | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 1476 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_pvt::next, gtalk_candidate::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().
{
struct gtalk_pvt *p = NULL, *tmp = NULL;
struct aji_client *c = client->connection;
struct gtalk_candidate *newcandidate = NULL;
iks *traversenodes = NULL, *receipt = NULL;
char *from;
from = iks_find_attrib(pak->x,"to");
if (!from) {
from = c->jid->full;
}
for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
p = tmp;
break;
}
}
if (!p) {
return -1;
}
traversenodes = pak->query;
while(traversenodes) {
if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) {
traversenodes = iks_first_tag(traversenodes);
continue;
}
if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) {
traversenodes = iks_child(traversenodes);
continue;
}
if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) {
newcandidate = ast_calloc(1, sizeof(*newcandidate));
if (!newcandidate)
return 0;
ast_copy_string(newcandidate->name,
S_OR(iks_find_attrib(traversenodes, "name"), ""),
sizeof(newcandidate->name));
ast_copy_string(newcandidate->ip,
S_OR(iks_find_attrib(traversenodes, "address"), ""),
sizeof(newcandidate->ip));
newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
ast_copy_string(newcandidate->username,
S_OR(iks_find_attrib(traversenodes, "username"), ""),
sizeof(newcandidate->username));
ast_copy_string(newcandidate->password,
S_OR(iks_find_attrib(traversenodes, "password"), ""),
sizeof(newcandidate->password));
newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp"))
newcandidate->protocol = AJI_PROTOCOL_UDP;
if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp"))
newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun"))
newcandidate->type = AJI_CONNECT_STUN;
if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local"))
newcandidate->type = AJI_CONNECT_LOCAL;
if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay"))
newcandidate->type = AJI_CONNECT_RELAY;
ast_copy_string(newcandidate->network,
S_OR(iks_find_attrib(traversenodes, "network"), ""),
sizeof(newcandidate->network));
newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0"));
newcandidate->next = NULL;
newcandidate->next = p->theircandidates;
p->theircandidates = newcandidate;
p->laststun = 0;
gtalk_update_stun(p->parent, p);
newcandidate = NULL;
}
traversenodes = iks_next_tag(traversenodes);
}
receipt = iks_new("iq");
iks_insert_attrib(receipt, "type", "result");
iks_insert_attrib(receipt, "from", from);
iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
ast_aji_send(c, receipt);
iks_delete(receipt);
return 1;
}
| static struct gtalk_pvt * gtalk_alloc | ( | struct gtalk * | client, |
| const char * | us, | ||
| const char * | them, | ||
| const char * | sid | ||
| ) | [static, read] |
Definition at line 977 of file chan_gtalk.c.
References ast_aji_buddy_destroy(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_random(), ast_rtp_codecs_payloads_clear(), AST_RTP_DTMF_MODE_RFC2833, ast_rtp_instance_dtmf_mode_set(), ast_rtp_instance_get_codecs(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_DTMF, AST_RTP_PROPERTY_RTCP, AST_RTP_PROPERTY_STUN, ast_sockaddr_from_sin, ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNREF, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk_pvt::capability, gtalk::capability, gtalk_pvt::cid_name, gtalk::connection, exten, gtalk_pvt::exten, global_capability, gtalklock, gtalk_pvt::initiator, aji_version::jingle, gtalk_pvt::lock, LOG_ERROR, LOG_WARNING, gtalk::name, aji_resource::next, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_pvt::prefs, gtalk::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().
{
struct gtalk_pvt *tmp = NULL;
struct aji_resource *resources = NULL;
struct aji_buddy *buddy = NULL;
char idroster[200];
char *data, *exten = NULL;
struct ast_sockaddr bindaddr_tmp;
ast_debug(1, "The client is %s for alloc\n", client->name);
if (!sid && !strchr(them, '/')) { /* I started call! */
if (!strcasecmp(client->name, "guest")) {
buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
if (buddy) {
resources = buddy->resources;
}
} else if (client->buddy) {
resources = client->buddy->resources;
}
while (resources) {
if (resources->cap->jingle) {
break;
}
resources = resources->next;
}
if (resources) {
snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
} else if ((*them == '+') || (strstr(them, "@voice.google.com"))) {
snprintf(idroster, sizeof(idroster), "%s", them);
} else {
ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
if (buddy) {
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
}
return NULL;
}
if (buddy) {
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
}
}
if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
return NULL;
}
memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref));
if (sid) {
ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
ast_copy_string(tmp->them, them, sizeof(tmp->them));
ast_copy_string(tmp->us, us, sizeof(tmp->us));
} else {
snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
ast_copy_string(tmp->us, us, sizeof(tmp->us));
tmp->initiator = 1;
}
/* clear codecs */
bindaddr.sin_family = AF_INET;
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) {
ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
ast_free(tmp);
return NULL;
}
ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1);
ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1);
ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833);
ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
/* add user configured codec capabilites */
if (client->capability) {
tmp->capability = client->capability;
} else if (global_capability) {
tmp->capability = global_capability;
}
tmp->parent = client;
if (!tmp->rtp) {
ast_log(LOG_WARNING, "Out of RTP sessions?\n");
ast_free(tmp);
return NULL;
}
/* Set CALLERID(name) to the full JID of the remote peer */
ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name));
if(strchr(tmp->us, '/')) {
data = ast_strdupa(tmp->us);
exten = strsep(&data, "/");
} else {
exten = tmp->us;
}
ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
ast_mutex_init(&tmp->lock);
ast_mutex_lock(>alklock);
tmp->next = client->p;
client->p = tmp;
ast_mutex_unlock(>alklock);
return tmp;
}
| static int gtalk_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 508 of file chan_gtalk.c.
References ast_debug, ast_mutex_lock, ast_mutex_unlock, EVENT_FLAG_SYSTEM, gtalk_invite(), gtalk_pvt::lock, manager_event, ast_channel::name, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.
{
struct gtalk_pvt *p = ast->tech_pvt;
int res = 0;
ast_debug(1, "Answer!\n");
ast_mutex_lock(&p->lock);
gtalk_invite(p, p->them, p->us,p->sid, 0);
manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
ast->name, "GTALK", p->sid);
ast_mutex_unlock(&p->lock);
return res;
}
| static int gtalk_call | ( | struct ast_channel * | ast, |
| char * | dest, | ||
| int | timeout | ||
| ) | [static] |
Initiate new call, part of PBX interface dest is the dial string.
Definition at line 1806 of file chan_gtalk.c.
References ast_channel::_state, ast_copy_string(), ast_log(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RING, gtalk::connection, aji_client::f, gtalk_invite(), gtalk_ringing_ack(), LOG_WARNING, aji_client::mid, ast_channel::name, gtalk_pvt::parent, gtalk_pvt::ring, gtalk_pvt::ringrule, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.
{
struct gtalk_pvt *p = ast->tech_pvt;
if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
return -1;
}
ast_setstate(ast, AST_STATE_RING);
if (!p->ringrule) {
ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
IKS_RULE_ID, p->ring, IKS_RULE_DONE);
} else {
ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
}
gtalk_invite(p, p->them, p->us, p->sid, 1);
return 0;
}
| static int gtalk_create_candidates | ( | struct gtalk * | client, |
| struct gtalk_pvt * | p, | ||
| char * | sid, | ||
| char * | from, | ||
| char * | to | ||
| ) | [static] |
Definition at line 840 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_pvt::next, gtalk_candidate::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().
{
struct gtalk_candidate *tmp;
struct aji_client *c = client->connection;
struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
struct sockaddr_in sin = { 0, };
struct ast_sockaddr sin_tmp;
struct ast_sockaddr us;
iks *iq, *gtalk, *candidate, *transport;
char user[17], pass[17], preference[5], port[7];
char *lowerfrom = NULL;
iq = iks_new("iq");
gtalk = iks_new("session");
candidate = iks_new("candidate");
transport = iks_new("transport");
if (!iq || !gtalk || !candidate || !transport) {
ast_log(LOG_ERROR, "Memory allocation error\n");
goto safeout;
}
ours1 = ast_calloc(1, sizeof(*ours1));
ours2 = ast_calloc(1, sizeof(*ours2));
if (!ours1 || !ours2)
goto safeout;
iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS);
iks_insert_node(iq, gtalk);
iks_insert_node(gtalk,candidate);
iks_insert_node(gtalk,transport);
for (; p; p = p->next) {
if (!strcasecmp(p->sid, sid))
break;
}
if (!p) {
ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
goto safeout;
}
ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
ast_sockaddr_to_sin(&sin_tmp, &sin);
gtalk_get_local_ip(&us);
if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) {
ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute.");
}
/* Setup our gtalk candidates */
ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
ours1->port = ntohs(sin.sin_port);
ours1->preference = 1;
snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
ast_copy_string(ours1->username, user, sizeof(ours1->username));
ast_copy_string(ours1->password, pass, sizeof(ours1->password));
ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us),
sizeof(ours1->ip));
ours1->protocol = AJI_PROTOCOL_UDP;
ours1->type = AJI_CONNECT_LOCAL;
ours1->generation = 0;
p->ourcandidates = ours1;
/* XXX this is a blocking action. We send a STUN request to the server
* and wait for the response. If blocking here is a problem the STUN requests/responses
* for the externip may need to be done differently. */
gtalk_update_externip();
if (!ast_strlen_zero(externip)) {
ast_copy_string(ours2->username, user, sizeof(ours2->username));
ast_copy_string(ours2->password, pass, sizeof(ours2->password));
ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
ours2->port = ntohs(sin.sin_port);
ours2->preference = 0.9;
ours2->protocol = AJI_PROTOCOL_UDP;
ours2->type = AJI_CONNECT_STUN;
ours2->generation = 0;
ours1->next = ours2;
ours2 = NULL;
}
ours1 = NULL;
for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
snprintf(port, sizeof(port), "%d", tmp->port);
snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
iks_insert_attrib(iq, "from", to);
iks_insert_attrib(iq, "to", from);
iks_insert_attrib(iq, "type", "set");
iks_insert_attrib(iq, "id", c->mid);
ast_aji_increment_mid(c->mid);
iks_insert_attrib(gtalk, "type", "candidates");
iks_insert_attrib(gtalk, "id", sid);
/* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */
if (!p->initiator) {
char c;
char *t = lowerfrom = ast_strdupa(from);
while (((c = *t) != '/') && (*t++ = tolower(c)));
}
iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom);
iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
iks_insert_attrib(candidate, "name", tmp->name);
iks_insert_attrib(candidate, "address", tmp->ip);
iks_insert_attrib(candidate, "port", port);
iks_insert_attrib(candidate, "username", tmp->username);
iks_insert_attrib(candidate, "password", tmp->password);
iks_insert_attrib(candidate, "preference", preference);
if (tmp->protocol == AJI_PROTOCOL_UDP)
iks_insert_attrib(candidate, "protocol", "udp");
if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
iks_insert_attrib(candidate, "protocol", "ssltcp");
if (tmp->type == AJI_CONNECT_STUN)
iks_insert_attrib(candidate, "type", "stun");
if (tmp->type == AJI_CONNECT_LOCAL)
iks_insert_attrib(candidate, "type", "local");
if (tmp->type == AJI_CONNECT_RELAY)
iks_insert_attrib(candidate, "type", "relay");
iks_insert_attrib(candidate, "network", "0");
iks_insert_attrib(candidate, "generation", "0");
ast_aji_send(c, iq);
}
p->laststun = 0;
safeout:
if (ours1)
ast_free(ours1);
if (ours2)
ast_free(ours2);
iks_delete(iq);
iks_delete(gtalk);
iks_delete(candidate);
iks_delete(transport);
return 1;
}
| 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 2028 of file chan_gtalk.c.
References gtalk::allowguest, aji_client::allowguest, ast_aji_get_client(), ast_copy_string(), ast_log(), ast_parse_allow_disallow(), ASTOBJ_CONTAINER_FIND, aji_client::buddies, gtalk::buddy, gtalk::capability, gtalk::connection, gtalk::context, aji_client::f, GOOGLE_NS, gtalk_parser(), LOG_ERROR, LOG_WARNING, ast_variable::name, gtalk::name, ast_variable::next, gtalk::parkinglot, gtalk::prefs, prefs, gtalk::user, and ast_variable::value.
Referenced by gtalk_load_config().
{
struct aji_client *client;
if (!member)
ast_log(LOG_WARNING, "Out of memory.\n");
ast_copy_string(member->name, label, sizeof(member->name));
ast_copy_string(member->user, label, sizeof(member->user));
ast_copy_string(member->context, context, sizeof(member->context));
member->allowguest = allowguest;
member->prefs = prefs;
while (var) {
if (!strcasecmp(var->name, "username"))
ast_copy_string(member->user, var->value, sizeof(member->user));
else if (!strcasecmp(var->name, "disallow"))
ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
else if (!strcasecmp(var->name, "allow"))
ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
else if (!strcasecmp(var->name, "context"))
ast_copy_string(member->context, var->value, sizeof(member->context));
else if (!strcasecmp(var->name, "parkinglot"))
ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot));
else if (!strcasecmp(var->name, "connection")) {
if ((client = ast_aji_get_client(var->value))) {
member->connection = client;
iks_filter_add_rule(client->f, gtalk_parser, member,
IKS_RULE_TYPE, IKS_PAK_IQ,
IKS_RULE_FROM_PARTIAL, member->user,
IKS_RULE_NS, GOOGLE_NS,
IKS_RULE_DONE);
} else {
ast_log(LOG_ERROR, "connection referenced not found!\n");
return 0;
}
}
var = var->next;
}
if (member->connection && member->user)
member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
else {
ast_log(LOG_ERROR, "No Connection or Username!\n");
}
return 1;
}
| static int gtalk_digit_begin | ( | struct ast_channel * | ast, |
| char | digit | ||
| ) | [static] |
Definition at line 1706 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.
{
struct gtalk_pvt *p = chan->tech_pvt;
int res = 0;
ast_mutex_lock(&p->lock);
if (p->rtp) {
ast_rtp_instance_dtmf_begin(p->rtp, digit);
} else {
res = -1;
}
ast_mutex_unlock(&p->lock);
return res;
}
| static int gtalk_digit_end | ( | struct ast_channel * | ast, |
| char | digit, | ||
| unsigned int | duration | ||
| ) | [static] |
Definition at line 1722 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.
{
struct gtalk_pvt *p = chan->tech_pvt;
int res = 0;
ast_mutex_lock(&p->lock);
if (p->rtp) {
ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration);
} else {
res = -1;
}
ast_mutex_unlock(&p->lock);
return res;
}
| static int gtalk_fixup | ( | struct ast_channel * | oldchan, |
| struct ast_channel * | newchan | ||
| ) | [static] |
Definition at line 1653 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, gtalk_pvt::owner, and ast_channel::tech_pvt.
{
struct gtalk_pvt *p = newchan->tech_pvt;
ast_mutex_lock(&p->lock);
if ((p->owner != oldchan)) {
ast_mutex_unlock(&p->lock);
return -1;
}
if (p->owner == oldchan)
p->owner = newchan;
ast_mutex_unlock(&p->lock);
return 0;
}
| static void gtalk_free_candidates | ( | struct gtalk_candidate * | candidate | ) | [static] |
Definition at line 1209 of file chan_gtalk.c.
References ast_free, last, and gtalk_candidate::next.
Referenced by gtalk_free_pvt(), and gtalk_load_config().
{
struct gtalk_candidate *last;
while (candidate) {
last = candidate;
candidate = candidate->next;
ast_free(last);
}
}
Definition at line 1219 of file chan_gtalk.c.
References ast_free, ast_log(), ast_rtp_instance_destroy(), gtalk::connection, aji_client::f, gtalk_free_candidates(), LOG_WARNING, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::ringrule, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_pvt::vrtp.
Referenced by gtalk_hangup(), and gtalk_newcall().
{
struct gtalk_pvt *cur, *prev = NULL;
cur = client->p;
while (cur) {
if (cur == p) {
if (prev)
prev->next = p->next;
else
client->p = p->next;
break;
}
prev = cur;
cur = cur->next;
}
if (p->ringrule)
iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
if (p->owner)
ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
if (p->rtp)
ast_rtp_instance_destroy(p->rtp);
if (p->vrtp)
ast_rtp_instance_destroy(p->vrtp);
gtalk_free_candidates(p->theircandidates);
ast_free(p);
}
| static format_t gtalk_get_codec | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 541 of file chan_gtalk.c.
References gtalk_pvt::peercapability, and ast_channel::tech_pvt.
{
struct gtalk_pvt *p = chan->tech_pvt;
return p->peercapability;
}
| static int gtalk_get_local_ip | ( | struct ast_sockaddr * | ourip | ) | [static] |
Definition at line 812 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().
{
struct ast_sockaddr root;
struct ast_sockaddr bindaddr_tmp;
struct ast_sockaddr *addrs;
int addrs_cnt;
/* If bind address is not 0.0.0.0, then bindaddr is our local ip. */
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
if (!ast_sockaddr_is_any(&bindaddr_tmp)) {
ast_sockaddr_copy(ourip, &bindaddr_tmp);
return 0;
}
/* If no bind address was provided, lets see what ip we would use to connect to google.com and use that.
* If you can't resolve google.com from your network, then this module is useless for you anyway. */
if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) {
ast_sockaddr_copy(&root, &addrs[0]);
ast_free(addrs);
if (!ast_ouraddrfor(&root, ourip)) {
return 0;
}
}
/* As a last resort, use this function to find our local address. */
return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET);
}
| static enum ast_rtp_glue_result gtalk_get_rtp_peer | ( | struct ast_channel * | chan, |
| struct ast_rtp_instance ** | instance | ||
| ) | [static] |
Definition at line 522 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.
{
struct gtalk_pvt *p = chan->tech_pvt;
enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
if (!p)
return res;
ast_mutex_lock(&p->lock);
if (p->rtp){
ao2_ref(p->rtp, +1);
*instance = p->rtp;
res = AST_RTP_GLUE_RESULT_LOCAL;
}
ast_mutex_unlock(&p->lock);
return res;
}
| static int gtalk_handle_dtmf | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 713 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().
{
struct gtalk_pvt *tmp;
iks *dtmfnode = NULL, *dtmfchild = NULL;
char *dtmf;
char *from;
/* Make sure our new call doesn't exist yet */
for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid))
break;
}
from = iks_find_attrib(pak->x, "to");
if (!from) {
from = client->connection->jid->full;
}
if (tmp) {
if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
gtalk_response(client, from, pak,
"feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
"unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
return -1;
}
if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
f.subclass.integer = dtmf[0];
ast_queue_frame(tmp->owner, &f);
ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
} else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
struct ast_frame f = {AST_FRAME_DTMF_END, };
f.subclass.integer = dtmf[0];
ast_queue_frame(tmp->owner, &f);
ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
} else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
struct ast_frame f = {AST_FRAME_DTMF, };
f.subclass.integer = dtmf[0];
ast_queue_frame(tmp->owner, &f);
ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
}
}
} else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) {
if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
struct ast_frame f = {AST_FRAME_DTMF_END, };
f.subclass.integer = dtmf[0];
ast_queue_frame(tmp->owner, &f);
ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
} else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
f.subclass.integer = dtmf[0];
ast_queue_frame(tmp->owner, &f);
ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer);
}
}
}
}
gtalk_response(client, from, pak, NULL, NULL);
return 1;
} else {
ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
}
gtalk_response(client, from, pak, NULL, NULL);
return 1;
}
| static int gtalk_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the gtalk proxy channel.
Definition at line 1830 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, ast_module_info::self, and ast_channel::tech_pvt.
Referenced by gtalk_newcall().
{
struct gtalk_pvt *p = ast->tech_pvt;
struct gtalk *client;
ast_mutex_lock(&p->lock);
client = p->parent;
p->owner = NULL;
ast->tech_pvt = NULL;
if (!p->alreadygone) {
gtalk_action(client, p, "terminate");
}
ast_mutex_unlock(&p->lock);
gtalk_free_pvt(client, p);
ast_module_unref(ast_module_info->self);
return 0;
}
| static int gtalk_hangup_farend | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 782 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().
{
struct gtalk_pvt *tmp;
char *from;
ast_debug(1, "The client is %s\n", client->name);
/* Make sure our new call doesn't exist yet */
for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
break;
}
}
from = iks_find_attrib(pak->x, "to");
if (!from) {
from = client->connection->jid->full;
}
if (tmp) {
tmp->alreadygone = 1;
if (tmp->owner) {
ast_queue_hangup(tmp->owner);
}
} else {
ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n");
}
gtalk_response(client, from, pak, NULL, NULL);
return 1;
}
| static int gtalk_indicate | ( | struct ast_channel * | ast, |
| int | condition, | ||
| const void * | data, | ||
| size_t | datalen | ||
| ) | [static] |
Definition at line 1668 of file chan_gtalk.c.
References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, ast_moh_start(), and ast_moh_stop().
{
int res = 0;
switch (condition) {
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, NULL);
break;
case AST_CONTROL_UNHOLD:
ast_moh_stop(ast);
break;
default:
ast_debug(3, "Don't know how to indicate condition '%d'\n", condition);
res = -1;
}
return res;
}
| static int gtalk_invite | ( | struct gtalk_pvt * | p, |
| char * | to, | ||
| char * | from, | ||
| char * | sid, | ||
| int | initiator | ||
| ) | [static] |
Definition at line 383 of file chan_gtalk.c.
References add_codec_to_answer(), ast_aji_increment_mid(), ast_aji_send(), ast_codec_pref_index(), ast_log(), ast_strdupa, gtalk::capability, gtalk::connection, GOOGLE_AUDIO_NS, GOOGLE_NS, GOOGLE_TRANSPORT_NS, LOG_ERROR, aji_client::mid, gtalk_pvt::parent, and gtalk::prefs.
Referenced by gtalk_answer(), gtalk_call(), and gtalk_ringing_ack().
{
struct gtalk *client = p->parent;
iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
int x;
int pref_codec = 0;
int alreadysent = 0;
int codecs_num = 0;
char *lowerto = NULL;
iq = iks_new("iq");
gtalk = iks_new("session");
dcodecs = iks_new("description");
transport = iks_new("transport");
payload_telephone = iks_new("payload-type");
if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
iks_delete(iq);
iks_delete(gtalk);
iks_delete(dcodecs);
iks_delete(transport);
iks_delete(payload_telephone);
ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
return 0;
}
iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS);
iks_insert_attrib(dcodecs, "xml:lang", "en");
for (x = 0; x < 64; x++) {
if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
break;
if (!(client->capability & pref_codec))
continue;
if (alreadysent & pref_codec)
continue;
codecs_num = add_codec_to_answer(p, pref_codec, dcodecs);
alreadysent |= pref_codec;
}
if (codecs_num) {
/* only propose DTMF within an audio session */
iks_insert_attrib(payload_telephone, "id", "101");
iks_insert_attrib(payload_telephone, "name", "telephone-event");
iks_insert_attrib(payload_telephone, "clockrate", "8000");
}
iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS);
iks_insert_attrib(iq, "type", "set");
iks_insert_attrib(iq, "to", to);
iks_insert_attrib(iq, "from", from);
iks_insert_attrib(iq, "id", client->connection->mid);
ast_aji_increment_mid(client->connection->mid);
iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
/* put the initiator attribute to lower case if we receive the call
* otherwise GoogleTalk won't establish the session */
if (!initiator) {
char c;
char *t = lowerto = ast_strdupa(to);
while (((c = *t) != '/') && (*t++ = tolower(c)));
}
iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto);
iks_insert_attrib(gtalk, "id", sid);
iks_insert_node(iq, gtalk);
iks_insert_node(gtalk, dcodecs);
iks_insert_node(dcodecs, payload_telephone);
ast_aji_send(client->connection, iq);
iks_delete(payload_telephone);
iks_delete(transport);
iks_delete(dcodecs);
iks_delete(gtalk);
iks_delete(iq);
return 1;
}
| static int gtalk_is_accepted | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 684 of file chan_gtalk.c.
References ast_log(), gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, LOG_DEBUG, LOG_NOTICE, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, and gtalk_pvt::sid.
Referenced by gtalk_parser().
{
struct gtalk_pvt *tmp;
char *from;
ast_log(LOG_DEBUG, "The client is %s\n", client->name);
/* find corresponding call */
for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
break;
}
}
from = iks_find_attrib(pak->x, "to");
if (!from) {
from = client->connection->jid->full;
}
if (tmp) {
gtalk_update_stun(tmp->parent, tmp);
} else {
ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n");
}
/* answer 'iq' packet to let the remote peer know that we're alive */
gtalk_response(client, from, pak, NULL, NULL);
return 1;
}
| static int gtalk_is_answered | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 606 of file chan_gtalk.c.
References AST_CONTROL_ANSWER, ast_getformatname_multiple(), ast_log(), ast_queue_control(), ast_queue_hangup(), ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), gtalk_pvt::capability, gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, gtalk_pvt::jointcapability, LOG_DEBUG, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercapability, gtalk_pvt::rtp, and gtalk_pvt::sid.
Referenced by gtalk_parser().
{
struct gtalk_pvt *tmp = NULL;
char *from;
iks *codec;
char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
int peernoncodeccapability;
ast_log(LOG_DEBUG, "The client is %s\n", client->name);
/* Make sure our new call does exist */
for (tmp = client->p; tmp; tmp = tmp->next) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
break;
} else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) {
break;
}
}
if (!tmp) {
ast_log(LOG_WARNING, "Could not find session in iq\n");
return -1;
}
/* codec points to the first <payload-type/> tag */
codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
while (codec) {
char *codec_id = iks_find_attrib(codec, "id");
char *codec_name = iks_find_attrib(codec, "name");
if (!codec_id || !codec_name) {
codec = iks_next_tag(codec);
continue;
}
ast_rtp_codecs_payloads_set_m_type(
ast_rtp_instance_get_codecs(tmp->rtp),
tmp->rtp,
atoi(codec_id));
ast_rtp_codecs_payloads_set_rtpmap_type(
ast_rtp_instance_get_codecs(tmp->rtp),
tmp->rtp,
atoi(codec_id),
"audio",
codec_name,
0);
codec = iks_next_tag(codec);
}
/* Now gather all of the codecs that we are asked for */
ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability);
/* at this point, we received an awser from the remote Gtalk client,
which allows us to compare capabilities */
tmp->jointcapability = tmp->capability & tmp->peercapability;
if (!tmp->jointcapability) {
ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability),
ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability),
ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability));
/* close session if capabilities don't match */
ast_queue_hangup(tmp->owner);
return -1;
}
from = iks_find_attrib(pak->x, "to");
if (!from) {
from = client->connection->jid->full;
}
if (tmp->owner) {
ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
}
gtalk_update_stun(tmp->parent, tmp);
gtalk_response(client, from, pak, NULL, NULL);
return 1;
}
| static int gtalk_load_config | ( | void | ) | [static] |
Definition at line 2076 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_gethostbyname(), ast_jb_read_conf(), ast_log(), AST_MAX_CONTEXT, 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::capability, clients, CONFIG_STATUS_FILEINVALID, gtalk::connection, context, gtalk::context, 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, ast_variable::name, gtalk::name, ast_variable::next, gtalk::parkinglot, parkinglot, PARSE_INADDR, gtalk::prefs, prefs, STANDARD_STUN_PORT, stunaddr, gtalk::user, ast_variable::value, and var.
Referenced by load_module().
{
char *cat = NULL;
struct ast_config *cfg = NULL;
char context[AST_MAX_CONTEXT];
char parkinglot[AST_MAX_CONTEXT];
int allowguest = 1;
struct ast_variable *var;
struct gtalk *member;
struct ast_codec_pref prefs;
struct aji_client_container *clients;
struct gtalk_candidate *global_candidates = NULL;
struct hostent *hp;
struct ast_hostent ahp;
struct ast_flags config_flags = { 0 };
cfg = ast_config_load(GOOGLE_CONFIG, config_flags);
if (!cfg) {
return 0;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG);
return 0;
}
/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
/* set defaults */
memset(&stunaddr, 0, sizeof(stunaddr));
cat = ast_category_browse(cfg, NULL);
for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
/* handle jb conf */
if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
continue;
if (!strcasecmp(var->name, "allowguest")) {
allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
} else if (!strcasecmp(var->name, "disallow")) {
ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
} else if (!strcasecmp(var->name, "allow")) {
ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
} else if (!strcasecmp(var->name, "context")) {
ast_copy_string(context, var->value, sizeof(context));
} else if (!strcasecmp(var->name, "externip")) {
ast_copy_string(externip, var->value, sizeof(externip));
} else if (!strcasecmp(var->name, "parkinglot")) {
ast_copy_string(parkinglot, var->value, sizeof(parkinglot));
} else if (!strcasecmp(var->name, "bindaddr")) {
if (!(hp = ast_gethostbyname(var->value, &ahp))) {
ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
} else {
memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
}
} else if (!strcasecmp(var->name, "stunaddr")) {
stunaddr.sin_port = htons(STANDARD_STUN_PORT);
if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) {
ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value);
}
}
}
while (cat) {
if (strcasecmp(cat, "general")) {
var = ast_variable_browse(cfg, cat);
member = ast_calloc(1, sizeof(*member));
ASTOBJ_INIT(member);
ASTOBJ_WRLOCK(member);
if (!strcasecmp(cat, "guest")) {
ast_copy_string(member->name, "guest", sizeof(member->name));
ast_copy_string(member->user, "guest", sizeof(member->user));
ast_copy_string(member->context, context, sizeof(member->context));
ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot));
member->allowguest = allowguest;
member->prefs = prefs;
while (var) {
if (!strcasecmp(var->name, "disallow")) {
ast_parse_allow_disallow(&member->prefs, &member->capability,
var->value, 0);
} else if (!strcasecmp(var->name, "allow")) {
ast_parse_allow_disallow(&member->prefs, &member->capability,
var->value, 1);
} else if (!strcasecmp(var->name, "context")) {
ast_copy_string(member->context, var->value,
sizeof(member->context));
} else if (!strcasecmp(var->name, "parkinglot")) {
ast_copy_string(member->parkinglot, var->value,
sizeof(member->parkinglot));
}
var = var->next;
}
ASTOBJ_UNLOCK(member);
clients = ast_aji_get_clients();
if (clients) {
ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
ASTOBJ_WRLOCK(iterator);
ASTOBJ_WRLOCK(member);
if (member->connection) {
ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
}
member->connection = NULL;
iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);
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);
ASTOBJ_UNLOCK(member);
ASTOBJ_UNLOCK(iterator);
});
ASTOBJ_CONTAINER_LINK(>alk_list, member);
ASTOBJ_UNREF(member, gtalk_member_destroy);
} else {
ASTOBJ_UNLOCK(member);
ASTOBJ_UNREF(member, gtalk_member_destroy);
}
} else {
ASTOBJ_UNLOCK(member);
if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
ASTOBJ_CONTAINER_LINK(>alk_list, member);
ASTOBJ_UNREF(member, gtalk_member_destroy);
}
}
cat = ast_category_browse(cfg, cat);
}
gtalk_update_externip();
gtalk_free_candidates(global_candidates);
return 1;
}
| static void gtalk_member_destroy | ( | struct gtalk * | obj | ) | [static] |
Definition at line 241 of file chan_gtalk.c.
References ast_free.
Referenced by gtalk_load_config(), gtalk_parser(), gtalk_request(), and unload_module().
{
ast_free(obj);
}
| 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 1081 of file chan_gtalk.c.
References gtalk::accountcode, accountcode, ast_channel::adsicpe, gtalk::amaflags, ast_channel::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc(), ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), AST_FORMAT_VIDEO_MASK, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_random(), ast_rtp_codecs_packetization_set(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::caller, gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, gtalk_pvt::cid_name, gtalk_pvt::cid_num, gtalk::context, ast_channel::context, ast_channel::dialed, EVENT_FLAG_SYSTEM, gtalk_pvt::exten, ast_channel::exten, global_capability, global_jbconf, gtalk_tech, ast_channel::hangupcause, ast_party_caller::id, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_party_id::name, ast_channel::name, ast_channel::nativeformats, ast_party_id::number, ast_party_dialed::number, gtalk_pvt::owner, gtalk::parkinglot, parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_party_name::presentation, ast_party_number::presentation, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, ast_module_info::self, 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().
{
struct ast_channel *tmp;
int fmt;
int what;
const char *n2;
if (title)
n2 = title;
else
n2 = i->us;
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);
if (!tmp) {
ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
return NULL;
}
tmp->tech = >alk_tech;
/* Select our native format based on codec preference until we receive
something from another device to the contrary. */
if (i->jointcapability)
what = i->jointcapability;
else if (i->capability)
what = i->capability;
else
what = global_capability;
/* Set Frame packetization */
if (i->rtp) {
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
}
tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
fmt = ast_best_codec(tmp->nativeformats);
if (i->rtp) {
ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
}
if (i->vrtp) {
ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
}
if (state == AST_STATE_RING)
tmp->rings = 1;
tmp->adsicpe = AST_ADSI_UNAVAILABLE;
tmp->writeformat = fmt;
tmp->rawwriteformat = fmt;
tmp->readformat = fmt;
tmp->rawreadformat = fmt;
tmp->tech_pvt = i;
tmp->callgroup = client->callgroup;
tmp->pickupgroup = client->pickupgroup;
tmp->caller.id.name.presentation = client->callingpres;
tmp->caller.id.number.presentation = client->callingpres;
if (!ast_strlen_zero(client->accountcode))
ast_string_field_set(tmp, accountcode, client->accountcode);
if (client->amaflags)
tmp->amaflags = client->amaflags;
if (!ast_strlen_zero(client->language))
ast_string_field_set(tmp, language, client->language);
if (!ast_strlen_zero(client->musicclass))
ast_string_field_set(tmp, musicclass, client->musicclass);
if (!ast_strlen_zero(client->parkinglot))
ast_string_field_set(tmp, parkinglot, client->parkinglot);
i->owner = tmp;
ast_module_ref(ast_module_info->self);
ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
tmp->dialed.number.str = ast_strdup(i->exten);
}
tmp->priority = 1;
if (i->rtp)
ast_jb_configure(tmp, &global_jbconf);
if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
ast_hangup(tmp);
tmp = NULL;
} else {
manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
"Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
i->owner ? i->owner->name : "", "Gtalk", i->sid);
}
return tmp;
}
| static int gtalk_newcall | ( | struct gtalk * | client, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 1247 of file chan_gtalk.c.
References gtalk_pvt::alreadygone, ast_aji_client_destroy(), ast_aji_get_client(), ast_channel_release(), ast_copy_string(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, ASTOBJ_UNREF, gtalk_pvt::capability, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_new(), gtalk_response(), aji_client::jid, gtalk_pvt::jointcapability, gtalk_pvt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::peercapability, gtalk_pvt::rtp, S_OR, gtalk_pvt::sid, gtalk_pvt::them, gtalk_pvt::us, and gtalk_pvt::vrtp.
Referenced by gtalk_parser().
{
struct gtalk_pvt *p, *tmp = client->p;
struct ast_channel *chan;
int res;
iks *codec;
char *from = NULL;
char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ];
int peernoncodeccapability;
char *sid;
/* Make sure our new call doesn't exist yet */
from = iks_find_attrib(pak->x,"to");
if (!from) {
from = client->connection->jid->full;
}
while (tmp) {
if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) ||
(iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) {
ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
gtalk_response(client, from, pak, "out-of-order", NULL);
return -1;
}
tmp = tmp->next;
}
if (!strcasecmp(client->name, "guest")){
/* the guest account is not tied to any configured XMPP client,
let's set it now */
if (client->connection) {
ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
}
client->connection = ast_aji_get_client(from);
if (!client->connection) {
ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
return -1;
}
}
if (!(sid = iks_find_attrib(pak->query, "id"))) {
ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n");
return -1;
}
p = gtalk_alloc(client, from, pak->from->full, sid);
if (!p) {
ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
return -1;
}
chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
if (!chan) {
gtalk_free_pvt(client, p);
return -1;
}
ast_mutex_lock(&p->lock);
ast_copy_string(p->them, pak->from->full, sizeof(p->them));
ast_copy_string(p->sid, sid, sizeof(p->sid));
/* codec points to the first <payload-type/> tag */
codec = iks_first_tag(iks_first_tag(pak->query));
while (codec) {
char *codec_id = iks_find_attrib(codec, "id");
char *codec_name = iks_find_attrib(codec, "name");
if (!codec_id || !codec_name) {
codec = iks_next_tag(codec);
continue;
}
if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) {
ast_rtp_codecs_payloads_set_m_type(
ast_rtp_instance_get_codecs(p->vrtp),
p->vrtp,
atoi(codec_id));
ast_rtp_codecs_payloads_set_rtpmap_type(
ast_rtp_instance_get_codecs(p->vrtp),
p->vrtp,
atoi(codec_id),
"video",
codec_name,
0);
} else {
ast_rtp_codecs_payloads_set_m_type(
ast_rtp_instance_get_codecs(p->rtp),
p->rtp,
atoi(codec_id));
ast_rtp_codecs_payloads_set_rtpmap_type(
ast_rtp_instance_get_codecs(p->rtp),
p->rtp,
atoi(codec_id),
"audio",
codec_name,
0);
}
codec = iks_next_tag(codec);
}
/* Now gather all of the codecs that we are asked for */
ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), &p->peercapability, &peernoncodeccapability);
p->jointcapability = p->capability & p->peercapability;
ast_mutex_unlock(&p->lock);
ast_setstate(chan, AST_STATE_RING);
if (!p->jointcapability) {
ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability),
ast_getformatname_multiple(s2, BUFSIZ, p->peercapability),
ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability));
/* close session if capabilities don't match */
gtalk_action(client, p, "reject");
p->alreadygone = 1;
gtalk_hangup(chan);
ast_channel_release(chan);
return -1;
}
res = ast_pbx_start(chan);
switch (res) {
case AST_PBX_FAILED:
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
gtalk_response(client, from, pak, "service-unavailable", NULL);
break;
case AST_PBX_CALL_LIMIT:
ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
gtalk_response(client, from, pak, "service-unavailable", NULL);
break;
case AST_PBX_SUCCESS:
gtalk_response(client, from, pak, NULL, NULL);
gtalk_create_candidates(client, p, p->sid, p->them, p->us);
/* nothing to do */
break;
}
return 1;
}
| static int gtalk_parser | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
CLI command "gtalk reload".
Definition at line 1985 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().
{
struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
int res;
iks *tmp;
if (!strcasecmp(iks_name(pak->query), "jin:jingle") && (tmp = iks_next(pak->query)) && !strcasecmp(iks_name(tmp), "ses:session")) {
ast_debug(1, "New method detected. Skipping jingle offer and using old gtalk method.\n");
pak->query = tmp;
}
if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n");
}
if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) {
ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n");
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) {
/* New call */
gtalk_newcall(client, pak);
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) {
ast_debug(3, "About to add candidate!\n");
res = gtalk_add_candidate(client, pak);
if (!res) {
ast_log(LOG_WARNING, "Could not add any candidate\n");
} else {
ast_debug(3, "Candidate Added!\n");
}
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) {
gtalk_is_answered(client, pak);
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) {
gtalk_is_accepted(client, pak);
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) {
gtalk_handle_dtmf(client, pak);
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) {
gtalk_hangup_farend(client, pak);
} else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) {
gtalk_hangup_farend(client, pak);
}
ASTOBJ_UNREF(client, gtalk_member_destroy);
return IKS_FILTER_EAT;
}
| static struct ast_frame * gtalk_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 1595 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_rtp_read(), gtalk_pvt::lock, and ast_channel::tech_pvt.
{
struct ast_frame *fr;
struct gtalk_pvt *p = ast->tech_pvt;
ast_mutex_lock(&p->lock);
fr = gtalk_rtp_read(ast, p);
ast_mutex_unlock(&p->lock);
return fr;
}
| static struct ast_channel * gtalk_request | ( | const char * | type, |
| format_t | format, | ||
| const struct ast_channel * | requestor, | ||
| void * | data, | ||
| int * | cause | ||
| ) | [static, read] |
Part of PBX interface.
Definition at line 1851 of file chan_gtalk.c.
References ast_aji_client_destroy(), ast_aji_get_client(), ast_log(), AST_STATE_DOWN, ast_strdupa, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, gtalk::connection, find_gtalk(), gtalk_alloc(), gtalk_member_destroy(), gtalk_new(), aji_client::jid, ast_channel::linkedid, LOG_ERROR, LOG_WARNING, gtalk::name, strsep(), and gtalk::user.
{
struct gtalk_pvt *p = NULL;
struct gtalk *client = NULL;
char *sender = NULL, *to = NULL, *s = NULL;
struct ast_channel *chan = NULL;
if (data) {
s = ast_strdupa(data);
if (s) {
sender = strsep(&s, "/");
if (sender && (sender[0] != '\0')) {
to = strsep(&s, "/");
}
if (!to) {
ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
return NULL;
}
}
}
client = find_gtalk(to, sender);
if (!client) {
ast_log(LOG_WARNING, "Could not find recipient.\n");
return NULL;
}
if (!strcasecmp(client->name, "guest")){
/* the guest account is not tied to any configured XMPP client,
let's set it now */
if (client->connection) {
ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
}
client->connection = ast_aji_get_client(sender);
if (!client->connection) {
ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
ASTOBJ_UNREF(client, gtalk_member_destroy);
return NULL;
}
}
ASTOBJ_WRLOCK(client);
p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
if (p) {
chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL);
}
ASTOBJ_UNLOCK(client);
return chan;
}
| static int gtalk_response | ( | struct gtalk * | client, |
| char * | from, | ||
| ikspak * | pak, | ||
| const char * | reasonstr, | ||
| const char * | reasonstr2 | ||
| ) | [static] |
Definition at line 574 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().
{
iks *response = NULL, *error = NULL, *reason = NULL;
int res = -1;
response = iks_new("iq");
if (response) {
iks_insert_attrib(response, "type", "result");
iks_insert_attrib(response, "from", from);
iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), ""));
iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), ""));
if (reasonstr) {
error = iks_new("error");
if (error) {
iks_insert_attrib(error, "type", "cancel");
reason = iks_new(reasonstr);
if (reason)
iks_insert_node(error, reason);
iks_insert_node(response, error);
}
}
ast_aji_send(client->connection, response);
res = 0;
}
iks_delete(reason);
iks_delete(error);
iks_delete(response);
return res;
}
| static int gtalk_ringing_ack | ( | void * | data, |
| ikspak * | pak | ||
| ) | [static] |
Definition at line 461 of file chan_gtalk.c.
References AST_CONTROL_RINGING, ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_create_candidates(), gtalk_invite(), gtalk_pvt::lock, LOG_DEBUG, name, gtalk_pvt::owner, gtalk_pvt::parent, gtalk_pvt::ringrule, S_OR, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.
Referenced by gtalk_call().
{
struct gtalk_pvt *p = data;
struct ast_channel *owner;
ast_mutex_lock(&p->lock);
if (p->ringrule) {
iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
}
p->ringrule = NULL;
/* this may be a redirect */
if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) {
char *name = NULL;
char *redirect = NULL;
iks *traversenodes = NULL;
traversenodes = pak->query;
while (traversenodes) {
if (!(name = iks_name(traversenodes))) {
break;
}
if (!strcasecmp(name, "error") &&
((redirect = iks_find_cdata(traversenodes, "redirect")) ||
(redirect = iks_find_cdata(traversenodes, "sta:redirect"))) &&
(redirect = strstr(redirect, "xmpp:"))) {
redirect += 5;
ast_log(LOG_DEBUG, "redirect %s\n", redirect);
ast_copy_string(p->them, redirect, sizeof(p->them));
gtalk_invite(p, p->them, p->us, p->sid, 1);
break;
}
traversenodes = iks_next_tag(traversenodes);
}
}
gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
owner = p->owner;
ast_mutex_unlock(&p->lock);
if (owner) {
ast_queue_control(owner, AST_CONTROL_RINGING);
}
return IKS_FILTER_EAT;
}
| static struct ast_frame* gtalk_rtp_read | ( | struct ast_channel * | ast, |
| struct gtalk_pvt * | p | ||
| ) | [static, read] |
Definition at line 1566 of file chan_gtalk.c.
References ast_debug, AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_FRAME_VOICE, ast_getformatname(), ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), ast_frame_subclass::codec, f, ast_frame::frametype, gtalk_update_stun(), ast_channel::nativeformats, gtalk_pvt::owner, gtalk_pvt::parent, ast_channel::readformat, gtalk_pvt::rtp, ast_frame::subclass, and ast_channel::writeformat.
Referenced by gtalk_read().
{
struct ast_frame *f;
if (!p->rtp) {
return &ast_null_frame;
}
f = ast_rtp_instance_read(p->rtp, 0);
gtalk_update_stun(p->parent, p);
if (p->owner) {
/* We already hold the channel lock */
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass.codec != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
p->owner->nativeformats =
(p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass.codec;
ast_set_read_format(p->owner, p->owner->readformat);
ast_set_write_format(p->owner, p->owner->writeformat);
}
/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner, p->vad, f);
if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
} */
}
}
return f;
}
| static int gtalk_sendhtml | ( | struct ast_channel * | ast, |
| int | subclass, | ||
| const char * | data, | ||
| int | datalen | ||
| ) | [static] |
Definition at line 1797 of file chan_gtalk.c.
References ast_log(), and LOG_NOTICE.
{
ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
return -1;
}
| static int gtalk_sendtext | ( | struct ast_channel * | ast, |
| const char * | text | ||
| ) | [static] |
Definition at line 1687 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.
{
int res = 0;
struct aji_client *client = NULL;
struct gtalk_pvt *p = chan->tech_pvt;
if (!p->parent) {
ast_log(LOG_ERROR, "Parent channel not found\n");
return -1;
}
if (!p->parent->connection) {
ast_log(LOG_ERROR, "XMPP client not found\n");
return -1;
}
client = p->parent->connection;
res = ast_aji_send_chat(client, p->them, text);
return res;
}
| static int gtalk_set_rtp_peer | ( | struct ast_channel * | chan, |
| struct ast_rtp_instance * | rtp, | ||
| struct ast_rtp_instance * | vrtp, | ||
| struct ast_rtp_instance * | trtp, | ||
| format_t | codecs, | ||
| int | nat_active | ||
| ) | [static] |
Definition at line 547 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, and ast_channel::tech_pvt.
{
struct gtalk_pvt *p;
p = chan->tech_pvt;
if (!p)
return -1;
ast_mutex_lock(&p->lock);
/* if (rtp)
ast_rtp_get_peer(rtp, &p->redirip);
else
memset(&p->redirip, 0, sizeof(p->redirip));
p->redircodecs = codecs; */
/* Reset lastrtprx timer */
ast_mutex_unlock(&p->lock);
return 0;
}
| 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 1901 of file chan_gtalk.c.
References AJI_MAX_JIDLEN, ast_cli_args::argc, ast_cli(), ast_copy_string(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, gtalk_list, gtalklock, LOG_WARNING, ast_channel::name, gtalk_pvt::next, gtalk_pvt::owner, ast_channel::readformat, gtalk_pvt::them, ast_cli_entry::usage, and ast_channel::writeformat.
{
#define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
struct gtalk_pvt *p;
struct ast_channel *chan;
int numchans = 0;
char them[AJI_MAX_JIDLEN];
char *jid = NULL;
char *resource = NULL;
switch (cmd) {
case CLI_INIT:
e->command = "gtalk show channels";
e->usage =
"Usage: gtalk show channels\n"
" Shows current state of the Gtalk channels.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
ast_mutex_lock(>alklock);
ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
ASTOBJ_WRLOCK(iterator);
p = iterator->p;
while(p) {
chan = p->owner;
ast_copy_string(them, p->them, sizeof(them));
jid = them;
resource = strchr(them, '/');
if (!resource)
resource = "None";
else {
*resource = '\0';
resource ++;
}
if (chan)
ast_cli(a->fd, FORMAT,
chan->name,
jid,
resource,
ast_getformatname(chan->readformat),
ast_getformatname(chan->writeformat)
);
else
ast_log(LOG_WARNING, "No available channel\n");
numchans ++;
p = p->next;
}
ASTOBJ_UNLOCK(iterator);
});
ast_mutex_unlock(>alklock);
ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : "");
return CLI_SUCCESS;
#undef FORMAT
}
| static int gtalk_update_externip | ( | void | ) | [static] |
Definition at line 1385 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().
{
int sock;
char *newaddr;
struct sockaddr_in answer = { 0, };
struct sockaddr_in *dst;
struct ast_sockaddr tmp_dst;
if (!stunaddr.sin_addr.s_addr) {
return -1;
}
dst = &stunaddr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno));
return -1;
}
ast_sockaddr_from_sin(&tmp_dst, dst);
if (ast_connect(sock, &tmp_dst) != 0) {
ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst));
close(sock);
return -1;
}
if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) {
close(sock);
return -1;
}
newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr));
memcpy(externip, newaddr, sizeof(externip));
close(sock);
return 0;
}
Definition at line 1424 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().
{
struct gtalk_candidate *tmp;
struct hostent *hp;
struct ast_hostent ahp;
struct sockaddr_in sin = { 0, };
struct sockaddr_in aux = { 0, };
struct ast_sockaddr sin_tmp;
struct ast_sockaddr aux_tmp;
if (time(NULL) == p->laststun)
return 0;
tmp = p->theircandidates;
p->laststun = time(NULL);
while (tmp) {
char username[256];
/* Find the IP address of the host */
if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) {
ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip);
tmp = tmp->next;
continue;
}
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(tmp->port);
snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username);
/* Find out the result of the STUN */
ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp);
ast_sockaddr_to_sin(&aux_tmp, &aux);
/* If the STUN result is different from the IP of the hostname,
* lock on the stun IP of the hostname advertised by the
* remote client */
if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) {
ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username);
} else {
ast_sockaddr_from_sin(&sin_tmp, &sin);
ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
}
if (aux.sin_addr.s_addr) {
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);
ast_debug(4, "Sending STUN request to %s\n", tmp->ip);
}
tmp = tmp->next;
}
return 1;
}
| static int gtalk_write | ( | struct ast_channel * | ast, |
| struct ast_frame * | f | ||
| ) | [static] |
Send frame to media channel (rtp)
Definition at line 1607 of file chan_gtalk.c.
References AST_FRAME_IMAGE, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_frame_subclass::codec, ast_frame::frametype, gtalk_pvt::lock, LOG_WARNING, ast_channel::nativeformats, ast_channel::readformat, gtalk_pvt::rtp, ast_frame::subclass, ast_channel::tech_pvt, gtalk_pvt::vrtp, and ast_channel::writeformat.
{
struct gtalk_pvt *p = ast->tech_pvt;
int res = 0;
char buf[256];
switch (frame->frametype) {
case AST_FRAME_VOICE:
if (!(frame->subclass.codec & ast->nativeformats)) {
ast_log(LOG_WARNING,
"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
ast_getformatname(frame->subclass.codec),
ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
ast_getformatname(ast->readformat),
ast_getformatname(ast->writeformat));
return 0;
}
if (p) {
ast_mutex_lock(&p->lock);
if (p->rtp) {
res = ast_rtp_instance_write(p->rtp, frame);
}
ast_mutex_unlock(&p->lock);
}
break;
case AST_FRAME_VIDEO:
if (p) {
ast_mutex_lock(&p->lock);
if (p->vrtp) {
res = ast_rtp_instance_write(p->vrtp, frame);
}
ast_mutex_unlock(&p->lock);
}
break;
case AST_FRAME_IMAGE:
return 0;
break;
default:
ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
frame->frametype);
return 0;
}
return res;
}
| static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 2204 of file chan_gtalk.c.
References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_glue_register, ast_sockaddr_from_sin, ast_sockaddr_ipv4(), ASTOBJ_CONTAINER_INIT, free, GOOGLE_CONFIG, gtalk_get_local_ip(), gtalk_list, gtalk_load_config(), io_context_create(), LOG_ERROR, LOG_WARNING, sched_context_create(), and ast_channel_tech::type.
{
struct ast_sockaddr bindaddr_tmp;
struct ast_sockaddr ourip_tmp;
char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
free(jabber_loaded);
if (!jabber_loaded) {
/* If embedded, check for a different module name */
jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
free(jabber_loaded);
if (!jabber_loaded) {
ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n");
return AST_MODULE_LOAD_DECLINE;
}
}
ASTOBJ_CONTAINER_INIT(>alk_list);
if (!gtalk_load_config()) {
ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
return 0;
}
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
}
io = io_context_create();
if (!io) {
ast_log(LOG_WARNING, "Unable to create I/O context\n");
}
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
if (gtalk_get_local_ip(&ourip_tmp)) {
ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
return 0;
}
__ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
ast_rtp_glue_register(>alk_rtp_glue);
ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
/* Make sure we can register our channel type */
if (ast_channel_register(>alk_tech)) {
ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
return -1;
}
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Reload module.
Unload the gtalk channel from Asterisk
Definition at line 2264 of file chan_gtalk.c.
References ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_glue_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, gtalk_list, gtalk_member_destroy(), gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.
{
struct gtalk_pvt *privates = NULL;
ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
/* First, take us out of the channel loop */
ast_channel_unregister(>alk_tech);
ast_rtp_glue_unregister(>alk_rtp_glue);
if (!ast_mutex_lock(>alklock)) {
/* Hangup all interfaces if they have an owner */
ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
ASTOBJ_WRLOCK(iterator);
privates = iterator->p;
while(privates) {
if (privates->owner)
ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
privates = privates->next;
}
iterator->p = NULL;
ASTOBJ_UNLOCK(iterator);
});
ast_mutex_unlock(>alklock);
} else {
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
return -1;
}
ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
ASTOBJ_CONTAINER_DESTROY(>alk_list);
return 0;
}
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 2300 of file chan_gtalk.c.
struct in_addr __ourip [static] |
Definition at line 229 of file chan_gtalk.c.
Referenced by load_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2300 of file chan_gtalk.c.
struct sockaddr_in bindaddr = { 0, } [static] |
The address we bind to
Definition at line 225 of file chan_gtalk.c.
Referenced by __oh323_rtp_create(), config_load(), config_parse_variables(), handle_skinny_show_settings(), load_module(), reload_config(), and start_rtp().
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 236 of file chan_gtalk.c.
format_t global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263 [static] |
Definition at line 171 of file chan_gtalk.c.
Referenced by gtalk_alloc(), and gtalk_new().
struct ast_jb_conf global_jbconf [static] |
Definition at line 91 of file chan_gtalk.c.
Referenced by gtalk_load_config(), and gtalk_new().
struct ast_cli_entry gtalk_cli[] [static] |
{
AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
}
Definition at line 231 of file chan_gtalk.c.
struct gtalk_container gtalk_list [static] |
Definition at line 239 of file chan_gtalk.c.
Referenced by find_gtalk(), gtalk_load_config(), gtalk_show_channels(), load_module(), and unload_module().
struct ast_rtp_glue gtalk_rtp_glue [static] |
Definition at line 567 of file chan_gtalk.c.
struct ast_channel_tech gtalk_tech [static] |
PBX interface structure for channel registration.
Definition at line 201 of file chan_gtalk.c.
Referenced by gtalk_new().
ast_mutex_t gtalklock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Protect the interface list (of gtalk_pvt's)
Definition at line 173 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 228 of file chan_gtalk.c.
Referenced by ast_udptl_new_with_bindaddr().
struct sched_context* sched [static] |
The scheduling context
Definition at line 227 of file chan_gtalk.c.
struct sockaddr_in stunaddr [static] |
the stun server we get the externip from
Definition at line 237 of file chan_gtalk.c.
Referenced by gtalk_load_config(), and gtalk_update_externip().