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