63e230e34ff65af05debffb212d7b323c9e448dc
[asterisk/asterisk.git] / channels / chan_local.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \author Mark Spencer <markster@digium.com>
22  *
23  * \brief Local Proxy Channel
24  * 
25  * \ingroup channel_drivers
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <fcntl.h>
39 #include <netdb.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <sys/signal.h>
43
44 #include "asterisk/lock.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/config.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/module.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/options.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/io.h"
54 #include "asterisk/rtp.h"
55 #include "asterisk/acl.h"
56 #include "asterisk/callerid.h"
57 #include "asterisk/file.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/app.h"
60 #include "asterisk/musiconhold.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/stringfields.h"
63 #include "asterisk/devicestate.h"
64
65 static const char tdesc[] = "Local Proxy Channel Driver";
66
67 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
68
69 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
70 static int local_digit_begin(struct ast_channel *ast, char digit);
71 static int local_digit_end(struct ast_channel *ast, char digit);
72 static int local_call(struct ast_channel *ast, char *dest, int timeout);
73 static int local_hangup(struct ast_channel *ast);
74 static int local_answer(struct ast_channel *ast);
75 static struct ast_frame *local_read(struct ast_channel *ast);
76 static int local_write(struct ast_channel *ast, struct ast_frame *f);
77 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
78 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
79 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
80 static int local_sendtext(struct ast_channel *ast, const char *text);
81 static int local_devicestate(void *data);
82
83 /* PBX interface structure for channel registration */
84 static const struct ast_channel_tech local_tech = {
85         .type = "Local",
86         .description = tdesc,
87         .capabilities = -1,
88         .requester = local_request,
89         .send_digit_begin = local_digit_begin,
90         .send_digit_end = local_digit_end,
91         .call = local_call,
92         .hangup = local_hangup,
93         .answer = local_answer,
94         .read = local_read,
95         .write = local_write,
96         .write_video = local_write,
97         .exception = local_read,
98         .indicate = local_indicate,
99         .fixup = local_fixup,
100         .send_html = local_sendhtml,
101         .send_text = local_sendtext,
102         .devicestate = local_devicestate,
103 };
104
105 struct local_pvt {
106         ast_mutex_t lock;                       /* Channel private lock */
107         unsigned int flags;                     /* Private flags */
108         char context[AST_MAX_CONTEXT];          /* Context to call */
109         char exten[AST_MAX_EXTENSION];          /* Extension to call */
110         int reqformat;                          /* Requested format */
111         struct ast_channel *owner;              /* Master Channel */
112         struct ast_channel *chan;               /* Outbound channel */
113         struct ast_module_user *u_owner;        /*! reference to keep the module loaded while in use */
114         struct ast_module_user *u_chan;         /*! reference to keep the module loaded while in use */
115         AST_LIST_ENTRY(local_pvt) list;         /* Next entity */
116 };
117
118 #define LOCAL_GLARE_DETECT    (1 << 0) /*!< Detect glare on hangup */
119 #define LOCAL_CANCEL_QUEUE    (1 << 1) /*!< Cancel queue */
120 #define LOCAL_ALREADY_MASQED  (1 << 2) /*!< Already masqueraded */
121 #define LOCAL_LAUNCHED_PBX    (1 << 3) /*!< PBX was launched */
122 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
123
124 static AST_LIST_HEAD_STATIC(locals, local_pvt);
125
126 /*! \brief Adds devicestate to local channels */
127 static int local_devicestate(void *data)
128 {
129         char *exten = ast_strdupa(data);
130         char *context = NULL;
131         int res;
132
133         if (!(context = strchr(exten, '@'))) {
134                 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
135                 return AST_DEVICE_INVALID;      
136         }
137
138         *context++ = '\0';
139
140         if (option_debug > 2)
141                 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
142         res = ast_exists_extension(NULL, context, exten, 1, NULL);
143         if (!res)               
144                 return AST_DEVICE_INVALID;
145         else
146                 return AST_DEVICE_UNKNOWN;
147 }
148
149 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
150 {
151         struct ast_channel *other = NULL;
152
153 retrylock:              
154
155         /* Recalculate outbound channel */
156         other = isoutbound ? p->owner : p->chan;
157
158         /* Set glare detection */
159         ast_set_flag(p, LOCAL_GLARE_DETECT);
160         if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
161                 /* We had a glare on the hangup.  Forget all this business,
162                 return and destroy p.  */
163                 ast_mutex_unlock(&p->lock);
164                 ast_mutex_destroy(&p->lock);
165                 free(p);
166                 return -1;
167         }
168         if (!other) {
169                 ast_clear_flag(p, LOCAL_GLARE_DETECT);
170                 return 0;
171         }
172         if (ast_mutex_trylock(&other->lock)) {
173                 /* Failed to lock.  Release main lock and try again */
174                 ast_mutex_unlock(&p->lock);
175                 if (us) {
176                         if (ast_mutex_unlock(&us->lock)) {
177                                 ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n",
178                                         us->name, f->frametype, f->subclass);
179                                 us = NULL;
180                         }
181                 }
182                 /* Wait just a bit */
183                 usleep(1);
184                 /* Only we can destroy ourselves, so we can't disappear here */
185                 if (us)
186                         ast_mutex_lock(&us->lock);
187                 ast_mutex_lock(&p->lock);
188                 goto retrylock;
189         }
190         ast_queue_frame(other, f);
191         ast_mutex_unlock(&other->lock);
192         ast_clear_flag(p, LOCAL_GLARE_DETECT);
193         return 0;
194 }
195
196 static int local_answer(struct ast_channel *ast)
197 {
198         struct local_pvt *p = ast->tech_pvt;
199         int isoutbound;
200         int res = -1;
201
202         ast_mutex_lock(&p->lock);
203         isoutbound = IS_OUTBOUND(ast, p);
204         if (isoutbound) {
205                 /* Pass along answer since somebody answered us */
206                 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
207                 res = local_queue_frame(p, isoutbound, &answer, ast);
208         } else
209                 ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
210         ast_mutex_unlock(&p->lock);
211         return res;
212 }
213
214 static void check_bridge(struct local_pvt *p, int isoutbound)
215 {
216         if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner)
217                 return;
218
219         /* only do the masquerade if we are being called on the outbound channel,
220            if it has been bridged to another channel and if there are no pending
221            frames on the owner channel (because they would be transferred to the
222            outbound channel during the masquerade)
223         */
224         if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
225                 /* Masquerade bridged channel into owner */
226                 /* Lock everything we need, one by one, and give up if
227                    we can't get everything.  Remember, we'll get another
228                    chance in just a little bit */
229                 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
230                         if (!p->chan->_bridge->_softhangup) {
231                                 if (!ast_mutex_trylock(&p->owner->lock)) {
232                                         if (!p->owner->_softhangup) {
233                                                 ast_channel_masquerade(p->owner, p->chan->_bridge);
234                                                 ast_set_flag(p, LOCAL_ALREADY_MASQED);
235                                         }
236                                         ast_mutex_unlock(&p->owner->lock);
237                                 }
238                                 ast_mutex_unlock(&(p->chan->_bridge)->lock);
239                         }
240                 }
241         /* We only allow masquerading in one 'direction'... it's important to preserve the state
242            (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
243            when the local channels go away.
244         */
245 #if 0
246         } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
247                 /* Masquerade bridged channel into chan */
248                 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
249                         if (!p->owner->_bridge->_softhangup) {
250                                 if (!ast_mutex_trylock(&p->chan->lock)) {
251                                         if (!p->chan->_softhangup) {
252                                                 ast_channel_masquerade(p->chan, p->owner->_bridge);
253                                                 ast_set_flag(p, LOCAL_ALREADY_MASQED);
254                                         }
255                                         ast_mutex_unlock(&p->chan->lock);
256                                 }
257                         }
258                         ast_mutex_unlock(&(p->owner->_bridge)->lock);
259                 }
260 #endif
261         }
262 }
263
264 static struct ast_frame  *local_read(struct ast_channel *ast)
265 {
266         return &ast_null_frame;
267 }
268
269 static int local_write(struct ast_channel *ast, struct ast_frame *f)
270 {
271         struct local_pvt *p = ast->tech_pvt;
272         int res = -1;
273         int isoutbound;
274
275         /* Just queue for delivery to the other side */
276         ast_mutex_lock(&p->lock);
277         isoutbound = IS_OUTBOUND(ast, p);
278         if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
279                 check_bridge(p, isoutbound);
280         if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
281                 res = local_queue_frame(p, isoutbound, f, ast);
282         else {
283                 if (option_debug)
284                         ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
285                 res = 0;
286         }
287         ast_mutex_unlock(&p->lock);
288         return res;
289 }
290
291 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
292 {
293         struct local_pvt *p = newchan->tech_pvt;
294         ast_mutex_lock(&p->lock);
295
296         if ((p->owner != oldchan) && (p->chan != oldchan)) {
297                 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
298                 ast_mutex_unlock(&p->lock);
299                 return -1;
300         }
301         if (p->owner == oldchan)
302                 p->owner = newchan;
303         else
304                 p->chan = newchan;
305         ast_mutex_unlock(&p->lock);
306         return 0;
307 }
308
309 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
310 {
311         struct local_pvt *p = ast->tech_pvt;
312         int res = -1;
313         struct ast_frame f = { AST_FRAME_CONTROL, };
314         int isoutbound;
315
316         /* Queue up a frame representing the indication as a control frame */
317         ast_mutex_lock(&p->lock);
318         isoutbound = IS_OUTBOUND(ast, p);
319         f.subclass = condition;
320         f.data = (void*)data;
321         f.datalen = datalen;
322         res = local_queue_frame(p, isoutbound, &f, ast);
323         ast_mutex_unlock(&p->lock);
324         return res;
325 }
326
327 static int local_digit_begin(struct ast_channel *ast, char digit)
328 {
329         struct local_pvt *p = ast->tech_pvt;
330         int res = -1;
331         struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
332         int isoutbound;
333
334         ast_mutex_lock(&p->lock);
335         isoutbound = IS_OUTBOUND(ast, p);
336         f.subclass = digit;
337         res = local_queue_frame(p, isoutbound, &f, ast);
338         ast_mutex_unlock(&p->lock);
339
340         return res;
341 }
342
343 static int local_digit_end(struct ast_channel *ast, char digit)
344 {
345         struct local_pvt *p = ast->tech_pvt;
346         int res = -1;
347         struct ast_frame f = { AST_FRAME_DTMF_END, };
348         int isoutbound;
349
350         ast_mutex_lock(&p->lock);
351         isoutbound = IS_OUTBOUND(ast, p);
352         f.subclass = digit;
353         res = local_queue_frame(p, isoutbound, &f, ast);
354         ast_mutex_unlock(&p->lock);
355         
356         return res;
357 }
358
359 static int local_sendtext(struct ast_channel *ast, const char *text)
360 {
361         struct local_pvt *p = ast->tech_pvt;
362         int res = -1;
363         struct ast_frame f = { AST_FRAME_TEXT, };
364         int isoutbound;
365
366         ast_mutex_lock(&p->lock);
367         isoutbound = IS_OUTBOUND(ast, p);
368         f.data = (char *) text;
369         f.datalen = strlen(text) + 1;
370         res = local_queue_frame(p, isoutbound, &f, ast);
371         ast_mutex_unlock(&p->lock);
372         return res;
373 }
374
375 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
376 {
377         struct local_pvt *p = ast->tech_pvt;
378         int res = -1;
379         struct ast_frame f = { AST_FRAME_HTML, };
380         int isoutbound;
381
382         ast_mutex_lock(&p->lock);
383         isoutbound = IS_OUTBOUND(ast, p);
384         f.subclass = subclass;
385         f.data = (char *)data;
386         f.datalen = datalen;
387         res = local_queue_frame(p, isoutbound, &f, ast);
388         ast_mutex_unlock(&p->lock);
389         return res;
390 }
391
392 /*! \brief Initiate new call, part of PBX interface 
393  *      dest is the dial string */
394 static int local_call(struct ast_channel *ast, char *dest, int timeout)
395 {
396         struct local_pvt *p = ast->tech_pvt;
397         int res;
398         struct ast_var_t *varptr = NULL, *new;
399         size_t len, namelen;
400         
401         ast_mutex_lock(&p->lock);
402
403         p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
404         p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
405         p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
406         p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
407         p->chan->cid.cid_pres = p->owner->cid.cid_pres;
408         ast_string_field_set(p->chan, language, p->owner->language);
409         ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
410         p->chan->cdrflags = p->owner->cdrflags;
411
412         /* copy the channel variables from the incoming channel to the outgoing channel */
413         /* Note that due to certain assumptions, they MUST be in the same order */
414         AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
415                 namelen = strlen(varptr->name);
416                 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
417                 if ((new = ast_calloc(1, len))) {
418                         memcpy(new, varptr, len);
419                         new->value = &(new->name[0]) + namelen + 1;
420                         AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
421                 }
422         }
423
424         ast_set_flag(p, LOCAL_LAUNCHED_PBX);
425
426         /* Start switch on sub channel */
427         res = ast_pbx_start(p->chan);
428         ast_mutex_unlock(&p->lock);
429         return res;
430 }
431
432 /*! \brief Hangup a call through the local proxy channel */
433 static int local_hangup(struct ast_channel *ast)
434 {
435         struct local_pvt *p = ast->tech_pvt;
436         int isoutbound;
437         struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
438         struct ast_channel *ochan = NULL;
439         int glaredetect = 0;
440
441         ast_mutex_lock(&p->lock);
442         isoutbound = IS_OUTBOUND(ast, p);
443         if (isoutbound) {
444                 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
445                 if ((status) && (p->owner))
446                         pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
447                 p->chan = NULL;
448                 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
449                 ast_module_user_remove(p->u_chan);
450         } else {
451                 p->owner = NULL;
452                 ast_module_user_remove(p->u_owner);
453         }
454         
455         ast->tech_pvt = NULL;
456         
457         if (!p->owner && !p->chan) {
458                 /* Okay, done with the private part now, too. */
459                 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
460                 /* If we have a queue holding, don't actually destroy p yet, but
461                    let local_queue do it. */
462                 if (glaredetect)
463                         ast_set_flag(p, LOCAL_CANCEL_QUEUE);
464                 ast_mutex_unlock(&p->lock);
465                 /* Remove from list */
466                 AST_LIST_LOCK(&locals);
467                 AST_LIST_REMOVE(&locals, p, list);
468                 AST_LIST_UNLOCK(&locals);
469                 /* Grab / release lock just in case */
470                 ast_mutex_lock(&p->lock);
471                 ast_mutex_unlock(&p->lock);
472                 /* And destroy */
473                 if (!glaredetect) {
474                         ast_mutex_destroy(&p->lock);
475                         free(p);
476                 }
477                 return 0;
478         }
479         if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
480                 /* Need to actually hangup since there is no PBX */
481                 ochan = p->chan;
482         else
483                 local_queue_frame(p, isoutbound, &f, NULL);
484         ast_mutex_unlock(&p->lock);
485         if (ochan)
486                 ast_hangup(ochan);
487         return 0;
488 }
489
490 /*! \brief Create a call structure */
491 static struct local_pvt *local_alloc(const char *data, int format)
492 {
493         struct local_pvt *tmp = NULL;
494         char *c = NULL, *opts = NULL;
495
496         if (!(tmp = ast_calloc(1, sizeof(*tmp))))
497                 return NULL;
498
499         /* Initialize private structure information */
500         ast_mutex_init(&tmp->lock);
501         ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
502
503         /* Look for options */
504         if ((opts = strchr(tmp->exten, '/'))) {
505                 *opts++ = '\0';
506                 if (strchr(opts, 'n'))
507                         ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
508         }
509
510         /* Look for a context */
511         if ((c = strchr(tmp->exten, '@')))
512                 *c++ = '\0';
513
514         ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
515
516         tmp->reqformat = format;
517
518         if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
519                 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
520                 ast_mutex_destroy(&tmp->lock);
521                 free(tmp);
522                 tmp = NULL;
523         } else {
524                 /* Add to list */
525                 AST_LIST_LOCK(&locals);
526                 AST_LIST_INSERT_HEAD(&locals, tmp, list);
527                 AST_LIST_UNLOCK(&locals);
528         }
529         
530         return tmp;
531 }
532
533 /*! \brief Start new local channel */
534 static struct ast_channel *local_new(struct local_pvt *p, int state)
535 {
536         struct ast_channel *tmp = NULL, *tmp2 = NULL;
537         int randnum = ast_random() & 0xffff, fmt = 0;
538
539         /* Allocate two new Asterisk channels */
540         if (!(tmp = ast_channel_alloc(1)) || !(tmp2 = ast_channel_alloc(1))) {
541                 if (tmp)
542                         ast_channel_free(tmp);
543                 if (tmp2)
544                         ast_channel_free(tmp2);
545                 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
546                 return NULL;
547         } 
548
549         tmp2->tech = tmp->tech = &local_tech;
550
551         tmp->nativeformats = p->reqformat;
552         tmp2->nativeformats = p->reqformat;
553
554         ast_string_field_build(tmp, name, "Local/%s@%s-%04x,1", p->exten, p->context, randnum);
555         ast_string_field_build(tmp2, name, "Local/%s@%s-%04x,2", p->exten, p->context, randnum);
556
557         ast_setstate(tmp, state);
558         ast_setstate(tmp2, AST_STATE_RING);
559
560         /* Determine our read/write format and set it on each channel */
561         fmt = ast_best_codec(p->reqformat);
562         tmp->writeformat = fmt;
563         tmp2->writeformat = fmt;
564         tmp->rawwriteformat = fmt;
565         tmp2->rawwriteformat = fmt;
566         tmp->readformat = fmt;
567         tmp2->readformat = fmt;
568         tmp->rawreadformat = fmt;
569         tmp2->rawreadformat = fmt;
570
571         tmp->tech_pvt = p;
572         tmp2->tech_pvt = p;
573
574         p->owner = tmp;
575         p->chan = tmp2;
576         p->u_owner = ast_module_user_add(p->owner);
577         p->u_chan = ast_module_user_add(p->chan);
578
579         ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
580         ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
581         ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
582         tmp->priority = 1;
583         tmp2->priority = 1;
584
585         return tmp;
586 }
587
588
589 /*! \brief Part of PBX interface */
590 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
591 {
592         struct local_pvt *p = NULL;
593         struct ast_channel *chan = NULL;
594
595         /* Allocate a new private structure and then Asterisk channel */
596         if ((p = local_alloc(data, format)))
597                 chan = local_new(p, AST_STATE_DOWN);
598
599         return chan;
600 }
601
602 /*! \brief CLI command "local show channels" */
603 static int locals_show(int fd, int argc, char **argv)
604 {
605         struct local_pvt *p = NULL;
606
607         if (argc != 3)
608                 return RESULT_SHOWUSAGE;
609
610         AST_LIST_LOCK(&locals);
611         if (!AST_LIST_EMPTY(&locals)) {
612                 AST_LIST_TRAVERSE(&locals, p, list) {
613                         ast_mutex_lock(&p->lock);
614                         ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
615                         ast_mutex_unlock(&p->lock);
616                 }
617         } else
618                 ast_cli(fd, "No local channels in use\n");
619         AST_LIST_UNLOCK(&locals);
620
621         return RESULT_SUCCESS;
622 }
623
624 static char show_locals_usage[] = 
625 "Usage: local list channels\n"
626 "       Provides summary information on active local proxy channels.\n";
627
628 static struct ast_cli_entry cli_local[] = {
629         { { "local", "list", "channels", NULL },
630         locals_show, "List status of local channels",
631         show_locals_usage },
632 };
633
634 /*! \brief Load module into PBX, register channel */
635 static int load_module(void)
636 {
637         /* Make sure we can register our channel type */
638         if (ast_channel_register(&local_tech)) {
639                 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
640                 return -1;
641         }
642         ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
643         return 0;
644 }
645
646 /*! \brief Unload the local proxy channel from Asterisk */
647 static int unload_module(void)
648 {
649         struct local_pvt *p = NULL;
650
651         /* First, take us out of the channel loop */
652         ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
653         ast_channel_unregister(&local_tech);
654         if (!AST_LIST_LOCK(&locals)) {
655                 /* Hangup all interfaces if they have an owner */
656                 AST_LIST_TRAVERSE(&locals, p, list) {
657                         if (p->owner)
658                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
659                 }
660                 AST_LIST_UNLOCK(&locals);
661                 AST_LIST_HEAD_DESTROY(&locals);
662         } else {
663                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
664                 return -1;
665         }               
666         return 0;
667 }
668
669 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel");