Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 <version>19.0.0</version>
45 </since>
46 <synopsis>
47 Drops specific frame types in the TX or RX direction on a channel.
48 </synopsis>
49 <syntax>
50 <parameter name="direction" required="true">
51 <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>
52 <para>Subsequent calls to this function will replace previous settings, allowing certain frames to be dropped only temporarily, for instance.</para>
53 <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:
54 for instance, if you drop ANSWER control frames, you should explicitly use <literal>Progress()</literal> for your call or undesired behavior
55 may occur.</para>
56 <enumlist>
57 <enum name = "DTMF_BEGIN" />
58 <enum name = "DTMF_END" />
59 <enum name = "VOICE" />
60 <enum name = "VIDEO" />
61 <enum name = "CONTROL" />
62 <enum name = "NULL" />
63 <enum name = "IAX" />
64 <enum name = "TEXT" />
65 <enum name = "TEXT_DATA" />
66 <enum name = "IMAGE" />
67 <enum name = "HTML" />
68 <enum name = "CNG" />
69 <enum name = "MODEM" />
70 </enumlist>
71 <para>The following CONTROL frames can also be dropped:</para>
72 <enumlist>
73 <enum name = "RING" />
74 <enum name = "RINGING" />
75 <enum name = "ANSWER" />
76 <enum name = "BUSY" />
77 <enum name = "TAKEOFFHOOK" />
78 <enum name = "OFFHOOK" />
79 <enum name = "CONGESTION" />
80 <enum name = "FLASH" />
81 <enum name = "WINK" />
82 <enum name = "PROGRESS" />
83 <enum name = "PROCEEDING" />
84 <enum name = "HOLD" />
85 <enum name = "UNHOLD" />
86 <enum name = "VIDUPDATE" />
87 <enum name = "CONNECTED_LINE" />
88 <enum name = "REDIRECTING" />
89 </enumlist>
90 </parameter>
91 </syntax>
92 <description>
93 <para>Examples:</para>
94 <example title="Drop only DTMF frames towards this channel">
95 exten => 1,1,Set(FRAME_DROP(TX)=DTMF_BEGIN,DTMF_END)
96 </example>
97 <example title="Drop only Answer control frames towards this channel">
98 exten => 1,1,Set(FRAME_DROP(TX)=ANSWER)
99 </example>
100 <example title="Drop only DTMF frames received on this channel">
101 exten => 1,1,Set(FRAME_DROP(RX)=DTMF_BEGIN,DTMF_END)
102 </example>
103 </description>
104 </function>
105 ***/
106
107static struct {
109 const char *str;
110} frametype2str[] = {
111 { AST_FRAME_DTMF_BEGIN, ",DTMF_BEGIN," },
112 { AST_FRAME_DTMF_END, ",DTMF_END," },
113 { AST_FRAME_VOICE, ",VOICE," },
114 { AST_FRAME_VIDEO, ",VIDEO," },
115 { AST_FRAME_CONTROL, ",CONTROL," },
116 { AST_FRAME_NULL, ",NULL," },
117 { AST_FRAME_IAX, ",IAX," },
118 { AST_FRAME_TEXT, ",TEXT," },
119 { AST_FRAME_TEXT_DATA, ",TEXT_DATA," },
120 { AST_FRAME_IMAGE, ",IMAGE," },
121 { AST_FRAME_HTML, ",HTML," },
122 { AST_FRAME_CNG, ",CNG," },
123 { AST_FRAME_MODEM, ",MODEM," },
125
126static struct {
127 int type;
128 const char *str;
130 { AST_CONTROL_RING, ",RING," },
131 { AST_CONTROL_RINGING, ",RINGING," },
132 { AST_CONTROL_ANSWER, ",ANSWER," },
133 { AST_CONTROL_BUSY, ",BUSY," },
134 { AST_CONTROL_TAKEOFFHOOK, ",TAKEOFFHOOK," },
135 { AST_CONTROL_OFFHOOK, ",OFFHOOK," },
136 { AST_CONTROL_CONGESTION, ",CONGESTION," },
137 { AST_CONTROL_FLASH, ",FLASH," },
138 { AST_CONTROL_WINK, ",WINK," },
139 { AST_CONTROL_PROGRESS, ",PROGRESS," },
140 { AST_CONTROL_PROCEEDING, ",PROCEEDING," },
141 { AST_CONTROL_HOLD, ",HOLD," },
142 { AST_CONTROL_UNHOLD, ",UNHOLD," },
143 { AST_CONTROL_VIDUPDATE, ",VIDUPDATE," },
144 { AST_CONTROL_CONNECTED_LINE, ",CONNECTED_LINE," },
145 { AST_CONTROL_REDIRECTING, ",REDIRECTING," },
147
149 TX = 0,
151};
152
157};
158
159static void datastore_destroy_cb(void *data) {
160 ast_free(data);
161}
162
164 .type = "framedrop",
165 .destroy = datastore_destroy_cb
166};
167
168static void hook_destroy_cb(void *framedata)
169{
170 ast_free(framedata);
171}
172
173static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
174{
175 int i;
176 int drop_frame = 0;
177 struct frame_drop_data *framedata = data;
178 if (!frame) {
179 return frame;
180 }
181
182 if (!((event == AST_FRAMEHOOK_EVENT_WRITE && framedata->list_type == TX) ||
183 (event == AST_FRAMEHOOK_EVENT_READ && framedata->list_type == RX))) {
184 return frame;
185 }
186
187 if (frame->frametype == AST_FRAME_CONTROL) {
188 for (i = 0; i < ARRAY_LEN(controlframetype2str); i++) {
189 if (frame->subclass.integer == controlframetype2str[i].type) {
190 if (framedata->controlvalues[i]) {
191 drop_frame = 1;
192 }
193 break;
194 }
195 }
196 } else {
197 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
198 if (frame->frametype == frametype2str[i].type) {
199 if (framedata->values[i]) {
200 drop_frame = 1;
201 }
202 break;
203 }
204 }
205 }
206
207 if (drop_frame) {
208 ast_frfree(frame);
209 frame = &ast_null_frame;
210 }
211 return frame;
212}
213
214static int frame_drop_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
215{
216 char *buffer;
217 struct frame_drop_data *framedata;
218 struct ast_datastore *datastore = NULL;
219 struct ast_framehook_interface interface = {
221 .event_cb = hook_event_cb,
222 .destroy_cb = hook_destroy_cb,
223 };
224 int i = 0;
225
226 if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
227 return 0;
228 }
229
230 interface.data = framedata;
231
232 if (!strcasecmp(data, "RX")) {
233 framedata->list_type = RX;
234 } else {
235 framedata->list_type = TX;
236 }
237
238 buffer = ast_malloc(sizeof(value) + 3); /* leading and trailing comma and null terminator */
239 snprintf(buffer, sizeof(value) + 2, ",%s,", value);
240 for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
241 if (strcasestr(buffer, frametype2str[i].str)) {
242 framedata->values[i] = 1;
243 }
244 }
245
246 for (i = 0; i < ARRAY_LEN(controlframetype2str); i++) {
247 if (strcasestr(buffer, controlframetype2str[i].str)) {
248 framedata->controlvalues[i] = 1;
249 }
250 }
251 ast_free(buffer);
252
253 ast_channel_lock(chan);
254 i = ast_framehook_attach(chan, &interface);
255 if (i >= 0) {
256 int *id;
257 if ((datastore = ast_channel_datastore_find(chan, &frame_drop_datastore, NULL))) {
258 id = datastore->data;
259 ast_framehook_detach(chan, *id);
260 ast_channel_datastore_remove(chan, datastore);
261 ast_datastore_free(datastore);
262 }
263
264 if (!(datastore = ast_datastore_alloc(&frame_drop_datastore, NULL))) {
265 ast_framehook_detach(chan, i);
266 ast_channel_unlock(chan);
267 return 0;
268 }
269
270 if (!(id = ast_calloc(1, sizeof(int)))) {
271 ast_datastore_free(datastore);
272 ast_framehook_detach(chan, i);
273 ast_channel_unlock(chan);
274 return 0;
275 }
276
277 *id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
278 datastore->data = id;
279 ast_channel_datastore_add(chan, datastore);
280 }
281 ast_channel_unlock(chan);
282
283 return 0;
284}
285
287 .name = "FRAME_DROP",
288 .write = frame_drop_helper,
289};
290
291static int unload_module(void)
292{
294}
295
296static int load_module(void)
297{
300}
301
302AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Function to drop frames on a channel.");
enum queue_result id
Definition: app_queue.c:1667
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:2404
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
#define ast_channel_lock(chan)
Definition: channel.h:2968
#define ast_channel_unlock(chan)
Definition: channel.h:2969
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:2418
#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
char * strcasestr(const char *, const char *)
#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:1558
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.
struct ast_frame_subclass subclass
union ast_frame::@226 data
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