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: 119354 $")
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <sys/time.h>
00036 #include <signal.h>
00037 #include <errno.h>
00038 #include <unistd.h>
00039
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/frame.h"
00042 #include "asterisk/sched.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/translate.h"
00048 #include "asterisk/manager.h"
00049 #include "asterisk/chanvars.h"
00050 #include "asterisk/linkedlists.h"
00051 #include "asterisk/indications.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/utils.h"
00054
00055 #define MAX_AUTOMONS 1500
00056
00057 struct asent {
00058 struct ast_channel *chan;
00059
00060
00061
00062 unsigned int use_count;
00063 unsigned int orig_end_dtmf_flag:1;
00064 AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
00065 AST_LIST_ENTRY(asent) list;
00066 };
00067
00068 static AST_LIST_HEAD_STATIC(aslist, asent);
00069 static ast_cond_t as_cond;
00070
00071 static pthread_t asthread = AST_PTHREADT_NULL;
00072
00073 static int as_chan_list_state;
00074
00075 static void *autoservice_run(void *ign)
00076 {
00077 for (;;) {
00078 struct ast_channel *mons[MAX_AUTOMONS];
00079 struct asent *ents[MAX_AUTOMONS];
00080 struct ast_channel *chan;
00081 struct asent *as;
00082 int i, x = 0, ms = 50;
00083 struct ast_frame *f = NULL;
00084 struct ast_frame *defer_frame = NULL;
00085
00086 AST_LIST_LOCK(&aslist);
00087
00088
00089
00090 as_chan_list_state++;
00091
00092 if (AST_LIST_EMPTY(&aslist)) {
00093 ast_cond_wait(&as_cond, &aslist.lock);
00094 }
00095
00096 AST_LIST_TRAVERSE(&aslist, as, list) {
00097 if (!as->chan->_softhangup) {
00098 if (x < MAX_AUTOMONS) {
00099 ents[x] = as;
00100 mons[x++] = as->chan;
00101 } else {
00102 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
00103 }
00104 }
00105 }
00106
00107 AST_LIST_UNLOCK(&aslist);
00108
00109 chan = ast_waitfor_n(mons, x, &ms);
00110 if (!chan) {
00111 continue;
00112 }
00113
00114 f = ast_read(chan);
00115
00116 if (!f) {
00117 struct ast_frame hangup_frame = { 0, };
00118
00119
00120
00121
00122
00123
00124 hangup_frame.frametype = AST_FRAME_CONTROL;
00125 hangup_frame.subclass = AST_CONTROL_HANGUP;
00126
00127 defer_frame = &hangup_frame;
00128 } else {
00129
00130
00131
00132
00133
00134 switch (f->frametype) {
00135
00136 case AST_FRAME_DTMF_END:
00137 case AST_FRAME_CONTROL:
00138 case AST_FRAME_TEXT:
00139 case AST_FRAME_IMAGE:
00140 case AST_FRAME_HTML:
00141 defer_frame = f;
00142 break;
00143
00144
00145 case AST_FRAME_DTMF_BEGIN:
00146 case AST_FRAME_VOICE:
00147 case AST_FRAME_VIDEO:
00148 case AST_FRAME_NULL:
00149 case AST_FRAME_IAX:
00150 case AST_FRAME_CNG:
00151 case AST_FRAME_MODEM:
00152 break;
00153 }
00154 }
00155
00156 if (!defer_frame) {
00157 if (f) {
00158 ast_frfree(f);
00159 }
00160 continue;
00161 }
00162
00163 if (f) {
00164 for (i = 0; i < x; i++) {
00165 struct ast_frame *dup_f;
00166
00167 if (mons[i] != chan) {
00168 continue;
00169 }
00170
00171 if ((dup_f = ast_frdup(f))) {
00172 AST_LIST_INSERT_TAIL(&ents[i]->deferred_frames, dup_f, frame_list);
00173 }
00174
00175 break;
00176 }
00177 ast_frfree(f);
00178 }
00179 }
00180
00181 asthread = AST_PTHREADT_NULL;
00182
00183 return NULL;
00184 }
00185
00186 int ast_autoservice_start(struct ast_channel *chan)
00187 {
00188 int res = 0;
00189 struct asent *as;
00190
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(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00215 if (!as->orig_end_dtmf_flag)
00216 ast_set_flag(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(&aslist, 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 (!chan->_softhangup) {
00294 res = 0;
00295 }
00296
00297 if (!as->orig_end_dtmf_flag) {
00298 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00299 }
00300
00301 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00302 ast_queue_frame(chan, f);
00303 ast_frfree(f);
00304 }
00305
00306 free(as);
00307
00308 return res;
00309 }
00310
00311 void ast_autoservice_init(void)
00312 {
00313 ast_cond_init(&as_cond, NULL);
00314 }