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 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
56 #include "asterisk/lock.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/config_options.h"
59 #include "asterisk/module.h"
60 #include "asterisk/pbx.h"
61 #include "asterisk/sched.h"
62 #include "asterisk/io.h"
63 #include "asterisk/rtp_engine.h"
64 #include "asterisk/acl.h"
65 #include "asterisk/callerid.h"
66 #include "asterisk/file.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/app.h"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/manager.h"
71 #include "asterisk/stringfields.h"
72 #include "asterisk/utils.h"
73 #include "asterisk/causes.h"
74 #include "asterisk/abstract_jb.h"
75 #include "asterisk/xmpp.h"
76 #include "asterisk/endpoints.h"
77 #include "asterisk/stasis_channels.h"
78 #include "asterisk/format_cache.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_format_cap *cap; /*!< Formats to use */
289 ast_group_t callgroup; /*!< Call group */
290 ast_group_t pickupgroup; /*!< Pickup group */
291 enum jingle_transport transport; /*!< Default transport to use on outgoing sessions */
292 struct jingle_endpoint_state *state; /*!< Endpoint state information */
295 /*! \brief Session which contains information about an active session */
296 struct jingle_session {
297 AST_DECLARE_STRING_FIELDS(
298 AST_STRING_FIELD(sid); /*!< Session identifier */
299 AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
300 AST_STRING_FIELD(video_name); /*!< Name of the video content */
302 struct jingle_endpoint_state *state; /*!< Endpoint we are associated with */
303 struct ast_xmpp_client *connection; /*!< Connection to use for traffic */
304 enum jingle_transport transport; /*!< Transport type to use for this session */
305 unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */
306 unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */
307 char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
308 char remote[XMPP_MAX_JIDLEN]; /*!< Identifier of the remote party */
309 iksrule *rule; /*!< Session matching rule */
310 struct ast_channel *owner; /*!< Master Channel */
311 struct ast_rtp_instance *rtp; /*!< RTP audio session */
312 struct ast_rtp_instance *vrtp; /*!< RTP video session */
313 struct ast_format_cap *cap; /*!< Local codec capabilities */
314 struct ast_format_cap *jointcap; /*!< Joint codec capabilities */
315 struct ast_format_cap *peercap; /*!< Peer codec capabilities */
316 unsigned int outgoing:1; /*!< Whether this is an outgoing leg or not */
317 unsigned int gone:1; /*!< In the eyes of Jingle this session is already gone */
318 ast_callid callid; /*!< Bound session call-id */
321 static const char channel_type[] = "Motif";
323 struct jingle_config {
324 struct ao2_container *endpoints; /*!< Configured endpoints */
327 static AO2_GLOBAL_OBJ_STATIC(globals);
329 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
331 /* \brief Asterisk core interaction functions */
332 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
333 static int jingle_sendtext(struct ast_channel *ast, const char *text);
334 static int jingle_digit_begin(struct ast_channel *ast, char digit);
335 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
336 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
337 static int jingle_hangup(struct ast_channel *ast);
338 static int jingle_answer(struct ast_channel *ast);
339 static struct ast_frame *jingle_read(struct ast_channel *ast);
340 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
341 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
342 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
343 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
345 /*! \brief Action handlers */
346 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
347 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
348 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
349 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
350 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
352 /*! \brief PBX interface structure for channel registration */
353 static struct ast_channel_tech jingle_tech = {
355 .description = "Motif Jingle Channel Driver",
356 .requester = jingle_request,
357 .send_text = jingle_sendtext,
358 .send_digit_begin = jingle_digit_begin,
359 .send_digit_end = jingle_digit_end,
361 .hangup = jingle_hangup,
362 .answer = jingle_answer,
364 .write = jingle_write,
365 .write_video = jingle_write,
366 .exception = jingle_read,
367 .indicate = jingle_indicate,
368 .fixup = jingle_fixup,
369 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
372 /*! \brief Defined handlers for different Jingle actions */
373 static const struct jingle_action_handler {
375 void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
376 } jingle_action_handlers[] = {
378 { "session-initiate", jingle_action_session_initiate, },
379 { "transport-info", jingle_action_transport_info, },
380 { "session-accept", jingle_action_session_accept, },
381 { "session-info", jingle_action_session_info, },
382 { "session-terminate", jingle_action_session_terminate, },
383 /* Google-V1 actions */
384 { "initiate", jingle_action_session_initiate, },
385 { "candidates", jingle_action_transport_info, },
386 { "accept", jingle_action_session_accept, },
387 { "terminate", jingle_action_session_terminate, },
388 { "reject", jingle_action_session_terminate, },
391 /*! \brief Reason text <-> cause code mapping */
392 static const struct jingle_reason_mapping {
395 } jingle_reason_mappings[] = {
396 { "busy", AST_CAUSE_BUSY, },
397 { "cancel", AST_CAUSE_CALL_REJECTED, },
398 { "connectivity-error", AST_CAUSE_INTERWORKING, },
399 { "decline", AST_CAUSE_CALL_REJECTED, },
400 { "expired", AST_CAUSE_NO_USER_RESPONSE, },
401 { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
402 { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
403 { "general-error", AST_CAUSE_CONGESTION, },
404 { "gone", AST_CAUSE_NORMAL_CLEARING, },
405 { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
406 { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
407 { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
408 { "success", AST_CAUSE_NORMAL_CLEARING, },
409 { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
410 { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
411 { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
414 /*! \brief Hashing function for Jingle sessions */
415 static int jingle_session_hash(const void *obj, const int flags)
417 const struct jingle_session *session = obj;
418 const char *sid = obj;
420 return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
423 /*! \brief Comparator function for Jingle sessions */
424 static int jingle_session_cmp(void *obj, void *arg, int flags)
426 struct jingle_session *session1 = obj, *session2 = arg;
427 const char *sid = arg;
429 return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
432 /*! \brief Destructor for Jingle endpoint state */
433 static void jingle_endpoint_state_destructor(void *obj)
435 struct jingle_endpoint_state *state = obj;
437 ao2_ref(state->sessions, -1);
440 /*! \brief Destructor for Jingle endpoints */
441 static void jingle_endpoint_destructor(void *obj)
443 struct jingle_endpoint *endpoint = obj;
445 if (endpoint->rule) {
446 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
449 if (endpoint->connection) {
450 ast_xmpp_client_unref(endpoint->connection);
453 ao2_cleanup(endpoint->cap);
454 ao2_ref(endpoint->state, -1);
456 ast_string_field_free_memory(endpoint);
459 /*! \brief Find function for Jingle endpoints */
460 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
462 return ao2_find(tmp_container, category, OBJ_KEY);
465 /*! \brief Allocator function for Jingle endpoint state */
466 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
468 struct jingle_endpoint_state *state;
470 if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
474 if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
482 /*! \brief State find/create function */
483 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
485 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
486 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
488 if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
489 return jingle_endpoint_state_create();
492 ao2_ref(endpoint->state, +1);
493 return endpoint->state;
496 /*! \brief Allocator function for Jingle endpoints */
497 static void *jingle_endpoint_alloc(const char *cat)
499 struct jingle_endpoint *endpoint;
501 if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
505 if (ast_string_field_init(endpoint, 512)) {
506 ao2_ref(endpoint, -1);
510 if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
511 ao2_ref(endpoint, -1);
515 ast_string_field_set(endpoint, name, cat);
517 endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
518 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
523 /*! \brief Hashing function for Jingle endpoints */
524 static int jingle_endpoint_hash(const void *obj, const int flags)
526 const struct jingle_endpoint *endpoint = obj;
527 const char *name = obj;
529 return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
532 /*! \brief Comparator function for Jingle endpoints */
533 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
535 struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
536 const char *name = arg;
538 return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
541 static struct aco_type endpoint_option = {
544 .category_match = ACO_BLACKLIST_EXACT,
545 .category = "general",
546 .item_alloc = jingle_endpoint_alloc,
547 .item_find = jingle_endpoint_find,
548 .item_offset = offsetof(struct jingle_config, endpoints),
551 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
553 struct aco_file jingle_conf = {
554 .filename = "motif.conf",
555 .types = ACO_TYPES(&endpoint_option),
558 /*! \brief Destructor for Jingle sessions */
559 static void jingle_session_destructor(void *obj)
561 struct jingle_session *session = obj;
564 iks_filter_remove_rule(session->connection->filter, session->rule);
567 if (session->connection) {
568 ast_xmpp_client_unref(session->connection);
572 ast_rtp_instance_stop(session->rtp);
573 ast_rtp_instance_destroy(session->rtp);
577 ast_rtp_instance_stop(session->vrtp);
578 ast_rtp_instance_destroy(session->vrtp);
581 ao2_cleanup(session->cap);
582 ao2_cleanup(session->jointcap);
583 ao2_cleanup(session->peercap);
585 ast_string_field_free_memory(session);
588 /*! \brief Destructor called when module configuration goes away */
589 static void jingle_config_destructor(void *obj)
591 struct jingle_config *cfg = obj;
592 ao2_cleanup(cfg->endpoints);
595 /*! \brief Allocator called when module configuration should appear */
596 static void *jingle_config_alloc(void)
598 struct jingle_config *cfg;
600 if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
604 if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
612 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
613 .files = ACO_FILES(&jingle_conf),
616 /*! \brief Function called by RTP engine to get local RTP peer */
617 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
619 struct jingle_session *session = ast_channel_tech_pvt(chan);
620 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
623 return AST_RTP_GLUE_RESULT_FORBID;
626 ao2_ref(session->rtp, +1);
627 *instance = session->rtp;
632 /*! \brief Function called by RTP engine to get peer capabilities */
633 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
637 /*! \brief Function called by RTP engine to change where the remote party should send media */
638 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)
643 /*! \brief Local glue for interacting with the RTP engine core */
644 static struct ast_rtp_glue jingle_rtp_glue = {
646 .get_rtp_info = jingle_get_rtp_peer,
647 .get_codec = jingle_get_codec,
648 .update_peer = jingle_set_rtp_peer,
651 /*! \brief Set the channel owner on the \ref jingle_session object and related objects */
652 static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
654 session->owner = chan;
656 ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
659 ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
663 /*! \brief Internal helper function which enables video support on a sesson if possible */
664 static void jingle_enable_video(struct jingle_session *session)
666 struct ast_sockaddr tmp;
667 struct ast_rtp_engine_ice *ice;
669 /* If video is already present don't do anything */
674 /* If there are no configured video codecs do not turn video support on, it just won't work */
675 if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) {
679 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
681 if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
685 ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
686 ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
687 ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
688 ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
689 ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp),
690 ast_format_cap_get_framing(session->cap));
691 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
692 ice->stop(session->vrtp);
696 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
697 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
699 struct jingle_session *session;
701 struct ast_sockaddr tmp;
703 if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
707 callid = ast_read_threadstorage_callid();
708 session->callid = (callid ? callid : ast_create_callid());
710 if (ast_string_field_init(session, 512)) {
711 ao2_ref(session, -1);
715 if (!ast_strlen_zero(from)) {
716 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
717 ast_copy_string(session->remote, from, sizeof(session->remote));
720 if (ast_strlen_zero(sid)) {
721 ast_string_field_build(session, sid, "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
722 session->outgoing = 1;
723 ast_string_field_set(session, audio_name, "audio");
724 ast_string_field_set(session, video_name, "video");
726 ast_string_field_set(session, sid, sid);
729 ao2_ref(endpoint->state, +1);
730 session->state = endpoint->state;
731 ao2_ref(endpoint->connection, +1);
732 session->connection = endpoint->connection;
733 session->transport = endpoint->transport;
735 if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
736 !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
737 !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
739 ao2_ref(session, -1);
743 ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN);
745 /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
746 * that we want IPv4 */
747 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
749 /* Sessions always carry audio, but video is optional so don't enable it here */
750 if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
751 ao2_ref(session, -1);
754 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
755 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
757 session->maxicecandidates = endpoint->maxicecandidates;
758 session->maxpayloads = endpoint->maxpayloads;
763 /*! \brief Function called to create a new Jingle Asterisk channel */
764 static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
766 struct ast_channel *chan;
767 const char *str = S_OR(title, session->remote);
768 struct ast_format_cap *caps;
769 struct ast_format *tmpfmt;
771 if (!ast_format_cap_count(session->cap)) {
775 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
780 if (!(chan = ast_channel_alloc_with_endpoint(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, endpoint->connection->endpoint, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
785 ast_channel_stage_snapshot(chan);
787 ast_channel_tech_set(chan, &jingle_tech);
788 ast_channel_tech_pvt_set(chan, session);
789 jingle_set_owner(session, chan);
791 ast_channel_callid_set(chan, session->callid);
793 ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN);
794 ast_channel_nativeformats_set(chan, caps);
798 struct ast_rtp_engine_ice *ice;
800 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
801 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
802 ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp),
803 ast_format_cap_get_framing(session->cap));
805 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
806 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
807 (ice = ast_rtp_instance_get_ice(session->rtp))) {
808 /* We stop built in ICE support because we need to fall back to old old old STUN support */
809 ice->stop(session->rtp);
813 if (state == AST_STATE_RING) {
814 ast_channel_rings_set(chan, 1);
817 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
819 tmpfmt = ast_format_cap_get_format(session->cap, 0);
820 ast_channel_set_writeformat(chan, tmpfmt);
821 ast_channel_set_rawwriteformat(chan, tmpfmt);
822 ast_channel_set_readformat(chan, tmpfmt);
823 ast_channel_set_rawreadformat(chan, tmpfmt);
828 ast_channel_callgroup_set(chan, endpoint->callgroup);
829 ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
831 if (!ast_strlen_zero(endpoint->accountcode)) {
832 ast_channel_accountcode_set(chan, endpoint->accountcode);
835 if (!ast_strlen_zero(endpoint->language)) {
836 ast_channel_language_set(chan, endpoint->language);
839 if (!ast_strlen_zero(endpoint->musicclass)) {
840 ast_channel_musicclass_set(chan, endpoint->musicclass);
843 ast_channel_context_set(chan, endpoint->context);
844 if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
845 ast_channel_exten_set(chan, endpoint->name);
847 ast_channel_exten_set(chan, "s");
849 ast_channel_priority_set(chan, 1);
851 ao2_unlock(endpoint);
853 ast_channel_stage_snapshot_done(chan);
854 ast_channel_unlock(chan);
859 /*! \brief Internal helper function which sends a response */
860 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
864 if (!(response = iks_new("iq"))) {
865 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
869 iks_insert_attrib(response, "type", "result");
870 iks_insert_attrib(response, "from", connection->jid->full);
871 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
872 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
874 ast_xmpp_client_send(connection, response);
876 iks_delete(response);
879 /*! \brief Internal helper function which sends an error response */
880 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
882 iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
884 if (!(response = iks_new("iq")) ||
885 !(error = iks_new("error")) ||
886 !(reason = iks_new(reasonstr))) {
887 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
891 iks_insert_attrib(response, "type", "error");
892 iks_insert_attrib(response, "from", connection->jid->full);
893 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
894 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
896 iks_insert_attrib(error, "type", type);
897 iks_insert_node(error, reason);
899 if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
900 iks_insert_node(error, reason2);
903 iks_insert_node(response, error);
905 ast_xmpp_client_send(connection, response);
910 iks_delete(response);
913 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
914 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
916 struct ast_rtp_engine_ice *ice;
917 struct ao2_container *local_candidates;
918 struct ao2_iterator it;
919 struct ast_rtp_engine_ice_candidate *candidate;
922 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
923 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
927 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
928 iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
929 iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
931 it = ao2_iterator_init(local_candidates, 0);
933 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
934 iks *local_candidate;
937 if (!(local_candidate = iks_new("candidate"))) {
939 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
943 snprintf(tmp, sizeof(tmp), "%u", candidate->id);
944 iks_insert_attrib(local_candidate, "component", tmp);
945 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
946 iks_insert_attrib(local_candidate, "foundation", tmp);
947 iks_insert_attrib(local_candidate, "generation", "0");
948 iks_insert_attrib(local_candidate, "network", "0");
949 snprintf(tmp, sizeof(tmp), "%04lx", (unsigned long)(ast_random() & 0xffff));
950 iks_insert_attrib(local_candidate, "id", tmp);
951 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
952 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
953 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
954 iks_insert_attrib(local_candidate, "priority", tmp);
955 iks_insert_attrib(local_candidate, "protocol", "udp");
957 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
958 iks_insert_attrib(local_candidate, "type", "host");
959 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
960 iks_insert_attrib(local_candidate, "type", "srflx");
961 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
962 iks_insert_attrib(local_candidate, "type", "relay");
965 iks_insert_node(transport, local_candidate);
966 candidates[i++] = local_candidate;
969 ao2_iterator_destroy(&it);
970 ao2_ref(local_candidates, -1);
975 /*! \brief Internal helper function which adds Google candidates to a transport node */
976 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)
978 struct ast_rtp_engine_ice *ice;
979 struct ao2_container *local_candidates;
980 struct ao2_iterator it;
981 struct ast_rtp_engine_ice_candidate *candidate;
984 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
985 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
989 if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
990 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
993 it = ao2_iterator_init(local_candidates, 0);
995 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
996 iks *local_candidate;
997 /* In Google land a username is 16 bytes, explicitly */
1000 if (!(local_candidate = iks_new("candidate"))) {
1002 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
1006 if (candidate->id == 1) {
1007 iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
1008 } else if (candidate->id == 2) {
1009 iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
1011 iks_delete(local_candidate);
1015 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
1016 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
1018 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
1019 iks_insert_attrib(local_candidate, "preference", "0.95");
1020 iks_insert_attrib(local_candidate, "type", "local");
1021 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
1022 iks_insert_attrib(local_candidate, "preference", "0.9");
1023 iks_insert_attrib(local_candidate, "type", "stun");
1026 iks_insert_attrib(local_candidate, "protocol", "udp");
1027 iks_insert_attrib(local_candidate, "network", "0");
1028 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
1029 iks_insert_attrib(local_candidate, "username", ufrag);
1030 iks_insert_attrib(local_candidate, "generation", "0");
1032 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
1033 iks_insert_attrib(local_candidate, "password", "");
1034 iks_insert_attrib(local_candidate, "foundation", "0");
1035 iks_insert_attrib(local_candidate, "component", "1");
1037 iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
1040 /* You may notice a lack of relay support up above - this is because we don't support it for use with
1041 * the Google talk transport due to their arcane support. */
1043 iks_insert_node(transport, local_candidate);
1044 candidates[i++] = local_candidate;
1047 ao2_iterator_destroy(&it);
1048 ao2_ref(local_candidates, -1);
1053 /*! \brief Internal function which sends a session-terminate message */
1054 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
1056 iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
1058 if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
1059 !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
1060 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
1064 iks_insert_attrib(iq, "to", session->remote);
1065 iks_insert_attrib(iq, "type", "set");
1066 iks_insert_attrib(iq, "id", session->connection->mid);
1067 ast_xmpp_increment_mid(session->connection->mid);
1069 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1070 iks_insert_attrib(jingle, "type", "terminate");
1071 iks_insert_attrib(jingle, "id", session->sid);
1072 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1073 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1075 iks_insert_attrib(jingle, "action", "session-terminate");
1076 iks_insert_attrib(jingle, "sid", session->sid);
1077 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1080 iks_insert_node(iq, jingle);
1081 iks_insert_node(jingle, reason);
1082 iks_insert_node(reason, text);
1084 ast_xmpp_client_send(session->connection, iq);
1093 /*! \brief Internal function which sends a session-info message */
1094 static void jingle_send_session_info(struct jingle_session *session, const char *info)
1096 iks *iq = NULL, *jingle = NULL, *text = NULL;
1098 /* Google-V1 has no way to send informational messages so don't even bother trying */
1099 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1103 if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
1104 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
1108 iks_insert_attrib(iq, "to", session->remote);
1109 iks_insert_attrib(iq, "type", "set");
1110 iks_insert_attrib(iq, "id", session->connection->mid);
1111 ast_xmpp_increment_mid(session->connection->mid);
1113 iks_insert_attrib(jingle, "action", "session-info");
1114 iks_insert_attrib(jingle, "sid", session->sid);
1115 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1116 iks_insert_node(iq, jingle);
1117 iks_insert_node(jingle, text);
1119 ast_xmpp_client_send(session->connection, iq);
1129 * \brief Locks both pvt and pvt owner if owner is present.
1131 * \note This function gives a ref to pvt->owner if it is present and locked.
1132 * This reference must be decremented after pvt->owner is unlocked.
1134 * \note This function will never give you up,
1135 * \note This function will never let you down.
1136 * \note This function will run around and desert you.
1138 * \pre pvt is not locked
1139 * \post pvt is locked
1140 * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
1142 * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
1144 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
1146 struct ast_channel *chan;
1148 /* Locking is simple when it is done right. If you see a deadlock resulting
1149 * in this function, it is not this function's fault, Your problem exists elsewhere.
1150 * This function is perfect... seriously. */
1152 /* First, get the channel and grab a reference to it */
1156 /* The channel can not go away while we hold the pvt lock.
1157 * Give the channel a ref so it will not go away after we let
1158 * the pvt lock go. */
1159 ast_channel_ref(chan);
1161 /* no channel, return pvt locked */
1165 /* We had to hold the pvt lock while getting a ref to the owner channel
1166 * but now we have to let this lock go in order to preserve proper
1167 * locking order when grabbing the channel lock */
1170 /* Look, no deadlock avoidance, hooray! */
1171 ast_channel_lock(chan);
1173 if (pvt->owner == chan) {
1178 /* If the owner changed while everything was unlocked, no problem,
1179 * just start over and everthing will work. This is rare, do not be
1180 * confused by this loop and think this it is an expensive operation.
1181 * The majority of the calls to this function will never involve multiple
1182 * executions of this loop. */
1183 ast_channel_unlock(chan);
1184 ast_channel_unref(chan);
1188 /* If owner exists, it is locked and reffed */
1192 /*! \brief Helper function which queues a hangup frame with cause code */
1193 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1195 struct ast_channel *chan;
1197 if ((chan = jingle_session_lock_full(session))) {
1198 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1199 ast_queue_hangup_with_cause(chan, cause);
1200 ast_channel_unlock(chan);
1201 ast_channel_unref(chan);
1203 ao2_unlock(session);
1206 /*! \brief Internal function which sends a transport-info message */
1207 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1209 iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1210 iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1213 if (!(iq = iks_new("iq")) ||
1214 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1216 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1217 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1221 memset(audio_candidates, 0, sizeof(audio_candidates));
1222 memset(video_candidates, 0, sizeof(video_candidates));
1224 iks_insert_attrib(iq, "from", session->connection->jid->full);
1225 iks_insert_attrib(iq, "to", from);
1226 iks_insert_attrib(iq, "type", "set");
1227 iks_insert_attrib(iq, "id", session->connection->mid);
1228 ast_xmpp_increment_mid(session->connection->mid);
1230 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1231 iks_insert_attrib(jingle, "type", "candidates");
1232 iks_insert_attrib(jingle, "id", session->sid);
1233 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1234 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1236 iks_insert_attrib(jingle, "action", "transport-info");
1237 iks_insert_attrib(jingle, "sid", session->sid);
1238 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1240 iks_insert_node(iq, jingle);
1243 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1244 /* V1 protocol has the candidates directly in the session */
1245 res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1246 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1247 iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1248 iks_insert_attrib(audio, "name", session->audio_name);
1249 iks_insert_node(jingle, audio);
1250 iks_insert_node(audio, audio_transport);
1252 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1253 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1254 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1255 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1256 session->maxicecandidates);
1263 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1264 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1265 iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1266 iks_insert_attrib(video, "name", session->video_name);
1267 iks_insert_node(jingle, video);
1268 iks_insert_node(video, video_transport);
1270 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1271 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1272 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1273 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1274 session->maxicecandidates);
1282 ast_xmpp_client_send(session->connection, iq);
1284 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1287 /* Clean up after ourselves */
1288 for (i = 0; i < session->maxicecandidates; i++) {
1289 iks_delete(video_candidates[i]);
1290 iks_delete(audio_candidates[i]);
1293 iks_delete(video_transport);
1295 iks_delete(audio_transport);
1301 /*! \brief Internal helper function which adds payloads to a description */
1302 static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_media_type type)
1304 int x = 0, i = 0, res = 0;
1306 for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) {
1307 struct ast_format *format = ast_format_cap_get_format(session->jointcap, x);
1312 if (ast_format_get_type(format) != type) {
1313 ao2_ref(format, -1);
1317 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) ||
1318 (!(payload = iks_new("payload-type")))) {
1319 ao2_ref(format, -1);
1323 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1324 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1327 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1328 iks_insert_attrib(payload, "id", tmp);
1329 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
1330 iks_insert_attrib(payload, "channels", "1");
1332 if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) &&
1333 ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1334 iks_insert_attrib(payload, "clockrate", "16000");
1336 snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0));
1337 iks_insert_attrib(payload, "clockrate", tmp);
1340 if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1343 /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1344 if ((parameter = iks_new("parameter"))) {
1345 iks_insert_attrib(parameter, "name", "width");
1346 iks_insert_attrib(parameter, "value", "640");
1347 iks_insert_node(payload, parameter);
1349 if ((parameter = iks_new("parameter"))) {
1350 iks_insert_attrib(parameter, "name", "height");
1351 iks_insert_attrib(parameter, "value", "480");
1352 iks_insert_node(payload, parameter);
1354 if ((parameter = iks_new("parameter"))) {
1355 iks_insert_attrib(parameter, "name", "framerate");
1356 iks_insert_attrib(parameter, "value", "30");
1357 iks_insert_node(payload, parameter);
1361 iks_insert_node(description, payload);
1362 payloads[i++] = payload;
1364 ao2_ref(format, -1);
1366 /* If this is for audio and there is room for RFC2833 add it in */
1367 if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) {
1370 if ((payload = iks_new("payload-type"))) {
1371 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1372 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1375 iks_insert_attrib(payload, "id", "101");
1376 iks_insert_attrib(payload, "name", "telephone-event");
1377 iks_insert_attrib(payload, "channels", "1");
1378 iks_insert_attrib(payload, "clockrate", "8000");
1379 iks_insert_node(description, payload);
1380 payloads[i++] = payload;
1387 /*! \brief Helper function which adds content to a description */
1388 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1389 const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads)
1393 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1394 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1395 iks_insert_attrib(content, "name", name);
1396 iks_insert_node(jingle, content);
1398 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1399 if (type == AST_MEDIA_TYPE_AUDIO) {
1400 iks_insert_attrib(description, "media", "audio");
1401 } else if (type == AST_MEDIA_TYPE_VIDEO) {
1402 iks_insert_attrib(description, "media", "video");
1406 iks_insert_node(content, description);
1408 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1409 iks_insert_node(jingle, description);
1412 if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1413 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1414 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1415 iks_insert_node(content, transport);
1416 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1417 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1418 iks_insert_node(content, transport);
1425 /*! \brief Internal function which sends a complete session message */
1426 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1428 iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1429 iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1430 iks *audio_transport = NULL, *video_transport = NULL;
1433 if (!(iq = iks_new("iq")) ||
1434 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1435 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1440 memset(audio_payloads, 0, sizeof(audio_payloads));
1441 memset(video_payloads, 0, sizeof(video_payloads));
1443 iks_insert_attrib(iq, "from", session->connection->jid->full);
1444 iks_insert_attrib(iq, "to", session->remote);
1445 iks_insert_attrib(iq, "type", "set");
1446 iks_insert_attrib(iq, "id", session->connection->mid);
1447 ast_xmpp_increment_mid(session->connection->mid);
1449 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1450 iks_insert_attrib(jingle, "type", action);
1451 iks_insert_attrib(jingle, "id", session->sid);
1452 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1454 iks_insert_attrib(jingle, "action", action);
1455 iks_insert_attrib(jingle, "sid", session->sid);
1456 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1459 if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1460 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1463 iks_insert_node(iq, jingle);
1465 if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1466 (audio_transport = iks_new("transport"))) {
1467 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1468 AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads);
1470 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1474 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1475 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1476 (video_transport = iks_new("transport"))) {
1477 res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1478 AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads);
1480 ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1486 ast_xmpp_client_send(session->connection, iq);
1488 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1491 iks_delete(video_transport);
1492 iks_delete(audio_transport);
1494 for (i = 0; i < session->maxpayloads; i++) {
1495 iks_delete(video_payloads[i]);
1496 iks_delete(audio_payloads[i]);
1499 iks_delete(video_description);
1501 iks_delete(audio_description);
1507 /*! \brief Internal function which sends a session-inititate message */
1508 static void jingle_send_session_initiate(struct jingle_session *session)
1510 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1513 /*! \brief Internal function which sends a session-accept message */
1514 static void jingle_send_session_accept(struct jingle_session *session)
1516 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1519 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1520 static int jingle_outgoing_hook(void *data, ikspak *pak)
1522 struct jingle_session *session = data;
1523 iks *error = iks_find(pak->x, "error"), *redirect;
1525 /* In all cases this hook is done with */
1526 iks_filter_remove_rule(session->connection->filter, session->rule);
1527 session->rule = NULL;
1529 ast_callid_threadassoc_add(session->callid);
1531 /* If no error occurred they accepted our session-initiate message happily */
1533 struct ast_channel *chan;
1535 if ((chan = jingle_session_lock_full(session))) {
1536 ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1537 ast_channel_unlock(chan);
1538 ast_channel_unref(chan);
1540 ao2_unlock(session);
1542 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1547 /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1550 /* Map the error we received to an appropriate cause code and hang up the channel */
1551 if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1552 iks *to = iks_child(redirect);
1555 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1556 /* Make the xmpp: go away if it is present */
1557 if (!strncmp(target, "xmpp:", 5)) {
1561 /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1562 ast_copy_string(session->remote, target, sizeof(session->remote));
1564 /* Add a new hook so we can get the status of redirected session */
1565 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1566 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1568 jingle_send_session_initiate(session);
1572 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1574 } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1575 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1576 } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1577 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1578 } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1579 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1580 } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1581 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1582 } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1583 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1584 session->transport--;
1586 /* If we still have a viable transport mechanism re-send the session-initiate */
1587 if (session->transport != JINGLE_TRANSPORT_NONE) {
1588 struct ast_rtp_engine_ice *ice;
1590 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1591 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1592 (ice = ast_rtp_instance_get_ice(session->rtp))) {
1593 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1594 ice->stop(session->rtp);
1597 /* Re-send the message to the *original* target and not a redirected one */
1598 ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1600 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1601 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1603 jingle_send_session_initiate(session);
1607 /* Otherwise we have exhausted all transports */
1608 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1611 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1615 ast_callid_threadassoc_remove();
1617 return IKS_FILTER_EAT;
1620 /*! \brief Function called by core when we should answer a Jingle session */
1621 static int jingle_answer(struct ast_channel *ast)
1623 struct jingle_session *session = ast_channel_tech_pvt(ast);
1625 /* The channel has already been answered so we don't need to do anything */
1626 if (ast_channel_state(ast) == AST_STATE_UP) {
1630 jingle_send_session_accept(session);
1635 /*! \brief Function called by core to read any waiting frames */
1636 static struct ast_frame *jingle_read(struct ast_channel *ast)
1638 struct jingle_session *session = ast_channel_tech_pvt(ast);
1639 struct ast_frame *frame = &ast_null_frame;
1641 switch (ast_channel_fdno(ast)) {
1644 frame = ast_rtp_instance_read(session->rtp, 0);
1649 frame = ast_rtp_instance_read(session->rtp, 1);
1653 if (session->vrtp) {
1654 frame = ast_rtp_instance_read(session->vrtp, 0);
1658 if (session->vrtp) {
1659 frame = ast_rtp_instance_read(session->vrtp, 1);
1666 if (frame && frame->frametype == AST_FRAME_VOICE &&
1667 ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1668 if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1669 ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1670 ast_format_get_name(frame->subclass.format), ast_channel_name(ast));
1672 frame = &ast_null_frame;
1674 struct ast_format_cap *caps;
1676 ast_debug(1, "Oooh, format changed to %s\n",
1677 ast_format_get_name(frame->subclass.format));
1679 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1681 ast_format_cap_append(caps, frame->subclass.format, 0);
1682 ast_channel_nativeformats_set(ast, caps);
1685 ast_set_read_format(ast, ast_channel_readformat(ast));
1686 ast_set_write_format(ast, ast_channel_writeformat(ast));
1693 /*! \brief Function called by core to write frames */
1694 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1696 struct jingle_session *session = ast_channel_tech_pvt(ast);
1699 switch (frame->frametype) {
1700 case AST_FRAME_VOICE:
1701 if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1702 struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1704 ast_log(LOG_WARNING,
1705 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1706 ast_format_get_name(frame->subclass.format),
1707 ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
1708 ast_format_get_name(ast_channel_readformat(ast)),
1709 ast_format_get_name(ast_channel_writeformat(ast)));
1712 if (session && session->rtp) {
1713 res = ast_rtp_instance_write(session->rtp, frame);
1716 case AST_FRAME_VIDEO:
1717 if (session && session->vrtp) {
1718 res = ast_rtp_instance_write(session->vrtp, frame);
1722 ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
1730 /*! \brief Function called by core to change the underlying owner channel */
1731 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1733 struct jingle_session *session = ast_channel_tech_pvt(newchan);
1737 jingle_set_owner(session, newchan);
1739 ao2_unlock(session);
1744 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1745 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1747 struct jingle_session *session = ast_channel_tech_pvt(ast);
1750 switch (condition) {
1751 case AST_CONTROL_RINGING:
1752 if (ast_channel_state(ast) == AST_STATE_RING) {
1753 jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1758 case AST_CONTROL_BUSY:
1759 if (ast_channel_state(ast) != AST_STATE_UP) {
1760 ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1761 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1766 case AST_CONTROL_CONGESTION:
1767 if (ast_channel_state(ast) != AST_STATE_UP) {
1768 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1769 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1774 case AST_CONTROL_INCOMPLETE:
1775 if (ast_channel_state(ast) != AST_STATE_UP) {
1776 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1777 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1780 case AST_CONTROL_HOLD:
1781 ast_moh_start(ast, data, NULL);
1783 case AST_CONTROL_UNHOLD:
1786 case AST_CONTROL_SRCUPDATE:
1788 ast_rtp_instance_update_source(session->rtp);
1791 case AST_CONTROL_SRCCHANGE:
1793 ast_rtp_instance_change_source(session->rtp);
1796 case AST_CONTROL_VIDUPDATE:
1797 case AST_CONTROL_UPDATE_RTP_PEER:
1798 case AST_CONTROL_CONNECTED_LINE:
1800 case AST_CONTROL_PVT_CAUSE_CODE:
1801 case AST_CONTROL_MASQUERADE_NOTIFY:
1806 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1813 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1814 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1816 struct jingle_session *session = ast_channel_tech_pvt(chan);
1818 return ast_xmpp_client_send_message(session->connection, session->remote, text);
1821 /*! \brief Function called by core to start a DTMF digit */
1822 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1824 struct jingle_session *session = ast_channel_tech_pvt(chan);
1827 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1833 /*! \brief Function called by core to stop a DTMF digit */
1834 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1836 struct jingle_session *session = ast_channel_tech_pvt(ast);
1839 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1845 /*! \brief Function called by core to actually start calling a remote party */
1846 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1848 struct jingle_session *session = ast_channel_tech_pvt(ast);
1850 ast_setstate(ast, AST_STATE_RING);
1852 /* Since we have no idea of the remote capabilities use ours for now */
1853 ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN);
1855 /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1856 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1857 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1859 jingle_send_session_initiate(session);
1864 /*! \brief Function called by core to hang up a Jingle session */
1865 static int jingle_hangup(struct ast_channel *ast)
1867 struct jingle_session *session = ast_channel_tech_pvt(ast);
1871 if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1872 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1873 const char *reason = "success";
1876 /* Get the appropriate reason and send a session-terminate */
1877 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1878 if (jingle_reason_mappings[i].cause == cause) {
1879 reason = jingle_reason_mappings[i].reason;
1884 jingle_send_session_terminate(session, reason);
1887 ast_channel_tech_pvt_set(ast, NULL);
1888 jingle_set_owner(session, NULL);
1890 ao2_unlink(session->state->sessions, session);
1891 ao2_ref(session->state, -1);
1893 ao2_unlock(session);
1894 ao2_ref(session, -1);
1899 /*! \brief Function called by core to create a new outgoing Jingle session */
1900 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
1902 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1903 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1904 char *dialed, target[1024] = "";
1905 struct ast_xmpp_buddy *buddy;
1906 struct jingle_session *session;
1907 struct ast_channel *chan;
1908 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1909 struct ast_rtp_engine_ice *ice;
1910 AST_DECLARE_APP_ARGS(args,
1912 AST_APP_ARG(target);
1915 /* We require at a minimum one audio format to be requested */
1916 if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) {
1917 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1918 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1922 if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1923 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1924 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1928 /* Parse the given dial string and validate the results */
1929 AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1931 if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1932 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1933 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1937 if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1938 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1939 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1943 ao2_lock(endpoint->state);
1945 /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1946 if (!endpoint->connection) {
1947 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1948 *cause = AST_CAUSE_SWITCH_CONGESTION;
1949 ao2_unlock(endpoint->state);
1953 /* Find the target in the roster so we can choose a resource */
1954 if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1955 struct ao2_iterator res;
1956 struct ast_xmpp_resource *resource;
1958 /* Iterate through finding the first viable Jingle capable resource */
1959 res = ao2_iterator_init(buddy->resources, 0);
1960 while ((resource = ao2_iterator_next(&res))) {
1961 if (resource->caps.jingle) {
1962 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1963 transport = JINGLE_TRANSPORT_ICE_UDP;
1965 } else if (resource->caps.google) {
1966 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1967 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1970 ao2_ref(resource, -1);
1972 ao2_iterator_destroy(&res);
1976 /* If the target is NOT in the roster use the provided target as-is */
1977 ast_copy_string(target, args.target, sizeof(target));
1980 ao2_unlock(endpoint->state);
1982 /* If no target was found we can't set up a session */
1983 if (ast_strlen_zero(target)) {
1984 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);
1985 *cause = AST_CAUSE_SWITCH_CONGESTION;
1989 if (!(session = jingle_alloc(endpoint, target, NULL))) {
1990 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1991 *cause = AST_CAUSE_SWITCH_CONGESTION;
1995 /* Update the transport if we learned what we should actually use */
1996 if (transport != JINGLE_TRANSPORT_NONE) {
1997 session->transport = transport;
1998 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
2001 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
2002 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
2003 *cause = AST_CAUSE_SWITCH_CONGESTION;
2004 ao2_ref(session, -1);
2008 /* If video was requested try to enable it on the session */
2009 if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) {
2010 jingle_enable_video(session);
2013 /* As this is outgoing set ourselves as controlling */
2014 if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
2015 ice->ice_lite(session->rtp);
2018 if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
2019 ice->ice_lite(session->vrtp);
2022 /* We purposely don't decrement the session here as there is a reference on the channel */
2023 ao2_link(endpoint->state->sessions, session);
2028 /*! \brief Helper function which handles content descriptions */
2029 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2031 char *media = iks_find_attrib(description, "media");
2032 struct ast_rtp_codecs codecs;
2034 int othercapability = 0;
2036 /* Google-V1 is always carrying audio, but just doesn't tell us so */
2037 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2039 } else if (ast_strlen_zero(media)) {
2040 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2041 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2045 /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2046 if (!strcasecmp(media, "audio")) {
2047 if (!ast_strlen_zero(name)) {
2048 ast_string_field_set(session, audio_name, name);
2050 *rtp = session->rtp;
2051 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO);
2052 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO);
2053 } else if (!strcasecmp(media, "video")) {
2054 if (!ast_strlen_zero(name)) {
2055 ast_string_field_set(session, video_name, name);
2058 jingle_enable_video(session);
2059 *rtp = session->vrtp;
2061 /* If video is not present cancel this session */
2062 if (!session->vrtp) {
2063 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2064 ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2068 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO);
2069 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO);
2071 /* Unknown media type */
2072 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2073 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2077 if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2078 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2079 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2083 /* Iterate the codecs updating the relevant RTP instance as we go */
2084 for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2085 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
2086 char *clockrate = iks_find_attrib(codec, "clockrate");
2087 int rtp_id, rtp_clockrate;
2089 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2090 if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2091 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2093 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2098 ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2099 ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
2101 if (!ast_format_cap_count(session->jointcap)) {
2102 /* We have no compatible codecs, so terminate the session appropriately */
2103 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2104 ast_rtp_codecs_payloads_destroy(&codecs);
2108 ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2109 ast_rtp_codecs_payloads_destroy(&codecs);
2114 /*! \brief Helper function which handles ICE-UDP transport information */
2115 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2117 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2118 char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2122 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2123 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2127 if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2128 ice->set_authentication(rtp, ufrag, pwd);
2131 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2132 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2133 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2134 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2135 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2136 char *type = iks_find_attrib(candidate, "type");
2137 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2139 struct ast_sockaddr remote_address = { { 0, } };
2141 /* If this candidate is incomplete skip it */
2142 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2143 ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2144 ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2145 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2146 ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2150 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2151 (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
2152 (sscanf(port, "%30d", &real_port) != 1)) {
2153 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2154 ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2158 local_candidate.foundation = foundation;
2159 local_candidate.transport = protocol;
2161 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2163 /* We only support IPv4 right now */
2164 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2168 ast_sockaddr_set_port(&local_candidate.address, real_port);
2170 if (!strcasecmp(type, "host")) {
2171 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2172 } else if (!strcasecmp(type, "srflx")) {
2173 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2174 } else if (!strcasecmp(type, "relay")) {
2175 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2180 /* Worst case use the first viable address */
2181 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2183 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2184 ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2187 ice->add_remote_candidate(rtp, &local_candidate);
2195 /*! \brief Helper function which handles Google transport information */
2196 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2198 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2202 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2203 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2207 /* If this session has not transitioned to the Google transport do so now */
2208 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2209 (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2210 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2213 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2216 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2217 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2218 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2219 char *protocol = iks_find_attrib(candidate, "protocol");
2221 struct ast_sockaddr target = { { 0, } };
2222 /* In Google land the combined value is 32 bytes */
2223 char combined[33] = "";
2225 /* If this is NOT actually a candidate just skip it */
2226 if (strcasecmp(iks_name(candidate), "candidate") &&
2227 strcasecmp(iks_name(candidate), "p:candidate") &&
2228 strcasecmp(iks_name(candidate), "ses:candidate")) {
2232 /* If this candidate is incomplete skip it */
2233 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2234 ast_strlen_zero(name)) {
2235 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2236 ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2240 /* We only support UDP so skip any other protocols */
2241 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2245 /* We only permit audio and video, not RTCP */
2246 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2250 /* Parse the target information so we can send a STUN request to the candidate */
2251 if (sscanf(port, "%30d", &real_port) != 1) {
2252 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2253 ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2256 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2257 ast_sockaddr_set_port(&target, real_port);
2259 /* Per the STUN support Google talk uses combine the two usernames */
2260 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2262 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2263 ast_rtp_instance_stun_request(rtp, &target, combined);
2270 * \brief Helper function which locates content stanzas and interprets them
2272 * \note The session *must not* be locked before calling this
2274 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2277 unsigned int changed = 0;
2278 struct ast_channel *chan;
2280 /* Look at the content in the session initiation */
2281 for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2283 struct ast_rtp_instance *rtp = NULL;
2284 iks *description, *transport;
2286 /* Ignore specific parts if they are known not to be useful */
2287 if (!strcmp(iks_name(content), "conference-info")) {
2291 name = iks_find_attrib(content, "name");
2293 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2294 /* If this content stanza has no name consider it invalid and move on */
2295 if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2296 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2297 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2301 /* Try to pre-populate which RTP instance this content is relevant to */
2302 if (!strcmp(session->audio_name, name)) {
2304 } else if (!strcmp(session->video_name, name)) {
2305 rtp = session->vrtp;
2308 /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2312 /* If description information is available use it */
2313 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2314 (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2315 (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2316 (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2317 (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2318 (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2319 /* If we failed to do something with the content description abort immediately */
2320 if (jingle_interpret_description(session, description, name, &rtp)) {
2324 /* If we successfully interpret the description then the codecs need updating */
2328 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2330 ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2331 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2335 /* If ICE UDP transport information is available use it */
2336 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2337 if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2340 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2341 (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2342 (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2343 (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2344 /* If Google transport support is available use it */
2345 if (jingle_interpret_google_transport(session, transport, rtp)) {
2348 } else if (iks_find(content, "transport")) {
2349 /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2350 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2351 ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2360 if ((chan = jingle_session_lock_full(session))) {
2361 struct ast_format_cap *caps;
2362 struct ast_format *fmt;
2364 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
2366 ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
2367 ast_channel_nativeformats_set(chan, caps);
2371 fmt = ast_format_cap_get_format(session->jointcap, 0);
2372 ast_set_read_format(chan, fmt);
2373 ast_set_write_format(chan, fmt);
2376 ast_channel_unlock(chan);
2377 ast_channel_unref(chan);
2379 ao2_unlock(session);
2384 /*! \brief Handler function for the 'session-initiate' action */
2385 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2388 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2389 struct ast_channel *chan;
2393 /* This is a duplicate session setup, so respond accordingly */
2394 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2398 /* Retrieve the session identifier from the message, note that this may alter the transport */
2399 if ((sid = iks_find_attrib(pak->query, "id"))) {
2400 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2401 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2402 } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2403 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2407 /* Create a new local session */
2408 if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2409 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2413 /* If we determined that the transport should change as a result of how we got the SID change it */
2414 if (transport != JINGLE_TRANSPORT_NONE) {
2415 session->transport = transport;
2418 /* Create a new Asterisk channel using the above local session */
2419 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2420 ao2_ref(session, -1);
2421 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2425 ao2_link(endpoint->state->sessions, session);
2427 ast_channel_lock(chan);
2428 ast_setstate(chan, AST_STATE_RING);
2429 ast_channel_unlock(chan);
2430 res = ast_pbx_start(chan);
2433 case AST_PBX_FAILED:
2434 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2435 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2439 case AST_PBX_CALL_LIMIT:
2440 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2441 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2444 case AST_PBX_SUCCESS:
2445 jingle_send_response(endpoint->connection, pak);
2447 /* Only send a transport-info message if we successfully interpreted the available content */
2448 if (!jingle_interpret_content(session, pak)) {
2449 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2455 /*! \brief Handler function for the 'transport-info' action */
2456 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2459 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2460 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2464 jingle_interpret_content(session, pak);
2465 jingle_send_response(endpoint->connection, pak);
2468 /*! \brief Handler function for the 'session-accept' action */
2469 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2471 struct ast_channel *chan;
2474 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2475 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2480 jingle_interpret_content(session, pak);
2482 if ((chan = jingle_session_lock_full(session))) {
2483 ast_queue_control(chan, AST_CONTROL_ANSWER);
2484 ast_channel_unlock(chan);
2485 ast_channel_unref(chan);
2487 ao2_unlock(session);
2489 jingle_send_response(endpoint->connection, pak);
2492 /*! \brief Handler function for the 'session-info' action */
2493 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2495 struct ast_channel *chan;
2498 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2499 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2503 if (!(chan = jingle_session_lock_full(session))) {
2504 ao2_unlock(session);
2505 jingle_send_response(endpoint->connection, pak);
2509 if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2510 ast_queue_control(chan, AST_CONTROL_RINGING);
2511 if (ast_channel_state(chan) != AST_STATE_UP) {
2512 ast_setstate(chan, AST_STATE_RINGING);
2514 } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2515 ast_queue_hold(chan, NULL);
2516 } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2517 ast_queue_unhold(chan);
2520 ast_channel_unlock(chan);
2521 ast_channel_unref(chan);
2522 ao2_unlock(session);
2524 jingle_send_response(endpoint->connection, pak);
2527 /*! \brief Handler function for the 'session-terminate' action */
2528 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2530 struct ast_channel *chan;
2532 int cause = AST_CAUSE_NORMAL;
2533 struct ast_control_pvt_cause_code *cause_code;
2534 int data_size = sizeof(*cause_code);
2537 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2538 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2542 if (!(chan = jingle_session_lock_full(session))) {
2543 ao2_unlock(session);
2544 jingle_send_response(endpoint->connection, pak);
2548 /* Pull the reason text from the session-terminate message and translate it into a cause code */
2549 if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2552 /* Size of the string making up the cause code is "Motif " + text */
2553 data_size += 6 + strlen(iks_name(text));
2554 cause_code = ast_alloca(data_size);
2555 memset(cause_code, 0, data_size);
2557 /* Get the appropriate cause code mapping for this reason */
2558 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2559 if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2560 cause = jingle_reason_mappings[i].cause;
2565 /* Store the technology specific information */
2566 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2568 /* No technology specific information is available */
2569 cause_code = ast_alloca(data_size);
2570 memset(cause_code, 0, data_size);
2573 ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2574 cause_code->ast_cause = cause;
2575 ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2576 ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2578 ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2579 ast_queue_hangup_with_cause(chan, cause);
2582 ast_channel_unlock(chan);
2583 ast_channel_unref(chan);
2584 ao2_unlock(session);
2586 jingle_send_response(endpoint->connection, pak);
2589 /*! \brief Callback for when a Jingle action is received from an endpoint */
2590 static int jingle_action_hook(void *data, ikspak *pak)
2593 const char *sid = NULL;
2594 struct jingle_session *session = NULL;
2595 struct jingle_endpoint *endpoint = data;
2598 /* We accept both Jingle and Google-V1 */
2599 if (!(action = iks_find_attrib(pak->query, "action")) &&
2600 !(action = iks_find_attrib(pak->query, "type"))) {
2601 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2602 * to a message that has no response hook. */
2603 return IKS_FILTER_EAT;
2606 /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2607 * does not permit us to make this completely safe. */
2608 ao2_ref(endpoint, +1);
2610 /* If a Jingle session identifier is present use it */
2611 if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2612 /* If a Google-V1 session identifier is present use it */
2613 sid = iks_find_attrib(pak->query, "id");
2616 /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2617 * this is required or not */
2618 if (!ast_strlen_zero(sid)) {
2619 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2622 /* If a session is present associate the callid with this thread */
2624 ast_callid_threadassoc_add(session->callid);
2627 /* Iterate through supported action handlers looking for one that is able to handle this */
2628 for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2629 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2630 jingle_action_handlers[i].handler(endpoint, session, pak);
2636 /* If no action handler is present for the action they sent us make it evident */
2638 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2641 /* If a session was successfully found for this message deref it now since the handler is done */
2643 ast_callid_threadassoc_remove();
2644 ao2_ref(session, -1);
2647 ao2_ref(endpoint, -1);
2649 return IKS_FILTER_EAT;
2652 /*! \brief Custom handler for groups */
2653 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2655 struct jingle_endpoint *endpoint = obj;
2657 if (!strcasecmp(var->name, "callgroup")) {
2658 endpoint->callgroup = ast_get_group(var->value);
2659 } else if (!strcasecmp(var->name, "pickupgroup")) {
2660 endpoint->pickupgroup = ast_get_group(var->value);
2668 /*! \brief Custom handler for connection */
2669 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2671 struct jingle_endpoint *endpoint = obj;
2673 /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2674 * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2676 if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2677 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2681 if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2682 IKS_RULE_TYPE, IKS_PAK_IQ,
2683 IKS_RULE_NS, JINGLE_NS,
2684 IKS_RULE_NS, GOOGLE_SESSION_NS,
2686 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2693 /*! \brief Custom handler for transport */
2694 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2696 struct jingle_endpoint *endpoint = obj;
2698 if (!strcasecmp(var->value, "ice-udp")) {
2699 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2700 } else if (!strcasecmp(var->value, "google")) {
2701 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2702 } else if (!strcasecmp(var->value, "google-v1")) {
2703 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2705 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2706 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2713 * \brief Load the module
2715 * Module loading including tests for configuration or dependencies.
2716 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2717 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2718 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2719 * configuration file or other non-critical problem return
2720 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2722 static int load_module(void)
2724 if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2725 return AST_MODULE_LOAD_DECLINE;
2728 if (aco_info_init(&cfg_info)) {
2729 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2733 aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2734 aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2735 aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2736 aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2737 aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2738 aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2739 aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2740 aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
2741 aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
2742 aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2743 aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2744 aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2745 FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2746 aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2747 FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2749 ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
2751 if (aco_process_config(&cfg_info, 0)) {
2752 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2753 aco_info_destroy(&cfg_info);
2754 ao2_cleanup(jingle_tech.capabilities);
2755 jingle_tech.capabilities = NULL;
2756 return AST_MODULE_LOAD_DECLINE;
2759 if (!(sched = ast_sched_context_create())) {
2760 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2764 if (ast_sched_start_thread(sched)) {
2765 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2769 ast_rtp_glue_register(&jingle_rtp_glue);
2771 if (ast_channel_register(&jingle_tech)) {
2772 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2779 ast_rtp_glue_unregister(&jingle_rtp_glue);
2782 ast_sched_context_destroy(sched);
2785 aco_info_destroy(&cfg_info);
2786 ao2_global_obj_release(globals);
2788 ao2_cleanup(jingle_tech.capabilities);
2789 jingle_tech.capabilities = NULL;
2791 return AST_MODULE_LOAD_DECLINE;
2794 /*! \brief Reload module */
2795 static int reload(void)
2797 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2804 /*! \brief Unload the jingle channel from Asterisk */
2805 static int unload_module(void)
2807 ast_channel_unregister(&jingle_tech);
2808 ao2_cleanup(jingle_tech.capabilities);
2809 jingle_tech.capabilities = NULL;
2810 ast_rtp_glue_unregister(&jingle_rtp_glue);
2811 ast_sched_context_destroy(sched);
2812 aco_info_destroy(&cfg_info);
2813 ao2_global_obj_release(globals);
2818 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2819 .support_level = AST_MODULE_SUPPORT_CORE,
2820 .load = load_module,
2821 .unload = unload_module,
2823 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2824 .requires = "res_xmpp",