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: 415464 $")
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_callid *callid = NULL;
00082 struct ast_frame hangup_frame = {
00083 .frametype = AST_FRAME_CONTROL,
00084 .subclass.integer = AST_CONTROL_HANGUP,
00085 };
00086
00087 while (!asexit) {
00088 struct ast_channel *mons[MAX_AUTOMONS];
00089 struct asent *ents[MAX_AUTOMONS];
00090 struct ast_channel *chan;
00091 struct asent *as;
00092 int i, x = 0, ms = 50;
00093 struct ast_frame *f = NULL;
00094 struct ast_frame *defer_frame = NULL;
00095
00096 AST_LIST_LOCK(&aslist);
00097
00098
00099
00100 as_chan_list_state++;
00101
00102 if (AST_LIST_EMPTY(&aslist)) {
00103 ast_cond_wait(&as_cond, &aslist.lock);
00104 }
00105
00106 AST_LIST_TRAVERSE(&aslist, as, list) {
00107 if (!ast_check_hangup(as->chan)) {
00108 if (x < MAX_AUTOMONS) {
00109 ents[x] = as;
00110 mons[x++] = as->chan;
00111 } else {
00112 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
00113 }
00114 }
00115 }
00116
00117 AST_LIST_UNLOCK(&aslist);
00118
00119 if (!x) {
00120
00121
00122
00123
00124 usleep(10000);
00125 continue;
00126 }
00127
00128 chan = ast_waitfor_n(mons, x, &ms);
00129 if (!chan) {
00130 continue;
00131 }
00132
00133 callid = ast_channel_callid(chan);
00134 ast_callid_threadassoc_change(callid);
00135 if (callid) {
00136 callid = ast_callid_unref(callid);
00137 }
00138
00139 f = ast_read(chan);
00140
00141 if (!f) {
00142
00143
00144
00145
00146
00147
00148 defer_frame = &hangup_frame;
00149 } else if (ast_is_deferrable_frame(f)) {
00150 defer_frame = f;
00151 }
00152
00153 if (defer_frame) {
00154 for (i = 0; i < x; i++) {
00155 struct ast_frame *dup_f;
00156
00157 if (mons[i] != chan) {
00158 continue;
00159 }
00160
00161 if (defer_frame != f) {
00162 if ((dup_f = ast_frdup(defer_frame))) {
00163 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00164 }
00165 } else {
00166 if ((dup_f = ast_frisolate(defer_frame))) {
00167 if (dup_f != defer_frame) {
00168 ast_frfree(defer_frame);
00169 }
00170 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00171 }
00172 }
00173
00174 break;
00175 }
00176 } else if (f) {
00177 ast_frfree(f);
00178 }
00179 }
00180
00181 ast_callid_threadassoc_change(NULL);
00182 asthread = AST_PTHREADT_NULL;
00183
00184 return NULL;
00185 }
00186
00187 int ast_autoservice_start(struct ast_channel *chan)
00188 {
00189 int res = 0;
00190 struct asent *as;
00191
00192 AST_LIST_LOCK(&aslist);
00193 AST_LIST_TRAVERSE(&aslist, as, list) {
00194 if (as->chan == chan) {
00195 as->use_count++;
00196 break;
00197 }
00198 }
00199 AST_LIST_UNLOCK(&aslist);
00200
00201 if (as) {
00202
00203 return 0;
00204 }
00205
00206 if (!(as = ast_calloc(1, sizeof(*as))))
00207 return -1;
00208
00209
00210 as->chan = chan;
00211 as->use_count = 1;
00212
00213 ast_channel_lock(chan);
00214 as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00215 if (!as->orig_end_dtmf_flag)
00216 ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
00217 ast_channel_unlock(chan);
00218
00219 AST_LIST_LOCK(&aslist);
00220
00221 if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00222 ast_cond_signal(&as_cond);
00223 }
00224
00225 AST_LIST_INSERT_HEAD(&aslist, as, list);
00226
00227 if (asthread == AST_PTHREADT_NULL) {
00228 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00229 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00230
00231
00232 AST_LIST_REMOVE(&aslist, as, list);
00233 free(as);
00234 asthread = AST_PTHREADT_NULL;
00235 res = -1;
00236 } else {
00237 pthread_kill(asthread, SIGURG);
00238 }
00239 }
00240
00241 AST_LIST_UNLOCK(&aslist);
00242
00243 return res;
00244 }
00245
00246 int ast_autoservice_stop(struct ast_channel *chan)
00247 {
00248 int res = -1;
00249 struct asent *as, *removed = NULL;
00250 struct ast_frame *f;
00251 int chan_list_state;
00252
00253 AST_LIST_LOCK(&aslist);
00254
00255
00256
00257
00258
00259 chan_list_state = as_chan_list_state;
00260
00261
00262
00263 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
00264 if (as->chan == chan) {
00265 as->use_count--;
00266 if (as->use_count < 1) {
00267 AST_LIST_REMOVE_CURRENT(list);
00268 removed = as;
00269 }
00270 break;
00271 }
00272 }
00273 AST_LIST_TRAVERSE_SAFE_END;
00274
00275 if (removed && asthread != AST_PTHREADT_NULL) {
00276 pthread_kill(asthread, SIGURG);
00277 }
00278
00279 AST_LIST_UNLOCK(&aslist);
00280
00281 if (!removed) {
00282 return 0;
00283 }
00284
00285
00286 while (chan_list_state == as_chan_list_state) {
00287 usleep(1000);
00288 }
00289
00290
00291
00292
00293 if (!ast_channel_softhangup_internal_flag(chan)) {
00294 res = 0;
00295 }
00296
00297 if (!as->orig_end_dtmf_flag) {
00298 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
00299 }
00300
00301 ast_channel_lock(chan);
00302 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00303 if (!((1 << f->frametype) & as->ignore_frame_types)) {
00304 ast_queue_frame_head(chan, f);
00305 }
00306 ast_frfree(f);
00307 }
00308 ast_channel_unlock(chan);
00309
00310 free(as);
00311
00312 return res;
00313 }
00314
00315 void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
00316 {
00317 if (chan && !ast_autoservice_start(chan)) {
00318 ast_hangup(peer);
00319 ast_autoservice_stop(chan);
00320 } else {
00321 ast_hangup(peer);
00322 }
00323 }
00324
00325 int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype)
00326 {
00327 struct asent *as;
00328 int res = -1;
00329
00330 AST_LIST_LOCK(&aslist);
00331 AST_LIST_TRAVERSE(&aslist, as, list) {
00332 if (as->chan == chan) {
00333 res = 0;
00334 as->ignore_frame_types |= (1 << ftype);
00335 break;
00336 }
00337 }
00338 AST_LIST_UNLOCK(&aslist);
00339 return res;
00340 }
00341
00342 static void autoservice_shutdown(void)
00343 {
00344 pthread_t th = asthread;
00345 asexit = 1;
00346 if (th != AST_PTHREADT_NULL) {
00347 ast_cond_signal(&as_cond);
00348 pthread_kill(th, SIGURG);
00349 pthread_join(th, NULL);
00350 }
00351 }
00352
00353 void ast_autoservice_init(void)
00354 {
00355 ast_register_cleanup(autoservice_shutdown);
00356 ast_cond_init(&as_cond, NULL);
00357 }