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