00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 72331 $")
00037
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <sys/socket.h>
00043 #include <errno.h>
00044 #include <stdlib.h>
00045 #include <fcntl.h>
00046 #include <netdb.h>
00047 #include <netinet/in.h>
00048 #include <arpa/inet.h>
00049 #include <sys/signal.h>
00050 #include <iksemel.h>
00051 #include <pthread.h>
00052
00053 #ifdef HAVE_GNUTLS
00054 #include <gcrypt.h>
00055 GCRY_THREAD_OPTION_PTHREAD_IMPL;
00056 #endif
00057
00058 #include "asterisk/lock.h"
00059 #include "asterisk/channel.h"
00060 #include "asterisk/config.h"
00061 #include "asterisk/logger.h"
00062 #include "asterisk/module.h"
00063 #include "asterisk/pbx.h"
00064 #include "asterisk/options.h"
00065 #include "asterisk/lock.h"
00066 #include "asterisk/sched.h"
00067 #include "asterisk/io.h"
00068 #include "asterisk/rtp.h"
00069 #include "asterisk/acl.h"
00070 #include "asterisk/callerid.h"
00071 #include "asterisk/file.h"
00072 #include "asterisk/cli.h"
00073 #include "asterisk/app.h"
00074 #include "asterisk/musiconhold.h"
00075 #include "asterisk/manager.h"
00076 #include "asterisk/stringfields.h"
00077 #include "asterisk/utils.h"
00078 #include "asterisk/causes.h"
00079 #include "asterisk/astobj.h"
00080 #include "asterisk/abstract_jb.h"
00081 #include "asterisk/jabber.h"
00082
00083 #define GOOGLE_CONFIG "gtalk.conf"
00084
00085 #define GOOGLE_NS "http://www.google.com/session"
00086
00087
00088
00089 static struct ast_jb_conf default_jbconf =
00090 {
00091 .flags = 0,
00092 .max_size = -1,
00093 .resync_threshold = -1,
00094 .impl = ""
00095 };
00096 static struct ast_jb_conf global_jbconf;
00097
00098 enum gtalk_protocol {
00099 AJI_PROTOCOL_UDP = 1,
00100 AJI_PROTOCOL_SSLTCP = 2,
00101 };
00102
00103 enum gtalk_connect_type {
00104 AJI_CONNECT_STUN = 1,
00105 AJI_CONNECT_LOCAL = 2,
00106 AJI_CONNECT_RELAY = 3,
00107 };
00108
00109 struct gtalk_pvt {
00110 ast_mutex_t lock;
00111 time_t laststun;
00112 struct gtalk *parent;
00113 char sid[100];
00114 char us[100];
00115 char them[100];
00116 char ring[10];
00117 iksrule *ringrule;
00118 int initiator;
00119 int alreadygone;
00120 int capability;
00121 struct ast_codec_pref prefs;
00122 struct gtalk_candidate *theircandidates;
00123 struct gtalk_candidate *ourcandidates;
00124 char cid_num[80];
00125 char cid_name[80];
00126 char exten[80];
00127 struct ast_channel *owner;
00128 struct ast_rtp *rtp;
00129 struct ast_rtp *vrtp;
00130 int jointcapability;
00131 int peercapability;
00132 struct gtalk_pvt *next;
00133 };
00134
00135 struct gtalk_candidate {
00136 char name[100];
00137 enum gtalk_protocol protocol;
00138 double preference;
00139 char username[100];
00140 char password[100];
00141 enum gtalk_connect_type type;
00142 char network[6];
00143 int generation;
00144 char ip[16];
00145 int port;
00146 int receipt;
00147 struct gtalk_candidate *next;
00148 };
00149
00150 struct gtalk {
00151 ASTOBJ_COMPONENTS(struct gtalk);
00152 struct aji_client *connection;
00153 struct aji_buddy *buddy;
00154 struct gtalk_pvt *p;
00155 struct ast_codec_pref prefs;
00156 int amaflags;
00157 char user[100];
00158 char context[100];
00159 char accountcode[AST_MAX_ACCOUNT_CODE];
00160 int capability;
00161 ast_group_t callgroup;
00162 ast_group_t pickupgroup;
00163 int callingpres;
00164 int allowguest;
00165 char language[MAX_LANGUAGE];
00166 char musicclass[MAX_MUSICCLASS];
00167 };
00168
00169 struct gtalk_container {
00170 ASTOBJ_CONTAINER_COMPONENTS(struct gtalk);
00171 };
00172
00173 static const char desc[] = "Gtalk Channel";
00174
00175 static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
00176
00177 AST_MUTEX_DEFINE_STATIC(gtalklock);
00178
00179
00180 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause);
00181 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration);
00182 static int gtalk_digit_begin(struct ast_channel *ast, char digit);
00183 static int gtalk_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00184 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout);
00185 static int gtalk_hangup(struct ast_channel *ast);
00186 static int gtalk_answer(struct ast_channel *ast);
00187 static int gtalk_newcall(struct gtalk *client, ikspak *pak);
00188 static struct ast_frame *gtalk_read(struct ast_channel *ast);
00189 static int gtalk_write(struct ast_channel *ast, struct ast_frame *f);
00190 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00191 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00192 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00193 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
00194 static int gtalk_do_reload(int fd, int argc, char **argv);
00195 static int gtalk_show_channels(int fd, int argc, char **argv);
00196
00197 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
00198 struct ast_rtp *vrtp, int codecs, int nat_active);
00199 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
00200 static int gtalk_get_codec(struct ast_channel *chan);
00201
00202
00203 static const struct ast_channel_tech gtalk_tech = {
00204 .type = "Gtalk",
00205 .description = "Gtalk Channel Driver",
00206 .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
00207 .requester = gtalk_request,
00208 .send_digit_begin = gtalk_digit_begin,
00209 .send_digit_end = gtalk_digit_end,
00210 .bridge = ast_rtp_bridge,
00211 .call = gtalk_call,
00212 .hangup = gtalk_hangup,
00213 .answer = gtalk_answer,
00214 .read = gtalk_read,
00215 .write = gtalk_write,
00216 .exception = gtalk_read,
00217 .indicate = gtalk_indicate,
00218 .fixup = gtalk_fixup,
00219 .send_html = gtalk_sendhtml,
00220 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00221 };
00222
00223 static struct sockaddr_in bindaddr = { 0, };
00224
00225 static struct sched_context *sched;
00226 static struct io_context *io;
00227 static struct in_addr __ourip;
00228
00229
00230
00231 static struct ast_rtp_protocol gtalk_rtp = {
00232 type: "Gtalk",
00233 get_rtp_info: gtalk_get_rtp_peer,
00234 set_rtp_peer: gtalk_set_rtp_peer,
00235 get_codec: gtalk_get_codec,
00236 };
00237
00238 static char debug_usage[] =
00239 "Usage: gtalk show channels\n"
00240 " Shows current state of the Gtalk channels.\n";
00241
00242 static char reload_usage[] =
00243 "Usage: gtalk reload\n"
00244 " Reload gtalk channel driver.\n";
00245
00246
00247 static struct ast_cli_entry gtalk_cli[] = {
00248 {{ "gtalk", "reload", NULL}, gtalk_do_reload, "Enable Jabber debugging", reload_usage },
00249 {{ "gtalk", "show", "channels", NULL}, gtalk_show_channels, "Show GoogleTalk Channels", debug_usage },
00250 };
00251
00252
00253
00254 static char externip[16];
00255
00256 static struct gtalk_container gtalk_list;
00257
00258 static void gtalk_member_destroy(struct gtalk *obj)
00259 {
00260 free(obj);
00261 }
00262
00263 static struct gtalk *find_gtalk(char *name, char *connection)
00264 {
00265 struct gtalk *gtalk = NULL;
00266 char *domain = NULL , *s = NULL;
00267
00268 if(strchr(connection, '@')) {
00269 s = ast_strdupa(connection);
00270 domain = strsep(&s, "@");
00271 ast_verbose("OOOOH domain = %s\n", domain);
00272 }
00273 gtalk = ASTOBJ_CONTAINER_FIND(>alk_list, name);
00274 if (!gtalk && strchr(name, '@'))
00275 gtalk = ASTOBJ_CONTAINER_FIND_FULL(>alk_list, name, user,,, strcasecmp);
00276
00277 if (!gtalk) {
00278 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
00279 ASTOBJ_RDLOCK(iterator);
00280 if (!strcasecmp(iterator->name, "guest")) {
00281 if (!strcasecmp(iterator->connection->jid->partial, connection)) {
00282 gtalk = iterator;
00283 } else if (!strcasecmp(iterator->connection->name, connection)) {
00284 gtalk = iterator;
00285 } else if (iterator->connection->component && !strcasecmp(iterator->connection->user,domain)) {
00286 gtalk = iterator;
00287 }
00288 }
00289 ASTOBJ_UNLOCK(iterator);
00290
00291 if (gtalk)
00292 break;
00293 });
00294
00295 }
00296 return gtalk;
00297 }
00298
00299
00300 static int add_codec_to_answer(const struct gtalk_pvt *p, int codec, iks *dcodecs)
00301 {
00302 char *format = ast_getformatname(codec);
00303
00304 if (!strcasecmp("ulaw", format)) {
00305 iks *payload_eg711u, *payload_pcmu;
00306 payload_pcmu = iks_new("payload-type");
00307 payload_eg711u = iks_new("payload-type");
00308
00309 if(!payload_eg711u || !payload_pcmu) {
00310 if(payload_pcmu)
00311 iks_delete(payload_pcmu);
00312 if(payload_eg711u)
00313 iks_delete(payload_eg711u);
00314 ast_log(LOG_WARNING,"Failed to allocate iks node");
00315 return -1;
00316 }
00317 iks_insert_attrib(payload_pcmu, "id", "0");
00318 iks_insert_attrib(payload_pcmu, "name", "PCMU");
00319 iks_insert_attrib(payload_pcmu, "clockrate","8000");
00320 iks_insert_attrib(payload_pcmu, "bitrate","64000");
00321 iks_insert_attrib(payload_eg711u, "id", "100");
00322 iks_insert_attrib(payload_eg711u, "name", "EG711U");
00323 iks_insert_attrib(payload_eg711u, "clockrate","8000");
00324 iks_insert_attrib(payload_eg711u, "bitrate","64000");
00325 iks_insert_node(dcodecs, payload_pcmu);
00326 iks_insert_node(dcodecs, payload_eg711u);
00327 }
00328 if (!strcasecmp("alaw", format)) {
00329 iks *payload_eg711a, *payload_pcma;
00330 payload_pcma = iks_new("payload-type");
00331 payload_eg711a = iks_new("payload-type");
00332 if(!payload_eg711a || !payload_pcma) {
00333 if(payload_eg711a)
00334 iks_delete(payload_eg711a);
00335 if(payload_pcma)
00336 iks_delete(payload_pcma);
00337 ast_log(LOG_WARNING,"Failed to allocate iks node");
00338 return -1;
00339 }
00340 iks_insert_attrib(payload_pcma, "id", "8");
00341 iks_insert_attrib(payload_pcma, "name", "PCMA");
00342 iks_insert_attrib(payload_pcma, "clockrate","8000");
00343 iks_insert_attrib(payload_pcma, "bitrate","64000");
00344 payload_eg711a = iks_new("payload-type");
00345 iks_insert_attrib(payload_eg711a, "id", "101");
00346 iks_insert_attrib(payload_eg711a, "name", "EG711A");
00347 iks_insert_attrib(payload_eg711a, "clockrate","8000");
00348 iks_insert_attrib(payload_eg711a, "bitrate","64000");
00349 iks_insert_node(dcodecs, payload_pcma);
00350 iks_insert_node(dcodecs, payload_eg711a);
00351 }
00352 if (!strcasecmp("ilbc", format)) {
00353 iks *payload_ilbc = iks_new("payload-type");
00354 if(!payload_ilbc) {
00355 ast_log(LOG_WARNING,"Failed to allocate iks node");
00356 return -1;
00357 }
00358 iks_insert_attrib(payload_ilbc, "id", "97");
00359 iks_insert_attrib(payload_ilbc, "name", "iLBC");
00360 iks_insert_attrib(payload_ilbc, "clockrate","8000");
00361 iks_insert_attrib(payload_ilbc, "bitrate","13300");
00362 iks_insert_node(dcodecs, payload_ilbc);
00363 }
00364 if (!strcasecmp("g723", format)) {
00365 iks *payload_g723 = iks_new("payload-type");
00366 if(!payload_g723) {
00367 ast_log(LOG_WARNING,"Failed to allocate iks node");
00368 return -1;
00369 }
00370 iks_insert_attrib(payload_g723, "id", "4");
00371 iks_insert_attrib(payload_g723, "name", "G723");
00372 iks_insert_attrib(payload_g723, "clockrate","8000");
00373 iks_insert_attrib(payload_g723, "bitrate","6300");
00374 iks_insert_node(dcodecs, payload_g723);
00375 }
00376 if (!strcasecmp("speex", format)) {
00377 iks *payload_speex = iks_new("payload-type");
00378 if(!payload_speex) {
00379 ast_log(LOG_WARNING,"Failed to allocate iks node");
00380 return -1;
00381 }
00382 iks_insert_attrib(payload_speex, "id", "110");
00383 iks_insert_attrib(payload_speex, "name", "speex");
00384 iks_insert_attrib(payload_speex, "clockrate","8000");
00385 iks_insert_attrib(payload_speex, "bitrate","11000");
00386 iks_insert_node(dcodecs, payload_speex);
00387 }
00388 ast_rtp_lookup_code(p->rtp, 1, codec);
00389 return 0;
00390 }
00391
00392 static int gtalk_invite(struct gtalk_pvt *p, char *to, char *from, char *sid, int initiator)
00393 {
00394 struct gtalk *client = p->parent;
00395 iks *iq, *gtalk, *dcodecs, *payload_telephone, *transport;
00396 int x;
00397 int pref_codec = 0;
00398 int alreadysent = 0;
00399
00400
00401 iq = iks_new("iq");
00402 gtalk = iks_new("session");
00403 dcodecs = iks_new("description");
00404 transport = iks_new("transport");
00405 payload_telephone = iks_new("payload-type");
00406 if (!(iq && gtalk && dcodecs && transport && payload_telephone)){
00407 if(iq)
00408 iks_delete(iq);
00409 if(gtalk)
00410 iks_delete(gtalk);
00411 if(dcodecs)
00412 iks_delete(dcodecs);
00413 if(transport)
00414 iks_delete(transport);
00415 if(payload_telephone)
00416 iks_delete(payload_telephone);
00417
00418 ast_log(LOG_ERROR, "Could not allocate iksemel nodes\n");
00419 return 0;
00420 }
00421 iks_insert_attrib(dcodecs, "xmlns", "http://www.google.com/session/phone");
00422 iks_insert_attrib(dcodecs, "xml:lang", "en");
00423
00424 for (x = 0; x < 32; x++) {
00425 if (!(pref_codec = ast_codec_pref_index(&client->prefs, x)))
00426 break;
00427 if (!(client->capability & pref_codec))
00428 continue;
00429 if (alreadysent & pref_codec)
00430 continue;
00431 add_codec_to_answer(p, pref_codec, dcodecs);
00432 alreadysent |= pref_codec;
00433 }
00434
00435 iks_insert_attrib(payload_telephone, "id", "106");
00436 iks_insert_attrib(payload_telephone, "name", "telephone-event");
00437 iks_insert_attrib(payload_telephone, "clockrate", "8000");
00438
00439 iks_insert_attrib(transport,"xmlns","http://www.google.com/transport/p2p");
00440
00441 iks_insert_attrib(iq, "type", "set");
00442 iks_insert_attrib(iq, "to", to);
00443 iks_insert_attrib(iq, "from", from);
00444 iks_insert_attrib(iq, "id", client->connection->mid);
00445 ast_aji_increment_mid(client->connection->mid);
00446
00447 iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session");
00448 iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept");
00449 iks_insert_attrib(gtalk, "initiator", initiator ? from : to);
00450 iks_insert_attrib(gtalk, "id", sid);
00451 iks_insert_node(iq, gtalk);
00452 iks_insert_node(gtalk, dcodecs);
00453 iks_insert_node(gtalk, transport);
00454 iks_insert_node(dcodecs, payload_telephone);
00455
00456 iks_send(client->connection->p, iq);
00457 iks_delete(payload_telephone);
00458 iks_delete(transport);
00459 iks_delete(dcodecs);
00460 iks_delete(gtalk);
00461 iks_delete(iq);
00462 return 1;
00463 }
00464
00465 static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator)
00466 {
00467 iks *iq, *session, *transport;
00468 iq = iks_new("iq");
00469 session = iks_new("session");
00470 transport = iks_new("transport");
00471 if(!(iq && session && transport)) {
00472 if(iq)
00473 iks_delete(iq);
00474 if(session)
00475 iks_delete(session);
00476 if(transport)
00477 iks_delete(transport);
00478 ast_log(LOG_ERROR, " Unable to allocate IKS node\n");
00479 return -1;
00480 }
00481 iks_insert_attrib(iq, "from", from);
00482 iks_insert_attrib(iq, "to", to);
00483 iks_insert_attrib(iq, "type", "set");
00484 iks_insert_attrib(iq, "id",p->parent->connection->mid);
00485 ast_aji_increment_mid(p->parent->connection->mid);
00486 iks_insert_attrib(session, "type", "transport-accept");
00487 iks_insert_attrib(session, "id", sid);
00488 iks_insert_attrib(session, "initiator", initiator ? from : to);
00489 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
00490 iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p");
00491 iks_insert_node(iq,session);
00492 iks_insert_node(session,transport);
00493 iks_send(p->parent->connection->p, iq);
00494 iks_delete(transport);
00495 iks_delete(session);
00496 iks_delete(iq);
00497 return 1;
00498
00499 }
00500
00501 static int gtalk_ringing_ack(void *data, ikspak *pak)
00502 {
00503 struct gtalk_pvt *p = data;
00504
00505 if (p->ringrule)
00506 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
00507 p->ringrule = NULL;
00508 if (p->owner)
00509 ast_queue_control(p->owner, AST_CONTROL_RINGING);
00510 return IKS_FILTER_EAT;
00511 }
00512
00513 static int gtalk_answer(struct ast_channel *ast)
00514 {
00515 struct gtalk_pvt *p = ast->tech_pvt;
00516 int res = 0;
00517
00518 if (option_debug)
00519 ast_log(LOG_DEBUG, "Answer!\n");
00520 ast_mutex_lock(&p->lock);
00521 gtalk_invite(p, p->them, p->us,p->sid, 0);
00522 ast_mutex_unlock(&p->lock);
00523 return res;
00524 }
00525
00526 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
00527 {
00528 struct gtalk_pvt *p = chan->tech_pvt;
00529 enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
00530
00531 if (!p)
00532 return res;
00533
00534 ast_mutex_lock(&p->lock);
00535 if (p->rtp){
00536 *rtp = p->rtp;
00537 res = AST_RTP_TRY_PARTIAL;
00538 }
00539 ast_mutex_unlock(&p->lock);
00540
00541 return res;
00542 }
00543
00544 static int gtalk_get_codec(struct ast_channel *chan)
00545 {
00546 struct gtalk_pvt *p = chan->tech_pvt;
00547 return p->peercapability;
00548 }
00549
00550 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
00551 {
00552 struct gtalk_pvt *p;
00553
00554 p = chan->tech_pvt;
00555 if (!p)
00556 return -1;
00557 ast_mutex_lock(&p->lock);
00558
00559
00560
00561
00562
00563
00564
00565
00566 ast_mutex_unlock(&p->lock);
00567 return 0;
00568 }
00569
00570 static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
00571 {
00572 iks *response = NULL, *error = NULL, *reason = NULL;
00573 int res = -1;
00574
00575 response = iks_new("iq");
00576 if (response) {
00577 iks_insert_attrib(response, "type", "result");
00578 iks_insert_attrib(response, "from", from);
00579 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00580 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00581 if (reasonstr) {
00582 error = iks_new("error");
00583 if (error) {
00584 iks_insert_attrib(error, "type", "cancel");
00585 reason = iks_new(reasonstr);
00586 if (reason)
00587 iks_insert_node(error, reason);
00588 iks_insert_node(response, error);
00589 }
00590 }
00591 iks_send(client->connection->p, response);
00592 if (reason)
00593 iks_delete(reason);
00594 if (error)
00595 iks_delete(error);
00596 iks_delete(response);
00597 res = 0;
00598 }
00599 return res;
00600 }
00601
00602 static int gtalk_is_answered(struct gtalk *client, ikspak *pak)
00603 {
00604 struct gtalk_pvt *tmp;
00605 char *from;
00606 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00607
00608 for (tmp = client->p; tmp; tmp = tmp->next) {
00609 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00610 break;
00611 }
00612
00613 from = iks_find_attrib(pak->x, "to");
00614 if(!from)
00615 from = client->connection->jid->full;
00616
00617 if (tmp) {
00618 if (tmp->owner)
00619 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
00620 } else
00621 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00622 gtalk_response(client, from, pak, NULL, NULL);
00623 return 1;
00624 }
00625
00626 static int gtalk_handle_dtmf(struct gtalk *client, ikspak *pak)
00627 {
00628 struct gtalk_pvt *tmp;
00629 iks *dtmfnode = NULL;
00630 char *dtmf;
00631 char *from;
00632
00633 for (tmp = client->p; tmp; tmp = tmp->next) {
00634 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00635 break;
00636 }
00637 from = iks_find_attrib(pak->x, "to");
00638 if(!from)
00639 from = client->connection->jid->full;
00640
00641
00642 if (tmp) {
00643 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
00644 gtalk_response(client, from, pak,
00645 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
00646 "unsupported-dtmf-method xmlns='http://jabber.org/protocol/gtalk/info/dtmf#errors'");
00647 return -1;
00648 }
00649 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
00650 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
00651 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
00652 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
00653 f.subclass = dtmf[0];
00654 ast_queue_frame(tmp->owner, &f);
00655 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00656 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
00657 struct ast_frame f = {AST_FRAME_DTMF_END, };
00658 f.subclass = dtmf[0];
00659 ast_queue_frame(tmp->owner, &f);
00660 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00661 } else if(iks_find_attrib(pak->x, "dtmf")) {
00662 struct ast_frame f = {AST_FRAME_DTMF, };
00663 f.subclass = dtmf[0];
00664 ast_queue_frame(tmp->owner, &f);
00665 ast_verbose("GOOGLE! DTMF-relay event received: %c\n", f.subclass);
00666 }
00667 }
00668 }
00669 gtalk_response(client, from, pak, NULL, NULL);
00670 return 1;
00671 } else
00672 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00673
00674 gtalk_response(client, from, pak, NULL, NULL);
00675 return 1;
00676 }
00677
00678
00679 static int gtalk_hangup_farend(struct gtalk *client, ikspak *pak)
00680 {
00681 struct gtalk_pvt *tmp;
00682 char *from;
00683
00684 ast_log(LOG_DEBUG, "The client is %s\n", client->name);
00685
00686 for (tmp = client->p; tmp; tmp = tmp->next) {
00687 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid))
00688 break;
00689 }
00690 from = iks_find_attrib(pak->x, "to");
00691 if(!from)
00692 from = client->connection->jid->full;
00693
00694 if (tmp) {
00695 tmp->alreadygone = 1;
00696 if (tmp->owner)
00697 ast_queue_hangup(tmp->owner);
00698 } else
00699 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
00700 gtalk_response(client, from, pak, NULL, NULL);
00701 return 1;
00702 }
00703
00704 static int gtalk_create_candidates(struct gtalk *client, struct gtalk_pvt *p, char *sid, char *from, char *to)
00705 {
00706 struct gtalk_candidate *tmp;
00707 struct aji_client *c = client->connection;
00708 struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
00709 struct sockaddr_in sin;
00710 struct sockaddr_in dest;
00711 struct in_addr us;
00712 iks *iq, *gtalk, *candidate, *transport;
00713 char user[17], pass[17], preference[5], port[7];
00714
00715
00716 iq = iks_new("iq");
00717 gtalk = iks_new("session");
00718 candidate = iks_new("candidate");
00719 transport = iks_new("transport");
00720 if (!iq || !gtalk || !candidate || !transport) {
00721 ast_log(LOG_ERROR, "Memory allocation error\n");
00722 goto safeout;
00723 }
00724 ours1 = ast_calloc(1, sizeof(*ours1));
00725 ours2 = ast_calloc(1, sizeof(*ours2));
00726 if (!ours1 || !ours2)
00727 goto safeout;
00728
00729 iks_insert_attrib(transport, "xmlns","http://www.google.com/transport/p2p");
00730 iks_insert_node(iq, gtalk);
00731 iks_insert_node(gtalk,transport);
00732 iks_insert_node(transport, candidate);
00733
00734 for (; p; p = p->next) {
00735 if (!strcasecmp(p->sid, sid))
00736 break;
00737 }
00738
00739 if (!p) {
00740 ast_log(LOG_NOTICE, "No matching gtalk session - SID %s!\n", sid);
00741 goto safeout;
00742 }
00743
00744 ast_rtp_get_us(p->rtp, &sin);
00745 ast_find_ourip(&us, bindaddr);
00746
00747
00748 ast_copy_string(ours1->name, "rtp", sizeof(ours1->name));
00749 ours1->port = ntohs(sin.sin_port);
00750 ours1->preference = 1;
00751 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00752 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00753 ast_copy_string(ours1->username, user, sizeof(ours1->username));
00754 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
00755 ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
00756 ours1->protocol = AJI_PROTOCOL_UDP;
00757 ours1->type = AJI_CONNECT_LOCAL;
00758 ours1->generation = 0;
00759 p->ourcandidates = ours1;
00760
00761 if (!ast_strlen_zero(externip)) {
00762
00763 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
00764 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
00765 ast_copy_string(ours2->username, user, sizeof(ours2->username));
00766 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
00767 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
00768 ast_copy_string(ours2->name, "rtp", sizeof(ours1->name));
00769 ours2->port = ntohs(sin.sin_port);
00770 ours2->preference = 0.9;
00771 ours2->protocol = AJI_PROTOCOL_UDP;
00772 ours2->type = AJI_CONNECT_STUN;
00773 ours2->generation = 0;
00774 ours1->next = ours2;
00775 ours2 = NULL;
00776 }
00777 ours1 = NULL;
00778 dest.sin_addr = __ourip;
00779 dest.sin_port = sin.sin_port;
00780
00781
00782 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
00783 snprintf(port, sizeof(port), "%d", tmp->port);
00784 snprintf(preference, sizeof(preference), "%.2f", tmp->preference);
00785 iks_insert_attrib(iq, "from", to);
00786 iks_insert_attrib(iq, "to", from);
00787 iks_insert_attrib(iq, "type", "set");
00788 iks_insert_attrib(iq, "id", c->mid);
00789 ast_aji_increment_mid(c->mid);
00790 iks_insert_attrib(gtalk, "type", "transport-info");
00791 iks_insert_attrib(gtalk, "id", sid);
00792 iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from);
00793 iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS);
00794 iks_insert_attrib(candidate, "name", tmp->name);
00795 iks_insert_attrib(candidate, "address", tmp->ip);
00796 iks_insert_attrib(candidate, "port", port);
00797 iks_insert_attrib(candidate, "username", tmp->username);
00798 iks_insert_attrib(candidate, "password", tmp->password);
00799 iks_insert_attrib(candidate, "preference", preference);
00800 if (tmp->protocol == AJI_PROTOCOL_UDP)
00801 iks_insert_attrib(candidate, "protocol", "udp");
00802 if (tmp->protocol == AJI_PROTOCOL_SSLTCP)
00803 iks_insert_attrib(candidate, "protocol", "ssltcp");
00804 if (tmp->type == AJI_CONNECT_STUN)
00805 iks_insert_attrib(candidate, "type", "stun");
00806 if (tmp->type == AJI_CONNECT_LOCAL)
00807 iks_insert_attrib(candidate, "type", "local");
00808 if (tmp->type == AJI_CONNECT_RELAY)
00809 iks_insert_attrib(candidate, "type", "relay");
00810 iks_insert_attrib(candidate, "network", "0");
00811 iks_insert_attrib(candidate, "generation", "0");
00812 iks_send(c->p, iq);
00813 }
00814 p->laststun = 0;
00815
00816 safeout:
00817 if (ours1)
00818 free(ours1);
00819 if (ours2)
00820 free(ours2);
00821 if (iq)
00822 iks_delete(iq);
00823 if (gtalk)
00824 iks_delete(gtalk);
00825 if (candidate)
00826 iks_delete(candidate);
00827 if(transport)
00828 iks_delete(transport);
00829 return 1;
00830 }
00831
00832 static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid)
00833 {
00834 struct gtalk_pvt *tmp = NULL;
00835 struct aji_resource *resources = NULL;
00836 struct aji_buddy *buddy;
00837 char idroster[200];
00838 char *data, *exten = NULL;
00839
00840 if (option_debug)
00841 ast_log(LOG_DEBUG, "The client is %s for alloc\n", client->name);
00842 if (!sid && !strchr(them, '/')) {
00843 if (!strcasecmp(client->name, "guest")) {
00844 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them);
00845 if (buddy)
00846 resources = buddy->resources;
00847 } else if (client->buddy)
00848 resources = client->buddy->resources;
00849 while (resources) {
00850 if (resources->cap->jingle) {
00851 break;
00852 }
00853 resources = resources->next;
00854 }
00855 if (resources)
00856 snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource);
00857 else {
00858 ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
00859 return NULL;
00860 }
00861 }
00862 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00863 return NULL;
00864 }
00865 if (sid) {
00866 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
00867 ast_copy_string(tmp->them, them, sizeof(tmp->them));
00868 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00869 } else {
00870 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
00871 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
00872 ast_copy_string(tmp->us, us, sizeof(tmp->us));
00873 tmp->initiator = 1;
00874 }
00875 tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
00876 tmp->parent = client;
00877 if (!tmp->rtp) {
00878 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
00879 free(tmp);
00880 return NULL;
00881 }
00882
00883 if(strchr(tmp->us, '/')) {
00884 data = ast_strdupa(tmp->us);
00885 exten = strsep(&data, "/");
00886 } else
00887 exten = tmp->us;
00888 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
00889 ast_mutex_init(&tmp->lock);
00890 ast_mutex_lock(>alklock);
00891 tmp->next = client->p;
00892 client->p = tmp;
00893 ast_mutex_unlock(>alklock);
00894 return tmp;
00895 }
00896
00897
00898 static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title)
00899 {
00900 struct ast_channel *tmp;
00901 int fmt;
00902 int what;
00903 const char *n2;
00904 char *data = NULL, *cid = NULL;
00905
00906 if (title)
00907 n2 = title;
00908 else
00909 n2 = i->us;
00910 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff);
00911 if (!tmp) {
00912 ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n");
00913 return NULL;
00914 }
00915 tmp->tech = >alk_tech;
00916
00917
00918
00919
00920 if (i->jointcapability)
00921 what = i->jointcapability;
00922 else if (i->capability)
00923 what = i->capability;
00924 else
00925 what = global_capability;
00926 tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
00927 fmt = ast_best_codec(tmp->nativeformats);
00928
00929 if (i->rtp) {
00930 ast_rtp_setstun(i->rtp, 1);
00931 tmp->fds[0] = ast_rtp_fd(i->rtp);
00932 tmp->fds[1] = ast_rtcp_fd(i->rtp);
00933 }
00934 if (i->vrtp) {
00935 ast_rtp_setstun(i->rtp, 1);
00936 tmp->fds[2] = ast_rtp_fd(i->vrtp);
00937 tmp->fds[3] = ast_rtcp_fd(i->vrtp);
00938 }
00939 if (state == AST_STATE_RING)
00940 tmp->rings = 1;
00941 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
00942 tmp->writeformat = fmt;
00943 tmp->rawwriteformat = fmt;
00944 tmp->readformat = fmt;
00945 tmp->rawreadformat = fmt;
00946 tmp->tech_pvt = i;
00947
00948 tmp->callgroup = client->callgroup;
00949 tmp->pickupgroup = client->pickupgroup;
00950 tmp->cid.cid_pres = client->callingpres;
00951 if (!ast_strlen_zero(client->accountcode))
00952 ast_string_field_set(tmp, accountcode, client->accountcode);
00953 if (client->amaflags)
00954 tmp->amaflags = client->amaflags;
00955 if (!ast_strlen_zero(client->language))
00956 ast_string_field_set(tmp, language, client->language);
00957 if (!ast_strlen_zero(client->musicclass))
00958 ast_string_field_set(tmp, musicclass, client->musicclass);
00959 i->owner = tmp;
00960 ast_module_ref(ast_module_info->self);
00961 ast_copy_string(tmp->context, client->context, sizeof(tmp->context));
00962 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
00963
00964
00965 if (!strcasecmp(client->name, "guest")) {
00966 data = ast_strdupa(i->them);
00967 if (strchr(data, '/')) {
00968 cid = strsep(&data, "/");
00969 } else
00970 cid = data;
00971 } else {
00972 data = ast_strdupa(client->user);
00973 cid = data;
00974 }
00975 cid = strsep(&cid, "@");
00976 tmp->cid.cid_num = ast_strdup(cid);
00977 tmp->cid.cid_ani = ast_strdup(cid);
00978 tmp->cid.cid_name = ast_strdup(i->them);
00979 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
00980 tmp->cid.cid_dnid = ast_strdup(i->exten);
00981 tmp->priority = 1;
00982 if (i->rtp)
00983 ast_jb_configure(tmp, &global_jbconf);
00984 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
00985 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00986 tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
00987 ast_hangup(tmp);
00988 tmp = NULL;
00989 }
00990
00991 return tmp;
00992 }
00993
00994 static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action)
00995 {
00996 iks *request, *session = NULL;
00997 int res = -1;
00998
00999 request = iks_new("iq");
01000 if (request) {
01001 iks_insert_attrib(request, "type", "set");
01002 iks_insert_attrib(request, "from", p->us);
01003 iks_insert_attrib(request, "to", p->them);
01004 iks_insert_attrib(request, "id", client->connection->mid);
01005 ast_aji_increment_mid(client->connection->mid);
01006 session = iks_new("session");
01007 if (session) {
01008 iks_insert_attrib(session, "type", action);
01009 iks_insert_attrib(session, "id", p->sid);
01010 iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them);
01011 iks_insert_attrib(session, "xmlns", "http://www.google.com/session");
01012 iks_insert_node(request, session);
01013 iks_send(client->connection->p, request);
01014 iks_delete(session);
01015 res = 0;
01016 }
01017 iks_delete(request);
01018 }
01019 return res;
01020 }
01021
01022 static void gtalk_free_candidates(struct gtalk_candidate *candidate)
01023 {
01024 struct gtalk_candidate *last;
01025 while (candidate) {
01026 last = candidate;
01027 candidate = candidate->next;
01028 free(last);
01029 }
01030 }
01031
01032 static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p)
01033 {
01034 struct gtalk_pvt *cur, *prev = NULL;
01035 cur = client->p;
01036 while (cur) {
01037 if (cur == p) {
01038 if (prev)
01039 prev->next = p->next;
01040 else
01041 client->p = p->next;
01042 break;
01043 }
01044 prev = cur;
01045 cur = cur->next;
01046 }
01047 if (p->ringrule)
01048 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
01049 if (p->owner)
01050 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
01051 if (p->rtp)
01052 ast_rtp_destroy(p->rtp);
01053 if (p->vrtp)
01054 ast_rtp_destroy(p->vrtp);
01055 gtalk_free_candidates(p->theircandidates);
01056 free(p);
01057 }
01058
01059
01060 static int gtalk_newcall(struct gtalk *client, ikspak *pak)
01061 {
01062 struct gtalk_pvt *p, *tmp = client->p;
01063 struct ast_channel *chan;
01064 int res;
01065 iks *codec;
01066 char *from = NULL;
01067
01068 from = iks_find_attrib(pak->x,"to");
01069 if(!from)
01070 from = client->connection->jid->full;
01071
01072 while (tmp) {
01073 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01074 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
01075 gtalk_response(client, from, pak, "out-of-order", NULL);
01076 return -1;
01077 }
01078 tmp = tmp->next;
01079 }
01080
01081 p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id"));
01082 if (!p) {
01083 ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n");
01084 return -1;
01085 }
01086 chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user);
01087 if (chan) {
01088 ast_mutex_lock(&p->lock);
01089 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
01090 if (iks_find_attrib(pak->query, "id")) {
01091 ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"),
01092 sizeof(p->sid));
01093 }
01094
01095 codec = iks_child(iks_child(iks_child(pak->x)));
01096 while (codec) {
01097 ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
01098 ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio",
01099 iks_find_attrib(codec, "name"), 0);
01100 codec = iks_next(codec);
01101 }
01102
01103 ast_mutex_unlock(&p->lock);
01104 ast_setstate(chan, AST_STATE_RING);
01105 res = ast_pbx_start(chan);
01106
01107 switch (res) {
01108 case AST_PBX_FAILED:
01109 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
01110 gtalk_response(client, from, pak, "service-unavailable", NULL);
01111 break;
01112 case AST_PBX_CALL_LIMIT:
01113 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
01114 gtalk_response(client, from, pak, "service-unavailable", NULL);
01115 break;
01116 case AST_PBX_SUCCESS:
01117 gtalk_response(client, from, pak, NULL, NULL);
01118 gtalk_invite_response(p, p->them, p->us,p->sid, 0);
01119 gtalk_create_candidates(client, p, p->sid, p->them, p->us);
01120
01121 break;
01122 }
01123 } else {
01124 gtalk_free_pvt(client, p);
01125 }
01126 return 1;
01127 }
01128
01129 static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p)
01130 {
01131 struct gtalk_candidate *tmp;
01132 struct hostent *hp;
01133 struct ast_hostent ahp;
01134 struct sockaddr_in sin;
01135 struct sockaddr_in aux;
01136
01137 if (time(NULL) == p->laststun)
01138 return 0;
01139
01140 tmp = p->theircandidates;
01141 p->laststun = time(NULL);
01142 while (tmp) {
01143 char username[256];
01144
01145
01146 hp = ast_gethostbyname(tmp->ip, &ahp);
01147 sin.sin_family = AF_INET;
01148 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01149 sin.sin_port = htons(tmp->port);
01150 snprintf(username, sizeof(username), "%s%s", tmp->username,
01151 p->ourcandidates->username);
01152
01153
01154 ast_rtp_get_peer(p->rtp, &aux);
01155
01156
01157
01158
01159 if (aux.sin_addr.s_addr &&
01160 aux.sin_addr.s_addr != sin.sin_addr.s_addr)
01161 ast_rtp_stun_request(p->rtp, &aux, username);
01162 else
01163 ast_rtp_stun_request(p->rtp, &sin, username);
01164
01165 if (aux.sin_addr.s_addr && option_debug > 3) {
01166 ast_log(LOG_DEBUG, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
01167 ast_log(LOG_DEBUG, "Sending STUN request to %s\n", tmp->ip);
01168 }
01169
01170 tmp = tmp->next;
01171 }
01172 return 1;
01173 }
01174
01175 static int gtalk_add_candidate(struct gtalk *client, ikspak *pak)
01176 {
01177 struct gtalk_pvt *p = NULL, *tmp = NULL;
01178 struct aji_client *c = client->connection;
01179 struct gtalk_candidate *newcandidate = NULL;
01180 iks *traversenodes = NULL, *receipt = NULL;
01181 char *from;
01182
01183 from = iks_find_attrib(pak->x,"to");
01184 if(!from)
01185 from = c->jid->full;
01186
01187 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01188 if (!newcandidate)
01189 return 0;
01190 for (tmp = client->p; tmp; tmp = tmp->next) {
01191 if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) {
01192 p = tmp;
01193 break;
01194 }
01195 }
01196
01197 if (!p)
01198 return -1;
01199
01200 traversenodes = pak->query;
01201 while(traversenodes) {
01202 if(!strcasecmp(iks_name(traversenodes), "session")) {
01203 traversenodes = iks_child(traversenodes);
01204 continue;
01205 }
01206 if(!strcasecmp(iks_name(traversenodes), "transport")) {
01207 traversenodes = iks_child(traversenodes);
01208 continue;
01209 }
01210 if(!strcasecmp(iks_name(traversenodes), "candidate")) {
01211 newcandidate = ast_calloc(1, sizeof(*newcandidate));
01212 if (!newcandidate)
01213 return 0;
01214 ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"),
01215 sizeof(newcandidate->name));
01216 ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"),
01217 sizeof(newcandidate->ip));
01218 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
01219 ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"),
01220 sizeof(newcandidate->username));
01221 ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"),
01222 sizeof(newcandidate->password));
01223 newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference"));
01224 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
01225 newcandidate->protocol = AJI_PROTOCOL_UDP;
01226 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
01227 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
01228
01229 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun"))
01230 newcandidate->type = AJI_CONNECT_STUN;
01231 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local"))
01232 newcandidate->type = AJI_CONNECT_LOCAL;
01233 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
01234 newcandidate->type = AJI_CONNECT_RELAY;
01235 ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"),
01236 sizeof(newcandidate->network));
01237 newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
01238 newcandidate->next = NULL;
01239
01240 newcandidate->next = p->theircandidates;
01241 p->theircandidates = newcandidate;
01242 p->laststun = 0;
01243 gtalk_update_stun(p->parent, p);
01244 newcandidate = NULL;
01245 }
01246 traversenodes = iks_next(traversenodes);
01247 }
01248
01249 receipt = iks_new("iq");
01250 iks_insert_attrib(receipt, "type", "result");
01251 iks_insert_attrib(receipt, "from", from);
01252 iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
01253 iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
01254 iks_send(c->p, receipt);
01255 iks_delete(receipt);
01256
01257 return 1;
01258 }
01259
01260 static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p)
01261 {
01262 struct ast_frame *f;
01263
01264 if (!p->rtp)
01265 return &ast_null_frame;
01266 f = ast_rtp_read(p->rtp);
01267 gtalk_update_stun(p->parent, p);
01268 if (p->owner) {
01269
01270 if (f->frametype == AST_FRAME_VOICE) {
01271 if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
01272 if (option_debug)
01273 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
01274 p->owner->nativeformats =
01275 (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
01276 ast_set_read_format(p->owner, p->owner->readformat);
01277 ast_set_write_format(p->owner, p->owner->writeformat);
01278 }
01279
01280
01281
01282
01283
01284 }
01285 }
01286 return f;
01287 }
01288
01289 static struct ast_frame *gtalk_read(struct ast_channel *ast)
01290 {
01291 struct ast_frame *fr;
01292 struct gtalk_pvt *p = ast->tech_pvt;
01293
01294 ast_mutex_lock(&p->lock);
01295 fr = gtalk_rtp_read(ast, p);
01296 ast_mutex_unlock(&p->lock);
01297 return fr;
01298 }
01299
01300
01301 static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame)
01302 {
01303 struct gtalk_pvt *p = ast->tech_pvt;
01304 int res = 0;
01305
01306 switch (frame->frametype) {
01307 case AST_FRAME_VOICE:
01308 if (!(frame->subclass & ast->nativeformats)) {
01309 ast_log(LOG_WARNING,
01310 "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01311 frame->subclass, ast->nativeformats, ast->readformat,
01312 ast->writeformat);
01313 return 0;
01314 }
01315 if (p) {
01316 ast_mutex_lock(&p->lock);
01317 if (p->rtp) {
01318 res = ast_rtp_write(p->rtp, frame);
01319 }
01320 ast_mutex_unlock(&p->lock);
01321 }
01322 break;
01323 case AST_FRAME_VIDEO:
01324 if (p) {
01325 ast_mutex_lock(&p->lock);
01326 if (p->vrtp) {
01327 res = ast_rtp_write(p->vrtp, frame);
01328 }
01329 ast_mutex_unlock(&p->lock);
01330 }
01331 break;
01332 case AST_FRAME_IMAGE:
01333 return 0;
01334 break;
01335 default:
01336 ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n",
01337 frame->frametype);
01338 return 0;
01339 }
01340
01341 return res;
01342 }
01343
01344 static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01345 {
01346 struct gtalk_pvt *p = newchan->tech_pvt;
01347 ast_mutex_lock(&p->lock);
01348
01349 if ((p->owner != oldchan)) {
01350 ast_mutex_unlock(&p->lock);
01351 return -1;
01352 }
01353 if (p->owner == oldchan)
01354 p->owner = newchan;
01355 ast_mutex_unlock(&p->lock);
01356 return 0;
01357 }
01358
01359 static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01360 {
01361 int res = 0;
01362
01363 switch (condition) {
01364 case AST_CONTROL_HOLD:
01365 ast_moh_start(ast, data, NULL);
01366 break;
01367 case AST_CONTROL_UNHOLD:
01368 ast_moh_stop(ast);
01369 break;
01370 default:
01371 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01372 res = -1;
01373 }
01374
01375 return res;
01376 }
01377
01378 static int gtalk_digit_begin(struct ast_channel *chan, char digit)
01379 {
01380 return gtalk_digit(chan, digit, 0);
01381 }
01382
01383 static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01384 {
01385 return gtalk_digit(chan, digit, duration);
01386 }
01387
01388 static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration)
01389 {
01390 struct gtalk_pvt *p = ast->tech_pvt;
01391 struct gtalk *client = p->parent;
01392 iks *iq, *gtalk, *dtmf;
01393 char buffer[2] = {digit, '\0'};
01394 iq = iks_new("iq");
01395 gtalk = iks_new("gtalk");
01396 dtmf = iks_new("dtmf");
01397 if(!iq || !gtalk || !dtmf) {
01398 if(iq)
01399 iks_delete(iq);
01400 if(gtalk)
01401 iks_delete(gtalk);
01402 if(dtmf)
01403 iks_delete(dtmf);
01404 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
01405 return -1;
01406 }
01407
01408 iks_insert_attrib(iq, "type", "set");
01409 iks_insert_attrib(iq, "to", p->them);
01410 iks_insert_attrib(iq, "from", p->us);
01411 iks_insert_attrib(iq, "id", client->connection->mid);
01412 ast_aji_increment_mid(client->connection->mid);
01413 iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk");
01414 iks_insert_attrib(gtalk, "action", "content-info");
01415 iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them);
01416 iks_insert_attrib(gtalk, "sid", p->sid);
01417 iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf");
01418 iks_insert_attrib(dtmf, "code", buffer);
01419 iks_insert_node(iq, gtalk);
01420 iks_insert_node(gtalk, dtmf);
01421
01422 ast_mutex_lock(&p->lock);
01423 if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN) {
01424 iks_insert_attrib(dtmf, "action", "button-down");
01425 } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END) {
01426 iks_insert_attrib(dtmf, "action", "button-up");
01427 }
01428 iks_send(client->connection->p, iq);
01429 iks_delete(iq);
01430 iks_delete(gtalk);
01431 iks_delete(dtmf);
01432 ast_mutex_unlock(&p->lock);
01433 return 0;
01434 }
01435
01436 static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
01437 {
01438 ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n");
01439
01440 return -1;
01441 }
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463 static int gtalk_call(struct ast_channel *ast, char *dest, int timeout)
01464 {
01465 struct gtalk_pvt *p = ast->tech_pvt;
01466
01467 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01468 ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name);
01469 return -1;
01470 }
01471
01472 ast_setstate(ast, AST_STATE_RING);
01473 p->jointcapability = p->capability;
01474 if (!p->ringrule) {
01475 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
01476 p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p,
01477 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
01478 } else
01479 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
01480
01481 gtalk_invite(p, p->them, p->us, p->sid, 1);
01482 gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us);
01483
01484 return 0;
01485 }
01486
01487
01488 static int gtalk_hangup(struct ast_channel *ast)
01489 {
01490 struct gtalk_pvt *p = ast->tech_pvt;
01491 struct gtalk *client;
01492
01493 ast_mutex_lock(&p->lock);
01494 client = p->parent;
01495 p->owner = NULL;
01496 ast->tech_pvt = NULL;
01497 if (!p->alreadygone)
01498 gtalk_action(client, p, "terminate");
01499 ast_mutex_unlock(&p->lock);
01500
01501 gtalk_free_pvt(client, p);
01502 ast_module_unref(ast_module_info->self);
01503
01504 return 0;
01505 }
01506
01507
01508 static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause)
01509 {
01510 struct gtalk_pvt *p = NULL;
01511 struct gtalk *client = NULL;
01512 char *sender = NULL, *to = NULL, *s = NULL;
01513 struct ast_channel *chan = NULL;
01514
01515 if (data) {
01516 s = ast_strdupa(data);
01517 if (s) {
01518 sender = strsep(&s, "/");
01519 if (sender && (sender[0] != '\0'))
01520 to = strsep(&s, "/");
01521 if (!to) {
01522 ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data);
01523 return NULL;
01524 }
01525 }
01526 }
01527 client = find_gtalk(to, sender);
01528 if (!client) {
01529 ast_log(LOG_WARNING, "Could not find recipient.\n");
01530 return NULL;
01531 }
01532 ASTOBJ_WRLOCK(client);
01533 p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL);
01534 if (p)
01535 chan = gtalk_new(client, p, AST_STATE_DOWN, to);
01536
01537 ASTOBJ_UNLOCK(client);
01538 return chan;
01539 }
01540
01541
01542 static int gtalk_show_channels(int fd, int argc, char **argv)
01543 {
01544 if (argc != 3)
01545 return RESULT_SHOWUSAGE;
01546 ast_mutex_lock(>alklock);
01547
01548 ast_cli(fd, "No gtalk channels in use\n");
01549 ast_mutex_unlock(>alklock);
01550 return RESULT_SUCCESS;
01551 }
01552
01553
01554 static int gtalk_do_reload(int fd, int argc, char **argv)
01555 {
01556 ast_verbose("IT DOES WORK!\n");
01557 return RESULT_SUCCESS;
01558 }
01559
01560 static int gtalk_parser(void *data, ikspak *pak)
01561 {
01562 struct gtalk *client = ASTOBJ_REF((struct gtalk *) data);
01563
01564 if (iks_find_with_attrib(pak->x, "session", "type", "initiate")) {
01565
01566 gtalk_newcall(client, pak);
01567 } else if (iks_find_with_attrib(pak->x, "session", "type", "candidates") || iks_find_with_attrib(pak->x, "session", "type", "transport-info")) {
01568 if (option_debug > 2)
01569 ast_log(LOG_DEBUG, "About to add candidate!\n");
01570 gtalk_add_candidate(client, pak);
01571 if (option_debug > 2)
01572 ast_log(LOG_DEBUG, "Candidate Added!\n");
01573 } else if (iks_find_with_attrib(pak->x, "session", "type", "accept") || iks_find_with_attrib(pak->x, "session", "type", "transport-accept")) {
01574 gtalk_is_answered(client, pak);
01575 } else if (iks_find_with_attrib(pak->x, "session", "type", "content-info")) {
01576 gtalk_handle_dtmf(client, pak);
01577 } else if (iks_find_with_attrib(pak->x, "session", "type", "terminate")) {
01578 gtalk_hangup_farend(client, pak);
01579 } else if (iks_find_with_attrib(pak->x, "session", "type", "reject")) {
01580 gtalk_hangup_farend(client, pak);
01581 }
01582 ASTOBJ_UNREF(client, gtalk_member_destroy);
01583 return IKS_FILTER_EAT;
01584 }
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634 static int gtalk_create_member(char *label, struct ast_variable *var, int allowguest,
01635 struct ast_codec_pref prefs, char *context,
01636 struct gtalk *member)
01637 {
01638 struct aji_client *client;
01639
01640 if (!member)
01641 ast_log(LOG_WARNING, "Out of memory.\n");
01642
01643 ast_copy_string(member->name, label, sizeof(member->name));
01644 ast_copy_string(member->user, label, sizeof(member->user));
01645 ast_copy_string(member->context, context, sizeof(member->context));
01646 member->allowguest = allowguest;
01647 member->prefs = prefs;
01648 while (var) {
01649 #if 0
01650 struct gtalk_candidate *candidate = NULL;
01651 #endif
01652 if (!strcasecmp(var->name, "username"))
01653 ast_copy_string(member->user, var->value, sizeof(member->user));
01654 else if (!strcasecmp(var->name, "disallow"))
01655 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 0);
01656 else if (!strcasecmp(var->name, "allow"))
01657 ast_parse_allow_disallow(&member->prefs, &member->capability, var->value, 1);
01658 else if (!strcasecmp(var->name, "context"))
01659 ast_copy_string(member->context, var->value, sizeof(member->context));
01660 #if 0
01661 else if (!strcasecmp(var->name, "candidate")) {
01662 candidate = gtalk_create_candidate(var->value);
01663 if (candidate) {
01664 candidate->next = member->ourcandidates;
01665 member->ourcandidates = candidate;
01666 }
01667 }
01668 #endif
01669 else if (!strcasecmp(var->name, "connection")) {
01670 if ((client = ast_aji_get_client(var->value))) {
01671 member->connection = client;
01672 iks_filter_add_rule(client->f, gtalk_parser, member, IKS_RULE_TYPE,
01673 IKS_PAK_IQ, IKS_RULE_FROM_PARTIAL, member->user,
01674 IKS_RULE_NS, "http://www.google.com/session",
01675 IKS_RULE_DONE);
01676
01677 } else {
01678 ast_log(LOG_ERROR, "connection referenced not found!\n");
01679 return 0;
01680 }
01681 }
01682 var = var->next;
01683 }
01684 if (member->connection && member->user)
01685 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
01686 else {
01687 ast_log(LOG_ERROR, "No Connection or Username!\n");
01688 }
01689 return 1;
01690 }
01691
01692 static int gtalk_load_config(void)
01693 {
01694 char *cat = NULL;
01695 struct ast_config *cfg = NULL;
01696 char context[100];
01697 int allowguest = 1;
01698 struct ast_variable *var;
01699 struct gtalk *member;
01700 struct ast_codec_pref prefs;
01701 struct aji_client_container *clients;
01702 struct gtalk_candidate *global_candidates = NULL;
01703 struct hostent *hp;
01704 struct ast_hostent ahp;
01705
01706 cfg = ast_config_load(GOOGLE_CONFIG);
01707 if (!cfg)
01708 return 0;
01709
01710
01711 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
01712
01713 cat = ast_category_browse(cfg, NULL);
01714 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
01715
01716 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
01717 continue;
01718
01719 if (!strcasecmp(var->name, "allowguest"))
01720 allowguest =
01721 (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
01722 else if (!strcasecmp(var->name, "disallow"))
01723 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 0);
01724 else if (!strcasecmp(var->name, "allow"))
01725 ast_parse_allow_disallow(&prefs, &global_capability, var->value, 1);
01726 else if (!strcasecmp(var->name, "context"))
01727 ast_copy_string(context, var->value, sizeof(context));
01728 else if (!strcasecmp(var->name, "bindaddr")) {
01729 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
01730 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
01731 } else {
01732 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
01733 }
01734 }
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745 }
01746 while (cat) {
01747 if (strcasecmp(cat, "general")) {
01748 var = ast_variable_browse(cfg, cat);
01749 member = (struct gtalk *) malloc(sizeof(struct gtalk));
01750 memset(member, 0, sizeof(struct gtalk));
01751 ASTOBJ_INIT(member);
01752 ASTOBJ_WRLOCK(member);
01753 if (!strcasecmp(cat, "guest")) {
01754 ast_copy_string(member->name, "guest", sizeof(member->name));
01755 ast_copy_string(member->user, "guest", sizeof(member->user));
01756 ast_copy_string(member->context, context, sizeof(member->context));
01757 member->allowguest = allowguest;
01758 member->prefs = prefs;
01759 while (var) {
01760 if (!strcasecmp(var->name, "disallow"))
01761 ast_parse_allow_disallow(&member->prefs, &member->capability,
01762 var->value, 0);
01763 else if (!strcasecmp(var->name, "allow"))
01764 ast_parse_allow_disallow(&member->prefs, &member->capability,
01765 var->value, 1);
01766 else if (!strcasecmp(var->name, "context"))
01767 ast_copy_string(member->context, var->value,
01768 sizeof(member->context));
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779 var = var->next;
01780 }
01781 ASTOBJ_UNLOCK(member);
01782 clients = ast_aji_get_clients();
01783 if (clients) {
01784 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
01785 ASTOBJ_WRLOCK(iterator);
01786 ASTOBJ_WRLOCK(member);
01787 member->connection = iterator;
01788 iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS,
01789 "http://www.google.com/session", IKS_RULE_DONE);
01790 ASTOBJ_UNLOCK(member);
01791 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01792 ASTOBJ_UNLOCK(iterator);
01793 });
01794 } else {
01795 ASTOBJ_UNLOCK(member);
01796 ASTOBJ_UNREF(member, gtalk_member_destroy);
01797 }
01798 } else {
01799 ASTOBJ_UNLOCK(member);
01800 if (gtalk_create_member(cat, var, allowguest, prefs, context, member))
01801 ASTOBJ_CONTAINER_LINK(>alk_list, member);
01802 ASTOBJ_UNREF(member, gtalk_member_destroy);
01803 }
01804 }
01805 cat = ast_category_browse(cfg, cat);
01806 }
01807 gtalk_free_candidates(global_candidates);
01808 return 1;
01809 }
01810
01811
01812 static int load_module(void)
01813 {
01814 #ifdef HAVE_GNUTLS
01815 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
01816 #endif
01817
01818 ASTOBJ_CONTAINER_INIT(>alk_list);
01819 if (!gtalk_load_config()) {
01820 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", GOOGLE_CONFIG);
01821 return 0;
01822 }
01823
01824 sched = sched_context_create();
01825 if (!sched)
01826 ast_log(LOG_WARNING, "Unable to create schedule context\n");
01827
01828 io = io_context_create();
01829 if (!io)
01830 ast_log(LOG_WARNING, "Unable to create I/O context\n");
01831
01832 if (ast_find_ourip(&__ourip, bindaddr)) {
01833 ast_log(LOG_WARNING, "Unable to get own IP address, Gtalk disabled\n");
01834 return 0;
01835 }
01836
01837 ast_rtp_proto_register(>alk_rtp);
01838 ast_cli_register_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01839
01840
01841 if (ast_channel_register(>alk_tech)) {
01842 ast_log(LOG_ERROR, "Unable to register channel class %s\n", gtalk_tech.type);
01843 return -1;
01844 }
01845 return 0;
01846 }
01847
01848
01849 static int reload(void)
01850 {
01851 return 0;
01852 }
01853
01854
01855 static int unload_module(void)
01856 {
01857 struct gtalk_pvt *privates = NULL;
01858 ast_cli_unregister_multiple(gtalk_cli, sizeof(gtalk_cli) / sizeof(gtalk_cli[0]));
01859
01860 ast_channel_unregister(>alk_tech);
01861 ast_rtp_proto_unregister(>alk_rtp);
01862
01863 if (!ast_mutex_lock(>alklock)) {
01864
01865 ASTOBJ_CONTAINER_TRAVERSE(>alk_list, 1, {
01866 ASTOBJ_WRLOCK(iterator);
01867 privates = iterator->p;
01868 while(privates) {
01869 if (privates->owner)
01870 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
01871 privates = privates->next;
01872 }
01873 iterator->p = NULL;
01874 ASTOBJ_UNLOCK(iterator);
01875 });
01876 ast_mutex_unlock(>alklock);
01877 } else {
01878 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01879 return -1;
01880 }
01881 ASTOBJ_CONTAINER_DESTROYALL(>alk_list, gtalk_member_destroy);
01882 ASTOBJ_CONTAINER_DESTROY(>alk_list);
01883 return 0;
01884 }
01885
01886 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Gtalk Channel Driver",
01887 .load = load_module,
01888 .unload = unload_module,
01889 .reload = reload,
01890 );