Asterisk - The Open Source Telephony Project  GIT-master-c559667
core_local.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013 Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief Local proxy channel driver.
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  *
25  * See Also:
26  * \arg \ref AstCREDITS
27  */
28 
29 /*** MODULEINFO
30  <support_level>core</support_level>
31  ***/
32 
33 
34 #include "asterisk.h"
35 
36 /* ------------------------------------------------------------------- */
37 
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/manager.h"
42 #include "asterisk/devicestate.h"
43 #include "asterisk/astobj2.h"
44 #include "asterisk/bridge.h"
45 #include "asterisk/core_unreal.h"
46 #include "asterisk/core_local.h"
47 #include "asterisk/stasis.h"
49 #include "asterisk/_private.h"
51 #include "asterisk/stream.h"
52 #include "asterisk/translate.h"
53 
54 /*** DOCUMENTATION
55  <manager name="LocalOptimizeAway" language="en_US">
56  <synopsis>
57  Optimize away a local channel when possible.
58  </synopsis>
59  <syntax>
60  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
61  <parameter name="Channel" required="true">
62  <para>The channel name to optimize away.</para>
63  </parameter>
64  </syntax>
65  <description>
66  <para>A local channel created with "/n" will not automatically optimize away.
67  Calling this command on the local channel will clear that flag and allow
68  it to optimize away if it's bridged or when it becomes bridged.</para>
69  </description>
70  </manager>
71  <managerEvent language="en_US" name="LocalBridge">
72  <managerEventInstance class="EVENT_FLAG_CALL">
73  <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
74  <syntax>
75  <channel_snapshot prefix="LocalOne"/>
76  <channel_snapshot prefix="LocalTwo"/>
77  <parameter name="Context">
78  <para>The context in the dialplan that Channel2 starts in.</para>
79  </parameter>
80  <parameter name="Exten">
81  <para>The extension in the dialplan that Channel2 starts in.</para>
82  </parameter>
83  <parameter name="LocalOptimization">
84  <enumlist>
85  <enum name="Yes"/>
86  <enum name="No"/>
87  </enumlist>
88  </parameter>
89  </syntax>
90  </managerEventInstance>
91  </managerEvent>
92  <managerEvent language="en_US" name="LocalOptimizationBegin">
93  <managerEventInstance class="EVENT_FLAG_CALL">
94  <synopsis>Raised when two halves of a Local Channel begin to optimize
95  themselves out of the media path.</synopsis>
96  <syntax>
97  <channel_snapshot prefix="LocalOne"/>
98  <channel_snapshot prefix="LocalTwo"/>
99  <channel_snapshot prefix="Source"/>
100  <parameter name="DestUniqueId">
101  <para>The unique ID of the bridge into which the local channel is optimizing.</para>
102  </parameter>
103  <parameter name="Id">
104  <para>Identification for the optimization operation.</para>
105  </parameter>
106  </syntax>
107  <see-also>
108  <ref type="managerEvent">LocalOptimizationEnd</ref>
109  <ref type="manager">LocalOptimizeAway</ref>
110  </see-also>
111  </managerEventInstance>
112  </managerEvent>
113  <managerEvent language="en_US" name="LocalOptimizationEnd">
114  <managerEventInstance class="EVENT_FLAG_CALL">
115  <synopsis>Raised when two halves of a Local Channel have finished optimizing
116  themselves out of the media path.</synopsis>
117  <syntax>
118  <channel_snapshot prefix="LocalOne"/>
119  <channel_snapshot prefix="LocalTwo"/>
120  <parameter name="Success">
121  <para>Indicates whether the local optimization succeeded.</para>
122  </parameter>
123  <parameter name="Id">
124  <para>Identification for the optimization operation. Matches the <replaceable>Id</replaceable>
125  from a previous <literal>LocalOptimizationBegin</literal></para>
126  </parameter>
127  </syntax>
128  <see-also>
129  <ref type="managerEvent">LocalOptimizationBegin</ref>
130  <ref type="manager">LocalOptimizeAway</ref>
131  </see-also>
132  </managerEventInstance>
133  </managerEvent>
134  ***/
135 
136 static const char tdesc[] = "Local Proxy Channel Driver";
137 
138 static struct ao2_container *locals;
139 
140 static struct ast_channel *local_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);
141 static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
142 static int local_call(struct ast_channel *ast, const char *dest, int timeout);
143 static int local_hangup(struct ast_channel *ast);
144 static int local_devicestate(const char *data);
145 static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
146  enum ast_unreal_channel_indicator dest, unsigned int id);
147 static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id);
148 static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
149 
151 
152 /*!
153  * @{ \brief Define local channel message types.
154  */
157  );
160  );
163  );
164 /*! @} */
165 
166 /*! \brief Callbacks from the unreal core when channel optimization occurs */
169  .optimization_finished = local_optimization_finished_cb,
170 };
171 
172 /* PBX interface structure for channel registration */
173 static struct ast_channel_tech local_tech = {
174  .type = "Local",
175  .description = tdesc,
176  .requester = local_request,
177  .requester_with_stream_topology = local_request_with_stream_topology,
178  .send_digit_begin = ast_unreal_digit_begin,
179  .send_digit_end = ast_unreal_digit_end,
180  .call = local_call,
181  .hangup = local_hangup,
182  .answer = ast_unreal_answer,
183  .read_stream = ast_unreal_read,
184  .write = ast_unreal_write,
185  .write_stream = ast_unreal_write_stream,
186  .exception = ast_unreal_read,
187  .indicate = ast_unreal_indicate,
188  .fixup = ast_unreal_fixup,
189  .send_html = ast_unreal_sendhtml,
190  .send_text = ast_unreal_sendtext,
191  .devicestate = local_devicestate,
192  .queryoption = ast_unreal_queryoption,
193  .setoption = local_setoption,
194 };
195 
196 /*! What to do with the ;2 channel when ast_call() happens. */
198  /* The ast_call() will run dialplan on the ;2 channel. */
200  /* The ast_call() will impart the ;2 channel into a bridge. */
202  /* The ast_call() will masquerade the ;2 channel into a channel. */
204 };
205 
206 /*! Join a bridge on ast_call() parameters. */
207 struct local_bridge {
208  /*! Bridge to join. */
209  struct ast_bridge *join;
210  /*! Channel to swap with when joining bridge. */
211  struct ast_channel *swap;
212  /*! Features that are specific to this channel when pushed into the bridge. */
214 };
215 
216 /*!
217  * \brief the local pvt structure for all channels
218  *
219  * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
220  *
221  * ast_chan owner -> local_pvt -> ast_chan chan
222  */
223 struct local_pvt {
224  /*! Unreal channel driver base class values. */
225  struct ast_unreal_pvt base;
226  /*! Additional action arguments */
227  union {
228  /*! Make ;2 join a bridge on ast_call(). */
229  struct local_bridge bridge;
230  /*! Make ;2 masquerade into this channel on ast_call(). */
231  struct ast_channel *masq;
232  } action;
233  /*! What to do with the ;2 channel on ast_call(). */
235  /*! Context to call */
237  /*! Extension to call */
239 };
240 
241 void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt,
242  struct ast_channel **base_chan, struct ast_channel **base_owner)
243 {
244  struct local_pvt *p = ast_channel_tech_pvt(chan);
245 
246  *tech_pvt = NULL;
247  *base_chan = NULL;
248  *base_owner = NULL;
249 
250  if (p) {
251  *tech_pvt = ao2_bump(p);
252  ast_unreal_lock_all(&p->base, base_chan, base_owner);
253  }
254 }
255 
256 void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan,
257  struct ast_channel *base_owner)
258 {
259  if (base_chan) {
260  ast_channel_unlock(base_chan);
261  ast_channel_unref(base_chan);
262  }
263 
264  if (base_owner) {
265  ast_channel_unlock(base_owner);
266  ast_channel_unref(base_owner);
267  }
268 
269  if (tech_pvt) {
270  struct local_pvt *p = tech_pvt;
271  ao2_unlock(&p->base);
272  ao2_ref(tech_pvt, -1);
273  }
274 }
275 
277 {
278  struct local_pvt *p = ast_channel_tech_pvt(ast);
279  struct local_pvt *found;
280  struct ast_channel *peer;
281 
282  if (!p) {
283  return NULL;
284  }
285 
286  found = p ? ao2_find(locals, p, 0) : NULL;
287  if (!found) {
288  /* ast is either not a local channel or it has alredy been hungup */
289  return NULL;
290  }
291  ao2_lock(found);
292  if (ast == p->base.owner) {
293  peer = p->base.chan;
294  } else if (ast == p->base.chan) {
295  peer = p->base.owner;
296  } else {
297  peer = NULL;
298  }
299  if (peer) {
300  ast_channel_ref(peer);
301  }
302  ao2_unlock(found);
303  ao2_ref(found, -1);
304  return peer;
305 }
306 
307 /*! \brief Adds devicestate to local channels */
308 static int local_devicestate(const char *data)
309 {
310  int is_inuse = 0;
311  int res = AST_DEVICE_INVALID;
312  char *exten = ast_strdupa(data);
313  char *context;
314  char *opts;
315  struct local_pvt *lp;
316  struct ao2_iterator it;
317 
318  /* Strip options if they exist */
319  opts = strchr(exten, '/');
320  if (opts) {
321  *opts = '\0';
322  }
323 
324  context = strchr(exten, '@');
325  if (!context) {
327  "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
328  return AST_DEVICE_INVALID;
329  }
330  *context++ = '\0';
331 
332  it = ao2_iterator_init(locals, 0);
333  for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
334  ao2_lock(lp);
335  if (!strcmp(exten, lp->exten)
336  && !strcmp(context, lp->context)) {
337  res = AST_DEVICE_NOT_INUSE;
338  if (lp->base.owner
340  is_inuse = 1;
341  }
342  }
343  ao2_unlock(lp);
344  if (is_inuse) {
345  res = AST_DEVICE_INUSE;
346  ao2_ref(lp, -1);
347  break;
348  }
349  }
351 
352  if (res == AST_DEVICE_INVALID) {
353  ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
354  if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
355  res = AST_DEVICE_NOT_INUSE;
356  }
357  }
358 
359  return res;
360 }
361 
363  struct ast_json *json_object)
364 {
365  struct ast_multi_channel_blob *payload;
366  RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
367  RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
368 
370  if (!local_one_snapshot) {
371  return NULL;
372  }
373 
375  if (!local_two_snapshot) {
376  return NULL;
377  }
378 
379  payload = ast_multi_channel_blob_create(json_object);
380  if (!payload) {
381  return NULL;
382  }
383  ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
384  ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
385 
386  return payload;
387 }
388 
389 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_started_cb */
390 static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
391  enum ast_unreal_channel_indicator dest, unsigned int id)
392 {
393  RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
394  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
395  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
396  struct local_pvt *p = (struct local_pvt *)base;
397 
399  return;
400  }
401 
402  json_object = ast_json_pack("{s: i, s: I}",
403  "dest", dest, "id", (ast_json_int_t)id);
404 
405  if (!json_object) {
406  return;
407  }
408 
409  payload = local_channel_optimization_blob(p, json_object);
410  if (!payload) {
411  return;
412  }
413 
414  if (source) {
415  RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
416  source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
417  if (!source_snapshot) {
418  return;
419  }
420 
421  ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
422  }
423 
425  if (!msg) {
426  return;
427  }
428 
430 }
431 
432 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_finished_cb */
433 static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
434 {
435  RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
436  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
437  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
438  struct local_pvt *p = (struct local_pvt *)base;
439 
441  return;
442  }
443 
444  json_object = ast_json_pack("{s: i, s: I}", "success", success, "id", (ast_json_int_t)id);
445 
446  if (!json_object) {
447  return;
448  }
449 
450  payload = local_channel_optimization_blob(p, json_object);
451  if (!payload) {
452  return;
453  }
454 
456  if (!msg) {
457  return;
458  }
459 
461 }
462 
464 {
465  struct ast_multi_channel_blob *obj = stasis_message_data(message);
466  struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
467  struct ast_channel_snapshot *local_snapshot_one;
468  struct ast_channel_snapshot *local_snapshot_two;
469  RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
470  RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
471  RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
472  const char *event;
473 
474  local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
475  local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
476  if (!local_snapshot_one || !local_snapshot_two) {
477  return NULL;
478  }
479 
480  event_buffer = ast_str_create(1024);
481  local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
482  local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
483  if (!event_buffer || !local_channel_one || !local_channel_two) {
484  return NULL;
485  }
486 
488  struct ast_channel_snapshot *source_snapshot;
489  RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
490  const char *dest_uniqueid;
491 
492  source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
493  if (source_snapshot) {
494  source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
495  if (!source_str) {
496  return NULL;
497  }
498  }
499 
500  dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
501  local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
502 
503  event = "LocalOptimizationBegin";
504  if (source_str) {
505  ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
506  }
507  ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
508  ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
509  } else if (stasis_message_type(message) == ast_local_optimization_end_type()) {
510  event = "LocalOptimizationEnd";
511  ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
512  ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
513  } else if (stasis_message_type(message) == ast_local_bridge_type()) {
514  event = "LocalBridge";
515  ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
516  ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
517  ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
518  } else {
519  return NULL;
520  }
521 
523  "%s"
524  "%s"
525  "%s",
526  ast_str_buffer(local_channel_one),
527  ast_str_buffer(local_channel_two),
528  ast_str_buffer(event_buffer));
529 }
530 
531 /*!
532  * \internal
533  * \brief Post the \ref ast_local_bridge_type \ref stasis message
534  * \since 12.0.0
535  *
536  * \param p local_pvt to raise the local bridge message
537  *
538  * \return Nothing
539  */
541 {
542  RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
543  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
544  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
545  RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
546  RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
547  struct ast_channel *owner;
548  struct ast_channel *chan;
549 
550  if (!ast_local_bridge_type()) {
551  return;
552  }
553 
554  ast_unreal_lock_all(&p->base, &chan, &owner);
555 
556  blob = ast_json_pack("{s: s, s: s, s: b}",
557  "context", p->context,
558  "exten", p->exten,
559  "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
560  if (!blob) {
561  goto end;
562  }
563 
564  multi_blob = ast_multi_channel_blob_create(blob);
565  if (!multi_blob) {
566  goto end;
567  }
568 
570  if (!one_snapshot) {
571  goto end;
572  }
573 
575  if (!two_snapshot) {
576  goto end;
577  }
578 
579  ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
580  ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
581 
582  msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
583  if (!msg) {
584  goto end;
585  }
586 
587  stasis_publish(ast_channel_topic(owner), msg);
588 
589 end:
590  ast_channel_unlock(owner);
591  ast_channel_unref(owner);
592 
593  ast_channel_unlock(chan);
594  ast_channel_unref(chan);
595 
596  ao2_unlock(&p->base);
597 }
598 
600 {
601  struct local_pvt *p;
602  struct local_pvt *found;
603  int res = -1;
604 
605  /* Sanity checks. */
606  if (!ast || !bridge) {
607  ast_bridge_features_destroy(features);
608  return -1;
609  }
610 
611  ast_channel_lock(ast);
612  p = ast_channel_tech_pvt(ast);
613  ast_channel_unlock(ast);
614 
615  found = p ? ao2_find(locals, p, 0) : NULL;
616  if (found) {
617  ao2_lock(found);
618  if (found->type == LOCAL_CALL_ACTION_DIALPLAN
619  && found->base.owner
620  && found->base.chan
622  ao2_ref(bridge, +1);
623  if (swap) {
624  ast_channel_ref(swap);
625  }
627  found->action.bridge.join = bridge;
628  found->action.bridge.swap = swap;
629  found->action.bridge.features = features;
630  res = 0;
631  } else {
632  ast_bridge_features_destroy(features);
633  }
634  ao2_unlock(found);
635  ao2_ref(found, -1);
636  }
637 
638  return res;
639 }
640 
642 {
643  struct local_pvt *p;
644  struct local_pvt *found;
645  int res = -1;
646 
647  /* Sanity checks. */
648  if (!ast || !masq) {
649  return -1;
650  }
651 
652  ast_channel_lock(ast);
653  p = ast_channel_tech_pvt(ast);
654  ast_channel_unlock(ast);
655 
656  found = p ? ao2_find(locals, p, 0) : NULL;
657  if (found) {
658  ao2_lock(found);
659  if (found->type == LOCAL_CALL_ACTION_DIALPLAN
660  && found->base.owner
661  && found->base.chan
663  ast_channel_ref(masq);
665  found->action.masq = masq;
666  res = 0;
667  }
668  ao2_unlock(found);
669  ao2_ref(found, -1);
670  }
671 
672  return res;
673 }
674 
675 /*! \brief Initiate new call, part of PBX interface
676  * dest is the dial string */
677 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
678 {
679  struct local_pvt *p = ast_channel_tech_pvt(ast);
680  int pvt_locked = 0;
681 
682  struct ast_channel *owner = NULL;
683  struct ast_channel *chan = NULL;
684  int res;
685  char *reduced_dest = ast_strdupa(dest);
686  char *slash;
687  const char *chan_cid;
688 
689  if (!p) {
690  return -1;
691  }
692 
693  /* since we are letting go of channel locks that were locked coming into
694  * this function, then we need to give the tech pvt a ref */
695  ao2_ref(p, 1);
696  ast_channel_unlock(ast);
697 
698  ast_unreal_lock_all(&p->base, &chan, &owner);
699  pvt_locked = 1;
700 
701  if (owner != ast) {
702  res = -1;
703  goto return_cleanup;
704  }
705 
706  if (!owner || !chan) {
707  res = -1;
708  goto return_cleanup;
709  }
710 
711  ast_unreal_call_setup(owner, chan);
712 
713  /*
714  * If the local channel has /n on the end of it, we need to lop
715  * that off for our argument to setting up the CC_INTERFACES
716  * variable.
717  */
718  if ((slash = strrchr(reduced_dest, '/'))) {
719  *slash = '\0';
720  }
721  ast_set_cc_interfaces_chanvar(chan, reduced_dest);
722 
723  ao2_unlock(p);
724  pvt_locked = 0;
725 
726  ast_channel_unlock(owner);
727 
728  chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
729  ast_channel_caller(chan)->id.number.str, NULL);
730  if (chan_cid) {
731  chan_cid = ast_strdupa(chan_cid);
732  }
733  ast_channel_unlock(chan);
734 
735  res = -1;
736  switch (p->type) {
738  if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
739  ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
740  p->exten, p->context);
741  } else {
743 
744  /* Start switch on sub channel */
745  res = ast_pbx_start(chan);
746  }
747  break;
750  ast_answer(chan);
751  res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
753  ao2_ref(p->action.bridge.join, -1);
754  p->action.bridge.join = NULL;
756  p->action.bridge.swap = NULL;
757  p->action.bridge.features = NULL;
758  break;
761  ast_answer(chan);
762  res = ast_channel_move(p->action.masq, chan);
763  if (!res) {
764  /* Chan is now an orphaned zombie. Destroy it. */
765  ast_hangup(chan);
766  }
768  break;
769  }
770  if (!res) {
771  ao2_lock(p);
773  ao2_unlock(p);
774  }
775 
776  /* we already unlocked them, clear them here so the cleanup label won't touch them. */
777  owner = ast_channel_unref(owner);
778  chan = ast_channel_unref(chan);
779 
780 return_cleanup:
781  if (p) {
782  if (pvt_locked) {
783  ao2_unlock(p);
784  }
785  ao2_ref(p, -1);
786  }
787  if (chan) {
788  ast_channel_unlock(chan);
789  ast_channel_unref(chan);
790  }
791 
792  /*
793  * owner is supposed to be == to ast, if it is, don't unlock it
794  * because ast must exit locked
795  */
796  if (owner) {
797  if (owner != ast) {
798  ast_channel_unlock(owner);
799  ast_channel_lock(ast);
800  }
801  ast_channel_unref(owner);
802  } else {
803  /* we have to exit with ast locked */
804  ast_channel_lock(ast);
805  }
806 
807  return res;
808 }
809 
810 /*! \brief Hangup a call through the local proxy channel */
811 static int local_hangup(struct ast_channel *ast)
812 {
813  struct local_pvt *p = ast_channel_tech_pvt(ast);
814  int res;
815 
816  if (!p) {
817  return -1;
818  }
819 
820  /* give the pvt a ref to fulfill calling requirements. */
821  ao2_ref(p, +1);
822  res = ast_unreal_hangup(&p->base, ast);
823  if (!res) {
824  int unlink;
825 
826  ao2_lock(p);
827  unlink = !p->base.owner && !p->base.chan;
828  ao2_unlock(p);
829  if (unlink) {
830  ao2_unlink(locals, p);
831  }
832  }
833  ao2_ref(p, -1);
834 
835  return res;
836 }
837 
838 /*!
839  * \internal
840  * \brief struct local_pvt destructor.
841  *
842  * \param vdoomed Object to destroy.
843  *
844  * \return Nothing
845  */
846 static void local_pvt_destructor(void *vdoomed)
847 {
848  struct local_pvt *doomed = vdoomed;
849 
850  switch (doomed->type) {
852  break;
854  ao2_cleanup(doomed->action.bridge.join);
855  ao2_cleanup(doomed->action.bridge.swap);
857  break;
859  ao2_cleanup(doomed->action.masq);
860  break;
861  }
862  ast_unreal_destructor(&doomed->base);
863 }
864 
865 /*! \brief Create a call structure */
866 static struct local_pvt *local_alloc(const char *data, struct ast_stream_topology *topology)
867 {
868  struct local_pvt *pvt;
869  char *parse;
870  char *context;
871  char *opts;
872 
873  pvt = (struct local_pvt *) ast_unreal_alloc_stream_topology(sizeof(*pvt), local_pvt_destructor, topology);
874  if (!pvt) {
875  return NULL;
876  }
878 
879  parse = ast_strdupa(data);
880 
881  /*
882  * Local channels intercept MOH by default.
883  *
884  * This is a silly default because it represents state held by
885  * the local channels. Unless local channel optimization is
886  * disabled, the state will dissapear when the local channels
887  * optimize out.
888  */
890 
891  /* Look for options */
892  if ((opts = strchr(parse, '/'))) {
893  *opts++ = '\0';
894  if (strchr(opts, 'n')) {
896  }
897  if (strchr(opts, 'j')) {
900  } else {
901  ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
902  }
903  }
904  if (strchr(opts, 'm')) {
906  }
907  }
908 
909  /* Look for a context */
910  if ((context = strchr(parse, '@'))) {
911  *context++ = '\0';
912  }
913 
914  ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
915  ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
916  snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
917 
918  return pvt; /* this is returned with a ref */
919 }
920 
921 /*! \brief Part of PBX interface */
922 static struct ast_channel *local_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)
923 {
924  struct ast_stream_topology *topology;
925  struct ast_channel *chan;
926 
928  if (!topology) {
929  return NULL;
930  }
931 
932  chan = local_request_with_stream_topology(type, topology, assignedids, requestor, data, cause);
933 
934  ast_stream_topology_free(topology);
935 
936  return chan;
937 }
938 
939 /*! \brief Part of PBX interface */
940 static struct ast_channel *local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
941 {
942  struct ast_stream_topology *audio_filtered_topology;
943  int i;
944  struct local_pvt *p;
945  struct ast_channel *chan;
947 
948  /* Create a copy of the requested topology as we don't have ownership over
949  * the one that is passed in.
950  */
951  audio_filtered_topology = ast_stream_topology_clone(topology);
952  if (!audio_filtered_topology) {
953  return NULL;
954  }
955 
956  /* Some users of Local channels request every known format in the
957  * universe. The core itself automatically pruned this list down to a single
958  * "best" format for audio in non-multistream. We replicate the logic here to
959  * do the same thing.
960  */
961  for (i = 0; i < ast_stream_topology_get_count(audio_filtered_topology); ++i) {
962  struct ast_stream *stream;
963  int res;
964  struct ast_format *tmp_fmt = NULL;
965  struct ast_format *best_audio_fmt = NULL;
966  struct ast_format_cap *caps;
967 
968  stream = ast_stream_topology_get_stream(audio_filtered_topology, i);
969 
970  if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO) {
971  continue;
972  }
973 
974  /* Respect the immutable state of formats on the stream and create a new
975  * format capabilities to replace the existing one.
976  */
978  if (!caps) {
979  ao2_ref(audio_filtered_topology, -1);
980  return NULL;
981  }
982 
983  /* The ast_translator_best_choice function treats both caps as const
984  * but does not declare it in the API.
985  */
987  &tmp_fmt, &best_audio_fmt);
988  if (res < 0) {
989  struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
990  struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
991 
992  ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
993  ast_format_cap_get_names(local_tech.capabilities, &tech_codecs),
994  ast_format_cap_get_names(ast_stream_get_formats(stream), &request_codecs));
995 
996  /* If there are no formats then we abort */
997  ao2_ref(caps, -1);
998  ao2_ref(audio_filtered_topology, -1);
999  return NULL;
1000  }
1001 
1002  ast_format_cap_append(caps, best_audio_fmt, 0);
1003  ast_stream_set_formats(stream, caps);
1004 
1005  ao2_ref(caps, -1);
1006  ao2_ref(tmp_fmt, -1);
1007  ao2_ref(best_audio_fmt, -1);
1008  }
1009 
1010  /* Allocate a new private structure and then Asterisk channels */
1011  p = local_alloc(data, audio_filtered_topology);
1012  ao2_ref(audio_filtered_topology, -1);
1013  if (!p) {
1014  return NULL;
1015  }
1016  callid = ast_read_threadstorage_callid();
1017  chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
1018  p->exten, p->context, assignedids, requestor, callid);
1019  if (chan) {
1020  ao2_link(locals, p);
1021  }
1022  ao2_ref(p, -1); /* kill the ref from the alloc */
1023 
1024  return chan;
1025 }
1026 
1027 
1028 /*! \brief CLI command "local show channels" */
1029 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1030 {
1031  struct local_pvt *p;
1032  struct ao2_iterator it;
1033 
1034  switch (cmd) {
1035  case CLI_INIT:
1036  e->command = "local show channels";
1037  e->usage =
1038  "Usage: local show channels\n"
1039  " Provides summary information on active local proxy channels.\n";
1040  return NULL;
1041  case CLI_GENERATE:
1042  return NULL;
1043  }
1044 
1045  if (a->argc != 3) {
1046  return CLI_SHOWUSAGE;
1047  }
1048 
1049  if (ao2_container_count(locals) == 0) {
1050  ast_cli(a->fd, "No local channels in use\n");
1051  return RESULT_SUCCESS;
1052  }
1053 
1054  it = ao2_iterator_init(locals, 0);
1055  while ((p = ao2_iterator_next(&it))) {
1056  ao2_lock(p);
1057  ast_cli(a->fd, "%s -- %s\n",
1058  p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
1059  p->base.name);
1060  ao2_unlock(p);
1061  ao2_ref(p, -1);
1062  }
1063  ao2_iterator_destroy(&it);
1064 
1065  return CLI_SUCCESS;
1066 }
1067 
1068 static struct ast_cli_entry cli_local[] = {
1069  AST_CLI_DEFINE(locals_show, "List status of local channels"),
1070 };
1071 
1072 static int manager_optimize_away(struct mansession *s, const struct message *m)
1073 {
1074  const char *channel;
1075  struct local_pvt *p;
1076  struct local_pvt *found;
1077  struct ast_channel *chan;
1078 
1079  channel = astman_get_header(m, "Channel");
1080  if (ast_strlen_zero(channel)) {
1081  astman_send_error(s, m, "'Channel' not specified.");
1082  return 0;
1083  }
1084 
1085  chan = ast_channel_get_by_name(channel);
1086  if (!chan) {
1087  astman_send_error(s, m, "Channel does not exist.");
1088  return 0;
1089  }
1090 
1091  p = ast_channel_tech_pvt(chan);
1092  ast_channel_unref(chan);
1093 
1094  found = p ? ao2_find(locals, p, 0) : NULL;
1095  if (found) {
1096  ao2_lock(found);
1098  ao2_unlock(found);
1099  ao2_ref(found, -1);
1100  astman_send_ack(s, m, "Queued channel to be optimized away");
1101  } else {
1102  astman_send_error(s, m, "Unable to find channel");
1103  }
1104 
1105  return 0;
1106 }
1107 
1108 
1109 static int locals_cmp_cb(void *obj, void *arg, int flags)
1110 {
1111  return (obj == arg) ? CMP_MATCH : 0;
1112 }
1113 
1114 /*!
1115  * \internal
1116  * \brief Shutdown the local proxy channel.
1117  * \since 12.0.0
1118  *
1119  * \return Nothing
1120  */
1121 static void local_shutdown(void)
1122 {
1123  /* First, take us out of the channel loop */
1124  ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
1125  ast_manager_unregister("LocalOptimizeAway");
1126  ast_channel_unregister(&local_tech);
1127 
1128  ao2_ref(locals, -1);
1129  locals = NULL;
1130 
1131  ao2_cleanup(local_tech.capabilities);
1132  local_tech.capabilities = NULL;
1133 
1137 }
1138 
1140 {
1142  return -1;
1143  }
1144 
1146  return -1;
1147  }
1148 
1150  return -1;
1151  }
1152 
1154  return -1;
1155  }
1157 
1159  if (!locals) {
1160  return -1;
1161  }
1162 
1163  /* Make sure we can register our channel type */
1164  if (ast_channel_register(&local_tech)) {
1165  ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
1166 
1167  return -1;
1168  }
1169  ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
1171 
1173  return 0;
1174 }
1175 
1176 int local_setoption(struct ast_channel *ast, int option, void *data, int datalen)
1177 {
1178  switch (option) {
1181  return 0; /* local calls (like forwardings) are secure always */
1182  default:
1183  return ast_unreal_setoption(ast, option, data, datalen);
1184  }
1185 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static const char type[]
Definition: chan_ooh323.c:109
Struct containing info for an AMI event to send out.
Definition: manager.h:491
#define ast_channel_lock(chan)
Definition: channel.h:2890
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
Local proxy channel special access.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
const char *const type
Definition: channel.h:630
struct ast_channel_snapshot_base * base
static int manager_optimize_away(struct mansession *s, const struct message *m)
Definition: core_local.c:1072
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
Callback for ast_unreal_pvt_callbacks optimization_finished_cb.
Definition: core_local.c:433
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
static int locals_cmp_cb(void *obj, void *arg, int flags)
Definition: core_local.c:1109
char context[AST_MAX_CONTEXT]
Definition: core_local.c:236
Structure that contains features information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2926
#define ast_test_flag(p, flag)
Definition: utils.h:63
Device state management.
Support for translation of data formats. translate.c.
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition: core_local.c:276
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:566
struct ast_unreal_pvt_callbacks * callbacks
Definition: core_unreal.h:92
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
#define ast_set_flag(p, flag)
Definition: utils.h:70
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#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
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
static const char tdesc[]
Definition: core_local.c:136
static int timeout
Definition: cdr_mysql.c:86
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
struct ast_channel * owner
Definition: core_unreal.h:93
int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
Definition: core_unreal.c:756
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition: json.c:253
Structure representing a snapshot of channel state.
static struct ast_multi_channel_blob * local_channel_optimization_blob(struct local_pvt *p, struct ast_json *json_object)
Definition: core_local.c:362
#define AST_UNREAL_NO_OPTIMIZATION
Definition: core_unreal.h:106
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
struct ast_jb_conf jb_conf
Definition: core_unreal.h:96
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
#define EVENT_FLAG_CALL
Definition: manager.h:72
Definition: cli.h:152
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
struct ast_channel * swap
Definition: core_local.c:211
Definition: astman.c:222
Definition of a media format.
Definition: format.c:43
const ast_string_field uniqueid
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
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 AST_UNREAL_CARETAKER_THREAD
Definition: core_unreal.h:105
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct ast_stream_topology * ast_stream_topology_create_from_format_cap(struct ast_format_cap *cap)
A helper function that, given a format capabilities structure, creates a topology and separates the m...
Definition: stream.c:848
unsigned int ast_callid
Definition: logger.h:87
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define AST_OPTION_SECURE_MEDIA
#define ao2_unlock(a)
Definition: astobj2.h:730
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:535
Definition: muted.c:95
#define ast_str_alloca(init_len)
Definition: strings.h:800
static int local_hangup(struct ast_channel *ast)
Hangup a call through the local proxy channel.
Definition: core_local.c:811
struct ast_channel * ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, ast_callid callid)
Create the semi1 and semi2 unreal channels.
Definition: core_unreal.c:1068
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition: stream.c:788
int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
Definition: core_unreal.c:622
#define NULL
Definition: resample.c:96
const char * data
int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
Move a channel from its current location to a new location.
Definition: channel.c:10724
char * end
Definition: eagi_proxy.c:73
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Destroy an allocated bridge features struct.
Definition: bridge.c:3741
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj...
int ast_translator_best_choice(struct ast_format_cap *dst_cap, struct ast_format_cap *src_cap, struct ast_format **dst_fmt_out, struct ast_format **src_fmt_out)
Chooses the best translation path.
Definition: translate.c:1379
Media Stream API.
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:1932
static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source, enum ast_unreal_channel_indicator dest, unsigned int id)
Callback for ast_unreal_pvt_callbacks optimization_started_cb.
Definition: core_local.c:390
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static struct ast_channel * local_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)
Part of PBX interface.
Definition: core_local.c:922
int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: core_unreal.c:369
static struct ast_cli_entry cli_local[]
Definition: core_local.c:1068
Number structure.
Definition: app_followme.c:154
#define AST_UNREAL_MOH_INTERCEPT
Definition: core_unreal.h:107
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#define ao2_bump(obj)
Definition: astobj2.h:491
int ast_local_init(void)
Initialize the local proxy channel.
Definition: core_local.c:1139
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
Setup the outgoing local channel to join a bridge on ast_call().
Definition: core_local.c:599
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1924
General Asterisk PBX channel definitions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
struct ast_unreal_pvt base
Definition: core_local.c:225
void(*const optimization_started)(struct ast_unreal_pvt *p, struct ast_channel *source, enum ast_unreal_channel_indicator dest, unsigned int id)
Called when an optimization attempt has started.
Definition: core_unreal.h:69
#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:851
const int fd
Definition: cli.h:159
void ast_unreal_destructor(void *vdoomed)
struct ast_unreal_pvt destructor.
Definition: core_unreal.c:1007
static char * locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command "local show channels".
Definition: core_local.c:1029
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct ast_bridge_features * features
Definition: core_local.c:213
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: core_unreal.c:97
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
static struct ast_channel * local_request_with_stream_topology(const char *type, struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Part of PBX interface.
Definition: core_local.c:940
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition: stream.c:330
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
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
Core PBX routines and definitions.
struct ast_channel * chan
Definition: core_unreal.h:94
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
Setup unreal owner and chan channels before initiating call.
Definition: core_unreal.c:780
struct ast_unreal_pvt_callbacks local_unreal_callbacks
Callbacks from the unreal core when channel optimization occurs.
Definition: core_local.c:167
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
enum local_call_action type
Definition: core_local.c:234
local_call_action
Definition: core_local.c:197
static void publish_local_bridge_message(struct local_pvt *p)
Definition: core_local.c:540
Structure that contains information about a bridge.
Definition: bridge.h:357
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
Definition: core_unreal.c:318
#define LOG_ERROR
Definition: logger.h:285
void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan, struct ast_channel *base_owner)
Remove a reference to the given local channel&#39;s private tech, unlock the given local channel&#39;s privat...
Definition: core_local.c:256
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
int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
Definition: core_unreal.c:689
static struct ast_channel_tech local_tech
Definition: core_local.c:173
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define CLI_SHOWUSAGE
Definition: cli.h:45
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
char name[AST_MAX_EXTENSION+AST_MAX_CONTEXT+2]
Definition: core_unreal.h:99
The base pvt structure for local channel derivatives.
Definition: core_unreal.h:91
STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type,.to_ami=local_message_to_ami,)
Define local channel message types.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#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
int ast_unreal_write_stream(struct ast_channel *ast, int stream_num, struct ast_frame *f)
Definition: core_unreal.c:323
struct ast_format_cap * capabilities
Definition: channel.h:633
int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: core_unreal.c:711
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2891
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
struct ast_bridge * join
Definition: core_local.c:209
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1507
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define AST_OPTION_SECURE_SIGNALING
static int local_devicestate(const char *data)
Adds devicestate to local channels.
Definition: core_local.c:308
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2534
static struct local_pvt * local_alloc(const char *data, struct ast_stream_topology *topology)
Create a call structure.
Definition: core_local.c:866
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
struct ast_frame * ast_unreal_read(struct ast_channel *ast)
Definition: core_unreal.c:313
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
Setup the outgoing local channel to masquerade into a channel on ast_call().
Definition: core_local.c:641
Prototypes for public functions only of internal interest,.
ast_unreal_channel_indicator
Definition: core_unreal.h:49
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
struct stasis_message_type * ast_local_bridge_type(void)
Message type for when two local channel halves are bridged together.
#define ast_clear_flag(p, flag)
Definition: utils.h:77
const char * usage
Definition: cli.h:177
static struct ast_manager_event_blob * local_message_to_ami(struct stasis_message *msg)
Definition: core_local.c:463
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
#define CLI_SUCCESS
Definition: cli.h:44
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
Initiate new call, part of PBX interface dest is the dial string.
Definition: core_local.c:677
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt, struct ast_channel **base_chan, struct ast_channel **base_owner)
Add a reference to the local channel&#39;s private tech, lock the local channel&#39;s private base...
Definition: core_local.c:241
int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
Definition: core_unreal.c:166
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2915
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
union local_pvt::@370 action
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
the local pvt structure for all channels
Definition: core_local.c:223
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
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
int ast_unreal_answer(struct ast_channel *ast)
Definition: core_unreal.c:254
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_unreal_pvt * ast_unreal_alloc_stream_topology(size_t size, ao2_destructor_fn destructor, struct ast_stream_topology *topology)
Allocate the base unreal struct for a derivative.
Definition: core_unreal.c:1034
A multi channel blob data structure for multi_channel_blob stasis messages.
static void local_pvt_destructor(void *vdoomed)
Definition: core_local.c:846
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2800
char exten[AST_MAX_EXTENSION]
Definition: core_local.c:238
Abstract JSON element (object, array, string, int, ...).
struct ast_channel * masq
Definition: core_local.c:231
Generic container type.
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
static struct ao2_container * locals
Definition: core_local.c:138
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1450
Bridging API.
#define RESULT_SUCCESS
Definition: cli.h:40
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
Callbacks that can be provided by concrete implementations of the unreal channel driver that will be ...
Definition: core_unreal.h:58
static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen)
Definition: core_local.c:1176
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct local_bridge bridge
Definition: core_local.c:229
int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast)
Hangup one end (maybe both ends) of an unreal channel derivative.
Definition: core_unreal.c:928
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
Send an unreal pvt in with no locks held and get all locks.
Definition: core_unreal.c:47
int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char *const extension)
Set the CC_INTERFACES channel variable for a channel using an.
Definition: ccss.c:3668
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static void local_shutdown(void)
Definition: core_local.c:1121
int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
Definition: core_unreal.c:734
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549
Unreal channel derivative framework.