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 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 278167 $")
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <sys/time.h>
00036 #include <signal.h>
00037 #include <errno.h>
00038 #include <unistd.h>
00039
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/frame.h"
00042 #include "asterisk/sched.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/translate.h"
00048 #include "asterisk/manager.h"
00049 #include "asterisk/chanvars.h"
00050 #include "asterisk/linkedlists.h"
00051 #include "asterisk/indications.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/utils.h"
00054
00055 #define MAX_AUTOMONS 1500
00056
00057 struct asent {
00058 struct ast_channel *chan;
00059
00060
00061
00062 unsigned int use_count;
00063 unsigned int orig_end_dtmf_flag:1;
00064 unsigned int ignore_frame_types;
00065
00066
00067
00068 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
00069 AST_LIST_ENTRY(asent) list;
00070 };
00071
00072 static AST_LIST_HEAD_STATIC(aslist, asent);
00073 static ast_cond_t as_cond;
00074
00075 static pthread_t asthread = AST_PTHREADT_NULL;
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 = AST_CONTROL_HANGUP,
00084 };
00085
00086 for (;;) {
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 (!as->chan->_softhangup) {
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
00185 AST_LIST_LOCK(&aslist);
00186 AST_LIST_TRAVERSE(&aslist, as, list) {
00187 if (as->chan == chan) {
00188 as->use_count++;
00189 break;
00190 }
00191 }
00192 AST_LIST_UNLOCK(&aslist);
00193
00194 if (as) {
00195
00196 return 0;
00197 }
00198
00199 if (!(as = ast_calloc(1, sizeof(*as))))
00200 return -1;
00201
00202
00203 as->chan = chan;
00204 as->use_count = 1;
00205
00206 ast_channel_lock(chan);
00207 as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00208 if (!as->orig_end_dtmf_flag)
00209 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00210 ast_channel_unlock(chan);
00211
00212 AST_LIST_LOCK(&aslist);
00213
00214 if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00215 ast_cond_signal(&as_cond);
00216 }
00217
00218 AST_LIST_INSERT_HEAD(&aslist, as, list);
00219
00220 if (asthread == AST_PTHREADT_NULL) {
00221 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00222 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00223
00224
00225 AST_LIST_REMOVE(&aslist, as, list);
00226 free(as);
00227 asthread = AST_PTHREADT_NULL;
00228 res = -1;
00229 } else {
00230 pthread_kill(asthread, SIGURG);
00231 }
00232 }
00233
00234 AST_LIST_UNLOCK(&aslist);
00235
00236 return res;
00237 }
00238
00239 int ast_autoservice_stop(struct ast_channel *chan)
00240 {
00241 int res = -1;
00242 struct asent *as, *removed = NULL;
00243 struct ast_frame *f;
00244 int chan_list_state;
00245
00246 AST_LIST_LOCK(&aslist);
00247
00248
00249
00250
00251
00252 chan_list_state = as_chan_list_state;
00253
00254
00255
00256 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
00257 if (as->chan == chan) {
00258 as->use_count--;
00259 if (as->use_count < 1) {
00260 AST_LIST_REMOVE_CURRENT(&aslist, list);
00261 removed = as;
00262 }
00263 break;
00264 }
00265 }
00266 AST_LIST_TRAVERSE_SAFE_END
00267
00268 if (removed && asthread != AST_PTHREADT_NULL) {
00269 pthread_kill(asthread, SIGURG);
00270 }
00271
00272 AST_LIST_UNLOCK(&aslist);
00273
00274 if (!removed) {
00275 return 0;
00276 }
00277
00278
00279 while (chan_list_state == as_chan_list_state) {
00280 usleep(1000);
00281 }
00282
00283
00284
00285
00286 if (!chan->_softhangup) {
00287 res = 0;
00288 }
00289
00290 if (!as->orig_end_dtmf_flag) {
00291 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00292 }
00293
00294 ast_channel_lock(chan);
00295 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00296 if (!((1 << f->frametype) & as->ignore_frame_types)) {
00297 ast_queue_frame_head(chan, f);
00298 }
00299 ast_frfree(f);
00300 }
00301 ast_channel_unlock(chan);
00302
00303 free(as);
00304
00305 return res;
00306 }
00307
00308 int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype)
00309 {
00310 struct asent *as;
00311 int res = -1;
00312
00313 AST_LIST_LOCK(&aslist);
00314 AST_LIST_TRAVERSE(&aslist, as, list) {
00315 if (as->chan == chan) {
00316 res = 0;
00317 as->ignore_frame_types |= (1 << ftype);
00318 break;
00319 }
00320 }
00321 AST_LIST_UNLOCK(&aslist);
00322 return res;
00323 }
00324
00325 void ast_autoservice_init(void)
00326 {
00327 ast_cond_init(&as_cond, NULL);
00328 }