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