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