7dcec2a8c29fccea4ae8d91ec21fdb9048e0d23d
[asterisk/asterisk.git] / autoservice.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 /*
20  *
21  * Automatic channel service routines
22  * 
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <signal.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <math.h>                       /* For PI */
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/pbx.h"
39 #include "asterisk/frame.h"
40 #include "asterisk/sched.h"
41 #include "asterisk/options.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/file.h"
45 #include "asterisk/translate.h"
46 #include "asterisk/manager.h"
47 #include "asterisk/chanvars.h"
48 #include "asterisk/linkedlists.h"
49 #include "asterisk/indications.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/utils.h"
52
53 #define MAX_AUTOMONS 256
54
55 AST_MUTEX_DEFINE_STATIC(autolock);
56
57 struct asent {
58         struct ast_channel *chan;
59         struct asent *next;
60 };
61
62 static struct asent *aslist = NULL;
63 static pthread_t asthread = AST_PTHREADT_NULL;
64
65 static void *autoservice_run(void *ign)
66 {
67         struct ast_channel *mons[MAX_AUTOMONS];
68         int x;
69         int ms;
70         struct ast_channel *chan;
71         struct asent *as;
72         struct ast_frame *f;
73         for(;;) {
74                 x = 0;
75                 ast_mutex_lock(&autolock);
76                 as = aslist;
77                 while(as) {
78                         if (!as->chan->_softhangup) {
79                                 if (x < MAX_AUTOMONS)
80                                         mons[x++] = as->chan;
81                                 else
82                                         ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events.  Fix autoservice.c\n");
83                         }
84                         as = as->next;
85                 }
86                 ast_mutex_unlock(&autolock);
87
88 /*              if (!aslist)
89                         break; */
90                 ms = 500;
91                 chan = ast_waitfor_n(mons, x, &ms);
92                 if (chan) {
93                         /* Read and ignore anything that occurs */
94                         f = ast_read(chan);
95                         if (f)
96                                 ast_frfree(f);
97                 }
98         }
99         asthread = AST_PTHREADT_NULL;
100         return NULL;
101 }
102
103 int ast_autoservice_start(struct ast_channel *chan)
104 {
105         int res = -1;
106         struct asent *as;
107         int needstart;
108         ast_mutex_lock(&autolock);
109         needstart = (asthread == AST_PTHREADT_NULL) ? 1 : 0 /* aslist ? 0 : 1 */;
110         as = aslist;
111         while(as) {
112                 if (as->chan == chan)
113                         break;
114                 as = as->next;
115         }
116         if (!as) {
117                 as = malloc(sizeof(struct asent));
118                 if (as) {
119                         memset(as, 0, sizeof(struct asent));
120                         as->chan = chan;
121                         as->next = aslist;
122                         aslist = as;
123                         res = 0;
124                         if (needstart) {
125                                 if (ast_pthread_create(&asthread, NULL, autoservice_run, NULL)) {
126                                         ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
127                                         free(aslist);
128                                         aslist = NULL;
129                                         res = -1;
130                                 } else
131                                         pthread_kill(asthread, SIGURG);
132                         }
133                 }
134         }
135         ast_mutex_unlock(&autolock);
136         return res;
137 }
138
139 int ast_autoservice_stop(struct ast_channel *chan)
140 {
141         int res = -1;
142         struct asent *as, *prev;
143         ast_mutex_lock(&autolock);
144         as = aslist;
145         prev = NULL;
146         while(as) {
147                 if (as->chan == chan)
148                         break;
149                 prev = as;
150                 as = as->next;
151         }
152         if (as) {
153                 if (prev)
154                         prev->next = as->next;
155                 else
156                         aslist = as->next;
157                 free(as);
158                 if (!chan->_softhangup)
159                         res = 0;
160         }
161         if (asthread != AST_PTHREADT_NULL) 
162                 pthread_kill(asthread, SIGURG);
163         ast_mutex_unlock(&autolock);
164         /* Wait for it to un-block */
165         while(ast_test_flag(chan, AST_FLAG_BLOCKING))
166                 usleep(1000);
167         return res;
168 }