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