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