Asterisk - The Open Source Telephony Project  21.4.1
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"

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.

Function Documentation

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

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

Referenced by dial_exec_full().

343 {
344  if (chan && !ast_autoservice_start(chan)) {
345  ast_hangup(peer);
346  ast_autoservice_stop(chan);
347  } else {
348  ast_hangup(peer);
349  }
350 }
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
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 352 of file autoservice.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

353 {
354  struct asent *as;
355  int res = -1;
356 
358  AST_LIST_TRAVERSE(&aslist, as, list) {
359  if (as->chan == chan) {
360  res = 0;
361  as->ignore_frame_types |= (1 << ftype);
362  break;
363  }
364  }
366  return res;
367 }
#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
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
void ast_autoservice_init ( void  )

Provided by autoservice.c

Definition at line 380 of file autoservice.c.

References ast_register_cleanup().

381 {
382  ast_register_cleanup(autoservice_shutdown);
383  ast_cond_init(&as_cond, NULL);
384 }
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
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.

References ast_calloc, ast_debug, 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_thread_is_user_interface(), and asent::use_count.

Referenced by acf_odbc_write(), 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(), confbridge_exec(), dial_exec_full(), join_conference_bridge(), lua_autoservice_start(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), push_announcer(), and ring_one().

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",
208  ast_channel_name(chan));
209  return 0;
210  }
211 
213  AST_LIST_TRAVERSE(&aslist, as, list) {
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 
233  ast_channel_lock(chan);
234  as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
235  if (!as->orig_end_dtmf_flag)
236  ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
237  ast_channel_unlock(chan);
238 
240 
241  if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
242  ast_cond_signal(&as_cond);
243  }
244 
245  AST_LIST_INSERT_HEAD(&aslist, as, list);
246 
247  if (asthread == AST_PTHREADT_NULL) { /* need start the thread */
248  if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
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. */
252  AST_LIST_REMOVE(&aslist, as, list);
253  ast_free(as);
254  asthread = AST_PTHREADT_NULL;
255  res = -1;
256  } else {
257  pthread_kill(asthread, SIGURG);
258  }
259  }
260 
262 
263  return res;
264 }
#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
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
int ast_thread_is_user_interface(void)
Indicates whether the current thread is a user interface.
Definition: utils.c:3248
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int use_count
Definition: autoservice.c:59
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
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.

References ast_debug, AST_FLAG_END_DTMF_ONLY, 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_queue_frame_head(), ast_thread_is_user_interface(), asent::deferred_frames, ast_frame::frametype, and asent::use_count.

Referenced by acf_odbc_write(), 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(), confbridge_exec(), dial_exec_full(), hangup_playback(), join_conference_bridge(), lua_autoservice_stop(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), and ring_one().

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  /* Wait while autoservice thread rebuilds its list. */
313  while (chan_list_state == as_chan_list_state) {
314  usleep(1000);
315  }
316 
317  /* Now autoservice thread should have no references to our entry
318  and we can safely destroy it */
319 
320  if (!ast_channel_softhangup_internal_flag(chan)) {
321  res = 0;
322  }
323 
324  ast_channel_lock(chan);
325  if (!as->orig_end_dtmf_flag) {
326  ast_clear_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
327  }
328 
329  while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
330  if (!((1 << f->frametype) & as->ignore_frame_types)) {
331  ast_queue_frame_head(chan, f);
332  }
333  ast_frfree(f);
334  }
335  ast_channel_unlock(chan);
336 
337  ast_free(as);
338 
339  return res;
340 }
#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
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
int ast_thread_is_user_interface(void)
Indicates whether the current thread is a user interface.
Definition: utils.c:3248
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
unsigned int use_count
Definition: autoservice.c:59
struct asent::@309 deferred_frames
Data structure associated with a single frame of data.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
enum ast_frame_type frametype
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:1144