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: 412324 $")
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
00076 static int as_chan_list_state;
00077
00078 static void *autoservice_run(void *ign)
00079 {
00080 struct ast_callid *callid = NULL;
00081 struct ast_frame hangup_frame = {
00082 .frametype = AST_FRAME_CONTROL,
00083 .subclass.integer = 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 (!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 callid = ast_channel_callid(chan);
00133 ast_callid_threadassoc_change(callid);
00134 if (callid) {
00135 callid = ast_callid_unref(callid);
00136 }
00137
00138 f = ast_read(chan);
00139
00140 if (!f) {
00141
00142
00143
00144
00145
00146
00147 defer_frame = &hangup_frame;
00148 } else if (ast_is_deferrable_frame(f)) {
00149 defer_frame = f;
00150 }
00151
00152 if (defer_frame) {
00153 for (i = 0; i < x; i++) {
00154 struct ast_frame *dup_f;
00155
00156 if (mons[i] != chan) {
00157 continue;
00158 }
00159
00160 if (defer_frame != f) {
00161 if ((dup_f = ast_frdup(defer_frame))) {
00162 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00163 }
00164 } else {
00165 if ((dup_f = ast_frisolate(defer_frame))) {
00166 if (dup_f != defer_frame) {
00167 ast_frfree(defer_frame);
00168 }
00169 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00170 }
00171 }
00172
00173 break;
00174 }
00175 } else if (f) {
00176 ast_frfree(f);
00177 }
00178 }
00179
00180 asthread = AST_PTHREADT_NULL;
00181
00182 return NULL;
00183 }
00184
00185 int ast_autoservice_start(struct ast_channel *chan)
00186 {
00187 int res = 0;
00188 struct asent *as;
00189
00190 AST_LIST_LOCK(&aslist);
00191 AST_LIST_TRAVERSE(&aslist, as, list) {
00192 if (as->chan == chan) {
00193 as->use_count++;
00194 break;
00195 }
00196 }
00197 AST_LIST_UNLOCK(&aslist);
00198
00199 if (as) {
00200
00201 return 0;
00202 }
00203
00204 if (!(as = ast_calloc(1, sizeof(*as))))
00205 return -1;
00206
00207
00208 as->chan = chan;
00209 as->use_count = 1;
00210
00211 ast_channel_lock(chan);
00212 as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00213 if (!as->orig_end_dtmf_flag)
00214 ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
00215 ast_channel_unlock(chan);
00216
00217 AST_LIST_LOCK(&aslist);
00218
00219 if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00220 ast_cond_signal(&as_cond);
00221 }
00222
00223 AST_LIST_INSERT_HEAD(&aslist, as, list);
00224
00225 if (asthread == AST_PTHREADT_NULL) {
00226 if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00227 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00228
00229
00230 AST_LIST_REMOVE(&aslist, as, list);
00231 free(as);
00232 asthread = AST_PTHREADT_NULL;
00233 res = -1;
00234 } else {
00235 pthread_kill(asthread, SIGURG);
00236 }
00237 }
00238
00239 AST_LIST_UNLOCK(&aslist);
00240
00241 return res;
00242 }
00243
00244 int ast_autoservice_stop(struct ast_channel *chan)
00245 {
00246 int res = -1;
00247 struct asent *as, *removed = NULL;
00248 struct ast_frame *f;
00249 int chan_list_state;
00250
00251 AST_LIST_LOCK(&aslist);
00252
00253
00254
00255
00256
00257 chan_list_state = as_chan_list_state;
00258
00259
00260
00261 AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
00262 if (as->chan == chan) {
00263 as->use_count--;
00264 if (as->use_count < 1) {
00265 AST_LIST_REMOVE_CURRENT(list);
00266 removed = as;
00267 }
00268 break;
00269 }
00270 }
00271 AST_LIST_TRAVERSE_SAFE_END;
00272
00273 if (removed && asthread != AST_PTHREADT_NULL) {
00274 pthread_kill(asthread, SIGURG);
00275 }
00276
00277 AST_LIST_UNLOCK(&aslist);
00278
00279 if (!removed) {
00280 return 0;
00281 }
00282
00283
00284 while (chan_list_state == as_chan_list_state) {
00285 usleep(1000);
00286 }
00287
00288
00289
00290
00291 if (!ast_channel_softhangup_internal_flag(chan)) {
00292 res = 0;
00293 }
00294
00295 if (!as->orig_end_dtmf_flag) {
00296 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
00297 }
00298
00299 ast_channel_lock(chan);
00300 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00301 if (!((1 << f->frametype) & as->ignore_frame_types)) {
00302 ast_queue_frame_head(chan, f);
00303 }
00304 ast_frfree(f);
00305 }
00306 ast_channel_unlock(chan);
00307
00308 free(as);
00309
00310 return res;
00311 }
00312
00313 void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
00314 {
00315 if (chan && !ast_autoservice_start(chan)) {
00316 ast_hangup(peer);
00317 ast_autoservice_stop(chan);
00318 } else {
00319 ast_hangup(peer);
00320 }
00321 }
00322
00323 int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype)
00324 {
00325 struct asent *as;
00326 int res = -1;
00327
00328 AST_LIST_LOCK(&aslist);
00329 AST_LIST_TRAVERSE(&aslist, as, list) {
00330 if (as->chan == chan) {
00331 res = 0;
00332 as->ignore_frame_types |= (1 << ftype);
00333 break;
00334 }
00335 }
00336 AST_LIST_UNLOCK(&aslist);
00337 return res;
00338 }
00339
00340 void ast_autoservice_init(void)
00341 {
00342 ast_cond_init(&as_cond, NULL);
00343 }