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