Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/manager.h"
71 #include "asterisk/stringfields.h"
72 #include "asterisk/utils.h"
73 #include "asterisk/causes.h"
74 #include "asterisk/abstract_jb.h"
75 #include "asterisk/xmpp.h"
76 #include "asterisk/endpoints.h"
78 #include "asterisk/format_cache.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 pyaloads 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 
321 static const char channel_type[] = "Motif";
322 
324  struct ao2_container *endpoints; /*!< Configured endpoints */
325 };
326 
328 
329 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
330 
331 /* \brief Asterisk core interaction functions */
332 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);
333 static int jingle_sendtext(struct ast_channel *ast, const char *text);
334 static int jingle_digit_begin(struct ast_channel *ast, char digit);
335 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
336 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
337 static int jingle_hangup(struct ast_channel *ast);
338 static int jingle_answer(struct ast_channel *ast);
339 static struct ast_frame *jingle_read(struct ast_channel *ast);
340 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
341 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
342 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
343 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
344 
345 /*! \brief Action handlers */
346 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
347 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
348 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
349 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
350 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
351 
352 /*! \brief PBX interface structure for channel registration */
353 static struct ast_channel_tech jingle_tech = {
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 */
373 static 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, },
389 };
390 
391 /*! \brief Reason text <-> cause code mapping */
392 static 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, },
409  { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
410  { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
411  { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
412 };
413 
414 /*! \brief Hashing function for Jingle sessions */
415 static 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 */
424 static 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 */
433 static void jingle_endpoint_state_destructor(void *obj)
434 {
435  struct jingle_endpoint_state *state = obj;
436 
437  ao2_ref(state->sessions, -1);
438 }
439 
440 /*! \brief Destructor for Jingle endpoints */
441 static 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 */
460 static 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 
470  if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
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 */
499 static void *jingle_endpoint_alloc(const char *cat)
500 {
501  struct jingle_endpoint *endpoint;
502 
503  if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
504  return NULL;
505  }
506 
507  if (ast_string_field_init(endpoint, 512)) {
508  ao2_ref(endpoint, -1);
509  return NULL;
510  }
511 
512  if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
513  ao2_ref(endpoint, -1);
514  return NULL;
515  }
516 
517  ast_string_field_set(endpoint, name, cat);
518 
521 
522  return endpoint;
523 }
524 
525 /*! \brief Hashing function for Jingle endpoints */
526 static int jingle_endpoint_hash(const void *obj, const int flags)
527 {
528  const struct jingle_endpoint *endpoint = obj;
529  const char *name = obj;
530 
531  return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
532 }
533 
534 /*! \brief Comparator function for Jingle endpoints */
535 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
536 {
537  struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
538  const char *name = arg;
539 
540  return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
541 }
542 
543 static struct aco_type endpoint_option = {
544  .type = ACO_ITEM,
545  .name = "endpoint",
546  .category_match = ACO_BLACKLIST_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 
553 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
554 
556  .filename = "motif.conf",
557  .types = ACO_TYPES(&endpoint_option),
558 };
559 
560 /*! \brief Destructor for Jingle sessions */
561 static void jingle_session_destructor(void *obj)
562 {
563  struct jingle_session *session = obj;
564 
565  if (session->rule) {
566  iks_filter_remove_rule(session->connection->filter, session->rule);
567  }
568 
569  if (session->connection) {
571  }
572 
573  if (session->rtp) {
574  ast_rtp_instance_stop(session->rtp);
575  ast_rtp_instance_destroy(session->rtp);
576  }
577 
578  if (session->vrtp) {
579  ast_rtp_instance_stop(session->vrtp);
580  ast_rtp_instance_destroy(session->vrtp);
581  }
582 
583  ao2_cleanup(session->cap);
584  ao2_cleanup(session->jointcap);
585  ao2_cleanup(session->peercap);
586 
588 }
589 
590 /*! \brief Destructor called when module configuration goes away */
591 static void jingle_config_destructor(void *obj)
592 {
593  struct jingle_config *cfg = obj;
594  ao2_cleanup(cfg->endpoints);
595 }
596 
597 /*! \brief Allocator called when module configuration should appear */
598 static void *jingle_config_alloc(void)
599 {
600  struct jingle_config *cfg;
601 
602  if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
603  return NULL;
604  }
605 
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 */
621 static 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 */
637 static 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 */
642 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)
643 {
644  return -1;
645 }
646 
647 /*! \brief Local glue for interacting with the RTP engine core */
648 static struct ast_rtp_glue jingle_rtp_glue = {
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 */
656 static void jingle_set_owner(struct jingle_session *session, struct ast_channel *chan)
657 {
658  session->owner = chan;
659  if (session->rtp) {
660  ast_rtp_instance_set_channel_id(session->rtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
661  }
662  if (session->vrtp) {
663  ast_rtp_instance_set_channel_id(session->vrtp, session->owner ? ast_channel_uniqueid(session->owner) : "");
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 
691  ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
692  ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
694  ast_format_cap_get_framing(session->cap));
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 */
701 static 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 
707  if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
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 */
768 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)
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 
791  ast_channel_tech_set(chan, &jingle_tech);
792  ast_channel_tech_pvt_set(chan, session);
793  jingle_set_owner(session, chan);
794 
795  ast_channel_callid_set(chan, session->callid);
796 
798  ast_channel_nativeformats_set(chan, caps);
799  ao2_ref(caps, -1);
800 
801  if (session->rtp) {
802  struct ast_rtp_engine_ice *ice;
803 
804  ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
805  ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
807  ast_format_cap_get_framing(session->cap));
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);
833  ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
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  }
853  ast_channel_priority_set(chan, 1);
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 */
864 static 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 */
884 static 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);
910 end:
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 */
918 static 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 */
980 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)
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 
1051  ao2_iterator_destroy(&it);
1052  ao2_ref(local_candidates, -1);
1053 
1054  return res;
1055 }
1056 
1057 /*! \brief Internal function which sends a session-terminate message */
1058 static 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);
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 
1090 end:
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 */
1098 static 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);
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 
1125 end:
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  }
1207  ao2_unlock(session);
1208 }
1209 
1210 /*! \brief Internal function which sends a transport-info message */
1211 static 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);
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 */
1306 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)
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 */
1392 static 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 */
1430 static 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);
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 */
1524 static 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  }
1544  ao2_unlock(session);
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 
1618 end:
1620 
1621  return IKS_FILTER_EAT;
1622 }
1623 
1624 /*! \brief Function called by core when we should answer a Jingle session */
1625 static 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 
1634  jingle_send_session_accept(session);
1635 
1636  return 0;
1637 }
1638 
1639 /*! \brief Function called by core to read any waiting frames */
1640 static 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);
1686  ast_channel_nativeformats_set(ast, caps);
1687  ao2_ref(caps, -1);
1688  }
1691  }
1692  }
1693 
1694  return frame;
1695 }
1696 
1697 /*! \brief Function called by core to write frames */
1698 static 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 */
1735 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1736 {
1737  struct jingle_session *session = ast_channel_tech_pvt(newchan);
1738 
1739  ao2_lock(session);
1740 
1741  jingle_set_owner(session, newchan);
1742 
1743  ao2_unlock(session);
1744 
1745  return 0;
1746 }
1747 
1748 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1749 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1750 {
1752  int res = 0;
1753 
1754  switch (condition) {
1755  case AST_CONTROL_RINGING:
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;
1790  case AST_CONTROL_SRCUPDATE:
1791  if (session->rtp) {
1793  }
1794  break;
1795  case AST_CONTROL_SRCCHANGE:
1796  if (session->rtp) {
1798  }
1799  break;
1800  case AST_CONTROL_VIDUPDATE:
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 */
1818 static 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 */
1826 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1827 {
1829 
1830  if (session->rtp) {
1831  ast_rtp_instance_dtmf_begin(session->rtp, digit);
1832  }
1833 
1834  return 0;
1835 }
1836 
1837 /*! \brief Function called by core to stop a DTMF digit */
1838 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1839 {
1841 
1842  if (session->rtp) {
1843  ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1844  }
1845 
1846  return 0;
1847 }
1848 
1849 /*! \brief Function called by core to actually start calling a remote party */
1850 static 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 */
1869 static int jingle_hangup(struct ast_channel *ast)
1870 {
1872 
1873  ao2_lock(session);
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 
1888  jingle_send_session_terminate(session, reason);
1889  }
1890 
1892  jingle_set_owner(session, NULL);
1893 
1894  ao2_unlink(session->state->sessions, session);
1895  ao2_ref(session->state, -1);
1896 
1897  ao2_unlock(session);
1898  ao2_ref(session, -1);
1899 
1900  return 0;
1901 }
1902 
1903 /*! \brief Function called by core to create a new outgoing Jingle session */
1904 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)
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;
1915  AST_APP_ARG(name);
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);
1952  *cause = AST_CAUSE_SWITCH_CONGESTION;
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;
1960  struct ast_xmpp_resource *resource;
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  }
1976  ao2_iterator_destroy(&res);
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);
1989  *cause = AST_CAUSE_SWITCH_CONGESTION;
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);
1995  *cause = AST_CAUSE_SWITCH_CONGESTION;
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);
2007  *cause = AST_CAUSE_SWITCH_CONGESTION;
2008  ao2_ref(session, -1);
2009  return NULL;
2010  }
2011 
2012  /* If video was requested try to enable it on the session */
2014  jingle_enable_video(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 */
2033 static 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 
2062  jingle_enable_video(session);
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 
2081  if (ast_rtp_codecs_payloads_initialize(&codecs)) {
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 */
2120 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2121 {
2122  struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2123  char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
2124  iks *candidate;
2125 
2126  if (!ice) {
2128  ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
2129  return -1;
2130  }
2131 
2132  if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
2133  ice->set_authentication(rtp, ufrag, pwd);
2134  }
2135 
2136  for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2137  char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
2138  char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
2139  char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
2140  char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
2141  char *type = iks_find_attrib(candidate, "type");
2142  struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
2143  int real_port;
2144  struct ast_sockaddr remote_address = { { 0, } };
2145 
2146  /* If this candidate is incomplete skip it */
2147  if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
2148  ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
2149  ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
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 */
2201 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2202 {
2203  struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2204  iks *candidate;
2205 
2206  if (!ice) {
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) ||
2239  ast_strlen_zero(name)) {
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  }
2261  ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2262  ast_sockaddr_set_port(&target, real_port);
2263 
2264  /* Per the STUN support Google talk uses combine the two usernames */
2265  snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2266 
2267  /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2268  ast_rtp_instance_stun_request(rtp, &target, combined);
2269  }
2270 
2271  return 0;
2272 }
2273 
2274 /*!
2275  * \brief Helper function which locates content stanzas and interprets them
2276  *
2277  * \note The session *must not* be locked before calling this
2278  */
2279 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2280 {
2281  iks *content;
2282  unsigned int changed = 0;
2283  struct ast_channel *chan;
2284 
2285  /* Look at the content in the session initiation */
2286  for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2287  char *name;
2288  struct ast_rtp_instance *rtp = NULL;
2289  iks *description, *transport;
2290 
2291  /* Ignore specific parts if they are known not to be useful */
2292  if (!strcmp(iks_name(content), "conference-info")) {
2293  continue;
2294  }
2295 
2296  name = iks_find_attrib(content, "name");
2297 
2298  if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2299  /* If this content stanza has no name consider it invalid and move on */
2300  if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2302  ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2303  return -1;
2304  }
2305 
2306  /* Try to pre-populate which RTP instance this content is relevant to */
2307  if (!strcmp(session->audio_name, name)) {
2308  rtp = session->rtp;
2309  } else if (!strcmp(session->video_name, name)) {
2310  rtp = session->vrtp;
2311  }
2312  } else {
2313  /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2314  rtp = session->rtp;
2315  }
2316 
2317  /* If description information is available use it */
2318  if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2319  (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2320  (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2321  (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2322  (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2323  (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2324  /* If we failed to do something with the content description abort immediately */
2325  if (jingle_interpret_description(session, description, name, &rtp)) {
2326  return -1;
2327  }
2328 
2329  /* If we successfully interpret the description then the codecs need updating */
2330  changed = 1;
2331  }
2332 
2333  /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2334  if (!rtp) {
2335  ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
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) {
2372  ast_channel_nativeformats_set(chan, caps);
2373  ao2_ref(caps, -1);
2374  }
2375 
2376  fmt = ast_format_cap_get_format(session->jointcap, 0);
2377  ast_set_read_format(chan, fmt);
2378  ast_set_write_format(chan, fmt);
2379  ao2_ref(fmt, -1);
2380 
2381  ast_channel_unlock(chan);
2382  ast_channel_unref(chan);
2383  }
2384  ao2_unlock(session);
2385 
2386  return 0;
2387 }
2388 
2389 /*! \brief Handler function for the 'session-initiate' action */
2390 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2391 {
2392  char *sid;
2393  enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2394  struct ast_channel *chan;
2395  int res;
2396 
2397  if (session) {
2398  /* This is a duplicate session setup, so respond accordingly */
2399  jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2400  return;
2401  }
2402 
2403  /* Retrieve the session identifier from the message, note that this may alter the transport */
2404  if ((sid = iks_find_attrib(pak->query, "id"))) {
2405  /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2406  transport = JINGLE_TRANSPORT_GOOGLE_V1;
2407  } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2408  jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2409  return;
2410  }
2411 
2412  /* Create a new local session */
2413  if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2414  jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2415  return;
2416  }
2417 
2418  /* If we determined that the transport should change as a result of how we got the SID change it */
2419  if (transport != JINGLE_TRANSPORT_NONE) {
2420  session->transport = transport;
2421  }
2422 
2423  /* Create a new Asterisk channel using the above local session */
2424  if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, NULL, pak->from->full))) {
2425  ao2_ref(session, -1);
2426  jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2427  return;
2428  }
2429 
2430  ao2_link(endpoint->state->sessions, session);
2431 
2432  ast_channel_lock(chan);
2434  ast_channel_unlock(chan);
2435  res = ast_pbx_start(chan);
2436 
2437  switch (res) {
2438  case AST_PBX_FAILED:
2439  ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2440  jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2441  session->gone = 1;
2442  ast_hangup(chan);
2443  break;
2444  case AST_PBX_CALL_LIMIT:
2445  ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2446  jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2447  ast_hangup(chan);
2448  break;
2449  case AST_PBX_SUCCESS:
2450  jingle_send_response(endpoint->connection, pak);
2451 
2452  /* Only send a transport-info message if we successfully interpreted the available content */
2453  if (!jingle_interpret_content(session, pak)) {
2454  jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2455  }
2456  break;
2457  }
2458 }
2459 
2460 /*! \brief Handler function for the 'transport-info' action */
2461 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2462 {
2463  if (!session) {
2464  jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2465  "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2466  return;
2467  }
2468 
2469  jingle_interpret_content(session, pak);
2470  jingle_send_response(endpoint->connection, pak);
2471 }
2472 
2473 /*! \brief Handler function for the 'session-accept' action */
2474 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2475 {
2476  struct ast_channel *chan;
2477 
2478  if (!session) {
2479  jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2480  "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2481  return;
2482  }
2483 
2484 
2485  jingle_interpret_content(session, pak);
2486 
2487  if ((chan = jingle_session_lock_full(session))) {
2489  ast_channel_unlock(chan);
2490  ast_channel_unref(chan);
2491  }
2492  ao2_unlock(session);
2493 
2494  jingle_send_response(endpoint->connection, pak);
2495 }
2496 
2497 /*! \brief Handler function for the 'session-info' action */
2498 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2499 {
2500  struct ast_channel *chan;
2501 
2502  if (!session) {
2503  jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2504  "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2505  return;
2506  }
2507 
2508  if (!(chan = jingle_session_lock_full(session))) {
2509  ao2_unlock(session);
2510  jingle_send_response(endpoint->connection, pak);
2511  return;
2512  }
2513 
2514  if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
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);
2527  ao2_unlock(session);
2528 
2529  jingle_send_response(endpoint->connection, pak);
2530 }
2531 
2532 /*! \brief Handler function for the 'session-terminate' action */
2533 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2534 {
2535  struct ast_channel *chan;
2536  iks *reason, *text;
2537  int cause = AST_CAUSE_NORMAL;
2538  struct ast_control_pvt_cause_code *cause_code;
2539  int data_size = sizeof(*cause_code);
2540 
2541  if (!session) {
2542  jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2543  "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2544  return;
2545  }
2546 
2547  if (!(chan = jingle_session_lock_full(session))) {
2548  ao2_unlock(session);
2549  jingle_send_response(endpoint->connection, pak);
2550  return;
2551  }
2552 
2553  /* Pull the reason text from the session-terminate message and translate it into a cause code */
2554  if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2555  int i;
2556 
2557  /* Size of the string making up the cause code is "Motif " + text */
2558  data_size += 6 + strlen(iks_name(text));
2559  cause_code = ast_alloca(data_size);
2560  memset(cause_code, 0, data_size);
2561 
2562  /* Get the appropriate cause code mapping for this reason */
2563  for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2564  if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2565  cause = jingle_reason_mappings[i].cause;
2566  break;
2567  }
2568  }
2569 
2570  /* Store the technology specific information */
2571  snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "Motif %s", iks_name(text));
2572  } else {
2573  /* No technology specific information is available */
2574  cause_code = ast_alloca(data_size);
2575  memset(cause_code, 0, data_size);
2576  }
2577 
2579  cause_code->ast_cause = cause;
2580  ast_queue_control_data(chan, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
2581  ast_channel_hangupcause_hash_set(chan, cause_code, data_size);
2582 
2583  ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2584  ast_queue_hangup_with_cause(chan, cause);
2585  session->gone = 1;
2586 
2587  ast_channel_unlock(chan);
2588  ast_channel_unref(chan);
2589  ao2_unlock(session);
2590 
2591  jingle_send_response(endpoint->connection, pak);
2592 }
2593 
2594 /*! \brief Callback for when a Jingle action is received from an endpoint */
2595 static int jingle_action_hook(void *data, ikspak *pak)
2596 {
2597  char *action;
2598  const char *sid = NULL;
2599  struct jingle_session *session = NULL;
2600  struct jingle_endpoint *endpoint = data;
2601  int i, handled = 0;
2602 
2603  /* We accept both Jingle and Google-V1 */
2604  if (!(action = iks_find_attrib(pak->query, "action")) &&
2605  !(action = iks_find_attrib(pak->query, "type"))) {
2606  /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2607  * to a message that has no response hook. */
2608  return IKS_FILTER_EAT;
2609  }
2610 
2611  /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2612  * does not permit us to make this completely safe. */
2613  ao2_ref(endpoint, +1);
2614 
2615  /* If a Jingle session identifier is present use it */
2616  if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2617  /* If a Google-V1 session identifier is present use it */
2618  sid = iks_find_attrib(pak->query, "id");
2619  }
2620 
2621  /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2622  * this is required or not */
2623  if (!ast_strlen_zero(sid)) {
2624  session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2625  }
2626 
2627  /* If a session is present associate the callid with this thread */
2628  if (session) {
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 */
2658 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2659 {
2660  struct jingle_endpoint *endpoint = obj;
2661 
2662  if (!strcasecmp(var->name, "callgroup")) {
2663  endpoint->callgroup = ast_get_group(var->value);
2664  } else if (!strcasecmp(var->name, "pickupgroup")) {
2665  endpoint->pickupgroup = ast_get_group(var->value);
2666  } else {
2667  return -1;
2668  }
2669 
2670  return 0;
2671 }
2672 
2673 /*! \brief Custom handler for connection */
2674 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2675 {
2676  struct jingle_endpoint *endpoint = obj;
2677 
2678  /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2679  * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2680  */
2681  if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2682  ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2683  return -1;
2684  }
2685 
2686  if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2687  IKS_RULE_TYPE, IKS_PAK_IQ,
2688  IKS_RULE_NS, JINGLE_NS,
2689  IKS_RULE_NS, GOOGLE_SESSION_NS,
2690  IKS_RULE_DONE))) {
2691  ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2692  return -1;
2693  }
2694 
2695  return 0;
2696 }
2697 
2698 /*! \brief Custom handler for transport */
2699 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2700 {
2701  struct jingle_endpoint *endpoint = obj;
2702 
2703  if (!strcasecmp(var->value, "ice-udp")) {
2704  endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2705  } else if (!strcasecmp(var->value, "google")) {
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);
2711  endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2712  }
2713 
2714  return 0;
2715 }
2716 
2717 /*!
2718  * \brief Load the module
2719  *
2720  * Module loading including tests for configuration or dependencies.
2721  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2722  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2723  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2724  * configuration file or other non-critical problem return
2725  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2726  */
2727 static int load_module(void)
2728 {
2730  return AST_MODULE_LOAD_DECLINE;
2731  }
2732 
2733  if (aco_info_init(&cfg_info)) {
2734  ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2735  goto end;
2736  }
2737 
2738  aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2739  aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2740  aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2741  aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2742  aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2743  aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2744  aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2745  aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, cap));
2746  aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, cap));
2747  aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2748  aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2749  aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2751  aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
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);
2759  ao2_cleanup(jingle_tech.capabilities);
2760  jingle_tech.capabilities = NULL;
2761  return AST_MODULE_LOAD_DECLINE;
2762  }
2763 
2764  if (!(sched = ast_sched_context_create())) {
2765  ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2766  goto end;
2767  }
2768 
2769  if (ast_sched_start_thread(sched)) {
2770  ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2771  goto end;
2772  }
2773 
2774  ast_rtp_glue_register(&jingle_rtp_glue);
2775 
2776  if (ast_channel_register(&jingle_tech)) {
2777  ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2778  goto end;
2779  }
2780 
2781  return 0;
2782 
2783 end:
2784  ast_rtp_glue_unregister(&jingle_rtp_glue);
2785 
2786  if (sched) {
2788  }
2789 
2790  aco_info_destroy(&cfg_info);
2792 
2793  ao2_cleanup(jingle_tech.capabilities);
2794  jingle_tech.capabilities = NULL;
2795 
2796  return AST_MODULE_LOAD_DECLINE;
2797 }
2798 
2799 /*! \brief Reload module */
2800 static 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 */
2810 static int unload_module(void)
2811 {
2812  ast_channel_unregister(&jingle_tech);
2813  ao2_cleanup(jingle_tech.capabilities);
2814  jingle_tech.capabilities = NULL;
2815  ast_rtp_glue_unregister(&jingle_rtp_glue);
2817  aco_info_destroy(&cfg_info);
2819 
2820  return 0;
2821 }
2822 
2823 AST_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",
2830 );
static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
Handler function for the &#39;transport-info&#39; action.
Definition: chan_motif.c:2461
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:1580
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:932
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:195
#define AST_CAUSE_PROTOCOL_ERROR
Definition: causes.h:144
const ast_string_field audio_name
Definition: chan_motif.c:301
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:162
Type for default option handler for format capabilities.
unsigned long long ast_group_t
Definition: channel.h:214
static const char type[]
Definition: chan_ooh323.c:109
enum sip_cc_notify_state state
Definition: chan_sip.c:959
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:428
void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
const ast_string_field sid
Definition: chan_motif.c:301
char digit
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
Music on hold handling.
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
static void jingle_endpoint_destructor(void *obj)
Destructor for Jingle endpoints.
Definition: chan_motif.c:441
const char * action
Definition: chan_motif.c:374
enum ast_media_type ast_format_get_type(const struct ast_format *format)
Get the media type of a format.
Definition: format.c:354
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
const char *const type
Definition: channel.h:630
Asterisk locking-related definitions:
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 void jingle_endpoint_state_destructor(void *obj)
Destructor for Jingle endpoint state.
Definition: chan_motif.c:433
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_channel_tech jingle_tech
PBX interface structure for channel registration.
Definition: chan_motif.c:353
unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
Get the global framing.
Definition: format_cap.c:438
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char chan_name[AST_CHANNEL_NAME]
static char parkinglot[AST_MAX_CONTEXT]
Definition: chan_mgcp.c:163
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
struct ast_format_cap * cap
Definition: chan_motif.c:288
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:553
#define ast_channel_alloc_with_endpoint(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag, endpoint,...)
Definition: channel.h:1263
static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
Comparator function for Jingle endpoints.
Definition: chan_motif.c:535
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
Channels have this property if they can accept input with jitter; i.e. most VoIP channels.
Definition: channel.h:961
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:2160
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
unsigned int maxpayloads
Definition: chan_motif.c:287
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
struct jingle_endpoint_state * state
Definition: chan_motif.c:302
#define DEFAULT_MAX_ICE_CANDIDATES
Default maximum number of ICE candidates we will offer.
Definition: chan_motif.c:220
const char *(* get_password)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:497
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 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 GOOGLE_TRANSPORT_NS
Namespace for Google Talk ICE-UDP.
Definition: chan_motif.c:244
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
Handler function for the &#39;session-accept&#39; action.
Definition: chan_motif.c:2474
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
#define AST_CAUSE_SWITCH_CONGESTION
Definition: causes.h:122
#define OBJ_KEY
Definition: astobj2.h:1155
char * address
Definition: f2c.h:59
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1216
static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
Internal helper function which sends a response.
Definition: chan_motif.c:864
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
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:727
#define LOG_WARNING
Definition: logger.h:274
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
Defined handlers for different Jingle actions.
Definition: chan_motif.c:373
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
#define GOOGLE_PHONE_NS
Namespace for Google Phone description.
Definition: chan_motif.c:253
ast_callid callid
Definition: chan_motif.c:318
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
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
#define AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE
Definition: causes.h:142
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
static int jingle_session_hash(const void *obj, const int flags)
Hashing function for Jingle sessions.
Definition: chan_motif.c:415
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition: rtp_engine.c:568
#define ast_rtp_glue_register(glue)
Definition: rtp_engine.h:847
const ast_string_field language
Definition: chan_motif.c:283
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 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
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
const ast_string_field name
Definition: chan_motif.c:283
struct jingle_endpoint_state * state
Definition: chan_motif.c:292
void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
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:2891
void(* add_remote_candidate)(struct ast_rtp_instance *instance, const struct ast_rtp_engine_ice_candidate *candidate)
Definition: rtp_engine.h:489
static struct jingle_endpoint_state * jingle_endpoint_state_find_or_create(const char *category)
State find/create function.
Definition: chan_motif.c:485
Definition of a media format.
Definition: format.c:43
char resource[XMPP_MAX_RESJIDLEN]
Definition: xmpp.h:93
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.
struct ao2_container * endpoints
Definition: chan_motif.c: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
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
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
unsigned int ast_callid
Definition: logger.h:87
struct ast_format_cap * jointcap
Definition: chan_motif.c:314
struct ast_channel * owner
Definition: chan_motif.c:310
#define ao2_unlock(a)
Definition: astobj2.h:730
ast_group_t pickupgroup
Definition: chan_motif.c:290
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
char * text
Definition: app_queue.c:1508
#define ast_str_alloca(init_len)
Definition: strings.h:800
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Endpoint abstractions.
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:1558
const char * str
Definition: app_jack.c:147
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void(* stop)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:493
const char * args
#define NULL
Definition: resample.c:96
const char * data
#define AST_CAUSE_NO_USER_RESPONSE
Definition: causes.h:107
Session which contains information about an active session.
Definition: chan_motif.c:296
I/O Management (derived from Cheops-NG)
char * end
Definition: eagi_proxy.c:73
struct ast_format * ast_format_g722
Built-in cached g722 format.
Definition: format_cache.c:111
The representation of a single configuration file to be processed.
Common implementation-independent jitterbuffer stuff.
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
void(* handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
Definition: chan_motif.c:375
static int priority
enum aco_type_t type
static int jingle_hangup(struct ast_channel *ast)
Function called by core to hang up a Jingle session.
Definition: chan_motif.c:1869
Structure for an ICE candidate.
Definition: rtp_engine.h:474
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
ast_group_t callgroup
Definition: chan_motif.c:289
Socket address structure.
Definition: netsock2.h:97
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static int jingle_session_cmp(void *obj, void *arg, int flags)
Comparator function for Jingle sessions.
Definition: chan_motif.c:424
const char * type
Definition: rtp_engine.h:722
struct ast_rtp_instance * rtp
Definition: chan_motif.c:311
static const struct jingle_action_handler jingle_action_handlers[]
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:2537
int ast_callid_threadassoc_remove(void)
Removes callid from thread storage of the calling thread.
Definition: logger.c:2003
struct ast_frame_subclass subclass
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
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:1962
Utility functions.
int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
Queue a hangup frame with hangupcause set.
Definition: channel.c:1166
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define JINGLE_RTP_INFO_NS
Namespace for Jingle RTP info.
Definition: chan_motif.c:238
#define ENDPOINT_BUCKETS
Number of buckets for endpoints.
Definition: chan_motif.c:226
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
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:583
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:2661
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:127
enum ast_rtp_ice_candidate_type type
Definition: rtp_engine.h:481
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:1984
unsigned int outgoing
Definition: chan_motif.c:316
void ast_xmpp_increment_mid(char *mid)
Helper function which increments the message identifier.
Definition: res_xmpp.c:1019
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:362
static void jingle_send_session_accept(struct jingle_session *session)
Internal function which sends a session-accept message.
Definition: chan_motif.c:1518
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
const ast_string_field context
Definition: chan_motif.c:283
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
const ast_string_field musicclass
Definition: chan_motif.c:283
void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
Stop an RTP instance.
Definition: rtp_engine.c:2183
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 FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
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
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
struct ast_format_cap * cap
Definition: chan_motif.c:313
General Asterisk PBX channel definitions.
void ast_channel_rings_set(struct ast_channel *chan, int value)
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:1992
XMPP Client Connection.
Definition: xmpp.h:119
XMPP Interface.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#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:911
Type for default option handler for unsigned integers.
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:1873
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
static struct ast_mansession session
struct aco_type * endpoint_options[]
Definition: chan_motif.c:553
unsigned int google
Definition: xmpp.h:88
Access Control of various sorts.
static struct aco_type endpoint_option
Definition: chan_motif.c:543
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
Scheduler Routines (derived from cheops)
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
static struct ao2_container * endpoints
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
long int ast_random(void)
Definition: main/utils.c:2064
static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
Handler function for the &#39;session-terminate&#39; action.
Definition: chan_motif.c:2533
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static AO2_GLOBAL_OBJ_STATIC(globals)
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:117
static struct console_pvt globals
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
ast_group_t ast_get_group(const char *s)
Definition: channel.c:7718
Endpoint state information.
Definition: chan_motif.c:270
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
unsigned int maxicecandidates
Definition: chan_motif.c:305
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:4179
ast_rtp_glue_result
Definition: rtp_engine.h:158
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition: channel.c:1191
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:1428
#define AST_CAUSE_FACILITY_NOT_IMPLEMENTED
Definition: causes.h:132
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
Core PBX routines and definitions.
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:525
static void * jingle_endpoint_alloc(const char *cat)
Allocator function for Jingle endpoints.
Definition: chan_motif.c:499
static int unload_module(void)
Unload the jingle channel from Asterisk.
Definition: chan_motif.c:2810
Their was an error and no changes were applied.
#define XMPP_MAX_JIDLEN
Definition: xmpp.h:62
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
int ast_channel_fdno(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_party_dialed dialed
Dialed/Called information.
#define AST_CAUSE_NORMAL
Definition: causes.h:150
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
void ast_xmpp_client_unref(struct ast_xmpp_client *client)
Release XMPP client connection reference.
Definition: res_xmpp.c:888
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
jingle_transport
The various transport methods supported, from highest priority to lowest priority when doing fallback...
Definition: chan_motif.c:262
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)
Function called by core to create a new outgoing Jingle session.
Definition: chan_motif.c:1904
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
XMPP Resource.
Definition: xmpp.h:92
const char *(* get_ufrag)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:495
Configuration option-handling.
Endpoint which contains configuration information and active sessions.
Definition: chan_motif.c:275
void(* set_authentication)(struct ast_rtp_instance *instance, const char *ufrag, const char *password)
Definition: rtp_engine.h:487
static void * jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
Find function for Jingle endpoints.
Definition: chan_motif.c:460
#define LOG_ERROR
Definition: logger.h:285
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
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
struct ao2_container *(* get_local_candidates)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:499
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition: logger.c:1957
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
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
char remote_original[XMPP_MAX_JIDLEN]
Definition: chan_motif.c:307
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
struct ast_rtp_instance * vrtp
Definition: chan_motif.c:312
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define AST_CAUSE_CHANNEL_UNACCEPTABLE
Definition: causes.h:101
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
unsigned int jingle
Definition: xmpp.h:87
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the &#39;nonstandard&#39; argument separation process for an application.
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 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:1080
def info(msg)
iksfilter * filter
Definition: xmpp.h:128
enum ast_rtp_ice_component_type id
Definition: rtp_engine.h:476
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
int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
Begin sending a DTMF digit.
Definition: rtp_engine.c:2081
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_reason_mapping jingle_reason_mappings[]
CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,.files=ACO_FILES(&jingle_conf),)
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:7866
struct ast_xmpp_client * connection
Definition: chan_motif.c:303
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define XMPP_STANZAS_NS
Namespace for XMPP stanzas.
Definition: chan_motif.c:259
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define LOG_NOTICE
Definition: logger.h:263
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:736
#define JINGLE_RTP_NS
Namespace for Jingle RTP sessions.
Definition: chan_motif.c:235
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
struct ast_format_cap * capabilities
Definition: channel.h:633
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2463
static int reload(void)
Reload module.
Definition: chan_motif.c:2800
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
#define ast_channel_unlock(chan)
Definition: channel.h:2946
unsigned int gone
Definition: chan_motif.c:317
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:2022
static const char name[]
Definition: cdr_mysql.c:74
void(* start)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:491
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
#define AST_CHANNEL_NAME
Definition: channel.h:172
XMPP Buddy.
Definition: xmpp.h:112
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct ast_endpoint * endpoint
Definition: xmpp.h:148
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:2192
struct ast_xmpp_client * connection
Definition: chan_motif.c:284
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
char remote[XMPP_MAX_JIDLEN]
Definition: chan_motif.c:308
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
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
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ao2_container * resources
Definition: xmpp.h:114
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
#define AST_CAUSE_INTERWORKING
Definition: causes.h:145
iksid * jid
Definition: xmpp.h:126
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:974
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
Handler function for the &#39;session-info&#39; action.
Definition: chan_motif.c:2498
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition: rtp_engine.c:458
static int jingle_endpoint_hash(const void *obj, const int flags)
Hashing function for Jingle endpoints.
Definition: chan_motif.c:526
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
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 char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:165
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
void ast_channel_callid_set(struct ast_channel *chan, ast_callid value)
struct aco_file jingle_conf
Definition: chan_motif.c:555
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
static struct ast_rtp_glue jingle_rtp_glue
Local glue for interacting with the RTP engine core.
Definition: chan_motif.c:648
struct ast_frame ast_null_frame
Definition: main/frame.c:79
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:1224
static void jingle_session_destructor(void *obj)
Destructor for Jingle sessions.
Definition: chan_motif.c:561
#define ACO_FILES(...)
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL
Definition: causes.h:124
#define SESSION_BUCKETS
Number of buckets for sessions, on a per-endpoint basis.
Definition: chan_motif.c:229
#define AST_CAUSE_NO_ROUTE_DESTINATION
Definition: causes.h:99
#define GOOGLE_VIDEO_NS
Namespace for Google Video description.
Definition: chan_motif.c:256
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
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2970
#define DEFAULT_MAX_PAYLOADS
Default maximum number of payloads we will offer.
Definition: chan_motif.c:223
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int ast_rtp_codecs_payloads_initialize(struct ast_rtp_codecs *codecs)
Initialize an RTP codecs structure.
Definition: rtp_engine.c:958
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
static int load_module(void)
Load the module.
Definition: chan_motif.c:2727
int ast_channel_hangupcause(const struct ast_channel *chan)
Type information about a category-level configurable object.
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
static struct ast_sched_context * sched
Definition: chan_motif.c:329
const char * filename
const char * reason
Definition: chan_motif.c:393
enum jingle_transport transport
Definition: chan_motif.c:304
char mid[6]
Definition: xmpp.h:125
static struct ast_channel * jingle_session_lock_full(struct jingle_session *pvt)
Definition: chan_motif.c:1148
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
Unregister RTP glue.
Definition: rtp_engine.c:408
#define ast_frfree(fr)
static void * jingle_config_alloc(void)
Allocator called when module configuration should appear.
Definition: chan_motif.c:598
static PGresult * result
Definition: cel_pgsql.c:88
static const char channel_type[]
Definition: chan_motif.c:321
Reason text <-> cause code mapping.
Definition: chan_motif.c:392
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:1238
int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
Determine if the address is an IPv4 address.
Definition: netsock2.c:497
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:1343
#define AST_CAUSE_BUSY
Definition: causes.h:148
unsigned int maxpayloads
Definition: chan_motif.c:306
Data structure associated with a single frame of data.
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
Internal Asterisk hangup causes.
const ast_string_field accountcode
Definition: chan_motif.c:283
Structure that represents the optional ICE support within an RTP engine.
Definition: rtp_engine.h:485
static struct ast_frame * jingle_read(struct ast_channel *ast)
Function called by core to read any waiting frames.
Definition: chan_motif.c:1640
Type for default option handler for stringfields.
struct ast_format_cap * peercap
Definition: chan_motif.c:315
static void jingle_send_session_initiate(struct jingle_session *session)
Internal function which sends a session-inititate message.
Definition: chan_motif.c:1512
enum jingle_transport transport
Definition: chan_motif.c:291
int error(const char *format,...)
Definition: utils/frame.c:999
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:705
union ast_frame::@263 data
ast_media_type
Types of media.
Definition: codec.h:30
enum ast_frame_type frametype
char x
Definition: extconf.c:81
struct ast_sockaddr address
Definition: rtp_engine.h:479
Generic container type.
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
struct ast_xmpp_client * ast_xmpp_client_find(const char *name)
Find an XMPP client connection using a given name.
Definition: res_xmpp.c:875
#define GOOGLE_SESSION_NS
Namespace for Google Session.
Definition: chan_motif.c:250
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
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
int ast_rtp_instance_dtmf_end_with_duration(struct ast_rtp_instance *instance, char digit, unsigned int duration)
Definition: rtp_engine.c:2109
struct ast_xmpp_capabilities caps
Definition: xmpp.h:97
struct ast_format * format
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_send_session_info(struct jingle_session *session, const char *info)
Internal function which sends a session-info message.
Definition: chan_motif.c:1098
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:465
const ast_string_field video_name
Definition: chan_motif.c:301
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define AST_CAUSE_CALL_REJECTED
Definition: causes.h:110
void ast_channel_priority_set(struct ast_channel *chan, int value)
iksrule * rule
Definition: chan_motif.c:309
Pluggable RTP Architecture.
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
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:2151
unsigned int maxicecandidates
Definition: chan_motif.c:286
#define AST_CAUSE_BEARERCAPABILITY_NOTAVAIL
Definition: causes.h:129
Asterisk module definitions.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
struct ao2_container * sessions
Definition: chan_motif.c:271
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
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:630
static snd_pcm_format_t format
Definition: chan_alsa.c:102
#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:1192
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
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 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
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:4391
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
char * description
Definition: xmpp.h:95
#define AST_CAUSE_CONGESTION
Definition: causes.h:152
iksrule * rule
Definition: chan_motif.c:285
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:615
#define JINGLE_NS
Namespace for Jingle itself.
Definition: chan_motif.c:232
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition: rtp_engine.c:578
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:331
static void jingle_config_destructor(void *obj)
Destructor called when module configuration goes away.
Definition: chan_motif.c:591
Media Format Cache API.
#define AST_APP_ARG(name)
Define an application argument.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1206
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static struct jingle_endpoint_state * jingle_endpoint_state_create(void)
Allocator function for Jingle endpoint state.
Definition: chan_motif.c:466
Channels have this property if they can create jitter; i.e. most VoIP channels.
Definition: channel.h:966
void(* ice_lite)(struct ast_rtp_instance *instance)
Definition: rtp_engine.h:501
#define ao2_link(container, obj)
Definition: astobj2.h:1549
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 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