Add channel locking for channel snapshot creation.
[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_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", ast_random(), 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 char *linkedid, 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, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) {
786                 return NULL;
787         }
788         ast_channel_lock(chan);
789
790         ast_channel_stage_snapshot(chan);
791
792         ast_channel_tech_set(chan, &jingle_tech);
793         ast_channel_tech_pvt_set(chan, session);
794         jingle_set_owner(session, chan);
795
796         ast_channel_callid_set(chan, session->callid);
797
798         ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
799         ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
800
801         if (session->rtp) {
802                 struct ast_rtp_engine_ice *ice;
803
804                 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
805                 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
806                 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
807
808                 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
809                      (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
810                     (ice = ast_rtp_instance_get_ice(session->rtp))) {
811                         /* We stop built in ICE support because we need to fall back to old old old STUN support */
812                         ice->stop(session->rtp);
813                 }
814         }
815
816         if (state == AST_STATE_RING) {
817                 ast_channel_rings_set(chan, 1);
818         }
819
820         ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
821
822         ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
823         ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
824         ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
825         ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
826         ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
827
828         ao2_lock(endpoint);
829
830         ast_channel_callgroup_set(chan, endpoint->callgroup);
831         ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
832
833         if (!ast_strlen_zero(endpoint->accountcode)) {
834                 ast_channel_accountcode_set(chan, endpoint->accountcode);
835         }
836
837         if (!ast_strlen_zero(endpoint->language)) {
838                 ast_channel_language_set(chan, endpoint->language);
839         }
840
841         if (!ast_strlen_zero(endpoint->musicclass)) {
842                 ast_channel_musicclass_set(chan, endpoint->musicclass);
843         }
844
845         ast_channel_context_set(chan, endpoint->context);
846         if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
847                 ast_channel_exten_set(chan, endpoint->name);
848         } else {
849                 ast_channel_exten_set(chan, "s");
850         }
851         ast_channel_priority_set(chan, 1);
852
853         ao2_unlock(endpoint);
854
855         ast_channel_stage_snapshot_done(chan);
856         ast_channel_unlock(chan);
857
858         return chan;
859 }
860
861 /*! \brief Internal helper function which sends a response */
862 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
863 {
864         iks *response;
865
866         if (!(response = iks_new("iq"))) {
867                 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
868                 return;
869         }
870
871         iks_insert_attrib(response, "type", "result");
872         iks_insert_attrib(response, "from", connection->jid->full);
873         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
874         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
875
876         ast_xmpp_client_send(connection, response);
877
878         iks_delete(response);
879 }
880
881 /*! \brief Internal helper function which sends an error response */
882 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
883 {
884         iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
885
886         if (!(response = iks_new("iq")) ||
887             !(error = iks_new("error")) ||
888             !(reason = iks_new(reasonstr))) {
889                 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
890                 goto end;
891         }
892
893         iks_insert_attrib(response, "type", "error");
894         iks_insert_attrib(response, "from", connection->jid->full);
895         iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
896         iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
897
898         iks_insert_attrib(error, "type", type);
899         iks_insert_node(error, reason);
900
901         if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
902                 iks_insert_node(error, reason2);
903         }
904
905         iks_insert_node(response, error);
906
907         ast_xmpp_client_send(connection, response);
908 end:
909         iks_delete(reason2);
910         iks_delete(reason);
911         iks_delete(error);
912         iks_delete(response);
913 }
914
915 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
916 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
917 {
918         struct ast_rtp_engine_ice *ice;
919         struct ao2_container *local_candidates;
920         struct ao2_iterator it;
921         struct ast_rtp_engine_ice_candidate *candidate;
922         int i = 0, res = 0;
923
924         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
925                 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
926                 return -1;
927         }
928
929         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
930         iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
931         iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
932
933         it = ao2_iterator_init(local_candidates, 0);
934
935         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
936                 iks *local_candidate;
937                 char tmp[30];
938
939                 if (!(local_candidate = iks_new("candidate"))) {
940                         res = -1;
941                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
942                         break;
943                 }
944
945                 snprintf(tmp, sizeof(tmp), "%d", candidate->id);
946                 iks_insert_attrib(local_candidate, "component", tmp);
947                 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
948                 iks_insert_attrib(local_candidate, "foundation", tmp);
949                 iks_insert_attrib(local_candidate, "generation", "0");
950                 iks_insert_attrib(local_candidate, "network", "0");
951                 snprintf(tmp, sizeof(tmp), "%04lx", ast_random() & 0xffff);
952                 iks_insert_attrib(local_candidate, "id", tmp);
953                 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
954                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
955                 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
956                 iks_insert_attrib(local_candidate, "priority", tmp);
957                 iks_insert_attrib(local_candidate, "protocol", "udp");
958
959                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
960                         iks_insert_attrib(local_candidate, "type", "host");
961                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
962                         iks_insert_attrib(local_candidate, "type", "srflx");
963                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
964                         iks_insert_attrib(local_candidate, "type", "relay");
965                 }
966
967                 iks_insert_node(transport, local_candidate);
968                 candidates[i++] = local_candidate;
969         }
970
971         ao2_iterator_destroy(&it);
972         ao2_ref(local_candidates, -1);
973
974         return res;
975 }
976
977 /*! \brief Internal helper function which adds Google candidates to a transport node */
978 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)
979 {
980         struct ast_rtp_engine_ice *ice;
981         struct ao2_container *local_candidates;
982         struct ao2_iterator it;
983         struct ast_rtp_engine_ice_candidate *candidate;
984         int i = 0, res = 0;
985
986         if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
987                 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
988                 return -1;
989         }
990
991         if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
992                 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
993         }
994
995         it = ao2_iterator_init(local_candidates, 0);
996
997         while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
998                 iks *local_candidate;
999                 /* In Google land a username is 16 bytes, explicitly */
1000                 char ufrag[17] = "";
1001
1002                 if (!(local_candidate = iks_new("candidate"))) {
1003                         res = -1;
1004                         ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
1005                         break;
1006                 }
1007
1008                 if (candidate->id == 1) {
1009                         iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
1010                 } else if (candidate->id == 2) {
1011                         iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
1012                 } else {
1013                         iks_delete(local_candidate);
1014                         continue;
1015                 }
1016
1017                 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
1018                 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
1019
1020                 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
1021                         iks_insert_attrib(local_candidate, "preference", "0.95");
1022                         iks_insert_attrib(local_candidate, "type", "local");
1023                 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
1024                         iks_insert_attrib(local_candidate, "preference", "0.9");
1025                         iks_insert_attrib(local_candidate, "type", "stun");
1026                 }
1027
1028                 iks_insert_attrib(local_candidate, "protocol", "udp");
1029                 iks_insert_attrib(local_candidate, "network", "0");
1030                 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
1031                 iks_insert_attrib(local_candidate, "username", ufrag);
1032                 iks_insert_attrib(local_candidate, "generation", "0");
1033
1034                 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
1035                         iks_insert_attrib(local_candidate, "password", "");
1036                         iks_insert_attrib(local_candidate, "foundation", "0");
1037                         iks_insert_attrib(local_candidate, "component", "1");
1038                 } else {
1039                         iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
1040                 }
1041
1042                 /* You may notice a lack of relay support up above - this is because we don't support it for use with
1043                  * the Google talk transport due to their arcane support. */
1044
1045                 iks_insert_node(transport, local_candidate);
1046                 candidates[i++] = local_candidate;
1047         }
1048
1049         ao2_iterator_destroy(&it);
1050         ao2_ref(local_candidates, -1);
1051
1052         return res;
1053 }
1054
1055 /*! \brief Internal function which sends a session-terminate message */
1056 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
1057 {
1058         iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
1059
1060         if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
1061             !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
1062                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
1063                 goto end;
1064         }
1065
1066         iks_insert_attrib(iq, "to", session->remote);
1067         iks_insert_attrib(iq, "type", "set");
1068         iks_insert_attrib(iq, "id", session->connection->mid);
1069         ast_xmpp_increment_mid(session->connection->mid);
1070
1071         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1072                 iks_insert_attrib(jingle, "type", "terminate");
1073                 iks_insert_attrib(jingle, "id", session->sid);
1074                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1075                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1076         } else {
1077                 iks_insert_attrib(jingle, "action", "session-terminate");
1078                 iks_insert_attrib(jingle, "sid", session->sid);
1079                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1080         }
1081
1082         iks_insert_node(iq, jingle);
1083         iks_insert_node(jingle, reason);
1084         iks_insert_node(reason, text);
1085
1086         ast_xmpp_client_send(session->connection, iq);
1087
1088 end:
1089         iks_delete(text);
1090         iks_delete(reason);
1091         iks_delete(jingle);
1092         iks_delete(iq);
1093 }
1094
1095 /*! \brief Internal function which sends a session-info message */
1096 static void jingle_send_session_info(struct jingle_session *session, const char *info)
1097 {
1098         iks *iq = NULL, *jingle = NULL, *text = NULL;
1099
1100         /* Google-V1 has no way to send informational messages so don't even bother trying */
1101         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1102                 return;
1103         }
1104
1105         if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
1106                 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
1107                 goto end;
1108         }
1109
1110         iks_insert_attrib(iq, "to", session->remote);
1111         iks_insert_attrib(iq, "type", "set");
1112         iks_insert_attrib(iq, "id", session->connection->mid);
1113         ast_xmpp_increment_mid(session->connection->mid);
1114
1115         iks_insert_attrib(jingle, "action", "session-info");
1116         iks_insert_attrib(jingle, "sid", session->sid);
1117         iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1118         iks_insert_node(iq, jingle);
1119         iks_insert_node(jingle, text);
1120
1121         ast_xmpp_client_send(session->connection, iq);
1122
1123 end:
1124         iks_delete(text);
1125         iks_delete(jingle);
1126         iks_delete(iq);
1127 }
1128
1129 /*! \internal
1130  *
1131  * \brief Locks both pvt and pvt owner if owner is present.
1132  *
1133  * \note This function gives a ref to pvt->owner if it is present and locked.
1134  *       This reference must be decremented after pvt->owner is unlocked.
1135  *
1136  * \note This function will never give you up,
1137  * \note This function will never let you down.
1138  * \note This function will run around and desert you.
1139  *
1140  * \pre pvt is not locked
1141  * \post pvt is locked
1142  * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
1143  *
1144  * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
1145  */
1146 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
1147 {
1148         struct ast_channel *chan;
1149
1150         /* Locking is simple when it is done right.  If you see a deadlock resulting
1151          * in this function, it is not this function's fault, Your problem exists elsewhere.
1152          * This function is perfect... seriously. */
1153         for (;;) {
1154                 /* First, get the channel and grab a reference to it */
1155                 ao2_lock(pvt);
1156                 chan = pvt->owner;
1157                 if (chan) {
1158                         /* The channel can not go away while we hold the pvt lock.
1159                          * Give the channel a ref so it will not go away after we let
1160                          * the pvt lock go. */
1161                         ast_channel_ref(chan);
1162                 } else {
1163                         /* no channel, return pvt locked */
1164                         return NULL;
1165                 }
1166
1167                 /* We had to hold the pvt lock while getting a ref to the owner channel
1168                  * but now we have to let this lock go in order to preserve proper
1169                  * locking order when grabbing the channel lock */
1170                 ao2_unlock(pvt);
1171
1172                 /* Look, no deadlock avoidance, hooray! */
1173                 ast_channel_lock(chan);
1174                 ao2_lock(pvt);
1175                 if (pvt->owner == chan) {
1176                         /* done */
1177                         break;
1178                 }
1179
1180                 /* If the owner changed while everything was unlocked, no problem,
1181                  * just start over and everthing will work.  This is rare, do not be
1182                  * confused by this loop and think this it is an expensive operation.
1183                  * The majority of the calls to this function will never involve multiple
1184                  * executions of this loop. */
1185                 ast_channel_unlock(chan);
1186                 ast_channel_unref(chan);
1187                 ao2_unlock(pvt);
1188         }
1189
1190         /* If owner exists, it is locked and reffed */
1191         return pvt->owner;
1192 }
1193
1194 /*! \brief Helper function which queues a hangup frame with cause code */
1195 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1196 {
1197         struct ast_channel *chan;
1198
1199         if ((chan = jingle_session_lock_full(session))) {
1200                 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1201                 ast_queue_hangup_with_cause(chan, cause);
1202                 ast_channel_unlock(chan);
1203                 ast_channel_unref(chan);
1204         }
1205         ao2_unlock(session);
1206 }
1207
1208 /*! \brief Internal function which sends a transport-info message */
1209 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1210 {
1211         iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1212         iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1213         int i, res = 0;
1214
1215         if (!(iq = iks_new("iq")) ||
1216             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1217                 iks_delete(iq);
1218                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1219                 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1220                 return;
1221         }
1222
1223         memset(audio_candidates, 0, sizeof(audio_candidates));
1224         memset(video_candidates, 0, sizeof(video_candidates));
1225
1226         iks_insert_attrib(iq, "from", session->connection->jid->full);
1227         iks_insert_attrib(iq, "to", from);
1228         iks_insert_attrib(iq, "type", "set");
1229         iks_insert_attrib(iq, "id", session->connection->mid);
1230         ast_xmpp_increment_mid(session->connection->mid);
1231
1232         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1233                 iks_insert_attrib(jingle, "type", "candidates");
1234                 iks_insert_attrib(jingle, "id", session->sid);
1235                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1236                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1237         } else {
1238                 iks_insert_attrib(jingle, "action", "transport-info");
1239                 iks_insert_attrib(jingle, "sid", session->sid);
1240                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1241         }
1242         iks_insert_node(iq, jingle);
1243
1244         if (session->rtp) {
1245                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1246                         /* V1 protocol has the candidates directly in the session */
1247                         res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1248                 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1249                         iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1250                         iks_insert_attrib(audio, "name", session->audio_name);
1251                         iks_insert_node(jingle, audio);
1252                         iks_insert_node(audio, audio_transport);
1253
1254                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1255                                 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1256                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1257                                 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1258                                                                                 session->maxicecandidates);
1259                         }
1260                 } else {
1261                         res = -1;
1262                 }
1263         }
1264
1265         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1266                 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1267                         iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1268                         iks_insert_attrib(video, "name", session->video_name);
1269                         iks_insert_node(jingle, video);
1270                         iks_insert_node(video, video_transport);
1271
1272                         if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1273                                 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1274                         } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1275                                 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1276                                                                                 session->maxicecandidates);
1277                         }
1278                 } else {
1279                         res = -1;
1280                 }
1281         }
1282
1283         if (!res) {
1284                 ast_xmpp_client_send(session->connection, iq);
1285         } else {
1286                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1287         }
1288
1289         /* Clean up after ourselves */
1290         for (i = 0; i < session->maxicecandidates; i++) {
1291                 iks_delete(video_candidates[i]);
1292                 iks_delete(audio_candidates[i]);
1293         }
1294
1295         iks_delete(video_transport);
1296         iks_delete(video);
1297         iks_delete(audio_transport);
1298         iks_delete(audio);
1299         iks_delete(jingle);
1300         iks_delete(iq);
1301 }
1302
1303 /*! \brief Internal helper function which adds payloads to a description */
1304 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)
1305 {
1306         struct ast_format format;
1307         int x = 0, i = 0, res = 0;
1308
1309         for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
1310                 int rtp_code;
1311                 iks *payload;
1312                 char tmp[32];
1313
1314                 if (!ast_codec_pref_index(&session->prefs, x, &format)) {
1315                         break;
1316                 }
1317
1318                 if (AST_FORMAT_GET_TYPE(format.id) != type) {
1319                         continue;
1320                 }
1321
1322                 if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
1323                         continue;
1324                 }
1325
1326                 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
1327                     (!(payload = iks_new("payload-type")))) {
1328                         return -1;
1329                 }
1330
1331                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1332                         iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1333                 }
1334
1335                 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1336                 iks_insert_attrib(payload, "id", tmp);
1337                 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
1338                 iks_insert_attrib(payload, "channels", "1");
1339
1340                 if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1341                         iks_insert_attrib(payload, "clockrate", "16000");
1342                 } else {
1343                         snprintf(tmp, sizeof(tmp), "%d", ast_rtp_lookup_sample_rate2(1, &format, 0));
1344                         iks_insert_attrib(payload, "clockrate", tmp);
1345                 }
1346
1347                 if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1348                         iks *parameter;
1349
1350                         /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1351                         if ((parameter = iks_new("parameter"))) {
1352                                 iks_insert_attrib(parameter, "name", "width");
1353                                 iks_insert_attrib(parameter, "value", "640");
1354                                 iks_insert_node(payload, parameter);
1355                         }
1356                         if ((parameter = iks_new("parameter"))) {
1357                                 iks_insert_attrib(parameter, "name", "height");
1358                                 iks_insert_attrib(parameter, "value", "480");
1359                                 iks_insert_node(payload, parameter);
1360                         }
1361                         if ((parameter = iks_new("parameter"))) {
1362                                 iks_insert_attrib(parameter, "name", "framerate");
1363                                 iks_insert_attrib(parameter, "value", "30");
1364                                 iks_insert_node(payload, parameter);
1365                         }
1366                 }
1367
1368                 iks_insert_node(description, payload);
1369                 payloads[i++] = payload;
1370         }
1371         /* If this is for audio and there is room for RFC2833 add it in */
1372         if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
1373                 iks *payload;
1374
1375                 if ((payload = iks_new("payload-type"))) {
1376                         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1377                                 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1378                         }
1379
1380                         iks_insert_attrib(payload, "id", "101");
1381                         iks_insert_attrib(payload, "name", "telephone-event");
1382                         iks_insert_attrib(payload, "channels", "1");
1383                         iks_insert_attrib(payload, "clockrate", "8000");
1384                         iks_insert_node(description, payload);
1385                         payloads[i++] = payload;
1386                 }
1387         }
1388
1389         return res;
1390 }
1391
1392 /*! \brief Helper function which adds content to a description */
1393 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1394                               const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
1395 {
1396         int res = 0;
1397
1398         if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1399                 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1400                 iks_insert_attrib(content, "name", name);
1401                 iks_insert_node(jingle, content);
1402
1403                 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1404                 if (type == AST_FORMAT_TYPE_AUDIO) {
1405                         iks_insert_attrib(description, "media", "audio");
1406                 } else if (type == AST_FORMAT_TYPE_VIDEO) {
1407                         iks_insert_attrib(description, "media", "video");
1408                 } else {
1409                         return -1;
1410                 }
1411                 iks_insert_node(content, description);
1412         } else {
1413                 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1414                 iks_insert_node(jingle, description);
1415         }
1416
1417         if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1418                 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1419                         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1420                         iks_insert_node(content, transport);
1421                 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1422                         iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1423                         iks_insert_node(content, transport);
1424                 }
1425         }
1426
1427         return res;
1428 }
1429
1430 /*! \brief Internal function which sends a complete session message */
1431 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1432 {
1433         iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1434         iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1435         iks *audio_transport = NULL, *video_transport = NULL;
1436         int i, res = 0;
1437
1438         if (!(iq = iks_new("iq")) ||
1439             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1440                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1441                 iks_delete(iq);
1442                 return;
1443         }
1444
1445         memset(audio_payloads, 0, sizeof(audio_payloads));
1446         memset(video_payloads, 0, sizeof(video_payloads));
1447
1448         iks_insert_attrib(iq, "from", session->connection->jid->full);
1449         iks_insert_attrib(iq, "to", session->remote);
1450         iks_insert_attrib(iq, "type", "set");
1451         iks_insert_attrib(iq, "id", session->connection->mid);
1452         ast_xmpp_increment_mid(session->connection->mid);
1453
1454         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1455                 iks_insert_attrib(jingle, "type", action);
1456                 iks_insert_attrib(jingle, "id", session->sid);
1457                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1458         } else {
1459                 iks_insert_attrib(jingle, "action", action);
1460                 iks_insert_attrib(jingle, "sid", session->sid);
1461                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1462         }
1463
1464         if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1465                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1466         }
1467
1468         iks_insert_node(iq, jingle);
1469
1470         if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1471             (audio_transport = iks_new("transport"))) {
1472                 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1473                                          AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
1474         } else {
1475                 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1476                 res = -1;
1477         }
1478
1479         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1480                 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1481                     (video_transport = iks_new("transport"))) {
1482                         res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1483                                                  AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
1484                 } else {
1485                         ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1486                         res = -1;
1487                 }
1488         }
1489
1490         if (!res) {
1491                 ast_xmpp_client_send(session->connection, iq);
1492         } else {
1493                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1494         }
1495
1496         iks_delete(video_transport);
1497         iks_delete(audio_transport);
1498
1499         for (i = 0; i < session->maxpayloads; i++) {
1500                 iks_delete(video_payloads[i]);
1501                 iks_delete(audio_payloads[i]);
1502         }
1503
1504         iks_delete(video_description);
1505         iks_delete(video);
1506         iks_delete(audio_description);
1507         iks_delete(audio);
1508         iks_delete(jingle);
1509         iks_delete(iq);
1510 }
1511
1512 /*! \brief Internal function which sends a session-inititate message */
1513 static void jingle_send_session_initiate(struct jingle_session *session)
1514 {
1515         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1516 }
1517
1518 /*! \brief Internal function which sends a session-accept message */
1519 static void jingle_send_session_accept(struct jingle_session *session)
1520 {
1521         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1522 }
1523
1524 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1525 static int jingle_outgoing_hook(void *data, ikspak *pak)
1526 {
1527         struct jingle_session *session = data;
1528         iks *error = iks_find(pak->x, "error"), *redirect;
1529
1530         /* In all cases this hook is done with */
1531         iks_filter_remove_rule(session->connection->filter, session->rule);
1532         session->rule = NULL;
1533
1534         ast_callid_threadassoc_add(session->callid);
1535
1536         /* If no error occurred they accepted our session-initiate message happily */
1537         if (!error) {
1538                 struct ast_channel *chan;
1539
1540                 if ((chan = jingle_session_lock_full(session))) {
1541                         ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1542                         ast_channel_unlock(chan);
1543                         ast_channel_unref(chan);
1544                 }
1545                 ao2_unlock(session);
1546
1547                 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1548
1549                 goto end;
1550         }
1551
1552         /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1553         session->gone = 1;
1554
1555         /* Map the error we received to an appropriate cause code and hang up the channel */
1556         if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1557                 iks *to = iks_child(redirect);
1558                 char *target;
1559
1560                 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1561                         /* Make the xmpp: go away if it is present */
1562                         if (!strncmp(target, "xmpp:", 5)) {
1563                                 target += 5;
1564                         }
1565
1566                         /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1567                         ast_copy_string(session->remote, target, sizeof(session->remote));
1568
1569                         /* Add a new hook so we can get the status of redirected session */
1570                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1571                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1572
1573                         jingle_send_session_initiate(session);
1574
1575                         session->gone = 0;
1576                 } else {
1577                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1578                 }
1579         } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1580                 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1581         } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1582                 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1583         } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1584                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1585         } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1586                 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1587         } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1588                 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1589                 session->transport--;
1590
1591                 /* If we still have a viable transport mechanism re-send the session-initiate */
1592                 if (session->transport != JINGLE_TRANSPORT_NONE) {
1593                         struct ast_rtp_engine_ice *ice;
1594
1595                         if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1596                              (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1597                             (ice = ast_rtp_instance_get_ice(session->rtp))) {
1598                                 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1599                                 ice->stop(session->rtp);
1600                         }
1601
1602                         /* Re-send the message to the *original* target and not a redirected one */
1603                         ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1604
1605                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1606                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1607
1608                         jingle_send_session_initiate(session);
1609
1610                         session->gone = 0;
1611                 } else {
1612                         /* Otherwise we have exhausted all transports */
1613                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1614                 }
1615         } else {
1616                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1617         }
1618
1619 end:
1620         ast_callid_threadassoc_remove();
1621
1622         return IKS_FILTER_EAT;
1623 }
1624
1625 /*! \brief Function called by core when we should answer a Jingle session */
1626 static int jingle_answer(struct ast_channel *ast)
1627 {
1628         struct jingle_session *session = ast_channel_tech_pvt(ast);
1629
1630         /* The channel has already been answered so we don't need to do anything */
1631         if (ast_channel_state(ast) == AST_STATE_UP) {
1632                 return 0;
1633         }
1634
1635         jingle_send_session_accept(session);
1636
1637         return 0;
1638 }
1639
1640 /*! \brief Function called by core to read any waiting frames */
1641 static struct ast_frame *jingle_read(struct ast_channel *ast)
1642 {
1643         struct jingle_session *session = ast_channel_tech_pvt(ast);
1644         struct ast_frame *frame = &ast_null_frame;
1645
1646         switch (ast_channel_fdno(ast)) {
1647         case 0:
1648                 if (session->rtp) {
1649                         frame = ast_rtp_instance_read(session->rtp, 0);
1650                 }
1651                 break;
1652         case 1:
1653                 if (session->rtp) {
1654                         frame = ast_rtp_instance_read(session->rtp, 1);
1655                 }
1656                 break;
1657         case 2:
1658                 if (session->vrtp) {
1659                         frame = ast_rtp_instance_read(session->vrtp, 0);
1660                 }
1661                 break;
1662         case 3:
1663                 if (session->vrtp) {
1664                         frame = ast_rtp_instance_read(session->vrtp, 1);
1665                 }
1666                 break;
1667         default:
1668                 break;
1669         }
1670
1671         if (frame && frame->frametype == AST_FRAME_VOICE &&
1672             !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
1673                 if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
1674                         ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1675                                   ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
1676                         ast_frfree(frame);
1677                         frame = &ast_null_frame;
1678                 } else {
1679                         ast_debug(1, "Oooh, format changed to %s\n",
1680                                   ast_getformatname(&frame->subclass.format));
1681                         ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
1682                         ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
1683                         ast_set_read_format(ast, ast_channel_readformat(ast));
1684                         ast_set_write_format(ast, ast_channel_writeformat(ast));
1685                 }
1686         }
1687
1688         return frame;
1689 }
1690
1691 /*! \brief Function called by core to write frames */
1692 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1693 {
1694         struct jingle_session *session = ast_channel_tech_pvt(ast);
1695         int res = 0;
1696         char buf[256];
1697
1698         switch (frame->frametype) {
1699         case AST_FRAME_VOICE:
1700                 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
1701                         ast_log(LOG_WARNING,
1702                                 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1703                                 ast_getformatname(&frame->subclass.format),
1704                                 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
1705                                 ast_getformatname(ast_channel_readformat(ast)),
1706                                 ast_getformatname(ast_channel_writeformat(ast)));
1707                         return 0;
1708                 }
1709                 if (session && session->rtp) {
1710                         res = ast_rtp_instance_write(session->rtp, frame);
1711                 }
1712                 break;
1713         case AST_FRAME_VIDEO:
1714                 if (session && session->vrtp) {
1715                         res = ast_rtp_instance_write(session->vrtp, frame);
1716                 }
1717                 break;
1718         default:
1719                 ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
1720                         frame->frametype);
1721                 return 0;
1722         }
1723
1724         return res;
1725 }
1726
1727 /*! \brief Function called by core to change the underlying owner channel */
1728 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1729 {
1730         struct jingle_session *session = ast_channel_tech_pvt(newchan);
1731
1732         ao2_lock(session);
1733
1734         jingle_set_owner(session, newchan);
1735
1736         ao2_unlock(session);
1737
1738         return 0;
1739 }
1740
1741 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1742 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1743 {
1744         struct jingle_session *session = ast_channel_tech_pvt(ast);
1745         int res = 0;
1746
1747         switch (condition) {
1748         case AST_CONTROL_RINGING:
1749                 if (ast_channel_state(ast) == AST_STATE_RING) {
1750                         jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1751                 } else {
1752                         res = -1;
1753                 }
1754                 break;
1755         case AST_CONTROL_BUSY:
1756                 if (ast_channel_state(ast) != AST_STATE_UP) {
1757                         ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1758                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1759                 } else {
1760                         res = -1;
1761                 }
1762                 break;
1763         case AST_CONTROL_CONGESTION:
1764                 if (ast_channel_state(ast) != AST_STATE_UP) {
1765                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1766                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1767                 } else {
1768                         res = -1;
1769                 }
1770                 break;
1771         case AST_CONTROL_INCOMPLETE:
1772                 if (ast_channel_state(ast) != AST_STATE_UP) {
1773                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1774                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1775                 }
1776                 break;
1777         case AST_CONTROL_HOLD:
1778                 ast_moh_start(ast, data, NULL);
1779                 break;
1780         case AST_CONTROL_UNHOLD:
1781                 ast_moh_stop(ast);
1782                 break;
1783         case AST_CONTROL_SRCUPDATE:
1784                 if (session->rtp) {
1785                         ast_rtp_instance_update_source(session->rtp);
1786                 }
1787                 break;
1788         case AST_CONTROL_SRCCHANGE:
1789                 if (session->rtp) {
1790                         ast_rtp_instance_change_source(session->rtp);
1791                 }
1792                 break;
1793         case AST_CONTROL_VIDUPDATE:
1794         case AST_CONTROL_UPDATE_RTP_PEER:
1795         case AST_CONTROL_CONNECTED_LINE:
1796                 break;
1797         case AST_CONTROL_PVT_CAUSE_CODE:
1798         case -1:
1799                 res = -1;
1800                 break;
1801         default:
1802                 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1803                 res = -1;
1804         }
1805
1806         return res;
1807 }
1808
1809 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1810 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1811 {
1812         struct jingle_session *session = ast_channel_tech_pvt(chan);
1813
1814         return ast_xmpp_client_send_message(session->connection, session->remote, text);
1815 }
1816
1817 /*! \brief Function called by core to start a DTMF digit */
1818 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1819 {
1820         struct jingle_session *session = ast_channel_tech_pvt(chan);
1821
1822         if (session->rtp) {
1823                 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1824         }
1825
1826         return 0;
1827 }
1828
1829 /*! \brief Function called by core to stop a DTMF digit */
1830 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1831 {
1832         struct jingle_session *session = ast_channel_tech_pvt(ast);
1833
1834         if (session->rtp) {
1835                 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1836         }
1837
1838         return 0;
1839 }
1840
1841 /*! \brief Function called by core to actually start calling a remote party */
1842 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1843 {
1844         struct jingle_session *session = ast_channel_tech_pvt(ast);
1845
1846         ast_setstate(ast, AST_STATE_RING);
1847
1848         /* Since we have no idea of the remote capabilities use ours for now */
1849         ast_format_cap_copy(session->jointcap, session->cap);
1850
1851         /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1852         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1853                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1854
1855         jingle_send_session_initiate(session);
1856
1857         return 0;
1858 }
1859
1860 /*! \brief Function called by core to hang up a Jingle session */
1861 static int jingle_hangup(struct ast_channel *ast)
1862 {
1863         struct jingle_session *session = ast_channel_tech_pvt(ast);
1864
1865         ao2_lock(session);
1866
1867         if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1868                 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1869                 const char *reason = "success";
1870                 int i;
1871
1872                 /* Get the appropriate reason and send a session-terminate */
1873                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1874                         if (jingle_reason_mappings[i].cause == cause) {
1875                                 reason = jingle_reason_mappings[i].reason;
1876                                 break;
1877                         }
1878                 }
1879
1880                 jingle_send_session_terminate(session, reason);
1881         }
1882
1883         ast_channel_tech_pvt_set(ast, NULL);
1884         jingle_set_owner(session, NULL);
1885
1886         ao2_unlink(session->state->sessions, session);
1887         ao2_ref(session->state, -1);
1888
1889         ao2_unlock(session);
1890         ao2_ref(session, -1);
1891
1892         return 0;
1893 }
1894
1895 /*! \brief Function called by core to create a new outgoing Jingle session */
1896 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
1897 {
1898         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1899         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1900         char *dialed, target[200] = "";
1901         struct ast_xmpp_buddy *buddy;
1902         struct jingle_session *session;
1903         struct ast_channel *chan;
1904         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1905         struct ast_rtp_engine_ice *ice;
1906         AST_DECLARE_APP_ARGS(args,
1907                              AST_APP_ARG(name);
1908                              AST_APP_ARG(target);
1909                 );
1910
1911         /* We require at a minimum one audio format to be requested */
1912         if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
1913                 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1914                 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1915                 return NULL;
1916         }
1917
1918         if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1919                 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1920                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1921                 return NULL;
1922         }
1923
1924         /* Parse the given dial string and validate the results */
1925         AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1926
1927         if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1928                 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1929                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1930                 return NULL;
1931         }
1932
1933         if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1934                 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1935                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1936                 return NULL;
1937         }
1938
1939         ao2_lock(endpoint->state);
1940
1941         /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1942         if (!endpoint->connection) {
1943                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1944                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1945                 ao2_unlock(endpoint->state);
1946                 return NULL;
1947         }
1948
1949         /* Find the target in the roster so we can choose a resource */
1950         if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1951                 struct ao2_iterator res;
1952                 struct ast_xmpp_resource *resource;
1953
1954                 /* Iterate through finding the first viable Jingle capable resource */
1955                 res = ao2_iterator_init(buddy->resources, 0);
1956                 while ((resource = ao2_iterator_next(&res))) {
1957                         if (resource->caps.jingle) {
1958                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1959                                 transport = JINGLE_TRANSPORT_ICE_UDP;
1960                                 break;
1961                         } else if (resource->caps.google) {
1962                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1963                                 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1964                                 break;
1965                         }
1966                         ao2_ref(resource, -1);
1967                 }
1968                 ao2_iterator_destroy(&res);
1969
1970                 ao2_ref(buddy, -1);
1971         } else {
1972                 /* If the target is NOT in the roster use the provided target as-is */
1973                 ast_copy_string(target, args.target, sizeof(target));
1974         }
1975
1976         ao2_unlock(endpoint->state);
1977
1978         /* If no target was found we can't set up a session */
1979         if (ast_strlen_zero(target)) {
1980                 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);
1981                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1982                 return NULL;
1983         }
1984
1985         if (!(session = jingle_alloc(endpoint, target, NULL))) {
1986                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1987                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1988                 return NULL;
1989         }
1990
1991         /* Update the transport if we learned what we should actually use */
1992         if (transport != JINGLE_TRANSPORT_NONE) {
1993                 session->transport = transport;
1994                 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
1995         }
1996
1997         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
1998                 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
1999                 *cause = AST_CAUSE_SWITCH_CONGESTION;
2000                 ao2_ref(session, -1);
2001                 return NULL;
2002         }
2003
2004         /* If video was requested try to enable it on the session */
2005         if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
2006                 jingle_enable_video(session);
2007         }
2008
2009         /* As this is outgoing set ourselves as controlling */
2010         if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
2011                 ice->ice_lite(session->rtp);
2012         }
2013
2014         if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
2015                 ice->ice_lite(session->vrtp);
2016         }
2017
2018         /* We purposely don't decrement the session here as there is a reference on the channel */
2019         ao2_link(endpoint->state->sessions, session);
2020
2021         return chan;
2022 }
2023
2024 /*! \brief Helper function which handles content descriptions */
2025 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2026 {
2027         char *media = iks_find_attrib(description, "media");
2028         struct ast_rtp_codecs codecs;
2029         iks *codec;
2030         int othercapability = 0;
2031
2032         /* Google-V1 is always carrying audio, but just doesn't tell us so */
2033         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2034                 media = "audio";
2035         } else if (ast_strlen_zero(media)) {
2036                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2037                 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2038                 return -1;
2039         }
2040
2041         /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2042         if (!strcasecmp(media, "audio")) {
2043                 if (!ast_strlen_zero(name)) {
2044                         ast_string_field_set(session, audio_name, name);
2045                 }
2046                 *rtp = session->rtp;
2047                 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
2048                 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
2049         } else if (!strcasecmp(media, "video")) {
2050                 if (!ast_strlen_zero(name)) {
2051                         ast_string_field_set(session, video_name, name);
2052                 }
2053
2054                 jingle_enable_video(session);
2055                 *rtp = session->vrtp;
2056
2057                 /* If video is not present cancel this session */
2058                 if (!session->vrtp) {
2059                         jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2060                         ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2061                         return -1;
2062                 }
2063
2064                 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
2065                 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
2066         } else {
2067                 /* Unknown media type */
2068                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2069                 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2070                 return -1;
2071         }
2072
2073         if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2074                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2075                 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2076                 return -1;
2077         }
2078
2079         /* Iterate the codecs updating the relevant RTP instance as we go */
2080         for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2081                 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
2082                 char *clockrate = iks_find_attrib(codec, "clockrate");
2083                 int rtp_id, rtp_clockrate;
2084
2085                 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2086                         ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
2087
2088                         if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2089                                 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2090                         } else {
2091                                 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2092                         }
2093                 }
2094         }
2095
2096         ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2097         ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
2098
2099         if (ast_format_cap_is_empty(session->jointcap)) {
2100                 /* We have no compatible codecs, so terminate the session appropriately */
2101                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2102                 ast_rtp_codecs_payloads_destroy(&codecs);
2103                 return -1;
2104         }
2105
2106         ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2107         ast_rtp_codecs_payloads_destroy(&codecs);
2108
2109         return 0;
2110 }
2111
2112 /*! \brief Helper function which handles ICE-UDP transport information */
2113 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2114 {
2115         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2116         char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2117         iks *candidate;
2118
2119         if (!ice) {
2120                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2121                 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2122                 return -1;
2123         }
2124
2125         if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2126                 ice->set_authentication(rtp, ufrag, pwd);
2127         }
2128
2129         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2130                 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2131                 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2132                 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2133                 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2134                 char *type = iks_find_attrib(candidate, "type");
2135                 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2136                 int real_port;
2137                 struct ast_sockaddr remote_address = { { 0, } };
2138
2139                 /* If this candidate is incomplete skip it */
2140                 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2141                     ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2142                     ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2143                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2144                         ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2145                         return -1;
2146                 }
2147
2148                 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2149                     (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
2150                     (sscanf(port, "%30d", &real_port) != 1)) {
2151                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2152                         ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2153                         return -1;
2154                 }
2155
2156                 local_candidate.foundation = foundation;
2157                 local_candidate.transport = protocol;
2158
2159                 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2160
2161                 /* We only support IPv4 right now */
2162                 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2163                         continue;
2164                 }
2165
2166                 ast_sockaddr_set_port(&local_candidate.address, real_port);
2167
2168                 if (!strcasecmp(type, "host")) {
2169                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2170                 } else if (!strcasecmp(type, "srflx")) {
2171                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2172                 } else if (!strcasecmp(type, "relay")) {
2173                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2174                 } else {
2175                         continue;
2176                 }
2177
2178                 /* Worst case use the first viable address */
2179                 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2180
2181                 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2182                         ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2183                 }
2184
2185                 ice->add_remote_candidate(rtp, &local_candidate);
2186         }
2187
2188         ice->start(rtp);
2189
2190         return 0;
2191 }
2192
2193 /*! \brief Helper function which handles Google transport information */
2194 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2195 {
2196         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2197         iks *candidate;
2198
2199         if (!ice) {
2200                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2201                 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2202                 return -1;
2203         }
2204
2205         /* If this session has not transitioned to the Google transport do so now */
2206         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2207             (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2208                 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2209                 ice->stop(rtp);
2210
2211                 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2212         }
2213
2214         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2215                 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2216                 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2217                 char *protocol = iks_find_attrib(candidate, "protocol");
2218                 int real_port;
2219                 struct ast_sockaddr target = { { 0, } };
2220                 /* In Google land the combined value is 32 bytes */
2221                 char combined[33] = "";
2222
2223                 /* If this is NOT actually a candidate just skip it */
2224                 if (strcasecmp(iks_name(candidate), "candidate") &&
2225                     strcasecmp(iks_name(candidate), "p:candidate") &&
2226                     strcasecmp(iks_name(candidate), "ses:candidate")) {
2227                         continue;
2228                 }
2229
2230                 /* If this candidate is incomplete skip it */
2231                 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2232                     ast_strlen_zero(name)) {
2233                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2234                         ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2235                         return -1;
2236                 }
2237
2238                 /* We only support UDP so skip any other protocols */
2239                 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2240                         continue;
2241                 }
2242
2243                 /* We only permit audio and video, not RTCP */
2244                 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2245                         continue;
2246                 }
2247
2248                 /* Parse the target information so we can send a STUN request to the candidate */
2249                 if (sscanf(port, "%30d", &real_port) != 1) {
2250                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2251                         ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2252                         return -1;
2253                 }
2254                 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2255                 ast_sockaddr_set_port(&target, real_port);
2256
2257                 /* Per the STUN support Google talk uses combine the two usernames */
2258                 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2259
2260                 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2261                 ast_rtp_instance_stun_request(rtp, &target, combined);
2262         }
2263
2264         return 0;
2265 }
2266
2267 /*!
2268  * \brief Helper function which locates content stanzas and interprets them
2269  *
2270  * \note The session *must not* be locked before calling this
2271  */
2272 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2273 {
2274         iks *content;
2275         unsigned int changed = 0;
2276         struct ast_channel *chan;
2277
2278         /* Look at the content in the session initiation */
2279         for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2280                 char *name;
2281                 struct ast_rtp_instance *rtp = NULL;
2282                 iks *description, *transport;
2283
2284                 /* Ignore specific parts if they are known not to be useful */
2285                 if (!strcmp(iks_name(content), "conference-info")) {
2286                         continue;
2287                 }
2288
2289                 name = iks_find_attrib(content, "name");
2290
2291                 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2292                         /* If this content stanza has no name consider it invalid and move on */
2293                         if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2294                                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2295                                 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2296                                 return -1;
2297                         }
2298
2299                         /* Try to pre-populate which RTP instance this content is relevant to */
2300                         if (!strcmp(session->audio_name, name)) {
2301                                 rtp = session->rtp;
2302                         } else if (!strcmp(session->video_name, name)) {
2303                                 rtp = session->vrtp;
2304                         }
2305                 } else {
2306                         /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2307                         rtp = session->rtp;
2308                 }
2309
2310                 /* If description information is available use it */
2311                 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2312                     (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2313                     (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2314                     (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2315                     (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2316                     (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2317                         /* If we failed to do something with the content description abort immediately */
2318                         if (jingle_interpret_description(session, description, name, &rtp)) {
2319                                 return -1;
2320                         }
2321
2322                         /* If we successfully interpret the description then the codecs need updating */
2323                         changed = 1;
2324                 }
2325
2326                 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2327                 if (!rtp) {
2328                         ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2329                         jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2330                         return -1;
2331                 }
2332
2333                 /* If ICE UDP transport information is available use it */
2334                 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2335                         if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2336                                 return -1;
2337                         }
2338                 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2339                            (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2340                            (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2341                            (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2342                         /* If Google transport support is available use it */
2343                         if (jingle_interpret_google_transport(session, transport, rtp)) {
2344                                 return -1;
2345                         }
2346                 } else if (iks_find(content, "transport")) {
2347                         /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2348                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2349                         ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2350                         return -1;
2351                 }
2352         }
2353
2354         if (!changed) {
2355                 return 0;
2356         }
2357
2358         if ((chan = jingle_session_lock_full(session))) {
2359                 struct ast_format fmt;
2360
2361                 ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
2362                 ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
2363                 ast_set_read_format(chan, &fmt);
2364                 ast_set_write_format(chan, &fmt);
2365
2366                 ast_channel_unlock(chan);
2367                 ast_channel_unref(chan);
2368         }
2369         ao2_unlock(session);
2370
2371         return 0;
2372 }
2373
2374 /*! \brief Handler function for the 'session-initiate' action */
2375 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2376 {
2377         char *sid;
2378         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2379         struct ast_channel *chan;
2380         int res;
2381
2382         if (session) {
2383                 /* This is a duplicate session setup, so respond accordingly */
2384                 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2385                 return;
2386         }
2387
2388         /* Retrieve the session identifier from the message, note that this may alter the transport */
2389         if ((sid = iks_find_attrib(pak->query, "id"))) {
2390                 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2391                 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2392         } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2393                 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2394                 return;
2395         }
2396
2397         /* Create a new local session */
2398         if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2399                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2400                 return;
2401         }
2402
2403         /* If we determined that the transport should change as a result of how we got the SID change it */
2404         if (transport != JINGLE_TRANSPORT_NONE) {
2405                 session->transport = transport;
2406         }
2407
2408         /* Create a new Asterisk channel using the above local session */
2409         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
2410                 ao2_ref(session, -1);
2411                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2412                 return;
2413         }
2414
2415         ao2_link(endpoint->state->sessions, session);
2416
2417         ast_channel_lock(chan);
2418         ast_setstate(chan, AST_STATE_RING);
2419         ast_channel_unlock(chan);
2420         res = ast_pbx_start(chan);
2421
2422         switch (res) {
2423         case AST_PBX_FAILED:
2424                 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2425                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2426                 session->gone = 1;
2427                 ast_hangup(chan);
2428                 break;
2429         case AST_PBX_CALL_LIMIT:
2430                 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2431                 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2432                 ast_hangup(chan);
2433                 break;
2434         case AST_PBX_SUCCESS:
2435                 jingle_send_response(endpoint->connection, pak);
2436
2437                 /* Only send a transport-info message if we successfully interpreted the available content */
2438                 if (!jingle_interpret_content(session, pak)) {
2439                         jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2440                 }
2441                 break;
2442         }
2443 }
2444
2445 /*! \brief Handler function for the 'transport-info' action */
2446 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2447 {
2448         if (!session) {
2449                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2450                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2451                 return;
2452         }
2453
2454         jingle_interpret_content(session, pak);
2455         jingle_send_response(endpoint->connection, pak);
2456 }
2457
2458 /*! \brief Handler function for the 'session-accept' action */
2459 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2460 {
2461         struct ast_channel *chan;
2462
2463         if (!session) {
2464                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2465                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2466                 return;
2467         }
2468
2469
2470         jingle_interpret_content(session, pak);
2471
2472         if ((chan = jingle_session_lock_full(session))) {
2473                 ast_queue_control(chan, AST_CONTROL_ANSWER);
2474                 ast_channel_unlock(chan);
2475                 ast_channel_unref(chan);
2476         }
2477         ao2_unlock(session);
2478
2479         jingle_send_response(endpoint->connection, pak);
2480 }
2481
2482 /*! \brief Handler function for the 'session-info' action */
2483 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2484 {
2485         struct ast_channel *chan;
2486
2487         if (!session) {
2488                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2489                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2490                 return;
2491         }
2492
2493         if (!(chan = jingle_session_lock_full(session))) {
2494                 ao2_unlock(session);
2495                 jingle_send_response(endpoint->connection, pak);
2496                 return;
2497         }
2498
2499         if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2500                 ast_queue_control(chan, AST_CONTROL_RINGING);
2501                 if (ast_channel_state(chan) != AST_STATE_UP) {
2502                         ast_setstate(chan, AST_STATE_RINGING);
2503                 }
2504         } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2505                 ast_queue_hold(chan, NULL);
2506         } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2507                 ast_queue_unhold(chan);
2508         }
2509
2510         ast_channel_unlock(chan);
2511         ast_channel_unref(chan);
2512         ao2_unlock(session);
2513
2514         jingle_send_response(endpoint->connection, pak);
2515 }
2516
2517 /*! \brief Handler function for the 'session-terminate' action */
2518 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2519 {
2520         struct ast_channel *chan;
2521         iks *reason, *text;
2522         int cause = AST_CAUSE_NORMAL;
2523         struct ast_control_pvt_cause_code *cause_code;
2524         int data_size = sizeof(*cause_code);
2525
2526         if (!session) {
2527                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2528                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2529                 return;
2530         }
2531
2532         if (!(chan = jingle_session_lock_full(session))) {
2533                 ao2_unlock(session);
2534                 jingle_send_response(endpoint->connection, pak);
2535                 return;
2536         }
2537
2538         /* Pull the reason text from the session-terminate message and translate it into a cause code */
2539         if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2540                 int i;
2541
2542                 /* Size of the string making up the cause code is "Motif " + text */
2543                 data_size += 6 + strlen(iks_name(text));
2544                 cause_code = ast_alloca(data_size);
2545                 memset(cause_code, 0, data_size);
2546
2547                 /* Get the appropriate cause code mapping for this reason */
2548                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2549                         if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2550                                 cause = jingle_reason_mappings[i].cause;
2551                                 break;
2552                         }
2553                 }
2554
2555                 /* Store the technology specific information */
2556                 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2557         } else {
2558                 /* No technology specific information is available */
2559                 cause_code = ast_alloca(data_size);
2560                 memset(cause_code, 0, data_size);
2561         }
2562
2563         ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2564         cause_code->ast_cause = cause;
2565         ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2566         ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2567
2568         ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2569         ast_queue_hangup_with_cause(chan, cause);
2570         session->gone = 1;
2571
2572         ast_channel_unlock(chan);
2573         ast_channel_unref(chan);
2574         ao2_unlock(session);
2575
2576         jingle_send_response(endpoint->connection, pak);
2577 }
2578
2579 /*! \brief Callback for when a Jingle action is received from an endpoint */
2580 static int jingle_action_hook(void *data, ikspak *pak)
2581 {
2582         char *action;
2583         const char *sid = NULL;
2584         struct jingle_session *session = NULL;
2585         struct jingle_endpoint *endpoint = data;
2586         int i, handled = 0;
2587
2588         /* We accept both Jingle and Google-V1 */
2589         if (!(action = iks_find_attrib(pak->query, "action")) &&
2590             !(action = iks_find_attrib(pak->query, "type"))) {
2591                 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2592                  * to a message that has no response hook. */
2593                 return IKS_FILTER_EAT;
2594         }
2595
2596         /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2597          * does not permit us to make this completely safe. */
2598         ao2_ref(endpoint, +1);
2599
2600         /* If a Jingle session identifier is present use it */
2601         if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2602                 /* If a Google-V1 session identifier is present use it */
2603                 sid = iks_find_attrib(pak->query, "id");
2604         }
2605
2606         /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2607          * this is required or not */
2608         if (!ast_strlen_zero(sid)) {
2609                 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2610         }
2611
2612         /* If a session is present associate the callid with this thread */
2613         if (session) {
2614                 ast_callid_threadassoc_add(session->callid);
2615         }
2616
2617         /* Iterate through supported action handlers looking for one that is able to handle this */
2618         for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2619                 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2620                         jingle_action_handlers[i].handler(endpoint, session, pak);
2621                         handled = 1;
2622                         break;
2623                 }
2624         }
2625
2626         /* If no action handler is present for the action they sent us make it evident */
2627         if (!handled) {
2628                 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2629         }
2630
2631         /* If a session was successfully found for this message deref it now since the handler is done */
2632         if (session) {
2633                 ast_callid_threadassoc_remove();
2634                 ao2_ref(session, -1);
2635         }
2636
2637         ao2_ref(endpoint, -1);
2638
2639         return IKS_FILTER_EAT;
2640 }
2641
2642 /*! \brief Custom handler for groups */
2643 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2644 {
2645         struct jingle_endpoint *endpoint = obj;
2646
2647         if (!strcasecmp(var->name, "callgroup")) {
2648                 endpoint->callgroup = ast_get_group(var->value);
2649         } else if (!strcasecmp(var->name, "pickupgroup")) {
2650                 endpoint->pickupgroup = ast_get_group(var->value);
2651         } else {
2652                 return -1;
2653         }
2654
2655         return 0;
2656 }
2657
2658 /*! \brief Custom handler for connection */
2659 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2660 {
2661         struct jingle_endpoint *endpoint = obj;
2662
2663         /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2664          * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2665          */
2666         if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2667                 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2668                 return -1;
2669         }
2670
2671         if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2672                                                    IKS_RULE_TYPE, IKS_PAK_IQ,
2673                                                    IKS_RULE_NS, JINGLE_NS,
2674                                                    IKS_RULE_NS, GOOGLE_SESSION_NS,
2675                                                    IKS_RULE_DONE))) {
2676                 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2677                 return -1;
2678         }
2679
2680         return 0;
2681 }
2682
2683 /*! \brief Custom handler for transport */
2684 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2685 {
2686         struct jingle_endpoint *endpoint = obj;
2687
2688         if (!strcasecmp(var->value, "ice-udp")) {
2689                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2690         } else if (!strcasecmp(var->value, "google")) {
2691                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2692         } else if (!strcasecmp(var->value, "google-v1")) {
2693                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2694         } else {
2695                 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2696                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2697         }
2698
2699         return 0;
2700 }
2701
2702 /*!
2703  * \brief Load the module
2704  *
2705  * Module loading including tests for configuration or dependencies.
2706  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2707  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2708  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
2709  * configuration file or other non-critical problem return 
2710  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2711  */
2712 static int load_module(void)
2713 {
2714         if (!(jingle_tech.capabilities = ast_format_cap_alloc(0))) {
2715                 return AST_MODULE_LOAD_DECLINE;
2716         }
2717
2718         if (aco_info_init(&cfg_info)) {
2719                 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2720                 goto end;
2721         }
2722
2723         aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2724         aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2725         aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2726         aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2727         aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2728         aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2729         aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2730         aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
2731         aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
2732         aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2733         aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2734         aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2735                             FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2736         aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2737                             FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2738
2739         ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
2740
2741         if (aco_process_config(&cfg_info, 0)) {
2742                 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2743                 aco_info_destroy(&cfg_info);
2744                 return AST_MODULE_LOAD_DECLINE;
2745         }
2746
2747         if (!(sched = ast_sched_context_create())) {
2748                 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2749                 goto end;
2750         }
2751
2752         if (ast_sched_start_thread(sched)) {
2753                 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2754                 goto end;
2755         }
2756
2757         ast_rtp_glue_register(&jingle_rtp_glue);
2758
2759         if (ast_channel_register(&jingle_tech)) {
2760                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2761                 goto end;
2762         }
2763
2764         return 0;
2765
2766 end:
2767         ast_rtp_glue_unregister(&jingle_rtp_glue);
2768
2769         if (sched) {
2770                 ast_sched_context_destroy(sched);
2771         }
2772
2773         aco_info_destroy(&cfg_info);
2774
2775         return AST_MODULE_LOAD_FAILURE;
2776 }
2777
2778 /*! \brief Reload module */
2779 static int reload(void)
2780 {
2781         return aco_process_config(&cfg_info, 1);
2782 }
2783
2784 /*! \brief Unload the jingle channel from Asterisk */
2785 static int unload_module(void)
2786 {
2787         ast_channel_unregister(&jingle_tech);
2788         ast_format_cap_destroy(jingle_tech.capabilities);
2789         jingle_tech.capabilities = NULL;
2790         ast_rtp_glue_unregister(&jingle_rtp_glue);
2791         ast_sched_context_destroy(sched);
2792         aco_info_destroy(&cfg_info);
2793         ao2_global_obj_release(globals);
2794
2795         return 0;
2796 }
2797
2798 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2799                 .load = load_module,
2800                 .unload = unload_module,
2801                 .reload = reload,
2802                 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2803                );