Asterisk - The Open Source Telephony Project  21.4.1
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"
48 #include "asterisk/stasis_channels.h"
49 #include "asterisk/_private.h"
50 #include "asterisk/stasis_channels.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 
150 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *msg);
151 
152 /*!
153  * @{ \brief Define local channel message types.
154  */
156  .to_ami = local_message_to_ami,
157  );
159  .to_ami = local_message_to_ami,
160  );
162  .to_ami = local_message_to_ami,
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. */
199  LOCAL_CALL_ACTION_DIALPLAN,
200  /* The ast_call() will impart the ;2 channel into a bridge. */
201  LOCAL_CALL_ACTION_BRIDGE,
202  /* The ast_call() will masquerade the ;2 channel into a channel. */
203  LOCAL_CALL_ACTION_MASQUERADE,
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. */
226  /*! Additional action arguments */
227  union {
228  /*! Make ;2 join a bridge on ast_call(). */
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  context = strchr(exten, '@');
319  if (!context) {
320  ast_log(LOG_WARNING,
321  "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
322  return AST_DEVICE_INVALID;
323  }
324  *context++ = '\0';
325 
326  /* Strip options if they exist.
327  * However, don't strip '/' before an '@' (exten could contain slashes).
328  * So only start looking for '/' in context, because options would be past
329  * this point if they exist, but anything before would be a '/' in the exten,
330  * not options. */
331  opts = strchr(context, '/');
332  if (opts) {
333  *opts = '\0';
334  }
335 
336  it = ao2_iterator_init(locals, 0);
337  for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
338  ao2_lock(lp);
339  if (!strcmp(exten, lp->exten)
340  && !strcmp(context, lp->context)) {
341  res = AST_DEVICE_NOT_INUSE;
342  if (lp->base.owner
343  && ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
344  is_inuse = 1;
345  }
346  }
347  ao2_unlock(lp);
348  if (is_inuse) {
349  res = AST_DEVICE_INUSE;
350  ao2_ref(lp, -1);
351  break;
352  }
353  }
355 
356  if (res == AST_DEVICE_INVALID) {
357  ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
358  if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
359  res = AST_DEVICE_NOT_INUSE;
360  }
361  }
362 
363  return res;
364 }
365 
366 static struct ast_multi_channel_blob *local_channel_optimization_blob(struct local_pvt *p,
367  struct ast_json *json_object)
368 {
369  struct ast_multi_channel_blob *payload;
370  RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
371  RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
372 
373  local_one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.owner));
374  if (!local_one_snapshot) {
375  return NULL;
376  }
377 
378  local_two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.chan));
379  if (!local_two_snapshot) {
380  return NULL;
381  }
382 
383  payload = ast_multi_channel_blob_create(json_object);
384  if (!payload) {
385  return NULL;
386  }
387  ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
388  ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
389 
390  return payload;
391 }
392 
393 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_started */
394 static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct ast_channel *source,
395  enum ast_unreal_channel_indicator dest, unsigned int id)
396 {
397  RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
398  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
399  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
400  struct local_pvt *p = (struct local_pvt *)base;
401 
403  return;
404  }
405 
406  json_object = ast_json_pack("{s: i, s: I}",
407  "dest", dest, "id", (ast_json_int_t)id);
408 
409  if (!json_object) {
410  return;
411  }
412 
413  payload = local_channel_optimization_blob(p, json_object);
414  if (!payload) {
415  return;
416  }
417 
418  if (source) {
419  RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
420  source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
421  if (!source_snapshot) {
422  return;
423  }
424 
425  ast_multi_channel_blob_add_channel(payload, "source", source_snapshot);
426  }
427 
429  if (!msg) {
430  return;
431  }
432 
434 }
435 
436 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \p optimization_finished */
437 static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
438 {
439  RAII_VAR(struct ast_json *, json_object, ast_json_null(), ast_json_unref);
440  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
441  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
442  struct local_pvt *p = (struct local_pvt *)base;
443 
445  return;
446  }
447 
448  json_object = ast_json_pack("{s: i, s: I}", "success", success, "id", (ast_json_int_t)id);
449 
450  if (!json_object) {
451  return;
452  }
453 
454  payload = local_channel_optimization_blob(p, json_object);
455  if (!payload) {
456  return;
457  }
458 
460  if (!msg) {
461  return;
462  }
463 
465 }
466 
467 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *message)
468 {
469  struct ast_multi_channel_blob *obj = stasis_message_data(message);
470  struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
471  struct ast_channel_snapshot *local_snapshot_one;
472  struct ast_channel_snapshot *local_snapshot_two;
473  RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
474  RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
475  RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free);
476  const char *event;
477 
478  local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
479  local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
480  if (!local_snapshot_one || !local_snapshot_two) {
481  return NULL;
482  }
483 
484  event_buffer = ast_str_create(1024);
485  local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
486  local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
487  if (!event_buffer || !local_channel_one || !local_channel_two) {
488  return NULL;
489  }
490 
492  struct ast_channel_snapshot *source_snapshot;
493  RAII_VAR(struct ast_str *, source_str, NULL, ast_free);
494  const char *dest_uniqueid;
495 
496  source_snapshot = ast_multi_channel_blob_get_channel(obj, "source");
497  if (source_snapshot) {
498  source_str = ast_manager_build_channel_state_string_prefix(source_snapshot, "Source");
499  if (!source_str) {
500  return NULL;
501  }
502  }
503 
504  dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
505  local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
506 
507  event = "LocalOptimizationBegin";
508  if (source_str) {
509  ast_str_append(&event_buffer, 0, "%s", ast_str_buffer(source_str));
510  }
511  ast_str_append(&event_buffer, 0, "DestUniqueId: %s\r\n", dest_uniqueid);
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_optimization_end_type()) {
514  event = "LocalOptimizationEnd";
515  ast_str_append(&event_buffer, 0, "Success: %s\r\n", ast_json_integer_get(ast_json_object_get(blob, "success")) ? "Yes" : "No");
516  ast_str_append(&event_buffer, 0, "Id: %u\r\n", (unsigned int) ast_json_integer_get(ast_json_object_get(blob, "id")));
517  } else if (stasis_message_type(message) == ast_local_bridge_type()) {
518  event = "LocalBridge";
519  ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
520  ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
521  ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
522  } else {
523  return NULL;
524  }
525 
526  return ast_manager_event_blob_create(EVENT_FLAG_CALL, event,
527  "%s"
528  "%s"
529  "%s",
530  ast_str_buffer(local_channel_one),
531  ast_str_buffer(local_channel_two),
532  ast_str_buffer(event_buffer));
533 }
534 
535 /*!
536  * \internal
537  * \brief Post the \ref ast_local_bridge_type \ref stasis message
538  * \since 12.0.0
539  *
540  * \param p local_pvt to raise the local bridge message
541  */
542 static void publish_local_bridge_message(struct local_pvt *p)
543 {
544  RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
545  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
546  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
547  RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
548  RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
549  struct ast_channel *owner;
550  struct ast_channel *chan;
551 
552  if (!ast_local_bridge_type()) {
553  return;
554  }
555 
556  ast_unreal_lock_all(&p->base, &chan, &owner);
557 
558  blob = ast_json_pack("{s: s, s: s, s: b}",
559  "context", p->context,
560  "exten", p->exten,
561  "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
562  if (!blob) {
563  goto end;
564  }
565 
566  multi_blob = ast_multi_channel_blob_create(blob);
567  if (!multi_blob) {
568  goto end;
569  }
570 
571  one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(owner));
572  if (!one_snapshot) {
573  goto end;
574  }
575 
576  two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
577  if (!two_snapshot) {
578  goto end;
579  }
580 
581  ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
582  ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
583 
584  msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
585  if (!msg) {
586  goto end;
587  }
588 
589  stasis_publish(ast_channel_topic(owner), msg);
590 
591 end:
592  ast_channel_unlock(owner);
593  ast_channel_unref(owner);
594 
595  ast_channel_unlock(chan);
596  ast_channel_unref(chan);
597 
598  ao2_unlock(&p->base);
599 }
600 
601 int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
602 {
603  struct local_pvt *p;
604  struct local_pvt *found;
605  int res = -1;
606 
607  /* Sanity checks. */
608  if (!ast || !bridge) {
609  ast_bridge_features_destroy(features);
610  return -1;
611  }
612 
613  ast_channel_lock(ast);
614  p = ast_channel_tech_pvt(ast);
615  ast_channel_unlock(ast);
616 
617  found = p ? ao2_find(locals, p, 0) : NULL;
618  if (found) {
619  ao2_lock(found);
620  if (found->type == LOCAL_CALL_ACTION_DIALPLAN
621  && found->base.owner
622  && found->base.chan
623  && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
624  ao2_ref(bridge, +1);
625  if (swap) {
626  ast_channel_ref(swap);
627  }
628  found->type = LOCAL_CALL_ACTION_BRIDGE;
629  found->action.bridge.join = bridge;
630  found->action.bridge.swap = swap;
631  found->action.bridge.features = features;
632  res = 0;
633  } else {
634  ast_bridge_features_destroy(features);
635  }
636  ao2_unlock(found);
637  ao2_ref(found, -1);
638  }
639 
640  return res;
641 }
642 
644 {
645  struct local_pvt *p;
646  struct local_pvt *found;
647  int res = -1;
648 
649  /* Sanity checks. */
650  if (!ast || !masq) {
651  return -1;
652  }
653 
654  ast_channel_lock(ast);
655  p = ast_channel_tech_pvt(ast);
656  ast_channel_unlock(ast);
657 
658  found = p ? ao2_find(locals, p, 0) : NULL;
659  if (found) {
660  ao2_lock(found);
661  if (found->type == LOCAL_CALL_ACTION_DIALPLAN
662  && found->base.owner
663  && found->base.chan
664  && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
665  ast_channel_ref(masq);
666  found->type = LOCAL_CALL_ACTION_MASQUERADE;
667  found->action.masq = masq;
668  res = 0;
669  }
670  ao2_unlock(found);
671  ao2_ref(found, -1);
672  }
673 
674  return res;
675 }
676 
677 /*! \brief Initiate new call, part of PBX interface
678  * dest is the dial string */
679 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
680 {
681  struct local_pvt *p = ast_channel_tech_pvt(ast);
682  int pvt_locked = 0;
683 
684  struct ast_channel *owner = NULL;
685  struct ast_channel *chan = NULL;
686  int res;
687  char *reduced_dest = ast_strdupa(dest);
688  char *slash;
689  const char *chan_cid;
690 
691  if (!p) {
692  return -1;
693  }
694 
695  /* since we are letting go of channel locks that were locked coming into
696  * this function, then we need to give the tech pvt a ref */
697  ao2_ref(p, 1);
698  ast_channel_unlock(ast);
699 
700  ast_unreal_lock_all(&p->base, &chan, &owner);
701  pvt_locked = 1;
702 
703  if (owner != ast) {
704  res = -1;
705  goto return_cleanup;
706  }
707 
708  if (!owner || !chan) {
709  res = -1;
710  goto return_cleanup;
711  }
712 
713  ast_unreal_call_setup(owner, chan);
714 
715  /*
716  * If the local channel has /n on the end of it, we need to lop
717  * that off for our argument to setting up the CC_INTERFACES
718  * variable.
719  */
720  if ((slash = strrchr(reduced_dest, '/'))) {
721  *slash = '\0';
722  }
723  ast_set_cc_interfaces_chanvar(chan, reduced_dest);
724 
725  ao2_unlock(p);
726  pvt_locked = 0;
727 
728  ast_channel_unlock(owner);
729 
730  chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
731  ast_channel_caller(chan)->id.number.str, NULL);
732  if (chan_cid) {
733  chan_cid = ast_strdupa(chan_cid);
734  }
735  ast_channel_unlock(chan);
736 
737  res = -1;
738  switch (p->type) {
739  case LOCAL_CALL_ACTION_DIALPLAN:
740  if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
741  ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
742  p->exten, p->context);
743  } else {
744  publish_local_bridge_message(p);
745 
746  /* Start switch on sub channel */
747  res = ast_pbx_start(chan);
748  }
749  break;
750  case LOCAL_CALL_ACTION_BRIDGE:
751  publish_local_bridge_message(p);
752  ast_answer(chan);
753  res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
755  ao2_ref(p->action.bridge.join, -1);
756  p->action.bridge.join = NULL;
757  ao2_cleanup(p->action.bridge.swap);
758  p->action.bridge.swap = NULL;
759  p->action.bridge.features = NULL;
760  break;
761  case LOCAL_CALL_ACTION_MASQUERADE:
762  publish_local_bridge_message(p);
763  ast_answer(chan);
764  res = ast_channel_move(p->action.masq, chan);
765  if (!res) {
766  /* Chan is now an orphaned zombie. Destroy it. */
767  ast_hangup(chan);
768  }
770  break;
771  }
772  if (!res) {
773  ao2_lock(p);
774  ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
775  ao2_unlock(p);
776  }
777 
778  /* we already unlocked them, clear them here so the cleanup label won't touch them. */
779  owner = ast_channel_unref(owner);
780  chan = ast_channel_unref(chan);
781 
782 return_cleanup:
783  if (p) {
784  if (pvt_locked) {
785  ao2_unlock(p);
786  }
787  ao2_ref(p, -1);
788  }
789  if (chan) {
790  ast_channel_unlock(chan);
791  ast_channel_unref(chan);
792  }
793 
794  /*
795  * owner is supposed to be == to ast, if it is, don't unlock it
796  * because ast must exit locked
797  */
798  if (owner) {
799  if (owner != ast) {
800  ast_channel_unlock(owner);
801  ast_channel_lock(ast);
802  }
803  ast_channel_unref(owner);
804  } else {
805  /* we have to exit with ast locked */
806  ast_channel_lock(ast);
807  }
808 
809  return res;
810 }
811 
812 /*! \brief Hangup a call through the local proxy channel */
813 static int local_hangup(struct ast_channel *ast)
814 {
815  struct local_pvt *p = ast_channel_tech_pvt(ast);
816  int res;
817 
818  if (!p) {
819  return -1;
820  }
821 
822  /* give the pvt a ref to fulfill calling requirements. */
823  ao2_ref(p, +1);
824  res = ast_unreal_hangup(&p->base, ast);
825  if (!res) {
826  int unlink;
827 
828  ao2_lock(p);
829  unlink = !p->base.owner && !p->base.chan;
830  ao2_unlock(p);
831  if (unlink) {
832  ao2_unlink(locals, p);
833  }
834  }
835  ao2_ref(p, -1);
836 
837  return res;
838 }
839 
840 /*!
841  * \internal
842  * \brief struct local_pvt destructor.
843  *
844  * \param vdoomed Object to destroy.
845  */
846 static void local_pvt_destructor(void *vdoomed)
847 {
848  struct local_pvt *doomed = vdoomed;
849 
850  switch (doomed->type) {
851  case LOCAL_CALL_ACTION_DIALPLAN:
852  break;
853  case LOCAL_CALL_ACTION_BRIDGE:
854  ao2_cleanup(doomed->action.bridge.join);
855  ao2_cleanup(doomed->action.bridge.swap);
857  break;
858  case LOCAL_CALL_ACTION_MASQUERADE:
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  */
889  ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
890 
891  /* Look for options.
892  * Slashes can appear in channel names, so options are after the last match. */
893  if ((opts = strrchr(parse, '/'))) {
894  *opts++ = '\0';
895  if (strchr(opts, 'n')) {
896  ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
897  }
898  if (strchr(opts, 'j')) {
899  if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
900  ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
901  } else {
902  ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
903  }
904  }
905  if (strchr(opts, 'm')) {
906  ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
907  }
908  }
909 
910  /* Look for a context */
911  if ((context = strchr(parse, '@'))) {
912  *context++ = '\0';
913  }
914 
915  ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
916  ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
917  snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
918 
919  return pvt; /* this is returned with a ref */
920 }
921 
922 /*! \brief Part of PBX interface */
923 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)
924 {
925  struct ast_stream_topology *topology;
926  struct ast_channel *chan;
927 
929  if (!topology) {
930  return NULL;
931  }
932 
933  chan = local_request_with_stream_topology(type, topology, assignedids, requestor, data, cause);
934 
935  ast_stream_topology_free(topology);
936 
937  return chan;
938 }
939 
940 /*! \brief Part of PBX interface */
941 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)
942 {
943  struct ast_stream_topology *audio_filtered_topology;
944  int i;
945  struct local_pvt *p;
946  struct ast_channel *chan;
947  ast_callid callid;
948 
949  /* Create a copy of the requested topology as we don't have ownership over
950  * the one that is passed in.
951  */
952  audio_filtered_topology = ast_stream_topology_clone(topology);
953  if (!audio_filtered_topology) {
954  return NULL;
955  }
956 
957  /* Some users of Local channels request every known format in the
958  * universe. The core itself automatically pruned this list down to a single
959  * "best" format for audio in non-multistream. We replicate the logic here to
960  * do the same thing.
961  */
962  for (i = 0; i < ast_stream_topology_get_count(audio_filtered_topology); ++i) {
963  struct ast_stream *stream;
964  int res;
965  struct ast_format *tmp_fmt = NULL;
966  struct ast_format *best_audio_fmt = NULL;
967  struct ast_format_cap *caps;
968 
969  stream = ast_stream_topology_get_stream(audio_filtered_topology, i);
970 
971  if (ast_stream_get_type(stream) != AST_MEDIA_TYPE_AUDIO ||
973  continue;
974  }
975 
976  /* Respect the immutable state of formats on the stream and create a new
977  * format capabilities to replace the existing one.
978  */
980  if (!caps) {
981  ao2_ref(audio_filtered_topology, -1);
982  return NULL;
983  }
984 
985  /* The ast_translator_best_choice function treats both caps as const
986  * but does not declare it in the API.
987  */
989  &tmp_fmt, &best_audio_fmt);
990  if (res < 0) {
991  struct ast_str *tech_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
992  struct ast_str *request_codecs = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
993 
994  ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %s) to %s\n", type,
995  ast_format_cap_get_names(local_tech.capabilities, &tech_codecs),
996  ast_format_cap_get_names(ast_stream_get_formats(stream), &request_codecs));
997 
998  /* If there are no formats then we abort */
999  ao2_ref(caps, -1);
1000  ao2_ref(audio_filtered_topology, -1);
1001  return NULL;
1002  }
1003 
1004  ast_format_cap_append(caps, best_audio_fmt, 0);
1005  ast_stream_set_formats(stream, caps);
1006 
1007  ao2_ref(caps, -1);
1008  ao2_ref(tmp_fmt, -1);
1009  ao2_ref(best_audio_fmt, -1);
1010  }
1011 
1012  /* Allocate a new private structure and then Asterisk channels */
1013  p = local_alloc(data, audio_filtered_topology);
1014  ao2_ref(audio_filtered_topology, -1);
1015  if (!p) {
1016  return NULL;
1017  }
1018  callid = ast_read_threadstorage_callid();
1019  chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
1020  p->exten, p->context, assignedids, requestor, callid);
1021  if (chan) {
1022  ao2_link(locals, p);
1023  }
1024  ao2_ref(p, -1); /* kill the ref from the alloc */
1025 
1026  return chan;
1027 }
1028 
1029 
1030 /*! \brief CLI command "local show channels" */
1031 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1032 {
1033  struct local_pvt *p;
1034  struct ao2_iterator it;
1035 
1036  switch (cmd) {
1037  case CLI_INIT:
1038  e->command = "local show channels";
1039  e->usage =
1040  "Usage: local show channels\n"
1041  " Provides summary information on active local proxy channels.\n";
1042  return NULL;
1043  case CLI_GENERATE:
1044  return NULL;
1045  }
1046 
1047  if (a->argc != 3) {
1048  return CLI_SHOWUSAGE;
1049  }
1050 
1051  if (ao2_container_count(locals) == 0) {
1052  ast_cli(a->fd, "No local channels in use\n");
1053  return RESULT_SUCCESS;
1054  }
1055 
1056  it = ao2_iterator_init(locals, 0);
1057  while ((p = ao2_iterator_next(&it))) {
1058  ao2_lock(p);
1059  ast_cli(a->fd, "%s -- %s\n",
1060  p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
1061  p->base.name);
1062  ao2_unlock(p);
1063  ao2_ref(p, -1);
1064  }
1065  ao2_iterator_destroy(&it);
1066 
1067  return CLI_SUCCESS;
1068 }
1069 
1070 static struct ast_cli_entry cli_local[] = {
1071  AST_CLI_DEFINE(locals_show, "List status of local channels"),
1072 };
1073 
1074 static int manager_optimize_away(struct mansession *s, const struct message *m)
1075 {
1076  const char *channel;
1077  struct local_pvt *p;
1078  struct local_pvt *found;
1079  struct ast_channel *chan;
1080 
1081  channel = astman_get_header(m, "Channel");
1082  if (ast_strlen_zero(channel)) {
1083  astman_send_error(s, m, "'Channel' not specified.");
1084  return 0;
1085  }
1086 
1087  chan = ast_channel_get_by_name(channel);
1088  if (!chan) {
1089  astman_send_error(s, m, "Channel does not exist.");
1090  return 0;
1091  }
1092 
1093  p = ast_channel_tech_pvt(chan);
1094  ast_channel_unref(chan);
1095 
1096  found = p ? ao2_find(locals, p, 0) : NULL;
1097  if (found) {
1098  ao2_lock(found);
1099  ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
1100  ao2_unlock(found);
1101  ao2_ref(found, -1);
1102  astman_send_ack(s, m, "Queued channel to be optimized away");
1103  } else {
1104  astman_send_error(s, m, "Unable to find channel");
1105  }
1106 
1107  return 0;
1108 }
1109 
1110 
1111 static int locals_cmp_cb(void *obj, void *arg, int flags)
1112 {
1113  return (obj == arg) ? CMP_MATCH : 0;
1114 }
1115 
1116 /*!
1117  * \internal
1118  * \brief Shutdown the local proxy channel.
1119  * \since 12.0.0
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  }
1156  ast_format_cap_append_by_type(local_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
1157 
1158  locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
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));
1170  ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
1171 
1172  ast_register_cleanup(local_shutdown);
1173  return 0;
1174 }
1175 
1176 int local_setoption(struct ast_channel *ast, int option, void *data, int datalen)
1177 {
1178  switch (option) {
1180  case AST_OPTION_SECURE_MEDIA:
1181  return 0; /* local calls (like forwardings) are secure always */
1182  default:
1183  return ast_unreal_setoption(ast, option, data, datalen);
1184  }
1185 }
Struct containing info for an AMI event to send out.
Definition: manager.h:502
Main Channel structure associated with a channel.
Local proxy channel special access.
struct ast_channel_snapshot_base * base
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.
struct ast_flags flags
static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int success, unsigned int id)
Callback for ast_unreal_pvt_callbacks optimization_finished.
Definition: core_local.c:437
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
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
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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:570
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:1493
char context[AST_MAX_CONTEXT]
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
Definition: cli.h:171
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4708
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
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:846
int ast_json_is_true(const struct ast_json *value)
Check if value is JSON true.
Definition: json.c:263
Structure representing a snapshot of channel state.
#define AST_UNREAL_NO_OPTIMIZATION
Definition: core_unreal.h:108
Set when the stream has been removed/declined.
Definition: stream.h:78
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:1515
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:604
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:1139
#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:107
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
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2298
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
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
static int local_hangup(struct ast_channel *ast)
Hangup a call through the local proxy channel.
Definition: core_local.c:813
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:1160
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
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:10666
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:202
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:3674
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:10563
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:1402
Media Stream API.
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.
Definition: core_local.c:394
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
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:923
int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: core_unreal.c:369
Number structure.
Definition: app_followme.c:154
#define AST_UNREAL_MOH_INTERCEPT
Definition: core_unreal.h:109
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
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:601
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:1878
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 ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_unreal_destructor(void *vdoomed)
struct ast_unreal_pvt destructor.
Definition: core_unreal.c:1097
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:1031
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.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_bridge_features * features
Definition: core_local.c:213
#define AST_MAX_EXTENSION
Definition: channel.h:134
#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:87
In case you didn't read that giant block of text above the mansession_session struct, the 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:1785
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)
Add format capability to capabilities structure.
Definition: format_cap.h:99
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
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:941
#define ast_debug(level,...)
Log a DEBUG message.
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:4175
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:628
Core PBX routines and definitions.
struct ast_channel * chan
Definition: core_unreal.h:94
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:870
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:8057
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
Structure that contains information about a bridge.
Definition: bridge.h:349
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f)
Definition: core_unreal.c:318
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's private tech, unlock the given local channel's privat...
Definition: core_local.c:256
Support for dynamic strings.
Definition: strings.h:623
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:779
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
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.
union local_pvt::@342 action
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.
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
int ast_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:632
struct ast_bridge * bridge
int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: core_unreal.c:801
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's subscribers.
Definition: stasis.c:1511
#define AST_MAX_CONTEXT
Definition: channel.h:135
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:2541
static struct local_pvt * local_alloc(const char *data, struct ast_stream_topology *topology)
Create a call structure.
Definition: core_local.c:866
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:643
Prototypes for public functions only of internal interest,.
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.
const char * usage
Definition: cli.h:177
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
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:679
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's private tech, lock the local channel'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:2947
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...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
the local pvt structure for all channels
Definition: core_local.c:223
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:407
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
int ast_unreal_answer(struct ast_channel *ast)
Definition: core_unreal.c:254
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:1126
A multi channel blob data structure for multi_channel_blob stasis messages.
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
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.
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:1454
Bridging API.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
Callbacks that can be provided by concrete implementations of the unreal channel driver that will be ...
Definition: core_unreal.h:58
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
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:1018
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
char exten[AST_MAX_EXTENSION]
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:3633
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
Definition: core_unreal.c:824
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
Unreal channel derivative framework.