autoservice.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 415463 $")
00035
00036 #include <sys/time.h>
00037 #include <signal.h>
00038
00039 #include "asterisk/_private.h"
00040
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/frame.h"
00043 #include "asterisk/sched.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/translate.h"
00047 #include "asterisk/manager.h"
00048 #include "asterisk/chanvars.h"
00049 #include "asterisk/linkedlists.h"
00050 #include "asterisk/indications.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/utils.h"
00053
00054 #define MAX_AUTOMONS 1500
00055
00056 struct asent {
00057 struct ast_channel *chan;
00058
00059
00060
00061 unsigned int use_count;
00062 unsigned int orig_end_dtmf_flag:1;
00063 unsigned int ignore_frame_types;
00064
00065
00066
00067 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
00068 AST_LIST_ENTRY(asent) list;
00069 };
00070
00071 static AST_LIST_HEAD_STATIC(aslist, asent);
00072 static ast_cond_t as_cond;
00073
00074 static pthread_t asthread = AST_PTHREADT_NULL;
00075 static volatile int asexit = 0;
00076
00077 static int as_chan_list_state;
00078
00079 static void *autoservice_run(void *ign)
00080 {
00081 struct ast_frame hangup_frame = {
00082 .frametype = AST_FRAME_CONTROL,
00083 .subclass.integer = AST_CONTROL_HANGUP,
00084 };
00085
00086 while (!asexit) {
00087 struct ast_channel *mons[MAX_AUTOMONS];
00088 struct asent *ents[MAX_AUTOMONS];
00089 struct ast_channel *chan;
00090 struct asent *as;
00091 int i, x = 0, ms = 50;
00092 struct ast_frame *f = NULL;
00093 struct ast_frame *defer_frame = NULL;
00094
00095 AST_LIST_LOCK(&aslist);
00096
00097
00098
00099 as_chan_list_state++;
00100
00101 if (AST_LIST_EMPTY(&aslist)) {
00102 ast_cond_wait(&as_cond, &aslist.lock);
00103 }
00104
00105 AST_LIST_TRAVERSE(&aslist, as, list) {
00106 if (!ast_check_hangup(as->chan)) {
00107 if (x < MAX_AUTOMONS) {
00108 ents[x] = as;
00109 mons[x++] = as->chan;
00110 } else {
00111 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
00112 }
00113 }
00114 }
00115
00116 AST_LIST_UNLOCK(&aslist);
00117
00118 if (!x) {
00119
00120
00121
00122
00123 usleep(10000);
00124 continue;
00125 }
00126
00127 chan = ast_waitfor_n(mons, x, &ms);
00128 if (!chan) {
00129 continue;
00130 }
00131
00132 f = ast_read(chan);
00133
00134 if (!f) {
00135
00136
00137
00138
00139
00140
00141 defer_frame = &hangup_frame;
00142 } else if (ast_is_deferrable_frame(f)) {
00143 defer_frame = f;
00144 }
00145
00146 if (defer_frame) {
00147 for (i = 0; i < x; i++) {
00148 struct ast_frame *dup_f;
00149
00150 if (mons[i] != chan) {
00151 continue;
00152 }
00153
00154 if (defer_frame != f) {
00155 if ((dup_f = ast_frdup(defer_frame))) {
00156 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00157 }
00158 } else {
00159 if ((dup_f = ast_frisolate(defer_frame))) {
00160 if (dup_f != defer_frame) {
00161 ast_frfree(defer_frame);
00162 }
00163 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00164 }
00165 }
00166
00167 break;
00168 }
00169 } else if (f) {
00170 ast_frfree(f);
00171 }
00172 }
00173
00174 asthread = AST_PTHREADT_NULL;
00175
00176 return NULL;
00177 }
00178
00179 int ast_autoservice_start(struct ast_channel *chan)
00180 {
00181 int res = 0;
00182 struct asent *as;
00183
00184 AST_LIST_LOCK(&aslist);
00185 AST_LIST_TRAVERSE(&aslist, as, list) {
00186 if (as->chan == chan) {
00187 as->use_count++;
00188 break;
00189 }
00190 }
00191 AST_LIST_UNLOCK(&aslist);
00192
00193 if (as) {
00194
00195 return 0;
00196 }
00197
00198 if (!(as = ast_calloc(1, sizeof(*as))))
00199 return -1;
00200
00201
00202 as->chan = chan;
00203 as->use_count = 1;
00204
00205 ast_channel_lock(chan);
00206 as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00207 if (!as->orig_end_dtmf_flag)
00208 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00209 ast_channel_unlock(chan);
00210
00211 AST_LIST_LOCK(&aslist);
00212
00213 if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00214 ast_cond_signal(&as_cond);
00215 }
00216
00217 AST_LIST_INSERT_HEAD(&aslist, as, list);
00218
00219 if (asthread == AST_PTHREADT_NULL) {
00220 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00221 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00222
00223
00224 AST_LIST_REMOVE(&aslist, as, list);
00225 free(as);
00226 asthread = AST_PTHREADT_NULL;
00227 res = -1;
00228 } else {
00229 pthread_kill(asthread, SIGURG);
00230 }
00231 }
00232
00233 AST_LIST_UNLOCK(&aslist);
00234
00235 return res;
00236 }
00237
00238 int ast_autoservice_stop(struct ast_channel *chan)
00239 {
00240 int res = -1;
00241 struct asent *as, *removed = NULL;
00242 struct ast_frame *f;
00243 int chan_list_state;
00244
00245 AST_LIST_LOCK(&aslist);
00246
00247
00248
00249
00250
00251 chan_list_state = as_chan_list_state;
00252
00253
00254
00255 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
00256 if (as->chan == chan) {
00257 as->use_count--;
00258 if (as->use_count < 1) {
00259 AST_LIST_REMOVE_CURRENT(list);
00260 removed = as;
00261 }
00262 break;
00263 }
00264 }
00265 AST_LIST_TRAVERSE_SAFE_END;
00266
00267 if (removed && asthread != AST_PTHREADT_NULL) {
00268 pthread_kill(asthread, SIGURG);
00269 }
00270
00271 AST_LIST_UNLOCK(&aslist);
00272
00273 if (!removed) {
00274 return 0;
00275 }
00276
00277
00278 while (chan_list_state == as_chan_list_state) {
00279 usleep(1000);
00280 }
00281
00282
00283
00284
00285 if (!chan->_softhangup) {
00286 res = 0;
00287 }
00288
00289 if (!as->orig_end_dtmf_flag) {
00290 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00291 }
00292
00293 ast_channel_lock(chan);
00294 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00295 if (!((1 << f->frametype) & as->ignore_frame_types)) {
00296 ast_queue_frame_head(chan, f);
00297 }
00298 ast_frfree(f);
00299 }
00300 ast_channel_unlock(chan);
00301
00302 free(as);
00303
00304 return res;
00305 }
00306
00307 int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype)
00308 {
00309 struct asent *as;
00310 int res = -1;
00311
00312 AST_LIST_LOCK(&aslist);
00313 AST_LIST_TRAVERSE(&aslist, as, list) {
00314 if (as->chan == chan) {
00315 res = 0;
00316 as->ignore_frame_types |= (1 << ftype);
00317 break;
00318 }
00319 }
00320 AST_LIST_UNLOCK(&aslist);
00321 return res;
00322 }
00323
00324 static void autoservice_shutdown(void)
00325 {
00326 pthread_t th = asthread;
00327 asexit = 1;
00328 if (th != AST_PTHREADT_NULL) {
00329 ast_cond_signal(&as_cond);
00330 pthread_kill(th, SIGURG);
00331 pthread_join(th, NULL);
00332 }
00333 }
00334
00335 void ast_autoservice_init(void)
00336 {
00337 ast_register_cleanup(autoservice_shutdown);
00338 ast_cond_init(&as_cond, NULL);
00339 }