df1eeb8cefbe8988a90e2b5289d88b94ea60ddd8
[asterisk/asterisk.git] / channels / chan_motif.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \author Joshua Colp <jcolp@digium.com>
22  *
23  * \brief Motif Jingle Channel Driver
24  *
25  * Iksemel http://iksemel.jabberstudio.org/
26  *
27  * \ingroup channel_drivers
28  */
29
30 /*! \li \ref chan_motif.c uses the configuration file \ref motif.conf
31  * \addtogroup configuration_file
32  */
33
34 /*! \page motif.conf motif.conf
35  * \verbinclude motif.conf.sample
36  */
37
38 /*** MODULEINFO
39         <depend>iksemel</depend>
40         <depend>res_xmpp</depend>
41         <use type="external">openssl</use>
42         <support_level>core</support_level>
43  ***/
44
45 #include "asterisk.h"
46
47 #include <sys/socket.h>
48 #include <fcntl.h>
49 #include <netdb.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <signal.h>
53 #include <iksemel.h>
54 #include <pthread.h>
55
56 #include "asterisk/lock.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/config_options.h"
59 #include "asterisk/module.h"
60 #include "asterisk/pbx.h"
61 #include "asterisk/sched.h"
62 #include "asterisk/io.h"
63 #include "asterisk/rtp_engine.h"
64 #include "asterisk/acl.h"
65 #include "asterisk/callerid.h"
66 #include "asterisk/file.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/app.h"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/manager.h"
71 #include "asterisk/stringfields.h"
72 #include "asterisk/utils.h"
73 #include "asterisk/causes.h"
74 #include "asterisk/abstract_jb.h"
75 #include "asterisk/xmpp.h"
76 #include "asterisk/endpoints.h"
77 #include "asterisk/stasis_channels.h"
78 #include "asterisk/format_cache.h"
79
80 /*** DOCUMENTATION
81         <configInfo name="chan_motif" language="en_US">
82                 <synopsis>Jingle Channel Driver</synopsis>
83                 <description>
84                         <para><emphasis>Transports</emphasis></para>
85                         <para>There are three different transports and protocol derivatives
86                         supported by <literal>chan_motif</literal>. They are in order of
87                         preference: Jingle using ICE-UDP, Google Jingle, and Google-V1.</para>
88                         <para>Jingle as defined in XEP-0166 supports the widest range of
89                         features. It is referred to as <literal>ice-udp</literal>. This is
90                         the specification that Jingle clients implement.</para>
91                         <para>Google Jingle follows the Jingle specification for signaling
92                         but uses a custom transport for media. It is supported by the
93                         Google Talk Plug-in in Gmail and by some other Jingle clients. It
94                         is referred to as <literal>google</literal> in this file.</para>
95                         <para>Google-V1 is the original Google Talk signaling protocol
96                         which uses an initial preliminary version of Jingle. It also uses
97                         the same custom transport as Google Jingle for media. It is
98                         supported by Google Voice, some other Jingle clients, and the
99                         Windows Google Talk client. It is referred to as <literal>google-v1</literal>
100                         in this file.</para>
101                         <para>Incoming sessions will automatically switch to the correct
102                         transport once it has been determined.</para>
103                         <para>Outgoing sessions are capable of determining if the target
104                         is capable of Jingle or a Google transport if the target is in the
105                         roster. Unfortunately it is not possible to differentiate between
106                         a Google Jingle or Google-V1 capable resource until a session
107                         initiate attempt occurs. If a resource is determined to use a
108                         Google transport it will initially use Google Jingle but will fall
109                         back to Google-V1 if required.</para>
110                         <para>If an outgoing session attempt fails due to failure to
111                         support the given transport <literal>chan_motif</literal> will
112                         fall back in preference order listed previously until all
113                         transports have been exhausted.</para>
114                         <para><emphasis>Dialing and Resource Selection Strategy</emphasis></para>
115                         <para>Placing a call through an endpoint can be accomplished using the
116                         following dial string:</para>
117                         <para><literal>Motif/[endpoint name]/[target]</literal></para>
118                         <para>When placing an outgoing call through an endpoint the requested
119                         target is searched for in the roster list. If present the first Jingle
120                         or Google Jingle capable resource is specifically targeted. Since the
121                         capabilities of the resource are known the outgoing session initiation
122                         will disregard the configured transport and use the determined one.</para>
123                         <para>If the target is not found in the roster the target will be used
124                         as-is and a session will be initiated using the transport specified
125                         in this configuration file. If no transport has been specified the
126                         endpoint defaults to <literal>ice-udp</literal>.</para>
127                         <para><emphasis>Video Support</emphasis></para>
128                         <para>Support for video does not need to be explicitly enabled.
129                         Configuring any video codec on your endpoint will automatically enable
130                         it.</para>
131                         <para><emphasis>DTMF</emphasis></para>
132                         <para>The only supported method for DTMF is RFC2833. This is always
133                         enabled on audio streams and negotiated if possible.</para>
134                         <para><emphasis>Incoming Calls</emphasis></para>
135                         <para>Incoming calls will first look for the extension matching the
136                         name of the endpoint in the configured context. If no such extension
137                         exists the call will automatically fall back to the <literal>s</literal> extension.</para>
138                         <para><emphasis>CallerID</emphasis></para>
139                         <para>The incoming caller id number is populated with the username of
140                         the caller and the name is populated with the full identity of the
141                         caller. If you would like to perform authentication or filtering
142                         of incoming calls it is recommended that you use these fields to do so.</para>
143                         <para>Outgoing caller id can <emphasis>not</emphasis> be set.</para>
144                         <warning>
145                                 <para>Multiple endpoints using the
146                                 same connection is <emphasis>NOT</emphasis> supported. Doing so
147                                 may result in broken calls.</para>
148                         </warning>
149                 </description>
150                 <configFile name="motif.conf">
151                         <configObject name="endpoint">
152                                 <synopsis>The configuration for an endpoint.</synopsis>
153                                 <configOption name="context">
154                                         <synopsis>Default dialplan context that incoming sessions will be routed to</synopsis>
155                                 </configOption>
156                                 <configOption name="callgroup">
157                                         <synopsis>A callgroup to assign to this endpoint.</synopsis>
158                                 </configOption>
159                                 <configOption name="pickupgroup">
160                                         <synopsis>A pickup group to assign to this endpoint.</synopsis>
161                                 </configOption>
162                                 <configOption name="language">
163                                         <synopsis>The default language for this endpoint.</synopsis>
164                                 </configOption>
165                                 <configOption name="musicclass">
166                                         <synopsis>Default music on hold class for this endpoint.</synopsis>
167                                 </configOption>
168                                 <configOption name="parkinglot">
169                                         <synopsis>Default parking lot for this endpoint.</synopsis>
170                                 </configOption>
171                                 <configOption name="accountcode">
172                                         <synopsis>Accout code for CDR purposes</synopsis>
173                                 </configOption>
174                                 <configOption name="allow">
175                                         <synopsis>Codecs to allow</synopsis>
176                                 </configOption>
177                                 <configOption name="disallow">
178                                         <synopsis>Codecs to disallow</synopsis>
179                                 </configOption>
180                                 <configOption name="connection">
181                                         <synopsis>Connection to accept traffic on and on which to send traffic out</synopsis>
182                                 </configOption>
183                                 <configOption name="transport">
184                                         <synopsis>The transport to use for the endpoint.</synopsis>
185                                         <description>
186                                                 <para>The default outbound transport for this endpoint. Inbound
187                                                 messages are inferred. Allowed transports are <literal>ice-udp</literal>,
188                                                 <literal>google</literal>, or <literal>google-v1</literal>. Note
189                                                 that <literal>chan_motif</literal> will fall back to transport
190                                                 preference order if the transport value chosen here fails.</para>
191                                                 <enumlist>
192                                                         <enum name="ice-udp">
193                                                                 <para>The Jingle protocol, as defined in XEP 0166.</para>
194                                                         </enum>
195                                                         <enum name="google">
196                                                                 <para>The Google Jingle protocol, which follows the Jingle
197                                                                 specification for signaling but uses a custom transport for
198                                                                 media.</para>
199                                                         </enum>
200                                                         <enum name="google-v1">
201                                                                 <para>Google-V1 is the original Google Talk signaling
202                                                                 protocol which uses an initial preliminary version of Jingle.
203                                                                 It also uses the same custom transport as <literal>google</literal> for media.</para>
204                                                         </enum>
205                                                 </enumlist>
206                                         </description>
207                                 </configOption>
208                                 <configOption name="maxicecandidates">
209                                         <synopsis>Maximum number of ICE candidates to offer</synopsis>
210                                 </configOption>
211                                 <configOption name="maxpayloads">
212                                         <synopsis>Maximum number of pyaloads to offer</synopsis>
213                                 </configOption>
214                         </configObject>
215                 </configFile>
216         </configInfo>
217 ***/
218
219 /*! \brief Default maximum number of ICE candidates we will offer */
220 #define DEFAULT_MAX_ICE_CANDIDATES "10"
221
222 /*! \brief Default maximum number of payloads we will offer */
223 #define DEFAULT_MAX_PAYLOADS "30"
224
225 /*! \brief Number of buckets for endpoints */
226 #define ENDPOINT_BUCKETS 37
227
228 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
229 #define SESSION_BUCKETS 37
230
231 /*! \brief Namespace for Jingle itself */
232 #define JINGLE_NS "urn:xmpp:jingle:1"
233
234 /*! \brief Namespace for Jingle RTP sessions */
235 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
236
237 /*! \brief Namespace for Jingle RTP info */
238 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
239
240 /*! \brief Namespace for Jingle ICE-UDP */
241 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
242
243 /*! \brief Namespace for Google Talk ICE-UDP */
244 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
245
246 /*! \brief Namespace for Google Talk Raw UDP */
247 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
248
249 /*! \brief Namespace for Google Session */
250 #define GOOGLE_SESSION_NS "http://www.google.com/session"
251
252 /*! \brief Namespace for Google Phone description */
253 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
254
255 /*! \brief Namespace for Google Video description */
256 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
257
258 /*! \brief Namespace for XMPP stanzas */
259 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
260
261 /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */
262 enum jingle_transport {
263         JINGLE_TRANSPORT_ICE_UDP = 3,   /*!< XEP-0176 */
264         JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
265         JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
266         JINGLE_TRANSPORT_NONE = 0,      /*!< No transport specified */
267 };
268
269 /*! \brief Endpoint state information */
270 struct jingle_endpoint_state {
271         struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
272 };
273
274 /*! \brief Endpoint which contains configuration information and active sessions */
275 struct jingle_endpoint {
276         AST_DECLARE_STRING_FIELDS(
277                 AST_STRING_FIELD(name);              /*!< Name of the endpoint */
278                 AST_STRING_FIELD(context);           /*!< Context to place incoming calls into */
279                 AST_STRING_FIELD(accountcode);       /*!< Account code */
280                 AST_STRING_FIELD(language);          /*!< Default language for prompts */
281                 AST_STRING_FIELD(musicclass);        /*!< Configured music on hold class */
282                 AST_STRING_FIELD(parkinglot);        /*!< Configured parking lot */
283                 );
284         struct ast_xmpp_client *connection;     /*!< Connection to use for traffic */
285         iksrule *rule;                          /*!< Active matching rule */
286         unsigned int maxicecandidates;          /*!< Maximum number of ICE candidates we will offer */
287         unsigned int maxpayloads;               /*!< Maximum number of payloads we will offer */
288         struct ast_format_cap *cap;             /*!< Formats to use */
289         ast_group_t callgroup;                  /*!< Call group */
290         ast_group_t pickupgroup;                /*!< Pickup group */
291         enum jingle_transport transport;        /*!< Default transport to use on outgoing sessions */
292         struct jingle_endpoint_state *state;    /*!< Endpoint state information */
293 };
294
295 /*! \brief Session which contains information about an active session */
296 struct jingle_session {
297         AST_DECLARE_STRING_FIELDS(
298                 AST_STRING_FIELD(sid);        /*!< Session identifier */
299                 AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
300                 AST_STRING_FIELD(video_name); /*!< Name of the video content */
301                 );
302         struct jingle_endpoint_state *state;  /*!< Endpoint we are associated with */
303         struct ast_xmpp_client *connection;   /*!< Connection to use for traffic */
304         enum jingle_transport transport;      /*!< Transport type to use for this session */
305         unsigned int maxicecandidates;        /*!< Maximum number of ICE candidates we will offer */
306         unsigned int maxpayloads;             /*!< Maximum number of payloads we will offer */
307         char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
308         char remote[XMPP_MAX_JIDLEN];         /*!< Identifier of the remote party */
309         iksrule *rule;                        /*!< Session matching rule */
310         struct ast_channel *owner;            /*!< Master Channel */
311         struct ast_rtp_instance *rtp;         /*!< RTP audio session */
312         struct ast_rtp_instance *vrtp;        /*!< RTP video session */
313         struct ast_format_cap *cap;           /*!< Local codec capabilities */
314         struct ast_format_cap *jointcap;      /*!< Joint codec capabilities */
315         struct ast_format_cap *peercap;       /*!< Peer codec capabilities */
316         unsigned int outgoing:1;              /*!< Whether this is an outgoing leg or not */
317         unsigned int gone:1;                  /*!< In the eyes of Jingle this session is already gone */
318         ast_callid callid;                    /*!< Bound session call-id */
319 };
320
321 static const char channel_type[] = "Motif";
322
323 struct jingle_config {
324         struct ao2_container *endpoints; /*!< Configured endpoints */
325 };
326
327 static AO2_GLOBAL_OBJ_STATIC(globals);
328
329 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
330
331 /* \brief Asterisk core interaction functions */
332 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
333 static int jingle_sendtext(struct ast_channel *ast, const char *text);
334 static int jingle_digit_begin(struct ast_channel *ast, char digit);
335 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
336 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
337 static int jingle_hangup(struct ast_channel *ast);
338 static int jingle_answer(struct ast_channel *ast);
339 static struct ast_frame *jingle_read(struct ast_channel *ast);
340 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
341 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
342 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
343 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
344
345 /*! \brief Action handlers */
346 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
347 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
348 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
349 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
350 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
351
352 /*! \brief PBX interface structure for channel registration */
353 static struct ast_channel_tech jingle_tech = {
354         .type = "Motif",
355         .description = "Motif Jingle Channel Driver",
356         .requester = jingle_request,
357         .send_text = jingle_sendtext,
358         .send_digit_begin = jingle_digit_begin,
359         .send_digit_end = jingle_digit_end,
360         .call = jingle_call,
361         .hangup = jingle_hangup,
362         .answer = jingle_answer,
363         .read = jingle_read,
364         .write = jingle_write,
365         .write_video = jingle_write,
366         .exception = jingle_read,
367         .indicate = jingle_indicate,
368         .fixup = jingle_fixup,
369         .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
370 };
371
372 /*! \brief Defined handlers for different Jingle actions */
373 static const struct jingle_action_handler {
374         const char *action;
375         void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
376 } jingle_action_handlers[] = {
377         /* Jingle actions */
378         { "session-initiate", jingle_action_session_initiate, },
379         { "transport-info", jingle_action_transport_info, },
380         { "session-accept", jingle_action_session_accept, },
381         { "session-info", jingle_action_session_info, },
382         { "session-terminate", jingle_action_session_terminate, },
383         /* Google-V1 actions */
384         { "initiate", jingle_action_session_initiate, },
385         { "candidates", jingle_action_transport_info, },
386         { "accept", jingle_action_session_accept, },
387         { "terminate", jingle_action_session_terminate, },
388         { "reject", jingle_action_session_terminate, },
389 };
390
391 /*! \brief Reason text <-> cause code mapping */
392 static const struct jingle_reason_mapping {
393         const char *reason;
394         int cause;
395 } jingle_reason_mappings[] = {
396         { "busy", AST_CAUSE_BUSY, },
397         { "cancel", AST_CAUSE_CALL_REJECTED, },
398         { "connectivity-error", AST_CAUSE_INTERWORKING, },
399         { "decline", AST_CAUSE_CALL_REJECTED, },
400         { "expired", AST_CAUSE_NO_USER_RESPONSE, },
401         { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
402         { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
403         { "general-error", AST_CAUSE_CONGESTION, },
404         { "gone", AST_CAUSE_NORMAL_CLEARING, },
405         { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
406         { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
407         { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
408         { "success", AST_CAUSE_NORMAL_CLEARING, },
409         { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
410         { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
411         { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
412 };
413
414 /*! \brief Hashing function for Jingle sessions */
415 static int jingle_session_hash(const void *obj, const int flags)
416 {
417         const struct jingle_session *session = obj;
418         const char *sid = obj;
419
420         return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
421 }
422
423 /*! \brief Comparator function for Jingle sessions */
424 static int jingle_session_cmp(void *obj, void *arg, int flags)
425 {
426         struct jingle_session *session1 = obj, *session2 = arg;
427         const char *sid = arg;
428
429         return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
430 }
431
432 /*! \brief Destructor for Jingle endpoint state */
433 static void jingle_endpoint_state_destructor(void *obj)
434 {
435         struct jingle_endpoint_state *state = obj;
436
437         ao2_ref(state->sessions, -1);
438 }
439
440 /*! \brief Destructor for Jingle endpoints */
441 static void jingle_endpoint_destructor(void *obj)
442 {
443         struct jingle_endpoint *endpoint = obj;
444
445         if (endpoint->rule) {
446                 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
447         }
448
449         if (endpoint->connection) {
450                 ast_xmpp_client_unref(endpoint->connection);
451         }
452
453         ao2_cleanup(endpoint->cap);
454         ao2_ref(endpoint->state, -1);
455
456         ast_string_field_free_memory(endpoint);
457 }
458
459 /*! \brief Find function for Jingle endpoints */
460 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
461 {
462         return ao2_find(tmp_container, category, OBJ_KEY);
463 }
464
465 /*! \brief Allocator function for Jingle endpoint state */
466 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
467 {
468         struct jingle_endpoint_state *state;
469
470         if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
471                 return NULL;
472         }
473
474         if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
475                 ao2_ref(state, -1);
476                 return NULL;
477         }
478
479         return state;
480 }
481
482 /*! \brief State find/create function */
483 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
484 {
485         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
486         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
487
488         if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
489                 return jingle_endpoint_state_create();
490         }
491
492         ao2_ref(endpoint->state, +1);
493         return endpoint->state;
494 }
495
496 /*! \brief Allocator function for Jingle endpoints */
497 static void *jingle_endpoint_alloc(const char *cat)
498 {
499         struct jingle_endpoint *endpoint;
500
501         if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
502                 return NULL;
503         }
504
505         if (ast_string_field_init(endpoint, 512)) {
506                 ao2_ref(endpoint, -1);
507                 return NULL;
508         }
509
510         if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
511                 ao2_ref(endpoint, -1);
512                 return NULL;
513         }
514
515         ast_string_field_set(endpoint, name, cat);
516
517         endpoint->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
518         endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
519
520         return endpoint;
521 }
522
523 /*! \brief Hashing function for Jingle endpoints */
524 static int jingle_endpoint_hash(const void *obj, const int flags)
525 {
526         const struct jingle_endpoint *endpoint = obj;
527         const char *name = obj;
528
529         return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
530 }
531
532 /*! \brief Comparator function for Jingle endpoints */
533 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
534 {
535         struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
536         const char *name = arg;
537
538         return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
539 }
540
541 static struct aco_type endpoint_option = {
542         .type = ACO_ITEM,
543         .name = "endpoint",
544         .category_match = ACO_BLACKLIST_EXACT,
545         .category = "general",
546         .item_alloc = jingle_endpoint_alloc,
547         .item_find = jingle_endpoint_find,
548         .item_offset = offsetof(struct jingle_config, endpoints),
549 };
550
551 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
552
553 struct aco_file jingle_conf = {
554         .filename = "motif.conf",
555         .types = ACO_TYPES(&endpoint_option),
556 };
557
558 /*! \brief Destructor for Jingle sessions */
559 static void jingle_session_destructor(void *obj)
560 {
561         struct jingle_session *session = obj;
562
563         if (session->rule) {
564                 iks_filter_remove_rule(session->connection->filter, session->rule);
565         }
566
567         if (session->connection) {
568                 ast_xmpp_client_unref(session->connection);
569         }
570
571         if (session->rtp) {
572                 ast_rtp_instance_stop(session->rtp);
573                 ast_rtp_instance_destroy(session->rtp);
574         }
575
576         if (session->vrtp) {
577                 ast_rtp_instance_stop(session->vrtp);
578                 ast_rtp_instance_destroy(session->vrtp);
579         }
580
581         ao2_cleanup(session->cap);
582         ao2_cleanup(session->jointcap);
583         ao2_cleanup(session->peercap);
584
585         ast_string_field_free_memory(session);
586 }
587
588 /*! \brief Destructor called when module configuration goes away */
589 static void jingle_config_destructor(void *obj)
590 {
591         struct jingle_config *cfg = obj;
592         ao2_cleanup(cfg->endpoints);
593 }
594
595 /*! \brief Allocator called when module configuration should appear */
596 static void *jingle_config_alloc(void)
597 {
598         struct jingle_config *cfg;
599
600         if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
601                 return NULL;
602         }
603
604         if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
605                 ao2_ref(cfg, -1);
606                 return NULL;
607         }
608
609         return cfg;
610 }
611
612 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
613                      .files = ACO_FILES(&jingle_conf),
614         );
615
616 /*! \brief Function called by RTP engine to get local RTP peer */
617 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
618 {
619         struct jingle_session *session = ast_channel_tech_pvt(chan);
620         enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
621
622         if (!session->rtp) {
623                 return AST_RTP_GLUE_RESULT_FORBID;
624         }
625
626         ao2_ref(session->rtp, +1);
627         *instance = session->rtp;
628
629         return res;
630 }
631
632 /*! \brief Function called by RTP engine to get peer capabilities */
633 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
634 {
635 }
636
637 /*! \brief Function called by RTP engine to change where the remote party should send media */
638 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)
639 {
640         return -1;
641 }
642
643 /*! \brief Local glue for interacting with the RTP engine core */
644 static struct ast_rtp_glue jingle_rtp_glue = {
645         .type = "Motif",
646         .get_rtp_info = jingle_get_rtp_peer,
647         .get_codec = jingle_get_codec,
648         .update_peer = jingle_set_rtp_peer,
649 };
650
651 /*! \brief Set the channel owner on the \ref jingle_session object and related objects */
652 static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
653 {
654         session->owner = chan;
655         if (session->rtp) {
656                 ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
657         }
658         if (session->vrtp) {
659                 ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
660         }
661 }
662
663 /*! \brief Internal helper function which enables video support on a sesson if possible */
664 static void jingle_enable_video(struct jingle_session *session)
665 {
666         struct ast_sockaddr tmp;
667         struct ast_rtp_engine_ice *ice;
668
669         /* If video is already present don't do anything */
670         if (session->vrtp) {
671                 return;
672         }
673
674         /* If there are no configured video codecs do not turn video support on, it just won't work */
675         if (!ast_format_cap_has_type(session->cap, AST_MEDIA_TYPE_VIDEO)) {
676                 return;
677         }
678
679         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
680
681         if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
682                 return;
683         }
684
685         ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
686         ast_rtp_instance_set_channel_id(session->vrtp, ast_channel_uniqueid(session->owner));
687         ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
688         ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
689         ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->vrtp),
690                 ast_format_cap_get_framing(session->cap));
691         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
692                 ice->stop(session->vrtp);
693         }
694 }
695
696 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
697 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
698 {
699         struct jingle_session *session;
700         ast_callid callid;
701         struct ast_sockaddr tmp;
702
703         if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
704                 return NULL;
705         }
706
707         callid = ast_read_threadstorage_callid();
708         session->callid = (callid ? callid : ast_create_callid());
709
710         if (ast_string_field_init(session, 512)) {
711                 ao2_ref(session, -1);
712                 return NULL;
713         }
714
715         if (!ast_strlen_zero(from)) {
716                 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
717                 ast_copy_string(session->remote, from, sizeof(session->remote));
718         }
719
720         if (ast_strlen_zero(sid)) {
721                 ast_string_field_build(session, sid, "%08lx%08lx", (unsigned long)ast_random(), (unsigned long)ast_random());
722                 session->outgoing = 1;
723                 ast_string_field_set(session, audio_name, "audio");
724                 ast_string_field_set(session, video_name, "video");
725         } else {
726                 ast_string_field_set(session, sid, sid);
727         }
728
729         ao2_ref(endpoint->state, +1);
730         session->state = endpoint->state;
731         ao2_ref(endpoint->connection, +1);
732         session->connection = endpoint->connection;
733         session->transport = endpoint->transport;
734
735         if (!(session->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
736             !(session->jointcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
737             !(session->peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
738             !session->callid) {
739                 ao2_ref(session, -1);
740                 return NULL;
741         }
742
743         ast_format_cap_append_from_cap(session->cap, endpoint->cap, AST_MEDIA_TYPE_UNKNOWN);
744
745         /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
746          * that we want IPv4 */
747         ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
748
749         /* Sessions always carry audio, but video is optional so don't enable it here */
750         if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
751                 ao2_ref(session, -1);
752                 return NULL;
753         }
754         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
755         ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
756
757         session->maxicecandidates = endpoint->maxicecandidates;
758         session->maxpayloads = endpoint->maxpayloads;
759
760         return session;
761 }
762
763 /*! \brief Function called to create a new Jingle Asterisk channel */
764 static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name)
765 {
766         struct ast_channel *chan;
767         const char *str = S_OR(title, session->remote);
768         struct ast_format_cap *caps;
769         struct ast_format *tmpfmt;
770
771         if (!ast_format_cap_count(session->cap)) {
772                 return NULL;
773         }
774
775         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
776         if (!caps) {
777                 return NULL;
778         }
779
780         if (!(chan = ast_channel_alloc_with_endpoint(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", assignedids, requestor, 0, endpoint->connection->endpoint, "Motif/%s-%04lx", str, (unsigned long)(ast_random() & 0xffff)))) {
781                 ao2_ref(caps, -1);
782                 return NULL;
783         }
784
785         ast_channel_stage_snapshot(chan);
786
787         ast_channel_tech_set(chan, &jingle_tech);
788         ast_channel_tech_pvt_set(chan, session);
789         jingle_set_owner(session, chan);
790
791         ast_channel_callid_set(chan, session->callid);
792
793         ast_format_cap_append_from_cap(caps, session->cap, AST_MEDIA_TYPE_UNKNOWN);
794         ast_channel_nativeformats_set(chan, caps);
795         ao2_ref(caps, -1);
796
797         if (session->rtp) {
798                 struct ast_rtp_engine_ice *ice;
799
800                 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
801                 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
802                 ast_rtp_codecs_set_framing(ast_rtp_instance_get_codecs(session->rtp),
803                         ast_format_cap_get_framing(session->cap));
804
805                 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
806                      (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
807                     (ice = ast_rtp_instance_get_ice(session->rtp))) {
808                         /* We stop built in ICE support because we need to fall back to old old old STUN support */
809                         ice->stop(session->rtp);
810                 }
811         }
812
813         if (state == AST_STATE_RING) {
814                 ast_channel_rings_set(chan, 1);
815         }
816
817         ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
818
819         tmpfmt = ast_format_cap_get_format(session->cap, 0);
820         ast_channel_set_writeformat(chan, tmpfmt);
821         ast_channel_set_rawwriteformat(chan, tmpfmt);
822         ast_channel_set_readformat(chan, tmpfmt);
823         ast_channel_set_rawreadformat(chan, tmpfmt);
824         ao2_ref(tmpfmt, -1);
825
826         ao2_lock(endpoint);
827
828         ast_channel_callgroup_set(chan, endpoint->callgroup);
829         ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
830
831         if (!ast_strlen_zero(endpoint->accountcode)) {
832                 ast_channel_accountcode_set(chan, endpoint->accountcode);
833         }
834
835         if (!ast_strlen_zero(endpoint->language)) {
836                 ast_channel_language_set(chan, endpoint->language);
837         }
838
839         if (!ast_strlen_zero(endpoint->musicclass)) {
840                 ast_channel_musicclass_set(chan, endpoint->musicclass);
841         }
842
843         ast_channel_context_set(chan, endpoint->context);
844         if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
845                 ast_channel_exten_set(chan, endpoint->name);
846         } else {
847                 ast_channel_exten_set(chan, "s");
848         }
849         ast_channel_priority_set(chan, 1);
850
851         ao2_unlock(endpoint);
852
853         ast_channel_stage_snapshot_done(chan);
854         ast_channel_unlock(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), "%u", 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", (unsigned long)(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_media_type type)
1303 {
1304         int x = 0, i = 0, res = 0;
1305
1306         for (x = 0; (x < ast_format_cap_count(session->jointcap)) && (i < (session->maxpayloads - 2)); x++) {
1307                 struct ast_format *format = ast_format_cap_get_format(session->jointcap, x);
1308                 int rtp_code;
1309                 iks *payload;
1310                 char tmp[32];
1311
1312                 if (ast_format_get_type(format) != type) {
1313                         ao2_ref(format, -1);
1314                         continue;
1315                 }
1316
1317                 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, format, 0)) == -1) ||
1318                     (!(payload = iks_new("payload-type")))) {
1319                         ao2_ref(format, -1);
1320                         return -1;
1321                 }
1322
1323                 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1324                         iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1325                 }
1326
1327                 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1328                 iks_insert_attrib(payload, "id", tmp);
1329                 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
1330                 iks_insert_attrib(payload, "channels", "1");
1331
1332                 if ((ast_format_cmp(format, ast_format_g722) == AST_FORMAT_CMP_EQUAL) &&
1333                         ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1334                         iks_insert_attrib(payload, "clockrate", "16000");
1335                 } else {
1336                         snprintf(tmp, sizeof(tmp), "%u", ast_rtp_lookup_sample_rate2(1, format, 0));
1337                         iks_insert_attrib(payload, "clockrate", tmp);
1338                 }
1339
1340                 if ((type == AST_MEDIA_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1341                         iks *parameter;
1342
1343                         /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1344                         if ((parameter = iks_new("parameter"))) {
1345                                 iks_insert_attrib(parameter, "name", "width");
1346                                 iks_insert_attrib(parameter, "value", "640");
1347                                 iks_insert_node(payload, parameter);
1348                         }
1349                         if ((parameter = iks_new("parameter"))) {
1350                                 iks_insert_attrib(parameter, "name", "height");
1351                                 iks_insert_attrib(parameter, "value", "480");
1352                                 iks_insert_node(payload, parameter);
1353                         }
1354                         if ((parameter = iks_new("parameter"))) {
1355                                 iks_insert_attrib(parameter, "name", "framerate");
1356                                 iks_insert_attrib(parameter, "value", "30");
1357                                 iks_insert_node(payload, parameter);
1358                         }
1359                 }
1360
1361                 iks_insert_node(description, payload);
1362                 payloads[i++] = payload;
1363
1364                 ao2_ref(format, -1);
1365         }
1366         /* If this is for audio and there is room for RFC2833 add it in */
1367         if ((type == AST_MEDIA_TYPE_AUDIO) && (i < session->maxpayloads)) {
1368                 iks *payload;
1369
1370                 if ((payload = iks_new("payload-type"))) {
1371                         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1372                                 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1373                         }
1374
1375                         iks_insert_attrib(payload, "id", "101");
1376                         iks_insert_attrib(payload, "name", "telephone-event");
1377                         iks_insert_attrib(payload, "channels", "1");
1378                         iks_insert_attrib(payload, "clockrate", "8000");
1379                         iks_insert_node(description, payload);
1380                         payloads[i++] = payload;
1381                 }
1382         }
1383
1384         return res;
1385 }
1386
1387 /*! \brief Helper function which adds content to a description */
1388 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1389                               const char *name, enum ast_media_type type, struct ast_rtp_instance *rtp, iks **payloads)
1390 {
1391         int res = 0;
1392
1393         if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1394                 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1395                 iks_insert_attrib(content, "name", name);
1396                 iks_insert_node(jingle, content);
1397
1398                 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1399                 if (type == AST_MEDIA_TYPE_AUDIO) {
1400                         iks_insert_attrib(description, "media", "audio");
1401                 } else if (type == AST_MEDIA_TYPE_VIDEO) {
1402                         iks_insert_attrib(description, "media", "video");
1403                 } else {
1404                         return -1;
1405                 }
1406                 iks_insert_node(content, description);
1407         } else {
1408                 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1409                 iks_insert_node(jingle, description);
1410         }
1411
1412         if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1413                 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1414                         iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1415                         iks_insert_node(content, transport);
1416                 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1417                         iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1418                         iks_insert_node(content, transport);
1419                 }
1420         }
1421
1422         return res;
1423 }
1424
1425 /*! \brief Internal function which sends a complete session message */
1426 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1427 {
1428         iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1429         iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1430         iks *audio_transport = NULL, *video_transport = NULL;
1431         int i, res = 0;
1432
1433         if (!(iq = iks_new("iq")) ||
1434             !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1435                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1436                 iks_delete(iq);
1437                 return;
1438         }
1439
1440         memset(audio_payloads, 0, sizeof(audio_payloads));
1441         memset(video_payloads, 0, sizeof(video_payloads));
1442
1443         iks_insert_attrib(iq, "from", session->connection->jid->full);
1444         iks_insert_attrib(iq, "to", session->remote);
1445         iks_insert_attrib(iq, "type", "set");
1446         iks_insert_attrib(iq, "id", session->connection->mid);
1447         ast_xmpp_increment_mid(session->connection->mid);
1448
1449         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1450                 iks_insert_attrib(jingle, "type", action);
1451                 iks_insert_attrib(jingle, "id", session->sid);
1452                 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1453         } else {
1454                 iks_insert_attrib(jingle, "action", action);
1455                 iks_insert_attrib(jingle, "sid", session->sid);
1456                 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1457         }
1458
1459         if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1460                 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1461         }
1462
1463         iks_insert_node(iq, jingle);
1464
1465         if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1466             (audio_transport = iks_new("transport"))) {
1467                 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1468                                          AST_MEDIA_TYPE_AUDIO, session->rtp, audio_payloads);
1469         } else {
1470                 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1471                 res = -1;
1472         }
1473
1474         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1475                 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1476                     (video_transport = iks_new("transport"))) {
1477                         res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1478                                                  AST_MEDIA_TYPE_VIDEO, session->vrtp, video_payloads);
1479                 } else {
1480                         ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1481                         res = -1;
1482                 }
1483         }
1484
1485         if (!res) {
1486                 ast_xmpp_client_send(session->connection, iq);
1487         } else {
1488                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1489         }
1490
1491         iks_delete(video_transport);
1492         iks_delete(audio_transport);
1493
1494         for (i = 0; i < session->maxpayloads; i++) {
1495                 iks_delete(video_payloads[i]);
1496                 iks_delete(audio_payloads[i]);
1497         }
1498
1499         iks_delete(video_description);
1500         iks_delete(video);
1501         iks_delete(audio_description);
1502         iks_delete(audio);
1503         iks_delete(jingle);
1504         iks_delete(iq);
1505 }
1506
1507 /*! \brief Internal function which sends a session-inititate message */
1508 static void jingle_send_session_initiate(struct jingle_session *session)
1509 {
1510         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1511 }
1512
1513 /*! \brief Internal function which sends a session-accept message */
1514 static void jingle_send_session_accept(struct jingle_session *session)
1515 {
1516         jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1517 }
1518
1519 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1520 static int jingle_outgoing_hook(void *data, ikspak *pak)
1521 {
1522         struct jingle_session *session = data;
1523         iks *error = iks_find(pak->x, "error"), *redirect;
1524
1525         /* In all cases this hook is done with */
1526         iks_filter_remove_rule(session->connection->filter, session->rule);
1527         session->rule = NULL;
1528
1529         ast_callid_threadassoc_add(session->callid);
1530
1531         /* If no error occurred they accepted our session-initiate message happily */
1532         if (!error) {
1533                 struct ast_channel *chan;
1534
1535                 if ((chan = jingle_session_lock_full(session))) {
1536                         ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1537                         ast_channel_unlock(chan);
1538                         ast_channel_unref(chan);
1539                 }
1540                 ao2_unlock(session);
1541
1542                 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1543
1544                 goto end;
1545         }
1546
1547         /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1548         session->gone = 1;
1549
1550         /* Map the error we received to an appropriate cause code and hang up the channel */
1551         if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1552                 iks *to = iks_child(redirect);
1553                 char *target;
1554
1555                 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1556                         /* Make the xmpp: go away if it is present */
1557                         if (!strncmp(target, "xmpp:", 5)) {
1558                                 target += 5;
1559                         }
1560
1561                         /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1562                         ast_copy_string(session->remote, target, sizeof(session->remote));
1563
1564                         /* Add a new hook so we can get the status of redirected session */
1565                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1566                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1567
1568                         jingle_send_session_initiate(session);
1569
1570                         session->gone = 0;
1571                 } else {
1572                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1573                 }
1574         } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1575                 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1576         } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1577                 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1578         } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1579                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1580         } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1581                 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1582         } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1583                 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1584                 session->transport--;
1585
1586                 /* If we still have a viable transport mechanism re-send the session-initiate */
1587                 if (session->transport != JINGLE_TRANSPORT_NONE) {
1588                         struct ast_rtp_engine_ice *ice;
1589
1590                         if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1591                              (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1592                             (ice = ast_rtp_instance_get_ice(session->rtp))) {
1593                                 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1594                                 ice->stop(session->rtp);
1595                         }
1596
1597                         /* Re-send the message to the *original* target and not a redirected one */
1598                         ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1599
1600                         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1601                                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1602
1603                         jingle_send_session_initiate(session);
1604
1605                         session->gone = 0;
1606                 } else {
1607                         /* Otherwise we have exhausted all transports */
1608                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1609                 }
1610         } else {
1611                 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1612         }
1613
1614 end:
1615         ast_callid_threadassoc_remove();
1616
1617         return IKS_FILTER_EAT;
1618 }
1619
1620 /*! \brief Function called by core when we should answer a Jingle session */
1621 static int jingle_answer(struct ast_channel *ast)
1622 {
1623         struct jingle_session *session = ast_channel_tech_pvt(ast);
1624
1625         /* The channel has already been answered so we don't need to do anything */
1626         if (ast_channel_state(ast) == AST_STATE_UP) {
1627                 return 0;
1628         }
1629
1630         jingle_send_session_accept(session);
1631
1632         return 0;
1633 }
1634
1635 /*! \brief Function called by core to read any waiting frames */
1636 static struct ast_frame *jingle_read(struct ast_channel *ast)
1637 {
1638         struct jingle_session *session = ast_channel_tech_pvt(ast);
1639         struct ast_frame *frame = &ast_null_frame;
1640
1641         switch (ast_channel_fdno(ast)) {
1642         case 0:
1643                 if (session->rtp) {
1644                         frame = ast_rtp_instance_read(session->rtp, 0);
1645                 }
1646                 break;
1647         case 1:
1648                 if (session->rtp) {
1649                         frame = ast_rtp_instance_read(session->rtp, 1);
1650                 }
1651                 break;
1652         case 2:
1653                 if (session->vrtp) {
1654                         frame = ast_rtp_instance_read(session->vrtp, 0);
1655                 }
1656                 break;
1657         case 3:
1658                 if (session->vrtp) {
1659                         frame = ast_rtp_instance_read(session->vrtp, 1);
1660                 }
1661                 break;
1662         default:
1663                 break;
1664         }
1665
1666         if (frame && frame->frametype == AST_FRAME_VOICE &&
1667             ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1668                 if (ast_format_cap_iscompatible_format(session->jointcap, frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1669                         ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1670                                   ast_format_get_name(frame->subclass.format), ast_channel_name(ast));
1671                         ast_frfree(frame);
1672                         frame = &ast_null_frame;
1673                 } else {
1674                         struct ast_format_cap *caps;
1675
1676                         ast_debug(1, "Oooh, format changed to %s\n",
1677                                   ast_format_get_name(frame->subclass.format));
1678
1679                         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1680                         if (caps) {
1681                                 ast_format_cap_append(caps, frame->subclass.format, 0);
1682                                 ast_channel_nativeformats_set(ast, caps);
1683                                 ao2_ref(caps, -1);
1684                         }
1685                         ast_set_read_format(ast, ast_channel_readformat(ast));
1686                         ast_set_write_format(ast, ast_channel_writeformat(ast));
1687                 }
1688         }
1689
1690         return frame;
1691 }
1692
1693 /*! \brief Function called by core to write frames */
1694 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1695 {
1696         struct jingle_session *session = ast_channel_tech_pvt(ast);
1697         int res = 0;
1698
1699         switch (frame->frametype) {
1700         case AST_FRAME_VOICE:
1701                 if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
1702                         struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1703
1704                         ast_log(LOG_WARNING,
1705                                 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1706                                 ast_format_get_name(frame->subclass.format),
1707                                 ast_format_cap_get_names(ast_channel_nativeformats(ast), &codec_buf),
1708                                 ast_format_get_name(ast_channel_readformat(ast)),
1709                                 ast_format_get_name(ast_channel_writeformat(ast)));
1710                         return 0;
1711                 }
1712                 if (session && session->rtp) {
1713                         res = ast_rtp_instance_write(session->rtp, frame);
1714                 }
1715                 break;
1716         case AST_FRAME_VIDEO:
1717                 if (session && session->vrtp) {
1718                         res = ast_rtp_instance_write(session->vrtp, frame);
1719                 }
1720                 break;
1721         default:
1722                 ast_log(LOG_WARNING, "Can't send %u type frames with Jingle write\n",
1723                         frame->frametype);
1724                 return 0;
1725         }
1726
1727         return res;
1728 }
1729
1730 /*! \brief Function called by core to change the underlying owner channel */
1731 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1732 {
1733         struct jingle_session *session = ast_channel_tech_pvt(newchan);
1734
1735         ao2_lock(session);
1736
1737         jingle_set_owner(session, newchan);
1738
1739         ao2_unlock(session);
1740
1741         return 0;
1742 }
1743
1744 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1745 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1746 {
1747         struct jingle_session *session = ast_channel_tech_pvt(ast);
1748         int res = 0;
1749
1750         switch (condition) {
1751         case AST_CONTROL_RINGING:
1752                 if (ast_channel_state(ast) == AST_STATE_RING) {
1753                         jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1754                 } else {
1755                         res = -1;
1756                 }
1757                 break;
1758         case AST_CONTROL_BUSY:
1759                 if (ast_channel_state(ast) != AST_STATE_UP) {
1760                         ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1761                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1762                 } else {
1763                         res = -1;
1764                 }
1765                 break;
1766         case AST_CONTROL_CONGESTION:
1767                 if (ast_channel_state(ast) != AST_STATE_UP) {
1768                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1769                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1770                 } else {
1771                         res = -1;
1772                 }
1773                 break;
1774         case AST_CONTROL_INCOMPLETE:
1775                 if (ast_channel_state(ast) != AST_STATE_UP) {
1776                         ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1777                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1778                 }
1779                 break;
1780         case AST_CONTROL_HOLD:
1781                 ast_moh_start(ast, data, NULL);
1782                 break;
1783         case AST_CONTROL_UNHOLD:
1784                 ast_moh_stop(ast);
1785                 break;
1786         case AST_CONTROL_SRCUPDATE:
1787                 if (session->rtp) {
1788                         ast_rtp_instance_update_source(session->rtp);
1789                 }
1790                 break;
1791         case AST_CONTROL_SRCCHANGE:
1792                 if (session->rtp) {
1793                         ast_rtp_instance_change_source(session->rtp);
1794                 }
1795                 break;
1796         case AST_CONTROL_VIDUPDATE:
1797         case AST_CONTROL_UPDATE_RTP_PEER:
1798         case AST_CONTROL_CONNECTED_LINE:
1799                 break;
1800         case AST_CONTROL_PVT_CAUSE_CODE:
1801         case AST_CONTROL_MASQUERADE_NOTIFY:
1802         case -1:
1803                 res = -1;
1804                 break;
1805         default:
1806                 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1807                 res = -1;
1808         }
1809
1810         return res;
1811 }
1812
1813 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1814 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1815 {
1816         struct jingle_session *session = ast_channel_tech_pvt(chan);
1817
1818         return ast_xmpp_client_send_message(session->connection, session->remote, text);
1819 }
1820
1821 /*! \brief Function called by core to start a DTMF digit */
1822 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1823 {
1824         struct jingle_session *session = ast_channel_tech_pvt(chan);
1825
1826         if (session->rtp) {
1827                 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1828         }
1829
1830         return 0;
1831 }
1832
1833 /*! \brief Function called by core to stop a DTMF digit */
1834 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1835 {
1836         struct jingle_session *session = ast_channel_tech_pvt(ast);
1837
1838         if (session->rtp) {
1839                 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1840         }
1841
1842         return 0;
1843 }
1844
1845 /*! \brief Function called by core to actually start calling a remote party */
1846 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1847 {
1848         struct jingle_session *session = ast_channel_tech_pvt(ast);
1849
1850         ast_setstate(ast, AST_STATE_RING);
1851
1852         /* Since we have no idea of the remote capabilities use ours for now */
1853         ast_format_cap_append_from_cap(session->jointcap, session->cap, AST_MEDIA_TYPE_UNKNOWN);
1854
1855         /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1856         session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1857                                             IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1858
1859         jingle_send_session_initiate(session);
1860
1861         return 0;
1862 }
1863
1864 /*! \brief Function called by core to hang up a Jingle session */
1865 static int jingle_hangup(struct ast_channel *ast)
1866 {
1867         struct jingle_session *session = ast_channel_tech_pvt(ast);
1868
1869         ao2_lock(session);
1870
1871         if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1872                 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1873                 const char *reason = "success";
1874                 int i;
1875
1876                 /* Get the appropriate reason and send a session-terminate */
1877                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1878                         if (jingle_reason_mappings[i].cause == cause) {
1879                                 reason = jingle_reason_mappings[i].reason;
1880                                 break;
1881                         }
1882                 }
1883
1884                 jingle_send_session_terminate(session, reason);
1885         }
1886
1887         ast_channel_tech_pvt_set(ast, NULL);
1888         jingle_set_owner(session, NULL);
1889
1890         ao2_unlink(session->state->sessions, session);
1891         ao2_ref(session->state, -1);
1892
1893         ao2_unlock(session);
1894         ao2_ref(session, -1);
1895
1896         return 0;
1897 }
1898
1899 /*! \brief Function called by core to create a new outgoing Jingle session */
1900 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
1901 {
1902         RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1903         RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1904         char *dialed, target[1024] = "";
1905         struct ast_xmpp_buddy *buddy;
1906         struct jingle_session *session;
1907         struct ast_channel *chan;
1908         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1909         struct ast_rtp_engine_ice *ice;
1910         AST_DECLARE_APP_ARGS(args,
1911                              AST_APP_ARG(name);
1912                              AST_APP_ARG(target);
1913                 );
1914
1915         /* We require at a minimum one audio format to be requested */
1916         if (!ast_format_cap_has_type(cap, AST_MEDIA_TYPE_AUDIO)) {
1917                 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1918                 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1919                 return NULL;
1920         }
1921
1922         if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1923                 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1924                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1925                 return NULL;
1926         }
1927
1928         /* Parse the given dial string and validate the results */
1929         AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1930
1931         if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1932                 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1933                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1934                 return NULL;
1935         }
1936
1937         if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1938                 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1939                 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1940                 return NULL;
1941         }
1942
1943         ao2_lock(endpoint->state);
1944
1945         /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1946         if (!endpoint->connection) {
1947                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1948                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1949                 ao2_unlock(endpoint->state);
1950                 return NULL;
1951         }
1952
1953         /* Find the target in the roster so we can choose a resource */
1954         if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1955                 struct ao2_iterator res;
1956                 struct ast_xmpp_resource *resource;
1957
1958                 /* Iterate through finding the first viable Jingle capable resource */
1959                 res = ao2_iterator_init(buddy->resources, 0);
1960                 while ((resource = ao2_iterator_next(&res))) {
1961                         if (resource->caps.jingle) {
1962                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1963                                 transport = JINGLE_TRANSPORT_ICE_UDP;
1964                                 break;
1965                         } else if (resource->caps.google) {
1966                                 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1967                                 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1968                                 break;
1969                         }
1970                         ao2_ref(resource, -1);
1971                 }
1972                 ao2_iterator_destroy(&res);
1973
1974                 ao2_ref(buddy, -1);
1975         } else {
1976                 /* If the target is NOT in the roster use the provided target as-is */
1977                 ast_copy_string(target, args.target, sizeof(target));
1978         }
1979
1980         ao2_unlock(endpoint->state);
1981
1982         /* If no target was found we can't set up a session */
1983         if (ast_strlen_zero(target)) {
1984                 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);
1985                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1986                 return NULL;
1987         }
1988
1989         if (!(session = jingle_alloc(endpoint, target, NULL))) {
1990                 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1991                 *cause = AST_CAUSE_SWITCH_CONGESTION;
1992                 return NULL;
1993         }
1994
1995         /* Update the transport if we learned what we should actually use */
1996         if (transport != JINGLE_TRANSPORT_NONE) {
1997                 session->transport = transport;
1998                 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
1999         }
2000
2001         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, assignedids, requestor, NULL))) {
2002                 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
2003                 *cause = AST_CAUSE_SWITCH_CONGESTION;
2004                 ao2_ref(session, -1);
2005                 return NULL;
2006         }
2007
2008         /* If video was requested try to enable it on the session */
2009         if (ast_format_cap_has_type(cap, AST_MEDIA_TYPE_VIDEO)) {
2010                 jingle_enable_video(session);
2011         }
2012
2013         /* As this is outgoing set ourselves as controlling */
2014         if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
2015                 ice->ice_lite(session->rtp);
2016         }
2017
2018         if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
2019                 ice->ice_lite(session->vrtp);
2020         }
2021
2022         /* We purposely don't decrement the session here as there is a reference on the channel */
2023         ao2_link(endpoint->state->sessions, session);
2024
2025         return chan;
2026 }
2027
2028 /*! \brief Helper function which handles content descriptions */
2029 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
2030 {
2031         char *media = iks_find_attrib(description, "media");
2032         struct ast_rtp_codecs codecs;
2033         iks *codec;
2034         int othercapability = 0;
2035
2036         /* Google-V1 is always carrying audio, but just doesn't tell us so */
2037         if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
2038                 media = "audio";
2039         } else if (ast_strlen_zero(media)) {
2040                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2041                 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
2042                 return -1;
2043         }
2044
2045         /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
2046         if (!strcasecmp(media, "audio")) {
2047                 if (!ast_strlen_zero(name)) {
2048                         ast_string_field_set(session, audio_name, name);
2049                 }
2050                 *rtp = session->rtp;
2051                 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_AUDIO);
2052                 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_AUDIO);
2053         } else if (!strcasecmp(media, "video")) {
2054                 if (!ast_strlen_zero(name)) {
2055                         ast_string_field_set(session, video_name, name);
2056                 }
2057
2058                 jingle_enable_video(session);
2059                 *rtp = session->vrtp;
2060
2061                 /* If video is not present cancel this session */
2062                 if (!session->vrtp) {
2063                         jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2064                         ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
2065                         return -1;
2066                 }
2067
2068                 ast_format_cap_remove_by_type(session->peercap, AST_MEDIA_TYPE_VIDEO);
2069                 ast_format_cap_remove_by_type(session->jointcap, AST_MEDIA_TYPE_VIDEO);
2070         } else {
2071                 /* Unknown media type */
2072                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2073                 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
2074                 return -1;
2075         }
2076
2077         if (ast_rtp_codecs_payloads_initialize(&codecs)) {
2078                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2079                 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
2080                 return -1;
2081         }
2082
2083         /* Iterate the codecs updating the relevant RTP instance as we go */
2084         for (codec = iks_child(description); codec; codec = iks_next(codec)) {
2085                 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
2086                 char *clockrate = iks_find_attrib(codec, "clockrate");
2087                 int rtp_id, rtp_clockrate;
2088
2089                 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
2090                         if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
2091                                 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
2092                         } else {
2093                                 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
2094                         }
2095                 }
2096         }
2097
2098         ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
2099         ast_format_cap_get_compatible(session->cap, session->peercap, session->jointcap);
2100
2101         if (!ast_format_cap_count(session->jointcap)) {
2102                 /* We have no compatible codecs, so terminate the session appropriately */
2103                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2104                 ast_rtp_codecs_payloads_destroy(&codecs);
2105                 return -1;
2106         }
2107
2108         ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
2109         ast_rtp_codecs_payloads_destroy(&codecs);
2110
2111         return 0;
2112 }
2113
2114 /*! \brief Helper function which handles ICE-UDP transport information */
2115 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2116 {
2117         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2118         char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2119         iks *candidate;
2120
2121         if (!ice) {
2122                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2123                 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2124                 return -1;
2125         }
2126
2127         if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2128                 ice->set_authentication(rtp, ufrag, pwd);
2129         }
2130
2131         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2132                 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2133                 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2134                 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2135                 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2136                 char *type = iks_find_attrib(candidate, "type");
2137                 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2138                 int real_port;
2139                 struct ast_sockaddr remote_address = { { 0, } };
2140
2141                 /* If this candidate is incomplete skip it */
2142                 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2143                     ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2144                     ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
2145                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2146                         ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
2147                         return -1;
2148                 }
2149
2150                 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
2151                     (sscanf(priority, "%30u", (unsigned *)&local_candidate.priority) != 1) ||
2152                     (sscanf(port, "%30d", &real_port) != 1)) {
2153                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2154                         ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
2155                         return -1;
2156                 }
2157
2158                 local_candidate.foundation = foundation;
2159                 local_candidate.transport = protocol;
2160
2161                 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2162
2163                 /* We only support IPv4 right now */
2164                 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2165                         continue;
2166                 }
2167
2168                 ast_sockaddr_set_port(&local_candidate.address, real_port);
2169
2170                 if (!strcasecmp(type, "host")) {
2171                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2172                 } else if (!strcasecmp(type, "srflx")) {
2173                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2174                 } else if (!strcasecmp(type, "relay")) {
2175                         local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2176                 } else {
2177                         continue;
2178                 }
2179
2180                 /* Worst case use the first viable address */
2181                 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2182
2183                 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2184                         ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2185                 }
2186
2187                 ice->add_remote_candidate(rtp, &local_candidate);
2188         }
2189
2190         ice->start(rtp);
2191
2192         return 0;
2193 }
2194
2195 /*! \brief Helper function which handles Google transport information */
2196 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2197 {
2198         struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2199         iks *candidate;
2200
2201         if (!ice) {
2202                 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2203                 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2204                 return -1;
2205         }
2206
2207         /* If this session has not transitioned to the Google transport do so now */
2208         if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2209             (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2210                 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2211                 ice->stop(rtp);
2212
2213                 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2214         }
2215
2216         for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2217                 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2218                 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2219                 char *protocol = iks_find_attrib(candidate, "protocol");
2220                 int real_port;
2221                 struct ast_sockaddr target = { { 0, } };
2222                 /* In Google land the combined value is 32 bytes */
2223                 char combined[33] = "";
2224
2225                 /* If this is NOT actually a candidate just skip it */
2226                 if (strcasecmp(iks_name(candidate), "candidate") &&
2227                     strcasecmp(iks_name(candidate), "p:candidate") &&
2228                     strcasecmp(iks_name(candidate), "ses:candidate")) {
2229                         continue;
2230                 }
2231
2232                 /* If this candidate is incomplete skip it */
2233                 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2234                     ast_strlen_zero(name)) {
2235                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2236                         ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2237                         return -1;
2238                 }
2239
2240                 /* We only support UDP so skip any other protocols */
2241                 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2242                         continue;
2243                 }
2244
2245                 /* We only permit audio and video, not RTCP */
2246                 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2247                         continue;
2248                 }
2249
2250                 /* Parse the target information so we can send a STUN request to the candidate */
2251                 if (sscanf(port, "%30d", &real_port) != 1) {
2252                         jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2253                         ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2254                         return -1;
2255                 }
2256                 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2257                 ast_sockaddr_set_port(&target, real_port);
2258
2259                 /* Per the STUN support Google talk uses combine the two usernames */
2260                 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2261
2262                 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2263                 ast_rtp_instance_stun_request(rtp, &target, combined);
2264         }
2265
2266         return 0;
2267 }
2268
2269 /*!
2270  * \brief Helper function which locates content stanzas and interprets them
2271  *
2272  * \note The session *must not* be locked before calling this
2273  */
2274 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2275 {
2276         iks *content;
2277         unsigned int changed = 0;
2278         struct ast_channel *chan;
2279
2280         /* Look at the content in the session initiation */
2281         for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2282                 char *name;
2283                 struct ast_rtp_instance *rtp = NULL;
2284                 iks *description, *transport;
2285
2286                 /* Ignore specific parts if they are known not to be useful */
2287                 if (!strcmp(iks_name(content), "conference-info")) {
2288                         continue;
2289                 }
2290
2291                 name = iks_find_attrib(content, "name");
2292
2293                 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2294                         /* If this content stanza has no name consider it invalid and move on */
2295                         if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2296                                 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2297                                 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2298                                 return -1;
2299                         }
2300
2301                         /* Try to pre-populate which RTP instance this content is relevant to */
2302                         if (!strcmp(session->audio_name, name)) {
2303                                 rtp = session->rtp;
2304                         } else if (!strcmp(session->video_name, name)) {
2305                                 rtp = session->vrtp;
2306                         }
2307                 } else {
2308                         /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2309                         rtp = session->rtp;
2310                 }
2311
2312                 /* If description information is available use it */
2313                 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2314                     (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2315                     (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2316                     (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2317                     (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2318                     (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2319                         /* If we failed to do something with the content description abort immediately */
2320                         if (jingle_interpret_description(session, description, name, &rtp)) {
2321                                 return -1;
2322                         }
2323
2324                         /* If we successfully interpret the description then the codecs need updating */
2325                         changed = 1;
2326                 }
2327
2328                 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2329                 if (!rtp) {
2330                         ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2331                         jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2332                         return -1;
2333                 }
2334
2335                 /* If ICE UDP transport information is available use it */
2336                 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2337                         if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2338                                 return -1;
2339                         }
2340                 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2341                            (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2342                            (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2343                            (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2344                         /* If Google transport support is available use it */
2345                         if (jingle_interpret_google_transport(session, transport, rtp)) {
2346                                 return -1;
2347                         }
2348                 } else if (iks_find(content, "transport")) {
2349                         /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2350                         jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2351                         ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2352                         return -1;
2353                 }
2354         }
2355
2356         if (!changed) {
2357                 return 0;
2358         }
2359
2360         if ((chan = jingle_session_lock_full(session))) {
2361                 struct ast_format_cap *caps;
2362                 struct ast_format *fmt;
2363
2364                 caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
2365                 if (caps) {
2366                         ast_format_cap_append_from_cap(caps, session->jointcap, AST_MEDIA_TYPE_UNKNOWN);
2367                         ast_channel_nativeformats_set(chan, caps);
2368                         ao2_ref(caps, -1);
2369                 }
2370
2371                 fmt = ast_format_cap_get_format(session->jointcap, 0);
2372                 ast_set_read_format(chan, fmt);
2373                 ast_set_write_format(chan, fmt);
2374                 ao2_ref(fmt, -1);
2375
2376                 ast_channel_unlock(chan);
2377                 ast_channel_unref(chan);
2378         }
2379         ao2_unlock(session);
2380
2381         return 0;
2382 }
2383
2384 /*! \brief Handler function for the 'session-initiate' action */
2385 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2386 {
2387         char *sid;
2388         enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2389         struct ast_channel *chan;
2390         int res;
2391
2392         if (session) {
2393                 /* This is a duplicate session setup, so respond accordingly */
2394                 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2395                 return;
2396         }
2397
2398         /* Retrieve the session identifier from the message, note that this may alter the transport */
2399         if ((sid = iks_find_attrib(pak->query, "id"))) {
2400                 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2401                 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2402         } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2403                 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2404                 return;
2405         }
2406
2407         /* Create a new local session */
2408         if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
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         /* If we determined that the transport should change as a result of how we got the SID change it */
2414         if (transport != JINGLE_TRANSPORT_NONE) {
2415                 session->transport = transport;
2416         }
2417
2418         /* Create a new Asterisk channel using the above local session */
2419         if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2420                 ao2_ref(session, -1);
2421                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2422                 return;
2423         }
2424
2425         ao2_link(endpoint->state->sessions, session);
2426
2427         ast_channel_lock(chan);
2428         ast_setstate(chan, AST_STATE_RING);
2429         ast_channel_unlock(chan);
2430         res = ast_pbx_start(chan);
2431
2432         switch (res) {
2433         case AST_PBX_FAILED:
2434                 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2435                 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2436                 session->gone = 1;
2437                 ast_hangup(chan);
2438                 break;
2439         case AST_PBX_CALL_LIMIT:
2440                 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2441                 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2442                 ast_hangup(chan);
2443                 break;
2444         case AST_PBX_SUCCESS:
2445                 jingle_send_response(endpoint->connection, pak);
2446
2447                 /* Only send a transport-info message if we successfully interpreted the available content */
2448                 if (!jingle_interpret_content(session, pak)) {
2449                         jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2450                 }
2451                 break;
2452         }
2453 }
2454
2455 /*! \brief Handler function for the 'transport-info' action */
2456 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2457 {
2458         if (!session) {
2459                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2460                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2461                 return;
2462         }
2463
2464         jingle_interpret_content(session, pak);
2465         jingle_send_response(endpoint->connection, pak);
2466 }
2467
2468 /*! \brief Handler function for the 'session-accept' action */
2469 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2470 {
2471         struct ast_channel *chan;
2472
2473         if (!session) {
2474                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2475                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2476                 return;
2477         }
2478
2479
2480         jingle_interpret_content(session, pak);
2481
2482         if ((chan = jingle_session_lock_full(session))) {
2483                 ast_queue_control(chan, AST_CONTROL_ANSWER);
2484                 ast_channel_unlock(chan);
2485                 ast_channel_unref(chan);
2486         }
2487         ao2_unlock(session);
2488
2489         jingle_send_response(endpoint->connection, pak);
2490 }
2491
2492 /*! \brief Handler function for the 'session-info' action */
2493 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2494 {
2495         struct ast_channel *chan;
2496
2497         if (!session) {
2498                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2499                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2500                 return;
2501         }
2502
2503         if (!(chan = jingle_session_lock_full(session))) {
2504                 ao2_unlock(session);
2505                 jingle_send_response(endpoint->connection, pak);
2506                 return;
2507         }
2508
2509         if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2510                 ast_queue_control(chan, AST_CONTROL_RINGING);
2511                 if (ast_channel_state(chan) != AST_STATE_UP) {
2512                         ast_setstate(chan, AST_STATE_RINGING);
2513                 }
2514         } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2515                 ast_queue_hold(chan, NULL);
2516         } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2517                 ast_queue_unhold(chan);
2518         }
2519
2520         ast_channel_unlock(chan);
2521         ast_channel_unref(chan);
2522         ao2_unlock(session);
2523
2524         jingle_send_response(endpoint->connection, pak);
2525 }
2526
2527 /*! \brief Handler function for the 'session-terminate' action */
2528 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2529 {
2530         struct ast_channel *chan;
2531         iks *reason, *text;
2532         int cause = AST_CAUSE_NORMAL;
2533         struct ast_control_pvt_cause_code *cause_code;
2534         int data_size = sizeof(*cause_code);
2535
2536         if (!session) {
2537                 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2538                                            "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2539                 return;
2540         }
2541
2542         if (!(chan = jingle_session_lock_full(session))) {
2543                 ao2_unlock(session);
2544                 jingle_send_response(endpoint->connection, pak);
2545                 return;
2546         }
2547
2548         /* Pull the reason text from the session-terminate message and translate it into a cause code */
2549         if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2550                 int i;
2551
2552                 /* Size of the string making up the cause code is "Motif " + text */
2553                 data_size += 6 + strlen(iks_name(text));
2554                 cause_code = ast_alloca(data_size);
2555                 memset(cause_code, 0, data_size);
2556
2557                 /* Get the appropriate cause code mapping for this reason */
2558                 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2559                         if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2560                                 cause = jingle_reason_mappings[i].cause;
2561                                 break;
2562                         }
2563                 }
2564
2565                 /* Store the technology specific information */
2566                 snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2567         } else {
2568                 /* No technology specific information is available */
2569                 cause_code = ast_alloca(data_size);
2570                 memset(cause_code, 0, data_size);
2571         }
2572
2573         ast_copy_string(cause_code->chan_name, ast_channel_name(chan), AST_CHANNEL_NAME);
2574         cause_code->ast_cause = cause;
2575         ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2576         ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2577
2578         ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2579         ast_queue_hangup_with_cause(chan, cause);
2580         session->gone = 1;
2581
2582         ast_channel_unlock(chan);
2583         ast_channel_unref(chan);
2584         ao2_unlock(session);
2585
2586         jingle_send_response(endpoint->connection, pak);
2587 }
2588
2589 /*! \brief Callback for when a Jingle action is received from an endpoint */
2590 static int jingle_action_hook(void *data, ikspak *pak)
2591 {
2592         char *action;
2593         const char *sid = NULL;
2594         struct jingle_session *session = NULL;
2595         struct jingle_endpoint *endpoint = data;
2596         int i, handled = 0;
2597
2598         /* We accept both Jingle and Google-V1 */
2599         if (!(action = iks_find_attrib(pak->query, "action")) &&
2600             !(action = iks_find_attrib(pak->query, "type"))) {
2601                 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2602                  * to a message that has no response hook. */
2603                 return IKS_FILTER_EAT;
2604         }
2605
2606         /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2607          * does not permit us to make this completely safe. */
2608         ao2_ref(endpoint, +1);
2609
2610         /* If a Jingle session identifier is present use it */
2611         if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2612                 /* If a Google-V1 session identifier is present use it */
2613                 sid = iks_find_attrib(pak->query, "id");
2614         }
2615
2616         /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2617          * this is required or not */
2618         if (!ast_strlen_zero(sid)) {
2619                 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2620         }
2621
2622         /* If a session is present associate the callid with this thread */
2623         if (session) {
2624                 ast_callid_threadassoc_add(session->callid);
2625         }
2626
2627         /* Iterate through supported action handlers looking for one that is able to handle this */
2628         for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2629                 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2630                         jingle_action_handlers[i].handler(endpoint, session, pak);
2631                         handled = 1;
2632                         break;
2633                 }
2634         }
2635
2636         /* If no action handler is present for the action they sent us make it evident */
2637         if (!handled) {
2638                 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2639         }
2640
2641         /* If a session was successfully found for this message deref it now since the handler is done */
2642         if (session) {
2643                 ast_callid_threadassoc_remove();
2644                 ao2_ref(session, -1);
2645         }
2646
2647         ao2_ref(endpoint, -1);
2648
2649         return IKS_FILTER_EAT;
2650 }
2651
2652 /*! \brief Custom handler for groups */
2653 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2654 {
2655         struct jingle_endpoint *endpoint = obj;
2656
2657         if (!strcasecmp(var->name, "callgroup")) {
2658                 endpoint->callgroup = ast_get_group(var->value);
2659         } else if (!strcasecmp(var->name, "pickupgroup")) {
2660                 endpoint->pickupgroup = ast_get_group(var->value);
2661         } else {
2662                 return -1;
2663         }
2664
2665         return 0;
2666 }
2667
2668 /*! \brief Custom handler for connection */
2669 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2670 {
2671         struct jingle_endpoint *endpoint = obj;
2672
2673         /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2674          * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2675          */
2676         if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2677                 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2678                 return -1;
2679         }
2680
2681         if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2682                                                    IKS_RULE_TYPE, IKS_PAK_IQ,
2683                                                    IKS_RULE_NS, JINGLE_NS,
2684                                                    IKS_RULE_NS, GOOGLE_SESSION_NS,
2685                                                    IKS_RULE_DONE))) {
2686                 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2687                 return -1;
2688         }
2689
2690         return 0;
2691 }
2692
2693 /*! \brief Custom handler for transport */
2694 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2695 {
2696         struct jingle_endpoint *endpoint = obj;
2697
2698         if (!strcasecmp(var->value, "ice-udp")) {
2699                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2700         } else if (!strcasecmp(var->value, "google")) {
2701                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2702         } else if (!strcasecmp(var->value, "google-v1")) {
2703                 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2704         } else {
2705                 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2706                 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2707         }
2708
2709         return 0;
2710 }
2711
2712 /*!
2713  * \brief Load the module
2714  *
2715  * Module loading including tests for configuration or dependencies.
2716  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2717  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2718  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2719  * configuration file or other non-critical problem return
2720  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2721  */
2722 static int load_module(void)
2723 {
2724         if (!(jingle_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2725                 return AST_MODULE_LOAD_DECLINE;
2726         }
2727
2728         if (aco_info_init(&cfg_info)) {
2729                 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2730                 goto end;
2731         }
2732
2733         aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2734         aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2735         aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2736         aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2737         aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2738         aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2739         aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2740         aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
2741         aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
2742         aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2743         aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2744         aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2745                             FLDSET(struct jingle_endpoint, maxicecandidates), DEFAULT_MAX_ICE_CANDIDATES);
2746         aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2747                             FLDSET(struct jingle_endpoint, maxpayloads), DEFAULT_MAX_PAYLOADS);
2748
2749         ast_format_cap_append_by_type(jingle_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
2750
2751         if (aco_process_config(&cfg_info, 0)) {
2752                 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Module loaded but not running.\n");
2753                 aco_info_destroy(&cfg_info);
2754                 ao2_cleanup(jingle_tech.capabilities);
2755                 jingle_tech.capabilities = NULL;
2756                 return AST_MODULE_LOAD_DECLINE;
2757         }
2758
2759         if (!(sched = ast_sched_context_create())) {
2760                 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2761                 goto end;
2762         }
2763
2764         if (ast_sched_start_thread(sched)) {
2765                 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2766                 goto end;
2767         }
2768
2769         ast_rtp_glue_register(&jingle_rtp_glue);
2770
2771         if (ast_channel_register(&jingle_tech)) {
2772                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2773                 goto end;
2774         }
2775
2776         return 0;
2777
2778 end:
2779         ast_rtp_glue_unregister(&jingle_rtp_glue);
2780
2781         if (sched) {
2782                 ast_sched_context_destroy(sched);
2783         }
2784
2785         aco_info_destroy(&cfg_info);
2786         ao2_global_obj_release(globals);
2787
2788         ao2_cleanup(jingle_tech.capabilities);
2789         jingle_tech.capabilities = NULL;
2790
2791         return AST_MODULE_LOAD_DECLINE;
2792 }
2793
2794 /*! \brief Reload module */
2795 static int reload(void)
2796 {
2797         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2798                 return -1;
2799         }
2800
2801         return 0;
2802 }
2803
2804 /*! \brief Unload the jingle channel from Asterisk */
2805 static int unload_module(void)
2806 {
2807         ast_channel_unregister(&jingle_tech);
2808         ao2_cleanup(jingle_tech.capabilities);
2809         jingle_tech.capabilities = NULL;
2810         ast_rtp_glue_unregister(&jingle_rtp_glue);
2811         ast_sched_context_destroy(sched);
2812         aco_info_destroy(&cfg_info);
2813         ao2_global_obj_release(globals);
2814
2815         return 0;
2816 }
2817
2818 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2819         .support_level = AST_MODULE_SUPPORT_CORE,
2820         .load = load_module,
2821         .unload = unload_module,
2822         .reload = reload,
2823         .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2824 );