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