Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
func_frame_drop.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2021, Naveen Albert
5 *
6 * Naveen Albert <asterisk@phreaknet.org>
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 Function that drops specified frames from channels
22 *
23 * \author Naveen Albert <asterisk@phreaknet.org>
24 *
25 * \ingroup functions
26 */
27
28/*** MODULEINFO
29 <support_level>extended</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/module.h"
35#include "asterisk/channel.h"
36#include "asterisk/pbx.h"
37#include "asterisk/framehook.h"
38
39/*** DOCUMENTATION
40 <function name="FRAME_DROP" language="en_US">
41 <since>
42 <version>16.21.0</version>
43 <version>18.7.0</version>
44 </since>
45 <synopsis>
46 Drops specific frame types in the TX or RX direction on a channel.
47 </synopsis>
48 <syntax>
49 <parameter name="direction" required="true">
50 <para>List of frame types to be dropped for the specified direction. Direction can be <literal>TX</literal> or <literal>RX</literal>. The <literal>TX</literal> direction will prevent Asterisk from sending frames to a channel, and the <literal>RX</literal> direction will prevent Asterisk from receiving frames from a channel.</para>
51 <para>Subsequent calls to this function will replace previous settings, allowing certain frames to be dropped only temporarily, for instance.</para>
52 <para>Below are the different types of frames that can be dropped. Other actions may need to be taken in conjunction with use of this function:
53 for instance, if you drop ANSWER control frames, you should explicitly use <literal>Progress()</literal> for your call or undesired behavior
54 may occur.</para>
55 <enumlist>
56 <enum name = "DTMF_BEGIN" />
57 <enum name = "DTMF_END" />
58 <enum name = "VOICE" />
59 <enum name = "VIDEO" />
60 <enum name = "CONTROL" />
61 <enum name = "NULL" />
62 <enum name = "IAX" />
63 <enum name = "TEXT" />
64 <enum name = "TEXT_DATA" />
65 <enum name = "IMAGE" />
66 <enum name = "HTML" />
67 <enum name = "CNG" />
68 <enum name = "MODEM" />
69 </enumlist>
70 <para>The following CONTROL frames can also be dropped:</para>
71 <enumlist>
72 <enum name = "RING" />
73 <enum name = "RINGING" />
74 <enum name = "ANSWER" />
75 <enum name = "BUSY" />
76 <enum name = "TAKEOFFHOOK" />
77 <enum name = "OFFHOOK" />
78 <enum name = "CONGESTION" />
79 <enum name = "FLASH" />
80 <enum name = "WINK" />
81 <enum name = "PROGRESS" />
82 <enum name = "PROCEEDING" />
83 <enum name = "HOLD" />
84 <enum name = "UNHOLD" />
85 <enum name = "VIDUPDATE" />
86 <enum name = "CONNECTED_LINE" />
87 <enum name = "REDIRECTING" />
88 </enumlist>
89 </parameter>
90 </syntax>
91 <description>
92 <para>Examples:</para>
93 <example title="Drop only DTMF frames towards this channel">
94 exten => 1,1,Set(FRAME_DROP(TX)=DTMF_BEGIN,DTMF_END)
95 </example>
96 <example title="Drop only Answer control frames towards this channel">
97 exten => 1,1,Set(FRAME_DROP(TX)=ANSWER)
98 </example>
99 <example title="Drop only DTMF frames received on this channel">
100 exten => 1,1,Set(FRAME_DROP(RX)=DTMF_BEGIN,DTMF_END)
101 </example>
102 </description>
103 </function>
104 ***/
105
106static struct {
108 const char *str;
109} frametype2str[] = {
110 { AST_FRAME_DTMF_BEGIN, ",DTMF_BEGIN," },
111 { AST_FRAME_DTMF_END, ",DTMF_END," },
112 { AST_FRAME_VOICE, ",VOICE," },
113 { AST_FRAME_VIDEO, ",VIDEO," },
114 { AST_FRAME_CONTROL, ",CONTROL," },
115 { AST_FRAME_NULL, ",NULL," },
116 { AST_FRAME_IAX, ",IAX," },
117 { AST_FRAME_TEXT, ",TEXT," },
118 { AST_FRAME_TEXT_DATA, ",TEXT_DATA," },
119 { AST_FRAME_IMAGE, ",IMAGE," },
120 { AST_FRAME_HTML, ",HTML," },
121 { AST_FRAME_CNG, ",CNG," },
122 { AST_FRAME_MODEM, ",MODEM," },
124
125static struct {
126 int type;
127 const char *str;
129 { AST_CONTROL_RING, ",RING," },
130 { AST_CONTROL_RINGING, ",RINGING," },
131 { AST_CONTROL_ANSWER, ",ANSWER," },
132 { AST_CONTROL_BUSY, ",BUSY," },
133 { AST_CONTROL_TAKEOFFHOOK, ",TAKEOFFHOOK," },
134 { AST_CONTROL_OFFHOOK, ",OFFHOOK," },
135 { AST_CONTROL_CONGESTION, ",CONGESTION," },
136 { AST_CONTROL_FLASH, ",FLASH," },
137 { AST_CONTROL_WINK, ",WINK," },
138 { AST_CONTROL_PROGRESS, ",PROGRESS," },
139 { AST_CONTROL_PROCEEDING, ",PROCEEDING," },
140 { AST_CONTROL_HOLD, ",HOLD," },
141 { AST_CONTROL_UNHOLD, ",UNHOLD," },
142 { AST_CONTROL_VIDUPDATE, ",VIDUPDATE," },
143 { AST_CONTROL_CONNECTED_LINE, ",CONNECTED_LINE," },
144 { AST_CONTROL_REDIRECTING, ",REDIRECTING," },
146
148 TX = 0,
150};
151
156};
157
158static void datastore_destroy_cb(void *data) {
159 ast_free(data);
160}
161
163 .type = "framedrop",
164 .destroy = datastore_destroy_cb
165};
166
167static void hook_destroy_cb(void *framedata)
168{
169 ast_free(framedata);
170}
171
172static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
173{
174 int i;
175 int drop_frame = 0;
176 struct frame_drop_data *framedata = data;
177 if (!frame) {
178 return frame;
179 }
180
181 if (!((event == AST_FRAMEHOOK_EVENT_WRITE && framedata->list_type == TX) ||
182 (event == AST_FRAMEHOOK_EVENT_READ && framedata->list_type == RX))) {
183 return frame;
184 }
185
186 if (frame->frametype == AST_FRAME_CONTROL) {
187 for (i = 0; i < ARRAY_LEN(controlframetype2str); i++) {
188 if (frame->subclass.integer == controlframetype2str[i].type) {
189 if (framedata->controlvalues[i]) {
190 drop_frame = 1;
191 }
192 break;
193 }
194 }
195 } else {
196 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
197 if (frame->frametype == frametype2str[i].type) {
198 if (framedata->values[i]) {
199 drop_frame = 1;
200 }
201 break;
202 }
203 }
204 }
205
206 if (drop_frame) {
207 ast_frfree(frame);
208 frame = &ast_null_frame;
209 }
210 return frame;
211}
212
213static int frame_drop_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
214{
215 char *buffer;
216 struct frame_drop_data *framedata;
217 struct ast_datastore *datastore = NULL;
218 struct ast_framehook_interface interface = {
220 .event_cb = hook_event_cb,
221 .destroy_cb = hook_destroy_cb,
222 };
223 int i = 0;
224
225 if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
226 return 0;
227 }
228
229 interface.data = framedata;
230
231 if (!strcasecmp(data, "RX")) {
232 framedata->list_type = RX;
233 } else {
234 framedata->list_type = TX;
235 }
236
237 buffer = ast_malloc(sizeof(value) + 3); /* leading and trailing comma and null terminator */
238 snprintf(buffer, sizeof(value) + 2, ",%s,", value);
239 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
240 if (strcasestr(buffer, frametype2str[i].str)) {
241 framedata->values[i] = 1;
242 }
243 }
244
245 for (i = 0; i < ARRAY_LEN(controlframetype2str); i++) {
246 if (strcasestr(buffer, controlframetype2str[i].str)) {
247 framedata->controlvalues[i] = 1;
248 }
249 }
250 ast_free(buffer);
251
252 ast_channel_lock(chan);
253 i = ast_framehook_attach(chan, &interface);
254 if (i >= 0) {
255 int *id;
256 if ((datastore = ast_channel_datastore_find(chan, &frame_drop_datastore, NULL))) {
257 id = datastore->data;
258 ast_framehook_detach(chan, *id);
259 ast_channel_datastore_remove(chan, datastore);
260 ast_datastore_free(datastore);
261 }
262
263 if (!(datastore = ast_datastore_alloc(&frame_drop_datastore, NULL))) {
264 ast_framehook_detach(chan, i);
265 ast_channel_unlock(chan);
266 return 0;
267 }
268
269 if (!(id = ast_calloc(1, sizeof(int)))) {
270 ast_datastore_free(datastore);
271 ast_framehook_detach(chan, i);
272 ast_channel_unlock(chan);
273 return 0;
274 }
275
276 *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
277 datastore->data = id;
278 ast_channel_datastore_add(chan, datastore);
279 }
280 ast_channel_unlock(chan);
281
282 return 0;
283}
284
286 .name = "FRAME_DROP",
287 .write = frame_drop_helper,
288};
289
290static int unload_module(void)
291{
293}
294
295static int load_module(void)
296{
299}
300
301AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Function to drop frames on a channel.");
enum queue_result id
Definition: app_queue.c:1808
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
General Asterisk PBX channel definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
#define ast_channel_lock(chan)
Definition: channel.h:2970
#define ast_channel_unlock(chan)
Definition: channel.h:2971
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
FrameHook Architecture.
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
ast_framehook_event
These are the types of events that the framehook's event callback can receive.
Definition: framehook.h:151
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
@ AST_FRAMEHOOK_EVENT_READ
Definition: framehook.h:152
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
static int frame_drop_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static struct @170 frametype2str[]
static struct ast_custom_function frame_drop_function
static const struct ast_datastore_info frame_drop_datastore
static struct @171 controlframetype2str[]
direction
@ RX
@ TX
static struct ast_frame * hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Function to drop frames on a channel.")
static void hook_destroy_cb(void *framedata)
static void datastore_destroy_cb(void *data)
static int load_module(void)
enum ast_frame_type type
static int unload_module(void)
const char * str
#define ast_frfree(fr)
ast_frame_type
Frame types.
@ AST_FRAME_VIDEO
@ AST_FRAME_NULL
@ AST_FRAME_HTML
@ AST_FRAME_IMAGE
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_VOICE
@ AST_FRAME_MODEM
@ AST_FRAME_TEXT_DATA
@ AST_FRAME_CONTROL
@ AST_FRAME_TEXT
@ AST_CONTROL_RING
@ AST_CONTROL_WINK
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_PROCEEDING
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_TAKEOFFHOOK
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HOLD
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_FLASH
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Asterisk module definitions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Core PBX routines and definitions.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define NULL
Definition: resample.c:96
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Data structure associated with a single frame of data.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Definition: astman.c:222
int values[ARRAY_LEN(frametype2str)]
int controlvalues[ARRAY_LEN(controlframetype2str)]
enum direction list_type
int value
Definition: syslog.c:37
#define ARRAY_LEN(a)
Definition: utils.h:666