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