stasic.c: Fix printf format type mismatches with arguments.
[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"), *name = iks_find_attrib(codec, "name");
2090                 char *clockrate = iks_find_attrib(codec, "clockrate");
2091                 int rtp_id, rtp_clockrate;
2092
2093                 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2094                         if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2095                                 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2096                         } else {
2097                                 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2098                         }
2099                 }
2100         }
2101
2102         ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2103         ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
2104
2105         if (!ast_format_cap_count(session->jointcap)) {
2106                 /* We have no compatible codecs, so terminate the session appropriately */
2107                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2108                 ast_rtp_codecs_payloads_destroy(&codecs);
2109                 return -1;
2110         }
2111
2112         ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2113         ast_rtp_codecs_payloads_destroy(&codecs);
2114
2115         return 0;
2116 }
2117
2118 /*! \brief Helper function which handles ICE-UDP transport information */
2119 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2120 {
2121         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2122         char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2123         iks *candidate;
2124
2125         if (!ice) {
2126                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2127                 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2128                 return -1;
2129         }
2130
2131         if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2132                 ice->set_authentication(rtp, ufrag, pwd);
2133         }
2134
2135         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2136                 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2137                 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2138                 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2139                 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2140                 char *type = iks_find_attrib(candidate, "type");
2141                 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2142                 int real_port;
2143                 struct ast_sockaddr remote_address = { { 0, } };
2144
2145                 /* If this candidate is incomplete skip it */
2146                 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2147                     ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2148                     ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2149                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2150                         ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2151                         return -1;
2152                 }
2153
2154                 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2155                     (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
2156                     (sscanf(port, "%30d", &real_port) != 1)) {
2157                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2158                         ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2159                         return -1;
2160                 }
2161
2162                 local_candidate.foundation = foundation;
2163                 local_candidate.transport = protocol;
2164
2165                 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2166
2167                 /* We only support IPv4 right now */
2168                 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2169                         continue;
2170                 }
2171
2172                 ast_sockaddr_set_port(&local_candidate.address, real_port);
2173
2174                 if (!strcasecmp(type, "host")) {
2175                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2176                 } else if (!strcasecmp(type, "srflx")) {
2177                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2178                 } else if (!strcasecmp(type, "relay")) {
2179                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2180                 } else {
2181                         continue;
2182                 }
2183
2184                 /* Worst case use the first viable address */
2185                 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2186
2187                 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2188                         ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2189                 }
2190
2191                 ice->add_remote_candidate(rtp, &local_candidate);
2192         }
2193
2194         ice->start(rtp);
2195
2196         return 0;
2197 }
2198
2199 /*! \brief Helper function which handles Google transport information */
2200 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2201 {
2202         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2203         iks *candidate;
2204
2205         if (!ice) {
2206                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2207                 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2208                 return -1;
2209         }
2210
2211         /* If this session has not transitioned to the Google transport do so now */
2212         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2213             (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2214                 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2215                 ice->stop(rtp);
2216
2217                 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2218         }
2219
2220         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2221                 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2222                 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2223                 char *protocol = iks_find_attrib(candidate, "protocol");
2224                 int real_port;
2225                 struct ast_sockaddr target = { { 0, } };
2226                 /* In Google land the combined value is 32 bytes */
2227                 char combined[33] = "";
2228
2229                 /* If this is NOT actually a candidate just skip it */
2230                 if (strcasecmp(iks_name(candidate), "candidate") &&
2231                     strcasecmp(iks_name(candidate), "p:candidate") &&
2232                     strcasecmp(iks_name(candidate), "ses:candidate")) {
2233                         continue;
2234                 }
2235
2236                 /* If this candidate is incomplete skip it */
2237                 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2238                     ast_strlen_zero(name)) {
2239                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2240                         ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2241                         return -1;
2242                 }
2243
2244                 /* We only support UDP so skip any other protocols */
2245                 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2246                         continue;
2247                 }
2248
2249                 /* We only permit audio and video, not RTCP */
2250                 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2251                         continue;
2252                 }
2253
2254                 /* Parse the target information so we can send a STUN request to the candidate */
2255                 if (sscanf(port, "%30d", &real_port) != 1) {
2256                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2257                         ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2258                         return -1;
2259                 }
2260                 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2261                 ast_sockaddr_set_port(&target, real_port);
2262
2263                 /* Per the STUN support Google talk uses combine the two usernames */
2264                 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2265
2266                 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2267                 ast_rtp_instance_stun_request(rtp, &target, combined);
2268         }
2269
2270         return 0;
2271 }
2272
2273 /*!
2274  * \brief Helper function which locates content stanzas and interprets them
2275  *
2276  * \note The session *must not* be locked before calling this
2277  */
2278 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2279 {
2280         iks *content;
2281         unsigned int changed = 0;
2282         struct ast_channel *chan;
2283
2284         /* Look at the content in the session initiation */
2285         for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2286                 char *name;
2287                 struct ast_rtp_instance *rtp = NULL;
2288                 iks *description, *transport;
2289
2290                 /* Ignore specific parts if they are known not to be useful */
2291                 if (!strcmp(iks_name(content), "conference-info")) {
2292                         continue;
2293                 }
2294
2295                 name = iks_find_attrib(content, "name");
2296
2297                 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2298                         /* If this content stanza has no name consider it invalid and move on */
2299                         if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2300                                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2301                                 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2302                                 return -1;
2303                         }
2304
2305                         /* Try to pre-populate which RTP instance this content is relevant to */
2306                         if (!strcmp(session->audio_name, name)) {
2307                                 rtp = session->rtp;
2308                         } else if (!strcmp(session->video_name, name)) {
2309                                 rtp = session->vrtp;
2310                         }
2311                 } else {
2312                         /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2313                         rtp = session->rtp;
2314                 }
2315
2316                 /* If description information is available use it */
2317                 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2318                     (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2319                     (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2320                     (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2321                     (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2322                     (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2323                         /* If we failed to do something with the content description abort immediately */
2324                         if (jingle_interpret_description(session, description, name, &rtp)) {
2325                                 return -1;
2326                         }
2327
2328                         /* If we successfully interpret the description then the codecs need updating */
2329                         changed = 1;
2330                 }
2331
2332                 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2333                 if (!rtp) {
2334                         ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2335                         jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2336                         return -1;
2337                 }
2338
2339                 /* If ICE UDP transport information is available use it */
2340                 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2341                         if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2342                                 return -1;
2343                         }
2344                 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2345                            (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2346                            (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2347                            (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2348                         /* If Google transport support is available use it */
2349                         if (jingle_interpret_google_transport(session, transport, rtp)) {
2350                                 return -1;
2351                         }
2352                 } else if (iks_find(content, "transport")) {
2353                         /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2354                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2355                         ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2356                         return -1;
2357                 }
2358         }
2359
2360         if (!changed) {
2361                 return 0;
2362         }
2363
2364         if ((chan = jingle_session_lock_full(session))) {
2365                 struct ast_format_cap *caps;
2366                 struct ast_format *fmt;
2367
2368                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
2369                 if (caps) {
2370                         ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
2371                         ast_channel_nativeformats_set(chan, caps);
2372                         ao2_ref(caps, -1);
2373                 }
2374
2375                 fmt = ast_format_cap_get_format(session->jointcap, 0);
2376                 ast_set_read_format(chan, fmt);
2377                 ast_set_write_format(chan, fmt);
2378                 ao2_ref(fmt, -1);
2379
2380                 ast_channel_unlock(chan);
2381                 ast_channel_unref(chan);
2382         }
2383         ao2_unlock(session);
2384
2385         return 0;
2386 }
2387
2388 /*! \brief Handler function for the 'session-initiate' action */
2389 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2390 {
2391         char *sid;
2392         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2393         struct ast_channel *chan;
2394         int res;
2395
2396         if (session) {
2397                 /* This is a duplicate session setup, so respond accordingly */
2398                 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2399                 return;
2400         }
2401
2402         /* Retrieve the session identifier from the message, note that this may alter the transport */
2403         if ((sid = iks_find_attrib(pak->query, "id"))) {
2404                 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2405                 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2406         } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2407                 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2408                 return;
2409         }
2410
2411         /* Create a new local session */
2412         if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2413                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2414                 return;
2415         }
2416
2417         /* If we determined that the transport should change as a result of how we got the SID change it */
2418         if (transport != JINGLE_TRANSPORT_NONE) {
2419                 session->transport = transport;
2420         }
2421
2422         /* Create a new Asterisk channel using the above local session */
2423         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2424                 ao2_ref(session, -1);
2425                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2426                 return;
2427         }
2428
2429         ao2_link(endpoint->state->sessions, session);
2430
2431         ast_channel_lock(chan);
2432         ast_setstate(chan, AST_STATE_RING);
2433         ast_channel_unlock(chan);
2434         res = ast_pbx_start(chan);
2435
2436         switch (res) {
2437         case AST_PBX_FAILED:
2438                 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2439                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2440                 session->gone = 1;
2441                 ast_hangup(chan);
2442                 break;
2443         case AST_PBX_CALL_LIMIT:
2444                 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2445                 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2446                 ast_hangup(chan);
2447                 break;
2448         case AST_PBX_SUCCESS:
2449                 jingle_send_response(endpoint->connection, pak);
2450
2451                 /* Only send a transport-info message if we successfully interpreted the available content */
2452                 if (!jingle_interpret_content(session, pak)) {
2453                         jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2454                 }
2455                 break;
2456         }
2457 }
2458
2459 /*! \brief Handler function for the 'transport-info' action */
2460 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2461 {
2462         if (!session) {
2463                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2464                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2465                 return;
2466         }
2467
2468         jingle_interpret_content(session, pak);
2469         jingle_send_response(endpoint->connection, pak);
2470 }
2471
2472 /*! \brief Handler function for the 'session-accept' action */
2473 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2474 {
2475         struct ast_channel *chan;
2476
2477         if (!session) {
2478                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2479                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2480                 return;
2481         }
2482
2483
2484         jingle_interpret_content(session, pak);
2485
2486         if ((chan = jingle_session_lock_full(session))) {
2487                 ast_queue_control(chan, AST_CONTROL_ANSWER);
2488                 ast_channel_unlock(chan);
2489                 ast_channel_unref(chan);
2490         }
2491         ao2_unlock(session);
2492
2493         jingle_send_response(endpoint->connection, pak);
2494 }
2495
2496 /*! \brief Handler function for the 'session-info' action */
2497 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2498 {
2499         struct ast_channel *chan;
2500
2501         if (!session) {
2502                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2503                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2504                 return;
2505         }
2506
2507         if (!(chan = jingle_session_lock_full(session))) {
2508                 ao2_unlock(session);
2509                 jingle_send_response(endpoint->connection, pak);
2510                 return;
2511         }
2512
2513         if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2514                 ast_queue_control(chan, AST_CONTROL_RINGING);
2515                 if (ast_channel_state(chan) != AST_STATE_UP) {
2516                         ast_setstate(chan, AST_STATE_RINGING);
2517                 }
2518         } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2519                 ast_queue_hold(chan, NULL);
2520         } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2521                 ast_queue_unhold(chan);
2522         }
2523
2524         ast_channel_unlock(chan);
2525         ast_channel_unref(chan);
2526         ao2_unlock(session);
2527
2528         jingle_send_response(endpoint->connection, pak);
2529 }
2530
2531 /*! \brief Handler function for the 'session-terminate' action */
2532 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2533 {
2534         struct ast_channel *chan;
2535         iks *reason, *text;
2536         int cause = AST_CAUSE_NORMAL;
2537         struct ast_control_pvt_cause_code *cause_code;
2538         int data_size = sizeof(*cause_code);
2539
2540         if (!session) {
2541                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2542                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2543                 return;
2544         }
2545
2546         if (!(chan = jingle_session_lock_full(session))) {
2547                 ao2_unlock(session);
2548                 jingle_send_response(endpoint->connection, pak);
2549                 return;
2550         }
2551
2552         /* Pull the reason text from the session-terminate message and translate it into a cause code */
2553         if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2554                 int i;
2555
2556                 /* Size of the string making up the cause code is "Motif " + text */
2557                 data_size += 6 + strlen(iks_name(text));
2558                 cause_code = ast_alloca(data_size);
2559                 memset(cause_code, 0, data_size);
2560
2561                 /* Get the appropriate cause code mapping for this reason */
2562                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2563                         if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2564                                 cause = jingle_reason_mappings[i].cause;
2565                                 break;
2566                         }
2567                 }
2568
2569                 /* Store the technology specific information */
2570                 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2571         } else {
2572                 /* No technology specific information is available */
2573                 cause_code = ast_alloca(data_size);
2574                 memset(cause_code, 0, data_size);
2575         }
2576
2577         ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2578         cause_code->ast_cause = cause;
2579         ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2580         ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2581
2582         ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2583         ast_queue_hangup_with_cause(chan, cause);
2584         session->gone = 1;
2585
2586         ast_channel_unlock(chan);
2587         ast_channel_unref(chan);
2588         ao2_unlock(session);
2589
2590         jingle_send_response(endpoint->connection, pak);
2591 }
2592
2593 /*! \brief Callback for when a Jingle action is received from an endpoint */
2594 static int jingle_action_hook(void *data, ikspak *pak)
2595 {
2596         char *action;
2597         const char *sid = NULL;
2598         struct jingle_session *session = NULL;
2599         struct jingle_endpoint *endpoint = data;
2600         int i, handled = 0;
2601
2602         /* We accept both Jingle and Google-V1 */
2603         if (!(action = iks_find_attrib(pak->query, "action")) &&
2604             !(action = iks_find_attrib(pak->query, "type"))) {
2605                 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2606                  * to a message that has no response hook. */
2607                 return IKS_FILTER_EAT;
2608         }
2609
2610         /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2611          * does not permit us to make this completely safe. */
2612         ao2_ref(endpoint, +1);
2613
2614         /* If a Jingle session identifier is present use it */
2615         if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2616                 /* If a Google-V1 session identifier is present use it */
2617                 sid = iks_find_attrib(pak->query, "id");
2618         }
2619
2620         /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2621          * this is required or not */
2622         if (!ast_strlen_zero(sid)) {
2623                 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2624         }
2625
2626         /* If a session is present associate the callid with this thread */
2627         if (session) {
2628                 ast_callid_threadassoc_add(session->callid);
2629         }
2630
2631         /* Iterate through supported action handlers looking for one that is able to handle this */
2632         for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2633                 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2634                         jingle_action_handlers[i].handler(endpoint, session, pak);
2635                         handled = 1;
2636                         break;
2637                 }
2638         }
2639
2640         /* If no action handler is present for the action they sent us make it evident */
2641         if (!handled) {
2642                 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2643         }
2644
2645         /* If a session was successfully found for this message deref it now since the handler is done */
2646         if (session) {
2647                 ast_callid_threadassoc_remove();
2648                 ao2_ref(session, -1);
2649         }
2650
2651         ao2_ref(endpoint, -1);
2652
2653         return IKS_FILTER_EAT;
2654 }
2655
2656 /*! \brief Custom handler for groups */
2657 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2658 {
2659         struct jingle_endpoint *endpoint = obj;
2660
2661         if (!strcasecmp(var->name, "callgroup")) {
2662                 endpoint->callgroup = ast_get_group(var->value);
2663         } else if (!strcasecmp(var->name, "pickupgroup")) {
2664                 endpoint->pickupgroup = ast_get_group(var->value);
2665         } else {
2666                 return -1;
2667         }
2668
2669         return 0;
2670 }
2671
2672 /*! \brief Custom handler for connection */
2673 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2674 {
2675         struct jingle_endpoint *endpoint = obj;
2676
2677         /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2678          * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2679          */
2680         if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2681                 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2682                 return -1;
2683         }
2684
2685         if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2686                                                    IKS_RULE_TYPE, IKS_PAK_IQ,
2687                                                    IKS_RULE_NS, JINGLE_NS,
2688                                                    IKS_RULE_NS, GOOGLE_SESSION_NS,
2689                                                    IKS_RULE_DONE))) {
2690                 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2691                 return -1;
2692         }
2693
2694         return 0;
2695 }
2696
2697 /*! \brief Custom handler for transport */
2698 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2699 {
2700         struct jingle_endpoint *endpoint = obj;
2701
2702         if (!strcasecmp(var->value, "ice-udp")) {
2703                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2704         } else if (!strcasecmp(var->value, "google")) {
2705                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2706         } else if (!strcasecmp(var->value, "google-v1")) {
2707                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2708         } else {
2709                 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2710                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2711         }
2712
2713         return 0;
2714 }
2715
2716 /*!
2717  * \brief Load the module
2718  *
2719  * Module loading including tests for configuration or dependencies.
2720  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2721  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2722  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2723  * configuration file or other non-critical problem return
2724  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2725  */
2726 static int load_module(void)
2727 {
2728         if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2729                 return AST_MODULE_LOAD_DECLINE;
2730         }
2731
2732         if (aco_info_init(&cfg_info)) {
2733                 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2734                 goto end;
2735         }
2736
2737         aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2738         aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2739         aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2740         aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2741         aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2742         aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2743         aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2744         aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
2745         aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
2746         aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2747         aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2748         aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2749                             FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2750         aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2751                             FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2752
2753         ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
2754
2755         if (aco_process_config(&cfg_info, 0)) {
2756                 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2757                 aco_info_destroy(&cfg_info);
2758                 ao2_cleanup(jingle_tech.capabilities);
2759                 jingle_tech.capabilities = NULL;
2760                 return AST_MODULE_LOAD_DECLINE;
2761         }
2762
2763         if (!(sched = ast_sched_context_create())) {
2764                 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2765                 goto end;
2766         }
2767
2768         if (ast_sched_start_thread(sched)) {
2769                 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2770                 goto end;
2771         }
2772
2773         ast_rtp_glue_register(&jingle_rtp_glue);
2774
2775         if (ast_channel_register(&jingle_tech)) {
2776                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2777                 goto end;
2778         }
2779
2780         return 0;
2781
2782 end:
2783         ast_rtp_glue_unregister(&jingle_rtp_glue);
2784
2785         if (sched) {
2786                 ast_sched_context_destroy(sched);
2787         }
2788
2789         aco_info_destroy(&cfg_info);
2790         ao2_global_obj_release(globals);
2791
2792         ao2_cleanup(jingle_tech.capabilities);
2793         jingle_tech.capabilities = NULL;
2794
2795         return AST_MODULE_LOAD_DECLINE;
2796 }
2797
2798 /*! \brief Reload module */
2799 static int reload(void)
2800 {
2801         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2802                 return -1;
2803         }
2804
2805         return 0;
2806 }
2807
2808 /*! \brief Unload the jingle channel from Asterisk */
2809 static int unload_module(void)
2810 {
2811         ast_channel_unregister(&jingle_tech);
2812         ao2_cleanup(jingle_tech.capabilities);
2813         jingle_tech.capabilities = NULL;
2814         ast_rtp_glue_unregister(&jingle_rtp_glue);
2815         ast_sched_context_destroy(sched);
2816         aco_info_destroy(&cfg_info);
2817         ao2_global_obj_release(globals);
2818
2819         return 0;
2820 }
2821
2822 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2823         .support_level = AST_MODULE_SUPPORT_CORE,
2824         .load = load_module,
2825         .unload = unload_module,
2826         .reload = reload,
2827         .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2828         .requires = "res_xmpp",
2829 );