Bug #6116: Use list macros in autoservice.c (drumkilla)
[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 struct asent {
57         struct ast_channel *chan;
58         AST_LIST_ENTRY(asent) list;
59 };
60
61 static AST_LIST_HEAD_STATIC(aslist, asent);
62
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
74         for(;;) {
75                 x = 0;
76                 AST_LIST_LOCK(&aslist);
77                 AST_LIST_TRAVERSE(&aslist, as, list) {
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                 }
85                 AST_LIST_UNLOCK(&aslist);
86
87                 ms = 500;
88                 chan = ast_waitfor_n(mons, x, &ms);
89                 if (chan) {
90                         /* Read and ignore anything that occurs */
91                         f = ast_read(chan);
92                         if (f)
93                                 ast_frfree(f);
94                 }
95         }
96         asthread = AST_PTHREADT_NULL;
97         return NULL;
98 }
99
100 int ast_autoservice_start(struct ast_channel *chan)
101 {
102         int res = -1;
103         struct asent *as;
104         int needstart;
105         AST_LIST_LOCK(&aslist);
106
107         /* Check if autoservice thread is executing */
108         needstart = (asthread == AST_PTHREADT_NULL) ? 1 : 0 ;
109
110         /* Check if the channel already has autoservice */
111         AST_LIST_TRAVERSE(&aslist, as, list) {
112                 if (as->chan == chan)
113                         break;
114         }
115
116         /* If not, start autoservice on channel */
117         if (!as) {
118                 as = calloc(1, sizeof(struct asent));
119                 if (as) {
120                         as->chan = chan;
121                         AST_LIST_INSERT_HEAD(&aslist, as, list);
122                         res = 0;
123                         if (needstart) {
124                                 if (ast_pthread_create(&asthread, NULL, autoservice_run, NULL)) {
125                                         ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
126                                         /* There will only be a single member in the list at this point,
127                                            the one we just added. */
128                                         AST_LIST_REMOVE(&aslist, as, list);
129                                         free(as);
130                                         res = -1;
131                                 } else
132                                         pthread_kill(asthread, SIGURG);
133                         }
134                 }
135         }
136         AST_LIST_UNLOCK(&aslist);
137         return res;
138 }
139
140 int ast_autoservice_stop(struct ast_channel *chan)
141 {
142         int res = -1;
143         struct asent *as;
144
145         AST_LIST_LOCK(&aslist);
146         AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {       
147                 if (as->chan == chan) {
148                         AST_LIST_REMOVE_CURRENT(&aslist, list);
149                         free(as);
150                         if (!chan->_softhangup)
151                                 res = 0;
152                         break;
153                 }
154         }
155         AST_LIST_TRAVERSE_SAFE_END
156
157         if (asthread != AST_PTHREADT_NULL) 
158                 pthread_kill(asthread, SIGURG);
159         AST_LIST_UNLOCK(&aslist);
160
161         /* Wait for it to un-block */
162         while(ast_test_flag(chan, AST_FLAG_BLOCKING))
163                 usleep(1000);
164         return res;
165 }