Allow Asterisk to compile under GCC 4.10
[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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
48
49 #include <sys/socket.h>
50 #include <fcntl.h>
51 #include <netdb.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <sys/signal.h>
55 #include <iksemel.h>
56 #include <pthread.h>
57
58 #include "asterisk/lock.h"
59 #include "asterisk/channel.h"
60 #include "asterisk/config_options.h"
61 #include "asterisk/module.h"
62 #include "asterisk/pbx.h"
63 #include "asterisk/sched.h"
64 #include "asterisk/io.h"
65 #include "asterisk/rtp_engine.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/callerid.h"
68 #include "asterisk/file.h"
69 #include "asterisk/cli.h"
70 #include "asterisk/app.h"
71 #include "asterisk/musiconhold.h"
72 #include "asterisk/manager.h"
73 #include "asterisk/stringfields.h"
74 #include "asterisk/utils.h"
75 #include "asterisk/causes.h"
76 #include "asterisk/astobj.h"
77 #include "asterisk/abstract_jb.h"
78 #include "asterisk/xmpp.h"
79 #include "asterisk/stasis_channels.h"
80
81 /*** DOCUMENTATION
82         <configInfo name="chan_motif" language="en_US">
83                 <synopsis>Jingle Channel Driver</synopsis>
84                 <description>
85                         <para><emphasis>Transports</emphasis></para>
86                         <para>There are three different transports and protocol derivatives
87                         supported by <literal>chan_motif</literal>. They are in order of
88                         preference: Jingle using ICE-UDP, Google Jingle, and Google-V1.</para>
89                         <para>Jingle as defined in XEP-0166 supports the widest range of
90                         features. It is referred to as <literal>ice-udp</literal>. This is
91                         the specification that Jingle clients implement.</para>
92                         <para>Google Jingle follows the Jingle specification for signaling
93                         but uses a custom transport for media. It is supported by the
94                         Google Talk Plug-in in Gmail and by some other Jingle clients. It
95                         is referred to as <literal>google</literal> in this file.</para>
96                         <para>Google-V1 is the original Google Talk signaling protocol
97                         which uses an initial preliminary version of Jingle. It also uses
98                         the same custom transport as Google Jingle for media. It is
99                         supported by Google Voice, some other Jingle clients, and the
100                         Windows Google Talk client. It is referred to as <literal>google-v1</literal>
101                         in this file.</para>
102                         <para>Incoming sessions will automatically switch to the correct
103                         transport once it has been determined.</para>
104                         <para>Outgoing sessions are capable of determining if the target
105                         is capable of Jingle or a Google transport if the target is in the
106                         roster. Unfortunately it is not possible to differentiate between
107                         a Google Jingle or Google-V1 capable resource until a session
108                         initiate attempt occurs. If a resource is determined to use a
109                         Google transport it will initially use Google Jingle but will fall
110                         back to Google-V1 if required.</para>
111                         <para>If an outgoing session attempt fails due to failure to
112                         support the given transport <literal>chan_motif</literal> will
113                         fall back in preference order listed previously until all
114                         transports have been exhausted.</para>
115                         <para><emphasis>Dialing and Resource Selection Strategy</emphasis></para>
116                         <para>Placing a call through an endpoint can be accomplished using the
117                         following dial string:</para>
118                         <para><literal>Motif/[endpoint name]/[target]</literal></para>
119                         <para>When placing an outgoing call through an endpoint the requested
120                         target is searched for in the roster list. If present the first Jingle
121                         or Google Jingle capable resource is specifically targeted. Since the
122                         capabilities of the resource are known the outgoing session initiation
123                         will disregard the configured transport and use the determined one.</para>
124                         <para>If the target is not found in the roster the target will be used
125                         as-is and a session will be initiated using the transport specified
126                         in this configuration file. If no transport has been specified the
127                         endpoint defaults to <literal>ice-udp</literal>.</para>
128                         <para><emphasis>Video Support</emphasis></para>
129                         <para>Support for video does not need to be explicitly enabled.
130                         Configuring any video codec on your endpoint will automatically enable
131                         it.</para>
132                         <para><emphasis>DTMF</emphasis></para>
133                         <para>The only supported method for DTMF is RFC2833. This is always
134                         enabled on audio streams and negotiated if possible.</para>
135                         <para><emphasis>Incoming Calls</emphasis></para>
136                         <para>Incoming calls will first look for the extension matching the
137                         name of the endpoint in the configured context. If no such extension
138                         exists the call will automatically fall back to the <literal>s</literal> extension.</para>
139                         <para><emphasis>CallerID</emphasis></para>
140                         <para>The incoming caller id number is populated with the username of
141                         the caller and the name is populated with the full identity of the
142                         caller. If you would like to perform authentication or filtering
143                         of incoming calls it is recommended that you use these fields to do so.</para>
144                         <para>Outgoing caller id can <emphasis>not</emphasis> be set.</para>
145                         <warning>
146                                 <para>Multiple endpoints using the
147                                 same connection is <emphasis>NOT</emphasis> supported. Doing so
148                                 may result in broken calls.</para>
149                         </warning>
150                 </description>
151                 <configFile name="motif.conf">
152                         <configObject name="endpoint">
153                                 <synopsis>The configuration for an endpoint.</synopsis>
154                                 <configOption name="context">
155                                         <synopsis>Default dialplan context that incoming sessions will be routed to</synopsis>
156                                 </configOption>
157                                 <configOption name="callgroup">
158                                         <synopsis>A callgroup to assign to this endpoint.</synopsis>
159                                 </configOption>
160                                 <configOption name="pickupgroup">
161                                         <synopsis>A pickup group to assign to this endpoint.</synopsis>
162                                 </configOption>
163                                 <configOption name="language">
164                                         <synopsis>The default language for this endpoint.</synopsis>
165                                 </configOption>
166                                 <configOption name="musicclass">
167                                         <synopsis>Default music on hold class for this endpoint.</synopsis>
168                                 </configOption>
169                                 <configOption name="parkinglot">
170                                         <synopsis>Default parking lot for this endpoint.</synopsis>
171                                 </configOption>
172                                 <configOption name="accountcode">
173                                         <synopsis>Accout code for CDR purposes</synopsis>
174                                 </configOption>
175                                 <configOption name="allow">
176                                         <synopsis>Codecs to allow</synopsis>
177                                 </configOption>
178                                 <configOption name="disallow">
179                                         <synopsis>Codecs to disallow</synopsis>
180                                 </configOption>
181                                 <configOption name="connection">
182                                         <synopsis>Connection to accept traffic on and on which to send traffic out</synopsis>
183                                 </configOption>
184                                 <configOption name="transport">
185                                         <synopsis>The transport to use for the endpoint.</synopsis>
186                                         <description>
187                                                 <para>The default outbound transport for this endpoint. Inbound
188                                                 messages are inferred. Allowed transports are <literal>ice-udp</literal>,
189                                                 <literal>google</literal>, or <literal>google-v1</literal>. Note
190                                                 that <literal>chan_motif</literal> will fall back to transport
191                                                 preference order if the transport value chosen here fails.</para>
192                                                 <enumlist>
193                                                         <enum name="ice-udp">
194                                                                 <para>The Jingle protocol, as defined in XEP 0166.</para>
195                                                         </enum>
196                                                         <enum name="google">
197                                                                 <para>The Google Jingle protocol, which follows the Jingle
198                                                                 specification for signaling but uses a custom transport for
199                                                                 media.</para>
200                                                         </enum>
201                                                         <enum name="google-v1">
202                                                                 <para>Google-V1 is the original Google Talk signaling
203                                                                 protocol which uses an initial preliminary version of Jingle.
204                                                                 It also uses the same custom transport as <literal>google</literal> for media.</para>
205                                                         </enum>
206                                                 </enumlist>
207                                         </description>
208                                 </configOption>
209                                 <configOption name="maxicecandidates">
210                                         <synopsis>Maximum number of ICE candidates to offer</synopsis>
211                                 </configOption>
212                                 <configOption name="maxpayloads">
213                                         <synopsis>Maximum number of pyaloads to offer</synopsis>
214                                 </configOption>
215                         </configObject>
216                 </configFile>
217         </configInfo>
218 ***/
219
220 /*! \brief Default maximum number of ICE candidates we will offer */
221 #define DEFAULT_MAX_ICE_CANDIDATES "10"
222
223 /*! \brief Default maximum number of payloads we will offer */
224 #define DEFAULT_MAX_PAYLOADS "30"
225
226 /*! \brief Number of buckets for endpoints */
227 #define ENDPOINT_BUCKETS 37
228
229 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
230 #define SESSION_BUCKETS 37
231
232 /*! \brief Namespace for Jingle itself */
233 #define JINGLE_NS "urn:xmpp:jingle:1"
234
235 /*! \brief Namespace for Jingle RTP sessions */
236 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
237
238 /*! \brief Namespace for Jingle RTP info */
239 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
240
241 /*! \brief Namespace for Jingle ICE-UDP */
242 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
243
244 /*! \brief Namespace for Google Talk ICE-UDP */
245 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
246
247 /*! \brief Namespace for Google Talk Raw UDP */
248 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
249
250 /*! \brief Namespace for Google Session */
251 #define GOOGLE_SESSION_NS "http://www.google.com/session"
252
253 /*! \brief Namespace for Google Phone description */
254 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
255
256 /*! \brief Namespace for Google Video description */
257 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
258
259 /*! \brief Namespace for XMPP stanzas */
260 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
261
262 /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */
263 enum jingle_transport {
264         JINGLE_TRANSPORT_ICE_UDP = 3,   /*!< XEP-0176 */
265         JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
266         JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
267         JINGLE_TRANSPORT_NONE = 0,      /*!< No transport specified */
268 };
269
270 /*! \brief Endpoint state information */
271 struct jingle_endpoint_state {
272         struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
273 };
274
275 /*! \brief Endpoint which contains configuration information and active sessions */
276 struct jingle_endpoint {
277         AST_DECLARE_STRING_FIELDS(
278                 AST_STRING_FIELD(name);              /*!< Name of the endpoint */
279                 AST_STRING_FIELD(context);           /*!< Context to place incoming calls into */
280                 AST_STRING_FIELD(accountcode);       /*!< Account code */
281                 AST_STRING_FIELD(language);          /*!< Default language for prompts */
282                 AST_STRING_FIELD(musicclass);        /*!< Configured music on hold class */
283                 AST_STRING_FIELD(parkinglot);        /*!< Configured parking lot */
284                 );
285         struct ast_xmpp_client *connection;     /*!< Connection to use for traffic */
286         iksrule *rule;                          /*!< Active matching rule */
287         unsigned int maxicecandidates;          /*!< Maximum number of ICE candidates we will offer */
288         unsigned int maxpayloads;               /*!< Maximum number of payloads we will offer */
289         struct ast_codec_pref prefs;            /*!< Codec preferences */
290         struct ast_format_cap *cap;             /*!< Formats to use */
291         ast_group_t callgroup;                  /*!< Call group */
292         ast_group_t pickupgroup;                /*!< Pickup group */
293         enum jingle_transport transport;        /*!< Default transport to use on outgoing sessions */
294         struct jingle_endpoint_state *state;    /*!< Endpoint state information */
295 };
296
297 /*! \brief Session which contains information about an active session */
298 struct jingle_session {
299         AST_DECLARE_STRING_FIELDS(
300                 AST_STRING_FIELD(sid);        /*!< Session identifier */
301                 AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
302                 AST_STRING_FIELD(video_name); /*!< Name of the video content */
303                 );
304         struct jingle_endpoint_state *state;  /*!< Endpoint we are associated with */
305         struct ast_xmpp_client *connection;   /*!< Connection to use for traffic */
306         enum jingle_transport transport;      /*!< Transport type to use for this session */
307         unsigned int maxicecandidates;        /*!< Maximum number of ICE candidates we will offer */
308         unsigned int maxpayloads;             /*!< Maximum number of payloads we will offer */
309         char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
310         char remote[XMPP_MAX_JIDLEN];         /*!< Identifier of the remote party */
311         iksrule *rule;                        /*!< Session matching rule */
312         struct ast_codec_pref prefs;          /*!< Codec preferences */
313         struct ast_channel *owner;            /*!< Master Channel */
314         struct ast_rtp_instance *rtp;         /*!< RTP audio session */
315         struct ast_rtp_instance *vrtp;        /*!< RTP video session */
316         struct ast_format_cap *cap;           /*!< Local codec capabilities */
317         struct ast_format_cap *jointcap;      /*!< Joint codec capabilities */
318         struct ast_format_cap *peercap;       /*!< Peer codec capabilities */
319         unsigned int outgoing:1;              /*!< Whether this is an outgoing leg or not */
320         unsigned int gone:1;                  /*!< In the eyes of Jingle this session is already gone */
321         struct ast_callid *callid;            /*!< Bound session call-id */
322 };
323
324 static const char desc[] = "Motif Jingle Channel";
325 static const char channel_type[] = "Motif";
326
327 struct jingle_config {
328         struct ao2_container *endpoints; /*!< Configured endpoints */
329 };
330
331 static AO2_GLOBAL_OBJ_STATIC(globals);
332
333 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
334
335 /* \brief Asterisk core interaction functions */
336 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);
337 static int jingle_sendtext(struct ast_channel *ast, const char *text);
338 static int jingle_digit_begin(struct ast_channel *ast, char digit);
339 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
340 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
341 static int jingle_hangup(struct ast_channel *ast);
342 static int jingle_answer(struct ast_channel *ast);
343 static struct ast_frame *jingle_read(struct ast_channel *ast);
344 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
345 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
346 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
347 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
348
349 /*! \brief Action handlers */
350 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
351 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
352 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
353 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
354 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
355
356 /*! \brief PBX interface structure for channel registration */
357 static struct ast_channel_tech jingle_tech = {
358         .type = "Motif",
359         .description = "Motif Jingle Channel Driver",
360         .requester = jingle_request,
361         .send_text = jingle_sendtext,
362         .send_digit_begin = jingle_digit_begin,
363         .send_digit_end = jingle_digit_end,
364         .call = jingle_call,
365         .hangup = jingle_hangup,
366         .answer = jingle_answer,
367         .read = jingle_read,
368         .write = jingle_write,
369         .write_video = jingle_write,
370         .exception = jingle_read,
371         .indicate = jingle_indicate,
372         .fixup = jingle_fixup,
373         .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
374 };
375
376 /*! \brief Defined handlers for different Jingle actions */
377 static const struct jingle_action_handler {
378         const char *action;
379         void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
380 } jingle_action_handlers[] = {
381         /* Jingle actions */
382         { "session-initiate", jingle_action_session_initiate, },
383         { "transport-info", jingle_action_transport_info, },
384         { "session-accept", jingle_action_session_accept, },
385         { "session-info", jingle_action_session_info, },
386         { "session-terminate", jingle_action_session_terminate, },
387         /* Google-V1 actions */
388         { "initiate", jingle_action_session_initiate, },
389         { "candidates", jingle_action_transport_info, },
390         { "accept", jingle_action_session_accept, },
391         { "terminate", jingle_action_session_terminate, },
392         { "reject", jingle_action_session_terminate, },
393 };
394
395 /*! \brief Reason text <-> cause code mapping */
396 static const struct jingle_reason_mapping {
397         const char *reason;
398         int cause;
399 } jingle_reason_mappings[] = {
400         { "busy", AST_CAUSE_BUSY, },
401         { "cancel", AST_CAUSE_CALL_REJECTED, },
402         { "connectivity-error", AST_CAUSE_INTERWORKING, },
403         { "decline", AST_CAUSE_CALL_REJECTED, },
404         { "expired", AST_CAUSE_NO_USER_RESPONSE, },
405         { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
406         { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
407         { "general-error", AST_CAUSE_CONGESTION, },
408         { "gone", AST_CAUSE_NORMAL_CLEARING, },
409         { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
410         { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
411         { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
412         { "success", AST_CAUSE_NORMAL_CLEARING, },
413         { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
414         { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
415         { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
416 };
417
418 /*! \brief Hashing function for Jingle sessions */
419 static int jingle_session_hash(const void *obj, const int flags)
420 {
421         const struct jingle_session *session = obj;
422         const char *sid = obj;
423
424         return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
425 }
426
427 /*! \brief Comparator function for Jingle sessions */
428 static int jingle_session_cmp(void *obj, void *arg, int flags)
429 {
430         struct jingle_session *session1 = obj, *session2 = arg;
431         const char *sid = arg;
432
433         return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
434 }
435
436 /*! \brief Destructor for Jingle endpoint state */
437 static void jingle_endpoint_state_destructor(void *obj)
438 {
439         struct jingle_endpoint_state *state = obj;
440
441         ao2_ref(state->sessions, -1);
442 }
443
444 /*! \brief Destructor for Jingle endpoints */
445 static void jingle_endpoint_destructor(void *obj)
446 {
447         struct jingle_endpoint *endpoint = obj;
448
449         if (endpoint->rule) {
450                 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
451         }
452
453         if (endpoint->connection) {
454                 ast_xmpp_client_unref(endpoint->connection);
455         }
456
457         ast_format_cap_destroy(endpoint->cap);
458
459         ao2_ref(endpoint->state, -1);
460
461         ast_string_field_free_memory(endpoint);
462 }
463
464 /*! \brief Find function for Jingle endpoints */
465 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
466 {
467         return ao2_find(tmp_container, category, OBJ_KEY);
468 }
469
470 /*! \brief Allocator function for Jingle endpoint state */
471 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
472 {
473         struct jingle_endpoint_state *state;
474
475         if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
476                 return NULL;
477         }
478
479         if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
480                 ao2_ref(state, -1);
481                 return NULL;
482         }
483
484         return state;
485 }
486
487 /*! \brief State find/create function */
488 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
489 {
490         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
491         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
492
493         if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
494                 return jingle_endpoint_state_create();
495         }
496
497         ao2_ref(endpoint->state, +1);
498         return endpoint->state;
499 }
500
501 /*! \brief Allocator function for Jingle endpoints */
502 static void *jingle_endpoint_alloc(const char *cat)
503 {
504         struct jingle_endpoint *endpoint;
505
506         if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
507                 return NULL;
508         }
509
510         if (ast_string_field_init(endpoint, 512)) {
511                 ao2_ref(endpoint, -1);
512                 return NULL;
513         }
514
515         if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
516                 ao2_ref(endpoint, -1);
517                 return NULL;
518         }
519
520         ast_string_field_set(endpoint, name, cat);
521
522         endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
523         endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
524
525         return endpoint;
526 }
527
528 /*! \brief Hashing function for Jingle endpoints */
529 static int jingle_endpoint_hash(const void *obj, const int flags)
530 {
531         const struct jingle_endpoint *endpoint = obj;
532         const char *name = obj;
533
534         return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
535 }
536
537 /*! \brief Comparator function for Jingle endpoints */
538 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
539 {
540         struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
541         const char *name = arg;
542
543         return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
544 }
545
546 static struct aco_type endpoint_option = {
547         .type = ACO_ITEM,
548         .name = "endpoint",
549         .category_match = ACO_BLACKLIST,
550         .category = "^general$",
551         .item_alloc = jingle_endpoint_alloc,
552         .item_find = jingle_endpoint_find,
553         .item_offset = offsetof(struct jingle_config, endpoints),
554 };
555
556 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
557
558 struct aco_file jingle_conf = {
559         .filename = "motif.conf",
560         .types = ACO_TYPES(&endpoint_option),
561 };
562
563 /*! \brief Destructor for Jingle sessions */
564 static void jingle_session_destructor(void *obj)
565 {
566         struct jingle_session *session = obj;
567
568         if (session->rule) {
569                 iks_filter_remove_rule(session->connection->filter, session->rule);
570         }
571
572         if (session->connection) {
573                 ast_xmpp_client_unref(session->connection);
574         }
575
576         if (session->rtp) {
577                 ast_rtp_instance_stop(session->rtp);
578                 ast_rtp_instance_destroy(session->rtp);
579         }
580
581         if (session->vrtp) {
582                 ast_rtp_instance_stop(session->vrtp);
583                 ast_rtp_instance_destroy(session->vrtp);
584         }
585
586         ast_format_cap_destroy(session->cap);
587         ast_format_cap_destroy(session->jointcap);
588         ast_format_cap_destroy(session->peercap);
589
590         if (session->callid) {
591                 ast_callid_unref(session->callid);
592         }
593
594         ast_string_field_free_memory(session);
595 }
596
597 /*! \brief Destructor called when module configuration goes away */
598 static void jingle_config_destructor(void *obj)
599 {
600         struct jingle_config *cfg = obj;
601         ao2_cleanup(cfg->endpoints);
602 }
603
604 /*! \brief Allocator called when module configuration should appear */
605 static void *jingle_config_alloc(void)
606 {
607         struct jingle_config *cfg;
608
609         if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
610                 return NULL;
611         }
612
613         if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
614                 ao2_ref(cfg, -1);
615                 return NULL;
616         }
617
618         return cfg;
619 }
620
621 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
622                      .files = ACO_FILES(&jingle_conf),
623         );
624
625 /*! \brief Function called by RTP engine to get local RTP peer */
626 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
627 {
628         struct jingle_session *session = ast_channel_tech_pvt(chan);
629         enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
630
631         if (!session->rtp) {
632                 return AST_RTP_GLUE_RESULT_FORBID;
633         }
634
635         ao2_ref(session->rtp, +1);
636         *instance = session->rtp;
637
638         return res;
639 }
640
641 /*! \brief Function called by RTP engine to get peer capabilities */
642 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
643 {
644 }
645
646 /*! \brief Function called by RTP engine to change where the remote party should send media */
647 static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
648 {
649         return -1;
650 }
651
652 /*! \brief Local glue for interacting with the RTP engine core */
653 static struct ast_rtp_glue jingle_rtp_glue = {
654         .type = "Motif",
655         .get_rtp_info = jingle_get_rtp_peer,
656         .get_codec = jingle_get_codec,
657         .update_peer = jingle_set_rtp_peer,
658 };
659
660 /*! \brief Set the channel owner on the \ref jingle_session object and related objects */
661 static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
662 {
663         session->owner = chan;
664         if (session->rtp) {
665                 ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
666         }
667         if (session->vrtp) {
668                 ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
669         }
670 }
671
672 /*! \brief Internal helper function which enables video support on a sesson if possible */
673 static void jingle_enable_video(struct jingle_session *session)
674 {
675         struct ast_sockaddr tmp;
676         struct ast_rtp_engine_ice *ice;
677
678         /* If video is already present don't do anything */
679         if (session->vrtp) {
680                 return;
681         }
682
683         /* If there are no configured video codecs do not turn video support on, it just won't work */
684         if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
685                 return;
686         }
687
688         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
689
690         if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
691                 return;
692         }
693
694         ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
695         ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
696         ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
697         ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
698         ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
699
700         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
701                 ice->stop(session->vrtp);
702         }
703 }
704
705 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
706 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
707 {
708         struct jingle_session *session;
709         struct ast_callid *callid;
710         struct ast_sockaddr tmp;
711
712         if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
713                 return NULL;
714         }
715
716         callid = ast_read_threadstorage_callid();
717         session->callid = (callid ? callid : ast_create_callid());
718
719         if (ast_string_field_init(session, 512)) {
720                 ao2_ref(session, -1);
721                 return NULL;
722         }
723
724         if (!ast_strlen_zero(from)) {
725                 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
726                 ast_copy_string(session->remote, from, sizeof(session->remote));
727         }
728
729         if (ast_strlen_zero(sid)) {
730                 ast_string_field_build(session, sid, "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
731                 session->outgoing = 1;
732                 ast_string_field_set(session, audio_name, "audio");
733                 ast_string_field_set(session, video_name, "video");
734         } else {
735                 ast_string_field_set(session, sid, sid);
736         }
737
738         ao2_ref(endpoint->state, +1);
739         session->state = endpoint->state;
740         ao2_ref(endpoint->connection, +1);
741         session->connection = endpoint->connection;
742         session->transport = endpoint->transport;
743
744         if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) ||
745             !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) ||
746             !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) ||
747             !session->callid) {
748                 ao2_ref(session, -1);
749                 return NULL;
750         }
751
752         ast_format_cap_copy(session->cap, endpoint->cap);
753
754         /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
755          * that we want IPv4 */
756         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
757
758         /* Sessions always carry audio, but video is optional so don't enable it here */
759         if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
760                 ao2_ref(session, -1);
761                 return NULL;
762         }
763         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
764         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
765
766         memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
767
768         session->maxicecandidates = endpoint->maxicecandidates;
769         session->maxpayloads = endpoint->maxpayloads;
770
771         return session;
772 }
773
774 /*! \brief Function called to create a new Jingle Asterisk channel */
775 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)
776 {
777         struct ast_channel *chan;
778         const char *str = S_OR(title, session->remote);
779         struct ast_format tmpfmt;
780
781         if (ast_format_cap_is_empty(session->cap)) {
782                 return NULL;
783         }
784
785         if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
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_copy(ast_channel_nativeformats(chan), session->cap);
798         ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
799
800         if (session->rtp) {
801                 struct ast_rtp_engine_ice *ice;
802
803                 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
804                 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
805                 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
806
807                 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
808                      (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
809                     (ice = ast_rtp_instance_get_ice(session->rtp))) {
810                         /* We stop built in ICE support because we need to fall back to old old old STUN support */
811                         ice->stop(session->rtp);
812                 }
813         }
814
815         if (state == AST_STATE_RING) {
816                 ast_channel_rings_set(chan, 1);
817         }
818
819         ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
820
821         ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
822         ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
823         ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
824         ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
825         ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
826
827         ao2_lock(endpoint);
828
829         ast_channel_callgroup_set(chan, endpoint->callgroup);
830         ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
831
832         if (!ast_strlen_zero(endpoint->accountcode)) {
833                 ast_channel_accountcode_set(chan, endpoint->accountcode);
834         }
835
836         if (!ast_strlen_zero(endpoint->language)) {
837                 ast_channel_language_set(chan, endpoint->language);
838         }
839
840         if (!ast_strlen_zero(endpoint->musicclass)) {
841                 ast_channel_musicclass_set(chan, endpoint->musicclass);
842         }
843
844         ast_channel_context_set(chan, endpoint->context);
845         if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
846                 ast_channel_exten_set(chan, endpoint->name);
847         } else {
848                 ast_channel_exten_set(chan, "s");
849         }
850         ast_channel_priority_set(chan, 1);
851
852         ao2_unlock(endpoint);
853
854         ast_channel_stage_snapshot_done(chan);
855         ast_channel_unlock(chan);
856
857         return chan;
858 }
859
860 /*! \brief Internal helper function which sends a response */
861 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
862 {
863         iks *response;
864
865         if (!(response = iks_new("iq"))) {
866                 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
867                 return;
868         }
869
870         iks_insert_attrib(response, "type", "result");
871         iks_insert_attrib(response, "from", connection->jid->full);
872         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
873         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
874
875         ast_xmpp_client_send(connection, response);
876
877         iks_delete(response);
878 }
879
880 /*! \brief Internal helper function which sends an error response */
881 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
882 {
883         iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
884
885         if (!(response = iks_new("iq")) ||
886             !(error = iks_new("error")) ||
887             !(reason = iks_new(reasonstr))) {
888                 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
889                 goto end;
890         }
891
892         iks_insert_attrib(response, "type", "error");
893         iks_insert_attrib(response, "from", connection->jid->full);
894         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
895         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
896
897         iks_insert_attrib(error, "type", type);
898         iks_insert_node(error, reason);
899
900         if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
901                 iks_insert_node(error, reason2);
902         }
903
904         iks_insert_node(response, error);
905
906         ast_xmpp_client_send(connection, response);
907 end:
908         iks_delete(reason2);
909         iks_delete(reason);
910         iks_delete(error);
911         iks_delete(response);
912 }
913
914 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
915 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
916 {
917         struct ast_rtp_engine_ice *ice;
918         struct ao2_container *local_candidates;
919         struct ao2_iterator it;
920         struct ast_rtp_engine_ice_candidate *candidate;
921         int i = 0, res = 0;
922
923         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
924                 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
925                 return -1;
926         }
927
928         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
929         iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
930         iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
931
932         it = ao2_iterator_init(local_candidates, 0);
933
934         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
935                 iks *local_candidate;
936                 char tmp[30];
937
938                 if (!(local_candidate = iks_new("candidate"))) {
939                         res = -1;
940                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
941                         break;
942                 }
943
944                 snprintf(tmp, sizeof(tmp), "%u", candidate->id);
945                 iks_insert_attrib(local_candidate, "component", tmp);
946                 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
947                 iks_insert_attrib(local_candidate, "foundation", tmp);
948                 iks_insert_attrib(local_candidate, "generation", "0");
949                 iks_insert_attrib(local_candidate, "network", "0");
950                 snprintf(tmp, sizeof(tmp), "%04lx", (unsigned long)(ast_random() & 0xffff));
951                 iks_insert_attrib(local_candidate, "id", tmp);
952                 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
953                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
954                 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
955                 iks_insert_attrib(local_candidate, "priority", tmp);
956                 iks_insert_attrib(local_candidate, "protocol", "udp");
957
958                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
959                         iks_insert_attrib(local_candidate, "type", "host");
960                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
961                         iks_insert_attrib(local_candidate, "type", "srflx");
962                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
963                         iks_insert_attrib(local_candidate, "type", "relay");
964                 }
965
966                 iks_insert_node(transport, local_candidate);
967                 candidates[i++] = local_candidate;
968         }
969
970         ao2_iterator_destroy(&it);
971         ao2_ref(local_candidates, -1);
972
973         return res;
974 }
975
976 /*! \brief Internal helper function which adds Google candidates to a transport node */
977 static int jingle_add_google_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int video, enum jingle_transport transport_type, unsigned int maximum)
978 {
979         struct ast_rtp_engine_ice *ice;
980         struct ao2_container *local_candidates;
981         struct ao2_iterator it;
982         struct ast_rtp_engine_ice_candidate *candidate;
983         int i = 0, res = 0;
984
985         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
986                 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
987                 return -1;
988         }
989
990         if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
991                 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
992         }
993
994         it = ao2_iterator_init(local_candidates, 0);
995
996         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
997                 iks *local_candidate;
998                 /* In Google land a username is 16 bytes, explicitly */
999                 char ufrag[17] = "";
1000
1001                 if (!(local_candidate = iks_new("candidate"))) {
1002                         res = -1;
1003                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
1004                         break;
1005                 }
1006
1007                 if (candidate->id == 1) {
1008                         iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
1009                 } else if (candidate->id == 2) {
1010                         iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
1011                 } else {
1012                         iks_delete(local_candidate);
1013                         continue;
1014                 }
1015
1016                 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
1017                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
1018
1019                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
1020                         iks_insert_attrib(local_candidate, "preference", "0.95");
1021                         iks_insert_attrib(local_candidate, "type", "local");
1022                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
1023                         iks_insert_attrib(local_candidate, "preference", "0.9");
1024                         iks_insert_attrib(local_candidate, "type", "stun");
1025                 }
1026
1027                 iks_insert_attrib(local_candidate, "protocol", "udp");
1028                 iks_insert_attrib(local_candidate, "network", "0");
1029                 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
1030                 iks_insert_attrib(local_candidate, "username", ufrag);
1031                 iks_insert_attrib(local_candidate, "generation", "0");
1032
1033                 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
1034                         iks_insert_attrib(local_candidate, "password", "");
1035                         iks_insert_attrib(local_candidate, "foundation", "0");
1036                         iks_insert_attrib(local_candidate, "component", "1");
1037                 } else {
1038                         iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
1039                 }
1040
1041                 /* You may notice a lack of relay support up above - this is because we don't support it for use with
1042                  * the Google talk transport due to their arcane support. */
1043
1044                 iks_insert_node(transport, local_candidate);
1045                 candidates[i++] = local_candidate;
1046         }
1047
1048         ao2_iterator_destroy(&it);
1049         ao2_ref(local_candidates, -1);
1050
1051         return res;
1052 }
1053
1054 /*! \brief Internal function which sends a session-terminate message */
1055 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
1056 {
1057         iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
1058
1059         if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
1060             !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
1061                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
1062                 goto end;
1063         }
1064
1065         iks_insert_attrib(iq, "to", session->remote);
1066         iks_insert_attrib(iq, "type", "set");
1067         iks_insert_attrib(iq, "id", session->connection->mid);
1068         ast_xmpp_increment_mid(session->connection->mid);
1069
1070         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1071                 iks_insert_attrib(jingle, "type", "terminate");
1072                 iks_insert_attrib(jingle, "id", session->sid);
1073                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1074                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1075         } else {
1076                 iks_insert_attrib(jingle, "action", "session-terminate");
1077                 iks_insert_attrib(jingle, "sid", session->sid);
1078                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1079         }
1080
1081         iks_insert_node(iq, jingle);
1082         iks_insert_node(jingle, reason);
1083         iks_insert_node(reason, text);
1084
1085         ast_xmpp_client_send(session->connection, iq);
1086
1087 end:
1088         iks_delete(text);
1089         iks_delete(reason);
1090         iks_delete(jingle);
1091         iks_delete(iq);
1092 }
1093
1094 /*! \brief Internal function which sends a session-info message */
1095 static void jingle_send_session_info(struct jingle_session *session, const char *info)
1096 {
1097         iks *iq = NULL, *jingle = NULL, *text = NULL;
1098
1099         /* Google-V1 has no way to send informational messages so don't even bother trying */
1100         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1101                 return;
1102         }
1103
1104         if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
1105                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
1106                 goto end;
1107         }
1108
1109         iks_insert_attrib(iq, "to", session->remote);
1110         iks_insert_attrib(iq, "type", "set");
1111         iks_insert_attrib(iq, "id", session->connection->mid);
1112         ast_xmpp_increment_mid(session->connection->mid);
1113
1114         iks_insert_attrib(jingle, "action", "session-info");
1115         iks_insert_attrib(jingle, "sid", session->sid);
1116         iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1117         iks_insert_node(iq, jingle);
1118         iks_insert_node(jingle, text);
1119
1120         ast_xmpp_client_send(session->connection, iq);
1121
1122 end:
1123         iks_delete(text);
1124         iks_delete(jingle);
1125         iks_delete(iq);
1126 }
1127
1128 /*! \internal
1129  *
1130  * \brief Locks both pvt and pvt owner if owner is present.
1131  *
1132  * \note This function gives a ref to pvt->owner if it is present and locked.
1133  *       This reference must be decremented after pvt->owner is unlocked.
1134  *
1135  * \note This function will never give you up,
1136  * \note This function will never let you down.
1137  * \note This function will run around and desert you.
1138  *
1139  * \pre pvt is not locked
1140  * \post pvt is locked
1141  * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
1142  *
1143  * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
1144  */
1145 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
1146 {
1147         struct ast_channel *chan;
1148
1149         /* Locking is simple when it is done right.  If you see a deadlock resulting
1150          * in this function, it is not this function's fault, Your problem exists elsewhere.
1151          * This function is perfect... seriously. */
1152         for (;;) {
1153                 /* First, get the channel and grab a reference to it */
1154                 ao2_lock(pvt);
1155                 chan = pvt->owner;
1156                 if (chan) {
1157                         /* The channel can not go away while we hold the pvt lock.
1158                          * Give the channel a ref so it will not go away after we let
1159                          * the pvt lock go. */
1160                         ast_channel_ref(chan);
1161                 } else {
1162                         /* no channel, return pvt locked */
1163                         return NULL;
1164                 }
1165
1166                 /* We had to hold the pvt lock while getting a ref to the owner channel
1167                  * but now we have to let this lock go in order to preserve proper
1168                  * locking order when grabbing the channel lock */
1169                 ao2_unlock(pvt);
1170
1171                 /* Look, no deadlock avoidance, hooray! */
1172                 ast_channel_lock(chan);
1173                 ao2_lock(pvt);
1174                 if (pvt->owner == chan) {
1175                         /* done */
1176                         break;
1177                 }
1178
1179                 /* If the owner changed while everything was unlocked, no problem,
1180                  * just start over and everthing will work.  This is rare, do not be
1181                  * confused by this loop and think this it is an expensive operation.
1182                  * The majority of the calls to this function will never involve multiple
1183                  * executions of this loop. */
1184                 ast_channel_unlock(chan);
1185                 ast_channel_unref(chan);
1186                 ao2_unlock(pvt);
1187         }
1188
1189         /* If owner exists, it is locked and reffed */
1190         return pvt->owner;
1191 }
1192
1193 /*! \brief Helper function which queues a hangup frame with cause code */
1194 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1195 {
1196         struct ast_channel *chan;
1197
1198         if ((chan = jingle_session_lock_full(session))) {
1199                 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1200                 ast_queue_hangup_with_cause(chan, cause);
1201                 ast_channel_unlock(chan);
1202                 ast_channel_unref(chan);
1203         }
1204         ao2_unlock(session);
1205 }
1206
1207 /*! \brief Internal function which sends a transport-info message */
1208 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1209 {
1210         iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1211         iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1212         int i, res = 0;
1213
1214         if (!(iq = iks_new("iq")) ||
1215             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1216                 iks_delete(iq);
1217                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1218                 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1219                 return;
1220         }
1221
1222         memset(audio_candidates, 0, sizeof(audio_candidates));
1223         memset(video_candidates, 0, sizeof(video_candidates));
1224
1225         iks_insert_attrib(iq, "from", session->connection->jid->full);
1226         iks_insert_attrib(iq, "to", from);
1227         iks_insert_attrib(iq, "type", "set");
1228         iks_insert_attrib(iq, "id", session->connection->mid);
1229         ast_xmpp_increment_mid(session->connection->mid);
1230
1231         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1232                 iks_insert_attrib(jingle, "type", "candidates");
1233                 iks_insert_attrib(jingle, "id", session->sid);
1234                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1235                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1236         } else {
1237                 iks_insert_attrib(jingle, "action", "transport-info");
1238                 iks_insert_attrib(jingle, "sid", session->sid);
1239                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1240         }
1241         iks_insert_node(iq, jingle);
1242
1243         if (session->rtp) {
1244                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1245                         /* V1 protocol has the candidates directly in the session */
1246                         res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1247                 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1248                         iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1249                         iks_insert_attrib(audio, "name", session->audio_name);
1250                         iks_insert_node(jingle, audio);
1251                         iks_insert_node(audio, audio_transport);
1252
1253                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1254                                 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1255                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1256                                 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1257                                                                                 session->maxicecandidates);
1258                         }
1259                 } else {
1260                         res = -1;
1261                 }
1262         }
1263
1264         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1265                 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1266                         iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1267                         iks_insert_attrib(video, "name", session->video_name);
1268                         iks_insert_node(jingle, video);
1269                         iks_insert_node(video, video_transport);
1270
1271                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1272                                 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1273                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1274                                 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1275                                                                                 session->maxicecandidates);
1276                         }
1277                 } else {
1278                         res = -1;
1279                 }
1280         }
1281
1282         if (!res) {
1283                 ast_xmpp_client_send(session->connection, iq);
1284         } else {
1285                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1286         }
1287
1288         /* Clean up after ourselves */
1289         for (i = 0; i < session->maxicecandidates; i++) {
1290                 iks_delete(video_candidates[i]);
1291                 iks_delete(audio_candidates[i]);
1292         }
1293
1294         iks_delete(video_transport);
1295         iks_delete(video);
1296         iks_delete(audio_transport);
1297         iks_delete(audio);
1298         iks_delete(jingle);
1299         iks_delete(iq);
1300 }
1301
1302 /*! \brief Internal helper function which adds payloads to a description */
1303 static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type)
1304 {
1305         struct ast_format format;
1306         int x = 0, i = 0, res = 0;
1307
1308         for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
1309                 int rtp_code;
1310                 iks *payload;
1311                 char tmp[32];
1312
1313                 if (!ast_codec_pref_index(&session->prefs, x, &format)) {
1314                         break;
1315                 }
1316
1317                 if (AST_FORMAT_GET_TYPE(format.id) != type) {
1318                         continue;
1319                 }
1320
1321                 if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
1322                         continue;
1323                 }
1324
1325                 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
1326                     (!(payload = iks_new("payload-type")))) {
1327                         return -1;
1328                 }
1329
1330                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1331                         iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1332                 }
1333
1334                 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1335                 iks_insert_attrib(payload, "id", tmp);
1336                 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
1337                 iks_insert_attrib(payload, "channels", "1");
1338
1339                 if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1340                         iks_insert_attrib(payload, "clockrate", "16000");
1341                 } else {
1342                         snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, &format, 0));
1343                         iks_insert_attrib(payload, "clockrate", tmp);
1344                 }
1345
1346                 if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1347                         iks *parameter;
1348
1349                         /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1350                         if ((parameter = iks_new("parameter"))) {
1351                                 iks_insert_attrib(parameter, "name", "width");
1352                                 iks_insert_attrib(parameter, "value", "640");
1353                                 iks_insert_node(payload, parameter);
1354                         }
1355                         if ((parameter = iks_new("parameter"))) {
1356                                 iks_insert_attrib(parameter, "name", "height");
1357                                 iks_insert_attrib(parameter, "value", "480");
1358                                 iks_insert_node(payload, parameter);
1359                         }
1360                         if ((parameter = iks_new("parameter"))) {
1361                                 iks_insert_attrib(parameter, "name", "framerate");
1362                                 iks_insert_attrib(parameter, "value", "30");
1363                                 iks_insert_node(payload, parameter);
1364                         }
1365                 }
1366
1367                 iks_insert_node(description, payload);
1368                 payloads[i++] = payload;
1369         }
1370         /* If this is for audio and there is room for RFC2833 add it in */
1371         if ((type == AST_FORMAT_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_format_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_FORMAT_TYPE_AUDIO) {
1404                         iks_insert_attrib(description, "media", "audio");
1405                 } else if (type == AST_FORMAT_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_FORMAT_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_FORMAT_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(ast_channel_nativeformats(ast), &frame->subclass.format)) {
1672                 if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
1673                         ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1674                                   ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
1675                         ast_frfree(frame);
1676                         frame = &ast_null_frame;
1677                 } else {
1678                         ast_debug(1, "Oooh, format changed to %s\n",
1679                                   ast_getformatname(&frame->subclass.format));
1680                         ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
1681                         ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
1682                         ast_set_read_format(ast, ast_channel_readformat(ast));
1683                         ast_set_write_format(ast, ast_channel_writeformat(ast));
1684                 }
1685         }
1686
1687         return frame;
1688 }
1689
1690 /*! \brief Function called by core to write frames */
1691 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1692 {
1693         struct jingle_session *session = ast_channel_tech_pvt(ast);
1694         int res = 0;
1695         char buf[256];
1696
1697         switch (frame->frametype) {
1698         case AST_FRAME_VOICE:
1699                 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
1700                         ast_log(LOG_WARNING,
1701                                 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1702                                 ast_getformatname(&frame->subclass.format),
1703                                 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
1704                                 ast_getformatname(ast_channel_readformat(ast)),
1705                                 ast_getformatname(ast_channel_writeformat(ast)));
1706                         return 0;
1707                 }
1708                 if (session && session->rtp) {
1709                         res = ast_rtp_instance_write(session->rtp, frame);
1710                 }
1711                 break;
1712         case AST_FRAME_VIDEO:
1713                 if (session && session->vrtp) {
1714                         res = ast_rtp_instance_write(session->vrtp, frame);
1715                 }
1716                 break;
1717         default:
1718                 ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
1719                         frame->frametype);
1720                 return 0;
1721         }
1722
1723         return res;
1724 }
1725
1726 /*! \brief Function called by core to change the underlying owner channel */
1727 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1728 {
1729         struct jingle_session *session = ast_channel_tech_pvt(newchan);
1730
1731         ao2_lock(session);
1732
1733         jingle_set_owner(session, newchan);
1734
1735         ao2_unlock(session);
1736
1737         return 0;
1738 }
1739
1740 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1741 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1742 {
1743         struct jingle_session *session = ast_channel_tech_pvt(ast);
1744         int res = 0;
1745
1746         switch (condition) {
1747         case AST_CONTROL_RINGING:
1748                 if (ast_channel_state(ast) == AST_STATE_RING) {
1749                         jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1750                 } else {
1751                         res = -1;
1752                 }
1753                 break;
1754         case AST_CONTROL_BUSY:
1755                 if (ast_channel_state(ast) != AST_STATE_UP) {
1756                         ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1757                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1758                 } else {
1759                         res = -1;
1760                 }
1761                 break;
1762         case AST_CONTROL_CONGESTION:
1763                 if (ast_channel_state(ast) != AST_STATE_UP) {
1764                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1765                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1766                 } else {
1767                         res = -1;
1768                 }
1769                 break;
1770         case AST_CONTROL_INCOMPLETE:
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                 }
1775                 break;
1776         case AST_CONTROL_HOLD:
1777                 ast_moh_start(ast, data, NULL);
1778                 break;
1779         case AST_CONTROL_UNHOLD:
1780                 ast_moh_stop(ast);
1781                 break;
1782         case AST_CONTROL_SRCUPDATE:
1783                 if (session->rtp) {
1784                         ast_rtp_instance_update_source(session->rtp);
1785                 }
1786                 break;
1787         case AST_CONTROL_SRCCHANGE:
1788                 if (session->rtp) {
1789                         ast_rtp_instance_change_source(session->rtp);
1790                 }
1791                 break;
1792         case AST_CONTROL_VIDUPDATE:
1793         case AST_CONTROL_UPDATE_RTP_PEER:
1794         case AST_CONTROL_CONNECTED_LINE:
1795                 break;
1796         case AST_CONTROL_PVT_CAUSE_CODE:
1797         case -1:
1798                 res = -1;
1799                 break;
1800         default:
1801                 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1802                 res = -1;
1803         }
1804
1805         return res;
1806 }
1807
1808 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1809 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1810 {
1811         struct jingle_session *session = ast_channel_tech_pvt(chan);
1812
1813         return ast_xmpp_client_send_message(session->connection, session->remote, text);
1814 }
1815
1816 /*! \brief Function called by core to start a DTMF digit */
1817 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1818 {
1819         struct jingle_session *session = ast_channel_tech_pvt(chan);
1820
1821         if (session->rtp) {
1822                 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1823         }
1824
1825         return 0;
1826 }
1827
1828 /*! \brief Function called by core to stop a DTMF digit */
1829 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1830 {
1831         struct jingle_session *session = ast_channel_tech_pvt(ast);
1832
1833         if (session->rtp) {
1834                 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1835         }
1836
1837         return 0;
1838 }
1839
1840 /*! \brief Function called by core to actually start calling a remote party */
1841 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1842 {
1843         struct jingle_session *session = ast_channel_tech_pvt(ast);
1844
1845         ast_setstate(ast, AST_STATE_RING);
1846
1847         /* Since we have no idea of the remote capabilities use ours for now */
1848         ast_format_cap_copy(session->jointcap, session->cap);
1849
1850         /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1851         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1852                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1853
1854         jingle_send_session_initiate(session);
1855
1856         return 0;
1857 }
1858
1859 /*! \brief Function called by core to hang up a Jingle session */
1860 static int jingle_hangup(struct ast_channel *ast)
1861 {
1862         struct jingle_session *session = ast_channel_tech_pvt(ast);
1863
1864         ao2_lock(session);
1865
1866         if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1867                 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1868                 const char *reason = "success";
1869                 int i;
1870
1871                 /* Get the appropriate reason and send a session-terminate */
1872                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1873                         if (jingle_reason_mappings[i].cause == cause) {
1874                                 reason = jingle_reason_mappings[i].reason;
1875                                 break;
1876                         }
1877                 }
1878
1879                 jingle_send_session_terminate(session, reason);
1880         }
1881
1882         ast_channel_tech_pvt_set(ast, NULL);
1883         jingle_set_owner(session, NULL);
1884
1885         ao2_unlink(session->state->sessions, session);
1886         ao2_ref(session->state, -1);
1887
1888         ao2_unlock(session);
1889         ao2_ref(session, -1);
1890
1891         return 0;
1892 }
1893
1894 /*! \brief Function called by core to create a new outgoing Jingle session */
1895 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)
1896 {
1897         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1898         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1899         char *dialed, target[200] = "";
1900         struct ast_xmpp_buddy *buddy;
1901         struct jingle_session *session;
1902         struct ast_channel *chan;
1903         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1904         struct ast_rtp_engine_ice *ice;
1905         AST_DECLARE_APP_ARGS(args,
1906                              AST_APP_ARG(name);
1907                              AST_APP_ARG(target);
1908                 );
1909
1910         /* We require at a minimum one audio format to be requested */
1911         if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
1912                 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1913                 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1914                 return NULL;
1915         }
1916
1917         if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1918                 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1919                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1920                 return NULL;
1921         }
1922
1923         /* Parse the given dial string and validate the results */
1924         AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1925
1926         if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1927                 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1928                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1929                 return NULL;
1930         }
1931
1932         if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1933                 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1934                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1935                 return NULL;
1936         }
1937
1938         ao2_lock(endpoint->state);
1939
1940         /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1941         if (!endpoint->connection) {
1942                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1943                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1944                 ao2_unlock(endpoint->state);
1945                 return NULL;
1946         }
1947
1948         /* Find the target in the roster so we can choose a resource */
1949         if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1950                 struct ao2_iterator res;
1951                 struct ast_xmpp_resource *resource;
1952
1953                 /* Iterate through finding the first viable Jingle capable resource */
1954                 res = ao2_iterator_init(buddy->resources, 0);
1955                 while ((resource = ao2_iterator_next(&res))) {
1956                         if (resource->caps.jingle) {
1957                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1958                                 transport = JINGLE_TRANSPORT_ICE_UDP;
1959                                 break;
1960                         } else if (resource->caps.google) {
1961                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1962                                 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1963                                 break;
1964                         }
1965                         ao2_ref(resource, -1);
1966                 }
1967                 ao2_iterator_destroy(&res);
1968
1969                 ao2_ref(buddy, -1);
1970         } else {
1971                 /* If the target is NOT in the roster use the provided target as-is */
1972                 ast_copy_string(target, args.target, sizeof(target));
1973         }
1974
1975         ao2_unlock(endpoint->state);
1976
1977         /* If no target was found we can't set up a session */
1978         if (ast_strlen_zero(target)) {
1979                 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);
1980                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1981                 return NULL;
1982         }
1983
1984         if (!(session = jingle_alloc(endpoint, target, NULL))) {
1985                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1986                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1987                 return NULL;
1988         }
1989
1990         /* Update the transport if we learned what we should actually use */
1991         if (transport != JINGLE_TRANSPORT_NONE) {
1992                 session->transport = transport;
1993                 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
1994         }
1995
1996         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
1997                 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
1998                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1999                 ao2_ref(session, -1);
2000                 return NULL;
2001         }
2002
2003         /* If video was requested try to enable it on the session */
2004         if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
2005                 jingle_enable_video(session);
2006         }
2007
2008         /* As this is outgoing set ourselves as controlling */
2009         if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
2010                 ice->ice_lite(session->rtp);
2011         }
2012
2013         if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
2014                 ice->ice_lite(session->vrtp);
2015         }
2016
2017         /* We purposely don't decrement the session here as there is a reference on the channel */
2018         ao2_link(endpoint->state->sessions, session);
2019
2020         return chan;
2021 }
2022
2023 /*! \brief Helper function which handles content descriptions */
2024 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2025 {
2026         char *media = iks_find_attrib(description, "media");
2027         struct ast_rtp_codecs codecs;
2028         iks *codec;
2029         int othercapability = 0;
2030
2031         /* Google-V1 is always carrying audio, but just doesn't tell us so */
2032         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2033                 media = "audio";
2034         } else if (ast_strlen_zero(media)) {
2035                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2036                 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2037                 return -1;
2038         }
2039
2040         /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2041         if (!strcasecmp(media, "audio")) {
2042                 if (!ast_strlen_zero(name)) {
2043                         ast_string_field_set(session, audio_name, name);
2044                 }
2045                 *rtp = session->rtp;
2046                 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
2047                 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
2048         } else if (!strcasecmp(media, "video")) {
2049                 if (!ast_strlen_zero(name)) {
2050                         ast_string_field_set(session, video_name, name);
2051                 }
2052
2053                 jingle_enable_video(session);
2054                 *rtp = session->vrtp;
2055
2056                 /* If video is not present cancel this session */
2057                 if (!session->vrtp) {
2058                         jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2059                         ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2060                         return -1;
2061                 }
2062
2063                 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
2064                 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
2065         } else {
2066                 /* Unknown media type */
2067                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2068                 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2069                 return -1;
2070         }
2071
2072         if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2073                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2074                 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2075                 return -1;
2076         }
2077
2078         /* Iterate the codecs updating the relevant RTP instance as we go */
2079         for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2080                 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
2081                 char *clockrate = iks_find_attrib(codec, "clockrate");
2082                 int rtp_id, rtp_clockrate;
2083
2084                 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2085                         ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
2086
2087                         if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2088                                 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2089                         } else {
2090                                 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2091                         }
2092                 }
2093         }
2094
2095         ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2096         ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
2097
2098         if (ast_format_cap_is_empty(session->jointcap)) {
2099                 /* We have no compatible codecs, so terminate the session appropriately */
2100                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2101                 ast_rtp_codecs_payloads_destroy(&codecs);
2102                 return -1;
2103         }
2104
2105         ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2106         ast_rtp_codecs_payloads_destroy(&codecs);
2107
2108         return 0;
2109 }
2110
2111 /*! \brief Helper function which handles ICE-UDP transport information */
2112 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2113 {
2114         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2115         char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2116         iks *candidate;
2117
2118         if (!ice) {
2119                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2120                 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2121                 return -1;
2122         }
2123
2124         if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2125                 ice->set_authentication(rtp, ufrag, pwd);
2126         }
2127
2128         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2129                 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2130                 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2131                 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2132                 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2133                 char *type = iks_find_attrib(candidate, "type");
2134                 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2135                 int real_port;
2136                 struct ast_sockaddr remote_address = { { 0, } };
2137
2138                 /* If this candidate is incomplete skip it */
2139                 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2140                     ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2141                     ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2142                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2143                         ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2144                         return -1;
2145                 }
2146
2147                 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2148                     (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
2149                     (sscanf(port, "%30d", &real_port) != 1)) {
2150                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2151                         ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2152                         return -1;
2153                 }
2154
2155                 local_candidate.foundation = foundation;
2156                 local_candidate.transport = protocol;
2157
2158                 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2159
2160                 /* We only support IPv4 right now */
2161                 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2162                         continue;
2163                 }
2164
2165                 ast_sockaddr_set_port(&local_candidate.address, real_port);
2166
2167                 if (!strcasecmp(type, "host")) {
2168                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2169                 } else if (!strcasecmp(type, "srflx")) {
2170                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2171                 } else if (!strcasecmp(type, "relay")) {
2172                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2173                 } else {
2174                         continue;
2175                 }
2176
2177                 /* Worst case use the first viable address */
2178                 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2179
2180                 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2181                         ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2182                 }
2183
2184                 ice->add_remote_candidate(rtp, &local_candidate);
2185         }
2186
2187         ice->start(rtp);
2188
2189         return 0;
2190 }
2191
2192 /*! \brief Helper function which handles Google transport information */
2193 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2194 {
2195         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2196         iks *candidate;
2197
2198         if (!ice) {
2199                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2200                 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2201                 return -1;
2202         }
2203
2204         /* If this session has not transitioned to the Google transport do so now */
2205         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2206             (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2207                 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2208                 ice->stop(rtp);
2209
2210                 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2211         }
2212
2213         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2214                 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2215                 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2216                 char *protocol = iks_find_attrib(candidate, "protocol");
2217                 int real_port;
2218                 struct ast_sockaddr target = { { 0, } };
2219                 /* In Google land the combined value is 32 bytes */
2220                 char combined[33] = "";
2221
2222                 /* If this is NOT actually a candidate just skip it */
2223                 if (strcasecmp(iks_name(candidate), "candidate") &&
2224                     strcasecmp(iks_name(candidate), "p:candidate") &&
2225                     strcasecmp(iks_name(candidate), "ses:candidate")) {
2226                         continue;
2227                 }
2228
2229                 /* If this candidate is incomplete skip it */
2230                 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2231                     ast_strlen_zero(name)) {
2232                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2233                         ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2234                         return -1;
2235                 }
2236
2237                 /* We only support UDP so skip any other protocols */
2238                 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2239                         continue;
2240                 }
2241
2242                 /* We only permit audio and video, not RTCP */
2243                 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2244                         continue;
2245                 }
2246
2247                 /* Parse the target information so we can send a STUN request to the candidate */
2248                 if (sscanf(port, "%30d", &real_port) != 1) {
2249                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2250                         ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2251                         return -1;
2252                 }
2253                 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2254                 ast_sockaddr_set_port(&target, real_port);
2255
2256                 /* Per the STUN support Google talk uses combine the two usernames */
2257                 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2258
2259                 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2260                 ast_rtp_instance_stun_request(rtp, &target, combined);
2261         }
2262
2263         return 0;
2264 }
2265
2266 /*!
2267  * \brief Helper function which locates content stanzas and interprets them
2268  *
2269  * \note The session *must not* be locked before calling this
2270  */
2271 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2272 {
2273         iks *content;
2274         unsigned int changed = 0;
2275         struct ast_channel *chan;
2276
2277         /* Look at the content in the session initiation */
2278         for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2279                 char *name;
2280                 struct ast_rtp_instance *rtp = NULL;
2281                 iks *description, *transport;
2282
2283                 /* Ignore specific parts if they are known not to be useful */
2284                 if (!strcmp(iks_name(content), "conference-info")) {
2285                         continue;
2286                 }
2287
2288                 name = iks_find_attrib(content, "name");
2289
2290                 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2291                         /* If this content stanza has no name consider it invalid and move on */
2292                         if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2293                                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2294                                 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2295                                 return -1;
2296                         }
2297
2298                         /* Try to pre-populate which RTP instance this content is relevant to */
2299                         if (!strcmp(session->audio_name, name)) {
2300                                 rtp = session->rtp;
2301                         } else if (!strcmp(session->video_name, name)) {
2302                                 rtp = session->vrtp;
2303                         }
2304                 } else {
2305                         /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2306                         rtp = session->rtp;
2307                 }
2308
2309                 /* If description information is available use it */
2310                 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2311                     (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2312                     (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2313                     (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2314                     (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2315                     (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2316                         /* If we failed to do something with the content description abort immediately */
2317                         if (jingle_interpret_description(session, description, name, &rtp)) {
2318                                 return -1;
2319                         }
2320
2321                         /* If we successfully interpret the description then the codecs need updating */
2322                         changed = 1;
2323                 }
2324
2325                 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2326                 if (!rtp) {
2327                         ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2328                         jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2329                         return -1;
2330                 }
2331
2332                 /* If ICE UDP transport information is available use it */
2333                 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2334                         if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2335                                 return -1;
2336                         }
2337                 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2338                            (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2339                            (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2340                            (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2341                         /* If Google transport support is available use it */
2342                         if (jingle_interpret_google_transport(session, transport, rtp)) {
2343                                 return -1;
2344                         }
2345                 } else if (iks_find(content, "transport")) {
2346                         /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2347                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2348                         ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2349                         return -1;
2350                 }
2351         }
2352
2353         if (!changed) {
2354                 return 0;
2355         }
2356
2357         if ((chan = jingle_session_lock_full(session))) {
2358                 struct ast_format fmt;
2359
2360                 ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
2361                 ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
2362                 ast_set_read_format(chan, &fmt);
2363                 ast_set_write_format(chan, &fmt);
2364
2365                 ast_channel_unlock(chan);
2366                 ast_channel_unref(chan);
2367         }
2368         ao2_unlock(session);
2369
2370         return 0;
2371 }
2372
2373 /*! \brief Handler function for the 'session-initiate' action */
2374 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2375 {
2376         char *sid;
2377         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2378         struct ast_channel *chan;
2379         int res;
2380
2381         if (session) {
2382                 /* This is a duplicate session setup, so respond accordingly */
2383                 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2384                 return;
2385         }
2386
2387         /* Retrieve the session identifier from the message, note that this may alter the transport */
2388         if ((sid = iks_find_attrib(pak->query, "id"))) {
2389                 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2390                 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2391         } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2392                 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2393                 return;
2394         }
2395
2396         /* Create a new local session */
2397         if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2398                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2399                 return;
2400         }
2401
2402         /* If we determined that the transport should change as a result of how we got the SID change it */
2403         if (transport != JINGLE_TRANSPORT_NONE) {
2404                 session->transport = transport;
2405         }
2406
2407         /* Create a new Asterisk channel using the above local session */
2408         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2409                 ao2_ref(session, -1);
2410                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2411                 return;
2412         }
2413
2414         ao2_link(endpoint->state->sessions, session);
2415
2416         ast_channel_lock(chan);
2417         ast_setstate(chan, AST_STATE_RING);
2418         ast_channel_unlock(chan);
2419         res = ast_pbx_start(chan);
2420
2421         switch (res) {
2422         case AST_PBX_FAILED:
2423                 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2424                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2425                 session->gone = 1;
2426                 ast_hangup(chan);
2427                 break;
2428         case AST_PBX_CALL_LIMIT:
2429                 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2430                 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2431                 ast_hangup(chan);
2432                 break;
2433         case AST_PBX_SUCCESS:
2434                 jingle_send_response(endpoint->connection, pak);
2435
2436                 /* Only send a transport-info message if we successfully interpreted the available content */
2437                 if (!jingle_interpret_content(session, pak)) {
2438                         jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2439                 }
2440                 break;
2441         }
2442 }
2443
2444 /*! \brief Handler function for the 'transport-info' action */
2445 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2446 {
2447         if (!session) {
2448                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2449                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2450                 return;
2451         }
2452
2453         jingle_interpret_content(session, pak);
2454         jingle_send_response(endpoint->connection, pak);
2455 }
2456
2457 /*! \brief Handler function for the 'session-accept' action */
2458 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2459 {
2460         struct ast_channel *chan;
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
2469         jingle_interpret_content(session, pak);
2470
2471         if ((chan = jingle_session_lock_full(session))) {
2472                 ast_queue_control(chan, AST_CONTROL_ANSWER);
2473                 ast_channel_unlock(chan);
2474                 ast_channel_unref(chan);
2475         }
2476         ao2_unlock(session);
2477
2478         jingle_send_response(endpoint->connection, pak);
2479 }
2480
2481 /*! \brief Handler function for the 'session-info' action */
2482 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2483 {
2484         struct ast_channel *chan;
2485
2486         if (!session) {
2487                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2488                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2489                 return;
2490         }
2491
2492         if (!(chan = jingle_session_lock_full(session))) {
2493                 ao2_unlock(session);
2494                 jingle_send_response(endpoint->connection, pak);
2495                 return;
2496         }
2497
2498         if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2499                 ast_queue_control(chan, AST_CONTROL_RINGING);
2500                 if (ast_channel_state(chan) != AST_STATE_UP) {
2501                         ast_setstate(chan, AST_STATE_RINGING);
2502                 }
2503         } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2504                 ast_queue_hold(chan, NULL);
2505         } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2506                 ast_queue_unhold(chan);
2507         }
2508
2509         ast_channel_unlock(chan);
2510         ast_channel_unref(chan);
2511         ao2_unlock(session);
2512
2513         jingle_send_response(endpoint->connection, pak);
2514 }
2515
2516 /*! \brief Handler function for the 'session-terminate' action */
2517 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2518 {
2519         struct ast_channel *chan;
2520         iks *reason, *text;
2521         int cause = AST_CAUSE_NORMAL;
2522         struct ast_control_pvt_cause_code *cause_code;
2523         int data_size = sizeof(*cause_code);
2524
2525         if (!session) {
2526                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2527                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2528                 return;
2529         }
2530
2531         if (!(chan = jingle_session_lock_full(session))) {
2532                 ao2_unlock(session);
2533                 jingle_send_response(endpoint->connection, pak);
2534                 return;
2535         }
2536
2537         /* Pull the reason text from the session-terminate message and translate it into a cause code */
2538         if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2539                 int i;
2540
2541                 /* Size of the string making up the cause code is "Motif " + text */
2542                 data_size += 6 + strlen(iks_name(text));
2543                 cause_code = ast_alloca(data_size);
2544                 memset(cause_code, 0, data_size);
2545
2546                 /* Get the appropriate cause code mapping for this reason */
2547                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2548                         if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2549                                 cause = jingle_reason_mappings[i].cause;
2550                                 break;
2551                         }
2552                 }
2553
2554                 /* Store the technology specific information */
2555                 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2556         } else {
2557                 /* No technology specific information is available */
2558                 cause_code = ast_alloca(data_size);
2559                 memset(cause_code, 0, data_size);
2560         }
2561
2562         ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2563         cause_code->ast_cause = cause;
2564         ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2565         ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2566
2567         ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2568         ast_queue_hangup_with_cause(chan, cause);
2569         session->gone = 1;
2570
2571         ast_channel_unlock(chan);
2572         ast_channel_unref(chan);
2573         ao2_unlock(session);
2574
2575         jingle_send_response(endpoint->connection, pak);
2576 }
2577
2578 /*! \brief Callback for when a Jingle action is received from an endpoint */
2579 static int jingle_action_hook(void *data, ikspak *pak)
2580 {
2581         char *action;
2582         const char *sid = NULL;
2583         struct jingle_session *session = NULL;
2584         struct jingle_endpoint *endpoint = data;
2585         int i, handled = 0;
2586
2587         /* We accept both Jingle and Google-V1 */
2588         if (!(action = iks_find_attrib(pak->query, "action")) &&
2589             !(action = iks_find_attrib(pak->query, "type"))) {
2590                 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2591                  * to a message that has no response hook. */
2592                 return IKS_FILTER_EAT;
2593         }
2594
2595         /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2596          * does not permit us to make this completely safe. */
2597         ao2_ref(endpoint, +1);
2598
2599         /* If a Jingle session identifier is present use it */
2600         if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2601                 /* If a Google-V1 session identifier is present use it */
2602                 sid = iks_find_attrib(pak->query, "id");
2603         }
2604
2605         /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2606          * this is required or not */
2607         if (!ast_strlen_zero(sid)) {
2608                 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2609         }
2610
2611         /* If a session is present associate the callid with this thread */
2612         if (session) {
2613                 ast_callid_threadassoc_add(session->callid);
2614         }
2615
2616         /* Iterate through supported action handlers looking for one that is able to handle this */
2617         for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2618                 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2619                         jingle_action_handlers[i].handler(endpoint, session, pak);
2620                         handled = 1;
2621                         break;
2622                 }
2623         }
2624
2625         /* If no action handler is present for the action they sent us make it evident */
2626         if (!handled) {
2627                 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2628         }
2629
2630         /* If a session was successfully found for this message deref it now since the handler is done */
2631         if (session) {
2632                 ast_callid_threadassoc_remove();
2633                 ao2_ref(session, -1);
2634         }
2635
2636         ao2_ref(endpoint, -1);
2637
2638         return IKS_FILTER_EAT;
2639 }
2640
2641 /*! \brief Custom handler for groups */
2642 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2643 {
2644         struct jingle_endpoint *endpoint = obj;
2645
2646         if (!strcasecmp(var->name, "callgroup")) {
2647                 endpoint->callgroup = ast_get_group(var->value);
2648         } else if (!strcasecmp(var->name, "pickupgroup")) {
2649                 endpoint->pickupgroup = ast_get_group(var->value);
2650         } else {
2651                 return -1;
2652         }
2653
2654         return 0;
2655 }
2656
2657 /*! \brief Custom handler for connection */
2658 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2659 {
2660         struct jingle_endpoint *endpoint = obj;
2661
2662         /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2663          * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2664          */
2665         if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2666                 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2667                 return -1;
2668         }
2669
2670         if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2671                                                    IKS_RULE_TYPE, IKS_PAK_IQ,
2672                                                    IKS_RULE_NS, JINGLE_NS,
2673                                                    IKS_RULE_NS, GOOGLE_SESSION_NS,
2674                                                    IKS_RULE_DONE))) {
2675                 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2676                 return -1;
2677         }
2678
2679         return 0;
2680 }
2681
2682 /*! \brief Custom handler for transport */
2683 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2684 {
2685         struct jingle_endpoint *endpoint = obj;
2686
2687         if (!strcasecmp(var->value, "ice-udp")) {
2688                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2689         } else if (!strcasecmp(var->value, "google")) {
2690                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2691         } else if (!strcasecmp(var->value, "google-v1")) {
2692                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2693         } else {
2694                 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2695                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2696         }
2697
2698         return 0;
2699 }
2700
2701 /*!
2702  * \brief Load the module
2703  *
2704  * Module loading including tests for configuration or dependencies.
2705  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2706  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2707  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
2708  * configuration file or other non-critical problem return 
2709  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2710  */
2711 static int load_module(void)
2712 {
2713         if (!(jingle_tech.capabilities = ast_format_cap_alloc(0))) {
2714                 return AST_MODULE_LOAD_DECLINE;
2715         }
2716
2717         if (aco_info_init(&cfg_info)) {
2718                 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2719                 goto end;
2720         }
2721
2722         aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2723         aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2724         aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2725         aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2726         aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2727         aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2728         aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2729         aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
2730         aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
2731         aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2732         aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2733         aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2734                             FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2735         aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2736                             FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2737
2738         ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
2739
2740         if (aco_process_config(&cfg_info, 0)) {
2741                 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2742                 aco_info_destroy(&cfg_info);
2743                 return AST_MODULE_LOAD_DECLINE;
2744         }
2745
2746         if (!(sched = ast_sched_context_create())) {
2747                 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2748                 goto end;
2749         }
2750
2751         if (ast_sched_start_thread(sched)) {
2752                 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2753                 goto end;
2754         }
2755
2756         ast_rtp_glue_register(&jingle_rtp_glue);
2757
2758         if (ast_channel_register(&jingle_tech)) {
2759                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2760                 goto end;
2761         }
2762
2763         return 0;
2764
2765 end:
2766         ast_rtp_glue_unregister(&jingle_rtp_glue);
2767
2768         if (sched) {
2769                 ast_sched_context_destroy(sched);
2770         }
2771
2772         aco_info_destroy(&cfg_info);
2773
2774         return AST_MODULE_LOAD_FAILURE;
2775 }
2776
2777 /*! \brief Reload module */
2778 static int reload(void)
2779 {
2780         return aco_process_config(&cfg_info, 1);
2781 }
2782
2783 /*! \brief Unload the jingle channel from Asterisk */
2784 static int unload_module(void)
2785 {
2786         ast_channel_unregister(&jingle_tech);
2787         ast_format_cap_destroy(jingle_tech.capabilities);
2788         jingle_tech.capabilities = NULL;
2789         ast_rtp_glue_unregister(&jingle_rtp_glue);
2790         ast_sched_context_destroy(sched);
2791         aco_info_destroy(&cfg_info);
2792         ao2_global_obj_release(globals);
2793
2794         return 0;
2795 }
2796
2797 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2798                 .load = load_module,
2799                 .unload = unload_module,
2800                 .reload = reload,
2801                 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2802                );