2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \author Joshua Colp <jcolp@digium.com>
23 * \brief Motif Jingle Channel Driver
25 * Iksemel http://iksemel.jabberstudio.org/
27 * \ingroup channel_drivers
30 /*! \li \ref chan_motif.c uses the configuration file \ref motif.conf
31 * \addtogroup configuration_file
34 /*! \page motif.conf motif.conf
35 * \verbinclude motif.conf.sample
39 <depend>iksemel</depend>
40 <depend>res_xmpp</depend>
41 <use type="external">openssl</use>
42 <support_level>core</support_level>
47 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <sys/signal.h>
58 #include "asterisk/lock.h"
59 #include "asterisk/channel.h"
60 #include "asterisk/config_options.h"
61 #include "asterisk/module.h"
62 #include "asterisk/pbx.h"
63 #include "asterisk/sched.h"
64 #include "asterisk/io.h"
65 #include "asterisk/rtp_engine.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/callerid.h"
68 #include "asterisk/file.h"
69 #include "asterisk/cli.h"
70 #include "asterisk/app.h"
71 #include "asterisk/musiconhold.h"
72 #include "asterisk/manager.h"
73 #include "asterisk/stringfields.h"
74 #include "asterisk/utils.h"
75 #include "asterisk/causes.h"
76 #include "asterisk/astobj.h"
77 #include "asterisk/abstract_jb.h"
78 #include "asterisk/xmpp.h"
81 <configInfo name="chan_motif" language="en_US">
82 <synopsis>Jingle Channel Driver</synopsis>
84 <para><emphasis>Transports</emphasis></para>
85 <para>There are three different transports and protocol derivatives
86 supported by <literal>chan_motif</literal>. They are in order of
87 preference: Jingle using ICE-UDP, Google Jingle, and Google-V1.</para>
88 <para>Jingle as defined in XEP-0166 supports the widest range of
89 features. It is referred to as <literal>ice-udp</literal>. This is
90 the specification that Jingle clients implement.</para>
91 <para>Google Jingle follows the Jingle specification for signaling
92 but uses a custom transport for media. It is supported by the
93 Google Talk Plug-in in Gmail and by some other Jingle clients. It
94 is referred to as <literal>google</literal> in this file.</para>
95 <para>Google-V1 is the original Google Talk signaling protocol
96 which uses an initial preliminary version of Jingle. It also uses
97 the same custom transport as Google Jingle for media. It is
98 supported by Google Voice, some other Jingle clients, and the
99 Windows Google Talk client. It is referred to as <literal>google-v1</literal>
101 <para>Incoming sessions will automatically switch to the correct
102 transport once it has been determined.</para>
103 <para>Outgoing sessions are capable of determining if the target
104 is capable of Jingle or a Google transport if the target is in the
105 roster. Unfortunately it is not possible to differentiate between
106 a Google Jingle or Google-V1 capable resource until a session
107 initiate attempt occurs. If a resource is determined to use a
108 Google transport it will initially use Google Jingle but will fall
109 back to Google-V1 if required.</para>
110 <para>If an outgoing session attempt fails due to failure to
111 support the given transport <literal>chan_motif</literal> will
112 fall back in preference order listed previously until all
113 transports have been exhausted.</para>
114 <para><emphasis>Dialing and Resource Selection Strategy</emphasis></para>
115 <para>Placing a call through an endpoint can be accomplished using the
116 following dial string:</para>
117 <para><literal>Motif/[endpoint name]/[target]</literal></para>
118 <para>When placing an outgoing call through an endpoint the requested
119 target is searched for in the roster list. If present the first Jingle
120 or Google Jingle capable resource is specifically targeted. Since the
121 capabilities of the resource are known the outgoing session initiation
122 will disregard the configured transport and use the determined one.</para>
123 <para>If the target is not found in the roster the target will be used
124 as-is and a session will be initiated using the transport specified
125 in this configuration file. If no transport has been specified the
126 endpoint defaults to <literal>ice-udp</literal>.</para>
127 <para><emphasis>Video Support</emphasis></para>
128 <para>Support for video does not need to be explicitly enabled.
129 Configuring any video codec on your endpoint will automatically enable
131 <para><emphasis>DTMF</emphasis></para>
132 <para>The only supported method for DTMF is RFC2833. This is always
133 enabled on audio streams and negotiated if possible.</para>
134 <para><emphasis>Incoming Calls</emphasis></para>
135 <para>Incoming calls will first look for the extension matching the
136 name of the endpoint in the configured context. If no such extension
137 exists the call will automatically fall back to the <literal>s</literal> extension.</para>
138 <para><emphasis>CallerID</emphasis></para>
139 <para>The incoming caller id number is populated with the username of
140 the caller and the name is populated with the full identity of the
141 caller. If you would like to perform authentication or filtering
142 of incoming calls it is recommended that you use these fields to do so.</para>
143 <para>Outgoing caller id can <emphasis>not</emphasis> be set.</para>
145 <para>Multiple endpoints using the
146 same connection is <emphasis>NOT</emphasis> supported. Doing so
147 may result in broken calls.</para>
150 <configFile name="motif.conf">
151 <configObject name="endpoint">
152 <synopsis>The configuration for an endpoint.</synopsis>
153 <configOption name="context">
154 <synopsis>Default dialplan context that incoming sessions will be routed to</synopsis>
156 <configOption name="callgroup">
157 <synopsis>A callgroup to assign to this endpoint.</synopsis>
159 <configOption name="pickupgroup">
160 <synopsis>A pickup group to assign to this endpoint.</synopsis>
162 <configOption name="language">
163 <synopsis>The default language for this endpoint.</synopsis>
165 <configOption name="musicclass">
166 <synopsis>Default music on hold class for this endpoint.</synopsis>
168 <configOption name="parkinglot">
169 <synopsis>Default parking lot for this endpoint.</synopsis>
171 <configOption name="accountcode">
172 <synopsis>Accout code for CDR purposes</synopsis>
174 <configOption name="allow">
175 <synopsis>Codecs to allow</synopsis>
177 <configOption name="disallow">
178 <synopsis>Codecs to disallow</synopsis>
180 <configOption name="connection">
181 <synopsis>Connection to accept traffic on and on which to send traffic out</synopsis>
183 <configOption name="transport">
184 <synopsis>The transport to use for the endpoint.</synopsis>
186 <para>The default outbound transport for this endpoint. Inbound
187 messages are inferred. Allowed transports are <literal>ice-udp</literal>,
188 <literal>google</literal>, or <literal>google-v1</literal>. Note
189 that <literal>chan_motif</literal> will fall back to transport
190 preference order if the transport value chosen here fails.</para>
192 <enum name="ice-udp">
193 <para>The Jingle protocol, as defined in XEP 0166.</para>
196 <para>The Google Jingle protocol, which follows the Jingle
197 specification for signaling but uses a custom transport for
200 <enum name="google-v1">
201 <para>Google-V1 is the original Google Talk signaling
202 protocol which uses an initial preliminary version of Jingle.
203 It also uses the same custom transport as <literal>google</literal> for media.</para>
208 <configOption name="maxicecandidates">
209 <synopsis>Maximum number of ICE candidates to offer</synopsis>
211 <configOption name="maxpayloads">
212 <synopsis>Maximum number of pyaloads to offer</synopsis>
219 /*! \brief Default maximum number of ICE candidates we will offer */
220 #define DEFAULT_MAX_ICE_CANDIDATES "10"
222 /*! \brief Default maximum number of payloads we will offer */
223 #define DEFAULT_MAX_PAYLOADS "30"
225 /*! \brief Number of buckets for endpoints */
226 #define ENDPOINT_BUCKETS 37
228 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
229 #define SESSION_BUCKETS 37
231 /*! \brief Namespace for Jingle itself */
232 #define JINGLE_NS "urn:xmpp:jingle:1"
234 /*! \brief Namespace for Jingle RTP sessions */
235 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
237 /*! \brief Namespace for Jingle RTP info */
238 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
240 /*! \brief Namespace for Jingle ICE-UDP */
241 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
243 /*! \brief Namespace for Google Talk ICE-UDP */
244 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
246 /*! \brief Namespace for Google Talk Raw UDP */
247 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
249 /*! \brief Namespace for Google Session */
250 #define GOOGLE_SESSION_NS "http://www.google.com/session"
252 /*! \brief Namespace for Google Phone description */
253 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
255 /*! \brief Namespace for Google Video description */
256 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
258 /*! \brief Namespace for XMPP stanzas */
259 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
261 /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */
262 enum jingle_transport {
263 JINGLE_TRANSPORT_ICE_UDP = 3, /*!< XEP-0176 */
264 JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
265 JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
266 JINGLE_TRANSPORT_NONE = 0, /*!< No transport specified */
269 /*! \brief Endpoint state information */
270 struct jingle_endpoint_state {
271 struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
274 /*! \brief Endpoint which contains configuration information and active sessions */
275 struct jingle_endpoint {
276 AST_DECLARE_STRING_FIELDS(
277 AST_STRING_FIELD(name); /*!< Name of the endpoint */
278 AST_STRING_FIELD(context); /*!< Context to place incoming calls into */
279 AST_STRING_FIELD(accountcode); /*!< Account code */
280 AST_STRING_FIELD(language); /*!< Default language for prompts */
281 AST_STRING_FIELD(musicclass); /*!< Configured music on hold class */
282 AST_STRING_FIELD(parkinglot); /*!< Configured parking lot */
284 struct ast_xmpp_client *connection; /*!< Connection to use for traffic */
285 iksrule *rule; /*!< Active matching rule */
286 unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */
287 unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */
288 struct ast_codec_pref prefs; /*!< Codec preferences */
289 struct ast_format_cap *cap; /*!< Formats to use */
290 ast_group_t callgroup; /*!< Call group */
291 ast_group_t pickupgroup; /*!< Pickup group */
292 enum jingle_transport transport; /*!< Default transport to use on outgoing sessions */
293 struct jingle_endpoint_state *state; /*!< Endpoint state information */
296 /*! \brief Session which contains information about an active session */
297 struct jingle_session {
298 AST_DECLARE_STRING_FIELDS(
299 AST_STRING_FIELD(sid); /*!< Session identifier */
300 AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
301 AST_STRING_FIELD(video_name); /*!< Name of the video content */
303 struct jingle_endpoint_state *state; /*!< Endpoint we are associated with */
304 struct ast_xmpp_client *connection; /*!< Connection to use for traffic */
305 enum jingle_transport transport; /*!< Transport type to use for this session */
306 unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */
307 unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */
308 char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
309 char remote[XMPP_MAX_JIDLEN]; /*!< Identifier of the remote party */
310 iksrule *rule; /*!< Session matching rule */
311 struct ast_codec_pref prefs; /*!< Codec preferences */
312 struct ast_channel *owner; /*!< Master Channel */
313 struct ast_rtp_instance *rtp; /*!< RTP audio session */
314 struct ast_rtp_instance *vrtp; /*!< RTP video session */
315 struct ast_format_cap *cap; /*!< Local codec capabilities */
316 struct ast_format_cap *jointcap; /*!< Joint codec capabilities */
317 struct ast_format_cap *peercap; /*!< Peer codec capabilities */
318 unsigned int outgoing:1; /*!< Whether this is an outgoing leg or not */
319 unsigned int gone:1; /*!< In the eyes of Jingle this session is already gone */
320 struct ast_callid *callid; /*!< Bound session call-id */
323 static const char desc[] = "Motif Jingle Channel";
324 static const char channel_type[] = "Motif";
326 struct jingle_config {
327 struct ao2_container *endpoints; /*!< Configured endpoints */
330 static AO2_GLOBAL_OBJ_STATIC(globals);
332 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
334 /* \brief Asterisk core interaction functions */
335 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
336 static int jingle_sendtext(struct ast_channel *ast, const char *text);
337 static int jingle_digit_begin(struct ast_channel *ast, char digit);
338 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
339 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
340 static int jingle_hangup(struct ast_channel *ast);
341 static int jingle_answer(struct ast_channel *ast);
342 static struct ast_frame *jingle_read(struct ast_channel *ast);
343 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
344 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
345 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
346 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
348 /*! \brief Action handlers */
349 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
350 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
351 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
352 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
353 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
355 /*! \brief PBX interface structure for channel registration */
356 static struct ast_channel_tech jingle_tech = {
358 .description = "Motif Jingle Channel Driver",
359 .requester = jingle_request,
360 .send_text = jingle_sendtext,
361 .send_digit_begin = jingle_digit_begin,
362 .send_digit_end = jingle_digit_end,
363 .bridge = ast_rtp_instance_bridge,
365 .hangup = jingle_hangup,
366 .answer = jingle_answer,
368 .write = jingle_write,
369 .write_video = jingle_write,
370 .exception = jingle_read,
371 .indicate = jingle_indicate,
372 .fixup = jingle_fixup,
373 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
376 /*! \brief Defined handlers for different Jingle actions */
377 static const struct jingle_action_handler {
379 void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
380 } jingle_action_handlers[] = {
382 { "session-initiate", jingle_action_session_initiate, },
383 { "transport-info", jingle_action_transport_info, },
384 { "session-accept", jingle_action_session_accept, },
385 { "session-info", jingle_action_session_info, },
386 { "session-terminate", jingle_action_session_terminate, },
387 /* Google-V1 actions */
388 { "initiate", jingle_action_session_initiate, },
389 { "candidates", jingle_action_transport_info, },
390 { "accept", jingle_action_session_accept, },
391 { "terminate", jingle_action_session_terminate, },
392 { "reject", jingle_action_session_terminate, },
395 /*! \brief Reason text <-> cause code mapping */
396 static const struct jingle_reason_mapping {
399 } jingle_reason_mappings[] = {
400 { "busy", AST_CAUSE_BUSY, },
401 { "cancel", AST_CAUSE_CALL_REJECTED, },
402 { "connectivity-error", AST_CAUSE_INTERWORKING, },
403 { "decline", AST_CAUSE_CALL_REJECTED, },
404 { "expired", AST_CAUSE_NO_USER_RESPONSE, },
405 { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
406 { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
407 { "general-error", AST_CAUSE_CONGESTION, },
408 { "gone", AST_CAUSE_NORMAL_CLEARING, },
409 { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
410 { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
411 { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
412 { "success", AST_CAUSE_NORMAL_CLEARING, },
413 { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
414 { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
415 { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
418 /*! \brief Hashing function for Jingle sessions */
419 static int jingle_session_hash(const void *obj, const int flags)
421 const struct jingle_session *session = obj;
422 const char *sid = obj;
424 return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
427 /*! \brief Comparator function for Jingle sessions */
428 static int jingle_session_cmp(void *obj, void *arg, int flags)
430 struct jingle_session *session1 = obj, *session2 = arg;
431 const char *sid = arg;
433 return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
436 /*! \brief Destructor for Jingle endpoint state */
437 static void jingle_endpoint_state_destructor(void *obj)
439 struct jingle_endpoint_state *state = obj;
441 ao2_ref(state->sessions, -1);
444 /*! \brief Destructor for Jingle endpoints */
445 static void jingle_endpoint_destructor(void *obj)
447 struct jingle_endpoint *endpoint = obj;
449 if (endpoint->rule) {
450 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
453 if (endpoint->connection) {
454 ast_xmpp_client_unref(endpoint->connection);
457 ast_format_cap_destroy(endpoint->cap);
459 ao2_ref(endpoint->state, -1);
461 ast_string_field_free_memory(endpoint);
464 /*! \brief Find function for Jingle endpoints */
465 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
467 return ao2_find(tmp_container, category, OBJ_KEY);
470 /*! \brief Allocator function for Jingle endpoint state */
471 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
473 struct jingle_endpoint_state *state;
475 if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
479 if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
487 /*! \brief State find/create function */
488 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
490 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
491 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
493 if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
494 return jingle_endpoint_state_create();
497 ao2_ref(endpoint->state, +1);
498 return endpoint->state;
501 /*! \brief Allocator function for Jingle endpoints */
502 static void *jingle_endpoint_alloc(const char *cat)
504 struct jingle_endpoint *endpoint;
506 if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
510 if (ast_string_field_init(endpoint, 512)) {
511 ao2_ref(endpoint, -1);
515 if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
516 ao2_ref(endpoint, -1);
520 ast_string_field_set(endpoint, name, cat);
522 endpoint->cap = ast_format_cap_alloc_nolock();
523 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
528 /*! \brief Hashing function for Jingle endpoints */
529 static int jingle_endpoint_hash(const void *obj, const int flags)
531 const struct jingle_endpoint *endpoint = obj;
532 const char *name = obj;
534 return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
537 /*! \brief Comparator function for Jingle endpoints */
538 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
540 struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
541 const char *name = arg;
543 return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
546 static struct aco_type endpoint_option = {
549 .category_match = ACO_BLACKLIST,
550 .category = "^general$",
551 .item_alloc = jingle_endpoint_alloc,
552 .item_find = jingle_endpoint_find,
553 .item_offset = offsetof(struct jingle_config, endpoints),
556 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
558 struct aco_file jingle_conf = {
559 .filename = "motif.conf",
560 .types = ACO_TYPES(&endpoint_option),
563 /*! \brief Destructor for Jingle sessions */
564 static void jingle_session_destructor(void *obj)
566 struct jingle_session *session = obj;
569 iks_filter_remove_rule(session->connection->filter, session->rule);
572 if (session->connection) {
573 ast_xmpp_client_unref(session->connection);
577 ast_rtp_instance_stop(session->rtp);
578 ast_rtp_instance_destroy(session->rtp);
582 ast_rtp_instance_stop(session->vrtp);
583 ast_rtp_instance_destroy(session->vrtp);
586 ast_format_cap_destroy(session->cap);
587 ast_format_cap_destroy(session->jointcap);
588 ast_format_cap_destroy(session->peercap);
590 if (session->callid) {
591 ast_callid_unref(session->callid);
594 ast_string_field_free_memory(session);
597 /*! \brief Destructor called when module configuration goes away */
598 static void jingle_config_destructor(void *obj)
600 struct jingle_config *cfg = obj;
601 ao2_cleanup(cfg->endpoints);
604 /*! \brief Allocator called when module configuration should appear */
605 static void *jingle_config_alloc(void)
607 struct jingle_config *cfg;
609 if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
613 if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
621 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
622 .files = ACO_FILES(&jingle_conf),
625 /*! \brief Function called by RTP engine to get local RTP peer */
626 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
628 struct jingle_session *session = ast_channel_tech_pvt(chan);
629 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
632 return AST_RTP_GLUE_RESULT_FORBID;
635 ao2_ref(session->rtp, +1);
636 *instance = session->rtp;
641 /*! \brief Function called by RTP engine to get peer capabilities */
642 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
646 /*! \brief Function called by RTP engine to change where the remote party should send media */
647 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)
652 /*! \brief Local glue for interacting with the RTP engine core */
653 static struct ast_rtp_glue jingle_rtp_glue = {
655 .get_rtp_info = jingle_get_rtp_peer,
656 .get_codec = jingle_get_codec,
657 .update_peer = jingle_set_rtp_peer,
660 /*! \brief Internal helper function which enables video support on a sesson if possible */
661 static void jingle_enable_video(struct jingle_session *session)
663 struct ast_sockaddr tmp;
664 struct ast_rtp_engine_ice *ice;
666 /* If video is already present don't do anything */
671 /* If there are no configured video codecs do not turn video support on, it just won't work */
672 if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
676 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
678 if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
682 ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
684 ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
685 ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
686 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
688 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
689 ice->stop(session->vrtp);
693 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
694 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
696 struct jingle_session *session;
697 struct ast_callid *callid;
698 struct ast_sockaddr tmp;
700 if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
704 callid = ast_read_threadstorage_callid();
705 session->callid = (callid ? callid : ast_create_callid());
707 if (ast_string_field_init(session, 512)) {
708 ao2_ref(session, -1);
712 if (!ast_strlen_zero(from)) {
713 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
714 ast_copy_string(session->remote, from, sizeof(session->remote));
717 if (ast_strlen_zero(sid)) {
718 ast_string_field_build(session, sid, "%08lx%08lx", ast_random(), ast_random());
719 session->outgoing = 1;
720 ast_string_field_set(session, audio_name, "audio");
721 ast_string_field_set(session, video_name, "video");
723 ast_string_field_set(session, sid, sid);
726 ao2_ref(endpoint->state, +1);
727 session->state = endpoint->state;
728 ao2_ref(endpoint->connection, +1);
729 session->connection = endpoint->connection;
730 session->transport = endpoint->transport;
732 if (!(session->cap = ast_format_cap_alloc_nolock()) ||
733 !(session->jointcap = ast_format_cap_alloc_nolock()) ||
734 !(session->peercap = ast_format_cap_alloc_nolock()) ||
736 ao2_ref(session, -1);
740 ast_format_cap_copy(session->cap, endpoint->cap);
742 /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
743 * that we want IPv4 */
744 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
746 /* Sessions always carry audio, but video is optional so don't enable it here */
747 if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
748 ao2_ref(session, -1);
751 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
752 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
754 memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
756 session->maxicecandidates = endpoint->maxicecandidates;
757 session->maxpayloads = endpoint->maxpayloads;
762 /*! \brief Function called to create a new Jingle Asterisk channel */
763 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)
765 struct ast_channel *chan;
766 const char *str = S_OR(title, session->remote);
767 struct ast_format tmpfmt;
769 if (ast_format_cap_is_empty(session->cap)) {
773 if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) {
777 ast_channel_tech_set(chan, &jingle_tech);
778 ast_channel_tech_pvt_set(chan, session);
779 session->owner = chan;
781 ast_channel_callid_set(chan, session->callid);
783 ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
784 ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
787 struct ast_rtp_engine_ice *ice;
789 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
790 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
791 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
793 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
794 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
795 (ice = ast_rtp_instance_get_ice(session->rtp))) {
796 /* We stop built in ICE support because we need to fall back to old old old STUN support */
797 ice->stop(session->rtp);
801 if (state == AST_STATE_RING) {
802 ast_channel_rings_set(chan, 1);
805 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
807 ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
808 ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
809 ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
810 ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
811 ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
815 ast_channel_callgroup_set(chan, endpoint->callgroup);
816 ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
818 if (!ast_strlen_zero(endpoint->accountcode)) {
819 ast_channel_accountcode_set(chan, endpoint->accountcode);
822 if (!ast_strlen_zero(endpoint->language)) {
823 ast_channel_language_set(chan, endpoint->language);
826 if (!ast_strlen_zero(endpoint->musicclass)) {
827 ast_channel_musicclass_set(chan, endpoint->musicclass);
830 ast_channel_context_set(chan, endpoint->context);
831 if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
832 ast_channel_exten_set(chan, endpoint->name);
834 ast_channel_exten_set(chan, "s");
836 ast_channel_priority_set(chan, 1);
838 ao2_unlock(endpoint);
843 /*! \brief Internal helper function which sends a response */
844 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
848 if (!(response = iks_new("iq"))) {
849 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
853 iks_insert_attrib(response, "type", "result");
854 iks_insert_attrib(response, "from", connection->jid->full);
855 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
856 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
858 ast_xmpp_client_send(connection, response);
860 iks_delete(response);
863 /*! \brief Internal helper function which sends an error response */
864 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
866 iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
868 if (!(response = iks_new("iq")) ||
869 !(error = iks_new("error")) ||
870 !(reason = iks_new(reasonstr))) {
871 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
875 iks_insert_attrib(response, "type", "error");
876 iks_insert_attrib(response, "from", connection->jid->full);
877 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
878 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
880 iks_insert_attrib(error, "type", type);
881 iks_insert_node(error, reason);
883 if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
884 iks_insert_node(error, reason2);
887 iks_insert_node(response, error);
889 ast_xmpp_client_send(connection, response);
894 iks_delete(response);
897 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
898 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
900 struct ast_rtp_engine_ice *ice;
901 struct ao2_container *local_candidates;
902 struct ao2_iterator it;
903 struct ast_rtp_engine_ice_candidate *candidate;
906 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
907 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
911 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
912 iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
913 iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
915 it = ao2_iterator_init(local_candidates, 0);
917 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
918 iks *local_candidate;
921 if (!(local_candidate = iks_new("candidate"))) {
923 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
927 snprintf(tmp, sizeof(tmp), "%d", candidate->id);
928 iks_insert_attrib(local_candidate, "component", tmp);
929 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
930 iks_insert_attrib(local_candidate, "foundation", tmp);
931 iks_insert_attrib(local_candidate, "generation", "0");
932 iks_insert_attrib(local_candidate, "network", "0");
933 snprintf(tmp, sizeof(tmp), "%04lx", ast_random() & 0xffff);
934 iks_insert_attrib(local_candidate, "id", tmp);
935 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
936 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
937 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
938 iks_insert_attrib(local_candidate, "priority", tmp);
939 iks_insert_attrib(local_candidate, "protocol", "udp");
941 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
942 iks_insert_attrib(local_candidate, "type", "host");
943 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
944 iks_insert_attrib(local_candidate, "type", "srflx");
945 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
946 iks_insert_attrib(local_candidate, "type", "relay");
949 iks_insert_node(transport, local_candidate);
950 candidates[i++] = local_candidate;
953 ao2_iterator_destroy(&it);
954 ao2_ref(local_candidates, -1);
959 /*! \brief Internal helper function which adds Google candidates to a transport node */
960 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)
962 struct ast_rtp_engine_ice *ice;
963 struct ao2_container *local_candidates;
964 struct ao2_iterator it;
965 struct ast_rtp_engine_ice_candidate *candidate;
968 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
969 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
973 if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
974 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
977 it = ao2_iterator_init(local_candidates, 0);
979 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
980 iks *local_candidate;
981 /* In Google land a username is 16 bytes, explicitly */
984 if (!(local_candidate = iks_new("candidate"))) {
986 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
990 if (candidate->id == 1) {
991 iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
992 } else if (candidate->id == 2) {
993 iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
995 iks_delete(local_candidate);
999 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
1000 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
1002 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
1003 iks_insert_attrib(local_candidate, "preference", "0.95");
1004 iks_insert_attrib(local_candidate, "type", "local");
1005 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
1006 iks_insert_attrib(local_candidate, "preference", "0.9");
1007 iks_insert_attrib(local_candidate, "type", "stun");
1010 iks_insert_attrib(local_candidate, "protocol", "udp");
1011 iks_insert_attrib(local_candidate, "network", "0");
1012 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
1013 iks_insert_attrib(local_candidate, "username", ufrag);
1014 iks_insert_attrib(local_candidate, "generation", "0");
1016 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
1017 iks_insert_attrib(local_candidate, "password", "");
1018 iks_insert_attrib(local_candidate, "foundation", "0");
1019 iks_insert_attrib(local_candidate, "component", "1");
1021 iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
1024 /* You may notice a lack of relay support up above - this is because we don't support it for use with
1025 * the Google talk transport due to their arcane support. */
1027 iks_insert_node(transport, local_candidate);
1028 candidates[i++] = local_candidate;
1031 ao2_iterator_destroy(&it);
1032 ao2_ref(local_candidates, -1);
1037 /*! \brief Internal function which sends a session-terminate message */
1038 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
1040 iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
1042 if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
1043 !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
1044 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
1048 iks_insert_attrib(iq, "to", session->remote);
1049 iks_insert_attrib(iq, "type", "set");
1050 iks_insert_attrib(iq, "id", session->connection->mid);
1051 ast_xmpp_increment_mid(session->connection->mid);
1053 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1054 iks_insert_attrib(jingle, "type", "terminate");
1055 iks_insert_attrib(jingle, "id", session->sid);
1056 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1057 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1059 iks_insert_attrib(jingle, "action", "session-terminate");
1060 iks_insert_attrib(jingle, "sid", session->sid);
1061 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1064 iks_insert_node(iq, jingle);
1065 iks_insert_node(jingle, reason);
1066 iks_insert_node(reason, text);
1068 ast_xmpp_client_send(session->connection, iq);
1077 /*! \brief Internal function which sends a session-info message */
1078 static void jingle_send_session_info(struct jingle_session *session, const char *info)
1080 iks *iq = NULL, *jingle = NULL, *text = NULL;
1082 /* Google-V1 has no way to send informational messages so don't even bother trying */
1083 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1087 if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
1088 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
1092 iks_insert_attrib(iq, "to", session->remote);
1093 iks_insert_attrib(iq, "type", "set");
1094 iks_insert_attrib(iq, "id", session->connection->mid);
1095 ast_xmpp_increment_mid(session->connection->mid);
1097 iks_insert_attrib(jingle, "action", "session-info");
1098 iks_insert_attrib(jingle, "sid", session->sid);
1099 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1100 iks_insert_node(iq, jingle);
1101 iks_insert_node(jingle, text);
1103 ast_xmpp_client_send(session->connection, iq);
1113 * \brief Locks both pvt and pvt owner if owner is present.
1115 * \note This function gives a ref to pvt->owner if it is present and locked.
1116 * This reference must be decremented after pvt->owner is unlocked.
1118 * \note This function will never give you up,
1119 * \note This function will never let you down.
1120 * \note This function will run around and desert you.
1122 * \pre pvt is not locked
1123 * \post pvt is locked
1124 * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
1126 * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
1128 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
1130 struct ast_channel *chan;
1132 /* Locking is simple when it is done right. If you see a deadlock resulting
1133 * in this function, it is not this function's fault, Your problem exists elsewhere.
1134 * This function is perfect... seriously. */
1136 /* First, get the channel and grab a reference to it */
1140 /* The channel can not go away while we hold the pvt lock.
1141 * Give the channel a ref so it will not go away after we let
1142 * the pvt lock go. */
1143 ast_channel_ref(chan);
1145 /* no channel, return pvt locked */
1149 /* We had to hold the pvt lock while getting a ref to the owner channel
1150 * but now we have to let this lock go in order to preserve proper
1151 * locking order when grabbing the channel lock */
1154 /* Look, no deadlock avoidance, hooray! */
1155 ast_channel_lock(chan);
1157 if (pvt->owner == chan) {
1162 /* If the owner changed while everything was unlocked, no problem,
1163 * just start over and everthing will work. This is rare, do not be
1164 * confused by this loop and think this it is an expensive operation.
1165 * The majority of the calls to this function will never involve multiple
1166 * executions of this loop. */
1167 ast_channel_unlock(chan);
1168 ast_channel_unref(chan);
1172 /* If owner exists, it is locked and reffed */
1176 /*! \brief Helper function which queues a hangup frame with cause code */
1177 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1179 struct ast_channel *chan;
1181 if ((chan = jingle_session_lock_full(session))) {
1182 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1183 ast_queue_hangup_with_cause(chan, cause);
1184 ast_channel_unlock(chan);
1185 ast_channel_unref(chan);
1187 ao2_unlock(session);
1190 /*! \brief Internal function which sends a transport-info message */
1191 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1193 iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1194 iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1197 if (!(iq = iks_new("iq")) ||
1198 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1200 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1201 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1205 memset(audio_candidates, 0, sizeof(audio_candidates));
1206 memset(video_candidates, 0, sizeof(video_candidates));
1208 iks_insert_attrib(iq, "from", session->connection->jid->full);
1209 iks_insert_attrib(iq, "to", from);
1210 iks_insert_attrib(iq, "type", "set");
1211 iks_insert_attrib(iq, "id", session->connection->mid);
1212 ast_xmpp_increment_mid(session->connection->mid);
1214 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1215 iks_insert_attrib(jingle, "type", "candidates");
1216 iks_insert_attrib(jingle, "id", session->sid);
1217 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1218 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1220 iks_insert_attrib(jingle, "action", "transport-info");
1221 iks_insert_attrib(jingle, "sid", session->sid);
1222 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1224 iks_insert_node(iq, jingle);
1227 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1228 /* V1 protocol has the candidates directly in the session */
1229 res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1230 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1231 iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1232 iks_insert_attrib(audio, "name", session->audio_name);
1233 iks_insert_node(jingle, audio);
1234 iks_insert_node(audio, audio_transport);
1236 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1237 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1238 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1239 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1240 session->maxicecandidates);
1247 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1248 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1249 iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1250 iks_insert_attrib(video, "name", session->video_name);
1251 iks_insert_node(jingle, video);
1252 iks_insert_node(video, video_transport);
1254 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1255 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1256 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1257 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1258 session->maxicecandidates);
1266 ast_xmpp_client_send(session->connection, iq);
1268 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1271 /* Clean up after ourselves */
1272 for (i = 0; i < session->maxicecandidates; i++) {
1273 iks_delete(video_candidates[i]);
1274 iks_delete(audio_candidates[i]);
1277 iks_delete(video_transport);
1279 iks_delete(audio_transport);
1285 /*! \brief Internal helper function which adds payloads to a description */
1286 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)
1288 struct ast_format format;
1289 int x = 0, i = 0, res = 0;
1291 for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
1296 if (!ast_codec_pref_index(&session->prefs, x, &format)) {
1300 if (AST_FORMAT_GET_TYPE(format.id) != type) {
1304 if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
1308 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
1309 (!(payload = iks_new("payload-type")))) {
1313 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1314 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1317 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1318 iks_insert_attrib(payload, "id", tmp);
1319 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
1320 iks_insert_attrib(payload, "channels", "1");
1322 if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1323 iks_insert_attrib(payload, "clockrate", "16000");
1325 snprintf(tmp, sizeof(tmp), "%d", ast_rtp_lookup_sample_rate2(1, &format, 0));
1326 iks_insert_attrib(payload, "clockrate", tmp);
1329 if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1332 /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1333 if ((parameter = iks_new("parameter"))) {
1334 iks_insert_attrib(parameter, "name", "width");
1335 iks_insert_attrib(parameter, "value", "640");
1336 iks_insert_node(payload, parameter);
1338 if ((parameter = iks_new("parameter"))) {
1339 iks_insert_attrib(parameter, "name", "height");
1340 iks_insert_attrib(parameter, "value", "480");
1341 iks_insert_node(payload, parameter);
1343 if ((parameter = iks_new("parameter"))) {
1344 iks_insert_attrib(parameter, "name", "framerate");
1345 iks_insert_attrib(parameter, "value", "30");
1346 iks_insert_node(payload, parameter);
1350 iks_insert_node(description, payload);
1351 payloads[i++] = payload;
1353 /* If this is for audio and there is room for RFC2833 add it in */
1354 if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
1357 if ((payload = iks_new("payload-type"))) {
1358 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1359 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1362 iks_insert_attrib(payload, "id", "101");
1363 iks_insert_attrib(payload, "name", "telephone-event");
1364 iks_insert_attrib(payload, "channels", "1");
1365 iks_insert_attrib(payload, "clockrate", "8000");
1366 iks_insert_node(description, payload);
1367 payloads[i++] = payload;
1374 /*! \brief Helper function which adds content to a description */
1375 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1376 const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
1380 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1381 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1382 iks_insert_attrib(content, "name", name);
1383 iks_insert_node(jingle, content);
1385 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1386 if (type == AST_FORMAT_TYPE_AUDIO) {
1387 iks_insert_attrib(description, "media", "audio");
1388 } else if (type == AST_FORMAT_TYPE_VIDEO) {
1389 iks_insert_attrib(description, "media", "video");
1393 iks_insert_node(content, description);
1395 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1396 iks_insert_node(jingle, description);
1399 if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1400 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1401 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1402 iks_insert_node(content, transport);
1403 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1404 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1405 iks_insert_node(content, transport);
1412 /*! \brief Internal function which sends a complete session message */
1413 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1415 iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1416 iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1417 iks *audio_transport = NULL, *video_transport = NULL;
1420 if (!(iq = iks_new("iq")) ||
1421 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1422 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1427 memset(audio_payloads, 0, sizeof(audio_payloads));
1428 memset(video_payloads, 0, sizeof(video_payloads));
1430 iks_insert_attrib(iq, "from", session->connection->jid->full);
1431 iks_insert_attrib(iq, "to", session->remote);
1432 iks_insert_attrib(iq, "type", "set");
1433 iks_insert_attrib(iq, "id", session->connection->mid);
1434 ast_xmpp_increment_mid(session->connection->mid);
1436 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1437 iks_insert_attrib(jingle, "type", action);
1438 iks_insert_attrib(jingle, "id", session->sid);
1439 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1441 iks_insert_attrib(jingle, "action", action);
1442 iks_insert_attrib(jingle, "sid", session->sid);
1443 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1446 if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1447 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1450 iks_insert_node(iq, jingle);
1452 if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1453 (audio_transport = iks_new("transport"))) {
1454 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1455 AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
1457 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1461 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1462 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1463 (video_transport = iks_new("transport"))) {
1464 res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1465 AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
1467 ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1473 ast_xmpp_client_send(session->connection, iq);
1475 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1478 iks_delete(video_transport);
1479 iks_delete(audio_transport);
1481 for (i = 0; i < session->maxpayloads; i++) {
1482 iks_delete(video_payloads[i]);
1483 iks_delete(audio_payloads[i]);
1486 iks_delete(video_description);
1488 iks_delete(audio_description);
1494 /*! \brief Internal function which sends a session-inititate message */
1495 static void jingle_send_session_initiate(struct jingle_session *session)
1497 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1500 /*! \brief Internal function which sends a session-accept message */
1501 static void jingle_send_session_accept(struct jingle_session *session)
1503 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1506 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1507 static int jingle_outgoing_hook(void *data, ikspak *pak)
1509 struct jingle_session *session = data;
1510 iks *error = iks_find(pak->x, "error"), *redirect;
1512 /* In all cases this hook is done with */
1513 iks_filter_remove_rule(session->connection->filter, session->rule);
1514 session->rule = NULL;
1516 ast_callid_threadassoc_add(session->callid);
1518 /* If no error occurred they accepted our session-initiate message happily */
1520 struct ast_channel *chan;
1522 if ((chan = jingle_session_lock_full(session))) {
1523 ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1524 ast_channel_unlock(chan);
1525 ast_channel_unref(chan);
1527 ao2_unlock(session);
1529 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1534 /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1537 /* Map the error we received to an appropriate cause code and hang up the channel */
1538 if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1539 iks *to = iks_child(redirect);
1542 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1543 /* Make the xmpp: go away if it is present */
1544 if (!strncmp(target, "xmpp:", 5)) {
1548 /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1549 ast_copy_string(session->remote, target, sizeof(session->remote));
1551 /* Add a new hook so we can get the status of redirected session */
1552 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1553 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1555 jingle_send_session_initiate(session);
1559 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1561 } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1562 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1563 } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1564 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1565 } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1566 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1567 } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1568 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1569 } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1570 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1571 session->transport--;
1573 /* If we still have a viable transport mechanism re-send the session-initiate */
1574 if (session->transport != JINGLE_TRANSPORT_NONE) {
1575 struct ast_rtp_engine_ice *ice;
1577 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1578 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1579 (ice = ast_rtp_instance_get_ice(session->rtp))) {
1580 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1581 ice->stop(session->rtp);
1584 /* Re-send the message to the *original* target and not a redirected one */
1585 ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1587 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1588 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1590 jingle_send_session_initiate(session);
1594 /* Otherwise we have exhausted all transports */
1595 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1598 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1602 ast_callid_threadassoc_remove();
1604 return IKS_FILTER_EAT;
1607 /*! \brief Function called by core when we should answer a Jingle session */
1608 static int jingle_answer(struct ast_channel *ast)
1610 struct jingle_session *session = ast_channel_tech_pvt(ast);
1612 /* The channel has already been answered so we don't need to do anything */
1613 if (ast_channel_state(ast) == AST_STATE_UP) {
1617 jingle_send_session_accept(session);
1622 /*! \brief Function called by core to read any waiting frames */
1623 static struct ast_frame *jingle_read(struct ast_channel *ast)
1625 struct jingle_session *session = ast_channel_tech_pvt(ast);
1626 struct ast_frame *frame = &ast_null_frame;
1628 switch (ast_channel_fdno(ast)) {
1631 frame = ast_rtp_instance_read(session->rtp, 0);
1636 frame = ast_rtp_instance_read(session->rtp, 1);
1640 if (session->vrtp) {
1641 frame = ast_rtp_instance_read(session->vrtp, 0);
1645 if (session->vrtp) {
1646 frame = ast_rtp_instance_read(session->vrtp, 1);
1653 if (frame && frame->frametype == AST_FRAME_VOICE &&
1654 !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
1655 if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
1656 ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1657 ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
1659 frame = &ast_null_frame;
1661 ast_debug(1, "Oooh, format changed to %s\n",
1662 ast_getformatname(&frame->subclass.format));
1663 ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
1664 ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
1665 ast_set_read_format(ast, ast_channel_readformat(ast));
1666 ast_set_write_format(ast, ast_channel_writeformat(ast));
1673 /*! \brief Function called by core to write frames */
1674 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1676 struct jingle_session *session = ast_channel_tech_pvt(ast);
1680 switch (frame->frametype) {
1681 case AST_FRAME_VOICE:
1682 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
1683 ast_log(LOG_WARNING,
1684 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1685 ast_getformatname(&frame->subclass.format),
1686 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
1687 ast_getformatname(ast_channel_readformat(ast)),
1688 ast_getformatname(ast_channel_writeformat(ast)));
1691 if (session && session->rtp) {
1692 res = ast_rtp_instance_write(session->rtp, frame);
1695 case AST_FRAME_VIDEO:
1696 if (session && session->vrtp) {
1697 res = ast_rtp_instance_write(session->vrtp, frame);
1701 ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
1709 /*! \brief Function called by core to change the underlying owner channel */
1710 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1712 struct jingle_session *session = ast_channel_tech_pvt(newchan);
1716 session->owner = newchan;
1718 ao2_unlock(session);
1723 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1724 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1726 struct jingle_session *session = ast_channel_tech_pvt(ast);
1729 switch (condition) {
1730 case AST_CONTROL_RINGING:
1731 if (ast_channel_state(ast) == AST_STATE_RING) {
1732 jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1737 case AST_CONTROL_BUSY:
1738 if (ast_channel_state(ast) != AST_STATE_UP) {
1739 ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1740 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1745 case AST_CONTROL_CONGESTION:
1746 if (ast_channel_state(ast) != AST_STATE_UP) {
1747 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1748 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1753 case AST_CONTROL_INCOMPLETE:
1754 if (ast_channel_state(ast) != AST_STATE_UP) {
1755 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1756 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1759 case AST_CONTROL_HOLD:
1760 ast_moh_start(ast, data, NULL);
1762 case AST_CONTROL_UNHOLD:
1765 case AST_CONTROL_SRCUPDATE:
1767 ast_rtp_instance_update_source(session->rtp);
1770 case AST_CONTROL_SRCCHANGE:
1772 ast_rtp_instance_change_source(session->rtp);
1775 case AST_CONTROL_VIDUPDATE:
1776 case AST_CONTROL_UPDATE_RTP_PEER:
1777 case AST_CONTROL_CONNECTED_LINE:
1779 case AST_CONTROL_PVT_CAUSE_CODE:
1784 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1791 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1792 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1794 struct jingle_session *session = ast_channel_tech_pvt(chan);
1796 return ast_xmpp_client_send_message(session->connection, session->remote, text);
1799 /*! \brief Function called by core to start a DTMF digit */
1800 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1802 struct jingle_session *session = ast_channel_tech_pvt(chan);
1805 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1811 /*! \brief Function called by core to stop a DTMF digit */
1812 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1814 struct jingle_session *session = ast_channel_tech_pvt(ast);
1817 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1823 /*! \brief Function called by core to actually start calling a remote party */
1824 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1826 struct jingle_session *session = ast_channel_tech_pvt(ast);
1828 ast_setstate(ast, AST_STATE_RING);
1830 /* Since we have no idea of the remote capabilities use ours for now */
1831 ast_format_cap_copy(session->jointcap, session->cap);
1833 /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1834 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1835 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1837 jingle_send_session_initiate(session);
1842 /*! \brief Function called by core to hang up a Jingle session */
1843 static int jingle_hangup(struct ast_channel *ast)
1845 struct jingle_session *session = ast_channel_tech_pvt(ast);
1849 if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1850 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1851 const char *reason = "success";
1854 /* Get the appropriate reason and send a session-terminate */
1855 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1856 if (jingle_reason_mappings[i].cause == cause) {
1857 reason = jingle_reason_mappings[i].reason;
1862 jingle_send_session_terminate(session, reason);
1865 ast_channel_tech_pvt_set(ast, NULL);
1866 session->owner = NULL;
1868 ao2_unlink(session->state->sessions, session);
1869 ao2_ref(session->state, -1);
1871 ao2_unlock(session);
1872 ao2_ref(session, -1);
1877 /*! \brief Function called by core to create a new outgoing Jingle session */
1878 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
1880 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1881 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1882 char *dialed, target[200] = "";
1883 struct ast_xmpp_buddy *buddy;
1884 struct jingle_session *session;
1885 struct ast_channel *chan;
1886 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1887 struct ast_rtp_engine_ice *ice;
1888 AST_DECLARE_APP_ARGS(args,
1890 AST_APP_ARG(target);
1893 /* We require at a minimum one audio format to be requested */
1894 if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
1895 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1896 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1900 if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1901 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1902 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1906 /* Parse the given dial string and validate the results */
1907 AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1909 if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1910 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1911 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1915 if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1916 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1917 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1921 ao2_lock(endpoint->state);
1923 /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1924 if (!endpoint->connection) {
1925 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1926 *cause = AST_CAUSE_SWITCH_CONGESTION;
1927 ao2_unlock(endpoint->state);
1931 /* Find the target in the roster so we can choose a resource */
1932 if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1933 struct ao2_iterator res;
1934 struct ast_xmpp_resource *resource;
1936 /* Iterate through finding the first viable Jingle capable resource */
1937 res = ao2_iterator_init(buddy->resources, 0);
1938 while ((resource = ao2_iterator_next(&res))) {
1939 if (resource->caps.jingle) {
1940 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1941 transport = JINGLE_TRANSPORT_ICE_UDP;
1943 } else if (resource->caps.google) {
1944 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1945 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1948 ao2_ref(resource, -1);
1950 ao2_iterator_destroy(&res);
1954 /* If the target is NOT in the roster use the provided target as-is */
1955 ast_copy_string(target, args.target, sizeof(target));
1958 ao2_unlock(endpoint->state);
1960 /* If no target was found we can't set up a session */
1961 if (ast_strlen_zero(target)) {
1962 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);
1963 *cause = AST_CAUSE_SWITCH_CONGESTION;
1967 if (!(session = jingle_alloc(endpoint, target, NULL))) {
1968 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1969 *cause = AST_CAUSE_SWITCH_CONGESTION;
1973 /* Update the transport if we learned what we should actually use */
1974 if (transport != JINGLE_TRANSPORT_NONE) {
1975 session->transport = transport;
1976 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
1979 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
1980 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
1981 *cause = AST_CAUSE_SWITCH_CONGESTION;
1982 ao2_ref(session, -1);
1986 /* If video was requested try to enable it on the session */
1987 if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
1988 jingle_enable_video(session);
1991 /* As this is outgoing set ourselves as controlling */
1992 if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
1993 ice->ice_lite(session->rtp);
1996 if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
1997 ice->ice_lite(session->vrtp);
2000 /* We purposely don't decrement the session here as there is a reference on the channel */
2001 ao2_link(endpoint->state->sessions, session);
2006 /*! \brief Helper function which handles content descriptions */
2007 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2009 char *media = iks_find_attrib(description, "media");
2010 struct ast_rtp_codecs codecs;
2012 int othercapability = 0;
2014 /* Google-V1 is always carrying audio, but just doesn't tell us so */
2015 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2017 } else if (ast_strlen_zero(media)) {
2018 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2019 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2023 /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2024 if (!strcasecmp(media, "audio")) {
2025 if (!ast_strlen_zero(name)) {
2026 ast_string_field_set(session, audio_name, name);
2028 *rtp = session->rtp;
2029 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
2030 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
2031 } else if (!strcasecmp(media, "video")) {
2032 if (!ast_strlen_zero(name)) {
2033 ast_string_field_set(session, video_name, name);
2036 jingle_enable_video(session);
2037 *rtp = session->vrtp;
2039 /* If video is not present cancel this session */
2040 if (!session->vrtp) {
2041 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2042 ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2046 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
2047 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
2049 /* Unknown media type */
2050 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2051 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2055 if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2056 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2057 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2061 /* Iterate the codecs updating the relevant RTP instance as we go */
2062 for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2063 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
2064 char *clockrate = iks_find_attrib(codec, "clockrate");
2065 int rtp_id, rtp_clockrate;
2067 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2068 ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
2070 if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2071 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2073 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2078 ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2079 ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
2081 if (ast_format_cap_is_empty(session->jointcap)) {
2082 /* We have no compatible codecs, so terminate the session appropriately */
2083 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2084 ast_rtp_codecs_payloads_destroy(&codecs);
2088 ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2089 ast_rtp_codecs_payloads_destroy(&codecs);
2094 /*! \brief Helper function which handles ICE-UDP transport information */
2095 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2097 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2098 char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2102 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2103 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2107 if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2108 ice->set_authentication(rtp, ufrag, pwd);
2111 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2112 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2113 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2114 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2115 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2116 char *type = iks_find_attrib(candidate, "type");
2117 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2119 struct ast_sockaddr remote_address = { { 0, } };
2121 /* If this candidate is incomplete skip it */
2122 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2123 ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2124 ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2125 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2126 ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2130 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2131 (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
2132 (sscanf(port, "%30d", &real_port) != 1)) {
2133 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2134 ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2138 local_candidate.foundation = foundation;
2139 local_candidate.transport = protocol;
2141 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2143 /* We only support IPv4 right now */
2144 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2148 ast_sockaddr_set_port(&local_candidate.address, real_port);
2150 if (!strcasecmp(type, "host")) {
2151 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2152 } else if (!strcasecmp(type, "srflx")) {
2153 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2154 } else if (!strcasecmp(type, "relay")) {
2155 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2160 /* Worst case use the first viable address */
2161 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2163 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2164 ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2167 ice->add_remote_candidate(rtp, &local_candidate);
2175 /*! \brief Helper function which handles Google transport information */
2176 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2178 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2182 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2183 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2187 /* If this session has not transitioned to the Google transport do so now */
2188 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2189 (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2190 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2193 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2196 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2197 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2198 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2199 char *protocol = iks_find_attrib(candidate, "protocol");
2201 struct ast_sockaddr target = { { 0, } };
2202 /* In Google land the combined value is 32 bytes */
2203 char combined[33] = "";
2205 /* If this is NOT actually a candidate just skip it */
2206 if (strcasecmp(iks_name(candidate), "candidate") &&
2207 strcasecmp(iks_name(candidate), "p:candidate") &&
2208 strcasecmp(iks_name(candidate), "ses:candidate")) {
2212 /* If this candidate is incomplete skip it */
2213 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2214 ast_strlen_zero(name)) {
2215 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2216 ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2220 /* We only support UDP so skip any other protocols */
2221 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2225 /* We only permit audio and video, not RTCP */
2226 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2230 /* Parse the target information so we can send a STUN request to the candidate */
2231 if (sscanf(port, "%30d", &real_port) != 1) {
2232 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2233 ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2236 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2237 ast_sockaddr_set_port(&target, real_port);
2239 /* Per the STUN support Google talk uses combine the two usernames */
2240 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2242 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2243 ast_rtp_instance_stun_request(rtp, &target, combined);
2250 * \brief Helper function which locates content stanzas and interprets them
2252 * \note The session *must not* be locked before calling this
2254 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2257 unsigned int changed = 0;
2258 struct ast_channel *chan;
2260 /* Look at the content in the session initiation */
2261 for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2263 struct ast_rtp_instance *rtp = NULL;
2264 iks *description, *transport;
2266 /* Ignore specific parts if they are known not to be useful */
2267 if (!strcmp(iks_name(content), "conference-info")) {
2271 name = iks_find_attrib(content, "name");
2273 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2274 /* If this content stanza has no name consider it invalid and move on */
2275 if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2276 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2277 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2281 /* Try to pre-populate which RTP instance this content is relevant to */
2282 if (!strcmp(session->audio_name, name)) {
2284 } else if (!strcmp(session->video_name, name)) {
2285 rtp = session->vrtp;
2288 /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2292 /* If description information is available use it */
2293 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2294 (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2295 (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2296 (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2297 (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2298 (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2299 /* If we failed to do something with the content description abort immediately */
2300 if (jingle_interpret_description(session, description, name, &rtp)) {
2304 /* If we successfully interpret the description then the codecs need updating */
2308 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2310 ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2311 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2315 /* If ICE UDP transport information is available use it */
2316 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2317 if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2320 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2321 (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2322 (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2323 (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2324 /* If Google transport support is available use it */
2325 if (jingle_interpret_google_transport(session, transport, rtp)) {
2328 } else if (iks_find(content, "transport")) {
2329 /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2330 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2331 ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2340 if ((chan = jingle_session_lock_full(session))) {
2341 struct ast_format fmt;
2343 ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
2344 ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
2345 ast_set_read_format(chan, &fmt);
2346 ast_set_write_format(chan, &fmt);
2348 ast_channel_unlock(chan);
2349 ast_channel_unref(chan);
2351 ao2_unlock(session);
2356 /*! \brief Handler function for the 'session-initiate' action */
2357 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2360 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2361 struct ast_channel *chan;
2365 /* This is a duplicate session setup, so respond accordingly */
2366 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2370 /* Retrieve the session identifier from the message, note that this may alter the transport */
2371 if ((sid = iks_find_attrib(pak->query, "id"))) {
2372 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2373 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2374 } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2375 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2379 /* Create a new local session */
2380 if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2381 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2385 /* If we determined that the transport should change as a result of how we got the SID change it */
2386 if (transport != JINGLE_TRANSPORT_NONE) {
2387 session->transport = transport;
2390 /* Create a new Asterisk channel using the above local session */
2391 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
2392 ao2_ref(session, -1);
2393 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2397 ao2_link(endpoint->state->sessions, session);
2399 ast_setstate(chan, AST_STATE_RING);
2400 res = ast_pbx_start(chan);
2403 case AST_PBX_FAILED:
2404 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2405 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2409 case AST_PBX_CALL_LIMIT:
2410 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2411 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2414 case AST_PBX_SUCCESS:
2415 jingle_send_response(endpoint->connection, pak);
2417 /* Only send a transport-info message if we successfully interpreted the available content */
2418 if (!jingle_interpret_content(session, pak)) {
2419 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2425 /*! \brief Handler function for the 'transport-info' action */
2426 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2429 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2430 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2434 jingle_interpret_content(session, pak);
2435 jingle_send_response(endpoint->connection, pak);
2438 /*! \brief Handler function for the 'session-accept' action */
2439 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2441 struct ast_channel *chan;
2444 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2445 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2450 jingle_interpret_content(session, pak);
2452 if ((chan = jingle_session_lock_full(session))) {
2453 ast_queue_control(chan, AST_CONTROL_ANSWER);
2454 ast_channel_unlock(chan);
2455 ast_channel_unref(chan);
2457 ao2_unlock(session);
2459 jingle_send_response(endpoint->connection, pak);
2462 /*! \brief Handler function for the 'session-info' action */
2463 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2465 struct ast_channel *chan;
2468 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2469 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2473 if (!(chan = jingle_session_lock_full(session))) {
2474 ao2_unlock(session);
2475 jingle_send_response(endpoint->connection, pak);
2479 if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2480 ast_queue_control(chan, AST_CONTROL_RINGING);
2481 if (ast_channel_state(chan) != AST_STATE_UP) {
2482 ast_setstate(chan, AST_STATE_RINGING);
2484 } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2485 ast_queue_control(chan, AST_CONTROL_HOLD);
2486 } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2487 ast_queue_control(chan, AST_CONTROL_UNHOLD);
2490 ast_channel_unlock(chan);
2491 ast_channel_unref(chan);
2492 ao2_unlock(session);
2494 jingle_send_response(endpoint->connection, pak);
2497 /*! \brief Handler function for the 'session-terminate' action */
2498 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2500 struct ast_channel *chan;
2502 int cause = AST_CAUSE_NORMAL;
2503 struct ast_control_pvt_cause_code *cause_code;
2504 int data_size = sizeof(*cause_code);
2507 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2508 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2512 if (!(chan = jingle_session_lock_full(session))) {
2513 ao2_unlock(session);
2514 jingle_send_response(endpoint->connection, pak);
2518 /* Pull the reason text from the session-terminate message and translate it into a cause code */
2519 if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2522 /* Size of the string making up the cause code is "Motif " + text */
2523 data_size += 6 + strlen(iks_name(text));
2524 cause_code = ast_malloc(data_size);
2526 /* Get the appropriate cause code mapping for this reason */
2527 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2528 if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2529 cause = jingle_reason_mappings[i].cause;
2534 /* Store the technology specific information */
2535 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2537 /* No technology specific information is available */
2538 cause_code = ast_malloc(data_size);
2541 ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2542 cause_code->ast_cause = cause;
2543 ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2544 ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2546 ast_free(cause_code);
2548 ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2549 ast_queue_hangup_with_cause(chan, cause);
2552 ast_channel_unlock(chan);
2553 ast_channel_unref(chan);
2554 ao2_unlock(session);
2556 jingle_send_response(endpoint->connection, pak);
2559 /*! \brief Callback for when a Jingle action is received from an endpoint */
2560 static int jingle_action_hook(void *data, ikspak *pak)
2563 const char *sid = NULL;
2564 struct jingle_session *session = NULL;
2565 struct jingle_endpoint *endpoint = data;
2568 /* We accept both Jingle and Google-V1 */
2569 if (!(action = iks_find_attrib(pak->query, "action")) &&
2570 !(action = iks_find_attrib(pak->query, "type"))) {
2571 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2572 * to a message that has no response hook. */
2573 return IKS_FILTER_EAT;
2576 /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2577 * does not permit us to make this completely safe. */
2578 ao2_ref(endpoint, +1);
2580 /* If a Jingle session identifier is present use it */
2581 if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2582 /* If a Google-V1 session identifier is present use it */
2583 sid = iks_find_attrib(pak->query, "id");
2586 /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2587 * this is required or not */
2588 if (!ast_strlen_zero(sid)) {
2589 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2592 /* If a session is present associate the callid with this thread */
2594 ast_callid_threadassoc_add(session->callid);
2597 /* Iterate through supported action handlers looking for one that is able to handle this */
2598 for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2599 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2600 jingle_action_handlers[i].handler(endpoint, session, pak);
2606 /* If no action handler is present for the action they sent us make it evident */
2608 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2611 /* If a session was successfully found for this message deref it now since the handler is done */
2613 ast_callid_threadassoc_remove();
2614 ao2_ref(session, -1);
2617 ao2_ref(endpoint, -1);
2619 return IKS_FILTER_EAT;
2622 /*! \brief Custom handler for groups */
2623 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2625 struct jingle_endpoint *endpoint = obj;
2627 if (!strcasecmp(var->name, "callgroup")) {
2628 endpoint->callgroup = ast_get_group(var->value);
2629 } else if (!strcasecmp(var->name, "pickupgroup")) {
2630 endpoint->pickupgroup = ast_get_group(var->value);
2638 /*! \brief Custom handler for connection */
2639 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2641 struct jingle_endpoint *endpoint = obj;
2643 /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2644 * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2646 if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2647 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2651 if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2652 IKS_RULE_TYPE, IKS_PAK_IQ,
2653 IKS_RULE_NS, JINGLE_NS,
2654 IKS_RULE_NS, GOOGLE_SESSION_NS,
2656 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2663 /*! \brief Custom handler for transport */
2664 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2666 struct jingle_endpoint *endpoint = obj;
2668 if (!strcasecmp(var->value, "ice-udp")) {
2669 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2670 } else if (!strcasecmp(var->value, "google")) {
2671 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2672 } else if (!strcasecmp(var->value, "google-v1")) {
2673 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2675 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2676 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2683 * \brief Load the module
2685 * Module loading including tests for configuration or dependencies.
2686 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2687 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2688 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2689 * configuration file or other non-critical problem return
2690 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2692 static int load_module(void)
2694 if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
2695 return AST_MODULE_LOAD_DECLINE;
2698 if (aco_info_init(&cfg_info)) {
2699 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2703 aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2704 aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2705 aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2706 aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2707 aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2708 aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2709 aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2710 aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
2711 aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
2712 aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2713 aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2714 aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2715 FLDSET(struct jingle_endpoint, maxicecandidates));
2716 aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2717 FLDSET(struct jingle_endpoint, maxpayloads));
2719 ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
2721 if (aco_process_config(&cfg_info, 0)) {
2722 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2723 aco_info_destroy(&cfg_info);
2724 return AST_MODULE_LOAD_DECLINE;
2727 if (!(sched = ast_sched_context_create())) {
2728 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2732 if (ast_sched_start_thread(sched)) {
2733 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2737 ast_rtp_glue_register(&jingle_rtp_glue);
2739 if (ast_channel_register(&jingle_tech)) {
2740 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2747 ast_rtp_glue_unregister(&jingle_rtp_glue);
2750 ast_sched_context_destroy(sched);
2753 aco_info_destroy(&cfg_info);
2755 return AST_MODULE_LOAD_FAILURE;
2758 /*! \brief Reload module */
2759 static int reload(void)
2761 return aco_process_config(&cfg_info, 1);
2764 /*! \brief Unload the jingle channel from Asterisk */
2765 static int unload_module(void)
2767 ast_channel_unregister(&jingle_tech);
2768 ast_rtp_glue_unregister(&jingle_rtp_glue);
2769 ast_sched_context_destroy(sched);
2770 aco_info_destroy(&cfg_info);
2771 ao2_global_obj_release(globals);
2776 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2777 .load = load_module,
2778 .unload = unload_module,
2780 .load_pri = AST_MODPRI_CHANNEL_DRIVER,