logger.conf.sample: add missing comment mark
[asterisk/asterisk.git] / channels / chan_motif.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \author Joshua Colp <jcolp@digium.com>
22  *
23  * \brief Motif Jingle Channel Driver
24  *
25  * Iksemel http://iksemel.jabberstudio.org/
26  *
27  * \ingroup channel_drivers
28  */
29
30 /*! \li \ref chan_motif.c uses the configuration file \ref motif.conf
31  * \addtogroup configuration_file
32  */
33
34 /*! \page motif.conf motif.conf
35  * \verbinclude motif.conf.sample
36  */
37
38 /*** MODULEINFO
39         <depend>iksemel</depend>
40         <depend>res_xmpp</depend>
41         <use type="external">openssl</use>
42         <support_level>core</support_level>
43  ***/
44
45 #include "asterisk.h"
46
47 #include <sys/socket.h>
48 #include <fcntl.h>
49 #include <netdb.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <signal.h>
53 #include <iksemel.h>
54 #include <pthread.h>
55
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"
79
80 /*** DOCUMENTATION
81         <configInfo name="chan_motif" language="en_US">
82                 <synopsis>Jingle Channel Driver</synopsis>
83                 <description>
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>
100                         in this file.</para>
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
130                         it.</para>
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>
144                         <warning>
145                                 <para>Multiple endpoints using the
146                                 same connection is <emphasis>NOT</emphasis> supported. Doing so
147                                 may result in broken calls.</para>
148                         </warning>
149                 </description>
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>
155                                 </configOption>
156                                 <configOption name="callgroup">
157                                         <synopsis>A callgroup to assign to this endpoint.</synopsis>
158                                 </configOption>
159                                 <configOption name="pickupgroup">
160                                         <synopsis>A pickup group to assign to this endpoint.</synopsis>
161                                 </configOption>
162                                 <configOption name="language">
163                                         <synopsis>The default language for this endpoint.</synopsis>
164                                 </configOption>
165                                 <configOption name="musicclass">
166                                         <synopsis>Default music on hold class for this endpoint.</synopsis>
167                                 </configOption>
168                                 <configOption name="parkinglot">
169                                         <synopsis>Default parking lot for this endpoint.</synopsis>
170                                 </configOption>
171                                 <configOption name="accountcode">
172                                         <synopsis>Accout code for CDR purposes</synopsis>
173                                 </configOption>
174                                 <configOption name="allow">
175                                         <synopsis>Codecs to allow</synopsis>
176                                 </configOption>
177                                 <configOption name="disallow">
178                                         <synopsis>Codecs to disallow</synopsis>
179                                 </configOption>
180                                 <configOption name="connection">
181                                         <synopsis>Connection to accept traffic on and on which to send traffic out</synopsis>
182                                 </configOption>
183                                 <configOption name="transport">
184                                         <synopsis>The transport to use for the endpoint.</synopsis>
185                                         <description>
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>
191                                                 <enumlist>
192                                                         <enum name="ice-udp">
193                                                                 <para>The Jingle protocol, as defined in XEP 0166.</para>
194                                                         </enum>
195                                                         <enum name="google">
196                                                                 <para>The Google Jingle protocol, which follows the Jingle
197                                                                 specification for signaling but uses a custom transport for
198                                                                 media.</para>
199                                                         </enum>
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>
204                                                         </enum>
205                                                 </enumlist>
206                                         </description>
207                                 </configOption>
208                                 <configOption name="maxicecandidates">
209                                         <synopsis>Maximum number of ICE candidates to offer</synopsis>
210                                 </configOption>
211                                 <configOption name="maxpayloads">
212                                         <synopsis>Maximum number of pyaloads to offer</synopsis>
213                                 </configOption>
214                         </configObject>
215                 </configFile>
216         </configInfo>
217 ***/
218
219 /*! \brief Default maximum number of ICE candidates we will offer */
220 #define DEFAULT_MAX_ICE_CANDIDATES "10"
221
222 /*! \brief Default maximum number of payloads we will offer */
223 #define DEFAULT_MAX_PAYLOADS "30"
224
225 /*! \brief Number of buckets for endpoints */
226 #define ENDPOINT_BUCKETS 37
227
228 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
229 #define SESSION_BUCKETS 37
230
231 /*! \brief Namespace for Jingle itself */
232 #define JINGLE_NS "urn:xmpp:jingle:1"
233
234 /*! \brief Namespace for Jingle RTP sessions */
235 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
236
237 /*! \brief Namespace for Jingle RTP info */
238 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
239
240 /*! \brief Namespace for Jingle ICE-UDP */
241 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
242
243 /*! \brief Namespace for Google Talk ICE-UDP */
244 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
245
246 /*! \brief Namespace for Google Talk Raw UDP */
247 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
248
249 /*! \brief Namespace for Google Session */
250 #define GOOGLE_SESSION_NS "http://www.google.com/session"
251
252 /*! \brief Namespace for Google Phone description */
253 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
254
255 /*! \brief Namespace for Google Video description */
256 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
257
258 /*! \brief Namespace for XMPP stanzas */
259 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
260
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 */
267 };
268
269 /*! \brief Endpoint state information */
270 struct jingle_endpoint_state {
271         struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
272 };
273
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 */
283                 );
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 */
293 };
294
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 */
301                 );
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 */
319 };
320
321 static const char channel_type[] = "Motif";
322
323 struct jingle_config {
324         struct ao2_container *endpoints; /*!< Configured endpoints */
325 };
326
327 static AO2_GLOBAL_OBJ_STATIC(globals);
328
329 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
330
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);
344
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);
351
352 /*! \brief PBX interface structure for channel registration */
353 static struct ast_channel_tech jingle_tech = {
354         .type = "Motif",
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,
360         .call = jingle_call,
361         .hangup = jingle_hangup,
362         .answer = jingle_answer,
363         .read = jingle_read,
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
370 };
371
372 /*! \brief Defined handlers for different Jingle actions */
373 static const struct jingle_action_handler {
374         const char *action;
375         void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
376 } jingle_action_handlers[] = {
377         /* Jingle actions */
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, },
389 };
390
391 /*! \brief Reason text <-> cause code mapping */
392 static const struct jingle_reason_mapping {
393         const char *reason;
394         int cause;
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, },
412 };
413
414 /*! \brief Hashing function for Jingle sessions */
415 static int jingle_session_hash(const void *obj, const int flags)
416 {
417         const struct jingle_session *session = obj;
418         const char *sid = obj;
419
420         return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
421 }
422
423 /*! \brief Comparator function for Jingle sessions */
424 static int jingle_session_cmp(void *obj, void *arg, int flags)
425 {
426         struct jingle_session *session1 = obj, *session2 = arg;
427         const char *sid = arg;
428
429         return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
430 }
431
432 /*! \brief Destructor for Jingle endpoint state */
433 static void jingle_endpoint_state_destructor(void *obj)
434 {
435         struct jingle_endpoint_state *state = obj;
436
437         ao2_ref(state->sessions, -1);
438 }
439
440 /*! \brief Destructor for Jingle endpoints */
441 static void jingle_endpoint_destructor(void *obj)
442 {
443         struct jingle_endpoint *endpoint = obj;
444
445         if (endpoint->rule) {
446                 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
447         }
448
449         if (endpoint->connection) {
450                 ast_xmpp_client_unref(endpoint->connection);
451         }
452
453         ao2_cleanup(endpoint->cap);
454         ao2_ref(endpoint->state, -1);
455
456         ast_string_field_free_memory(endpoint);
457 }
458
459 /*! \brief Find function for Jingle endpoints */
460 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
461 {
462         return ao2_find(tmp_container, category, OBJ_KEY);
463 }
464
465 /*! \brief Allocator function for Jingle endpoint state */
466 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
467 {
468         struct jingle_endpoint_state *state;
469
470         if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
471                 return NULL;
472         }
473
474         state->sessions = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
475                 SESSION_BUCKETS, jingle_session_hash, NULL, jingle_session_cmp);
476         if (!state->sessions) {
477                 ao2_ref(state, -1);
478                 return NULL;
479         }
480
481         return state;
482 }
483
484 /*! \brief State find/create function */
485 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
486 {
487         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
488         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
489
490         if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
491                 return jingle_endpoint_state_create();
492         }
493
494         ao2_ref(endpoint->state, +1);
495         return endpoint->state;
496 }
497
498 /*! \brief Allocator function for Jingle endpoints */
499 static void *jingle_endpoint_alloc(const char *cat)
500 {
501         struct jingle_endpoint *endpoint;
502
503         if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
504                 return NULL;
505         }
506
507         if (ast_string_field_init(endpoint, 512)) {
508                 ao2_ref(endpoint, -1);
509                 return NULL;
510         }
511
512         if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
513                 ao2_ref(endpoint, -1);
514                 return NULL;
515         }
516
517         ast_string_field_set(endpoint, name, cat);
518
519         endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
520         endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
521
522         return endpoint;
523 }
524
525 /*! \brief Hashing function for Jingle endpoints */
526 static int jingle_endpoint_hash(const void *obj, const int flags)
527 {
528         const struct jingle_endpoint *endpoint = obj;
529         const char *name = obj;
530
531         return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
532 }
533
534 /*! \brief Comparator function for Jingle endpoints */
535 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
536 {
537         struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
538         const char *name = arg;
539
540         return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
541 }
542
543 static struct aco_type endpoint_option = {
544         .type = ACO_ITEM,
545         .name = "endpoint",
546         .category_match = ACO_BLACKLIST_EXACT,
547         .category = "general",
548         .item_alloc = jingle_endpoint_alloc,
549         .item_find = jingle_endpoint_find,
550         .item_offset = offsetof(struct jingle_config, endpoints),
551 };
552
553 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
554
555 struct aco_file jingle_conf = {
556         .filename = "motif.conf",
557         .types = ACO_TYPES(&endpoint_option),
558 };
559
560 /*! \brief Destructor for Jingle sessions */
561 static void jingle_session_destructor(void *obj)
562 {
563         struct jingle_session *session = obj;
564
565         if (session->rule) {
566                 iks_filter_remove_rule(session->connection->filter, session->rule);
567         }
568
569         if (session->connection) {
570                 ast_xmpp_client_unref(session->connection);
571         }
572
573         if (session->rtp) {
574                 ast_rtp_instance_stop(session->rtp);
575                 ast_rtp_instance_destroy(session->rtp);
576         }
577
578         if (session->vrtp) {
579                 ast_rtp_instance_stop(session->vrtp);
580                 ast_rtp_instance_destroy(session->vrtp);
581         }
582
583         ao2_cleanup(session->cap);
584         ao2_cleanup(session->jointcap);
585         ao2_cleanup(session->peercap);
586
587         ast_string_field_free_memory(session);
588 }
589
590 /*! \brief Destructor called when module configuration goes away */
591 static void jingle_config_destructor(void *obj)
592 {
593         struct jingle_config *cfg = obj;
594         ao2_cleanup(cfg->endpoints);
595 }
596
597 /*! \brief Allocator called when module configuration should appear */
598 static void *jingle_config_alloc(void)
599 {
600         struct jingle_config *cfg;
601
602         if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
603                 return NULL;
604         }
605
606         cfg->endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
607                 ENDPOINT_BUCKETS, jingle_endpoint_hash, NULL, jingle_endpoint_cmp);
608         if (!cfg->endpoints) {
609                 ao2_ref(cfg, -1);
610                 return NULL;
611         }
612
613         return cfg;
614 }
615
616 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
617                      .files = ACO_FILES(&jingle_conf),
618         );
619
620 /*! \brief Function called by RTP engine to get local RTP peer */
621 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
622 {
623         struct jingle_session *session = ast_channel_tech_pvt(chan);
624         enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
625
626         if (!session->rtp) {
627                 return AST_RTP_GLUE_RESULT_FORBID;
628         }
629
630         ao2_ref(session->rtp, +1);
631         *instance = session->rtp;
632
633         return res;
634 }
635
636 /*! \brief Function called by RTP engine to get peer capabilities */
637 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
638 {
639 }
640
641 /*! \brief Function called by RTP engine to change where the remote party should send media */
642 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 {
644         return -1;
645 }
646
647 /*! \brief Local glue for interacting with the RTP engine core */
648 static struct ast_rtp_glue jingle_rtp_glue = {
649         .type = "Motif",
650         .get_rtp_info = jingle_get_rtp_peer,
651         .get_codec = jingle_get_codec,
652         .update_peer = jingle_set_rtp_peer,
653 };
654
655 /*! \brief Set the channel owner on the \ref jingle_session object and related objects */
656 static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
657 {
658         session->owner = chan;
659         if (session->rtp) {
660                 ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
661         }
662         if (session->vrtp) {
663                 ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
664         }
665 }
666
667 /*! \brief Internal helper function which enables video support on a sesson if possible */
668 static void jingle_enable_video(struct jingle_session *session)
669 {
670         struct ast_sockaddr tmp;
671         struct ast_rtp_engine_ice *ice;
672
673         /* If video is already present don't do anything */
674         if (session->vrtp) {
675                 return;
676         }
677
678         /* If there are no configured video codecs do not turn video support on, it just won't work */
679         if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) {
680                 return;
681         }
682
683         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
684
685         if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
686                 return;
687         }
688
689         ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
690         ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
691         ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
692         ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
693         ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp),
694                 ast_format_cap_get_framing(session->cap));
695         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
696                 ice->stop(session->vrtp);
697         }
698 }
699
700 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
701 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
702 {
703         struct jingle_session *session;
704         ast_callid callid;
705         struct ast_sockaddr tmp;
706
707         if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
708                 return NULL;
709         }
710
711         callid = ast_read_threadstorage_callid();
712         session->callid = (callid ? callid : ast_create_callid());
713
714         if (ast_string_field_init(session, 512)) {
715                 ao2_ref(session, -1);
716                 return NULL;
717         }
718
719         if (!ast_strlen_zero(from)) {
720                 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
721                 ast_copy_string(session->remote, from, sizeof(session->remote));
722         }
723
724         if (ast_strlen_zero(sid)) {
725                 ast_string_field_build(session, sid, "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
726                 session->outgoing = 1;
727                 ast_string_field_set(session, audio_name, "audio");
728                 ast_string_field_set(session, video_name, "video");
729         } else {
730                 ast_string_field_set(session, sid, sid);
731         }
732
733         ao2_ref(endpoint->state, +1);
734         session->state = endpoint->state;
735         ao2_ref(endpoint->connection, +1);
736         session->connection = endpoint->connection;
737         session->transport = endpoint->transport;
738
739         if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
740             !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
741             !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
742             !session->callid) {
743                 ao2_ref(session, -1);
744                 return NULL;
745         }
746
747         ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN);
748
749         /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
750          * that we want IPv4 */
751         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
752
753         /* Sessions always carry audio, but video is optional so don't enable it here */
754         if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
755                 ao2_ref(session, -1);
756                 return NULL;
757         }
758         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
759         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
760
761         session->maxicecandidates = endpoint->maxicecandidates;
762         session->maxpayloads = endpoint->maxpayloads;
763
764         return session;
765 }
766
767 /*! \brief Function called to create a new Jingle Asterisk channel */
768 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)
769 {
770         struct ast_channel *chan;
771         const char *str = S_OR(title, session->remote);
772         struct ast_format_cap *caps;
773         struct ast_format *tmpfmt;
774
775         if (!ast_format_cap_count(session->cap)) {
776                 return NULL;
777         }
778
779         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
780         if (!caps) {
781                 return NULL;
782         }
783
784         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                 ao2_ref(caps, -1);
786                 return NULL;
787         }
788
789         ast_channel_stage_snapshot(chan);
790
791         ast_channel_tech_set(chan, &jingle_tech);
792         ast_channel_tech_pvt_set(chan, session);
793         jingle_set_owner(session, chan);
794
795         ast_channel_callid_set(chan, session->callid);
796
797         ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN);
798         ast_channel_nativeformats_set(chan, caps);
799         ao2_ref(caps, -1);
800
801         if (session->rtp) {
802                 struct ast_rtp_engine_ice *ice;
803
804                 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
805                 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
806                 ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp),
807                         ast_format_cap_get_framing(session->cap));
808
809                 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
810                      (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
811                     (ice = ast_rtp_instance_get_ice(session->rtp))) {
812                         /* We stop built in ICE support because we need to fall back to old old old STUN support */
813                         ice->stop(session->rtp);
814                 }
815         }
816
817         if (state == AST_STATE_RING) {
818                 ast_channel_rings_set(chan, 1);
819         }
820
821         ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
822
823         tmpfmt = ast_format_cap_get_format(session->cap, 0);
824         ast_channel_set_writeformat(chan, tmpfmt);
825         ast_channel_set_rawwriteformat(chan, tmpfmt);
826         ast_channel_set_readformat(chan, tmpfmt);
827         ast_channel_set_rawreadformat(chan, tmpfmt);
828         ao2_ref(tmpfmt, -1);
829
830         ao2_lock(endpoint);
831
832         ast_channel_callgroup_set(chan, endpoint->callgroup);
833         ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
834
835         if (!ast_strlen_zero(endpoint->accountcode)) {
836                 ast_channel_accountcode_set(chan, endpoint->accountcode);
837         }
838
839         if (!ast_strlen_zero(endpoint->language)) {
840                 ast_channel_language_set(chan, endpoint->language);
841         }
842
843         if (!ast_strlen_zero(endpoint->musicclass)) {
844                 ast_channel_musicclass_set(chan, endpoint->musicclass);
845         }
846
847         ast_channel_context_set(chan, endpoint->context);
848         if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
849                 ast_channel_exten_set(chan, endpoint->name);
850         } else {
851                 ast_channel_exten_set(chan, "s");
852         }
853         ast_channel_priority_set(chan, 1);
854
855         ao2_unlock(endpoint);
856
857         ast_channel_stage_snapshot_done(chan);
858         ast_channel_unlock(chan);
859
860         return chan;
861 }
862
863 /*! \brief Internal helper function which sends a response */
864 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
865 {
866         iks *response;
867
868         if (!(response = iks_new("iq"))) {
869                 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
870                 return;
871         }
872
873         iks_insert_attrib(response, "type", "result");
874         iks_insert_attrib(response, "from", connection->jid->full);
875         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
876         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
877
878         ast_xmpp_client_send(connection, response);
879
880         iks_delete(response);
881 }
882
883 /*! \brief Internal helper function which sends an error response */
884 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
885 {
886         iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
887
888         if (!(response = iks_new("iq")) ||
889             !(error = iks_new("error")) ||
890             !(reason = iks_new(reasonstr))) {
891                 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
892                 goto end;
893         }
894
895         iks_insert_attrib(response, "type", "error");
896         iks_insert_attrib(response, "from", connection->jid->full);
897         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
898         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
899
900         iks_insert_attrib(error, "type", type);
901         iks_insert_node(error, reason);
902
903         if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
904                 iks_insert_node(error, reason2);
905         }
906
907         iks_insert_node(response, error);
908
909         ast_xmpp_client_send(connection, response);
910 end:
911         iks_delete(reason2);
912         iks_delete(reason);
913         iks_delete(error);
914         iks_delete(response);
915 }
916
917 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
918 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
919 {
920         struct ast_rtp_engine_ice *ice;
921         struct ao2_container *local_candidates;
922         struct ao2_iterator it;
923         struct ast_rtp_engine_ice_candidate *candidate;
924         int i = 0, res = 0;
925
926         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
927                 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
928                 return -1;
929         }
930
931         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
932         iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
933         iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
934
935         it = ao2_iterator_init(local_candidates, 0);
936
937         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
938                 iks *local_candidate;
939                 char tmp[30];
940
941                 if (!(local_candidate = iks_new("candidate"))) {
942                         res = -1;
943                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
944                         break;
945                 }
946
947                 snprintf(tmp, sizeof(tmp), "%u", candidate->id);
948                 iks_insert_attrib(local_candidate, "component", tmp);
949                 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
950                 iks_insert_attrib(local_candidate, "foundation", tmp);
951                 iks_insert_attrib(local_candidate, "generation", "0");
952                 iks_insert_attrib(local_candidate, "network", "0");
953                 snprintf(tmp, sizeof(tmp), "%04lx", (unsigned long)(ast_random() & 0xffff));
954                 iks_insert_attrib(local_candidate, "id", tmp);
955                 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
956                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
957                 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
958                 iks_insert_attrib(local_candidate, "priority", tmp);
959                 iks_insert_attrib(local_candidate, "protocol", "udp");
960
961                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
962                         iks_insert_attrib(local_candidate, "type", "host");
963                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
964                         iks_insert_attrib(local_candidate, "type", "srflx");
965                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
966                         iks_insert_attrib(local_candidate, "type", "relay");
967                 }
968
969                 iks_insert_node(transport, local_candidate);
970                 candidates[i++] = local_candidate;
971         }
972
973         ao2_iterator_destroy(&it);
974         ao2_ref(local_candidates, -1);
975
976         return res;
977 }
978
979 /*! \brief Internal helper function which adds Google candidates to a transport node */
980 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)
981 {
982         struct ast_rtp_engine_ice *ice;
983         struct ao2_container *local_candidates;
984         struct ao2_iterator it;
985         struct ast_rtp_engine_ice_candidate *candidate;
986         int i = 0, res = 0;
987
988         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
989                 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
990                 return -1;
991         }
992
993         if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
994                 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
995         }
996
997         it = ao2_iterator_init(local_candidates, 0);
998
999         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
1000                 iks *local_candidate;
1001                 /* In Google land a username is 16 bytes, explicitly */
1002                 char ufrag[17] = "";
1003
1004                 if (!(local_candidate = iks_new("candidate"))) {
1005                         res = -1;
1006                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
1007                         break;
1008                 }
1009
1010                 if (candidate->id == 1) {
1011                         iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
1012                 } else if (candidate->id == 2) {
1013                         iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
1014                 } else {
1015                         iks_delete(local_candidate);
1016                         continue;
1017                 }
1018
1019                 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
1020                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
1021
1022                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
1023                         iks_insert_attrib(local_candidate, "preference", "0.95");
1024                         iks_insert_attrib(local_candidate, "type", "local");
1025                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
1026                         iks_insert_attrib(local_candidate, "preference", "0.9");
1027                         iks_insert_attrib(local_candidate, "type", "stun");
1028                 }
1029
1030                 iks_insert_attrib(local_candidate, "protocol", "udp");
1031                 iks_insert_attrib(local_candidate, "network", "0");
1032                 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
1033                 iks_insert_attrib(local_candidate, "username", ufrag);
1034                 iks_insert_attrib(local_candidate, "generation", "0");
1035
1036                 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
1037                         iks_insert_attrib(local_candidate, "password", "");
1038                         iks_insert_attrib(local_candidate, "foundation", "0");
1039                         iks_insert_attrib(local_candidate, "component", "1");
1040                 } else {
1041                         iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
1042                 }
1043
1044                 /* You may notice a lack of relay support up above - this is because we don't support it for use with
1045                  * the Google talk transport due to their arcane support. */
1046
1047                 iks_insert_node(transport, local_candidate);
1048                 candidates[i++] = local_candidate;
1049         }
1050
1051         ao2_iterator_destroy(&it);
1052         ao2_ref(local_candidates, -1);
1053
1054         return res;
1055 }
1056
1057 /*! \brief Internal function which sends a session-terminate message */
1058 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
1059 {
1060         iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
1061
1062         if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
1063             !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
1064                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
1065                 goto end;
1066         }
1067
1068         iks_insert_attrib(iq, "to", session->remote);
1069         iks_insert_attrib(iq, "type", "set");
1070         iks_insert_attrib(iq, "id", session->connection->mid);
1071         ast_xmpp_increment_mid(session->connection->mid);
1072
1073         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1074                 iks_insert_attrib(jingle, "type", "terminate");
1075                 iks_insert_attrib(jingle, "id", session->sid);
1076                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1077                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1078         } else {
1079                 iks_insert_attrib(jingle, "action", "session-terminate");
1080                 iks_insert_attrib(jingle, "sid", session->sid);
1081                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1082         }
1083
1084         iks_insert_node(iq, jingle);
1085         iks_insert_node(jingle, reason);
1086         iks_insert_node(reason, text);
1087
1088         ast_xmpp_client_send(session->connection, iq);
1089
1090 end:
1091         iks_delete(text);
1092         iks_delete(reason);
1093         iks_delete(jingle);
1094         iks_delete(iq);
1095 }
1096
1097 /*! \brief Internal function which sends a session-info message */
1098 static void jingle_send_session_info(struct jingle_session *session, const char *info)
1099 {
1100         iks *iq = NULL, *jingle = NULL, *text = NULL;
1101
1102         /* Google-V1 has no way to send informational messages so don't even bother trying */
1103         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1104                 return;
1105         }
1106
1107         if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
1108                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
1109                 goto end;
1110         }
1111
1112         iks_insert_attrib(iq, "to", session->remote);
1113         iks_insert_attrib(iq, "type", "set");
1114         iks_insert_attrib(iq, "id", session->connection->mid);
1115         ast_xmpp_increment_mid(session->connection->mid);
1116
1117         iks_insert_attrib(jingle, "action", "session-info");
1118         iks_insert_attrib(jingle, "sid", session->sid);
1119         iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1120         iks_insert_node(iq, jingle);
1121         iks_insert_node(jingle, text);
1122
1123         ast_xmpp_client_send(session->connection, iq);
1124
1125 end:
1126         iks_delete(text);
1127         iks_delete(jingle);
1128         iks_delete(iq);
1129 }
1130
1131 /*! \internal
1132  *
1133  * \brief Locks both pvt and pvt owner if owner is present.
1134  *
1135  * \note This function gives a ref to pvt->owner if it is present and locked.
1136  *       This reference must be decremented after pvt->owner is unlocked.
1137  *
1138  * \note This function will never give you up,
1139  * \note This function will never let you down.
1140  * \note This function will run around and desert you.
1141  *
1142  * \pre pvt is not locked
1143  * \post pvt is locked
1144  * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
1145  *
1146  * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
1147  */
1148 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
1149 {
1150         struct ast_channel *chan;
1151
1152         /* Locking is simple when it is done right.  If you see a deadlock resulting
1153          * in this function, it is not this function's fault, Your problem exists elsewhere.
1154          * This function is perfect... seriously. */
1155         for (;;) {
1156                 /* First, get the channel and grab a reference to it */
1157                 ao2_lock(pvt);
1158                 chan = pvt->owner;
1159                 if (chan) {
1160                         /* The channel can not go away while we hold the pvt lock.
1161                          * Give the channel a ref so it will not go away after we let
1162                          * the pvt lock go. */
1163                         ast_channel_ref(chan);
1164                 } else {
1165                         /* no channel, return pvt locked */
1166                         return NULL;
1167                 }
1168
1169                 /* We had to hold the pvt lock while getting a ref to the owner channel
1170                  * but now we have to let this lock go in order to preserve proper
1171                  * locking order when grabbing the channel lock */
1172                 ao2_unlock(pvt);
1173
1174                 /* Look, no deadlock avoidance, hooray! */
1175                 ast_channel_lock(chan);
1176                 ao2_lock(pvt);
1177                 if (pvt->owner == chan) {
1178                         /* done */
1179                         break;
1180                 }
1181
1182                 /* If the owner changed while everything was unlocked, no problem,
1183                  * just start over and everthing will work.  This is rare, do not be
1184                  * confused by this loop and think this it is an expensive operation.
1185                  * The majority of the calls to this function will never involve multiple
1186                  * executions of this loop. */
1187                 ast_channel_unlock(chan);
1188                 ast_channel_unref(chan);
1189                 ao2_unlock(pvt);
1190         }
1191
1192         /* If owner exists, it is locked and reffed */
1193         return pvt->owner;
1194 }
1195
1196 /*! \brief Helper function which queues a hangup frame with cause code */
1197 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1198 {
1199         struct ast_channel *chan;
1200
1201         if ((chan = jingle_session_lock_full(session))) {
1202                 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1203                 ast_queue_hangup_with_cause(chan, cause);
1204                 ast_channel_unlock(chan);
1205                 ast_channel_unref(chan);
1206         }
1207         ao2_unlock(session);
1208 }
1209
1210 /*! \brief Internal function which sends a transport-info message */
1211 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1212 {
1213         iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1214         iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1215         int i, res = 0;
1216
1217         if (!(iq = iks_new("iq")) ||
1218             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1219                 iks_delete(iq);
1220                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1221                 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1222                 return;
1223         }
1224
1225         memset(audio_candidates, 0, sizeof(audio_candidates));
1226         memset(video_candidates, 0, sizeof(video_candidates));
1227
1228         iks_insert_attrib(iq, "from", session->connection->jid->full);
1229         iks_insert_attrib(iq, "to", from);
1230         iks_insert_attrib(iq, "type", "set");
1231         iks_insert_attrib(iq, "id", session->connection->mid);
1232         ast_xmpp_increment_mid(session->connection->mid);
1233
1234         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1235                 iks_insert_attrib(jingle, "type", "candidates");
1236                 iks_insert_attrib(jingle, "id", session->sid);
1237                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1238                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1239         } else {
1240                 iks_insert_attrib(jingle, "action", "transport-info");
1241                 iks_insert_attrib(jingle, "sid", session->sid);
1242                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1243         }
1244         iks_insert_node(iq, jingle);
1245
1246         if (session->rtp) {
1247                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1248                         /* V1 protocol has the candidates directly in the session */
1249                         res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1250                 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1251                         iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1252                         iks_insert_attrib(audio, "name", session->audio_name);
1253                         iks_insert_node(jingle, audio);
1254                         iks_insert_node(audio, audio_transport);
1255
1256                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1257                                 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1258                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1259                                 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1260                                                                                 session->maxicecandidates);
1261                         }
1262                 } else {
1263                         res = -1;
1264                 }
1265         }
1266
1267         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1268                 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1269                         iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1270                         iks_insert_attrib(video, "name", session->video_name);
1271                         iks_insert_node(jingle, video);
1272                         iks_insert_node(video, video_transport);
1273
1274                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1275                                 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1276                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1277                                 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1278                                                                                 session->maxicecandidates);
1279                         }
1280                 } else {
1281                         res = -1;
1282                 }
1283         }
1284
1285         if (!res) {
1286                 ast_xmpp_client_send(session->connection, iq);
1287         } else {
1288                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1289         }
1290
1291         /* Clean up after ourselves */
1292         for (i = 0; i < session->maxicecandidates; i++) {
1293                 iks_delete(video_candidates[i]);
1294                 iks_delete(audio_candidates[i]);
1295         }
1296
1297         iks_delete(video_transport);
1298         iks_delete(video);
1299         iks_delete(audio_transport);
1300         iks_delete(audio);
1301         iks_delete(jingle);
1302         iks_delete(iq);
1303 }
1304
1305 /*! \brief Internal helper function which adds payloads to a description */
1306 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)
1307 {
1308         int x = 0, i = 0, res = 0;
1309
1310         for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) {
1311                 struct ast_format *format = ast_format_cap_get_format(session->jointcap, x);
1312                 int rtp_code;
1313                 iks *payload;
1314                 char tmp[32];
1315
1316                 if (ast_format_get_type(format) != type) {
1317                         ao2_ref(format, -1);
1318                         continue;
1319                 }
1320
1321                 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) ||
1322                     (!(payload = iks_new("payload-type")))) {
1323                         ao2_ref(format, -1);
1324                         return -1;
1325                 }
1326
1327                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1328                         iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1329                 }
1330
1331                 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1332                 iks_insert_attrib(payload, "id", tmp);
1333                 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
1334                 iks_insert_attrib(payload, "channels", "1");
1335
1336                 if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) &&
1337                         ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1338                         iks_insert_attrib(payload, "clockrate", "16000");
1339                 } else {
1340                         snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0));
1341                         iks_insert_attrib(payload, "clockrate", tmp);
1342                 }
1343
1344                 if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1345                         iks *parameter;
1346
1347                         /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1348                         if ((parameter = iks_new("parameter"))) {
1349                                 iks_insert_attrib(parameter, "name", "width");
1350                                 iks_insert_attrib(parameter, "value", "640");
1351                                 iks_insert_node(payload, parameter);
1352                         }
1353                         if ((parameter = iks_new("parameter"))) {
1354                                 iks_insert_attrib(parameter, "name", "height");
1355                                 iks_insert_attrib(parameter, "value", "480");
1356                                 iks_insert_node(payload, parameter);
1357                         }
1358                         if ((parameter = iks_new("parameter"))) {
1359                                 iks_insert_attrib(parameter, "name", "framerate");
1360                                 iks_insert_attrib(parameter, "value", "30");
1361                                 iks_insert_node(payload, parameter);
1362                         }
1363                 }
1364
1365                 iks_insert_node(description, payload);
1366                 payloads[i++] = payload;
1367
1368                 ao2_ref(format, -1);
1369         }
1370         /* If this is for audio and there is room for RFC2833 add it in */
1371         if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) {
1372                 iks *payload;
1373
1374                 if ((payload = iks_new("payload-type"))) {
1375                         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1376                                 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1377                         }
1378
1379                         iks_insert_attrib(payload, "id", "101");
1380                         iks_insert_attrib(payload, "name", "telephone-event");
1381                         iks_insert_attrib(payload, "channels", "1");
1382                         iks_insert_attrib(payload, "clockrate", "8000");
1383                         iks_insert_node(description, payload);
1384                         payloads[i++] = payload;
1385                 }
1386         }
1387
1388         return res;
1389 }
1390
1391 /*! \brief Helper function which adds content to a description */
1392 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1393                               const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads)
1394 {
1395         int res = 0;
1396
1397         if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1398                 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1399                 iks_insert_attrib(content, "name", name);
1400                 iks_insert_node(jingle, content);
1401
1402                 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1403                 if (type == AST_MEDIA_TYPE_AUDIO) {
1404                         iks_insert_attrib(description, "media", "audio");
1405                 } else if (type == AST_MEDIA_TYPE_VIDEO) {
1406                         iks_insert_attrib(description, "media", "video");
1407                 } else {
1408                         return -1;
1409                 }
1410                 iks_insert_node(content, description);
1411         } else {
1412                 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1413                 iks_insert_node(jingle, description);
1414         }
1415
1416         if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1417                 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1418                         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1419                         iks_insert_node(content, transport);
1420                 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1421                         iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1422                         iks_insert_node(content, transport);
1423                 }
1424         }
1425
1426         return res;
1427 }
1428
1429 /*! \brief Internal function which sends a complete session message */
1430 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1431 {
1432         iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1433         iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1434         iks *audio_transport = NULL, *video_transport = NULL;
1435         int i, res = 0;
1436
1437         if (!(iq = iks_new("iq")) ||
1438             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1439                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1440                 iks_delete(iq);
1441                 return;
1442         }
1443
1444         memset(audio_payloads, 0, sizeof(audio_payloads));
1445         memset(video_payloads, 0, sizeof(video_payloads));
1446
1447         iks_insert_attrib(iq, "from", session->connection->jid->full);
1448         iks_insert_attrib(iq, "to", session->remote);
1449         iks_insert_attrib(iq, "type", "set");
1450         iks_insert_attrib(iq, "id", session->connection->mid);
1451         ast_xmpp_increment_mid(session->connection->mid);
1452
1453         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1454                 iks_insert_attrib(jingle, "type", action);
1455                 iks_insert_attrib(jingle, "id", session->sid);
1456                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1457         } else {
1458                 iks_insert_attrib(jingle, "action", action);
1459                 iks_insert_attrib(jingle, "sid", session->sid);
1460                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1461         }
1462
1463         if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1464                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1465         }
1466
1467         iks_insert_node(iq, jingle);
1468
1469         if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1470             (audio_transport = iks_new("transport"))) {
1471                 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1472                                          AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads);
1473         } else {
1474                 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1475                 res = -1;
1476         }
1477
1478         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1479                 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1480                     (video_transport = iks_new("transport"))) {
1481                         res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1482                                                  AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads);
1483                 } else {
1484                         ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1485                         res = -1;
1486                 }
1487         }
1488
1489         if (!res) {
1490                 ast_xmpp_client_send(session->connection, iq);
1491         } else {
1492                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1493         }
1494
1495         iks_delete(video_transport);
1496         iks_delete(audio_transport);
1497
1498         for (i = 0; i < session->maxpayloads; i++) {
1499                 iks_delete(video_payloads[i]);
1500                 iks_delete(audio_payloads[i]);
1501         }
1502
1503         iks_delete(video_description);
1504         iks_delete(video);
1505         iks_delete(audio_description);
1506         iks_delete(audio);
1507         iks_delete(jingle);
1508         iks_delete(iq);
1509 }
1510
1511 /*! \brief Internal function which sends a session-inititate message */
1512 static void jingle_send_session_initiate(struct jingle_session *session)
1513 {
1514         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1515 }
1516
1517 /*! \brief Internal function which sends a session-accept message */
1518 static void jingle_send_session_accept(struct jingle_session *session)
1519 {
1520         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1521 }
1522
1523 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1524 static int jingle_outgoing_hook(void *data, ikspak *pak)
1525 {
1526         struct jingle_session *session = data;
1527         iks *error = iks_find(pak->x, "error"), *redirect;
1528
1529         /* In all cases this hook is done with */
1530         iks_filter_remove_rule(session->connection->filter, session->rule);
1531         session->rule = NULL;
1532
1533         ast_callid_threadassoc_add(session->callid);
1534
1535         /* If no error occurred they accepted our session-initiate message happily */
1536         if (!error) {
1537                 struct ast_channel *chan;
1538
1539                 if ((chan = jingle_session_lock_full(session))) {
1540                         ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1541                         ast_channel_unlock(chan);
1542                         ast_channel_unref(chan);
1543                 }
1544                 ao2_unlock(session);
1545
1546                 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1547
1548                 goto end;
1549         }
1550
1551         /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1552         session->gone = 1;
1553
1554         /* Map the error we received to an appropriate cause code and hang up the channel */
1555         if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1556                 iks *to = iks_child(redirect);
1557                 char *target;
1558
1559                 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1560                         /* Make the xmpp: go away if it is present */
1561                         if (!strncmp(target, "xmpp:", 5)) {
1562                                 target += 5;
1563                         }
1564
1565                         /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1566                         ast_copy_string(session->remote, target, sizeof(session->remote));
1567
1568                         /* Add a new hook so we can get the status of redirected session */
1569                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1570                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1571
1572                         jingle_send_session_initiate(session);
1573
1574                         session->gone = 0;
1575                 } else {
1576                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1577                 }
1578         } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1579                 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1580         } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1581                 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1582         } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1583                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1584         } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1585                 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1586         } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1587                 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1588                 session->transport--;
1589
1590                 /* If we still have a viable transport mechanism re-send the session-initiate */
1591                 if (session->transport != JINGLE_TRANSPORT_NONE) {
1592                         struct ast_rtp_engine_ice *ice;
1593
1594                         if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1595                              (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1596                             (ice = ast_rtp_instance_get_ice(session->rtp))) {
1597                                 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1598                                 ice->stop(session->rtp);
1599                         }
1600
1601                         /* Re-send the message to the *original* target and not a redirected one */
1602                         ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1603
1604                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1605                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1606
1607                         jingle_send_session_initiate(session);
1608
1609                         session->gone = 0;
1610                 } else {
1611                         /* Otherwise we have exhausted all transports */
1612                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1613                 }
1614         } else {
1615                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1616         }
1617
1618 end:
1619         ast_callid_threadassoc_remove();
1620
1621         return IKS_FILTER_EAT;
1622 }
1623
1624 /*! \brief Function called by core when we should answer a Jingle session */
1625 static int jingle_answer(struct ast_channel *ast)
1626 {
1627         struct jingle_session *session = ast_channel_tech_pvt(ast);
1628
1629         /* The channel has already been answered so we don't need to do anything */
1630         if (ast_channel_state(ast) == AST_STATE_UP) {
1631                 return 0;
1632         }
1633
1634         jingle_send_session_accept(session);
1635
1636         return 0;
1637 }
1638
1639 /*! \brief Function called by core to read any waiting frames */
1640 static struct ast_frame *jingle_read(struct ast_channel *ast)
1641 {
1642         struct jingle_session *session = ast_channel_tech_pvt(ast);
1643         struct ast_frame *frame = &ast_null_frame;
1644
1645         switch (ast_channel_fdno(ast)) {
1646         case 0:
1647                 if (session->rtp) {
1648                         frame = ast_rtp_instance_read(session->rtp, 0);
1649                 }
1650                 break;
1651         case 1:
1652                 if (session->rtp) {
1653                         frame = ast_rtp_instance_read(session->rtp, 1);
1654                 }
1655                 break;
1656         case 2:
1657                 if (session->vrtp) {
1658                         frame = ast_rtp_instance_read(session->vrtp, 0);
1659                 }
1660                 break;
1661         case 3:
1662                 if (session->vrtp) {
1663                         frame = ast_rtp_instance_read(session->vrtp, 1);
1664                 }
1665                 break;
1666         default:
1667                 break;
1668         }
1669
1670         if (frame && frame->frametype == AST_FRAME_VOICE &&
1671             ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1672                 if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1673                         ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1674                                   ast_format_get_name(frame->subclass.format), ast_channel_name(ast));
1675                         ast_frfree(frame);
1676                         frame = &ast_null_frame;
1677                 } else {
1678                         struct ast_format_cap *caps;
1679
1680                         ast_debug(1, "Oooh, format changed to %s\n",
1681                                   ast_format_get_name(frame->subclass.format));
1682
1683                         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1684                         if (caps) {
1685                                 ast_format_cap_append(caps, frame->subclass.format, 0);
1686                                 ast_channel_nativeformats_set(ast, caps);
1687                                 ao2_ref(caps, -1);
1688                         }
1689                         ast_set_read_format(ast, ast_channel_readformat(ast));
1690                         ast_set_write_format(ast, ast_channel_writeformat(ast));
1691                 }
1692         }
1693
1694         return frame;
1695 }
1696
1697 /*! \brief Function called by core to write frames */
1698 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1699 {
1700         struct jingle_session *session = ast_channel_tech_pvt(ast);
1701         int res = 0;
1702
1703         switch (frame->frametype) {
1704         case AST_FRAME_VOICE:
1705                 if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1706                         struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1707
1708                         ast_log(LOG_WARNING,
1709                                 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1710                                 ast_format_get_name(frame->subclass.format),
1711                                 ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
1712                                 ast_format_get_name(ast_channel_readformat(ast)),
1713                                 ast_format_get_name(ast_channel_writeformat(ast)));
1714                         return 0;
1715                 }
1716                 if (session && session->rtp) {
1717                         res = ast_rtp_instance_write(session->rtp, frame);
1718                 }
1719                 break;
1720         case AST_FRAME_VIDEO:
1721                 if (session && session->vrtp) {
1722                         res = ast_rtp_instance_write(session->vrtp, frame);
1723                 }
1724                 break;
1725         default:
1726                 ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
1727                         frame->frametype);
1728                 return 0;
1729         }
1730
1731         return res;
1732 }
1733
1734 /*! \brief Function called by core to change the underlying owner channel */
1735 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1736 {
1737         struct jingle_session *session = ast_channel_tech_pvt(newchan);
1738
1739         ao2_lock(session);
1740
1741         jingle_set_owner(session, newchan);
1742
1743         ao2_unlock(session);
1744
1745         return 0;
1746 }
1747
1748 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1749 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1750 {
1751         struct jingle_session *session = ast_channel_tech_pvt(ast);
1752         int res = 0;
1753
1754         switch (condition) {
1755         case AST_CONTROL_RINGING:
1756                 if (ast_channel_state(ast) == AST_STATE_RING) {
1757                         jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1758                 } else {
1759                         res = -1;
1760                 }
1761                 break;
1762         case AST_CONTROL_BUSY:
1763                 if (ast_channel_state(ast) != AST_STATE_UP) {
1764                         ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1765                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1766                 } else {
1767                         res = -1;
1768                 }
1769                 break;
1770         case AST_CONTROL_CONGESTION:
1771                 if (ast_channel_state(ast) != AST_STATE_UP) {
1772                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1773                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1774                 } else {
1775                         res = -1;
1776                 }
1777                 break;
1778         case AST_CONTROL_INCOMPLETE:
1779                 if (ast_channel_state(ast) != AST_STATE_UP) {
1780                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1781                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1782                 }
1783                 break;
1784         case AST_CONTROL_HOLD:
1785                 ast_moh_start(ast, data, NULL);
1786                 break;
1787         case AST_CONTROL_UNHOLD:
1788                 ast_moh_stop(ast);
1789                 break;
1790         case AST_CONTROL_SRCUPDATE:
1791                 if (session->rtp) {
1792                         ast_rtp_instance_update_source(session->rtp);
1793                 }
1794                 break;
1795         case AST_CONTROL_SRCCHANGE:
1796                 if (session->rtp) {
1797                         ast_rtp_instance_change_source(session->rtp);
1798                 }
1799                 break;
1800         case AST_CONTROL_VIDUPDATE:
1801         case AST_CONTROL_UPDATE_RTP_PEER:
1802         case AST_CONTROL_CONNECTED_LINE:
1803                 break;
1804         case AST_CONTROL_PVT_CAUSE_CODE:
1805         case AST_CONTROL_MASQUERADE_NOTIFY:
1806         case -1:
1807                 res = -1;
1808                 break;
1809         default:
1810                 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1811                 res = -1;
1812         }
1813
1814         return res;
1815 }
1816
1817 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1818 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1819 {
1820         struct jingle_session *session = ast_channel_tech_pvt(chan);
1821
1822         return ast_xmpp_client_send_message(session->connection, session->remote, text);
1823 }
1824
1825 /*! \brief Function called by core to start a DTMF digit */
1826 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1827 {
1828         struct jingle_session *session = ast_channel_tech_pvt(chan);
1829
1830         if (session->rtp) {
1831                 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1832         }
1833
1834         return 0;
1835 }
1836
1837 /*! \brief Function called by core to stop a DTMF digit */
1838 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1839 {
1840         struct jingle_session *session = ast_channel_tech_pvt(ast);
1841
1842         if (session->rtp) {
1843                 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1844         }
1845
1846         return 0;
1847 }
1848
1849 /*! \brief Function called by core to actually start calling a remote party */
1850 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1851 {
1852         struct jingle_session *session = ast_channel_tech_pvt(ast);
1853
1854         ast_setstate(ast, AST_STATE_RING);
1855
1856         /* Since we have no idea of the remote capabilities use ours for now */
1857         ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN);
1858
1859         /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1860         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1861                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1862
1863         jingle_send_session_initiate(session);
1864
1865         return 0;
1866 }
1867
1868 /*! \brief Function called by core to hang up a Jingle session */
1869 static int jingle_hangup(struct ast_channel *ast)
1870 {
1871         struct jingle_session *session = ast_channel_tech_pvt(ast);
1872
1873         ao2_lock(session);
1874
1875         if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1876                 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1877                 const char *reason = "success";
1878                 int i;
1879
1880                 /* Get the appropriate reason and send a session-terminate */
1881                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1882                         if (jingle_reason_mappings[i].cause == cause) {
1883                                 reason = jingle_reason_mappings[i].reason;
1884                                 break;
1885                         }
1886                 }
1887
1888                 jingle_send_session_terminate(session, reason);
1889         }
1890
1891         ast_channel_tech_pvt_set(ast, NULL);
1892         jingle_set_owner(session, NULL);
1893
1894         ao2_unlink(session->state->sessions, session);
1895         ao2_ref(session->state, -1);
1896
1897         ao2_unlock(session);
1898         ao2_ref(session, -1);
1899
1900         return 0;
1901 }
1902
1903 /*! \brief Function called by core to create a new outgoing Jingle session */
1904 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)
1905 {
1906         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1907         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1908         char *dialed, target[1024] = "";
1909         struct ast_xmpp_buddy *buddy;
1910         struct jingle_session *session;
1911         struct ast_channel *chan;
1912         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1913         struct ast_rtp_engine_ice *ice;
1914         AST_DECLARE_APP_ARGS(args,
1915                              AST_APP_ARG(name);
1916                              AST_APP_ARG(target);
1917                 );
1918
1919         /* We require at a minimum one audio format to be requested */
1920         if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) {
1921                 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1922                 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1923                 return NULL;
1924         }
1925
1926         if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1927                 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1928                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1929                 return NULL;
1930         }
1931
1932         /* Parse the given dial string and validate the results */
1933         AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1934
1935         if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1936                 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1937                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1938                 return NULL;
1939         }
1940
1941         if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1942                 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1943                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1944                 return NULL;
1945         }
1946
1947         ao2_lock(endpoint->state);
1948
1949         /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1950         if (!endpoint->connection) {
1951                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1952                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1953                 ao2_unlock(endpoint->state);
1954                 return NULL;
1955         }
1956
1957         /* Find the target in the roster so we can choose a resource */
1958         if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1959                 struct ao2_iterator res;
1960                 struct ast_xmpp_resource *resource;
1961
1962                 /* Iterate through finding the first viable Jingle capable resource */
1963                 res = ao2_iterator_init(buddy->resources, 0);
1964                 while ((resource = ao2_iterator_next(&res))) {
1965                         if (resource->caps.jingle) {
1966                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1967                                 transport = JINGLE_TRANSPORT_ICE_UDP;
1968                                 break;
1969                         } else if (resource->caps.google) {
1970                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1971                                 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1972                                 break;
1973                         }
1974                         ao2_ref(resource, -1);
1975                 }
1976                 ao2_iterator_destroy(&res);
1977
1978                 ao2_ref(buddy, -1);
1979         } else {
1980                 /* If the target is NOT in the roster use the provided target as-is */
1981                 ast_copy_string(target, args.target, sizeof(target));
1982         }
1983
1984         ao2_unlock(endpoint->state);
1985
1986         /* If no target was found we can't set up a session */
1987         if (ast_strlen_zero(target)) {
1988                 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);
1989                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1990                 return NULL;
1991         }
1992
1993         if (!(session = jingle_alloc(endpoint, target, NULL))) {
1994                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1995                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1996                 return NULL;
1997         }
1998
1999         /* Update the transport if we learned what we should actually use */
2000         if (transport != JINGLE_TRANSPORT_NONE) {
2001                 session->transport = transport;
2002                 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
2003         }
2004
2005         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
2006                 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
2007                 *cause = AST_CAUSE_SWITCH_CONGESTION;
2008                 ao2_ref(session, -1);
2009                 return NULL;
2010         }
2011
2012         /* If video was requested try to enable it on the session */
2013         if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) {
2014                 jingle_enable_video(session);
2015         }
2016
2017         /* As this is outgoing set ourselves as controlling */
2018         if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
2019                 ice->ice_lite(session->rtp);
2020         }
2021
2022         if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
2023                 ice->ice_lite(session->vrtp);
2024         }
2025
2026         /* We purposely don't decrement the session here as there is a reference on the channel */
2027         ao2_link(endpoint->state->sessions, session);
2028
2029         return chan;
2030 }
2031
2032 /*! \brief Helper function which handles content descriptions */
2033 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2034 {
2035         char *media = iks_find_attrib(description, "media");
2036         struct ast_rtp_codecs codecs;
2037         iks *codec;
2038         int othercapability = 0;
2039
2040         /* Google-V1 is always carrying audio, but just doesn't tell us so */
2041         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2042                 media = "audio";
2043         } else if (ast_strlen_zero(media)) {
2044                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2045                 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2046                 return -1;
2047         }
2048
2049         /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2050         if (!strcasecmp(media, "audio")) {
2051                 if (!ast_strlen_zero(name)) {
2052                         ast_string_field_set(session, audio_name, name);
2053                 }
2054                 *rtp = session->rtp;
2055                 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO);
2056                 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO);
2057         } else if (!strcasecmp(media, "video")) {
2058                 if (!ast_strlen_zero(name)) {
2059                         ast_string_field_set(session, video_name, name);
2060                 }
2061
2062                 jingle_enable_video(session);
2063                 *rtp = session->vrtp;
2064
2065                 /* If video is not present cancel this session */
2066                 if (!session->vrtp) {
2067                         jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2068                         ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2069                         return -1;
2070                 }
2071
2072                 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO);
2073                 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO);
2074         } else {
2075                 /* Unknown media type */
2076                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2077                 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2078                 return -1;
2079         }
2080
2081         if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2082                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2083                 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2084                 return -1;
2085         }
2086
2087         /* Iterate the codecs updating the relevant RTP instance as we go */
2088         for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2089                 char *id = iks_find_attrib(codec, "id");
2090                 char *attr_name = iks_find_attrib(codec, "name");
2091                 char *clockrate = iks_find_attrib(codec, "clockrate");
2092                 int rtp_id, rtp_clockrate;
2093
2094                 if (!ast_strlen_zero(id) && !ast_strlen_zero(attr_name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2095                         if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2096                                 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, attr_name, 0, rtp_clockrate);
2097                         } else {
2098                                 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, attr_name, 0);
2099                         }
2100                 }
2101         }
2102
2103         ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2104         ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
2105
2106         if (!ast_format_cap_count(session->jointcap)) {
2107                 /* We have no compatible codecs, so terminate the session appropriately */
2108                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2109                 ast_rtp_codecs_payloads_destroy(&codecs);
2110                 return -1;
2111         }
2112
2113         ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2114         ast_rtp_codecs_payloads_destroy(&codecs);
2115
2116         return 0;
2117 }
2118
2119 /*! \brief Helper function which handles ICE-UDP transport information */
2120 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2121 {
2122         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2123         char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2124         iks *candidate;
2125
2126         if (!ice) {
2127                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2128                 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2129                 return -1;
2130         }
2131
2132         if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2133                 ice->set_authentication(rtp, ufrag, pwd);
2134         }
2135
2136         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2137                 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2138                 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2139                 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2140                 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2141                 char *type = iks_find_attrib(candidate, "type");
2142                 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2143                 int real_port;
2144                 struct ast_sockaddr remote_address = { { 0, } };
2145
2146                 /* If this candidate is incomplete skip it */
2147                 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2148                     ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2149                     ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2150                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2151                         ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2152                         return -1;
2153                 }
2154
2155                 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2156                     (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
2157                     (sscanf(port, "%30d", &real_port) != 1)) {
2158                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2159                         ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2160                         return -1;
2161                 }
2162
2163                 local_candidate.foundation = foundation;
2164                 local_candidate.transport = protocol;
2165
2166                 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2167
2168                 /* We only support IPv4 right now */
2169                 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2170                         continue;
2171                 }
2172
2173                 ast_sockaddr_set_port(&local_candidate.address, real_port);
2174
2175                 if (!strcasecmp(type, "host")) {
2176                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2177                 } else if (!strcasecmp(type, "srflx")) {
2178                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2179                 } else if (!strcasecmp(type, "relay")) {
2180                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2181                 } else {
2182                         continue;
2183                 }
2184
2185                 /* Worst case use the first viable address */
2186                 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2187
2188                 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2189                         ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2190                 }
2191
2192                 ice->add_remote_candidate(rtp, &local_candidate);
2193         }
2194
2195         ice->start(rtp);
2196
2197         return 0;
2198 }
2199
2200 /*! \brief Helper function which handles Google transport information */
2201 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2202 {
2203         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2204         iks *candidate;
2205
2206         if (!ice) {
2207                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2208                 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2209                 return -1;
2210         }
2211
2212         /* If this session has not transitioned to the Google transport do so now */
2213         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2214             (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2215                 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2216                 ice->stop(rtp);
2217
2218                 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2219         }
2220
2221         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2222                 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2223                 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2224                 char *protocol = iks_find_attrib(candidate, "protocol");
2225                 int real_port;
2226                 struct ast_sockaddr target = { { 0, } };
2227                 /* In Google land the combined value is 32 bytes */
2228                 char combined[33] = "";
2229
2230                 /* If this is NOT actually a candidate just skip it */
2231                 if (strcasecmp(iks_name(candidate), "candidate") &&
2232                     strcasecmp(iks_name(candidate), "p:candidate") &&
2233                     strcasecmp(iks_name(candidate), "ses:candidate")) {
2234                         continue;
2235                 }
2236
2237                 /* If this candidate is incomplete skip it */
2238                 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2239                     ast_strlen_zero(name)) {
2240                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2241                         ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2242                         return -1;
2243                 }
2244
2245                 /* We only support UDP so skip any other protocols */
2246                 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2247                         continue;
2248                 }
2249
2250                 /* We only permit audio and video, not RTCP */
2251                 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2252                         continue;
2253                 }
2254
2255                 /* Parse the target information so we can send a STUN request to the candidate */
2256                 if (sscanf(port, "%30d", &real_port) != 1) {
2257                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2258                         ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2259                         return -1;
2260                 }
2261                 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2262                 ast_sockaddr_set_port(&target, real_port);
2263
2264                 /* Per the STUN support Google talk uses combine the two usernames */
2265                 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2266
2267                 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2268                 ast_rtp_instance_stun_request(rtp, &target, combined);
2269         }
2270
2271         return 0;
2272 }
2273
2274 /*!
2275  * \brief Helper function which locates content stanzas and interprets them
2276  *
2277  * \note The session *must not* be locked before calling this
2278  */
2279 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2280 {
2281         iks *content;
2282         unsigned int changed = 0;
2283         struct ast_channel *chan;
2284
2285         /* Look at the content in the session initiation */
2286         for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2287                 char *name;
2288                 struct ast_rtp_instance *rtp = NULL;
2289                 iks *description, *transport;
2290
2291                 /* Ignore specific parts if they are known not to be useful */
2292                 if (!strcmp(iks_name(content), "conference-info")) {
2293                         continue;
2294                 }
2295
2296                 name = iks_find_attrib(content, "name");
2297
2298                 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2299                         /* If this content stanza has no name consider it invalid and move on */
2300                         if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2301                                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2302                                 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2303                                 return -1;
2304                         }
2305
2306                         /* Try to pre-populate which RTP instance this content is relevant to */
2307                         if (!strcmp(session->audio_name, name)) {
2308                                 rtp = session->rtp;
2309                         } else if (!strcmp(session->video_name, name)) {
2310                                 rtp = session->vrtp;
2311                         }
2312                 } else {
2313                         /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2314                         rtp = session->rtp;
2315                 }
2316
2317                 /* If description information is available use it */
2318                 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2319                     (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2320                     (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2321                     (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2322                     (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2323                     (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2324                         /* If we failed to do something with the content description abort immediately */
2325                         if (jingle_interpret_description(session, description, name, &rtp)) {
2326                                 return -1;
2327                         }
2328
2329                         /* If we successfully interpret the description then the codecs need updating */
2330                         changed = 1;
2331                 }
2332
2333                 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2334                 if (!rtp) {
2335                         ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2336                         jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2337                         return -1;
2338                 }
2339
2340                 /* If ICE UDP transport information is available use it */
2341                 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2342                         if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2343                                 return -1;
2344                         }
2345                 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2346                            (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2347                            (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2348                            (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2349                         /* If Google transport support is available use it */
2350                         if (jingle_interpret_google_transport(session, transport, rtp)) {
2351                                 return -1;
2352                         }
2353                 } else if (iks_find(content, "transport")) {
2354                         /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2355                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2356                         ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2357                         return -1;
2358                 }
2359         }
2360
2361         if (!changed) {
2362                 return 0;
2363         }
2364
2365         if ((chan = jingle_session_lock_full(session))) {
2366                 struct ast_format_cap *caps;
2367                 struct ast_format *fmt;
2368
2369                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
2370                 if (caps) {
2371                         ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
2372                         ast_channel_nativeformats_set(chan, caps);
2373                         ao2_ref(caps, -1);
2374                 }
2375
2376                 fmt = ast_format_cap_get_format(session->jointcap, 0);
2377                 ast_set_read_format(chan, fmt);
2378                 ast_set_write_format(chan, fmt);
2379                 ao2_ref(fmt, -1);
2380
2381                 ast_channel_unlock(chan);
2382                 ast_channel_unref(chan);
2383         }
2384         ao2_unlock(session);
2385
2386         return 0;
2387 }
2388
2389 /*! \brief Handler function for the 'session-initiate' action */
2390 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2391 {
2392         char *sid;
2393         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2394         struct ast_channel *chan;
2395         int res;
2396
2397         if (session) {
2398                 /* This is a duplicate session setup, so respond accordingly */
2399                 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2400                 return;
2401         }
2402
2403         /* Retrieve the session identifier from the message, note that this may alter the transport */
2404         if ((sid = iks_find_attrib(pak->query, "id"))) {
2405                 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2406                 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2407         } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2408                 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2409                 return;
2410         }
2411
2412         /* Create a new local session */
2413         if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2414                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2415                 return;
2416         }
2417
2418         /* If we determined that the transport should change as a result of how we got the SID change it */
2419         if (transport != JINGLE_TRANSPORT_NONE) {
2420                 session->transport = transport;
2421         }
2422
2423         /* Create a new Asterisk channel using the above local session */
2424         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2425                 ao2_ref(session, -1);
2426                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2427                 return;
2428         }
2429
2430         ao2_link(endpoint->state->sessions, session);
2431
2432         ast_channel_lock(chan);
2433         ast_setstate(chan, AST_STATE_RING);
2434         ast_channel_unlock(chan);
2435         res = ast_pbx_start(chan);
2436
2437         switch (res) {
2438         case AST_PBX_FAILED:
2439                 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2440                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2441                 session->gone = 1;
2442                 ast_hangup(chan);
2443                 break;
2444         case AST_PBX_CALL_LIMIT:
2445                 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2446                 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2447                 ast_hangup(chan);
2448                 break;
2449         case AST_PBX_SUCCESS:
2450                 jingle_send_response(endpoint->connection, pak);
2451
2452                 /* Only send a transport-info message if we successfully interpreted the available content */
2453                 if (!jingle_interpret_content(session, pak)) {
2454                         jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2455                 }
2456                 break;
2457         }
2458 }
2459
2460 /*! \brief Handler function for the 'transport-info' action */
2461 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2462 {
2463         if (!session) {
2464                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2465                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2466                 return;
2467         }
2468
2469         jingle_interpret_content(session, pak);
2470         jingle_send_response(endpoint->connection, pak);
2471 }
2472
2473 /*! \brief Handler function for the 'session-accept' action */
2474 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2475 {
2476         struct ast_channel *chan;
2477
2478         if (!session) {
2479                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2480                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2481                 return;
2482         }
2483
2484
2485         jingle_interpret_content(session, pak);
2486
2487         if ((chan = jingle_session_lock_full(session))) {
2488                 ast_queue_control(chan, AST_CONTROL_ANSWER);
2489                 ast_channel_unlock(chan);
2490                 ast_channel_unref(chan);
2491         }
2492         ao2_unlock(session);
2493
2494         jingle_send_response(endpoint->connection, pak);
2495 }
2496
2497 /*! \brief Handler function for the 'session-info' action */
2498 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2499 {
2500         struct ast_channel *chan;
2501
2502         if (!session) {
2503                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2504                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2505                 return;
2506         }
2507
2508         if (!(chan = jingle_session_lock_full(session))) {
2509                 ao2_unlock(session);
2510                 jingle_send_response(endpoint->connection, pak);
2511                 return;
2512         }
2513
2514         if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2515                 ast_queue_control(chan, AST_CONTROL_RINGING);
2516                 if (ast_channel_state(chan) != AST_STATE_UP) {
2517                         ast_setstate(chan, AST_STATE_RINGING);
2518                 }
2519         } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2520                 ast_queue_hold(chan, NULL);
2521         } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2522                 ast_queue_unhold(chan);
2523         }
2524
2525         ast_channel_unlock(chan);
2526         ast_channel_unref(chan);
2527         ao2_unlock(session);
2528
2529         jingle_send_response(endpoint->connection, pak);
2530 }
2531
2532 /*! \brief Handler function for the 'session-terminate' action */
2533 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2534 {
2535         struct ast_channel *chan;
2536         iks *reason, *text;
2537         int cause = AST_CAUSE_NORMAL;
2538         struct ast_control_pvt_cause_code *cause_code;
2539         int data_size = sizeof(*cause_code);
2540
2541         if (!session) {
2542                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2543                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2544                 return;
2545         }
2546
2547         if (!(chan = jingle_session_lock_full(session))) {
2548                 ao2_unlock(session);
2549                 jingle_send_response(endpoint->connection, pak);
2550                 return;
2551         }
2552
2553         /* Pull the reason text from the session-terminate message and translate it into a cause code */
2554         if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2555                 int i;
2556
2557                 /* Size of the string making up the cause code is "Motif " + text */
2558                 data_size += 6 + strlen(iks_name(text));
2559                 cause_code = ast_alloca(data_size);
2560                 memset(cause_code, 0, data_size);
2561
2562                 /* Get the appropriate cause code mapping for this reason */
2563                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2564                         if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2565                                 cause = jingle_reason_mappings[i].cause;
2566                                 break;
2567                         }
2568                 }
2569
2570                 /* Store the technology specific information */
2571                 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2572         } else {
2573                 /* No technology specific information is available */
2574                 cause_code = ast_alloca(data_size);
2575                 memset(cause_code, 0, data_size);
2576         }
2577
2578         ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2579         cause_code->ast_cause = cause;
2580         ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2581         ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2582
2583         ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2584         ast_queue_hangup_with_cause(chan, cause);
2585         session->gone = 1;
2586
2587         ast_channel_unlock(chan);
2588         ast_channel_unref(chan);
2589         ao2_unlock(session);
2590
2591         jingle_send_response(endpoint->connection, pak);
2592 }
2593
2594 /*! \brief Callback for when a Jingle action is received from an endpoint */
2595 static int jingle_action_hook(void *data, ikspak *pak)
2596 {
2597         char *action;
2598         const char *sid = NULL;
2599         struct jingle_session *session = NULL;
2600         struct jingle_endpoint *endpoint = data;
2601         int i, handled = 0;
2602
2603         /* We accept both Jingle and Google-V1 */
2604         if (!(action = iks_find_attrib(pak->query, "action")) &&
2605             !(action = iks_find_attrib(pak->query, "type"))) {
2606                 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2607                  * to a message that has no response hook. */
2608                 return IKS_FILTER_EAT;
2609         }
2610
2611         /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2612          * does not permit us to make this completely safe. */
2613         ao2_ref(endpoint, +1);
2614
2615         /* If a Jingle session identifier is present use it */
2616         if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2617                 /* If a Google-V1 session identifier is present use it */
2618                 sid = iks_find_attrib(pak->query, "id");
2619         }
2620
2621         /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2622          * this is required or not */
2623         if (!ast_strlen_zero(sid)) {
2624                 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2625         }
2626
2627         /* If a session is present associate the callid with this thread */
2628         if (session) {
2629                 ast_callid_threadassoc_add(session->callid);
2630         }
2631
2632         /* Iterate through supported action handlers looking for one that is able to handle this */
2633         for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2634                 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2635                         jingle_action_handlers[i].handler(endpoint, session, pak);
2636                         handled = 1;
2637                         break;
2638                 }
2639         }
2640
2641         /* If no action handler is present for the action they sent us make it evident */
2642         if (!handled) {
2643                 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2644         }
2645
2646         /* If a session was successfully found for this message deref it now since the handler is done */
2647         if (session) {
2648                 ast_callid_threadassoc_remove();
2649                 ao2_ref(session, -1);
2650         }
2651
2652         ao2_ref(endpoint, -1);
2653
2654         return IKS_FILTER_EAT;
2655 }
2656
2657 /*! \brief Custom handler for groups */
2658 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2659 {
2660         struct jingle_endpoint *endpoint = obj;
2661
2662         if (!strcasecmp(var->name, "callgroup")) {
2663                 endpoint->callgroup = ast_get_group(var->value);
2664         } else if (!strcasecmp(var->name, "pickupgroup")) {
2665                 endpoint->pickupgroup = ast_get_group(var->value);
2666         } else {
2667                 return -1;
2668         }
2669
2670         return 0;
2671 }
2672
2673 /*! \brief Custom handler for connection */
2674 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2675 {
2676         struct jingle_endpoint *endpoint = obj;
2677
2678         /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2679          * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2680          */
2681         if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2682                 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2683                 return -1;
2684         }
2685
2686         if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2687                                                    IKS_RULE_TYPE, IKS_PAK_IQ,
2688                                                    IKS_RULE_NS, JINGLE_NS,
2689                                                    IKS_RULE_NS, GOOGLE_SESSION_NS,
2690                                                    IKS_RULE_DONE))) {
2691                 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2692                 return -1;
2693         }
2694
2695         return 0;
2696 }
2697
2698 /*! \brief Custom handler for transport */
2699 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2700 {
2701         struct jingle_endpoint *endpoint = obj;
2702
2703         if (!strcasecmp(var->value, "ice-udp")) {
2704                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2705         } else if (!strcasecmp(var->value, "google")) {
2706                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2707         } else if (!strcasecmp(var->value, "google-v1")) {
2708                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2709         } else {
2710                 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2711                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2712         }
2713
2714         return 0;
2715 }
2716
2717 /*!
2718  * \brief Load the module
2719  *
2720  * Module loading including tests for configuration or dependencies.
2721  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2722  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2723  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2724  * configuration file or other non-critical problem return
2725  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2726  */
2727 static int load_module(void)
2728 {
2729         if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2730                 return AST_MODULE_LOAD_DECLINE;
2731         }
2732
2733         if (aco_info_init(&cfg_info)) {
2734                 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2735                 goto end;
2736         }
2737
2738         aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2739         aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2740         aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2741         aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2742         aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2743         aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2744         aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2745         aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
2746         aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
2747         aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2748         aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2749         aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2750                             FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2751         aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2752                             FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2753
2754         ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
2755
2756         if (aco_process_config(&cfg_info, 0)) {
2757                 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2758                 aco_info_destroy(&cfg_info);
2759                 ao2_cleanup(jingle_tech.capabilities);
2760                 jingle_tech.capabilities = NULL;
2761                 return AST_MODULE_LOAD_DECLINE;
2762         }
2763
2764         if (!(sched = ast_sched_context_create())) {
2765                 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2766                 goto end;
2767         }
2768
2769         if (ast_sched_start_thread(sched)) {
2770                 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2771                 goto end;
2772         }
2773
2774         ast_rtp_glue_register(&jingle_rtp_glue);
2775
2776         if (ast_channel_register(&jingle_tech)) {
2777                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2778                 goto end;
2779         }
2780
2781         return 0;
2782
2783 end:
2784         ast_rtp_glue_unregister(&jingle_rtp_glue);
2785
2786         if (sched) {
2787                 ast_sched_context_destroy(sched);
2788         }
2789
2790         aco_info_destroy(&cfg_info);
2791         ao2_global_obj_release(globals);
2792
2793         ao2_cleanup(jingle_tech.capabilities);
2794         jingle_tech.capabilities = NULL;
2795
2796         return AST_MODULE_LOAD_DECLINE;
2797 }
2798
2799 /*! \brief Reload module */
2800 static int reload(void)
2801 {
2802         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2803                 return -1;
2804         }
2805
2806         return 0;
2807 }
2808
2809 /*! \brief Unload the jingle channel from Asterisk */
2810 static int unload_module(void)
2811 {
2812         ast_channel_unregister(&jingle_tech);
2813         ao2_cleanup(jingle_tech.capabilities);
2814         jingle_tech.capabilities = NULL;
2815         ast_rtp_glue_unregister(&jingle_rtp_glue);
2816         ast_sched_context_destroy(sched);
2817         aco_info_destroy(&cfg_info);
2818         ao2_global_obj_release(globals);
2819
2820         return 0;
2821 }
2822
2823 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2824         .support_level = AST_MODULE_SUPPORT_CORE,
2825         .load = load_module,
2826         .unload = unload_module,
2827         .reload = reload,
2828         .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2829         .requires = "res_xmpp",
2830 );