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