#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 Unload the gtalk channel from Asterisk. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Gtalk Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } |
static struct in_addr | __ourip |
static struct ast_module_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 = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } |
static struct io_context * | io |
static struct sched_context * | sched |
static struct sockaddr_in | stunaddr |
Philippe Sultan <philippe.sultan@gmail.com>
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" |
enum gtalk_connect_type |
Definition at line 97 of file chan_gtalk.c.
00097 { 00098 AJI_CONNECT_STUN = 1, 00099 AJI_CONNECT_LOCAL = 2, 00100 AJI_CONNECT_RELAY = 3, 00101 };
enum gtalk_protocol |
Definition at line 92 of file chan_gtalk.c.
00092 { 00093 AJI_PROTOCOL_UDP = 1, 00094 AJI_PROTOCOL_SSLTCP = 2, 00095 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 2276 of file chan_gtalk.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2276 of file chan_gtalk.c.
static int add_codec_to_answer | ( | const struct gtalk_pvt * | p, | |
int | codec, | |||
iks * | dcodecs | |||
) | [static] |
Definition at line 277 of file chan_gtalk.c.
References ast_getformatname(), ast_log(), format, and LOG_WARNING.
Referenced by gtalk_invite(), and jingle_accept_call().
00278 { 00279 int res = 0; 00280 char *format = ast_getformatname(codec); 00281 00282 if (!strcasecmp("ulaw", format)) { 00283 iks *payload_eg711u, *payload_pcmu; 00284 payload_pcmu = iks_new("payload-type"); 00285 payload_eg711u = iks_new("payload-type"); 00286 00287 if(!payload_eg711u || !payload_pcmu) { 00288 iks_delete(payload_pcmu); 00289 iks_delete(payload_eg711u); 00290 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00291 return -1; 00292 } 00293 iks_insert_attrib(payload_pcmu, "id", "0"); 00294 iks_insert_attrib(payload_pcmu, "name", "PCMU"); 00295 iks_insert_attrib(payload_pcmu, "clockrate","8000"); 00296 iks_insert_attrib(payload_pcmu, "bitrate","64000"); 00297 iks_insert_attrib(payload_eg711u, "id", "100"); 00298 iks_insert_attrib(payload_eg711u, "name", "EG711U"); 00299 iks_insert_attrib(payload_eg711u, "clockrate","8000"); 00300 iks_insert_attrib(payload_eg711u, "bitrate","64000"); 00301 iks_insert_node(dcodecs, payload_pcmu); 00302 iks_insert_node(dcodecs, payload_eg711u); 00303 res ++; 00304 } 00305 if (!strcasecmp("alaw", format)) { 00306 iks *payload_eg711a, *payload_pcma; 00307 payload_pcma = iks_new("payload-type"); 00308 payload_eg711a = iks_new("payload-type"); 00309 if(!payload_eg711a || !payload_pcma) { 00310 iks_delete(payload_eg711a); 00311 iks_delete(payload_pcma); 00312 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00313 return -1; 00314 } 00315 iks_insert_attrib(payload_pcma, "id", "8"); 00316 iks_insert_attrib(payload_pcma, "name", "PCMA"); 00317 iks_insert_attrib(payload_pcma, "clockrate","8000"); 00318 iks_insert_attrib(payload_pcma, "bitrate","64000"); 00319 payload_eg711a = iks_new("payload-type"); 00320 iks_insert_attrib(payload_eg711a, "id", "101"); 00321 iks_insert_attrib(payload_eg711a, "name", "EG711A"); 00322 iks_insert_attrib(payload_eg711a, "clockrate","8000"); 00323 iks_insert_attrib(payload_eg711a, "bitrate","64000"); 00324 iks_insert_node(dcodecs, payload_pcma); 00325 iks_insert_node(dcodecs, payload_eg711a); 00326 res ++; 00327 } 00328 if (!strcasecmp("ilbc", format)) { 00329 iks *payload_ilbc = iks_new("payload-type"); 00330 if(!payload_ilbc) { 00331 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00332 return -1; 00333 } 00334 iks_insert_attrib(payload_ilbc, "id", "97"); 00335 iks_insert_attrib(payload_ilbc, "name", "iLBC"); 00336 iks_insert_attrib(payload_ilbc, "clockrate","8000"); 00337 iks_insert_attrib(payload_ilbc, "bitrate","13300"); 00338 iks_insert_node(dcodecs, payload_ilbc); 00339 res ++; 00340 } 00341 if (!strcasecmp("g723", format)) { 00342 iks *payload_g723 = iks_new("payload-type"); 00343 if(!payload_g723) { 00344 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00345 return -1; 00346 } 00347 iks_insert_attrib(payload_g723, "id", "4"); 00348 iks_insert_attrib(payload_g723, "name", "G723"); 00349 iks_insert_attrib(payload_g723, "clockrate","8000"); 00350 iks_insert_attrib(payload_g723, "bitrate","6300"); 00351 iks_insert_node(dcodecs, payload_g723); 00352 res ++; 00353 } 00354 if (!strcasecmp("speex", format)) { 00355 iks *payload_speex = iks_new("payload-type"); 00356 if(!payload_speex) { 00357 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00358 return -1; 00359 } 00360 iks_insert_attrib(payload_speex, "id", "110"); 00361 iks_insert_attrib(payload_speex, "name", "speex"); 00362 iks_insert_attrib(payload_speex, "clockrate","8000"); 00363 iks_insert_attrib(payload_speex, "bitrate","11000"); 00364 iks_insert_node(dcodecs, payload_speex); 00365 res++; 00366 } 00367 if (!strcasecmp("gsm", format)) { 00368 iks *payload_gsm = iks_new("payload-type"); 00369 if(!payload_gsm) { 00370 ast_log(LOG_WARNING,"Failed to allocate iks node"); 00371 return -1; 00372 } 00373 iks_insert_attrib(payload_gsm, "id", "103"); 00374 iks_insert_attrib(payload_gsm, "name", "gsm"); 00375 iks_insert_node(dcodecs, payload_gsm); 00376 res++; 00377 } 00378 00379 return res; 00380 }
static struct gtalk* find_gtalk | ( | char * | name, | |
char * | connection | |||
) | [static] |
Definition at line 245 of file chan_gtalk.c.
References ast_strdupa, ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_FIND_FULL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, gtalk_list, and strsep().
Referenced by gtalk_request().
00246 { 00247 struct gtalk *gtalk = NULL; 00248 char *domain = NULL , *s = NULL; 00249 00250 if (strchr(connection, '@')) { 00251 s = ast_strdupa(connection); 00252 domain = strsep(&s, "@"); 00253 ast_verbose("OOOOH domain = %s\n", domain); 00254 } 00255 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name); 00256 if (!gtalk && strchr(name, '@')) 00257 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp); 00258 00259 if (!gtalk) { 00260 /* guest call */ 00261 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { 00262 ASTOBJ_RDLOCK(iterator); 00263 if (!strcasecmp(iterator->name, "guest")) { 00264 gtalk = iterator; 00265 } 00266 ASTOBJ_UNLOCK(iterator); 00267 00268 if (gtalk) 00269 break; 00270 }); 00271 00272 } 00273 return gtalk; 00274 }
static int gtalk_action | ( | struct gtalk * | client, | |
struct gtalk_pvt * | p, | |||
const char * | action | |||
) | [static] |
Definition at line 1163 of file chan_gtalk.c.
References ast_aji_increment_mid(), ast_aji_send(), ast_strdupa, gtalk::connection, GOOGLE_NS, gtalk_pvt::initiator, aji_client::mid, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.
Referenced by gtalk_hangup(), and gtalk_newcall().
01164 { 01165 iks *request, *session = NULL; 01166 int res = -1; 01167 char *lowerthem = NULL; 01168 01169 request = iks_new("iq"); 01170 if (request) { 01171 iks_insert_attrib(request, "type", "set"); 01172 iks_insert_attrib(request, "from", p->us); 01173 iks_insert_attrib(request, "to", p->them); 01174 iks_insert_attrib(request, "id", client->connection->mid); 01175 ast_aji_increment_mid(client->connection->mid); 01176 session = iks_new("session"); 01177 if (session) { 01178 iks_insert_attrib(session, "type", action); 01179 iks_insert_attrib(session, "id", p->sid); 01180 /* put the initiator attribute to lower case if we receive the call 01181 * otherwise GoogleTalk won't establish the session */ 01182 if (!p->initiator) { 01183 char c; 01184 char *t = lowerthem = ast_strdupa(p->them); 01185 while (((c = *t) != '/') && (*t++ = tolower(c))); 01186 } 01187 iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem); 01188 iks_insert_attrib(session, "xmlns", GOOGLE_NS); 01189 iks_insert_node(request, session); 01190 ast_aji_send(client->connection, request); 01191 res = 0; 01192 } 01193 } 01194 01195 iks_delete(session); 01196 iks_delete(request); 01197 01198 return res; 01199 }
static int gtalk_add_candidate | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 1465 of file chan_gtalk.c.
References AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_send(), ast_calloc, ast_copy_string(), gtalk::connection, gtalk_update_stun(), aji_client::jid, gtalk_pvt::laststun, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, gtalk_candidate::receipt, S_OR, and gtalk_pvt::theircandidates.
Referenced by gtalk_parser().
01466 { 01467 struct gtalk_pvt *p = NULL, *tmp = NULL; 01468 struct aji_client *c = client->connection; 01469 struct gtalk_candidate *newcandidate = NULL; 01470 iks *traversenodes = NULL, *receipt = NULL; 01471 char *from; 01472 01473 from = iks_find_attrib(pak->x,"to"); 01474 if (!from) { 01475 from = c->jid->full; 01476 } 01477 01478 for (tmp = client->p; tmp; tmp = tmp->next) { 01479 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || 01480 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { 01481 p = tmp; 01482 break; 01483 } 01484 } 01485 01486 if (!p) { 01487 return -1; 01488 } 01489 traversenodes = pak->query; 01490 while(traversenodes) { 01491 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "session")) { 01492 traversenodes = iks_first_tag(traversenodes); 01493 continue; 01494 } 01495 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:session")) { 01496 traversenodes = iks_child(traversenodes); 01497 continue; 01498 } 01499 if(!strcasecmp(S_OR(iks_name(traversenodes), ""), "candidate") || !strcasecmp(S_OR(iks_name(traversenodes), ""), "ses:candidate")) { 01500 newcandidate = ast_calloc(1, sizeof(*newcandidate)); 01501 if (!newcandidate) 01502 return 0; 01503 ast_copy_string(newcandidate->name, 01504 S_OR(iks_find_attrib(traversenodes, "name"), ""), 01505 sizeof(newcandidate->name)); 01506 ast_copy_string(newcandidate->ip, 01507 S_OR(iks_find_attrib(traversenodes, "address"), ""), 01508 sizeof(newcandidate->ip)); 01509 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port")); 01510 ast_copy_string(newcandidate->username, 01511 S_OR(iks_find_attrib(traversenodes, "username"), ""), 01512 sizeof(newcandidate->username)); 01513 ast_copy_string(newcandidate->password, 01514 S_OR(iks_find_attrib(traversenodes, "password"), ""), 01515 sizeof(newcandidate->password)); 01516 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference")); 01517 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "udp")) 01518 newcandidate->protocol = AJI_PROTOCOL_UDP; 01519 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "protocol"), ""), "ssltcp")) 01520 newcandidate->protocol = AJI_PROTOCOL_SSLTCP; 01521 01522 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "stun")) 01523 newcandidate->type = AJI_CONNECT_STUN; 01524 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "local")) 01525 newcandidate->type = AJI_CONNECT_LOCAL; 01526 if (!strcasecmp(S_OR(iks_find_attrib(traversenodes, "type"), ""), "relay")) 01527 newcandidate->type = AJI_CONNECT_RELAY; 01528 ast_copy_string(newcandidate->network, 01529 S_OR(iks_find_attrib(traversenodes, "network"), ""), 01530 sizeof(newcandidate->network)); 01531 newcandidate->generation = atoi(S_OR(iks_find_attrib(traversenodes, "generation"), "0")); 01532 newcandidate->next = NULL; 01533 01534 newcandidate->next = p->theircandidates; 01535 p->theircandidates = newcandidate; 01536 p->laststun = 0; 01537 gtalk_update_stun(p->parent, p); 01538 newcandidate = NULL; 01539 } 01540 traversenodes = iks_next_tag(traversenodes); 01541 } 01542 01543 receipt = iks_new("iq"); 01544 iks_insert_attrib(receipt, "type", "result"); 01545 iks_insert_attrib(receipt, "from", from); 01546 iks_insert_attrib(receipt, "to", S_OR(iks_find_attrib(pak->x, "from"), "")); 01547 iks_insert_attrib(receipt, "id", S_OR(iks_find_attrib(pak->x, "id"), "")); 01548 ast_aji_send(c, receipt); 01549 01550 iks_delete(receipt); 01551 01552 return 1; 01553 }
static struct gtalk_pvt * gtalk_alloc | ( | struct gtalk * | client, | |
const char * | us, | |||
const char * | them, | |||
const char * | sid | |||
) | [static] |
Definition at line 975 of file chan_gtalk.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_random(), ast_rtp_codecs_payloads_clear(), AST_RTP_DTMF_MODE_RFC2833, ast_rtp_instance_dtmf_mode_set(), ast_rtp_instance_get_codecs(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), AST_RTP_PROPERTY_DTMF, AST_RTP_PROPERTY_RTCP, AST_RTP_PROPERTY_STUN, ast_sockaddr_from_sin, ast_strdupa, ASTOBJ_CONTAINER_FIND, bindaddr, aji_client::buddies, gtalk::buddy, aji_resource::cap, gtalk::capability, gtalk::connection, exten, global_capability, gtalklock, aji_version::jingle, LOG_ERROR, LOG_WARNING, gtalk::name, aji_resource::next, gtalk::p, gtalk::prefs, aji_resource::resource, aji_buddy::resources, and strsep().
Referenced by gtalk_newcall(), and gtalk_request().
00976 { 00977 struct gtalk_pvt *tmp = NULL; 00978 struct aji_resource *resources = NULL; 00979 struct aji_buddy *buddy; 00980 char idroster[200]; 00981 char *data, *exten = NULL; 00982 struct ast_sockaddr bindaddr_tmp; 00983 00984 ast_debug(1, "The client is %s for alloc\n", client->name); 00985 if (!sid && !strchr(them, '/')) { /* I started call! */ 00986 if (!strcasecmp(client->name, "guest")) { 00987 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them); 00988 if (buddy) { 00989 resources = buddy->resources; 00990 } 00991 } else if (client->buddy) { 00992 resources = client->buddy->resources; 00993 } 00994 00995 while (resources) { 00996 if (resources->cap->jingle) { 00997 break; 00998 } 00999 resources = resources->next; 01000 } 01001 if (resources) { 01002 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource); 01003 } else if ((*them == '+') || (strstr(them, "@voice.google.com"))) { 01004 snprintf(idroster, sizeof(idroster), "%s", them); 01005 } else { 01006 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n"); 01007 return NULL; 01008 } 01009 } 01010 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { 01011 return NULL; 01012 } 01013 01014 memcpy(&tmp->prefs, &client->prefs, sizeof(struct ast_codec_pref)); 01015 01016 if (sid) { 01017 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid)); 01018 ast_copy_string(tmp->them, them, sizeof(tmp->them)); 01019 ast_copy_string(tmp->us, us, sizeof(tmp->us)); 01020 } else { 01021 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random()); 01022 ast_copy_string(tmp->them, idroster, sizeof(tmp->them)); 01023 ast_copy_string(tmp->us, us, sizeof(tmp->us)); 01024 tmp->initiator = 1; 01025 } 01026 /* clear codecs */ 01027 bindaddr.sin_family = AF_INET; 01028 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); 01029 if (!(tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL))) { 01030 ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n"); 01031 ast_free(tmp); 01032 return NULL; 01033 } 01034 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1); 01035 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_STUN, 1); 01036 ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_DTMF, 1); 01037 ast_rtp_instance_dtmf_mode_set(tmp->rtp, AST_RTP_DTMF_MODE_RFC2833); 01038 ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp); 01039 01040 /* add user configured codec capabilites */ 01041 if (client->capability) { 01042 tmp->capability = client->capability; 01043 } else if (global_capability) { 01044 tmp->capability = global_capability; 01045 } 01046 01047 tmp->parent = client; 01048 if (!tmp->rtp) { 01049 ast_log(LOG_WARNING, "Out of RTP sessions?\n"); 01050 ast_free(tmp); 01051 return NULL; 01052 } 01053 01054 /* Set CALLERID(name) to the full JID of the remote peer */ 01055 ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name)); 01056 01057 if(strchr(tmp->us, '/')) { 01058 data = ast_strdupa(tmp->us); 01059 exten = strsep(&data, "/"); 01060 } else { 01061 exten = tmp->us; 01062 } 01063 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); 01064 ast_mutex_init(&tmp->lock); 01065 ast_mutex_lock(>alklock); 01066 tmp->next = client->p; 01067 client->p = tmp; 01068 ast_mutex_unlock(>alklock); 01069 return tmp; 01070 }
static int gtalk_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 506 of file chan_gtalk.c.
References ast_debug, ast_mutex_lock, ast_mutex_unlock, EVENT_FLAG_SYSTEM, gtalk_invite(), gtalk_pvt::lock, manager_event, ast_channel::name, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.
00507 { 00508 struct gtalk_pvt *p = ast->tech_pvt; 00509 int res = 0; 00510 00511 ast_debug(1, "Answer!\n"); 00512 ast_mutex_lock(&p->lock); 00513 gtalk_invite(p, p->them, p->us,p->sid, 0); 00514 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n", 00515 ast->name, "GTALK", p->sid); 00516 ast_mutex_unlock(&p->lock); 00517 return res; 00518 }
static int gtalk_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Initiate new call, part of PBX interface dest is the dial string.
Definition at line 1795 of file chan_gtalk.c.
References ast_channel::_state, ast_copy_string(), ast_log(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RING, gtalk::connection, aji_client::f, gtalk_invite(), gtalk_ringing_ack(), LOG_WARNING, aji_client::mid, ast_channel::name, gtalk_pvt::parent, gtalk_pvt::ring, gtalk_pvt::ringrule, gtalk_pvt::sid, ast_channel::tech_pvt, gtalk_pvt::them, and gtalk_pvt::us.
01796 { 01797 struct gtalk_pvt *p = ast->tech_pvt; 01798 01799 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { 01800 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name); 01801 return -1; 01802 } 01803 01804 ast_setstate(ast, AST_STATE_RING); 01805 if (!p->ringrule) { 01806 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring)); 01807 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p, 01808 IKS_RULE_ID, p->ring, IKS_RULE_DONE); 01809 } else { 01810 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n"); 01811 } 01812 01813 gtalk_invite(p, p->them, p->us, p->sid, 1); 01814 01815 return 0; 01816 }
static int gtalk_create_candidates | ( | struct gtalk * | client, | |
struct gtalk_pvt * | p, | |||
char * | sid, | |||
char * | from, | |||
char * | to | |||
) | [static] |
Definition at line 838 of file chan_gtalk.c.
References AJI_CONNECT_LOCAL, AJI_CONNECT_RELAY, AJI_CONNECT_STUN, AJI_PROTOCOL_SSLTCP, AJI_PROTOCOL_UDP, ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_free, ast_log(), ast_random(), ast_rtp_instance_get_local_address(), ast_sockaddr_stringify_addr(), ast_sockaddr_to_sin, ast_strdupa, ast_strlen_zero(), gtalk::connection, externip, GOOGLE_NS, GOOGLE_TRANSPORT_NS, gtalk_get_local_ip(), gtalk_update_externip(), gtalk_pvt::initiator, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_client::mid, gtalk_candidate::name, gtalk_candidate::next, gtalk_pvt::next, gtalk_pvt::ourcandidates, pass, gtalk_candidate::password, gtalk_candidate::port, gtalk_candidate::preference, gtalk_candidate::protocol, gtalk_pvt::rtp, gtalk_pvt::sid, gtalk_candidate::type, and gtalk_candidate::username.
Referenced by gtalk_newcall(), and gtalk_ringing_ack().
00839 { 00840 struct gtalk_candidate *tmp; 00841 struct aji_client *c = client->connection; 00842 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL; 00843 struct sockaddr_in sin = { 0, }; 00844 struct ast_sockaddr sin_tmp; 00845 struct ast_sockaddr us; 00846 iks *iq, *gtalk, *candidate, *transport; 00847 char user[17], pass[17], preference[5], port[7]; 00848 char *lowerfrom = NULL; 00849 00850 iq = iks_new("iq"); 00851 gtalk = iks_new("session"); 00852 candidate = iks_new("candidate"); 00853 transport = iks_new("transport"); 00854 if (!iq || !gtalk || !candidate || !transport) { 00855 ast_log(LOG_ERROR, "Memory allocation error\n"); 00856 goto safeout; 00857 } 00858 ours1 = ast_calloc(1, sizeof(*ours1)); 00859 ours2 = ast_calloc(1, sizeof(*ours2)); 00860 if (!ours1 || !ours2) 00861 goto safeout; 00862 00863 iks_insert_attrib(transport, "xmlns",GOOGLE_TRANSPORT_NS); 00864 iks_insert_node(iq, gtalk); 00865 iks_insert_node(gtalk,candidate); 00866 iks_insert_node(gtalk,transport); 00867 00868 for (; p; p = p->next) { 00869 if (!strcasecmp(p->sid, sid)) 00870 break; 00871 } 00872 00873 if (!p) { 00874 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid); 00875 goto safeout; 00876 } 00877 00878 ast_rtp_instance_get_local_address(p->rtp, &sin_tmp); 00879 ast_sockaddr_to_sin(&sin_tmp, &sin); 00880 00881 gtalk_get_local_ip(&us); 00882 00883 if (!strcmp(ast_sockaddr_stringify_addr(&us), "127.0.0.1")) { 00884 ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute."); 00885 } 00886 00887 /* Setup our gtalk candidates */ 00888 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name)); 00889 ours1->port = ntohs(sin.sin_port); 00890 ours1->preference = 1; 00891 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random()); 00892 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random()); 00893 ast_copy_string(ours1->username, user, sizeof(ours1->username)); 00894 ast_copy_string(ours1->password, pass, sizeof(ours1->password)); 00895 ast_copy_string(ours1->ip, ast_sockaddr_stringify_addr(&us), 00896 sizeof(ours1->ip)); 00897 ours1->protocol = AJI_PROTOCOL_UDP; 00898 ours1->type = AJI_CONNECT_LOCAL; 00899 ours1->generation = 0; 00900 p->ourcandidates = ours1; 00901 00902 /* XXX this is a blocking action. We send a STUN request to the server 00903 * and wait for the response. If blocking here is a problem the STUN requests/responses 00904 * for the externip may need to be done differently. */ 00905 gtalk_update_externip(); 00906 if (!ast_strlen_zero(externip)) { 00907 ast_copy_string(ours2->username, user, sizeof(ours2->username)); 00908 ast_copy_string(ours2->password, pass, sizeof(ours2->password)); 00909 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip)); 00910 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name)); 00911 ours2->port = ntohs(sin.sin_port); 00912 ours2->preference = 0.9; 00913 ours2->protocol = AJI_PROTOCOL_UDP; 00914 ours2->type = AJI_CONNECT_STUN; 00915 ours2->generation = 0; 00916 ours1->next = ours2; 00917 ours2 = NULL; 00918 } 00919 ours1 = NULL; 00920 00921 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) { 00922 snprintf(port, sizeof(port), "%d", tmp->port); 00923 snprintf(preference, sizeof(preference), "%.2f", tmp->preference); 00924 iks_insert_attrib(iq, "from", to); 00925 iks_insert_attrib(iq, "to", from); 00926 iks_insert_attrib(iq, "type", "set"); 00927 iks_insert_attrib(iq, "id", c->mid); 00928 ast_aji_increment_mid(c->mid); 00929 iks_insert_attrib(gtalk, "type", "candidates"); 00930 iks_insert_attrib(gtalk, "id", sid); 00931 /* put the initiator attribute to lower case if we receive the call 00932 * otherwise GoogleTalk won't establish the session */ 00933 if (!p->initiator) { 00934 char c; 00935 char *t = lowerfrom = ast_strdupa(from); 00936 while (((c = *t) != '/') && (*t++ = tolower(c))); 00937 } 00938 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom); 00939 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); 00940 iks_insert_attrib(candidate, "name", tmp->name); 00941 iks_insert_attrib(candidate, "address", tmp->ip); 00942 iks_insert_attrib(candidate, "port", port); 00943 iks_insert_attrib(candidate, "username", tmp->username); 00944 iks_insert_attrib(candidate, "password", tmp->password); 00945 iks_insert_attrib(candidate, "preference", preference); 00946 if (tmp->protocol == AJI_PROTOCOL_UDP) 00947 iks_insert_attrib(candidate, "protocol", "udp"); 00948 if (tmp->protocol == AJI_PROTOCOL_SSLTCP) 00949 iks_insert_attrib(candidate, "protocol", "ssltcp"); 00950 if (tmp->type == AJI_CONNECT_STUN) 00951 iks_insert_attrib(candidate, "type", "stun"); 00952 if (tmp->type == AJI_CONNECT_LOCAL) 00953 iks_insert_attrib(candidate, "type", "local"); 00954 if (tmp->type == AJI_CONNECT_RELAY) 00955 iks_insert_attrib(candidate, "type", "relay"); 00956 iks_insert_attrib(candidate, "network", "0"); 00957 iks_insert_attrib(candidate, "generation", "0"); 00958 ast_aji_send(c, iq); 00959 } 00960 p->laststun = 0; 00961 00962 safeout: 00963 if (ours1) 00964 ast_free(ours1); 00965 if (ours2) 00966 ast_free(ours2); 00967 iks_delete(iq); 00968 iks_delete(gtalk); 00969 iks_delete(candidate); 00970 iks_delete(transport); 00971 00972 return 1; 00973 }
static int gtalk_create_member | ( | char * | label, | |
struct ast_variable * | var, | |||
int | allowguest, | |||
struct ast_codec_pref | prefs, | |||
char * | context, | |||
struct gtalk * | member | |||
) | [static] |
Definition at line 2008 of file chan_gtalk.c.
References gtalk::allowguest, ast_aji_get_client(), ast_copy_string(), ast_log(), ast_parse_allow_disallow(), ASTOBJ_CONTAINER_FIND, aji_client::buddies, gtalk::buddy, gtalk::capability, gtalk::connection, gtalk::context, aji_client::f, GOOGLE_NS, gtalk_parser(), LOG_ERROR, LOG_WARNING, gtalk::name, gtalk::parkinglot, prefs, gtalk::prefs, gtalk::user, and var.
02011 { 02012 struct aji_client *client; 02013 02014 if (!member) 02015 ast_log(LOG_WARNING, "Out of memory.\n"); 02016 02017 ast_copy_string(member->name, label, sizeof(member->name)); 02018 ast_copy_string(member->user, label, sizeof(member->user)); 02019 ast_copy_string(member->context, context, sizeof(member->context)); 02020 member->allowguest = allowguest; 02021 member->prefs = prefs; 02022 while (var) { 02023 if (!strcasecmp(var->name, "username")) 02024 ast_copy_string(member->user, var->value, sizeof(member->user)); 02025 else if (!strcasecmp(var->name, "disallow")) 02026 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0); 02027 else if (!strcasecmp(var->name, "allow")) 02028 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1); 02029 else if (!strcasecmp(var->name, "context")) 02030 ast_copy_string(member->context, var->value, sizeof(member->context)); 02031 else if (!strcasecmp(var->name, "parkinglot")) 02032 ast_copy_string(member->parkinglot, var->value, sizeof(member->parkinglot)); 02033 else if (!strcasecmp(var->name, "connection")) { 02034 if ((client = ast_aji_get_client(var->value))) { 02035 member->connection = client; 02036 iks_filter_add_rule(client->f, gtalk_parser, member, 02037 IKS_RULE_TYPE, IKS_PAK_IQ, 02038 IKS_RULE_FROM_PARTIAL, member->user, 02039 IKS_RULE_NS, GOOGLE_NS, 02040 IKS_RULE_DONE); 02041 } else { 02042 ast_log(LOG_ERROR, "connection referenced not found!\n"); 02043 return 0; 02044 } 02045 } 02046 var = var->next; 02047 } 02048 if (member->connection && member->user) 02049 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user); 02050 else { 02051 ast_log(LOG_ERROR, "No Connection or Username!\n"); 02052 } 02053 return 1; 02054 }
static int gtalk_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 1695 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_begin(), gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.
01696 { 01697 struct gtalk_pvt *p = chan->tech_pvt; 01698 int res = 0; 01699 01700 ast_mutex_lock(&p->lock); 01701 if (p->rtp) { 01702 ast_rtp_instance_dtmf_begin(p->rtp, digit); 01703 } else { 01704 res = -1; 01705 } 01706 ast_mutex_unlock(&p->lock); 01707 01708 return res; 01709 }
static int gtalk_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 1711 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_end_with_duration(), gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.
01712 { 01713 struct gtalk_pvt *p = chan->tech_pvt; 01714 int res = 0; 01715 01716 ast_mutex_lock(&p->lock); 01717 if (p->rtp) { 01718 ast_rtp_instance_dtmf_end_with_duration(p->rtp, digit, duration); 01719 } else { 01720 res = -1; 01721 } 01722 ast_mutex_unlock(&p->lock); 01723 01724 return res; 01725 }
static int gtalk_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 1642 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, gtalk_pvt::owner, and ast_channel::tech_pvt.
01643 { 01644 struct gtalk_pvt *p = newchan->tech_pvt; 01645 ast_mutex_lock(&p->lock); 01646 01647 if ((p->owner != oldchan)) { 01648 ast_mutex_unlock(&p->lock); 01649 return -1; 01650 } 01651 if (p->owner == oldchan) 01652 p->owner = newchan; 01653 ast_mutex_unlock(&p->lock); 01654 return 0; 01655 }
static void gtalk_free_candidates | ( | struct gtalk_candidate * | candidate | ) | [static] |
Definition at line 1201 of file chan_gtalk.c.
References ast_free, last, and gtalk_candidate::next.
Referenced by gtalk_free_pvt().
01202 { 01203 struct gtalk_candidate *last; 01204 while (candidate) { 01205 last = candidate; 01206 candidate = candidate->next; 01207 ast_free(last); 01208 } 01209 }
Definition at line 1211 of file chan_gtalk.c.
References ast_free, ast_log(), ast_rtp_instance_destroy(), gtalk::connection, aji_client::f, gtalk_free_candidates(), LOG_WARNING, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::ringrule, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_pvt::vrtp.
Referenced by gtalk_hangup(), and gtalk_newcall().
01212 { 01213 struct gtalk_pvt *cur, *prev = NULL; 01214 cur = client->p; 01215 while (cur) { 01216 if (cur == p) { 01217 if (prev) 01218 prev->next = p->next; 01219 else 01220 client->p = p->next; 01221 break; 01222 } 01223 prev = cur; 01224 cur = cur->next; 01225 } 01226 if (p->ringrule) 01227 iks_filter_remove_rule(p->parent->connection->f, p->ringrule); 01228 if (p->owner) 01229 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n"); 01230 if (p->rtp) 01231 ast_rtp_instance_destroy(p->rtp); 01232 if (p->vrtp) 01233 ast_rtp_instance_destroy(p->vrtp); 01234 gtalk_free_candidates(p->theircandidates); 01235 ast_free(p); 01236 }
static format_t gtalk_get_codec | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 539 of file chan_gtalk.c.
References gtalk_pvt::peercapability, and ast_channel::tech_pvt.
00540 { 00541 struct gtalk_pvt *p = chan->tech_pvt; 00542 return p->peercapability; 00543 }
static int gtalk_get_local_ip | ( | struct ast_sockaddr * | ourip | ) | [static] |
Definition at line 810 of file chan_gtalk.c.
References ast_find_ourip(), ast_free, ast_ouraddrfor(), ast_sockaddr_copy(), ast_sockaddr_from_sin, ast_sockaddr_is_any(), ast_sockaddr_resolve(), bindaddr, and PARSE_PORT_FORBID.
Referenced by gtalk_create_candidates(), and load_module().
00811 { 00812 struct ast_sockaddr root; 00813 struct ast_sockaddr bindaddr_tmp; 00814 struct ast_sockaddr *addrs; 00815 int addrs_cnt; 00816 00817 /* If bind address is not 0.0.0.0, then bindaddr is our local ip. */ 00818 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); 00819 if (!ast_sockaddr_is_any(&bindaddr_tmp)) { 00820 ast_sockaddr_copy(ourip, &bindaddr_tmp); 00821 return 0; 00822 } 00823 00824 /* If no bind address was provided, lets see what ip we would use to connect to google.com and use that. 00825 * If you can't resolve google.com from your network, then this module is useless for you anyway. */ 00826 if ((addrs_cnt = ast_sockaddr_resolve(&addrs, "google.com", PARSE_PORT_FORBID, AF_INET)) > 0) { 00827 ast_sockaddr_copy(&root, &addrs[0]); 00828 ast_free(addrs); 00829 if (!ast_ouraddrfor(&root, ourip)) { 00830 return 0; 00831 } 00832 } 00833 00834 /* As a last resort, use this function to find our local address. */ 00835 return ast_find_ourip(ourip, &bindaddr_tmp, AF_INET); 00836 }
static enum ast_rtp_glue_result gtalk_get_rtp_peer | ( | struct ast_channel * | chan, | |
struct ast_rtp_instance ** | instance | |||
) | [static] |
Definition at line 520 of file chan_gtalk.c.
References ao2_ref, ast_mutex_lock, ast_mutex_unlock, AST_RTP_GLUE_RESULT_FORBID, AST_RTP_GLUE_RESULT_LOCAL, gtalk_pvt::lock, gtalk_pvt::rtp, and ast_channel::tech_pvt.
00521 { 00522 struct gtalk_pvt *p = chan->tech_pvt; 00523 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID; 00524 00525 if (!p) 00526 return res; 00527 00528 ast_mutex_lock(&p->lock); 00529 if (p->rtp){ 00530 ao2_ref(p->rtp, +1); 00531 *instance = p->rtp; 00532 res = AST_RTP_GLUE_RESULT_LOCAL; 00533 } 00534 ast_mutex_unlock(&p->lock); 00535 00536 return res; 00537 }
static int gtalk_handle_dtmf | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 711 of file chan_gtalk.c.
References AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_log(), ast_queue_frame(), ast_verbose, gtalk::connection, f, gtalk_response(), aji_client::jid, LOG_NOTICE, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, and gtalk_pvt::sid.
Referenced by gtalk_parser().
00712 { 00713 struct gtalk_pvt *tmp; 00714 iks *dtmfnode = NULL, *dtmfchild = NULL; 00715 char *dtmf; 00716 char *from; 00717 /* Make sure our new call doesn't exist yet */ 00718 for (tmp = client->p; tmp; tmp = tmp->next) { 00719 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || iks_find_with_attrib(pak->x, "gtalk", "sid", tmp->sid)) 00720 break; 00721 } 00722 from = iks_find_attrib(pak->x, "to"); 00723 if (!from) { 00724 from = client->connection->jid->full; 00725 } 00726 00727 if (tmp) { 00728 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) { 00729 gtalk_response(client, from, pak, 00730 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", 00731 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'"); 00732 return -1; 00733 } 00734 if ((dtmfnode = iks_find(pak->x, "dtmf"))) { 00735 if((dtmf = iks_find_attrib(dtmfnode, "code"))) { 00736 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) { 00737 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; 00738 f.subclass.integer = dtmf[0]; 00739 ast_queue_frame(tmp->owner, &f); 00740 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); 00741 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) { 00742 struct ast_frame f = {AST_FRAME_DTMF_END, }; 00743 f.subclass.integer = dtmf[0]; 00744 ast_queue_frame(tmp->owner, &f); 00745 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); 00746 } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */ 00747 struct ast_frame f = {AST_FRAME_DTMF, }; 00748 f.subclass.integer = dtmf[0]; 00749 ast_queue_frame(tmp->owner, &f); 00750 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); 00751 } 00752 } 00753 } else if ((dtmfnode = iks_find_with_attrib(pak->x, "gtalk", "action", "session-info"))) { 00754 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) { 00755 if((dtmf = iks_find_attrib(dtmfchild, "code"))) { 00756 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) { 00757 struct ast_frame f = {AST_FRAME_DTMF_END, }; 00758 f.subclass.integer = dtmf[0]; 00759 ast_queue_frame(tmp->owner, &f); 00760 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); 00761 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) { 00762 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, }; 00763 f.subclass.integer = dtmf[0]; 00764 ast_queue_frame(tmp->owner, &f); 00765 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", (int) f.subclass.integer); 00766 } 00767 } 00768 } 00769 } 00770 gtalk_response(client, from, pak, NULL, NULL); 00771 return 1; 00772 } else { 00773 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n"); 00774 } 00775 00776 gtalk_response(client, from, pak, NULL, NULL); 00777 return 1; 00778 }
static int gtalk_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the gtalk proxy channel.
Definition at line 1819 of file chan_gtalk.c.
References gtalk_pvt::alreadygone, ast_module_unref(), ast_mutex_lock, ast_mutex_unlock, gtalk_action(), gtalk_free_pvt(), gtalk_pvt::lock, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, and ast_channel::tech_pvt.
Referenced by gtalk_newcall().
01820 { 01821 struct gtalk_pvt *p = ast->tech_pvt; 01822 struct gtalk *client; 01823 01824 ast_mutex_lock(&p->lock); 01825 client = p->parent; 01826 p->owner = NULL; 01827 ast->tech_pvt = NULL; 01828 if (!p->alreadygone) { 01829 gtalk_action(client, p, "terminate"); 01830 } 01831 ast_mutex_unlock(&p->lock); 01832 01833 gtalk_free_pvt(client, p); 01834 ast_module_unref(ast_module_info->self); 01835 01836 return 0; 01837 }
static int gtalk_hangup_farend | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 780 of file chan_gtalk.c.
References gtalk_pvt::alreadygone, ast_debug, ast_log(), ast_queue_hangup(), gtalk::connection, gtalk_response(), aji_client::jid, LOG_NOTICE, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, and gtalk_pvt::sid.
Referenced by gtalk_parser().
00781 { 00782 struct gtalk_pvt *tmp; 00783 char *from; 00784 00785 ast_debug(1, "The client is %s\n", client->name); 00786 /* Make sure our new call doesn't exist yet */ 00787 for (tmp = client->p; tmp; tmp = tmp->next) { 00788 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || 00789 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { 00790 break; 00791 } 00792 } 00793 from = iks_find_attrib(pak->x, "to"); 00794 if (!from) { 00795 from = client->connection->jid->full; 00796 } 00797 00798 if (tmp) { 00799 tmp->alreadygone = 1; 00800 if (tmp->owner) { 00801 ast_queue_hangup(tmp->owner); 00802 } 00803 } else { 00804 ast_log(LOG_NOTICE, "Whoa, didn't find call during hangup!\n"); 00805 } 00806 gtalk_response(client, from, pak, NULL, NULL); 00807 return 1; 00808 }
static int gtalk_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 1657 of file chan_gtalk.c.
References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, ast_moh_start(), and ast_moh_stop().
01658 { 01659 int res = 0; 01660 01661 switch (condition) { 01662 case AST_CONTROL_HOLD: 01663 ast_moh_start(ast, data, NULL); 01664 break; 01665 case AST_CONTROL_UNHOLD: 01666 ast_moh_stop(ast); 01667 break; 01668 default: 01669 ast_debug(3, "Don't know how to indicate condition '%d'\n", condition); 01670 res = -1; 01671 } 01672 01673 return res; 01674 }
static int gtalk_invite | ( | struct gtalk_pvt * | p, | |
char * | to, | |||
char * | from, | |||
char * | sid, | |||
int | initiator | |||
) | [static] |
Definition at line 382 of file chan_gtalk.c.
References add_codec_to_answer(), ast_aji_increment_mid(), ast_aji_send(), ast_codec_pref_index(), ast_log(), ast_strdupa, gtalk::capability, gtalk::connection, GOOGLE_AUDIO_NS, GOOGLE_NS, GOOGLE_TRANSPORT_NS, LOG_ERROR, aji_client::mid, gtalk::p, gtalk_pvt::parent, and gtalk::prefs.
Referenced by gtalk_answer(), gtalk_call(), and gtalk_ringing_ack().
00383 { 00384 struct gtalk *client = p->parent; 00385 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport; 00386 int x; 00387 int pref_codec = 0; 00388 int alreadysent = 0; 00389 int codecs_num = 0; 00390 char *lowerto = NULL; 00391 00392 iq = iks_new("iq"); 00393 gtalk = iks_new("session"); 00394 dcodecs = iks_new("description"); 00395 transport = iks_new("transport"); 00396 payload_telephone = iks_new("payload-type"); 00397 if (!(iq && gtalk && dcodecs && transport && payload_telephone)){ 00398 iks_delete(iq); 00399 iks_delete(gtalk); 00400 iks_delete(dcodecs); 00401 iks_delete(transport); 00402 iks_delete(payload_telephone); 00403 00404 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n"); 00405 return 0; 00406 } 00407 iks_insert_attrib(dcodecs, "xmlns", GOOGLE_AUDIO_NS); 00408 iks_insert_attrib(dcodecs, "xml:lang", "en"); 00409 00410 for (x = 0; x < 64; x++) { 00411 if (!(pref_codec = ast_codec_pref_index(&client->prefs, x))) 00412 break; 00413 if (!(client->capability & pref_codec)) 00414 continue; 00415 if (alreadysent & pref_codec) 00416 continue; 00417 codecs_num = add_codec_to_answer(p, pref_codec, dcodecs); 00418 alreadysent |= pref_codec; 00419 } 00420 00421 if (codecs_num) { 00422 /* only propose DTMF within an audio session */ 00423 iks_insert_attrib(payload_telephone, "id", "101"); 00424 iks_insert_attrib(payload_telephone, "name", "telephone-event"); 00425 iks_insert_attrib(payload_telephone, "clockrate", "8000"); 00426 } 00427 iks_insert_attrib(transport,"xmlns",GOOGLE_TRANSPORT_NS); 00428 00429 iks_insert_attrib(iq, "type", "set"); 00430 iks_insert_attrib(iq, "to", to); 00431 iks_insert_attrib(iq, "from", from); 00432 iks_insert_attrib(iq, "id", client->connection->mid); 00433 ast_aji_increment_mid(client->connection->mid); 00434 00435 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); 00436 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept"); 00437 /* put the initiator attribute to lower case if we receive the call 00438 * otherwise GoogleTalk won't establish the session */ 00439 if (!initiator) { 00440 char c; 00441 char *t = lowerto = ast_strdupa(to); 00442 while (((c = *t) != '/') && (*t++ = tolower(c))); 00443 } 00444 iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto); 00445 iks_insert_attrib(gtalk, "id", sid); 00446 iks_insert_node(iq, gtalk); 00447 iks_insert_node(gtalk, dcodecs); 00448 iks_insert_node(dcodecs, payload_telephone); 00449 00450 ast_aji_send(client->connection, iq); 00451 00452 iks_delete(payload_telephone); 00453 iks_delete(transport); 00454 iks_delete(dcodecs); 00455 iks_delete(gtalk); 00456 iks_delete(iq); 00457 return 1; 00458 }
static int gtalk_is_accepted | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 682 of file chan_gtalk.c.
References ast_log(), gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, LOG_DEBUG, LOG_NOTICE, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::parent, and gtalk_pvt::sid.
Referenced by gtalk_parser().
00683 { 00684 struct gtalk_pvt *tmp; 00685 char *from; 00686 00687 ast_log(LOG_DEBUG, "The client is %s\n", client->name); 00688 /* find corresponding call */ 00689 for (tmp = client->p; tmp; tmp = tmp->next) { 00690 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { 00691 break; 00692 } 00693 } 00694 00695 from = iks_find_attrib(pak->x, "to"); 00696 if (!from) { 00697 from = client->connection->jid->full; 00698 } 00699 00700 if (tmp) { 00701 gtalk_update_stun(tmp->parent, tmp); 00702 } else { 00703 ast_log(LOG_NOTICE, "Whoa, didn't find call during accept?!\n"); 00704 } 00705 00706 /* answer 'iq' packet to let the remote peer know that we're alive */ 00707 gtalk_response(client, from, pak, NULL, NULL); 00708 return 1; 00709 }
static int gtalk_is_answered | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 604 of file chan_gtalk.c.
References AST_CONTROL_ANSWER, ast_getformatname_multiple(), ast_log(), ast_queue_control(), ast_queue_hangup(), ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), gtalk_pvt::capability, gtalk::connection, gtalk_response(), gtalk_update_stun(), aji_client::jid, gtalk_pvt::jointcapability, LOG_DEBUG, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk_pvt::owner, gtalk::p, gtalk_pvt::parent, gtalk_pvt::peercapability, gtalk_pvt::rtp, and gtalk_pvt::sid.
Referenced by gtalk_parser().
00605 { 00606 struct gtalk_pvt *tmp = NULL; 00607 char *from; 00608 iks *codec; 00609 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; 00610 int peernoncodeccapability; 00611 00612 ast_log(LOG_DEBUG, "The client is %s\n", client->name); 00613 00614 /* Make sure our new call does exist */ 00615 for (tmp = client->p; tmp; tmp = tmp->next) { 00616 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { 00617 break; 00618 } else if (iks_find_with_attrib(pak->x, "ses:session", "id", tmp->sid)) { 00619 break; 00620 } 00621 } 00622 00623 if (!tmp) { 00624 ast_log(LOG_WARNING, "Could not find session in iq\n"); 00625 return -1; 00626 } 00627 00628 /* codec points to the first <payload-type/> tag */ 00629 codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x))); 00630 while (codec) { 00631 char *codec_id = iks_find_attrib(codec, "id"); 00632 char *codec_name = iks_find_attrib(codec, "name"); 00633 if (!codec_id || !codec_name) { 00634 codec = iks_next_tag(codec); 00635 continue; 00636 } 00637 00638 ast_rtp_codecs_payloads_set_m_type( 00639 ast_rtp_instance_get_codecs(tmp->rtp), 00640 tmp->rtp, 00641 atoi(codec_id)); 00642 ast_rtp_codecs_payloads_set_rtpmap_type( 00643 ast_rtp_instance_get_codecs(tmp->rtp), 00644 tmp->rtp, 00645 atoi(codec_id), 00646 "audio", 00647 codec_name, 00648 0); 00649 codec = iks_next_tag(codec); 00650 } 00651 00652 /* Now gather all of the codecs that we are asked for */ 00653 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability); 00654 00655 /* at this point, we received an awser from the remote Gtalk client, 00656 which allows us to compare capabilities */ 00657 tmp->jointcapability = tmp->capability & tmp->peercapability; 00658 if (!tmp->jointcapability) { 00659 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, tmp->capability), 00660 ast_getformatname_multiple(s2, BUFSIZ, tmp->peercapability), 00661 ast_getformatname_multiple(s3, BUFSIZ, tmp->jointcapability)); 00662 /* close session if capabilities don't match */ 00663 ast_queue_hangup(tmp->owner); 00664 00665 return -1; 00666 00667 } 00668 00669 from = iks_find_attrib(pak->x, "to"); 00670 if (!from) { 00671 from = client->connection->jid->full; 00672 } 00673 00674 if (tmp->owner) { 00675 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER); 00676 } 00677 gtalk_update_stun(tmp->parent, tmp); 00678 gtalk_response(client, from, pak, NULL, NULL); 00679 return 1; 00680 }
static int gtalk_load_config | ( | void | ) | [static] |
Definition at line 2056 of file chan_gtalk.c.
References ahp, ast_category_browse(), ast_config_load, ast_jb_read_conf(), ast_log(), AST_MAX_CONTEXT, ast_parse_allow_disallow(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clients, config_flags, CONFIG_STATUS_FILEINVALID, context, default_jbconf, global_capability, global_jbconf, GOOGLE_CONFIG, hp, LOG_ERROR, parkinglot, prefs, stunaddr, and var.
Referenced by load_module().
02057 { 02058 char *cat = NULL; 02059 struct ast_config *cfg = NULL; 02060 char context[AST_MAX_CONTEXT]; 02061 char parkinglot[AST_MAX_CONTEXT]; 02062 int allowguest = 1; 02063 struct ast_variable *var; 02064 struct gtalk *member; 02065 struct ast_codec_pref prefs; 02066 struct aji_client_container *clients; 02067 struct gtalk_candidate *global_candidates = NULL; 02068 struct hostent *hp; 02069 struct ast_hostent ahp; 02070 struct ast_flags config_flags = { 0 }; 02071 02072 cfg = ast_config_load(GOOGLE_CONFIG, config_flags); 02073 if (!cfg) { 02074 return 0; 02075 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 02076 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG); 02077 return 0; 02078 } 02079 02080 /* Copy the default jb config over global_jbconf */ 02081 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); 02082 02083 /* set defaults */ 02084 memset(&stunaddr, 0, sizeof(stunaddr)); 02085 02086 cat = ast_category_browse(cfg, NULL); 02087 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02088 /* handle jb conf */ 02089 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value)) 02090 continue; 02091 02092 if (!strcasecmp(var->name, "allowguest")) { 02093 allowguest = (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0; 02094 } else if (!strcasecmp(var->name, "disallow")) { 02095 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0); 02096 } else if (!strcasecmp(var->name, "allow")) { 02097 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1); 02098 } else if (!strcasecmp(var->name, "context")) { 02099 ast_copy_string(context, var->value, sizeof(context)); 02100 } else if (!strcasecmp(var->name, "externip")) { 02101 ast_copy_string(externip, var->value, sizeof(externip)); 02102 } else if (!strcasecmp(var->name, "parkinglot")) { 02103 ast_copy_string(parkinglot, var->value, sizeof(parkinglot)); 02104 } else if (!strcasecmp(var->name, "bindaddr")) { 02105 if (!(hp = ast_gethostbyname(var->value, &ahp))) { 02106 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value); 02107 } else { 02108 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); 02109 } 02110 } else if (!strcasecmp(var->name, "stunaddr")) { 02111 stunaddr.sin_port = htons(STANDARD_STUN_PORT); 02112 if (ast_parse_arg(var->value, PARSE_INADDR, &stunaddr)) { 02113 ast_log(LOG_WARNING, "Invalid STUN server address: %s\n", var->value); 02114 } 02115 } 02116 } 02117 while (cat) { 02118 if (strcasecmp(cat, "general")) { 02119 var = ast_variable_browse(cfg, cat); 02120 member = ast_calloc(1, sizeof(*member)); 02121 ASTOBJ_INIT(member); 02122 ASTOBJ_WRLOCK(member); 02123 if (!strcasecmp(cat, "guest")) { 02124 ast_copy_string(member->name, "guest", sizeof(member->name)); 02125 ast_copy_string(member->user, "guest", sizeof(member->user)); 02126 ast_copy_string(member->context, context, sizeof(member->context)); 02127 ast_copy_string(member->parkinglot, parkinglot, sizeof(member->parkinglot)); 02128 member->allowguest = allowguest; 02129 member->prefs = prefs; 02130 while (var) { 02131 if (!strcasecmp(var->name, "disallow")) { 02132 ast_parse_allow_disallow(&member->prefs, &member->capability, 02133 var->value, 0); 02134 } else if (!strcasecmp(var->name, "allow")) { 02135 ast_parse_allow_disallow(&member->prefs, &member->capability, 02136 var->value, 1); 02137 } else if (!strcasecmp(var->name, "context")) { 02138 ast_copy_string(member->context, var->value, 02139 sizeof(member->context)); 02140 } else if (!strcasecmp(var->name, "parkinglot")) { 02141 ast_copy_string(member->parkinglot, var->value, 02142 sizeof(member->parkinglot)); 02143 } 02144 var = var->next; 02145 } 02146 ASTOBJ_UNLOCK(member); 02147 clients = ast_aji_get_clients(); 02148 if (clients) { 02149 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, { 02150 ASTOBJ_WRLOCK(iterator); 02151 ASTOBJ_WRLOCK(member); 02152 member->connection = NULL; 02153 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE); 02154 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, "http://jabber.org/protocol/gtalk", IKS_RULE_DONE); 02155 ASTOBJ_UNLOCK(member); 02156 ASTOBJ_UNLOCK(iterator); 02157 }); 02158 ASTOBJ_CONTAINER_LINK(>alk_list, member); 02159 ASTOBJ_UNREF(member, gtalk_member_destroy); 02160 } else { 02161 ASTOBJ_UNLOCK(member); 02162 ASTOBJ_UNREF(member, gtalk_member_destroy); 02163 } 02164 } else { 02165 ASTOBJ_UNLOCK(member); 02166 if (gtalk_create_member(cat, var, allowguest, prefs, context, member)) 02167 ASTOBJ_CONTAINER_LINK(>alk_list, member); 02168 ASTOBJ_UNREF(member, gtalk_member_destroy); 02169 } 02170 } 02171 cat = ast_category_browse(cfg, cat); 02172 } 02173 02174 gtalk_update_externip(); 02175 gtalk_free_candidates(global_candidates); 02176 return 1; 02177 }
static void gtalk_member_destroy | ( | struct gtalk * | obj | ) | [static] |
Definition at line 240 of file chan_gtalk.c.
References ast_free.
Referenced by gtalk_parser(), gtalk_request(), and unload_module().
00241 { 00242 ast_free(obj); 00243 }
static struct ast_channel* gtalk_new | ( | struct gtalk * | client, | |
struct gtalk_pvt * | i, | |||
int | state, | |||
const char * | title, | |||
const char * | linkedid | |||
) | [static] |
Start new gtalk channel.
Definition at line 1073 of file chan_gtalk.c.
References accountcode, gtalk::accountcode, ast_channel::adsicpe, ast_channel::amaflags, gtalk::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), AST_CAUSE_SWITCH_CONGESTION, ast_channel_alloc, ast_channel_set_fd(), ast_codec_choose(), ast_copy_string(), AST_FORMAT_VIDEO_MASK, ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_random(), ast_rtp_codecs_packetization_set(), ast_rtp_instance_fd(), ast_rtp_instance_get_codecs(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_channel::caller, gtalk::callgroup, ast_channel::callgroup, gtalk::callingpres, gtalk_pvt::capability, gtalk_pvt::cid_name, gtalk_pvt::cid_num, ast_channel::context, gtalk::context, ast_channel::dialed, EVENT_FLAG_SYSTEM, ast_channel::exten, gtalk_pvt::exten, global_capability, global_jbconf, gtalk_tech, ast_channel::hangupcause, ast_party_caller::id, gtalk_pvt::jointcapability, language, gtalk::language, LOG_WARNING, manager_event, musicclass, gtalk::musicclass, ast_channel::name, ast_party_id::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, gtalk_pvt::owner, parkinglot, gtalk::parkinglot, gtalk::pickupgroup, ast_channel::pickupgroup, gtalk_pvt::prefs, ast_party_number::presentation, ast_party_name::presentation, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, gtalk_pvt::rtp, gtalk_pvt::sid, ast_party_dialed::str, ast_channel::tech, ast_channel::tech_pvt, gtalk_pvt::us, gtalk_pvt::vrtp, and ast_channel::writeformat.
Referenced by gtalk_newcall(), and gtalk_request().
01074 { 01075 struct ast_channel *tmp; 01076 int fmt; 01077 int what; 01078 const char *n2; 01079 01080 if (title) 01081 n2 = title; 01082 else 01083 n2 = i->us; 01084 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff); 01085 if (!tmp) { 01086 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n"); 01087 return NULL; 01088 } 01089 tmp->tech = >alk_tech; 01090 01091 /* Select our native format based on codec preference until we receive 01092 something from another device to the contrary. */ 01093 if (i->jointcapability) 01094 what = i->jointcapability; 01095 else if (i->capability) 01096 what = i->capability; 01097 else 01098 what = global_capability; 01099 01100 /* Set Frame packetization */ 01101 if (i->rtp) { 01102 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs); 01103 } 01104 01105 tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK); 01106 fmt = ast_best_codec(tmp->nativeformats); 01107 01108 if (i->rtp) { 01109 ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); 01110 ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); 01111 } 01112 if (i->vrtp) { 01113 ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); 01114 ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1)); 01115 } 01116 if (state == AST_STATE_RING) 01117 tmp->rings = 1; 01118 tmp->adsicpe = AST_ADSI_UNAVAILABLE; 01119 tmp->writeformat = fmt; 01120 tmp->rawwriteformat = fmt; 01121 tmp->readformat = fmt; 01122 tmp->rawreadformat = fmt; 01123 tmp->tech_pvt = i; 01124 01125 tmp->callgroup = client->callgroup; 01126 tmp->pickupgroup = client->pickupgroup; 01127 tmp->caller.id.name.presentation = client->callingpres; 01128 tmp->caller.id.number.presentation = client->callingpres; 01129 if (!ast_strlen_zero(client->accountcode)) 01130 ast_string_field_set(tmp, accountcode, client->accountcode); 01131 if (client->amaflags) 01132 tmp->amaflags = client->amaflags; 01133 if (!ast_strlen_zero(client->language)) 01134 ast_string_field_set(tmp, language, client->language); 01135 if (!ast_strlen_zero(client->musicclass)) 01136 ast_string_field_set(tmp, musicclass, client->musicclass); 01137 if (!ast_strlen_zero(client->parkinglot)) 01138 ast_string_field_set(tmp, parkinglot, client->parkinglot); 01139 i->owner = tmp; 01140 ast_module_ref(ast_module_info->self); 01141 ast_copy_string(tmp->context, client->context, sizeof(tmp->context)); 01142 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten)); 01143 01144 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) { 01145 tmp->dialed.number.str = ast_strdup(i->exten); 01146 } 01147 tmp->priority = 1; 01148 if (i->rtp) 01149 ast_jb_configure(tmp, &global_jbconf); 01150 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { 01151 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); 01152 tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION; 01153 ast_hangup(tmp); 01154 tmp = NULL; 01155 } else { 01156 manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", 01157 "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n", 01158 i->owner ? i->owner->name : "", "Gtalk", i->sid); 01159 } 01160 return tmp; 01161 }
static int gtalk_newcall | ( | struct gtalk * | client, | |
ikspak * | pak | |||
) | [static] |
Definition at line 1239 of file chan_gtalk.c.
References gtalk_pvt::alreadygone, ast_aji_get_client(), ast_channel_release(), ast_copy_string(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_PBX_CALL_LIMIT, AST_PBX_FAILED, ast_pbx_start(), AST_PBX_SUCCESS, ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, gtalk_pvt::capability, gtalk::connection, gtalk_action(), gtalk_alloc(), gtalk_create_candidates(), gtalk_free_pvt(), gtalk_hangup(), gtalk_new(), gtalk_response(), aji_client::jid, gtalk_pvt::jointcapability, gtalk_pvt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, gtalk::name, gtalk_pvt::next, gtalk::p, gtalk_pvt::peercapability, gtalk_pvt::rtp, S_OR, gtalk_pvt::sid, gtalk_pvt::them, gtalk_pvt::us, and gtalk_pvt::vrtp.
Referenced by gtalk_parser().
01240 { 01241 struct gtalk_pvt *p, *tmp = client->p; 01242 struct ast_channel *chan; 01243 int res; 01244 iks *codec; 01245 char *from = NULL; 01246 char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; 01247 int peernoncodeccapability; 01248 char *sid; 01249 01250 /* Make sure our new call doesn't exist yet */ 01251 from = iks_find_attrib(pak->x,"to"); 01252 if (!from) { 01253 from = client->connection->jid->full; 01254 } 01255 01256 while (tmp) { 01257 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid) || 01258 (iks_find_attrib(pak->query, "id") && !strcmp(iks_find_attrib(pak->query, "id"), tmp->sid))) { 01259 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid); 01260 gtalk_response(client, from, pak, "out-of-order", NULL); 01261 return -1; 01262 } 01263 tmp = tmp->next; 01264 } 01265 01266 if (!strcasecmp(client->name, "guest")){ 01267 /* the guest account is not tied to any configured XMPP client, 01268 let's set it now */ 01269 client->connection = ast_aji_get_client(from); 01270 if (!client->connection) { 01271 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from); 01272 return -1; 01273 } 01274 } 01275 01276 if (!(sid = iks_find_attrib(pak->query, "id"))) { 01277 ast_log(LOG_WARNING, "Received Initiate without id attribute. Can not start call.\n"); 01278 return -1; 01279 } 01280 01281 p = gtalk_alloc(client, from, pak->from->full, sid); 01282 if (!p) { 01283 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n"); 01284 return -1; 01285 } 01286 01287 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user, NULL); 01288 if (!chan) { 01289 gtalk_free_pvt(client, p); 01290 return -1; 01291 } 01292 01293 ast_mutex_lock(&p->lock); 01294 ast_copy_string(p->them, pak->from->full, sizeof(p->them)); 01295 ast_copy_string(p->sid, sid, sizeof(p->sid)); 01296 01297 /* codec points to the first <payload-type/> tag */ 01298 codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x))); 01299 01300 while (codec) { 01301 char *codec_id = iks_find_attrib(codec, "id"); 01302 char *codec_name = iks_find_attrib(codec, "name"); 01303 if (!codec_id || !codec_name) { 01304 codec = iks_next_tag(codec); 01305 continue; 01306 } 01307 if (!strcmp(S_OR(iks_name(codec), ""), "vid:payload-type") && p->vrtp) { 01308 ast_rtp_codecs_payloads_set_m_type( 01309 ast_rtp_instance_get_codecs(p->vrtp), 01310 p->vrtp, 01311 atoi(codec_id)); 01312 ast_rtp_codecs_payloads_set_rtpmap_type( 01313 ast_rtp_instance_get_codecs(p->vrtp), 01314 p->vrtp, 01315 atoi(codec_id), 01316 "video", 01317 codec_name, 01318 0); 01319 } else { 01320 ast_rtp_codecs_payloads_set_m_type( 01321 ast_rtp_instance_get_codecs(p->rtp), 01322 p->rtp, 01323 atoi(codec_id)); 01324 ast_rtp_codecs_payloads_set_rtpmap_type( 01325 ast_rtp_instance_get_codecs(p->rtp), 01326 p->rtp, 01327 atoi(codec_id), 01328 "audio", 01329 codec_name, 01330 0); 01331 } 01332 codec = iks_next_tag(codec); 01333 } 01334 01335 /* Now gather all of the codecs that we are asked for */ 01336 ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), &p->peercapability, &peernoncodeccapability); 01337 p->jointcapability = p->capability & p->peercapability; 01338 ast_mutex_unlock(&p->lock); 01339 01340 ast_setstate(chan, AST_STATE_RING); 01341 if (!p->jointcapability) { 01342 ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability), 01343 ast_getformatname_multiple(s2, BUFSIZ, p->peercapability), 01344 ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability)); 01345 /* close session if capabilities don't match */ 01346 gtalk_action(client, p, "reject"); 01347 p->alreadygone = 1; 01348 gtalk_hangup(chan); 01349 ast_channel_release(chan); 01350 return -1; 01351 } 01352 01353 res = ast_pbx_start(chan); 01354 01355 switch (res) { 01356 case AST_PBX_FAILED: 01357 ast_log(LOG_WARNING, "Failed to start PBX :(\n"); 01358 gtalk_response(client, from, pak, "service-unavailable", NULL); 01359 break; 01360 case AST_PBX_CALL_LIMIT: 01361 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n"); 01362 gtalk_response(client, from, pak, "service-unavailable", NULL); 01363 break; 01364 case AST_PBX_SUCCESS: 01365 gtalk_response(client, from, pak, NULL, NULL); 01366 gtalk_create_candidates(client, p, p->sid, p->them, p->us); 01367 /* nothing to do */ 01368 break; 01369 } 01370 01371 return 1; 01372 }
static int gtalk_parser | ( | void * | data, | |
ikspak * | pak | |||
) | [static] |
CLI command "gtalk reload".
Definition at line 1971 of file chan_gtalk.c.
References ast_debug, ast_log(), ast_strlen_zero(), ASTOBJ_REF, ASTOBJ_UNREF, gtalk_add_candidate(), gtalk_handle_dtmf(), gtalk_hangup_farend(), gtalk_is_accepted(), gtalk_is_answered(), gtalk_member_destroy(), gtalk_newcall(), LOG_NOTICE, LOG_WARNING, and S_OR.
Referenced by gtalk_create_member().
01972 { 01973 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data); 01974 int res; 01975 01976 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) { 01977 ast_log(LOG_NOTICE, "Remote peer reported an error, trying to establish the call anyway\n"); 01978 } 01979 01980 if (ast_strlen_zero(iks_find_attrib(pak->query, "type"))) { 01981 ast_log(LOG_NOTICE, "No attribute \"type\" found. Ignoring message.\n"); 01982 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "initiate")) { 01983 /* New call */ 01984 gtalk_newcall(client, pak); 01985 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "candidates") || !strcmp(iks_find_attrib(pak->query, "type"), "transport-info")) { 01986 ast_debug(3, "About to add candidate!\n"); 01987 res = gtalk_add_candidate(client, pak); 01988 if (!res) { 01989 ast_log(LOG_WARNING, "Could not add any candidate\n"); 01990 } else { 01991 ast_debug(3, "Candidate Added!\n"); 01992 } 01993 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "accept")) { 01994 gtalk_is_answered(client, pak); 01995 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "transport-accept")) { 01996 gtalk_is_accepted(client, pak); 01997 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "content-info") || iks_find_with_attrib(pak->x, "gtalk", "action", "session-info")) { 01998 gtalk_handle_dtmf(client, pak); 01999 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "terminate")) { 02000 gtalk_hangup_farend(client, pak); 02001 } else if (!strcmp(iks_find_attrib(pak->query, "type"), "reject")) { 02002 gtalk_hangup_farend(client, pak); 02003 } 02004 ASTOBJ_UNREF(client, gtalk_member_destroy); 02005 return IKS_FILTER_EAT; 02006 }
static struct ast_frame * gtalk_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 1584 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_rtp_read(), gtalk_pvt::lock, and ast_channel::tech_pvt.
01585 { 01586 struct ast_frame *fr; 01587 struct gtalk_pvt *p = ast->tech_pvt; 01588 01589 ast_mutex_lock(&p->lock); 01590 fr = gtalk_rtp_read(ast, p); 01591 ast_mutex_unlock(&p->lock); 01592 return fr; 01593 }
static struct ast_channel * gtalk_request | ( | const char * | type, | |
format_t | format, | |||
const struct ast_channel * | requestor, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 1840 of file chan_gtalk.c.
References ast_aji_get_client(), ast_log(), AST_STATE_DOWN, ast_strdupa, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, gtalk::connection, find_gtalk(), gtalk_alloc(), gtalk_member_destroy(), gtalk_new(), aji_client::jid, ast_channel::linkedid, LOG_ERROR, LOG_WARNING, gtalk::name, strsep(), and gtalk::user.
01841 { 01842 struct gtalk_pvt *p = NULL; 01843 struct gtalk *client = NULL; 01844 char *sender = NULL, *to = NULL, *s = NULL; 01845 struct ast_channel *chan = NULL; 01846 01847 if (data) { 01848 s = ast_strdupa(data); 01849 if (s) { 01850 sender = strsep(&s, "/"); 01851 if (sender && (sender[0] != '\0')) { 01852 to = strsep(&s, "/"); 01853 } 01854 if (!to) { 01855 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data); 01856 return NULL; 01857 } 01858 } 01859 } 01860 01861 client = find_gtalk(to, sender); 01862 if (!client) { 01863 ast_log(LOG_WARNING, "Could not find recipient.\n"); 01864 return NULL; 01865 } 01866 if (!strcasecmp(client->name, "guest")){ 01867 /* the guest account is not tied to any configured XMPP client, 01868 let's set it now */ 01869 client->connection = ast_aji_get_client(sender); 01870 if (!client->connection) { 01871 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender); 01872 ASTOBJ_UNREF(client, gtalk_member_destroy); 01873 return NULL; 01874 } 01875 } 01876 01877 ASTOBJ_WRLOCK(client); 01878 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL); 01879 if (p) { 01880 chan = gtalk_new(client, p, AST_STATE_DOWN, to, requestor ? requestor->linkedid : NULL); 01881 } 01882 ASTOBJ_UNLOCK(client); 01883 return chan; 01884 }
static int gtalk_response | ( | struct gtalk * | client, | |
char * | from, | |||
ikspak * | pak, | |||
const char * | reasonstr, | |||
const char * | reasonstr2 | |||
) | [static] |
Definition at line 572 of file chan_gtalk.c.
References ast_aji_send(), gtalk::connection, and S_OR.
Referenced by gtalk_handle_dtmf(), gtalk_hangup_farend(), gtalk_is_accepted(), gtalk_is_answered(), and gtalk_newcall().
00573 { 00574 iks *response = NULL, *error = NULL, *reason = NULL; 00575 int res = -1; 00576 00577 response = iks_new("iq"); 00578 if (response) { 00579 iks_insert_attrib(response, "type", "result"); 00580 iks_insert_attrib(response, "from", from); 00581 iks_insert_attrib(response, "to", S_OR(iks_find_attrib(pak->x, "from"), "")); 00582 iks_insert_attrib(response, "id", S_OR(iks_find_attrib(pak->x, "id"), "")); 00583 if (reasonstr) { 00584 error = iks_new("error"); 00585 if (error) { 00586 iks_insert_attrib(error, "type", "cancel"); 00587 reason = iks_new(reasonstr); 00588 if (reason) 00589 iks_insert_node(error, reason); 00590 iks_insert_node(response, error); 00591 } 00592 } 00593 ast_aji_send(client->connection, response); 00594 res = 0; 00595 } 00596 00597 iks_delete(reason); 00598 iks_delete(error); 00599 iks_delete(response); 00600 00601 return res; 00602 }
static int gtalk_ringing_ack | ( | void * | data, | |
ikspak * | pak | |||
) | [static] |
Definition at line 460 of file chan_gtalk.c.
References AST_CONTROL_RINGING, ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), gtalk::connection, aji_client::f, gtalk_create_candidates(), gtalk_invite(), gtalk_pvt::lock, LOG_DEBUG, name, gtalk_pvt::owner, gtalk_pvt::parent, gtalk_pvt::ringrule, S_OR, gtalk_pvt::sid, gtalk_pvt::them, and gtalk_pvt::us.
Referenced by gtalk_call().
00461 { 00462 struct gtalk_pvt *p = data; 00463 struct ast_channel *owner; 00464 00465 ast_mutex_lock(&p->lock); 00466 00467 if (p->ringrule) { 00468 iks_filter_remove_rule(p->parent->connection->f, p->ringrule); 00469 } 00470 p->ringrule = NULL; 00471 00472 /* this may be a redirect */ 00473 if (!strcmp(S_OR(iks_find_attrib(pak->x, "type"), ""), "error")) { 00474 char *name = NULL; 00475 char *redirect = NULL; 00476 iks *traversenodes = NULL; 00477 traversenodes = pak->query; 00478 while (traversenodes) { 00479 if (!(name = iks_name(traversenodes))) { 00480 break; 00481 } 00482 if (!strcasecmp(name, "error") && 00483 (redirect = iks_find_cdata(traversenodes, "redirect")) && 00484 (redirect = strstr(redirect, "xmpp:"))) { 00485 redirect += 5; 00486 ast_log(LOG_DEBUG, "redirect %s\n", redirect); 00487 ast_copy_string(p->them, redirect, sizeof(p->them)); 00488 00489 gtalk_invite(p, p->them, p->us, p->sid, 1); 00490 break; 00491 } 00492 traversenodes = iks_next_tag(traversenodes); 00493 } 00494 } 00495 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us); 00496 owner = p->owner; 00497 ast_mutex_unlock(&p->lock); 00498 00499 if (owner) { 00500 ast_queue_control(owner, AST_CONTROL_RINGING); 00501 } 00502 00503 return IKS_FILTER_EAT; 00504 }
static struct ast_frame* gtalk_rtp_read | ( | struct ast_channel * | ast, | |
struct gtalk_pvt * | p | |||
) | [static] |
Definition at line 1555 of file chan_gtalk.c.
References ast_debug, AST_FORMAT_AUDIO_MASK, AST_FORMAT_VIDEO_MASK, AST_FRAME_VOICE, ast_getformatname(), ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), f, gtalk_update_stun(), ast_channel::nativeformats, gtalk_pvt::owner, gtalk_pvt::parent, ast_channel::readformat, gtalk_pvt::rtp, and ast_channel::writeformat.
Referenced by gtalk_read().
01556 { 01557 struct ast_frame *f; 01558 01559 if (!p->rtp) { 01560 return &ast_null_frame; 01561 } 01562 f = ast_rtp_instance_read(p->rtp, 0); 01563 gtalk_update_stun(p->parent, p); 01564 if (p->owner) { 01565 /* We already hold the channel lock */ 01566 if (f->frametype == AST_FRAME_VOICE) { 01567 if (f->subclass.codec != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) { 01568 ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec)); 01569 p->owner->nativeformats = 01570 (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass.codec; 01571 ast_set_read_format(p->owner, p->owner->readformat); 01572 ast_set_write_format(p->owner, p->owner->writeformat); 01573 } 01574 /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { 01575 f = ast_dsp_process(p->owner, p->vad, f); 01576 if (option_debug && f && (f->frametype == AST_FRAME_DTMF)) 01577 ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass); 01578 } */ 01579 } 01580 } 01581 return f; 01582 }
static int gtalk_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 1786 of file chan_gtalk.c.
References ast_log(), and LOG_NOTICE.
01787 { 01788 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n"); 01789 01790 return -1; 01791 }
static int gtalk_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 1676 of file chan_gtalk.c.
References ast_aji_send_chat(), ast_log(), gtalk::connection, LOG_ERROR, gtalk_pvt::parent, ast_channel::tech_pvt, and gtalk_pvt::them.
01677 { 01678 int res = 0; 01679 struct aji_client *client = NULL; 01680 struct gtalk_pvt *p = chan->tech_pvt; 01681 01682 if (!p->parent) { 01683 ast_log(LOG_ERROR, "Parent channel not found\n"); 01684 return -1; 01685 } 01686 if (!p->parent->connection) { 01687 ast_log(LOG_ERROR, "XMPP client not found\n"); 01688 return -1; 01689 } 01690 client = p->parent->connection; 01691 res = ast_aji_send_chat(client, p->them, text); 01692 return res; 01693 }
static int gtalk_set_rtp_peer | ( | struct ast_channel * | chan, | |
struct ast_rtp_instance * | rtp, | |||
struct ast_rtp_instance * | vrtp, | |||
struct ast_rtp_instance * | trtp, | |||
format_t | codecs, | |||
int | nat_active | |||
) | [static] |
Definition at line 545 of file chan_gtalk.c.
References ast_mutex_lock, ast_mutex_unlock, gtalk_pvt::lock, and ast_channel::tech_pvt.
00546 { 00547 struct gtalk_pvt *p; 00548 00549 p = chan->tech_pvt; 00550 if (!p) 00551 return -1; 00552 ast_mutex_lock(&p->lock); 00553 00554 /* if (rtp) 00555 ast_rtp_get_peer(rtp, &p->redirip); 00556 else 00557 memset(&p->redirip, 0, sizeof(p->redirip)); 00558 p->redircodecs = codecs; */ 00559 00560 /* Reset lastrtprx timer */ 00561 ast_mutex_unlock(&p->lock); 00562 return 0; 00563 }
static char * gtalk_show_channels | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command "gtalk show channels".
Definition at line 1887 of file chan_gtalk.c.
References AJI_MAX_JIDLEN, ast_cli_args::argc, ast_cli(), ast_copy_string(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, gtalk_list, gtalklock, LOG_WARNING, ast_channel::name, gtalk_pvt::next, gtalk_pvt::owner, ast_channel::readformat, gtalk_pvt::them, ast_cli_entry::usage, and ast_channel::writeformat.
01888 { 01889 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n" 01890 struct gtalk_pvt *p; 01891 struct ast_channel *chan; 01892 int numchans = 0; 01893 char them[AJI_MAX_JIDLEN]; 01894 char *jid = NULL; 01895 char *resource = NULL; 01896 01897 switch (cmd) { 01898 case CLI_INIT: 01899 e->command = "gtalk show channels"; 01900 e->usage = 01901 "Usage: gtalk show channels\n" 01902 " Shows current state of the Gtalk channels.\n"; 01903 return NULL; 01904 case CLI_GENERATE: 01905 return NULL; 01906 } 01907 01908 if (a->argc != 3) 01909 return CLI_SHOWUSAGE; 01910 01911 ast_mutex_lock(>alklock); 01912 ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write"); 01913 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { 01914 ASTOBJ_WRLOCK(iterator); 01915 p = iterator->p; 01916 while(p) { 01917 chan = p->owner; 01918 ast_copy_string(them, p->them, sizeof(them)); 01919 jid = them; 01920 resource = strchr(them, '/'); 01921 if (!resource) 01922 resource = "None"; 01923 else { 01924 *resource = '\0'; 01925 resource ++; 01926 } 01927 if (chan) 01928 ast_cli(a->fd, FORMAT, 01929 chan->name, 01930 jid, 01931 resource, 01932 ast_getformatname(chan->readformat), 01933 ast_getformatname(chan->writeformat) 01934 ); 01935 else 01936 ast_log(LOG_WARNING, "No available channel\n"); 01937 numchans ++; 01938 p = p->next; 01939 } 01940 ASTOBJ_UNLOCK(iterator); 01941 }); 01942 01943 ast_mutex_unlock(>alklock); 01944 01945 ast_cli(a->fd, "%d active gtalk channel%s\n", numchans, (numchans != 1) ? "s" : ""); 01946 return CLI_SUCCESS; 01947 #undef FORMAT 01948 }
static int gtalk_update_externip | ( | void | ) | [static] |
Definition at line 1374 of file chan_gtalk.c.
References ast_connect(), ast_inet_ntoa(), ast_log(), ast_sockaddr_from_sin, ast_sockaddr_stringify(), ast_strdupa, ast_stun_request(), errno, externip, LOG_WARNING, and stunaddr.
Referenced by gtalk_create_candidates().
01375 { 01376 int sock; 01377 char *newaddr; 01378 struct sockaddr_in answer = { 0, }; 01379 struct sockaddr_in *dst; 01380 struct ast_sockaddr tmp_dst; 01381 01382 if (!stunaddr.sin_addr.s_addr) { 01383 return -1; 01384 } 01385 dst = &stunaddr; 01386 01387 sock = socket(AF_INET, SOCK_DGRAM, 0); 01388 if (sock < 0) { 01389 ast_log(LOG_WARNING, "Unable to create STUN socket: %s\n", strerror(errno)); 01390 return -1; 01391 } 01392 01393 ast_sockaddr_from_sin(&tmp_dst, dst); 01394 if (ast_connect(sock, &tmp_dst) != 0) { 01395 ast_log(LOG_WARNING, "STUN Failed to connect to %s\n", ast_sockaddr_stringify(&tmp_dst)); 01396 close(sock); 01397 return -1; 01398 } 01399 01400 if ((ast_stun_request(sock, &stunaddr, NULL, &answer))) { 01401 close(sock); 01402 return -1; 01403 } 01404 01405 newaddr = ast_strdupa(ast_inet_ntoa(answer.sin_addr)); 01406 memcpy(externip, newaddr, sizeof(externip)); 01407 01408 close(sock); 01409 return 0; 01410 01411 }
Definition at line 1413 of file chan_gtalk.c.
References ahp, ast_debug, ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_instance_get_remote_address(), ast_rtp_instance_stun_request(), ast_sockaddr_from_sin, ast_sockaddr_to_sin, hp, gtalk_candidate::ip, gtalk_pvt::laststun, LOG_WARNING, gtalk_candidate::next, gtalk_pvt::ourcandidates, gtalk_candidate::port, gtalk_pvt::rtp, gtalk_pvt::theircandidates, and gtalk_candidate::username.
Referenced by gtalk_add_candidate(), gtalk_is_accepted(), gtalk_is_answered(), and gtalk_rtp_read().
01414 { 01415 struct gtalk_candidate *tmp; 01416 struct hostent *hp; 01417 struct ast_hostent ahp; 01418 struct sockaddr_in sin = { 0, }; 01419 struct sockaddr_in aux = { 0, }; 01420 struct ast_sockaddr sin_tmp; 01421 struct ast_sockaddr aux_tmp; 01422 01423 if (time(NULL) == p->laststun) 01424 return 0; 01425 01426 tmp = p->theircandidates; 01427 p->laststun = time(NULL); 01428 while (tmp) { 01429 char username[256]; 01430 01431 /* Find the IP address of the host */ 01432 if (!(hp = ast_gethostbyname(tmp->ip, &ahp))) { 01433 ast_log(LOG_WARNING, "Could not get host by name for %s\n", tmp->ip); 01434 tmp = tmp->next; 01435 continue; 01436 } 01437 sin.sin_family = AF_INET; 01438 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); 01439 sin.sin_port = htons(tmp->port); 01440 snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username); 01441 01442 /* Find out the result of the STUN */ 01443 ast_rtp_instance_get_remote_address(p->rtp, &aux_tmp); 01444 ast_sockaddr_to_sin(&aux_tmp, &aux); 01445 01446 /* If the STUN result is different from the IP of the hostname, 01447 * lock on the stun IP of the hostname advertised by the 01448 * remote client */ 01449 if (aux.sin_addr.s_addr && (aux.sin_addr.s_addr != sin.sin_addr.s_addr)) { 01450 ast_rtp_instance_stun_request(p->rtp, &aux_tmp, username); 01451 } else { 01452 ast_sockaddr_from_sin(&sin_tmp, &sin); 01453 ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username); 01454 } 01455 if (aux.sin_addr.s_addr) { 01456 ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip); 01457 ast_debug(4, "Sending STUN request to %s\n", tmp->ip); 01458 } 01459 01460 tmp = tmp->next; 01461 } 01462 return 1; 01463 }
static int gtalk_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Send frame to media channel (rtp).
Definition at line 1596 of file chan_gtalk.c.
References AST_FRAME_IMAGE, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_frame_subclass::codec, ast_frame::frametype, gtalk_pvt::lock, LOG_WARNING, ast_channel::nativeformats, ast_channel::readformat, gtalk_pvt::rtp, ast_frame::subclass, ast_channel::tech_pvt, gtalk_pvt::vrtp, and ast_channel::writeformat.
01597 { 01598 struct gtalk_pvt *p = ast->tech_pvt; 01599 int res = 0; 01600 char buf[256]; 01601 01602 switch (frame->frametype) { 01603 case AST_FRAME_VOICE: 01604 if (!(frame->subclass.codec & ast->nativeformats)) { 01605 ast_log(LOG_WARNING, 01606 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n", 01607 ast_getformatname(frame->subclass.codec), 01608 ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats), 01609 ast_getformatname(ast->readformat), 01610 ast_getformatname(ast->writeformat)); 01611 return 0; 01612 } 01613 if (p) { 01614 ast_mutex_lock(&p->lock); 01615 if (p->rtp) { 01616 res = ast_rtp_instance_write(p->rtp, frame); 01617 } 01618 ast_mutex_unlock(&p->lock); 01619 } 01620 break; 01621 case AST_FRAME_VIDEO: 01622 if (p) { 01623 ast_mutex_lock(&p->lock); 01624 if (p->vrtp) { 01625 res = ast_rtp_instance_write(p->vrtp, frame); 01626 } 01627 ast_mutex_unlock(&p->lock); 01628 } 01629 break; 01630 case AST_FRAME_IMAGE: 01631 return 0; 01632 break; 01633 default: 01634 ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n", 01635 frame->frametype); 01636 return 0; 01637 } 01638 01639 return res; 01640 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 2180 of file chan_gtalk.c.
References __ourip, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_module_helper(), AST_MODULE_LOAD_DECLINE, ast_rtp_glue_register, ast_sockaddr_from_sin, ast_sockaddr_ipv4(), ASTOBJ_CONTAINER_INIT, bindaddr, free, GOOGLE_CONFIG, gtalk_cli, gtalk_get_local_ip(), gtalk_list, gtalk_load_config(), gtalk_rtp_glue, gtalk_tech, io, io_context_create(), LOG_ERROR, LOG_WARNING, sched_context_create(), and ast_channel_tech::type.
02181 { 02182 struct ast_sockaddr bindaddr_tmp; 02183 struct ast_sockaddr ourip_tmp; 02184 02185 char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0); 02186 free(jabber_loaded); 02187 if (!jabber_loaded) { 02188 /* If embedded, check for a different module name */ 02189 jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0); 02190 free(jabber_loaded); 02191 if (!jabber_loaded) { 02192 ast_log(LOG_ERROR, "chan_gtalk.so depends upon res_jabber.so\n"); 02193 return AST_MODULE_LOAD_DECLINE; 02194 } 02195 } 02196 02197 ASTOBJ_CONTAINER_INIT(>alk_list); 02198 if (!gtalk_load_config()) { 02199 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG); 02200 return 0; 02201 } 02202 02203 sched = sched_context_create(); 02204 if (!sched) { 02205 ast_log(LOG_WARNING, "Unable to create schedule context\n"); 02206 } 02207 02208 io = io_context_create(); 02209 if (!io) { 02210 ast_log(LOG_WARNING, "Unable to create I/O context\n"); 02211 } 02212 02213 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr); 02214 if (gtalk_get_local_ip(&ourip_tmp)) { 02215 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n"); 02216 return 0; 02217 } 02218 __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp)); 02219 02220 ast_rtp_glue_register(>alk_rtp_glue); 02221 ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli)); 02222 02223 /* Make sure we can register our channel type */ 02224 if (ast_channel_register(>alk_tech)) { 02225 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type); 02226 return -1; 02227 } 02228 return 0; 02229 }
static int unload_module | ( | void | ) | [static] |
Reload module Unload the gtalk channel from Asterisk.
Definition at line 2240 of file chan_gtalk.c.
References ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_glue_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, gtalk_cli, gtalk_list, gtalk_member_destroy(), gtalk_rtp_glue, gtalk_tech, gtalklock, LOG_WARNING, gtalk_pvt::next, and gtalk_pvt::owner.
02241 { 02242 struct gtalk_pvt *privates = NULL; 02243 ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli)); 02244 /* First, take us out of the channel loop */ 02245 ast_channel_unregister(>alk_tech); 02246 ast_rtp_glue_unregister(>alk_rtp_glue); 02247 02248 if (!ast_mutex_lock(>alklock)) { 02249 /* Hangup all interfaces if they have an owner */ 02250 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, { 02251 ASTOBJ_WRLOCK(iterator); 02252 privates = iterator->p; 02253 while(privates) { 02254 if (privates->owner) 02255 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD); 02256 privates = privates->next; 02257 } 02258 iterator->p = NULL; 02259 ASTOBJ_UNLOCK(iterator); 02260 }); 02261 ast_mutex_unlock(>alklock); 02262 } else { 02263 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 02264 return -1; 02265 } 02266 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy); 02267 ASTOBJ_CONTAINER_DESTROY(>alk_list); 02268 return 0; 02269 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Gtalk Channel Driver" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, } [static] |
Definition at line 2276 of file chan_gtalk.c.
struct in_addr __ourip [static] |
Definition at line 228 of file chan_gtalk.c.
Referenced by find_subchannel_and_lock(), jingle_create_candidates(), and load_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2276 of file chan_gtalk.c.
struct sockaddr_in bindaddr = { 0, } [static] |
The address we bind to
Definition at line 224 of file chan_gtalk.c.
Referenced by __sip_subscribe_mwi_do(), ast_find_ourip(), ast_sip_ouraddrfor(), build_peer(), create_addr(), create_addr_from_peer(), dialog_initialize_rtp(), gtalk_alloc(), gtalk_get_local_ip(), handle_request_invite(), jingle_alloc(), jingle_create_candidates(), jingle_load_config(), load_module(), proxy_update(), realtime_peer(), reload_config(), sip_alloc(), sip_show_settings(), sipsock_read(), start_rtp(), and transmit_register().
struct ast_jb_conf default_jbconf [static] |
Global jitterbuffer configuration - by default, jb is disabled
Definition at line 82 of file chan_gtalk.c.
const char desc[] = "Gtalk Channel" [static] |
Definition at line 168 of file chan_gtalk.c.
char externip[16] [static] |
Definition at line 235 of file chan_gtalk.c.
Referenced by gtalk_create_candidates(), gtalk_update_externip(), jingle_create_candidates(), and jingle_load_config().
format_t global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263 [static] |
Definition at line 170 of file chan_gtalk.c.
Referenced by gtalk_alloc(), gtalk_load_config(), gtalk_new(), jingle_load_config(), and jingle_new().
struct ast_jb_conf global_jbconf [static] |
Definition at line 90 of file chan_gtalk.c.
struct ast_cli_entry gtalk_cli[] [static] |
Initial value:
{ { .handler = gtalk_show_channels , .summary = "Show GoogleTalk channels" ,__VA_ARGS__ }, }
Definition at line 230 of file chan_gtalk.c.
Referenced by load_module(), and unload_module().
struct gtalk_container gtalk_list [static] |
Definition at line 238 of file chan_gtalk.c.
Referenced by find_gtalk(), gtalk_show_channels(), load_module(), and unload_module().
struct ast_rtp_glue gtalk_rtp_glue [static] |
struct ast_channel_tech gtalk_tech [static] |
PBX interface structure for channel registration.
Definition at line 200 of file chan_gtalk.c.
Referenced by gtalk_new(), load_module(), and unload_module().
ast_mutex_t gtalklock = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } [static] |
Protect the interface list (of gtalk_pvt's)
Definition at line 172 of file chan_gtalk.c.
Referenced by gtalk_alloc(), gtalk_show_channels(), and unload_module().
struct io_context* io [static] |
The IO context
Definition at line 227 of file chan_gtalk.c.
Referenced by ast_expr(), ast_str_expr(), create_addr_from_peer(), do_monitor(), handle_request_invite(), load_module(), network_thread(), peer_set_srcaddr(), reload(), set_config(), sip_alloc(), and unload_module().
struct sched_context* sched [static] |
The scheduling context
Definition at line 226 of file chan_gtalk.c.
Referenced by __attempt_transmit(), __find_callno(), __iax2_poke_noanswer(), __oh323_destroy(), __oh323_rtp_create(), __oh323_update_info(), __send_lagrq(), __send_ping(), __unload_module(), ack_trans(), ast_rtp_instance_new(), auth_fail(), build_peer(), create_esc_entry(), delete_users(), destroy_event(), destroy_packet(), destroy_packets(), destroy_peer(), dnsmgr_init(), dnsmgr_start_refresh(), do_monitor(), do_refresh(), do_register(), do_reload(), dundi_discover(), dundi_query(), dundi_send(), esc_entry_destructor(), handle_command_response(), handle_dump_sched(), iax2_ack_registry(), iax2_call(), iax2_destroy_helper(), iax2_do_register(), iax2_dprequest(), iax2_frame_free(), iax2_hangup(), iax2_key_rotate(), iax2_poke_peer(), iax2_provision(), load_module(), make_trunk(), network_change_event_cb(), network_thread(), populate_addr(), precache_trans(), qualify_peer(), reg_source_db(), sched_delay_remove(), schedule_calendar_event(), schedule_delivery(), sip_cc_agent_start_offer_timer(), sip_cc_agent_stop_offer_timer(), sip_cc_monitor_cancel_available_timer(), sip_cc_monitor_request_cc(), socket_process(), start_rtp(), stun_start_monitor(), stun_stop_monitor(), transmit_frame(), unlink_peer(), unload_module(), update_jbsched(), and update_registry().
struct sockaddr_in stunaddr [static] |
the stun server we get the externip from
Definition at line 236 of file chan_gtalk.c.
Referenced by gtalk_load_config(), and gtalk_update_externip().