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