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