Asterisk - The Open Source Telephony Project  18.5.0
framehook.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief FrameHooks Architecture
22  *
23  * \author David Vossel <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/channel.h"
33 #include "asterisk/linkedlists.h"
34 #include "asterisk/framehook.h"
35 #include "asterisk/frame.h"
36 
37 struct ast_framehook {
39  /*! This pointer to ast_channel the framehook is attached to. */
40  struct ast_channel *chan;
41  /*! the id representing this framehook on a channel */
42  unsigned int id;
43  /*! when set, this signals the read and write function to detach the hook */
45  /*! list entry for ast_framehook_list object */
47 };
48 
50  /*! the number of hooks currently present */
51  unsigned int count;
52  /*! id for next framehook added */
53  unsigned int id_count;
55 };
56 
58 {
59  /*! Destroy the framehook outright. */
61  /*! Remove the framehook from the channel, but don't destroy the data since
62  * it will be used by a replacement framehook on another channel. */
64 };
65 
66 static void framehook_detach(struct ast_framehook *framehook, enum framehook_detachment_mode mode)
67 {
68  struct ast_frame *frame;
69  frame = framehook->i.event_cb(framehook->chan, NULL, AST_FRAMEHOOK_EVENT_DETACHED, framehook->i.data);
70  /* never assume anything about this function. If you can return a frame during
71  * the detached event, then assume someone will. */
72  if (frame) {
73  ast_frfree(frame);
74  }
75  framehook->chan = NULL;
76 
77  if (mode == FRAMEHOOK_DETACH_DESTROY && framehook->i.destroy_cb) {
78  framehook->i.destroy_cb(framehook->i.data);
79  }
80  ast_free(framehook);
81 }
82 
83 static struct ast_frame *framehook_list_push_event(struct ast_framehook_list *framehooks, struct ast_frame *frame, enum ast_framehook_event event)
84 {
85  struct ast_framehook *framehook;
86  struct ast_frame *original_frame;
87  int *skip;
88  size_t skip_size;
89 
90  if (!framehooks) {
91  return frame;
92  }
93 
94  skip_size = sizeof(int) * framehooks->count;
95  skip = ast_alloca(skip_size);
96  memset(skip, 0, skip_size);
97 
98  do {
99  unsigned int num = 0;
100  original_frame = frame;
101 
102  AST_LIST_TRAVERSE_SAFE_BEGIN(&framehooks->list, framehook, list) {
103  if (framehook->detach_and_destroy_me) {
104  /* this guy is signaled for destruction */
107  continue;
108  }
109 
110  /* If this framehook has been marked as needing to be skipped, do so */
111  if (skip[num]) {
112  num++;
113  continue;
114  }
115 
116  frame = framehook->i.event_cb(framehook->chan, frame, event, framehook->i.data);
117 
118  if (frame != original_frame) {
119  /* To prevent looping we skip any framehooks that have already provided a modified frame */
120  skip[num] = 1;
121  break;
122  }
123 
124  num++;
125  }
127  } while (frame != original_frame);
128 
129  return frame;
130 }
131 
133 {
134  struct ast_framehook *framehook;
135  struct ast_framehook_list *fh_list;
136  struct ast_frame *frame;
138  ast_log(LOG_ERROR, "Version '%hu' of framehook interface not what we compiled against (%i)\n",
140  return -1;
141  }
142  if (!i->event_cb || !(framehook = ast_calloc(1, sizeof(*framehook)))) {
143  return -1;
144  }
145  framehook->i = *i;
146  framehook->chan = chan;
147 
148  /* create the framehook list if it didn't already exist */
149  if (!ast_channel_framehooks(chan)) {
150  if (!(fh_list = ast_calloc(1, sizeof(*ast_channel_framehooks(chan))))) {
151  ast_free(framehook);
152  return -1;
153  }
154  ast_channel_framehooks_set(chan, fh_list);
155  }
156 
157  ast_channel_framehooks(chan)->count++;
158  framehook->id = ++ast_channel_framehooks(chan)->id_count;
160 
161  /* Tell the event callback we're live and rocking */
162  frame = framehook->i.event_cb(framehook->chan, NULL, AST_FRAMEHOOK_EVENT_ATTACHED, framehook->i.data);
163 
164  /* Never assume anything about this function. If you can return a frame during
165  * the attached event, then assume someone will. */
166  if (frame) {
167  ast_frfree(frame);
168  }
169 
170  if (ast_channel_is_bridged(chan)) {
172  }
173 
174  return framehook->id;
175 }
176 
178 {
179  struct ast_framehook *framehook;
180  int res = -1;
181 
182  if (!ast_channel_framehooks(chan)) {
183  return res;
184  }
185 
187  if (framehook->id == id) {
188  /* we mark for detachment rather than doing explicitly here because
189  * it needs to be safe for this function to be called within the
190  * event callback. If we allowed the hook to actually be destroyed
191  * immediately here, the event callback would crash on exit. */
192  framehook->detach_and_destroy_me = 1;
193  res = 0;
194  break;
195  }
196  }
198 
199  if (!res && ast_channel_is_bridged(chan)) {
201  }
202 
203  return res;
204 }
205 
207 {
208  struct ast_framehook *framehook;
209 
210  if (!ast_channel_framehooks(chan)) {
211  return 0;
212  }
216  }
220  return 0;
221 }
222 
223 void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan)
224 {
225  struct ast_framehook *framehook;
226  int moved_framehook_id;
227 
228  if (ast_channel_framehooks(new_chan)) {
230  if (framehook->i.disable_inheritance) {
231  ast_framehook_detach(new_chan, framehook->id);
232  continue;
233  }
234 
235  if (framehook->i.chan_breakdown_cb) {
236  framehook->i.chan_breakdown_cb(framehook->i.data, framehook->id,
237  old_chan, new_chan);
238  }
239  }
241  }
242 
243  if (!ast_channel_framehooks(old_chan)) {
244  return;
245  }
246 
247  if (!AST_LIST_EMPTY(&ast_channel_framehooks(old_chan)->list)
248  && ast_channel_is_bridged(old_chan)) {
250  }
251  while ((framehook = AST_LIST_REMOVE_HEAD(&ast_channel_framehooks(old_chan)->list, list))) {
252  /* If inheritance is not allowed for this framehook, just destroy it. */
253  if (framehook->i.disable_inheritance) {
255  continue;
256  }
257 
258  /* Otherwise move it to the other channel and perform any fixups set by the framehook interface */
259  moved_framehook_id = ast_framehook_attach(new_chan, &framehook->i);
260  if (moved_framehook_id < 0) {
261  ast_log(LOG_WARNING, "Failed framehook copy during masquerade. Expect loss of features.\n");
263  } else {
264  if (framehook->i.chan_fixup_cb) {
265  framehook->i.chan_fixup_cb(framehook->i.data, moved_framehook_id,
266  old_chan, new_chan);
267  }
268 
270  }
271  }
272 }
273 
275 {
276  if (!framehooks) {
277  return 1;
278  }
279  return AST_LIST_EMPTY(&framehooks->list) ? 1 : 0;
280 }
281 
283 {
284  return ast_framehook_list_contains_no_active_of_type(framehooks, 0);
285 }
286 
288  enum ast_frame_type type)
289 {
290  struct ast_framehook *cur;
291 
292  if (!framehooks) {
293  return 1;
294  }
295 
296  if (AST_LIST_EMPTY(&framehooks->list)) {
297  return 1;
298  }
299 
300  AST_LIST_TRAVERSE(&framehooks->list, cur, list) {
301  if (cur->detach_and_destroy_me) {
302  continue;
303  }
304  if (type && cur->i.consume_cb && !cur->i.consume_cb(cur->i.data, type)) {
305  continue;
306  }
307  return 0;
308  }
309 
310  return 1;
311 }
312 
313 struct ast_frame *ast_framehook_list_write_event(struct ast_framehook_list *framehooks, struct ast_frame *frame)
314 {
315  return framehook_list_push_event(framehooks, frame, AST_FRAMEHOOK_EVENT_WRITE);
316 }
317 
318 struct ast_frame *ast_framehook_list_read_event(struct ast_framehook_list *framehooks, struct ast_frame *frame)
319 {
320  return framehook_list_push_event(framehooks, frame, AST_FRAMEHOOK_EVENT_READ);
321 }
static const char type[]
Definition: chan_ooh323.c:109
ast_framehook_event_callback event_cb
Definition: framehook.h:233
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_frame * framehook_list_push_event(struct ast_framehook_list *framehooks, struct ast_frame *frame, enum ast_framehook_event event)
Definition: framehook.c:83
int ast_framehook_list_contains_no_active_of_type(struct ast_framehook_list *framehooks, enum ast_frame_type type)
Determine if a framehook list is free of active framehooks consuming a specific type of frame...
Definition: framehook.c:287
void ast_channel_framehooks_set(struct ast_channel *chan, struct ast_framehook_list *value)
static void framehook_detach(struct ast_framehook *framehook, enum framehook_detachment_mode mode)
Definition: framehook.c:66
struct ast_framehook_list * ast_channel_framehooks(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
ast_framehook_event
These are the types of events that the framehook&#39;s event callback can receive.
Definition: framehook.h:151
int ast_framehook_list_is_empty(struct ast_framehook_list *framehooks)
Determine if an framehook list is empty or not.
Definition: framehook.c:274
Definition: astman.c:222
struct ast_framehook_list::@394 list
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define NULL
Definition: resample.c:96
ast_framehook_destroy_callback destroy_cb
Definition: framehook.h:236
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan)
This is used by the channel API during a masquerade operation to move all mobile framehooks from the ...
Definition: framehook.c:223
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
int ast_framehook_list_destroy(struct ast_channel *chan)
This is used by the channel API to detach and destroy all framehooks on a channel during channel dest...
Definition: framehook.c:206
struct ast_framehook::@393 list
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
Asterisk internal frame definitions.
A set of macros to manage forward-linked lists.
int ast_framehook_list_contains_no_active(struct ast_framehook_list *framehooks)
Determine if a framehook list is free of active framehooks or not.
Definition: framehook.c:282
void ast_channel_set_unbridged_nolock(struct ast_channel *chan, int value)
Variant of ast_channel_set_unbridged. Use this if the channel is already locked prior to calling...
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
ast_frame_type
Frame types.
unsigned int id_count
Definition: framehook.c:53
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
ast_framehook_chan_fixup_callback chan_fixup_cb
Definition: framehook.h:244
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_frame * ast_framehook_list_write_event(struct ast_framehook_list *framehooks, struct ast_frame *frame)
This is used by the channel API push a frame write event to a channel&#39;s framehook list...
Definition: framehook.c:313
ast_framehook_chan_fixup_callback chan_breakdown_cb
Definition: framehook.h:248
ast_framehook_consume_callback consume_cb
Definition: framehook.h:240
struct ast_framehook_interface i
Definition: framehook.c:38
unsigned int id
Definition: framehook.c:42
FrameHook Architecture.
unsigned int count
Definition: framehook.c:51
framehook_detachment_mode
Definition: framehook.c:57
int ast_framehook_detach(struct ast_channel *chan, int id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define ast_frfree(fr)
Data structure associated with a single frame of data.
int detach_and_destroy_me
Definition: framehook.c:44
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
struct ast_channel * chan
Definition: framehook.c:40
struct ast_frame * ast_framehook_list_read_event(struct ast_framehook_list *framehooks, struct ast_frame *frame)
This is used by the channel API push a frame read event to a channel&#39;s framehook list.
Definition: framehook.c:318