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