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
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 397744 $")
00040
00041 #include <sys/socket.h>
00042 #include <fcntl.h>
00043 #include <netdb.h>
00044 #include <netinet/in.h>
00045 #include <arpa/inet.h>
00046 #include <sys/signal.h>
00047 #include <iksemel.h>
00048 #include <pthread.h>
00049
00050 #include "asterisk/lock.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/config_options.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/pbx.h"
00055 #include "asterisk/sched.h"
00056 #include "asterisk/io.h"
00057 #include "asterisk/rtp_engine.h"
00058 #include "asterisk/acl.h"
00059 #include "asterisk/callerid.h"
00060 #include "asterisk/file.h"
00061 #include "asterisk/cli.h"
00062 #include "asterisk/app.h"
00063 #include "asterisk/musiconhold.h"
00064 #include "asterisk/manager.h"
00065 #include "asterisk/stringfields.h"
00066 #include "asterisk/utils.h"
00067 #include "asterisk/causes.h"
00068 #include "asterisk/astobj.h"
00069 #include "asterisk/abstract_jb.h"
00070 #include "asterisk/xmpp.h"
00071
00072
00073 #define DEFAULT_MAX_ICE_CANDIDATES "10"
00074
00075
00076 #define DEFAULT_MAX_PAYLOADS "30"
00077
00078
00079 #define ENDPOINT_BUCKETS 37
00080
00081
00082 #define SESSION_BUCKETS 37
00083
00084
00085 #define JINGLE_NS "urn:xmpp:jingle:1"
00086
00087
00088 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
00089
00090
00091 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
00092
00093
00094 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
00095
00096
00097 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
00098
00099
00100 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
00101
00102
00103 #define GOOGLE_SESSION_NS "http://www.google.com/session"
00104
00105
00106 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
00107
00108
00109 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
00110
00111
00112 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
00113
00114
00115 enum jingle_transport {
00116 JINGLE_TRANSPORT_ICE_UDP = 3,
00117 JINGLE_TRANSPORT_GOOGLE_V2 = 2,
00118 JINGLE_TRANSPORT_GOOGLE_V1 = 1,
00119 JINGLE_TRANSPORT_NONE = 0,
00120 };
00121
00122
00123 struct jingle_endpoint_state {
00124 struct ao2_container *sessions;
00125 };
00126
00127
00128 struct jingle_endpoint {
00129 AST_DECLARE_STRING_FIELDS(
00130 AST_STRING_FIELD(name);
00131 AST_STRING_FIELD(context);
00132 AST_STRING_FIELD(accountcode);
00133 AST_STRING_FIELD(language);
00134 AST_STRING_FIELD(musicclass);
00135 AST_STRING_FIELD(parkinglot);
00136 );
00137 struct ast_xmpp_client *connection;
00138 iksrule *rule;
00139 unsigned int maxicecandidates;
00140 unsigned int maxpayloads;
00141 struct ast_codec_pref prefs;
00142 struct ast_format_cap *cap;
00143 ast_group_t callgroup;
00144 ast_group_t pickupgroup;
00145 enum jingle_transport transport;
00146 struct jingle_endpoint_state *state;
00147 };
00148
00149
00150 struct jingle_session {
00151 AST_DECLARE_STRING_FIELDS(
00152 AST_STRING_FIELD(sid);
00153 AST_STRING_FIELD(audio_name);
00154 AST_STRING_FIELD(video_name);
00155 );
00156 struct jingle_endpoint_state *state;
00157 struct ast_xmpp_client *connection;
00158 enum jingle_transport transport;
00159 unsigned int maxicecandidates;
00160 unsigned int maxpayloads;
00161 char remote_original[XMPP_MAX_JIDLEN];
00162 char remote[XMPP_MAX_JIDLEN];
00163 iksrule *rule;
00164 struct ast_codec_pref prefs;
00165 struct ast_channel *owner;
00166 struct ast_rtp_instance *rtp;
00167 struct ast_rtp_instance *vrtp;
00168 struct ast_format_cap *cap;
00169 struct ast_format_cap *jointcap;
00170 struct ast_format_cap *peercap;
00171 unsigned int outgoing:1;
00172 unsigned int gone:1;
00173 struct ast_callid *callid;
00174 };
00175
00176 static const char desc[] = "Motif Jingle Channel";
00177 static const char channel_type[] = "Motif";
00178
00179 struct jingle_config {
00180 struct ao2_container *endpoints;
00181 };
00182
00183 static AO2_GLOBAL_OBJ_STATIC(globals);
00184
00185 static struct ast_sched_context *sched;
00186
00187
00188 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00189 static int jingle_sendtext(struct ast_channel *ast, const char *text);
00190 static int jingle_digit_begin(struct ast_channel *ast, char digit);
00191 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00192 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
00193 static int jingle_hangup(struct ast_channel *ast);
00194 static int jingle_answer(struct ast_channel *ast);
00195 static struct ast_frame *jingle_read(struct ast_channel *ast);
00196 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
00197 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00198 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00199 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
00200
00201
00202 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00203 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00204 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00205 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00206 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00207
00208
00209 static struct ast_channel_tech jingle_tech = {
00210 .type = "Motif",
00211 .description = "Motif Jingle Channel Driver",
00212 .requester = jingle_request,
00213 .send_text = jingle_sendtext,
00214 .send_digit_begin = jingle_digit_begin,
00215 .send_digit_end = jingle_digit_end,
00216 .bridge = ast_rtp_instance_bridge,
00217 .call = jingle_call,
00218 .hangup = jingle_hangup,
00219 .answer = jingle_answer,
00220 .read = jingle_read,
00221 .write = jingle_write,
00222 .write_video = jingle_write,
00223 .exception = jingle_read,
00224 .indicate = jingle_indicate,
00225 .fixup = jingle_fixup,
00226 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
00227 };
00228
00229
00230 static const struct jingle_action_handler {
00231 const char *action;
00232 void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
00233 } jingle_action_handlers[] = {
00234
00235 { "session-initiate", jingle_action_session_initiate, },
00236 { "transport-info", jingle_action_transport_info, },
00237 { "session-accept", jingle_action_session_accept, },
00238 { "session-info", jingle_action_session_info, },
00239 { "session-terminate", jingle_action_session_terminate, },
00240
00241 { "initiate", jingle_action_session_initiate, },
00242 { "candidates", jingle_action_transport_info, },
00243 { "accept", jingle_action_session_accept, },
00244 { "terminate", jingle_action_session_terminate, },
00245 { "reject", jingle_action_session_terminate, },
00246 };
00247
00248
00249 static const struct jingle_reason_mapping {
00250 const char *reason;
00251 int cause;
00252 } jingle_reason_mappings[] = {
00253 { "busy", AST_CAUSE_BUSY, },
00254 { "cancel", AST_CAUSE_CALL_REJECTED, },
00255 { "connectivity-error", AST_CAUSE_INTERWORKING, },
00256 { "decline", AST_CAUSE_CALL_REJECTED, },
00257 { "expired", AST_CAUSE_NO_USER_RESPONSE, },
00258 { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
00259 { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
00260 { "general-error", AST_CAUSE_CONGESTION, },
00261 { "gone", AST_CAUSE_NORMAL_CLEARING, },
00262 { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00263 { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00264 { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
00265 { "success", AST_CAUSE_NORMAL_CLEARING, },
00266 { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
00267 { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
00268 { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
00269 };
00270
00271
00272 static int jingle_session_hash(const void *obj, const int flags)
00273 {
00274 const struct jingle_session *session = obj;
00275 const char *sid = obj;
00276
00277 return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
00278 }
00279
00280
00281 static int jingle_session_cmp(void *obj, void *arg, int flags)
00282 {
00283 struct jingle_session *session1 = obj, *session2 = arg;
00284 const char *sid = arg;
00285
00286 return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
00287 }
00288
00289
00290 static void jingle_endpoint_state_destructor(void *obj)
00291 {
00292 struct jingle_endpoint_state *state = obj;
00293
00294 ao2_ref(state->sessions, -1);
00295 }
00296
00297
00298 static void jingle_endpoint_destructor(void *obj)
00299 {
00300 struct jingle_endpoint *endpoint = obj;
00301
00302 if (endpoint->rule) {
00303 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
00304 }
00305
00306 if (endpoint->connection) {
00307 ast_xmpp_client_unref(endpoint->connection);
00308 }
00309
00310 ast_format_cap_destroy(endpoint->cap);
00311
00312 ao2_ref(endpoint->state, -1);
00313
00314 ast_string_field_free_memory(endpoint);
00315 }
00316
00317
00318 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
00319 {
00320 return ao2_find(tmp_container, category, OBJ_KEY);
00321 }
00322
00323
00324 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
00325 {
00326 struct jingle_endpoint_state *state;
00327
00328 if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
00329 return NULL;
00330 }
00331
00332 if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
00333 ao2_ref(state, -1);
00334 return NULL;
00335 }
00336
00337 return state;
00338 }
00339
00340
00341 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
00342 {
00343 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00344 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
00345
00346 if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
00347 return jingle_endpoint_state_create();
00348 }
00349
00350 ao2_ref(endpoint->state, +1);
00351 return endpoint->state;
00352 }
00353
00354
00355 static void *jingle_endpoint_alloc(const char *cat)
00356 {
00357 struct jingle_endpoint *endpoint;
00358
00359 if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
00360 return NULL;
00361 }
00362
00363 if (ast_string_field_init(endpoint, 512)) {
00364 ao2_ref(endpoint, -1);
00365 return NULL;
00366 }
00367
00368 if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
00369 ao2_ref(endpoint, -1);
00370 return NULL;
00371 }
00372
00373 ast_string_field_set(endpoint, name, cat);
00374
00375 endpoint->cap = ast_format_cap_alloc_nolock();
00376 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
00377
00378 return endpoint;
00379 }
00380
00381
00382 static int jingle_endpoint_hash(const void *obj, const int flags)
00383 {
00384 const struct jingle_endpoint *endpoint = obj;
00385 const char *name = obj;
00386
00387 return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
00388 }
00389
00390
00391 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
00392 {
00393 struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
00394 const char *name = arg;
00395
00396 return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
00397 }
00398
00399 static struct aco_type endpoint_option = {
00400 .type = ACO_ITEM,
00401 .category_match = ACO_BLACKLIST,
00402 .category = "^general$",
00403 .item_alloc = jingle_endpoint_alloc,
00404 .item_find = jingle_endpoint_find,
00405 .item_offset = offsetof(struct jingle_config, endpoints),
00406 };
00407
00408 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
00409
00410 struct aco_file jingle_conf = {
00411 .filename = "motif.conf",
00412 .types = ACO_TYPES(&endpoint_option),
00413 };
00414
00415
00416 static void jingle_session_destructor(void *obj)
00417 {
00418 struct jingle_session *session = obj;
00419
00420 if (session->rule) {
00421 iks_filter_remove_rule(session->connection->filter, session->rule);
00422 }
00423
00424 if (session->connection) {
00425 ast_xmpp_client_unref(session->connection);
00426 }
00427
00428 if (session->rtp) {
00429 ast_rtp_instance_stop(session->rtp);
00430 ast_rtp_instance_destroy(session->rtp);
00431 }
00432
00433 if (session->vrtp) {
00434 ast_rtp_instance_stop(session->vrtp);
00435 ast_rtp_instance_destroy(session->vrtp);
00436 }
00437
00438 ast_format_cap_destroy(session->cap);
00439 ast_format_cap_destroy(session->jointcap);
00440 ast_format_cap_destroy(session->peercap);
00441
00442 if (session->callid) {
00443 ast_callid_unref(session->callid);
00444 }
00445
00446 ast_string_field_free_memory(session);
00447 }
00448
00449
00450 static void jingle_config_destructor(void *obj)
00451 {
00452 struct jingle_config *cfg = obj;
00453 ao2_cleanup(cfg->endpoints);
00454 }
00455
00456
00457 static void *jingle_config_alloc(void)
00458 {
00459 struct jingle_config *cfg;
00460
00461 if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
00462 return NULL;
00463 }
00464
00465 if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
00466 ao2_ref(cfg, -1);
00467 return NULL;
00468 }
00469
00470 return cfg;
00471 }
00472
00473 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
00474 .files = ACO_FILES(&jingle_conf),
00475 );
00476
00477
00478 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
00479 {
00480 struct jingle_session *session = ast_channel_tech_pvt(chan);
00481 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
00482
00483 if (!session->rtp) {
00484 return AST_RTP_GLUE_RESULT_FORBID;
00485 }
00486
00487 ao2_ref(session->rtp, +1);
00488 *instance = session->rtp;
00489
00490 return res;
00491 }
00492
00493
00494 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
00495 {
00496 }
00497
00498
00499 static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
00500 {
00501 return -1;
00502 }
00503
00504
00505 static struct ast_rtp_glue jingle_rtp_glue = {
00506 .type = "Motif",
00507 .get_rtp_info = jingle_get_rtp_peer,
00508 .get_codec = jingle_get_codec,
00509 .update_peer = jingle_set_rtp_peer,
00510 };
00511
00512
00513 static void jingle_enable_video(struct jingle_session *session)
00514 {
00515 struct ast_sockaddr tmp;
00516 struct ast_rtp_engine_ice *ice;
00517
00518
00519 if (session->vrtp) {
00520 return;
00521 }
00522
00523
00524 if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
00525 return;
00526 }
00527
00528 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00529
00530 if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00531 return;
00532 }
00533
00534 ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
00535
00536 ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
00537 ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
00538 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
00539
00540 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
00541 ice->stop(session->vrtp);
00542 }
00543 }
00544
00545
00546 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
00547 {
00548 struct jingle_session *session;
00549 struct ast_callid *callid;
00550 struct ast_sockaddr tmp;
00551
00552 if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
00553 return NULL;
00554 }
00555
00556 callid = ast_read_threadstorage_callid();
00557 session->callid = (callid ? callid : ast_create_callid());
00558
00559 if (ast_string_field_init(session, 512)) {
00560 ao2_ref(session, -1);
00561 return NULL;
00562 }
00563
00564 if (!ast_strlen_zero(from)) {
00565 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
00566 ast_copy_string(session->remote, from, sizeof(session->remote));
00567 }
00568
00569 if (ast_strlen_zero(sid)) {
00570 ast_string_field_build(session, sid, "%08lx%08lx", ast_random(), ast_random());
00571 session->outgoing = 1;
00572 ast_string_field_set(session, audio_name, "audio");
00573 ast_string_field_set(session, video_name, "video");
00574 } else {
00575 ast_string_field_set(session, sid, sid);
00576 }
00577
00578 ao2_ref(endpoint->state, +1);
00579 session->state = endpoint->state;
00580 ao2_ref(endpoint->connection, +1);
00581 session->connection = endpoint->connection;
00582 session->transport = endpoint->transport;
00583
00584 if (!(session->cap = ast_format_cap_alloc_nolock()) ||
00585 !(session->jointcap = ast_format_cap_alloc_nolock()) ||
00586 !(session->peercap = ast_format_cap_alloc_nolock()) ||
00587 !session->callid) {
00588 ao2_ref(session, -1);
00589 return NULL;
00590 }
00591
00592 ast_format_cap_copy(session->cap, endpoint->cap);
00593
00594
00595
00596 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
00597
00598
00599 if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
00600 ao2_ref(session, -1);
00601 return NULL;
00602 }
00603 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
00604 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
00605
00606 memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
00607
00608 session->maxicecandidates = endpoint->maxicecandidates;
00609 session->maxpayloads = endpoint->maxpayloads;
00610
00611 return session;
00612 }
00613
00614
00615 static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const char *linkedid, const char *cid_name)
00616 {
00617 struct ast_channel *chan;
00618 const char *str = S_OR(title, session->remote);
00619 struct ast_format tmpfmt;
00620
00621 if (ast_format_cap_is_empty(session->cap)) {
00622 return NULL;
00623 }
00624
00625 if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) {
00626 return NULL;
00627 }
00628
00629 ast_channel_tech_set(chan, &jingle_tech);
00630 ast_channel_tech_pvt_set(chan, session);
00631 session->owner = chan;
00632
00633 ast_channel_callid_set(chan, session->callid);
00634
00635 ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
00636 ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
00637
00638 if (session->rtp) {
00639 struct ast_rtp_engine_ice *ice;
00640
00641 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
00642 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
00643 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
00644
00645 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
00646 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
00647 (ice = ast_rtp_instance_get_ice(session->rtp))) {
00648
00649 ice->stop(session->rtp);
00650 }
00651 }
00652
00653 if (state == AST_STATE_RING) {
00654 ast_channel_rings_set(chan, 1);
00655 }
00656
00657 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
00658
00659 ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
00660 ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
00661 ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
00662 ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
00663 ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
00664
00665 ao2_lock(endpoint);
00666
00667 ast_channel_callgroup_set(chan, endpoint->callgroup);
00668 ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
00669
00670 if (!ast_strlen_zero(endpoint->accountcode)) {
00671 ast_channel_accountcode_set(chan, endpoint->accountcode);
00672 }
00673
00674 if (!ast_strlen_zero(endpoint->language)) {
00675 ast_channel_language_set(chan, endpoint->language);
00676 }
00677
00678 if (!ast_strlen_zero(endpoint->musicclass)) {
00679 ast_channel_musicclass_set(chan, endpoint->musicclass);
00680 }
00681
00682 ast_channel_context_set(chan, endpoint->context);
00683 if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
00684 ast_channel_exten_set(chan, endpoint->name);
00685 } else {
00686 ast_channel_exten_set(chan, "s");
00687 }
00688 ast_channel_priority_set(chan, 1);
00689
00690 ao2_unlock(endpoint);
00691
00692 return chan;
00693 }
00694
00695
00696 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
00697 {
00698 iks *response;
00699
00700 if (!(response = iks_new("iq"))) {
00701 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
00702 return;
00703 }
00704
00705 iks_insert_attrib(response, "type", "result");
00706 iks_insert_attrib(response, "from", connection->jid->full);
00707 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00708 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00709
00710 ast_xmpp_client_send(connection, response);
00711
00712 iks_delete(response);
00713 }
00714
00715
00716 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
00717 {
00718 iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
00719
00720 if (!(response = iks_new("iq")) ||
00721 !(error = iks_new("error")) ||
00722 !(reason = iks_new(reasonstr))) {
00723 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
00724 goto end;
00725 }
00726
00727 iks_insert_attrib(response, "type", "error");
00728 iks_insert_attrib(response, "from", connection->jid->full);
00729 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
00730 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
00731
00732 iks_insert_attrib(error, "type", type);
00733 iks_insert_node(error, reason);
00734
00735 if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
00736 iks_insert_node(error, reason2);
00737 }
00738
00739 iks_insert_node(response, error);
00740
00741 ast_xmpp_client_send(connection, response);
00742 end:
00743 iks_delete(reason2);
00744 iks_delete(reason);
00745 iks_delete(error);
00746 iks_delete(response);
00747 }
00748
00749
00750 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
00751 {
00752 struct ast_rtp_engine_ice *ice;
00753 struct ao2_container *local_candidates;
00754 struct ao2_iterator it;
00755 struct ast_rtp_engine_ice_candidate *candidate;
00756 int i = 0, res = 0;
00757
00758 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00759 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
00760 return -1;
00761 }
00762
00763 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
00764 iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
00765 iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
00766
00767 it = ao2_iterator_init(local_candidates, 0);
00768
00769 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00770 iks *local_candidate;
00771 char tmp[30];
00772
00773 if (!(local_candidate = iks_new("candidate"))) {
00774 res = -1;
00775 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
00776 break;
00777 }
00778
00779 snprintf(tmp, sizeof(tmp), "%d", candidate->id);
00780 iks_insert_attrib(local_candidate, "component", tmp);
00781 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
00782 iks_insert_attrib(local_candidate, "foundation", tmp);
00783 iks_insert_attrib(local_candidate, "generation", "0");
00784 iks_insert_attrib(local_candidate, "network", "0");
00785 snprintf(tmp, sizeof(tmp), "%04lx", ast_random() & 0xffff);
00786 iks_insert_attrib(local_candidate, "id", tmp);
00787 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
00788 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
00789 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
00790 iks_insert_attrib(local_candidate, "priority", tmp);
00791 iks_insert_attrib(local_candidate, "protocol", "udp");
00792
00793 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
00794 iks_insert_attrib(local_candidate, "type", "host");
00795 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
00796 iks_insert_attrib(local_candidate, "type", "srflx");
00797 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
00798 iks_insert_attrib(local_candidate, "type", "relay");
00799 }
00800
00801 iks_insert_node(transport, local_candidate);
00802 candidates[i++] = local_candidate;
00803 }
00804
00805 ao2_iterator_destroy(&it);
00806 ao2_ref(local_candidates, -1);
00807
00808 return res;
00809 }
00810
00811
00812 static int jingle_add_google_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int video, enum jingle_transport transport_type, unsigned int maximum)
00813 {
00814 struct ast_rtp_engine_ice *ice;
00815 struct ao2_container *local_candidates;
00816 struct ao2_iterator it;
00817 struct ast_rtp_engine_ice_candidate *candidate;
00818 int i = 0, res = 0;
00819
00820 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
00821 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
00822 return -1;
00823 }
00824
00825 if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
00826 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
00827 }
00828
00829 it = ao2_iterator_init(local_candidates, 0);
00830
00831 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
00832 iks *local_candidate;
00833
00834 char ufrag[17] = "";
00835
00836 if (!(local_candidate = iks_new("candidate"))) {
00837 res = -1;
00838 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
00839 break;
00840 }
00841
00842 if (candidate->id == 1) {
00843 iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
00844 } else if (candidate->id == 2) {
00845 iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
00846 } else {
00847 iks_delete(local_candidate);
00848 continue;
00849 }
00850
00851 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
00852 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
00853
00854 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
00855 iks_insert_attrib(local_candidate, "preference", "0.95");
00856 iks_insert_attrib(local_candidate, "type", "local");
00857 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
00858 iks_insert_attrib(local_candidate, "preference", "0.9");
00859 iks_insert_attrib(local_candidate, "type", "stun");
00860 }
00861
00862 iks_insert_attrib(local_candidate, "protocol", "udp");
00863 iks_insert_attrib(local_candidate, "network", "0");
00864 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
00865 iks_insert_attrib(local_candidate, "username", ufrag);
00866 iks_insert_attrib(local_candidate, "generation", "0");
00867
00868 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
00869 iks_insert_attrib(local_candidate, "password", "");
00870 iks_insert_attrib(local_candidate, "foundation", "0");
00871 iks_insert_attrib(local_candidate, "component", "1");
00872 } else {
00873 iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
00874 }
00875
00876
00877
00878
00879 iks_insert_node(transport, local_candidate);
00880 candidates[i++] = local_candidate;
00881 }
00882
00883 ao2_iterator_destroy(&it);
00884 ao2_ref(local_candidates, -1);
00885
00886 return res;
00887 }
00888
00889
00890 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
00891 {
00892 iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
00893
00894 if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
00895 !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
00896 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
00897 goto end;
00898 }
00899
00900 iks_insert_attrib(iq, "to", session->remote);
00901 iks_insert_attrib(iq, "type", "set");
00902 iks_insert_attrib(iq, "id", session->connection->mid);
00903 ast_xmpp_increment_mid(session->connection->mid);
00904
00905 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
00906 iks_insert_attrib(jingle, "type", "terminate");
00907 iks_insert_attrib(jingle, "id", session->sid);
00908 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
00909 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
00910 } else {
00911 iks_insert_attrib(jingle, "action", "session-terminate");
00912 iks_insert_attrib(jingle, "sid", session->sid);
00913 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
00914 }
00915
00916 iks_insert_node(iq, jingle);
00917 iks_insert_node(jingle, reason);
00918 iks_insert_node(reason, text);
00919
00920 ast_xmpp_client_send(session->connection, iq);
00921
00922 end:
00923 iks_delete(text);
00924 iks_delete(reason);
00925 iks_delete(jingle);
00926 iks_delete(iq);
00927 }
00928
00929
00930 static void jingle_send_session_info(struct jingle_session *session, const char *info)
00931 {
00932 iks *iq = NULL, *jingle = NULL, *text = NULL;
00933
00934
00935 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
00936 return;
00937 }
00938
00939 if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
00940 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
00941 goto end;
00942 }
00943
00944 iks_insert_attrib(iq, "to", session->remote);
00945 iks_insert_attrib(iq, "type", "set");
00946 iks_insert_attrib(iq, "id", session->connection->mid);
00947 ast_xmpp_increment_mid(session->connection->mid);
00948
00949 iks_insert_attrib(jingle, "action", "session-info");
00950 iks_insert_attrib(jingle, "sid", session->sid);
00951 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
00952 iks_insert_node(iq, jingle);
00953 iks_insert_node(jingle, text);
00954
00955 ast_xmpp_client_send(session->connection, iq);
00956
00957 end:
00958 iks_delete(text);
00959 iks_delete(jingle);
00960 iks_delete(iq);
00961 }
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
00981 {
00982 struct ast_channel *chan;
00983
00984
00985
00986
00987 for (;;) {
00988
00989 ao2_lock(pvt);
00990 chan = pvt->owner;
00991 if (chan) {
00992
00993
00994
00995 ast_channel_ref(chan);
00996 } else {
00997
00998 return NULL;
00999 }
01000
01001
01002
01003
01004 ao2_unlock(pvt);
01005
01006
01007 ast_channel_lock(chan);
01008 ao2_lock(pvt);
01009 if (pvt->owner == chan) {
01010
01011 break;
01012 }
01013
01014
01015
01016
01017
01018
01019 ast_channel_unlock(chan);
01020 ast_channel_unref(chan);
01021 ao2_unlock(pvt);
01022 }
01023
01024
01025 return pvt->owner;
01026 }
01027
01028
01029 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
01030 {
01031 struct ast_channel *chan;
01032
01033 if ((chan = jingle_session_lock_full(session))) {
01034 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
01035 ast_queue_hangup_with_cause(chan, cause);
01036 ast_channel_unlock(chan);
01037 ast_channel_unref(chan);
01038 }
01039 ao2_unlock(session);
01040 }
01041
01042
01043 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
01044 {
01045 iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
01046 iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
01047 int i, res = 0;
01048
01049 if (!(iq = iks_new("iq")) ||
01050 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01051 iks_delete(iq);
01052 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01053 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
01054 return;
01055 }
01056
01057 memset(audio_candidates, 0, sizeof(audio_candidates));
01058 memset(video_candidates, 0, sizeof(video_candidates));
01059
01060 iks_insert_attrib(iq, "from", session->connection->jid->full);
01061 iks_insert_attrib(iq, "to", from);
01062 iks_insert_attrib(iq, "type", "set");
01063 iks_insert_attrib(iq, "id", session->connection->mid);
01064 ast_xmpp_increment_mid(session->connection->mid);
01065
01066 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01067 iks_insert_attrib(jingle, "type", "candidates");
01068 iks_insert_attrib(jingle, "id", session->sid);
01069 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01070 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
01071 } else {
01072 iks_insert_attrib(jingle, "action", "transport-info");
01073 iks_insert_attrib(jingle, "sid", session->sid);
01074 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01075 }
01076 iks_insert_node(iq, jingle);
01077
01078 if (session->rtp) {
01079 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01080
01081 res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
01082 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
01083 iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
01084 iks_insert_attrib(audio, "name", session->audio_name);
01085 iks_insert_node(jingle, audio);
01086 iks_insert_node(audio, audio_transport);
01087
01088 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01089 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
01090 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01091 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
01092 session->maxicecandidates);
01093 }
01094 } else {
01095 res = -1;
01096 }
01097 }
01098
01099 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01100 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
01101 iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
01102 iks_insert_attrib(video, "name", session->video_name);
01103 iks_insert_node(jingle, video);
01104 iks_insert_node(video, video_transport);
01105
01106 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01107 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
01108 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01109 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
01110 session->maxicecandidates);
01111 }
01112 } else {
01113 res = -1;
01114 }
01115 }
01116
01117 if (!res) {
01118 ast_xmpp_client_send(session->connection, iq);
01119 } else {
01120 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01121 }
01122
01123
01124 for (i = 0; i < session->maxicecandidates; i++) {
01125 iks_delete(video_candidates[i]);
01126 iks_delete(audio_candidates[i]);
01127 }
01128
01129 iks_delete(video_transport);
01130 iks_delete(video);
01131 iks_delete(audio_transport);
01132 iks_delete(audio);
01133 iks_delete(jingle);
01134 iks_delete(iq);
01135 }
01136
01137
01138 static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type)
01139 {
01140 struct ast_format format;
01141 int x = 0, i = 0, res = 0;
01142
01143 for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
01144 int rtp_code;
01145 iks *payload;
01146 char tmp[32];
01147
01148 if (!ast_codec_pref_index(&session->prefs, x, &format)) {
01149 break;
01150 }
01151
01152 if (AST_FORMAT_GET_TYPE(format.id) != type) {
01153 continue;
01154 }
01155
01156 if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
01157 continue;
01158 }
01159
01160 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
01161 (!(payload = iks_new("payload-type")))) {
01162 return -1;
01163 }
01164
01165 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01166 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01167 }
01168
01169 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
01170 iks_insert_attrib(payload, "id", tmp);
01171 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
01172 iks_insert_attrib(payload, "channels", "1");
01173
01174 if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
01175 iks_insert_attrib(payload, "clockrate", "16000");
01176 } else {
01177 snprintf(tmp, sizeof(tmp), "%d", ast_rtp_lookup_sample_rate2(1, &format, 0));
01178 iks_insert_attrib(payload, "clockrate", tmp);
01179 }
01180
01181 if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
01182 iks *parameter;
01183
01184
01185 if ((parameter = iks_new("parameter"))) {
01186 iks_insert_attrib(parameter, "name", "width");
01187 iks_insert_attrib(parameter, "value", "640");
01188 iks_insert_node(payload, parameter);
01189 }
01190 if ((parameter = iks_new("parameter"))) {
01191 iks_insert_attrib(parameter, "name", "height");
01192 iks_insert_attrib(parameter, "value", "480");
01193 iks_insert_node(payload, parameter);
01194 }
01195 if ((parameter = iks_new("parameter"))) {
01196 iks_insert_attrib(parameter, "name", "framerate");
01197 iks_insert_attrib(parameter, "value", "30");
01198 iks_insert_node(payload, parameter);
01199 }
01200 }
01201
01202 iks_insert_node(description, payload);
01203 payloads[i++] = payload;
01204 }
01205
01206 if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
01207 iks *payload;
01208
01209 if ((payload = iks_new("payload-type"))) {
01210 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01211 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
01212 }
01213
01214 iks_insert_attrib(payload, "id", "101");
01215 iks_insert_attrib(payload, "name", "telephone-event");
01216 iks_insert_attrib(payload, "channels", "1");
01217 iks_insert_attrib(payload, "clockrate", "8000");
01218 iks_insert_node(description, payload);
01219 payloads[i++] = payload;
01220 }
01221 }
01222
01223 return res;
01224 }
01225
01226
01227 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
01228 const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
01229 {
01230 int res = 0;
01231
01232 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
01233 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
01234 iks_insert_attrib(content, "name", name);
01235 iks_insert_node(jingle, content);
01236
01237 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
01238 if (type == AST_FORMAT_TYPE_AUDIO) {
01239 iks_insert_attrib(description, "media", "audio");
01240 } else if (type == AST_FORMAT_TYPE_VIDEO) {
01241 iks_insert_attrib(description, "media", "video");
01242 } else {
01243 return -1;
01244 }
01245 iks_insert_node(content, description);
01246 } else {
01247 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
01248 iks_insert_node(jingle, description);
01249 }
01250
01251 if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
01252 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
01253 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
01254 iks_insert_node(content, transport);
01255 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
01256 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
01257 iks_insert_node(content, transport);
01258 }
01259 }
01260
01261 return res;
01262 }
01263
01264
01265 static void jingle_send_session_action(struct jingle_session *session, const char *action)
01266 {
01267 iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
01268 iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
01269 iks *audio_transport = NULL, *video_transport = NULL;
01270 int i, res = 0;
01271
01272 if (!(iq = iks_new("iq")) ||
01273 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
01274 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01275 iks_delete(iq);
01276 return;
01277 }
01278
01279 memset(audio_payloads, 0, sizeof(audio_payloads));
01280 memset(video_payloads, 0, sizeof(video_payloads));
01281
01282 iks_insert_attrib(iq, "from", session->connection->jid->full);
01283 iks_insert_attrib(iq, "to", session->remote);
01284 iks_insert_attrib(iq, "type", "set");
01285 iks_insert_attrib(iq, "id", session->connection->mid);
01286 ast_xmpp_increment_mid(session->connection->mid);
01287
01288 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01289 iks_insert_attrib(jingle, "type", action);
01290 iks_insert_attrib(jingle, "id", session->sid);
01291 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
01292 } else {
01293 iks_insert_attrib(jingle, "action", action);
01294 iks_insert_attrib(jingle, "sid", session->sid);
01295 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
01296 }
01297
01298 if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
01299 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
01300 }
01301
01302 iks_insert_node(iq, jingle);
01303
01304 if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
01305 (audio_transport = iks_new("transport"))) {
01306 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
01307 AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
01308 } else {
01309 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
01310 res = -1;
01311 }
01312
01313 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
01314 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
01315 (video_transport = iks_new("transport"))) {
01316 res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
01317 AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
01318 } else {
01319 ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
01320 res = -1;
01321 }
01322 }
01323
01324 if (!res) {
01325 ast_xmpp_client_send(session->connection, iq);
01326 } else {
01327 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01328 }
01329
01330 iks_delete(video_transport);
01331 iks_delete(audio_transport);
01332
01333 for (i = 0; i < session->maxpayloads; i++) {
01334 iks_delete(video_payloads[i]);
01335 iks_delete(audio_payloads[i]);
01336 }
01337
01338 iks_delete(video_description);
01339 iks_delete(video);
01340 iks_delete(audio_description);
01341 iks_delete(audio);
01342 iks_delete(jingle);
01343 iks_delete(iq);
01344 }
01345
01346
01347 static void jingle_send_session_initiate(struct jingle_session *session)
01348 {
01349 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
01350 }
01351
01352
01353 static void jingle_send_session_accept(struct jingle_session *session)
01354 {
01355 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
01356 }
01357
01358
01359 static int jingle_outgoing_hook(void *data, ikspak *pak)
01360 {
01361 struct jingle_session *session = data;
01362 iks *error = iks_find(pak->x, "error"), *redirect;
01363
01364
01365 iks_filter_remove_rule(session->connection->filter, session->rule);
01366 session->rule = NULL;
01367
01368 ast_callid_threadassoc_add(session->callid);
01369
01370
01371 if (!error) {
01372 struct ast_channel *chan;
01373
01374 if ((chan = jingle_session_lock_full(session))) {
01375 ast_queue_control(chan, AST_CONTROL_PROCEEDING);
01376 ast_channel_unlock(chan);
01377 ast_channel_unref(chan);
01378 }
01379 ao2_unlock(session);
01380
01381 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
01382
01383 goto end;
01384 }
01385
01386
01387 session->gone = 1;
01388
01389
01390 if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
01391 iks *to = iks_child(redirect);
01392 char *target;
01393
01394 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
01395
01396 if (!strncmp(target, "xmpp:", 5)) {
01397 target += 5;
01398 }
01399
01400
01401 ast_copy_string(session->remote, target, sizeof(session->remote));
01402
01403
01404 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01405 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01406
01407 jingle_send_session_initiate(session);
01408
01409 session->gone = 0;
01410 } else {
01411 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01412 }
01413 } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
01414 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
01415 } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
01416 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
01417 } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
01418 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01419 } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
01420 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
01421 } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
01422
01423 session->transport--;
01424
01425
01426 if (session->transport != JINGLE_TRANSPORT_NONE) {
01427 struct ast_rtp_engine_ice *ice;
01428
01429 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
01430 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
01431 (ice = ast_rtp_instance_get_ice(session->rtp))) {
01432
01433 ice->stop(session->rtp);
01434 }
01435
01436
01437 ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
01438
01439 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01440 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01441
01442 jingle_send_session_initiate(session);
01443
01444 session->gone = 0;
01445 } else {
01446
01447 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
01448 }
01449 } else {
01450 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01451 }
01452
01453 end:
01454 ast_callid_threadassoc_remove();
01455
01456 return IKS_FILTER_EAT;
01457 }
01458
01459
01460 static int jingle_answer(struct ast_channel *ast)
01461 {
01462 struct jingle_session *session = ast_channel_tech_pvt(ast);
01463
01464
01465 if (ast_channel_state(ast) == AST_STATE_UP) {
01466 return 0;
01467 }
01468
01469 jingle_send_session_accept(session);
01470
01471 return 0;
01472 }
01473
01474
01475 static struct ast_frame *jingle_read(struct ast_channel *ast)
01476 {
01477 struct jingle_session *session = ast_channel_tech_pvt(ast);
01478 struct ast_frame *frame = &ast_null_frame;
01479
01480 switch (ast_channel_fdno(ast)) {
01481 case 0:
01482 if (session->rtp) {
01483 frame = ast_rtp_instance_read(session->rtp, 0);
01484 }
01485 break;
01486 case 1:
01487 if (session->rtp) {
01488 frame = ast_rtp_instance_read(session->rtp, 1);
01489 }
01490 break;
01491 case 2:
01492 if (session->vrtp) {
01493 frame = ast_rtp_instance_read(session->vrtp, 0);
01494 }
01495 break;
01496 case 3:
01497 if (session->vrtp) {
01498 frame = ast_rtp_instance_read(session->vrtp, 1);
01499 }
01500 break;
01501 default:
01502 break;
01503 }
01504
01505 if (frame && frame->frametype == AST_FRAME_VOICE &&
01506 !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
01507 if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
01508 ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
01509 ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
01510 ast_frfree(frame);
01511 frame = &ast_null_frame;
01512 } else {
01513 ast_debug(1, "Oooh, format changed to %s\n",
01514 ast_getformatname(&frame->subclass.format));
01515 ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
01516 ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
01517 ast_set_read_format(ast, ast_channel_readformat(ast));
01518 ast_set_write_format(ast, ast_channel_writeformat(ast));
01519 }
01520 }
01521
01522 return frame;
01523 }
01524
01525
01526 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
01527 {
01528 struct jingle_session *session = ast_channel_tech_pvt(ast);
01529 int res = 0;
01530 char buf[256];
01531
01532 switch (frame->frametype) {
01533 case AST_FRAME_VOICE:
01534 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
01535 ast_log(LOG_WARNING,
01536 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01537 ast_getformatname(&frame->subclass.format),
01538 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
01539 ast_getformatname(ast_channel_readformat(ast)),
01540 ast_getformatname(ast_channel_writeformat(ast)));
01541 return 0;
01542 }
01543 if (session && session->rtp) {
01544 res = ast_rtp_instance_write(session->rtp, frame);
01545 }
01546 break;
01547 case AST_FRAME_VIDEO:
01548 if (session && session->vrtp) {
01549 res = ast_rtp_instance_write(session->vrtp, frame);
01550 }
01551 break;
01552 default:
01553 ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
01554 frame->frametype);
01555 return 0;
01556 }
01557
01558 return res;
01559 }
01560
01561
01562 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01563 {
01564 struct jingle_session *session = ast_channel_tech_pvt(newchan);
01565
01566 ao2_lock(session);
01567
01568 session->owner = newchan;
01569
01570 ao2_unlock(session);
01571
01572 return 0;
01573 }
01574
01575
01576 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
01577 {
01578 struct jingle_session *session = ast_channel_tech_pvt(ast);
01579 int res = 0;
01580
01581 switch (condition) {
01582 case AST_CONTROL_RINGING:
01583 if (ast_channel_state(ast) == AST_STATE_RING) {
01584 jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
01585 } else {
01586 res = -1;
01587 }
01588 break;
01589 case AST_CONTROL_BUSY:
01590 if (ast_channel_state(ast) != AST_STATE_UP) {
01591 ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
01592 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01593 } else {
01594 res = -1;
01595 }
01596 break;
01597 case AST_CONTROL_CONGESTION:
01598 if (ast_channel_state(ast) != AST_STATE_UP) {
01599 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01600 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01601 } else {
01602 res = -1;
01603 }
01604 break;
01605 case AST_CONTROL_INCOMPLETE:
01606 if (ast_channel_state(ast) != AST_STATE_UP) {
01607 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
01608 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
01609 }
01610 break;
01611 case AST_CONTROL_HOLD:
01612 ast_moh_start(ast, data, NULL);
01613 break;
01614 case AST_CONTROL_UNHOLD:
01615 ast_moh_stop(ast);
01616 break;
01617 case AST_CONTROL_SRCUPDATE:
01618 if (session->rtp) {
01619 ast_rtp_instance_update_source(session->rtp);
01620 }
01621 break;
01622 case AST_CONTROL_SRCCHANGE:
01623 if (session->rtp) {
01624 ast_rtp_instance_change_source(session->rtp);
01625 }
01626 break;
01627 case AST_CONTROL_VIDUPDATE:
01628 case AST_CONTROL_UPDATE_RTP_PEER:
01629 case AST_CONTROL_CONNECTED_LINE:
01630 break;
01631 case AST_CONTROL_PVT_CAUSE_CODE:
01632 case -1:
01633 res = -1;
01634 break;
01635 default:
01636 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
01637 res = -1;
01638 }
01639
01640 return res;
01641 }
01642
01643
01644 static int jingle_sendtext(struct ast_channel *chan, const char *text)
01645 {
01646 struct jingle_session *session = ast_channel_tech_pvt(chan);
01647
01648 return ast_xmpp_client_send_message(session->connection, session->remote, text);
01649 }
01650
01651
01652 static int jingle_digit_begin(struct ast_channel *chan, char digit)
01653 {
01654 struct jingle_session *session = ast_channel_tech_pvt(chan);
01655
01656 if (session->rtp) {
01657 ast_rtp_instance_dtmf_begin(session->rtp, digit);
01658 }
01659
01660 return 0;
01661 }
01662
01663
01664 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
01665 {
01666 struct jingle_session *session = ast_channel_tech_pvt(ast);
01667
01668 if (session->rtp) {
01669 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
01670 }
01671
01672 return 0;
01673 }
01674
01675
01676 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
01677 {
01678 struct jingle_session *session = ast_channel_tech_pvt(ast);
01679
01680 ast_setstate(ast, AST_STATE_RING);
01681
01682
01683 ast_format_cap_copy(session->jointcap, session->cap);
01684
01685
01686 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
01687 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
01688
01689 jingle_send_session_initiate(session);
01690
01691 return 0;
01692 }
01693
01694
01695 static int jingle_hangup(struct ast_channel *ast)
01696 {
01697 struct jingle_session *session = ast_channel_tech_pvt(ast);
01698
01699 ao2_lock(session);
01700
01701 if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
01702 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
01703 const char *reason = "success";
01704 int i;
01705
01706
01707 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
01708 if (jingle_reason_mappings[i].cause == cause) {
01709 reason = jingle_reason_mappings[i].reason;
01710 break;
01711 }
01712 }
01713
01714 jingle_send_session_terminate(session, reason);
01715 }
01716
01717 ast_channel_tech_pvt_set(ast, NULL);
01718 session->owner = NULL;
01719
01720 ao2_unlink(session->state->sessions, session);
01721 ao2_ref(session->state, -1);
01722
01723 ao2_unlock(session);
01724 ao2_ref(session, -1);
01725
01726 return 0;
01727 }
01728
01729
01730 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
01731 {
01732 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
01733 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
01734 char *dialed, target[200] = "";
01735 struct ast_xmpp_buddy *buddy;
01736 struct jingle_session *session;
01737 struct ast_channel *chan;
01738 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
01739 struct ast_rtp_engine_ice *ice;
01740 AST_DECLARE_APP_ARGS(args,
01741 AST_APP_ARG(name);
01742 AST_APP_ARG(target);
01743 );
01744
01745
01746 if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
01747 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
01748 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
01749 return NULL;
01750 }
01751
01752 if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
01753 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
01754 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01755 return NULL;
01756 }
01757
01758
01759 AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
01760
01761 if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
01762 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
01763 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01764 return NULL;
01765 }
01766
01767 if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
01768 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
01769 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
01770 return NULL;
01771 }
01772
01773 ao2_lock(endpoint->state);
01774
01775
01776 if (!endpoint->connection) {
01777 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
01778 *cause = AST_CAUSE_SWITCH_CONGESTION;
01779 ao2_unlock(endpoint->state);
01780 return NULL;
01781 }
01782
01783
01784 if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
01785 struct ao2_iterator res;
01786 struct ast_xmpp_resource *resource;
01787
01788
01789 res = ao2_iterator_init(buddy->resources, 0);
01790 while ((resource = ao2_iterator_next(&res))) {
01791 if (resource->caps.jingle) {
01792 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01793 transport = JINGLE_TRANSPORT_ICE_UDP;
01794 break;
01795 } else if (resource->caps.google) {
01796 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
01797 transport = JINGLE_TRANSPORT_GOOGLE_V2;
01798 break;
01799 }
01800 ao2_ref(resource, -1);
01801 }
01802 ao2_iterator_destroy(&res);
01803
01804 ao2_ref(buddy, -1);
01805 } else {
01806
01807 ast_copy_string(target, args.target, sizeof(target));
01808 }
01809
01810 ao2_unlock(endpoint->state);
01811
01812
01813 if (ast_strlen_zero(target)) {
01814 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no capable resource for target '%s' was found\n", args.name, args.target);
01815 *cause = AST_CAUSE_SWITCH_CONGESTION;
01816 return NULL;
01817 }
01818
01819 if (!(session = jingle_alloc(endpoint, target, NULL))) {
01820 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
01821 *cause = AST_CAUSE_SWITCH_CONGESTION;
01822 return NULL;
01823 }
01824
01825
01826 if (transport != JINGLE_TRANSPORT_NONE) {
01827 session->transport = transport;
01828
01829 }
01830
01831 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
01832 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
01833 *cause = AST_CAUSE_SWITCH_CONGESTION;
01834 ao2_ref(session, -1);
01835 return NULL;
01836 }
01837
01838
01839 if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
01840 jingle_enable_video(session);
01841 }
01842
01843
01844 if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
01845 ice->ice_lite(session->rtp);
01846 }
01847
01848 if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
01849 ice->ice_lite(session->vrtp);
01850 }
01851
01852
01853 ao2_link(endpoint->state->sessions, session);
01854
01855 return chan;
01856 }
01857
01858
01859 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
01860 {
01861 char *media = iks_find_attrib(description, "media");
01862 struct ast_rtp_codecs codecs;
01863 iks *codec;
01864 int othercapability = 0;
01865
01866
01867 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
01868 media = "audio";
01869 } else if (ast_strlen_zero(media)) {
01870 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01871 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
01872 return -1;
01873 }
01874
01875
01876 if (!strcasecmp(media, "audio")) {
01877 if (!ast_strlen_zero(name)) {
01878 ast_string_field_set(session, audio_name, name);
01879 }
01880 *rtp = session->rtp;
01881 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
01882 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
01883 } else if (!strcasecmp(media, "video")) {
01884 if (!ast_strlen_zero(name)) {
01885 ast_string_field_set(session, video_name, name);
01886 }
01887
01888 jingle_enable_video(session);
01889 *rtp = session->vrtp;
01890
01891
01892 if (!session->vrtp) {
01893 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01894 ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
01895 return -1;
01896 }
01897
01898 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
01899 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
01900 } else {
01901
01902 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01903 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
01904 return -1;
01905 }
01906
01907 if (ast_rtp_codecs_payloads_initialize(&codecs)) {
01908 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01909 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
01910 return -1;
01911 }
01912
01913
01914 for (codec = iks_child(description); codec; codec = iks_next(codec)) {
01915 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
01916 char *clockrate = iks_find_attrib(codec, "clockrate");
01917 int rtp_id, rtp_clockrate;
01918
01919 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
01920 ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
01921
01922 if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
01923 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
01924 } else {
01925 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
01926 }
01927 }
01928 }
01929
01930 ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
01931 ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
01932
01933 if (ast_format_cap_is_empty(session->jointcap)) {
01934
01935 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
01936 ast_rtp_codecs_payloads_destroy(&codecs);
01937 return -1;
01938 }
01939
01940 ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
01941 ast_rtp_codecs_payloads_destroy(&codecs);
01942
01943 return 0;
01944 }
01945
01946
01947 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
01948 {
01949 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
01950 char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
01951 iks *candidate;
01952
01953 if (!ice) {
01954 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
01955 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
01956 return -1;
01957 }
01958
01959 if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
01960 ice->set_authentication(rtp, ufrag, pwd);
01961 }
01962
01963 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
01964 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
01965 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
01966 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
01967 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
01968 char *type = iks_find_attrib(candidate, "type");
01969 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
01970 int real_port;
01971 struct ast_sockaddr remote_address = { { 0, } };
01972
01973
01974 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
01975 ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
01976 ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
01977 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01978 ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
01979 return -1;
01980 }
01981
01982 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
01983 (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
01984 (sscanf(port, "%30d", &real_port) != 1)) {
01985 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
01986 ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
01987 return -1;
01988 }
01989
01990 local_candidate.foundation = foundation;
01991 local_candidate.transport = protocol;
01992
01993 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
01994
01995
01996 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
01997 continue;
01998 }
01999
02000 ast_sockaddr_set_port(&local_candidate.address, real_port);
02001
02002 if (!strcasecmp(type, "host")) {
02003 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
02004 } else if (!strcasecmp(type, "srflx")) {
02005 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
02006 } else if (!strcasecmp(type, "relay")) {
02007 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
02008 } else {
02009 continue;
02010 }
02011
02012
02013 ast_rtp_instance_get_remote_address(rtp, &remote_address);
02014
02015 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
02016 ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
02017 }
02018
02019 ice->add_remote_candidate(rtp, &local_candidate);
02020 }
02021
02022 ice->start(rtp);
02023
02024 return 0;
02025 }
02026
02027
02028 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
02029 {
02030 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
02031 iks *candidate;
02032
02033 if (!ice) {
02034 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02035 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
02036 return -1;
02037 }
02038
02039
02040 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
02041 (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
02042
02043 ice->stop(rtp);
02044
02045 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02046 }
02047
02048 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
02049 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
02050 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
02051 char *protocol = iks_find_attrib(candidate, "protocol");
02052 int real_port;
02053 struct ast_sockaddr target = { { 0, } };
02054
02055 char combined[33] = "";
02056
02057
02058 if (strcasecmp(iks_name(candidate), "candidate") &&
02059 strcasecmp(iks_name(candidate), "p:candidate") &&
02060 strcasecmp(iks_name(candidate), "ses:candidate")) {
02061 continue;
02062 }
02063
02064
02065 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
02066 ast_strlen_zero(name)) {
02067 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02068 ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
02069 return -1;
02070 }
02071
02072
02073 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
02074 continue;
02075 }
02076
02077
02078 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
02079 continue;
02080 }
02081
02082
02083 if (sscanf(port, "%30d", &real_port) != 1) {
02084 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
02085 ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
02086 return -1;
02087 }
02088 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
02089 ast_sockaddr_set_port(&target, real_port);
02090
02091
02092 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
02093
02094
02095 ast_rtp_instance_stun_request(rtp, &target, combined);
02096 }
02097
02098 return 0;
02099 }
02100
02101
02102
02103
02104
02105
02106 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
02107 {
02108 iks *content;
02109 unsigned int changed = 0;
02110 struct ast_channel *chan;
02111
02112
02113 for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
02114 char *name;
02115 struct ast_rtp_instance *rtp = NULL;
02116 iks *description, *transport;
02117
02118
02119 if (!strcmp(iks_name(content), "conference-info")) {
02120 continue;
02121 }
02122
02123 name = iks_find_attrib(content, "name");
02124
02125 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
02126
02127 if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
02128 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
02129 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
02130 return -1;
02131 }
02132
02133
02134 if (!strcmp(session->audio_name, name)) {
02135 rtp = session->rtp;
02136 } else if (!strcmp(session->video_name, name)) {
02137 rtp = session->vrtp;
02138 }
02139 } else {
02140
02141 rtp = session->rtp;
02142 }
02143
02144
02145 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
02146 (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
02147 (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02148 (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
02149 (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
02150 (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
02151
02152 if (jingle_interpret_description(session, description, name, &rtp)) {
02153 return -1;
02154 }
02155
02156
02157 changed = 1;
02158 }
02159
02160
02161 if (!rtp) {
02162 ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
02163 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
02164 return -1;
02165 }
02166
02167
02168 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
02169 if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
02170 return -1;
02171 }
02172 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
02173 (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
02174 (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
02175 (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
02176
02177 if (jingle_interpret_google_transport(session, transport, rtp)) {
02178 return -1;
02179 }
02180 } else if (iks_find(content, "transport")) {
02181
02182 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
02183 ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
02184 return -1;
02185 }
02186 }
02187
02188 if (!changed) {
02189 return 0;
02190 }
02191
02192 if ((chan = jingle_session_lock_full(session))) {
02193 struct ast_format fmt;
02194
02195 ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
02196 ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
02197 ast_set_read_format(chan, &fmt);
02198 ast_set_write_format(chan, &fmt);
02199
02200 ast_channel_unlock(chan);
02201 ast_channel_unref(chan);
02202 }
02203 ao2_unlock(session);
02204
02205 return 0;
02206 }
02207
02208
02209 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02210 {
02211 char *sid;
02212 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
02213 struct ast_channel *chan;
02214 int res;
02215
02216 if (session) {
02217
02218 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
02219 return;
02220 }
02221
02222
02223 if ((sid = iks_find_attrib(pak->query, "id"))) {
02224
02225 transport = JINGLE_TRANSPORT_GOOGLE_V1;
02226 } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02227 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
02228 return;
02229 }
02230
02231
02232 if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
02233 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02234 return;
02235 }
02236
02237
02238 if (transport != JINGLE_TRANSPORT_NONE) {
02239 session->transport = transport;
02240 }
02241
02242
02243 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
02244 ao2_ref(session, -1);
02245 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02246 return;
02247 }
02248
02249 ao2_link(endpoint->state->sessions, session);
02250
02251 ast_setstate(chan, AST_STATE_RING);
02252 res = ast_pbx_start(chan);
02253
02254 switch (res) {
02255 case AST_PBX_FAILED:
02256 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
02257 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02258 session->gone = 1;
02259 ast_hangup(chan);
02260 break;
02261 case AST_PBX_CALL_LIMIT:
02262 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
02263 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
02264 ast_hangup(chan);
02265 break;
02266 case AST_PBX_SUCCESS:
02267 jingle_send_response(endpoint->connection, pak);
02268
02269
02270 if (!jingle_interpret_content(session, pak)) {
02271 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
02272 }
02273 break;
02274 }
02275 }
02276
02277
02278 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02279 {
02280 if (!session) {
02281 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02282 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02283 return;
02284 }
02285
02286 jingle_interpret_content(session, pak);
02287 jingle_send_response(endpoint->connection, pak);
02288 }
02289
02290
02291 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02292 {
02293 struct ast_channel *chan;
02294
02295 if (!session) {
02296 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02297 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02298 return;
02299 }
02300
02301
02302 jingle_interpret_content(session, pak);
02303
02304 if ((chan = jingle_session_lock_full(session))) {
02305 ast_queue_control(chan, AST_CONTROL_ANSWER);
02306 ast_channel_unlock(chan);
02307 ast_channel_unref(chan);
02308 }
02309 ao2_unlock(session);
02310
02311 jingle_send_response(endpoint->connection, pak);
02312 }
02313
02314
02315 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02316 {
02317 struct ast_channel *chan;
02318
02319 if (!session) {
02320 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02321 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02322 return;
02323 }
02324
02325 if (!(chan = jingle_session_lock_full(session))) {
02326 ao2_unlock(session);
02327 jingle_send_response(endpoint->connection, pak);
02328 return;
02329 }
02330
02331 if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
02332 ast_queue_control(chan, AST_CONTROL_RINGING);
02333 if (ast_channel_state(chan) != AST_STATE_UP) {
02334 ast_setstate(chan, AST_STATE_RINGING);
02335 }
02336 } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
02337 ast_queue_control(chan, AST_CONTROL_HOLD);
02338 } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
02339 ast_queue_control(chan, AST_CONTROL_UNHOLD);
02340 }
02341
02342 ast_channel_unlock(chan);
02343 ast_channel_unref(chan);
02344 ao2_unlock(session);
02345
02346 jingle_send_response(endpoint->connection, pak);
02347 }
02348
02349
02350 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
02351 {
02352 struct ast_channel *chan;
02353 iks *reason, *text;
02354 int cause = AST_CAUSE_NORMAL;
02355 struct ast_control_pvt_cause_code *cause_code;
02356 int data_size = sizeof(*cause_code);
02357
02358 if (!session) {
02359 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
02360 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
02361 return;
02362 }
02363
02364 if (!(chan = jingle_session_lock_full(session))) {
02365 ao2_unlock(session);
02366 jingle_send_response(endpoint->connection, pak);
02367 return;
02368 }
02369
02370
02371 if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
02372 int i;
02373
02374
02375 data_size += 6 + strlen(iks_name(text));
02376 cause_code = ast_alloca(data_size);
02377 memset(cause_code, 0, data_size);
02378
02379
02380 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
02381 if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
02382 cause = jingle_reason_mappings[i].cause;
02383 break;
02384 }
02385 }
02386
02387
02388 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
02389 } else {
02390
02391 cause_code = ast_alloca(data_size);
02392 memset(cause_code, 0, data_size);
02393 }
02394
02395 ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
02396 cause_code->ast_cause = cause;
02397 ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
02398 ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
02399
02400 ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
02401 ast_queue_hangup_with_cause(chan, cause);
02402 session->gone = 1;
02403
02404 ast_channel_unlock(chan);
02405 ast_channel_unref(chan);
02406 ao2_unlock(session);
02407
02408 jingle_send_response(endpoint->connection, pak);
02409 }
02410
02411
02412 static int jingle_action_hook(void *data, ikspak *pak)
02413 {
02414 char *action;
02415 const char *sid = NULL;
02416 struct jingle_session *session = NULL;
02417 struct jingle_endpoint *endpoint = data;
02418 int i, handled = 0;
02419
02420
02421 if (!(action = iks_find_attrib(pak->query, "action")) &&
02422 !(action = iks_find_attrib(pak->query, "type"))) {
02423
02424
02425 return IKS_FILTER_EAT;
02426 }
02427
02428
02429
02430 ao2_ref(endpoint, +1);
02431
02432
02433 if (!(sid = iks_find_attrib(pak->query, "sid"))) {
02434
02435 sid = iks_find_attrib(pak->query, "id");
02436 }
02437
02438
02439
02440 if (!ast_strlen_zero(sid)) {
02441 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
02442 }
02443
02444
02445 if (session) {
02446 ast_callid_threadassoc_add(session->callid);
02447 }
02448
02449
02450 for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
02451 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
02452 jingle_action_handlers[i].handler(endpoint, session, pak);
02453 handled = 1;
02454 break;
02455 }
02456 }
02457
02458
02459 if (!handled) {
02460 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
02461 }
02462
02463
02464 if (session) {
02465 ast_callid_threadassoc_remove();
02466 ao2_ref(session, -1);
02467 }
02468
02469 ao2_ref(endpoint, -1);
02470
02471 return IKS_FILTER_EAT;
02472 }
02473
02474
02475 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02476 {
02477 struct jingle_endpoint *endpoint = obj;
02478
02479 if (!strcasecmp(var->name, "callgroup")) {
02480 endpoint->callgroup = ast_get_group(var->value);
02481 } else if (!strcasecmp(var->name, "pickupgroup")) {
02482 endpoint->pickupgroup = ast_get_group(var->value);
02483 } else {
02484 return -1;
02485 }
02486
02487 return 0;
02488 }
02489
02490
02491 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02492 {
02493 struct jingle_endpoint *endpoint = obj;
02494
02495
02496
02497
02498 if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
02499 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
02500 return -1;
02501 }
02502
02503 if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
02504 IKS_RULE_TYPE, IKS_PAK_IQ,
02505 IKS_RULE_NS, JINGLE_NS,
02506 IKS_RULE_NS, GOOGLE_SESSION_NS,
02507 IKS_RULE_DONE))) {
02508 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
02509 return -1;
02510 }
02511
02512 return 0;
02513 }
02514
02515
02516 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
02517 {
02518 struct jingle_endpoint *endpoint = obj;
02519
02520 if (!strcasecmp(var->value, "ice-udp")) {
02521 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02522 } else if (!strcasecmp(var->value, "google")) {
02523 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
02524 } else if (!strcasecmp(var->value, "google-v1")) {
02525 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
02526 } else {
02527 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
02528 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
02529 }
02530
02531 return 0;
02532 }
02533
02534
02535 static int load_module(void)
02536 {
02537 if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
02538 return AST_MODULE_LOAD_DECLINE;
02539 }
02540
02541 if (aco_info_init(&cfg_info)) {
02542 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
02543 goto end;
02544 }
02545
02546 aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
02547 aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02548 aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
02549 aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
02550 aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
02551 aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
02552 aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
02553 aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
02554 aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
02555 aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
02556 aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
02557 aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
02558 FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
02559 aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
02560 FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
02561
02562 ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
02563
02564 if (aco_process_config(&cfg_info, 0)) {
02565 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Not loading module.\n");
02566 aco_info_destroy(&cfg_info);
02567 return AST_MODULE_LOAD_DECLINE;
02568 }
02569
02570 if (!(sched = ast_sched_context_create())) {
02571 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
02572 goto end;
02573 }
02574
02575 if (ast_sched_start_thread(sched)) {
02576 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
02577 goto end;
02578 }
02579
02580 ast_rtp_glue_register(&jingle_rtp_glue);
02581
02582 if (ast_channel_register(&jingle_tech)) {
02583 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
02584 goto end;
02585 }
02586
02587 return 0;
02588
02589 end:
02590 ast_rtp_glue_unregister(&jingle_rtp_glue);
02591
02592 if (sched) {
02593 ast_sched_context_destroy(sched);
02594 }
02595
02596 aco_info_destroy(&cfg_info);
02597
02598 return AST_MODULE_LOAD_FAILURE;
02599 }
02600
02601
02602 static int reload(void)
02603 {
02604 return aco_process_config(&cfg_info, 1);
02605 }
02606
02607
02608 static int unload_module(void)
02609 {
02610 ast_channel_unregister(&jingle_tech);
02611 ast_format_cap_destroy(jingle_tech.capabilities);
02612 jingle_tech.capabilities = NULL;
02613 ast_rtp_glue_unregister(&jingle_rtp_glue);
02614 ast_sched_context_destroy(sched);
02615 aco_info_destroy(&cfg_info);
02616 ao2_global_obj_release(globals);
02617
02618 return 0;
02619 }
02620
02621 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
02622 .load = load_module,
02623 .unload = unload_module,
02624 .reload = reload,
02625 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
02626 );