Asterisk - The Open Source Telephony Project GIT-master-0bf3178
Data Structures | Macros | Functions | Variables
autoservice.c File Reference

Automatic channel service routines. More...

#include "asterisk.h"
#include <sys/time.h>
#include <signal.h>
#include "asterisk/_private.h"
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/chanvars.h"
#include "asterisk/linkedlists.h"
#include "asterisk/indications.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
Include dependency graph for autoservice.c:

Go to the source code of this file.

Data Structures

struct  asent
 
struct  aslist
 

Macros

#define MAX_AUTOMONS   1500
 

Functions

void ast_autoservice_chan_hangup_peer (struct ast_channel *chan, struct ast_channel *peer)
 Put chan into autoservice while hanging up peer. More...
 
int ast_autoservice_ignore (struct ast_channel *chan, enum ast_frame_type ftype)
 Ignore certain frame types. More...
 
void ast_autoservice_init (void)
 
int ast_autoservice_start (struct ast_channel *chan)
 Automatically service a channel for us... More...
 
int ast_autoservice_stop (struct ast_channel *chan)
 Stop servicing a channel for us... More...
 
static void * autoservice_run (void *ign)
 
static void autoservice_shutdown (void)
 

Variables

static int as_chan_list_state
 
static ast_cond_t as_cond
 
static volatile int asexit = 0
 
static struct aslist aslist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static pthread_t asthread = AST_PTHREADT_NULL
 

Detailed Description

Automatic channel service routines.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..com

Definition in file autoservice.c.

Macro Definition Documentation

◆ MAX_AUTOMONS

#define MAX_AUTOMONS   1500

Definition at line 52 of file autoservice.c.

Function Documentation

◆ ast_autoservice_chan_hangup_peer()

void ast_autoservice_chan_hangup_peer ( struct ast_channel chan,
struct ast_channel peer 
)

Put chan into autoservice while hanging up peer.

Since
11.0
Parameters
chanChan to put into autoservice.
peerChan to run hangup handlers and hangup.

Definition at line 349 of file autoservice.c.

350{
351 if (chan && !ast_autoservice_start(chan)) {
352 ast_hangup(peer);
354 } else {
355 ast_hangup(peer);
356 }
357}
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560

References ast_autoservice_start(), ast_autoservice_stop(), and ast_hangup().

Referenced by app_exec(), bridge_failed_peer_goto(), dial_exec_full(), and try_calling().

◆ ast_autoservice_ignore()

int ast_autoservice_ignore ( struct ast_channel chan,
enum ast_frame_type  ftype 
)

Ignore certain frame types.

Note
Normally, we cache DTMF, IMAGE, HTML, TEXT, and CONTROL frames while a channel is in autoservice and queue them up when taken out of autoservice. When this is not desireable, this API may be used to cause the channel to ignore those frametypes after the channel is put into autoservice, but before autoservice is stopped.
Return values
0success
-1channel is not in autoservice

Definition at line 359 of file autoservice.c.

360{
361 struct asent *as;
362 int res = -1;
363
366 if (as->chan == chan) {
367 res = 0;
368 as->ignore_frame_types |= (1 << ftype);
369 break;
370 }
371 }
373 return res;
374}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
unsigned int ignore_frame_types
Definition: autoservice.c:62
struct asent::@306 list
struct ast_channel * chan
Definition: autoservice.c:55

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, asent::chan, asent::ignore_frame_types, and asent::list.

◆ ast_autoservice_init()

void ast_autoservice_init ( void  )

Provided by autoservice.c

Definition at line 387 of file autoservice.c.

388{
391}
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
static ast_cond_t as_cond
Definition: autoservice.c:71
static void autoservice_shutdown(void)
Definition: autoservice.c:376
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define NULL
Definition: resample.c:96

References as_cond, ast_cond_init, ast_register_cleanup(), autoservice_shutdown(), and NULL.

Referenced by asterisk_daemon().

◆ ast_autoservice_start()

int ast_autoservice_start ( struct ast_channel chan)

Automatically service a channel for us...

Return values
0success
-1failure, or the channel is already being autoserviced

Definition at line 200 of file autoservice.c.

201{
202 int res = 0;
203 struct asent *as;
204
206 /* User interface threads do not handle channel media. */
207 ast_debug(1, "Thread is a user interface, not putting channel %s into autoservice\n",
209 return 0;
210 }
211
214 if (as->chan == chan) {
215 as->use_count++;
216 break;
217 }
218 }
220
221 if (as) {
222 /* Entry exists, autoservice is already handling this channel */
223 return 0;
224 }
225
226 if (!(as = ast_calloc(1, sizeof(*as))))
227 return -1;
228
229 /* New entry created */
230 as->chan = chan;
231 as->use_count = 1;
232
235 if (!as->orig_end_dtmf_flag)
238
240
243 }
244
246
247 if (asthread == AST_PTHREADT_NULL) { /* need start the thread */
249 ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
250 /* There will only be a single member in the list at this point,
251 the one we just added. */
253 ast_free(as);
255 res = -1;
256 } else {
257 pthread_kill(asthread, SIGURG);
258 }
259 }
260
262
263 return res;
264}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static void * autoservice_run(void *ign)
Definition: autoservice.c:78
static pthread_t asthread
Definition: autoservice.c:73
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2968
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1027
#define ast_channel_unlock(chan)
Definition: channel.h:2969
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_signal(cond)
Definition: lock.h:203
unsigned int use_count
Definition: autoservice.c:59
unsigned int orig_end_dtmf_flag
Definition: autoservice.c:60
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_thread_is_user_interface(void)
Indicates whether the current thread is a user interface.
Definition: utils.c:3248
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
#define ast_set_flag(p, flag)
Definition: utils.h:70

References as_cond, ast_calloc, ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_cond_signal, ast_debug, AST_FLAG_END_DTMF_ONLY, ast_free, AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_pthread_create_background, AST_PTHREADT_NULL, ast_set_flag, ast_test_flag, ast_thread_is_user_interface(), asthread, autoservice_run(), asent::chan, asent::list, LOG_WARNING, NULL, asent::orig_end_dtmf_flag, and asent::use_count.

Referenced by acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), action_toggle_mute_participants(), app_exec(), ast_app_exec_sub(), ast_audiosocket_connect(), ast_autoservice_chan_hangup_peer(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_mf_stream(), ast_sf_stream(), begin_dial_prerun(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), findmeexec(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), join_conference_bridge(), lock_read(), lua_autoservice_start(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), mf_stream(), originate_exec(), pbx_find_extension(), playback_common(), post_join_play_begin(), push_announcer(), realtimefield_read(), reload_exec(), ring_one(), sf_stream(), shell_helper(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), try_calling(), and trylock_read().

◆ ast_autoservice_stop()

int ast_autoservice_stop ( struct ast_channel chan)

Stop servicing a channel for us...

Note
if chan is locked prior to calling ast_autoservice_stop, it is likely that there will be a deadlock between the thread that calls ast_autoservice_stop and the autoservice thread. It is important that chan is not locked prior to this call
Parameters
chan
Return values
0success
-1error, or the channel has been hungup

Definition at line 266 of file autoservice.c.

267{
268 int res = -1;
269 struct asent *as, *removed = NULL;
270 struct ast_frame *f;
271 int chan_list_state;
272
274 /* User interface threads do not handle channel media. */
275 ast_debug(1, "Thread is a user interface, not removing channel %s from autoservice\n",
276 ast_channel_name(chan));
277 return 0;
278 }
279
281
282 /* Save the autoservice channel list state. We _must_ verify that the channel
283 * list has been rebuilt before we return. Because, after we return, the channel
284 * could get destroyed and we don't want our poor autoservice thread to step on
285 * it after its gone! */
286 chan_list_state = as_chan_list_state;
287
288 /* Find the entry, but do not free it because it still can be in the
289 autoservice thread array */
291 if (as->chan == chan) {
292 as->use_count--;
293 if (as->use_count < 1) {
295 removed = as;
296 }
297 break;
298 }
299 }
301
302 if (removed && asthread != AST_PTHREADT_NULL) {
303 pthread_kill(asthread, SIGURG);
304 }
305
307
308 if (!removed) {
309 return 0;
310 }
311
312 if (asthread != AST_PTHREADT_NULL && pthread_equal(pthread_self(), asthread)) {
313 /* Do not sleep if ast_autoservice_stop is called within the autoservice thread,
314 otherwise the thread will be stuck in an endless sleep. */
315 ast_debug(1, "ast_autoservice_stop is called within the autoservice thread, channel %s\n",
316 ast_channel_name(chan));
317 } else {
318 /* Wait while autoservice thread rebuilds its list. */
319 while (chan_list_state == as_chan_list_state) {
320 usleep(1000);
321 }
322 }
323
324 /* Now autoservice thread should have no references to our entry
325 and we can safely destroy it */
326
328 res = 0;
329 }
330
331 ast_channel_lock(chan);
332 if (!as->orig_end_dtmf_flag) {
334 }
335
336 while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
337 if (!((1 << f->frametype) & as->ignore_frame_types)) {
338 ast_queue_frame_head(chan, f);
339 }
340 ast_frfree(f);
341 }
342 ast_channel_unlock(chan);
343
344 ast_free(as);
345
346 return res;
347}
static int as_chan_list_state
Definition: autoservice.c:76
int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to the head of a channel's frame queue.
Definition: channel.c:1163
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
#define ast_frfree(fr)
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
struct asent::@305 deferred_frames
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define ast_clear_flag(p, flag)
Definition: utils.h:77

References as_chan_list_state, ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_clear_flag, ast_debug, AST_FLAG_END_DTMF_ONLY, ast_free, ast_frfree, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_queue_frame_head(), ast_thread_is_user_interface(), asthread, asent::chan, asent::deferred_frames, ast_frame::frametype, asent::ignore_frame_types, NULL, asent::orig_end_dtmf_flag, and asent::use_count.

Referenced by acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), action_toggle_mute_participants(), app_exec(), array(), ast_app_exec_sub(), ast_audiosocket_connect(), ast_autoservice_chan_hangup_peer(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_hangup(), ast_mf_stream(), ast_sf_stream(), begin_dial_prerun(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), findmeexec(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), hangup_playback(), join_conference_bridge(), lock_read(), lua_autoservice_stop(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), mf_stream(), originate_exec(), pbx_find_extension(), playback_common(), post_join_play_begin(), realtimefield_read(), reload_exec(), ring_one(), sf_stream(), shell_helper(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), try_calling(), and trylock_read().

◆ autoservice_run()

static void * autoservice_run ( void *  ign)
static

Definition at line 78 of file autoservice.c.

79{
80 ast_callid callid = 0;
81 struct ast_frame hangup_frame = {
83 .subclass.integer = AST_CONTROL_HANGUP,
84 };
85
86 while (!asexit) {
87 struct ast_channel *mons[MAX_AUTOMONS];
88 struct asent *ents[MAX_AUTOMONS];
89 struct ast_channel *chan;
90 struct asent *as;
91 int i, x = 0, ms = 50;
92 struct ast_frame *f = NULL;
93 struct ast_frame *defer_frame = NULL;
94
96
97 /* At this point, we know that no channels that have been removed are going
98 * to get used again. */
100
101 if (AST_LIST_EMPTY(&aslist)) {
103 }
104
105 AST_LIST_TRAVERSE(&aslist, as, list) {
106 if (!ast_check_hangup(as->chan)) {
107 if (x < MAX_AUTOMONS) {
108 ents[x] = as;
109 mons[x++] = as->chan;
110 } else {
111 ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
112 }
113 }
114 }
115
117
118 if (!x) {
119 /* If we don't sleep, this becomes a busy loop, which causes
120 * problems when Asterisk runs at a different priority than other
121 * user processes. As long as we check for new channels at least
122 * once every 10ms, we should be fine. */
123 usleep(10000);
124 continue;
125 }
126
127 chan = ast_waitfor_n(mons, x, &ms);
128 if (!chan) {
129 continue;
130 }
131
132 callid = ast_channel_callid(chan);
134
135 f = ast_read(chan);
136
137 if (!f) {
138 /* No frame means the channel has been hung up.
139 * A hangup frame needs to be queued here as ast_waitfor() may
140 * never return again for the condition to be detected outside
141 * of autoservice. So, we'll leave a HANGUP queued up so the
142 * thread in charge of this channel will know. */
143
144 defer_frame = &hangup_frame;
145 } else if (ast_is_deferrable_frame(f)) {
146 defer_frame = f;
147 } else {
148 /* Can't defer. Discard and continue with next. */
149 ast_frfree(f);
150 continue;
151 }
152
153 for (i = 0; i < x; i++) {
154 struct ast_frame *dup_f;
155
156 if (mons[i] != chan) {
157 continue;
158 }
159
160 if (!f) { /* defer_frame == &hangup_frame */
161 if ((dup_f = ast_frdup(defer_frame))) {
162 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
163 }
164 } else {
165 if (defer_frame->frametype == AST_FRAME_CONTROL &&
166 defer_frame->subclass.integer == AST_CONTROL_VIDUPDATE) {
167
168 /* If a video update is already queued don't needlessly queue another */
169 if (ents[i]->video_update) {
170 ast_frfree(defer_frame);
171 break;
172 }
173
174 ents[i]->video_update = 1;
175 }
176 if ((dup_f = ast_frisolate(defer_frame))) {
177 AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
178 }
179 if (dup_f != defer_frame) {
180 ast_frfree(defer_frame);
181 }
182 }
183
184 break;
185 }
186 /* The ast_waitfor_n() call will only read frames from
187 * the channels' file descriptors. If ast_waitfor_n()
188 * returns non-NULL, then one of the channels in the
189 * mons array must have triggered the return. It's
190 * therefore impossible that we got here while (i >= x).
191 * If we did, we'd need to ast_frfree(f) if (f). */
192 }
193
196
197 return NULL;
198}
static volatile int asexit
Definition: autoservice.c:74
#define MAX_AUTOMONS
Definition: autoservice.c:52
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3176
ast_callid ast_channel_callid(const struct ast_channel *chan)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_is_deferrable_frame(const struct ast_frame *frame)
Should we keep this frame for later?
Definition: channel.c:1486
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define ast_frdup(fr)
Copies a frame.
@ AST_FRAME_CONTROL
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_HANGUP
int ast_callid_threadassoc_change(ast_callid callid)
Sets what is stored in the thread storage to the given callid if it does not match what is already th...
Definition: logger.c:2307
unsigned int ast_callid
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
unsigned int video_update
Definition: autoservice.c:61
ast_mutex_t lock
Definition: autoservice.c:70
Main Channel structure associated with a channel.
struct ast_frame_subclass subclass

References as_chan_list_state, as_cond, asexit, ast_callid_threadassoc_change(), ast_channel_callid(), ast_check_hangup(), ast_cond_wait, AST_CONTROL_HANGUP, AST_CONTROL_VIDUPDATE, AST_FRAME_CONTROL, ast_frdup, ast_frfree, ast_frisolate, ast_is_deferrable_frame(), AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_PTHREADT_NULL, ast_read(), ast_waitfor_n(), asthread, ast_channel::callid, asent::chan, ast_frame::frametype, ast_frame_subclass::integer, aslist::lock, LOG_WARNING, MAX_AUTOMONS, NULL, ast_frame::subclass, and asent::video_update.

Referenced by ast_autoservice_start().

◆ autoservice_shutdown()

static void autoservice_shutdown ( void  )
static

Definition at line 376 of file autoservice.c.

377{
378 pthread_t th = asthread;
379 asexit = 1;
380 if (th != AST_PTHREADT_NULL) {
382 pthread_kill(th, SIGURG);
383 pthread_join(th, NULL);
384 }
385}

References as_cond, asexit, ast_cond_signal, AST_PTHREADT_NULL, asthread, and NULL.

Referenced by ast_autoservice_init().

Variable Documentation

◆ as_chan_list_state

int as_chan_list_state
static

Definition at line 76 of file autoservice.c.

Referenced by ast_autoservice_stop(), and autoservice_run().

◆ as_cond

ast_cond_t as_cond
static

◆ asexit

volatile int asexit = 0
static

Definition at line 74 of file autoservice.c.

Referenced by autoservice_run(), and autoservice_shutdown().

◆ aslist

struct aslist aslist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ asthread

pthread_t asthread = AST_PTHREADT_NULL
static