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