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