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