Wed Jan 8 2020 09:49:58

Asterisk developer's documentation


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"

Go to the source code of this file.

Data Structures

struct  asent
 
struct  aslist
 

Macros

#define MAX_AUTOMONS   1500
 

Functions

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 } , }
 
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

#define MAX_AUTOMONS   1500

Definition at line 54 of file autoservice.c.

Referenced by autoservice_run().

Function Documentation

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 307 of file autoservice.c.

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

Referenced by builtin_automixmonitor(), feature_exec_app(), and play_message_on_chan().

308 {
309  struct asent *as;
310  int res = -1;
311 
313  AST_LIST_TRAVERSE(&aslist, as, list) {
314  if (as->chan == chan) {
315  res = 0;
316  as->ignore_frame_types |= (1 << ftype);
317  break;
318  }
319  }
321  return res;
322 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct ast_channel * chan
Definition: autoservice.c:57
struct asent::@227 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
unsigned int ignore_frame_types
Definition: autoservice.c:63
void ast_autoservice_init ( void  )

Provided by autoservice.c

Definition at line 335 of file autoservice.c.

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

Referenced by main().

336 {
338  ast_cond_init(&as_cond, NULL);
339 }
#define ast_cond_init(cond, attr)
Definition: lock.h:167
static void autoservice_shutdown(void)
Definition: autoservice.c:324
static ast_cond_t as_cond
Definition: autoservice.c:72
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: asterisk.c:1003
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 179 of file autoservice.c.

References as_cond, ast_calloc, ast_channel_lock, ast_channel_unlock, ast_cond_signal, AST_FLAG_END_DTMF_ONLY, 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, asthread, autoservice_run(), asent::chan, free, asent::list, LOG_WARNING, asent::orig_end_dtmf_flag, and asent::use_count.

Referenced by _macro_exec(), acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), ast_app_exec_macro(), ast_app_exec_sub(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_masq_park_call_exten(), ast_park_call_exten(), bridge_playfile(), builtin_atxfer(), builtin_automixmonitor(), builtin_blindtransfer(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), feature_exec_app(), feature_request_and_dial(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), leave_conference_bridge(), lock_read(), lua_autoservice_start(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), originate_exec(), osplookup_exec(), pbx_find_extension(), play_message_on_chan(), realtimefield_read(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), try_calling(), and trylock_read().

180 {
181  int res = 0;
182  struct asent *as;
183 
185  AST_LIST_TRAVERSE(&aslist, as, list) {
186  if (as->chan == chan) {
187  as->use_count++;
188  break;
189  }
190  }
192 
193  if (as) {
194  /* Entry exists, autoservice is already handling this channel */
195  return 0;
196  }
197 
198  if (!(as = ast_calloc(1, sizeof(*as))))
199  return -1;
200 
201  /* New entry created */
202  as->chan = chan;
203  as->use_count = 1;
204 
205  ast_channel_lock(chan);
207  if (!as->orig_end_dtmf_flag)
209  ast_channel_unlock(chan);
210 
212 
215  }
216 
218 
219  if (asthread == AST_PTHREADT_NULL) { /* need start the thread */
221  ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
222  /* There will only be a single member in the list at this point,
223  the one we just added. */
224  AST_LIST_REMOVE(&aslist, as, list);
225  free(as);
227  res = -1;
228  } else {
229  pthread_kill(asthread, SIGURG);
230  }
231  }
232 
234 
235  return res;
236 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static void * autoservice_run(void *ign)
Definition: autoservice.c:79
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define ast_cond_signal(cond)
Definition: lock.h:169
static ast_cond_t as_cond
Definition: autoservice.c:72
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
struct ast_channel * chan
Definition: autoservice.c:57
#define AST_PTHREADT_NULL
Definition: lock.h:65
struct asent::@227 list
#define free(a)
Definition: astmm.h:94
unsigned int orig_end_dtmf_flag
Definition: autoservice.c:62
unsigned int use_count
Definition: autoservice.c:61
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static pthread_t asthread
Definition: autoservice.c:74
#define ast_calloc(a, b)
Definition: astmm.h:82
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 238 of file autoservice.c.

References ast_channel::_softhangup, as_chan_list_state, ast_channel_lock, ast_channel_unlock, ast_clear_flag, AST_FLAG_END_DTMF_ONLY, 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(), asthread, asent::chan, asent::deferred_frames, f, ast_frame::frametype, free, asent::ignore_frame_types, asent::list, asent::orig_end_dtmf_flag, and asent::use_count.

Referenced by _macro_exec(), acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), array(), ast_app_exec_macro(), ast_app_exec_sub(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_hangup(), ast_masq_park_call_exten(), ast_park_call_exten(), bridge_playfile(), builtin_atxfer(), builtin_automixmonitor(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), feature_exec_app(), feature_request_and_dial(), finishup(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), leave_conference_bridge(), lock_read(), lua_autoservice_stop(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), originate_exec(), osplookup_exec(), pbx_find_extension(), play_message_on_chan(), realtimefield_read(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), try_calling(), and trylock_read().

239 {
240  int res = -1;
241  struct asent *as, *removed = NULL;
242  struct ast_frame *f;
243  int chan_list_state;
244 
246 
247  /* Save the autoservice channel list state. We _must_ verify that the channel
248  * list has been rebuilt before we return. Because, after we return, the channel
249  * could get destroyed and we don't want our poor autoservice thread to step on
250  * it after its gone! */
251  chan_list_state = as_chan_list_state;
252 
253  /* Find the entry, but do not free it because it still can be in the
254  autoservice thread array */
255  AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {
256  if (as->chan == chan) {
257  as->use_count--;
258  if (as->use_count < 1) {
260  removed = as;
261  }
262  break;
263  }
264  }
266 
267  if (removed && asthread != AST_PTHREADT_NULL) {
268  pthread_kill(asthread, SIGURG);
269  }
270 
272 
273  if (!removed) {
274  return 0;
275  }
276 
277  /* Wait while autoservice thread rebuilds its list. */
278  while (chan_list_state == as_chan_list_state) {
279  usleep(1000);
280  }
281 
282  /* Now autoservice thread should have no references to our entry
283  and we can safely destroy it */
284 
285  if (!chan->_softhangup) {
286  res = 0;
287  }
288 
289  if (!as->orig_end_dtmf_flag) {
291  }
292 
293  ast_channel_lock(chan);
294  while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
295  if (!((1 << f->frametype) & as->ignore_frame_types)) {
296  ast_queue_frame_head(chan, f);
297  }
298  ast_frfree(f);
299  }
300  ast_channel_unlock(chan);
301 
302  free(as);
303 
304  return res;
305 }
struct asent::@226 deferred_frames
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
static int as_chan_list_state
Definition: autoservice.c:77
struct ast_channel * chan
Definition: autoservice.c:57
#define AST_PTHREADT_NULL
Definition: lock.h:65
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define free(a)
Definition: astmm.h:94
unsigned int orig_end_dtmf_flag
Definition: autoservice.c:62
unsigned int use_count
Definition: autoservice.c:61
int _softhangup
Definition: channel.h:832
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static pthread_t asthread
Definition: autoservice.c:74
static struct ast_format f[]
Definition: format_g726.c:181
#define ast_clear_flag(p, flag)
Definition: utils.h:77
Data structure associated with a single frame of data.
Definition: frame.h:142
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
Definition: frame.h:144
unsigned int ignore_frame_types
Definition: autoservice.c:63
#define ast_frfree(fr)
Definition: frame.h:583
int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to the head of a channel&#39;s frame queue.
Definition: channel.c:1563
static void* autoservice_run ( void *  ign)
static

Definition at line 79 of file autoservice.c.

References ast_check_hangup(), ast_cond_wait, AST_CONTROL_HANGUP, 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, asent::chan, f, ast_frame::frametype, LOG_WARNING, and MAX_AUTOMONS.

Referenced by ast_autoservice_start().

80 {
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  f = ast_read(chan);
133 
134  if (!f) {
135  /* No frame means the channel has been hung up.
136  * A hangup frame needs to be queued here as ast_waitfor() may
137  * never return again for the condition to be detected outside
138  * of autoservice. So, we'll leave a HANGUP queued up so the
139  * thread in charge of this channel will know. */
140 
141  defer_frame = &hangup_frame;
142  } else if (ast_is_deferrable_frame(f)) {
143  defer_frame = f;
144  }
145 
146  if (defer_frame) {
147  for (i = 0; i < x; i++) {
148  struct ast_frame *dup_f;
149 
150  if (mons[i] != chan) {
151  continue;
152  }
153 
154  if (defer_frame != f) {
155  if ((dup_f = ast_frdup(defer_frame))) {
156  AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
157  }
158  } else {
159  if ((dup_f = ast_frisolate(defer_frame))) {
160  if (dup_f != defer_frame) {
161  ast_frfree(defer_frame);
162  }
163  AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
164  }
165  }
166 
167  break;
168  }
169  } else if (f) {
170  ast_frfree(f);
171  }
172  }
173 
175 
176  return NULL;
177 }
static volatile int asexit
Definition: autoservice.c:75
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:3534
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define MAX_AUTOMONS
Definition: autoservice.c:54
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
#define ast_cond_wait(cond, mutex)
Definition: lock.h:171
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
struct ast_frame * ast_frisolate(struct ast_frame *fr)
Makes a frame independent of any static storage.
Definition: frame.c:391
ast_mutex_t lock
Definition: autoservice.c:71
static ast_cond_t as_cond
Definition: autoservice.c:72
static int as_chan_list_state
Definition: autoservice.c:77
struct ast_channel * chan
Definition: autoservice.c:57
#define AST_PTHREADT_NULL
Definition: lock.h:65
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
static pthread_t asthread
Definition: autoservice.c:74
static struct ast_format f[]
Definition: format_g726.c:181
int ast_is_deferrable_frame(const struct ast_frame *frame)
Should we keep this frame for later?
Definition: channel.c:1818
Data structure associated with a single frame of data.
Definition: frame.h:142
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
struct ast_frame * ast_frdup(const struct ast_frame *fr)
Copies a frame.
Definition: frame.c:474
static void autoservice_shutdown ( void  )
static

Definition at line 324 of file autoservice.c.

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

Referenced by ast_autoservice_init().

325 {
326  pthread_t th = asthread;
327  asexit = 1;
328  if (th != AST_PTHREADT_NULL) {
330  pthread_kill(th, SIGURG);
331  pthread_join(th, NULL);
332  }
333 }
static volatile int asexit
Definition: autoservice.c:75
#define ast_cond_signal(cond)
Definition: lock.h:169
static ast_cond_t as_cond
Definition: autoservice.c:72
#define AST_PTHREADT_NULL
Definition: lock.h:65
static pthread_t asthread
Definition: autoservice.c:74

Variable Documentation

int as_chan_list_state
static

Definition at line 77 of file autoservice.c.

Referenced by ast_autoservice_stop().

ast_cond_t as_cond
static

Definition at line 72 of file autoservice.c.

Referenced by ast_autoservice_init(), ast_autoservice_start(), and autoservice_shutdown().

volatile int asexit = 0
static

Definition at line 75 of file autoservice.c.

Referenced by autoservice_shutdown().

struct aslist aslist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } , }
static
pthread_t asthread = AST_PTHREADT_NULL
static