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