Fix documentation replication issues
[asterisk/asterisk.git] / main / core_local.c
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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 /* ------------------------------------------------------------------- */
39
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/manager.h"
44 #include "asterisk/devicestate.h"
45 #include "asterisk/astobj2.h"
46 #include "asterisk/bridge.h"
47 #include "asterisk/core_unreal.h"
48 #include "asterisk/core_local.h"
49 #include "asterisk/stasis.h"
50 #include "asterisk/stasis_channels.h"
51 #include "asterisk/_private.h"
52 #include "asterisk/stasis_channels.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                         </syntax>
100                         <see-also>
101                                 <ref type="managerEvent">LocalOptimizationEnd</ref>
102                                 <ref type="manager">LocalOptimizeAway</ref>
103                         </see-also>
104                 </managerEventInstance>
105         </managerEvent>
106         <managerEvent language="en_US" name="LocalOptimizationEnd">
107                 <managerEventInstance class="EVENT_FLAG_CALL">
108                         <synopsis>Raised when two halves of a Local Channel have finished optimizing
109                         themselves out of the media path.</synopsis>
110                         <syntax>
111                                 <channel_snapshot prefix="LocalOne"/>
112                                 <channel_snapshot prefix="LocalTwo"/>
113                         </syntax>
114                         <see-also>
115                                 <ref type="managerEvent">LocalOptimizationBegin</ref>
116                                 <ref type="manager">LocalOptimizeAway</ref>
117                         </see-also>
118                 </managerEventInstance>
119         </managerEvent>
120  ***/
121
122 static const char tdesc[] = "Local Proxy Channel Driver";
123
124 static struct ao2_container *locals;
125
126 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
127 static int local_call(struct ast_channel *ast, const char *dest, int timeout);
128 static int local_hangup(struct ast_channel *ast);
129 static int local_devicestate(const char *data);
130 static void local_optimization_started_cb(struct ast_unreal_pvt *base);
131 static void local_optimization_finished_cb(struct ast_unreal_pvt *base);
132
133 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *msg);
134
135 /*!
136  * @{ \brief Define local channel message types.
137  */
138 STASIS_MESSAGE_TYPE_DEFN(ast_local_bridge_type,
139         .to_ami = local_message_to_ami,
140         );
141 STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_begin_type,
142         .to_ami = local_message_to_ami,
143         );
144 STASIS_MESSAGE_TYPE_DEFN(ast_local_optimization_end_type,
145         .to_ami = local_message_to_ami,
146         );
147 /*! @} */
148
149 /*! \brief Callbacks from the unreal core when channel optimization occurs */
150 struct ast_unreal_pvt_callbacks local_unreal_callbacks = {
151         .optimization_started = local_optimization_started_cb,
152         .optimization_finished = local_optimization_finished_cb,
153 };
154
155 /* PBX interface structure for channel registration */
156 static struct ast_channel_tech local_tech = {
157         .type = "Local",
158         .description = tdesc,
159         .requester = local_request,
160         .send_digit_begin = ast_unreal_digit_begin,
161         .send_digit_end = ast_unreal_digit_end,
162         .call = local_call,
163         .hangup = local_hangup,
164         .answer = ast_unreal_answer,
165         .read = ast_unreal_read,
166         .write = ast_unreal_write,
167         .write_video = ast_unreal_write,
168         .exception = ast_unreal_read,
169         .indicate = ast_unreal_indicate,
170         .fixup = ast_unreal_fixup,
171         .send_html = ast_unreal_sendhtml,
172         .send_text = ast_unreal_sendtext,
173         .devicestate = local_devicestate,
174         .queryoption = ast_unreal_queryoption,
175         .setoption = ast_unreal_setoption,
176 };
177
178 /*! What to do with the ;2 channel when ast_call() happens. */
179 enum local_call_action {
180         /* The ast_call() will run dialplan on the ;2 channel. */
181         LOCAL_CALL_ACTION_DIALPLAN,
182         /* The ast_call() will impart the ;2 channel into a bridge. */
183         LOCAL_CALL_ACTION_BRIDGE,
184         /* The ast_call() will masquerade the ;2 channel into a channel. */
185         LOCAL_CALL_ACTION_MASQUERADE,
186 };
187
188 /*! Join a bridge on ast_call() parameters. */
189 struct local_bridge {
190         /*! Bridge to join. */
191         struct ast_bridge *join;
192         /*! Channel to swap with when joining bridge. */
193         struct ast_channel *swap;
194         /*! Features that are specific to this channel when pushed into the bridge. */
195         struct ast_bridge_features *features;
196 };
197
198 /*!
199  * \brief the local pvt structure for all channels
200  *
201  * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
202  *
203  * ast_chan owner -> local_pvt -> ast_chan chan
204  */
205 struct local_pvt {
206         /*! Unreal channel driver base class values. */
207         struct ast_unreal_pvt base;
208         /*! Additional action arguments */
209         union {
210                 /*! Make ;2 join a bridge on ast_call(). */
211                 struct local_bridge bridge;
212                 /*! Make ;2 masquerade into this channel on ast_call(). */
213                 struct ast_channel *masq;
214         } action;
215         /*! What to do with the ;2 channel on ast_call(). */
216         enum local_call_action type;
217         /*! Context to call */
218         char context[AST_MAX_CONTEXT];
219         /*! Extension to call */
220         char exten[AST_MAX_EXTENSION];
221 };
222
223 struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
224 {
225         struct local_pvt *p = ast_channel_tech_pvt(ast);
226         struct local_pvt *found;
227         struct ast_channel *peer;
228
229         if (!p) {
230                 return NULL;
231         }
232
233         found = p ? ao2_find(locals, p, 0) : NULL;
234         if (!found) {
235                 /* ast is either not a local channel or it has alredy been hungup */
236                 return NULL;
237         }
238         ao2_lock(found);
239         if (ast == p->base.owner) {
240                 peer = p->base.chan;
241         } else if (ast == p->base.chan) {
242                 peer = p->base.owner;
243         } else {
244                 peer = NULL;
245         }
246         if (peer) {
247                 ast_channel_ref(peer);
248         }
249         ao2_unlock(found);
250         ao2_ref(found, -1);
251         return peer;
252 }
253
254 /*! \brief Adds devicestate to local channels */
255 static int local_devicestate(const char *data)
256 {
257         int is_inuse = 0;
258         int res = AST_DEVICE_INVALID;
259         char *exten = ast_strdupa(data);
260         char *context;
261         char *opts;
262         struct local_pvt *lp;
263         struct ao2_iterator it;
264
265         /* Strip options if they exist */
266         opts = strchr(exten, '/');
267         if (opts) {
268                 *opts = '\0';
269         }
270
271         context = strchr(exten, '@');
272         if (!context) {
273                 ast_log(LOG_WARNING,
274                         "Someone used Local/%s somewhere without a @context. This is bad.\n", data);
275                 return AST_DEVICE_INVALID;
276         }
277         *context++ = '\0';
278
279         it = ao2_iterator_init(locals, 0);
280         for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
281                 ao2_lock(lp);
282                 if (!strcmp(exten, lp->exten)
283                         && !strcmp(context, lp->context)) {
284                         res = AST_DEVICE_NOT_INUSE;
285                         if (lp->base.owner
286                                 && ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
287                                 is_inuse = 1;
288                         }
289                 }
290                 ao2_unlock(lp);
291                 if (is_inuse) {
292                         res = AST_DEVICE_INUSE;
293                         ao2_ref(lp, -1);
294                         break;
295                 }
296         }
297         ao2_iterator_destroy(&it);
298
299         if (res == AST_DEVICE_INVALID) {
300                 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
301                 if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
302                         res = AST_DEVICE_NOT_INUSE;
303                 }
304         }
305
306         return res;
307 }
308
309 static void publish_local_optimization(struct local_pvt *p, int complete)
310 {
311         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
312         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
313         RAII_VAR(struct ast_json *, blob, ast_json_null(), ast_json_unref);
314         RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
315         RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
316
317         if (!blob) {
318                 return;
319         }
320
321         local_one_snapshot = ast_channel_snapshot_create(p->base.owner);
322         if (!local_one_snapshot) {
323                 return;
324         }
325
326         local_two_snapshot = ast_channel_snapshot_create(p->base.chan);
327         if (!local_two_snapshot) {
328                 return;
329         }
330
331         payload = ast_multi_channel_blob_create(blob);
332         if (!payload) {
333                 return;
334         }
335         ast_multi_channel_blob_add_channel(payload, "1", local_one_snapshot);
336         ast_multi_channel_blob_add_channel(payload, "2", local_two_snapshot);
337
338         msg = stasis_message_create(
339                         complete ? ast_local_optimization_end_type() : ast_local_optimization_begin_type(),
340                         payload);
341         if (!msg) {
342                 return;
343         }
344
345         stasis_publish(ast_channel_topic(p->base.owner), msg);
346
347 }
348
349 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_started_cb */
350 static void local_optimization_started_cb(struct ast_unreal_pvt *base)
351 {
352         struct local_pvt *p = (struct local_pvt *)base;
353         publish_local_optimization(p, 0);
354 }
355
356 /*! \brief Callback for \ref ast_unreal_pvt_callbacks \ref optimization_finished_cb */
357 static void local_optimization_finished_cb(struct ast_unreal_pvt *base)
358 {
359         struct local_pvt *p = (struct local_pvt *)base;
360         publish_local_optimization(p, 1);
361 }
362
363 static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message *message)
364 {
365         struct ast_multi_channel_blob *obj = stasis_message_data(message);
366         struct ast_json *blob = ast_multi_channel_blob_get_json(obj);
367         struct ast_channel_snapshot *local_snapshot_one;
368         struct ast_channel_snapshot *local_snapshot_two;
369         RAII_VAR(struct ast_str *, local_channel_one, NULL, ast_free);
370         RAII_VAR(struct ast_str *, local_channel_two, NULL, ast_free);
371         struct ast_str *event_buffer = ast_str_alloca(128);
372         const char *event;
373
374         local_snapshot_one = ast_multi_channel_blob_get_channel(obj, "1");
375         local_snapshot_two = ast_multi_channel_blob_get_channel(obj, "2");
376         if (!local_snapshot_one || !local_snapshot_two) {
377                 return NULL;
378         }
379
380         local_channel_one = ast_manager_build_channel_state_string_prefix(local_snapshot_one, "LocalOne");
381         local_channel_two = ast_manager_build_channel_state_string_prefix(local_snapshot_two, "LocalTwo");
382         if (!local_channel_one || !local_channel_two) {
383                 return NULL;
384         }
385
386         if (stasis_message_type(message) == ast_local_optimization_begin_type()) {
387                 event = "LocalOptimizationBegin";
388         } else if (stasis_message_type(message) == ast_local_optimization_end_type()) {
389                 event = "LocalOptimizationEnd";
390         } else if (stasis_message_type(message) == ast_local_bridge_type()) {
391                 event = "LocalBridge";
392                 ast_str_append(&event_buffer, 0, "Context: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "context")));
393                 ast_str_append(&event_buffer, 0, "Exten: %s\r\n", ast_json_string_get(ast_json_object_get(blob, "exten")));
394                 ast_str_append(&event_buffer, 0, "LocalOptimization: %s\r\n", ast_json_is_true(ast_json_object_get(blob, "can_optimize")) ? "Yes" : "No");
395         } else {
396                 return NULL;
397         }
398
399         return ast_manager_event_blob_create(EVENT_FLAG_CALL, event,
400                 "%s"
401                 "%s"
402                 "%s",
403                 ast_str_buffer(local_channel_one),
404                 ast_str_buffer(local_channel_two),
405                 ast_str_buffer(event_buffer));
406 }
407
408 /*!
409  * \internal
410  * \brief Post the \ref ast_local_bridge_type \ref stasis message
411  * \since 12.0.0
412  *
413  * \param p local_pvt to raise the local bridge message
414  *
415  * \return Nothing
416  */
417 static void publish_local_bridge_message(struct local_pvt *p)
418 {
419         RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
420         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
421         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
422         RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
423         RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
424         SCOPED_AO2LOCK(lock, p);
425
426         blob = ast_json_pack("{s: s, s: s, s: b}",
427                 "context", p->context,
428                 "exten", p->exten,
429                 "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
430         if (!blob) {
431                 return;
432         }
433
434         multi_blob = ast_multi_channel_blob_create(blob);
435         if (!multi_blob) {
436                 return;
437         }
438
439         one_snapshot = ast_channel_snapshot_create(p->base.owner);
440         if (!one_snapshot) {
441                 return;
442         }
443
444         two_snapshot = ast_channel_snapshot_create(p->base.chan);
445         if (!two_snapshot) {
446                 return;
447         }
448
449         ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
450         ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
451
452         msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
453         if (!msg) {
454                 return;
455         }
456
457         stasis_publish(ast_channel_topic(p->base.owner), msg);
458 }
459
460 int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
461 {
462         struct local_pvt *p;
463         struct local_pvt *found;
464         int res = -1;
465
466         /* Sanity checks. */
467         if (!ast || !bridge) {
468                 ast_bridge_features_destroy(features);
469                 return -1;
470         }
471
472         ast_channel_lock(ast);
473         p = ast_channel_tech_pvt(ast);
474         ast_channel_unlock(ast);
475
476         found = p ? ao2_find(locals, p, 0) : NULL;
477         if (found) {
478                 ao2_lock(found);
479                 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
480                         && found->base.owner
481                         && found->base.chan
482                         && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
483                         ao2_ref(bridge, +1);
484                         if (swap) {
485                                 ast_channel_ref(swap);
486                         }
487                         found->type = LOCAL_CALL_ACTION_BRIDGE;
488                         found->action.bridge.join = bridge;
489                         found->action.bridge.swap = swap;
490                         found->action.bridge.features = features;
491                         res = 0;
492                 } else {
493                         ast_bridge_features_destroy(features);
494                 }
495                 ao2_unlock(found);
496                 ao2_ref(found, -1);
497         }
498
499         return res;
500 }
501
502 int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
503 {
504         struct local_pvt *p;
505         struct local_pvt *found;
506         int res = -1;
507
508         /* Sanity checks. */
509         if (!ast || !masq) {
510                 return -1;
511         }
512
513         ast_channel_lock(ast);
514         p = ast_channel_tech_pvt(ast);
515         ast_channel_unlock(ast);
516
517         found = p ? ao2_find(locals, p, 0) : NULL;
518         if (found) {
519                 ao2_lock(found);
520                 if (found->type == LOCAL_CALL_ACTION_DIALPLAN
521                         && found->base.owner
522                         && found->base.chan
523                         && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
524                         ast_channel_ref(masq);
525                         found->type = LOCAL_CALL_ACTION_MASQUERADE;
526                         found->action.masq = masq;
527                         res = 0;
528                 }
529                 ao2_unlock(found);
530                 ao2_ref(found, -1);
531         }
532
533         return res;
534 }
535
536 /*! \brief Initiate new call, part of PBX interface
537  *         dest is the dial string */
538 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
539 {
540         struct local_pvt *p = ast_channel_tech_pvt(ast);
541         int pvt_locked = 0;
542
543         struct ast_channel *owner = NULL;
544         struct ast_channel *chan = NULL;
545         int res;
546         char *reduced_dest = ast_strdupa(dest);
547         char *slash;
548         const char *chan_cid;
549
550         if (!p) {
551                 return -1;
552         }
553
554         /* since we are letting go of channel locks that were locked coming into
555          * this function, then we need to give the tech pvt a ref */
556         ao2_ref(p, 1);
557         ast_channel_unlock(ast);
558
559         ast_unreal_lock_all(&p->base, &chan, &owner);
560         pvt_locked = 1;
561
562         if (owner != ast) {
563                 res = -1;
564                 goto return_cleanup;
565         }
566
567         if (!owner || !chan) {
568                 res = -1;
569                 goto return_cleanup;
570         }
571
572         ast_unreal_call_setup(owner, chan);
573
574         /*
575          * If the local channel has /n on the end of it, we need to lop
576          * that off for our argument to setting up the CC_INTERFACES
577          * variable.
578          */
579         if ((slash = strrchr(reduced_dest, '/'))) {
580                 *slash = '\0';
581         }
582         ast_set_cc_interfaces_chanvar(chan, reduced_dest);
583
584         ao2_unlock(p);
585         pvt_locked = 0;
586
587         ast_channel_unlock(owner);
588
589         chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
590                 ast_channel_caller(chan)->id.number.str, NULL);
591         if (chan_cid) {
592                 chan_cid = ast_strdupa(chan_cid);
593         }
594         ast_channel_unlock(chan);
595
596         res = -1;
597         switch (p->type) {
598         case LOCAL_CALL_ACTION_DIALPLAN:
599                 if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
600                         ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
601                                 p->exten, p->context);
602                 } else {
603                         publish_local_bridge_message(p);
604
605                         /* Start switch on sub channel */
606                         res = ast_pbx_start(chan);
607                 }
608                 break;
609         case LOCAL_CALL_ACTION_BRIDGE:
610                 publish_local_bridge_message(p);
611                 ast_answer(chan);
612                 res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
613                         p->action.bridge.features, 1);
614                 ao2_ref(p->action.bridge.join, -1);
615                 p->action.bridge.join = NULL;
616                 ao2_cleanup(p->action.bridge.swap);
617                 p->action.bridge.swap = NULL;
618                 p->action.bridge.features = NULL;
619                 break;
620         case LOCAL_CALL_ACTION_MASQUERADE:
621                 publish_local_bridge_message(p);
622                 ast_answer(chan);
623                 res = ast_channel_move(p->action.masq, chan);
624                 if (!res) {
625                         /* Chan is now an orphaned zombie.  Destroy it. */
626                         ast_hangup(chan);
627                 }
628                 p->action.masq = ast_channel_unref(p->action.masq);
629                 break;
630         }
631         if (!res) {
632                 ao2_lock(p);
633                 ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
634                 ao2_unlock(p);
635         }
636
637         /* we already unlocked them, clear them here so the cleanup label won't touch them. */
638         owner = ast_channel_unref(owner);
639         chan = ast_channel_unref(chan);
640
641 return_cleanup:
642         if (p) {
643                 if (pvt_locked) {
644                         ao2_unlock(p);
645                 }
646                 ao2_ref(p, -1);
647         }
648         if (chan) {
649                 ast_channel_unlock(chan);
650                 ast_channel_unref(chan);
651         }
652
653         /*
654          * owner is supposed to be == to ast, if it is, don't unlock it
655          * because ast must exit locked
656          */
657         if (owner) {
658                 if (owner != ast) {
659                         ast_channel_unlock(owner);
660                         ast_channel_lock(ast);
661                 }
662                 ast_channel_unref(owner);
663         } else {
664                 /* we have to exit with ast locked */
665                 ast_channel_lock(ast);
666         }
667
668         return res;
669 }
670
671 /*! \brief Hangup a call through the local proxy channel */
672 static int local_hangup(struct ast_channel *ast)
673 {
674         struct local_pvt *p = ast_channel_tech_pvt(ast);
675         int res;
676
677         if (!p) {
678                 return -1;
679         }
680
681         /* give the pvt a ref to fulfill calling requirements. */
682         ao2_ref(p, +1);
683         res = ast_unreal_hangup(&p->base, ast);
684         if (!res) {
685                 int unlink;
686
687                 ao2_lock(p);
688                 unlink = !p->base.owner && !p->base.chan;
689                 ao2_unlock(p);
690                 if (unlink) {
691                         ao2_unlink(locals, p);
692                 }
693         }
694         ao2_ref(p, -1);
695
696         return res;
697 }
698
699 /*!
700  * \internal
701  * \brief struct local_pvt destructor.
702  *
703  * \param vdoomed Object to destroy.
704  *
705  * \return Nothing
706  */
707 static void local_pvt_destructor(void *vdoomed)
708 {
709         struct local_pvt *doomed = vdoomed;
710
711         switch (doomed->type) {
712         case LOCAL_CALL_ACTION_DIALPLAN:
713                 break;
714         case LOCAL_CALL_ACTION_BRIDGE:
715                 ao2_cleanup(doomed->action.bridge.join);
716                 ao2_cleanup(doomed->action.bridge.swap);
717                 ast_bridge_features_destroy(doomed->action.bridge.features);
718                 break;
719         case LOCAL_CALL_ACTION_MASQUERADE:
720                 ao2_cleanup(doomed->action.masq);
721                 break;
722         }
723         ast_unreal_destructor(&doomed->base);
724 }
725
726 /*! \brief Create a call structure */
727 static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
728 {
729         struct local_pvt *pvt;
730         char *parse;
731         char *context;
732         char *opts;
733
734         pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);
735         if (!pvt) {
736                 return NULL;
737         }
738         pvt->base.callbacks = &local_unreal_callbacks;
739
740         parse = ast_strdupa(data);
741
742         /*
743          * Local channels intercept MOH by default.
744          *
745          * This is a silly default because it represents state held by
746          * the local channels.  Unless local channel optimization is
747          * disabled, the state will dissapear when the local channels
748          * optimize out.
749          */
750         ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
751
752         /* Look for options */
753         if ((opts = strchr(parse, '/'))) {
754                 *opts++ = '\0';
755                 if (strchr(opts, 'n')) {
756                         ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
757                 }
758                 if (strchr(opts, 'j')) {
759                         if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
760                                 ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
761                         } else {
762                                 ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
763                         }
764                 }
765                 if (strchr(opts, 'm')) {
766                         ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
767                 }
768         }
769
770         /* Look for a context */
771         if ((context = strchr(parse, '@'))) {
772                 *context++ = '\0';
773         }
774
775         ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
776         ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
777         snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
778
779         return pvt; /* this is returned with a ref */
780 }
781
782 /*! \brief Part of PBX interface */
783 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
784 {
785         struct local_pvt *p;
786         struct ast_channel *chan;
787         struct ast_callid *callid;
788
789         /* Allocate a new private structure and then Asterisk channels */
790         p = local_alloc(data, cap);
791         if (!p) {
792                 return NULL;
793         }
794         callid = ast_read_threadstorage_callid();
795         chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
796                 p->exten, p->context, requestor, callid);
797         if (chan) {
798                 ao2_link(locals, p);
799         }
800         if (callid) {
801                 ast_callid_unref(callid);
802         }
803         ao2_ref(p, -1); /* kill the ref from the alloc */
804
805         return chan;
806 }
807
808 /*! \brief CLI command "local show channels" */
809 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
810 {
811         struct local_pvt *p;
812         struct ao2_iterator it;
813
814         switch (cmd) {
815         case CLI_INIT:
816                 e->command = "local show channels";
817                 e->usage =
818                         "Usage: local show channels\n"
819                         "       Provides summary information on active local proxy channels.\n";
820                 return NULL;
821         case CLI_GENERATE:
822                 return NULL;
823         }
824
825         if (a->argc != 3) {
826                 return CLI_SHOWUSAGE;
827         }
828
829         if (ao2_container_count(locals) == 0) {
830                 ast_cli(a->fd, "No local channels in use\n");
831                 return RESULT_SUCCESS;
832         }
833
834         it = ao2_iterator_init(locals, 0);
835         while ((p = ao2_iterator_next(&it))) {
836                 ao2_lock(p);
837                 ast_cli(a->fd, "%s -- %s\n",
838                         p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
839                         p->base.name);
840                 ao2_unlock(p);
841                 ao2_ref(p, -1);
842         }
843         ao2_iterator_destroy(&it);
844
845         return CLI_SUCCESS;
846 }
847
848 static struct ast_cli_entry cli_local[] = {
849         AST_CLI_DEFINE(locals_show, "List status of local channels"),
850 };
851
852 static int manager_optimize_away(struct mansession *s, const struct message *m)
853 {
854         const char *channel;
855         struct local_pvt *p;
856         struct local_pvt *found;
857         struct ast_channel *chan;
858
859         channel = astman_get_header(m, "Channel");
860         if (ast_strlen_zero(channel)) {
861                 astman_send_error(s, m, "'Channel' not specified.");
862                 return 0;
863         }
864
865         chan = ast_channel_get_by_name(channel);
866         if (!chan) {
867                 astman_send_error(s, m, "Channel does not exist.");
868                 return 0;
869         }
870
871         p = ast_channel_tech_pvt(chan);
872         ast_channel_unref(chan);
873
874         found = p ? ao2_find(locals, p, 0) : NULL;
875         if (found) {
876                 ao2_lock(found);
877                 ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
878                 ao2_unlock(found);
879                 ao2_ref(found, -1);
880                 astman_send_ack(s, m, "Queued channel to be optimized away");
881         } else {
882                 astman_send_error(s, m, "Unable to find channel");
883         }
884
885         return 0;
886 }
887
888
889 static int locals_cmp_cb(void *obj, void *arg, int flags)
890 {
891         return (obj == arg) ? CMP_MATCH : 0;
892 }
893
894 /*!
895  * \internal
896  * \brief Shutdown the local proxy channel.
897  * \since 12.0.0
898  *
899  * \return Nothing
900  */
901 static void local_shutdown(void)
902 {
903         struct local_pvt *p;
904         struct ao2_iterator it;
905
906         /* First, take us out of the channel loop */
907         ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
908         ast_manager_unregister("LocalOptimizeAway");
909         ast_channel_unregister(&local_tech);
910
911         it = ao2_iterator_init(locals, 0);
912         while ((p = ao2_iterator_next(&it))) {
913                 if (p->base.owner) {
914                         ast_softhangup(p->base.owner, AST_SOFTHANGUP_APPUNLOAD);
915                 }
916                 ao2_ref(p, -1);
917         }
918         ao2_iterator_destroy(&it);
919         ao2_ref(locals, -1);
920         locals = NULL;
921
922         ast_format_cap_destroy(local_tech.capabilities);
923
924         STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_begin_type);
925         STASIS_MESSAGE_TYPE_CLEANUP(ast_local_optimization_end_type);
926         STASIS_MESSAGE_TYPE_CLEANUP(ast_local_bridge_type);
927 }
928
929 int ast_local_init(void)
930 {
931
932         if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_begin_type)) {
933                 return -1;
934         }
935
936         if (STASIS_MESSAGE_TYPE_INIT(ast_local_optimization_end_type)) {
937                 return -1;
938         }
939
940         if (STASIS_MESSAGE_TYPE_INIT(ast_local_bridge_type)) {
941                 return -1;
942         }
943
944         if (!(local_tech.capabilities = ast_format_cap_alloc())) {
945                 return -1;
946         }
947         ast_format_cap_add_all(local_tech.capabilities);
948
949         locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
950         if (!locals) {
951                 ast_format_cap_destroy(local_tech.capabilities);
952                 return -1;
953         }
954
955         /* Make sure we can register our channel type */
956         if (ast_channel_register(&local_tech)) {
957                 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
958                 ao2_ref(locals, -1);
959                 ast_format_cap_destroy(local_tech.capabilities);
960                 return -1;
961         }
962         ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
963         ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
964
965         ast_register_atexit(local_shutdown);
966         return 0;
967 }