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