Asterisk - The Open Source Telephony Project GIT-master-7805f28
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
channelstorage_ao2_legacy.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2024, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.com>
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#include "asterisk.h"
20
21#include "asterisk/channel.h"
22#include "asterisk/astobj2.h"
23#include "channelstorage.h"
24#include "channel_private.h"
25
28};
29
30#define getdb(driver) (driver->handle->handle)
31
32static void lock_driver(struct ast_channelstorage_instance *driver)
33{
34 ao2_lock(getdb(driver));
35}
36
37static void unlock_driver(struct ast_channelstorage_instance *driver)
38{
39 ao2_unlock(getdb(driver));
40}
41
43 struct ast_channel *chan, int flags, int lock)
44{
45 int ret = ao2_link_flags(getdb(driver), chan, flags);
46 if (ret == 1) {
47 chan->linked_in_container = 1;
48 }
49 return ret ? 0 : -1;
50}
51
53 struct ast_channel *chan, int lock)
54{
55 ao2_unlink(getdb(driver), chan);
56 chan->linked_in_container = 0;
57 return 0;
58}
59
60/*! \brief returns number of active/allocated channels */
62{
63 return getdb(driver) ? ao2_container_count(getdb(driver)) : 0;
64}
65
66static struct ast_channel *callback(struct ast_channelstorage_instance *driver,
67 ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
68{
69 return ao2_callback_data(getdb(driver), ao2_flags, cb_fn, arg, data);
70}
71
72static int by_name_cb(void *obj, void *arg, void *data, int flags)
73{
74 struct ast_channel *chan = obj;
75 const char *name = arg;
76 size_t name_len = *(size_t *) data;
77 int ret = 0;
78
79 ast_channel_lock(chan);
80 if (name_len == 0) {
81 if(strcasecmp(ast_channel_name(chan), name) == 0) {
82 ret = CMP_MATCH | ((flags & OBJ_MULTIPLE) ? 0 : CMP_STOP);
83 }
84 } else {
85 if (strncasecmp(ast_channel_name(chan), name, name_len) == 0) {
86 ret = CMP_MATCH | ((flags & OBJ_MULTIPLE) ? 0 : CMP_STOP);
87 }
88 }
90
91 return ret;
92}
93
94static int by_exten_cb(void *obj, void *arg, void *data, int flags)
95{
96 struct ast_channel *chan = obj;
97 char *context = arg;
98 char *exten = data;
99 int ret = CMP_MATCH;
100
101 ast_channel_lock(chan);
102 if (strcasecmp(ast_channel_context(chan), context)) {
103 ret = 0; /* Context match failed, continue */
104 } else if (strcasecmp(ast_channel_exten(chan), exten)) {
105 ret = 0; /* Extension match failed, continue */
106 }
107 ast_channel_unlock(chan);
108
109 return ret;
110}
111
112static int by_uniqueid_cb(void *obj, void *arg, void *data, int flags)
113{
114 struct ast_channel *chan = obj;
115 char *uniqueid = arg;
116 size_t id_len = *(size_t *) data;
117 int ret = CMP_MATCH;
118
120 ast_log(LOG_ERROR, "BUG! Must supply a uniqueid or partial uniqueid to match!\n");
121 return CMP_STOP;
122 }
123
124 ast_channel_lock(chan);
125 if ((!id_len && strcasecmp(ast_channel_uniqueid(chan), uniqueid))
126 || (id_len && strncasecmp(ast_channel_uniqueid(chan), uniqueid, id_len))) {
127 ret = 0; /* uniqueid match failed, keep looking */
128 }
129 ast_channel_unlock(chan);
130
131 return ret;
132}
133
135 /* storage for non-dynamically allocated iterator */
137 /* pointer to the actual iterator (simple_iterator or a dynamically
138 * allocated iterator)
139 */
141};
142
144 struct ast_channel_iterator *i)
145{
147 ast_free(i);
148
149 return NULL;
150}
151
153 const char *exten, const char *context)
154{
155 struct ast_channel_iterator *i;
156 char *l_exten = (char *) exten;
157 char *l_context = (char *) context;
158
159 if (!(i = ast_calloc(1, sizeof(*i)))) {
160 return NULL;
161 }
162
163 i->active_iterator = (void *) callback(driver, by_exten_cb,
164 l_context, l_exten, OBJ_MULTIPLE);
165 if (!i->active_iterator) {
166 ast_free(i);
167 return NULL;
168 }
169
170 return i;
171}
172
174 const char *name, size_t name_len)
175{
176 struct ast_channel_iterator *i;
177 char *l_name = (char *) name;
178
179 if (!(i = ast_calloc(1, sizeof(*i)))) {
180 return NULL;
181 }
182
183 i->active_iterator = (void *) callback(driver, by_name_cb,
184 l_name, &name_len,
185 OBJ_MULTIPLE | (name_len == 0 /* match the whole word, so optimize */ ? OBJ_KEY : 0));
186 if (!i->active_iterator) {
187 ast_free(i);
188 return NULL;
189 }
190
191 return i;
192}
193
195{
196 struct ast_channel_iterator *i;
197
198 if (!(i = ast_calloc(1, sizeof(*i)))) {
199 return NULL;
200 }
201
202 i->simple_iterator = ao2_iterator_init(getdb(driver), 0);
204
205 return i;
206}
207
209 struct ast_channel_iterator *i)
210{
212}
213
215 const char *uniqueid)
216{
217 char *l_name = (char *) uniqueid;
218 size_t name_len = strlen(uniqueid);
219
220 struct ast_channel *chan = callback(driver, by_uniqueid_cb, l_name, &name_len, 0);
221 return chan;
222}
223
225 const char *name, size_t name_len)
226{
227 struct ast_channel *chan;
228 char *l_name = (char *) name;
229
230 if (ast_strlen_zero(l_name)) {
231 /* We didn't have a name to search for so quit. */
232 return NULL;
233 }
234
235 chan = callback(driver, by_name_cb, l_name, &name_len,
236 (name_len == 0) /* optimize if it is a complete name match */ ? OBJ_KEY : 0);
237 if (chan) {
238 return chan;
239 }
240
241 /* Now try a search for uniqueid. */
242 chan = callback(driver, by_uniqueid_cb, l_name, &name_len, 0);
243 return chan;
244}
245
247 const char *exten, const char *context)
248{
249 char *l_exten = (char *) exten;
250 char *l_context = (char *) context;
251
252 return callback(driver, by_exten_cb, l_context, l_exten, 0);
253}
254
255static int hash_cb(const void *obj, const int flags)
256{
257 const char *name = (flags & OBJ_KEY) ? obj : ast_channel_name((struct ast_channel *) obj);
258
259 /* If the name isn't set, return 0 so that the ao2_find() search will
260 * start in the first bucket. */
261 if (ast_strlen_zero(name)) {
262 return 0;
263 }
264
265 return ast_str_case_hash(name);
266}
267
268/*!
269 * \internal
270 * \brief Print channel object key (name).
271 * \since 12.0.0
272 *
273 * \param v_obj A pointer to the object we want the key printed.
274 * \param where User data needed by prnt to determine where to put output.
275 * \param prnt Print output callback function to use.
276 */
277static void prnt_channel_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
278{
279 struct ast_channel *chan = v_obj;
280
281 if (!chan) {
282 return;
283 }
284 prnt(where, "%s", ast_channel_name(chan));
285}
286
288{
289 ast_debug(1, "Closing ao2_container channel storage driver %s\n", driver ? driver->name : "NULL");
290 if (!driver) {
291 return;
292 }
293
294 if (driver->handle) {
295 if (getdb(driver)) {
297 ao2_ref(getdb(driver), -1);
298 getdb(driver) = NULL;
299 }
300 ast_free(driver->handle);
301 driver->handle = NULL;
302 }
303 ast_free(driver);
304}
305
307 .handle = NULL,
308 .close = close_instance,
309 .insert = insert_channel,
310 .remove = delete_channel,
311 .rdlock = lock_driver,
312 .wrlock = lock_driver,
313 .unlock = unlock_driver,
314 .active_channels = active_channels,
315 .callback = callback,
316 .get_by_name_prefix_or_uniqueid = get_by_name_prefix,
317 .get_by_exten = get_by_exten,
318 .get_by_uniqueid = get_by_uniqueid,
319 .iterator_all_new = iterator_all_new,
320 .iterator_by_name_new = iterator_by_name_new,
321 .iterator_by_exten_new = iterator_by_exten_new,
322 .iterator_next = iterator_next,
323 .iterator_destroy = iterator_destroy,
324};
325
326static int channel_cmp_cb(void *obj_left, void *obj_right, int flags)
327{
328 struct ast_channel *tps_left = obj_left;
329 struct ast_channel *tps_right = obj_right;
330 const char *right_key = obj_right;
331 int cmp;
332
333 switch (flags & OBJ_SEARCH_MASK) {
334 default:
336 right_key = ast_channel_name(tps_right);
337 /* Fall through */
338 case OBJ_SEARCH_KEY:
339 cmp = strcasecmp(ast_channel_name(tps_left), right_key);
340 break;
342 cmp = strncasecmp(ast_channel_name(tps_left), right_key, strlen(right_key));
343 break;
344 }
345 return cmp == 0 ? CMP_MATCH : 0;
346}
347
348
350{
351 const char *_name = name ? name : "default";
352 struct ast_channelstorage_instance* driver = ast_calloc(1,
353 sizeof(*driver) + strlen(_name) + 1);
354
355 ast_debug(1, "Opening channel storage driver %s\n", _name);
356
357 if (!driver) {
358 ast_log(LOG_ERROR, "Failed to allocate memory for channel storage driver %s\n",
359 _name);
360 return NULL;
361 }
362 memcpy(driver, &channelstorage_instance, sizeof(*driver));
363 strcpy(driver->name, _name); /* Safe */
364 driver->handle = ast_calloc(1, sizeof(*driver->handle));
365 if (!driver->handle) {
366 close_instance(driver);
367 ast_log(LOG_ERROR, "Failed to allocate memory for channel storage driver %s\n",
368 _name);
369 return NULL;
370 }
371
374 if (!driver->handle) {
375 ast_log(LOG_ERROR, "Failed to create channel storage driver %s\n",
376 _name);
377 close_instance(driver);
378 return NULL;
379 }
381 ast_debug(1, "Opened channel storage driver %s. driver: %p container: %p\n",
382 _name, driver, driver->handle);
383
384 return driver;
385}
386
388 .driver_name = "ao2_legacy",
389 .open = get_instance,
390};
391
392static void __attribute__((constructor)) __startup(void)
393{
395}
396
397
ast_mutex_t lock
Definition: app_sla.c:337
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_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int() ao2_callback_data_fn(void *obj, void *arg, void *data, int flags)
Type of a generic callback function.
Definition: astobj2.h:1244
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
Definition: astobj2.h:1435
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2972
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
#define AST_NUM_CHANNEL_BUCKETS
Definition: channel.h:157
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
int ast_channelstorage_register_driver(const struct ast_channelstorage_driver *driver_type)
static int by_exten_cb(void *obj, void *arg, void *data, int flags)
static void lock_driver(struct ast_channelstorage_instance *driver)
static struct ast_channel * get_by_uniqueid(struct ast_channelstorage_instance *driver, const char *uniqueid)
static struct ast_channelstorage_driver driver_type
static struct ast_channel_iterator * iterator_by_exten_new(struct ast_channelstorage_instance *driver, const char *exten, const char *context)
static void close_instance(struct ast_channelstorage_instance *driver)
static void __startup(void)
static struct ast_channel * get_by_name_prefix(struct ast_channelstorage_instance *driver, const char *name, size_t name_len)
static struct ast_channel * iterator_next(struct ast_channelstorage_instance *driver, struct ast_channel_iterator *i)
static int active_channels(struct ast_channelstorage_instance *driver)
returns number of active/allocated channels
static int by_uniqueid_cb(void *obj, void *arg, void *data, int flags)
static int channel_cmp_cb(void *obj_left, void *obj_right, int flags)
static struct ast_channel_iterator * iterator_destroy(struct ast_channelstorage_instance *driver, struct ast_channel_iterator *i)
static struct ast_channel_iterator * iterator_by_name_new(struct ast_channelstorage_instance *driver, const char *name, size_t name_len)
static void unlock_driver(struct ast_channelstorage_instance *driver)
static struct ast_channelstorage_instance channelstorage_instance
#define getdb(driver)
static void prnt_channel_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
static int hash_cb(const void *obj, const int flags)
static int insert_channel(struct ast_channelstorage_instance *driver, struct ast_channel *chan, int flags, int lock)
static struct ast_channel * get_by_exten(struct ast_channelstorage_instance *driver, const char *exten, const char *context)
static struct ast_channel_iterator * iterator_all_new(struct ast_channelstorage_instance *driver)
static int by_name_cb(void *obj, void *arg, void *data, int flags)
static struct ast_channelstorage_instance * get_instance(const char *name)
static int delete_channel(struct ast_channelstorage_instance *driver, struct ast_channel *chan, int lock)
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
static const char name[]
Definition: format_mp3.c:68
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
struct ao2_iterator simple_iterator
struct ao2_iterator * active_iterator
Main Channel structure associated with a channel.
struct ast_channel_id uniqueid
char exten[AST_MAX_EXTENSION]
const char * data
struct ast_flags flags
struct ast_channelstorage_driver_pvt * handle