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: 278272 $")
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.integer = 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 }