Asterisk - The Open Source Telephony Project GIT-master-0a46be9
res_websocket_client.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2025, 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/*** MODULEINFO
20 <support_level>core</support_level>
21 ***/
22
23/*** DOCUMENTATION
24 <configInfo name="res_websocket_client" language="en_US">
25 <synopsis>Websocket Client Configuration</synopsis>
26 <configFile name="websocket_client.conf">
27 <configObject name="websocket_client">
28 <since>
29 <version>20.15.0</version>
30 <version>21.10.0</version>
31 <version>22.5.0</version>
32 </since>
33 <synopsis>Websocket Client Configuration</synopsis>
34 <see-also>
35 <ref type="link">/Configuration/Channel-Drivers/WebSocket/</ref>
36 <ref type="link">/Configuration/Interfaces/Asterisk-REST-Interface-ARI/ARI-Outbound-Websockets/</ref>
37 </see-also>
38 <description>
39 <para>
40 These config objects are currently shared by the following Asterisk capabilities:
41 </para>
42 <enumlist>
43 <enum name="chan_websocket"><para>The WebSocket channel driver.</para></enum>
44 <enum name="res_ari"><para>ARI Outbound WebSockets.</para></enum>
45 </enumlist>
46 <para>
47 They may have more specific information or restrictions on the parameters below.
48 </para>
49 <example title="websocket_client.conf">
50;
51; A connection for use by chan_websocket
52[media_connection1]
53type = websocket_client
54uri = ws://localhost:8787
55protocols = media
56username = media_username
57password = media_password
58connection_type = per_call_config
59connection_timeout = 500
60reconnect_interval = 500
61reconnect_attempts = 5
62tls_enabled = no
63;
64; A TLS connection for use by ARI Outbound Websocket
65[ari_connection1]
66type = websocket_client
67uri = wss://localhost:8765
68protocols = ari
69username = some_username
70password = some_password
71connection_type = persistent
72connection_timeout = 500
73reconnect_interval = 500
74reconnect_attempts = 5
75tls_enabled = yes
76ca_list_file = /etc/pki/tls/cert.pem
77verify_server_cert = no
78verify_server_hostname = no
79 </example>
80 </description>
81 <configOption name="type">
82 <since>
83 <version>20.15.0</version>
84 <version>21.10.0</version>
85 <version>22.5.0</version>
86 </since>
87 <synopsis>Must be "websocket_client".</synopsis>
88 </configOption>
89 <configOption name="uri">
90 <since>
91 <version>20.15.0</version>
92 <version>21.10.0</version>
93 <version>22.5.0</version>
94 </since>
95 <synopsis>Full URI to remote server.</synopsis>
96 </configOption>
97 <configOption name="protocols">
98 <since>
99 <version>20.15.0</version>
100 <version>21.10.0</version>
101 <version>22.5.0</version>
102 </since>
103 <synopsis>Comma separated list of protocols acceptable to the server.</synopsis>
104 </configOption>
105 <configOption name="username">
106 <since>
107 <version>20.15.0</version>
108 <version>21.10.0</version>
109 <version>22.5.0</version>
110 </since>
111 <synopsis>Server authentication username if required.</synopsis>
112 </configOption>
113 <configOption name="password">
114 <since>
115 <version>20.15.0</version>
116 <version>21.10.0</version>
117 <version>22.5.0</version>
118 </since>
119 <synopsis>Server authentication password if required.</synopsis>
120 </configOption>
121 <configOption name="connection_type">
122 <since>
123 <version>20.15.0</version>
124 <version>21.10.0</version>
125 <version>22.5.0</version>
126 </since>
127 <synopsis>Single persistent connection or per-call configuration.</synopsis>
128 <description>
129 <enumlist>
130 <enum name="persistent"><para>Single persistent connection for all calls.</para></enum>
131 <enum name="per_call_config"><para>New connection for each call to the Stasis() dialplan app.</para></enum>
132 </enumlist>
133 </description>
134 </configOption>
135 <configOption name="connection_timeout">
136 <since>
137 <version>20.15.0</version>
138 <version>21.10.0</version>
139 <version>22.5.0</version>
140 </since>
141 <synopsis>Connection timeout (ms).</synopsis>
142 </configOption>
143 <configOption name="reconnect_attempts">
144 <since>
145 <version>20.15.0</version>
146 <version>21.10.0</version>
147 <version>22.5.0</version>
148 </since>
149 <synopsis>On failure, how many times should reconnection be attempted?</synopsis>
150 <description>
151 <para>
152 For per_call connections, this is the number of
153 (re)connection attempts to make before returning an
154 and terminating the call. Persistent connections
155 always retry forever but this setting will control
156 how often failure messages are logged.
157 </para>
158 </description>
159 </configOption>
160 <configOption name="reconnect_interval">
161 <since>
162 <version>20.15.0</version>
163 <version>21.10.0</version>
164 <version>22.5.0</version>
165 </since>
166 <synopsis>How often should reconnection be attempted (ms)?</synopsis>
167 </configOption>
168 <configOption name="tls_enabled">
169 <since>
170 <version>20.15.0</version>
171 <version>21.10.0</version>
172 <version>22.5.0</version>
173 </since>
174 <synopsis>Enable TLS</synopsis>
175 </configOption>
176 <configOption name="ca_list_file">
177 <since>
178 <version>20.15.0</version>
179 <version>21.10.0</version>
180 <version>22.5.0</version>
181 </since>
182 <synopsis>File containing the server's CA certificate. (optional)</synopsis>
183 </configOption>
184 <configOption name="ca_list_path">
185 <since>
186 <version>20.15.0</version>
187 <version>21.10.0</version>
188 <version>22.5.0</version>
189 </since>
190 <synopsis>Path to a directory containing one or more hashed CA certificates. (optional)</synopsis>
191 </configOption>
192 <configOption name="cert_file">
193 <since>
194 <version>20.15.0</version>
195 <version>21.10.0</version>
196 <version>22.5.0</version>
197 </since>
198 <synopsis>File containing a client certificate. (optional)</synopsis>
199 </configOption>
200 <configOption name="priv_key_file">
201 <since>
202 <version>20.15.0</version>
203 <version>21.10.0</version>
204 <version>22.5.0</version>
205 </since>
206 <synopsis>File containing the client's private key. (optional)</synopsis>
207 </configOption>
208 <configOption name="verify_server_cert">
209 <since>
210 <version>20.15.0</version>
211 <version>21.10.0</version>
212 <version>22.5.0</version>
213 </since>
214 <synopsis>If set to true, verify the server's certificate. (optional)</synopsis>
215 </configOption>
216 <configOption name="verify_server_hostname">
217 <since>
218 <version>20.15.0</version>
219 <version>21.10.0</version>
220 <version>22.5.0</version>
221 </since>
222 <synopsis>If set to true, verify that the server's hostname matches the common name in it's certificate. (optional)</synopsis>
223 </configOption>
224 </configObject>
225 </configFile>
226 </configInfo>
227***/
228
229
230#include "asterisk.h"
231
232#include "asterisk/module.h"
233#include "asterisk/astobj2.h"
234#include "asterisk/strings.h"
235#include "asterisk/vector.h"
237
238static struct ast_sorcery *sorcery = NULL;
239
241 const char *uri_params)
242{
243 ast_string_field_set(wc, uri_params, uri_params);
244}
245
247 void *lock_obj, const char *display_name, enum ast_websocket_result *result)
248{
249 int reconnect_counter = wc->reconnect_attempts;
250 char *uri = NULL;
251
252 if (ast_strlen_zero(display_name)) {
253 display_name = ast_sorcery_object_get_id(wc);
254 }
255
256 if (!ast_strlen_zero(wc->uri_params)) {
257 /*
258 * If the configured URI doesn't already contain parameters, we append the
259 * new ones to the URI path component with '?'. If it does, we append the
260 * new ones to the existing ones with a '&'.
261 */
262 char sep = '?';
263 uri = ast_alloca(strlen(wc->uri) + strlen(wc->uri_params) + 2);
264 if (strchr(wc->uri, '?')) {
265 sep = '&';
266 }
267 sprintf(uri, "%s%c%s", wc->uri, sep, wc->uri_params); /*Safe */
268 }
269
270 while (1) {
271 struct ast_websocket *astws = NULL;
273 .uri = S_OR(uri, wc->uri),
274 .protocols = wc->protocols,
275 .username = wc->username,
276 .password = wc->password,
277 .timeout = wc->connect_timeout,
278 .suppress_connection_msgs = 1,
279 .tls_cfg = NULL,
280 };
281
282 if (lock_obj) {
283 ao2_lock(lock_obj);
284 }
285
286 if (wc->tls_enabled) {
287 /*
288 * tls_cfg and its contents are freed automatically
289 * by res_http_websocket when the connection ends.
290 * We create it even if tls is not enabled to we can
291 * suppress connection error messages and print our own.
292 */
293 options.tls_cfg = ast_calloc(1, sizeof(*options.tls_cfg));
294 if (!options.tls_cfg) {
295 if (lock_obj) {
296 ao2_unlock(lock_obj);
297 }
298 return NULL;
299 }
300 /* TLS options */
301 options.tls_cfg->enabled = wc->tls_enabled;
302 options.tls_cfg->cafile = ast_strdup(wc->ca_list_file);
303 options.tls_cfg->capath = ast_strdup(wc->ca_list_path);
304 options.tls_cfg->certfile = ast_strdup(wc->cert_file);
305 options.tls_cfg->pvtfile = ast_strdup(wc->priv_key_file);
308 }
309
311 if (astws && *result == WS_OK) {
312 if (lock_obj) {
313 ao2_unlock(lock_obj);
314 }
315 return astws;
316 }
317
318 reconnect_counter--;
319 if (reconnect_counter <= 0) {
322 "%s: Websocket connection to %s failed after %d tries: %s%s%s%s. Retrying in %d ms.\n",
323 display_name,
324 wc->uri,
327 errno ? " (" : "",
328 errno ? strerror(errno) : "",
329 errno ? ")" : "",
331 );
332 } else {
334 "%s: Websocket connection to %s failed after %d tries: %s%s%s%s. Hanging up after exhausting retries.\n",
335 display_name,
336 wc->uri,
339 errno ? " (" : "",
340 errno ? strerror(errno) : "",
341 errno ? ")" : ""
342 );
343 }
344 break;
345 }
346
347 if (lock_obj) {
348 ao2_lock(lock_obj);
349 }
350 usleep(wc->reconnect_interval * 1000);
351 }
352
353 return NULL;
354}
355
356
357
358static void wc_dtor(void *obj)
359{
360 struct ast_websocket_client *wc = obj;
361
362 ast_debug(3, "%s: Disposing of websocket client config\n",
365}
366
367static void *wc_alloc(const char *id)
368{
369 struct ast_websocket_client *wc = NULL;
370
371 wc = ast_sorcery_generic_alloc(sizeof(*wc), wc_dtor);
372 if (!wc) {
373 return NULL;
374 }
375
376 if (ast_string_field_init(wc, 1024) != 0) {
377 ao2_cleanup(wc);
378 return NULL;
379 }
380
381 if (ast_string_field_init_extended(wc, uri_params) != 0) {
382 ao2_cleanup(wc);
383 return NULL;
384 }
385
386 ast_debug(2, "%s: Allocated websocket client config\n", id);
387 return wc;
388}
389
391 struct ast_variable *var, void *obj)
392{
393 struct ast_websocket_client *ws = obj;
394
395 if (strcasecmp(var->value, "persistent") == 0) {
397 } else if (strcasecmp(var->value, "per_call_config") == 0) {
399 } else {
400 return -1;
401 }
402
403 return 0;
404}
405
406static int websocket_client_connection_type_to_str(const void *obj, const intptr_t *args, char **buf)
407{
408 const struct ast_websocket_client *wc = obj;
409
411 *buf = ast_strdup("persistent");
413 *buf = ast_strdup("per_call_config");
414 } else {
415 return -1;
416 }
417
418 return 0;
419}
420
421/*
422 * Can't use INT_MIN because it's an expression
423 * and macro substitutions using stringify can't
424 * handle that.
425 */
426#define DEFAULT_RECONNECT_ATTEMPTS -2147483648
427
428static int wc_apply(const struct ast_sorcery *sorcery, void *obj)
429{
430 struct ast_websocket_client *wc = obj;
431 const char *id = ast_sorcery_object_get_id(wc);
432 int res = 0;
433
434 ast_debug(3, "%s: Applying config\n", id);
435
436 if (ast_strlen_zero(wc->uri)) {
437 ast_log(LOG_WARNING, "%s: Websocket client missing uri\n", id);
438 res = -1;
439 }
440
441 if (res != 0) {
442 ast_log(LOG_WARNING, "%s: Websocket client configuration failed\n", id);
443 } else {
444 ast_debug(3, "%s: Websocket client configuration succeeded\n", id);
445
448 wc->reconnect_attempts = INT_MAX;
449 } else {
450 wc->reconnect_attempts = 4;
451 }
452 }
453 }
454
455 return res;
456}
457
459{
460 if (!sorcery) {
461 return NULL;
462 }
463
464 return ast_sorcery_retrieve_by_fields(sorcery, "websocket_client",
466}
467
469{
470 if (!sorcery) {
471 return NULL;
472 }
473
474 return ast_sorcery_retrieve_by_id(sorcery, "websocket_client", id);
475}
476
478 struct ast_websocket_client *old_wc,
479 struct ast_websocket_client *new_wc)
480{
482 const char *new_id = ast_sorcery_object_get_id(new_wc);
483 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
484 struct ast_variable *v = NULL;
485 int res = 0;
486 int changes_found = 0;
487
488 ast_debug(2, "%s: Detecting changes\n", new_id);
489
490 res = ast_sorcery_diff(sorcery, old_wc, new_wc, &changes);
491 if (res != 0) {
492 ast_log(LOG_WARNING, "%s: Failed to create changeset\n", new_id);
494 }
495
496 for (v = changes; v; v = v->next) {
497 changes_found = 1;
498 ast_debug(2, "%s: %s changed to %s\n", new_id, v->name, v->value);
499 if (ast_strings_equal(v->name, "connection_type")) {
501 } else if (ast_strings_equal(v->name, "uri")) {
502 changed |= AST_WS_CLIENT_FIELD_URI;
503 } else if (ast_strings_equal(v->name, "protocols")) {
505 } else if (ast_strings_equal(v->name, "username")) {
507 } else if (ast_strings_equal(v->name, "password")) {
509 } else if (ast_strings_equal(v->name, "tls_enabled")) {
511 } else if (ast_strings_equal(v->name, "ca_list_file")) {
513 } else if (ast_strings_equal(v->name, "ca_list_path")) {
515 } else if (ast_strings_equal(v->name, "cert_file")) {
517 } else if (ast_strings_equal(v->name, "priv_key_file")) {
519 } else if (ast_strings_equal(v->name, "reconnect_interval")) {
521 } else if (ast_strings_equal(v->name, "reconnect_attempts")) {
523 } else if (ast_strings_equal(v->name, "connection_timeout")) {
525 } else if (ast_strings_equal(v->name, "verify_server_cert")) {
527 } else if (ast_strings_equal(v->name, "verify_server_hostname")) {
529 } else {
530 ast_debug(2, "%s: Unknown change %s\n", new_id, v->name);
531 }
532 }
533
534 if (!changes_found) {
535 ast_debug(2, "%s: No changes found %p %p\n", new_id,
536 old_wc,new_wc);
537 }
538 return changed;
539
540}
541
543{
544 if (!sorcery || !callbacks) {
545 return -1;
546 }
547
548 if (ast_sorcery_observer_add(sorcery, "websocket_client", callbacks)) {
549 ast_log(LOG_ERROR, "Failed to register websocket client observers\n");
550 return -1;
551 }
552
553 return 0;
554}
555
557{
558 if (!sorcery || !callbacks) {
559 return;
560 }
561
562 ast_sorcery_observer_remove(sorcery, "websocket_client", callbacks);
563}
564
565
566static int load_module(void)
567{
568 ast_debug(2, "Initializing Websocket Client Configuration\n");
570 if (!sorcery) {
571 ast_log(LOG_ERROR, "Failed to open sorcery\n");
572 return -1;
573 }
574
575 ast_sorcery_apply_default(sorcery, "websocket_client", "config",
576 "websocket_client.conf,criteria=type=websocket_client");
577
578 if (ast_sorcery_object_register(sorcery, "websocket_client", wc_alloc,
579 NULL, wc_apply)) {
580 ast_log(LOG_ERROR, "Failed to register websocket_client object with sorcery\n");
582 sorcery = NULL;
583 return -1;
584 }
585
586 ast_sorcery_object_field_register(sorcery, "websocket_client", "type", "", OPT_NOOP_T, 0, 0);
587 ast_sorcery_register_cust(websocket_client, connection_type, "");
592 ast_sorcery_register_sf(websocket_client, ast_websocket_client, ca_list_file, ca_list_file, "");
593 ast_sorcery_register_sf(websocket_client, ast_websocket_client, ca_list_path, ca_list_path, "");
595 ast_sorcery_register_sf(websocket_client, ast_websocket_client, priv_key_file, priv_key_file, "");
596 ast_sorcery_register_bool(websocket_client, ast_websocket_client, tls_enabled, tls_enabled, "no");
597 ast_sorcery_register_bool(websocket_client, ast_websocket_client, verify_server_cert, verify_server_cert, "yes");
598 ast_sorcery_register_bool(websocket_client, ast_websocket_client, verify_server_hostname, verify_server_hostname, "yes");
599 ast_sorcery_register_int(websocket_client, ast_websocket_client, connection_timeout, connect_timeout, 500);
600 ast_sorcery_register_int(websocket_client, ast_websocket_client, reconnect_attempts, reconnect_attempts, 4);
601 ast_sorcery_register_int(websocket_client, ast_websocket_client, reconnect_interval, reconnect_interval, 500);
602
604
605 return 0;
606}
607
608static int reload_module(void)
609{
610 ast_debug(2, "Reloading Websocket Client Configuration\n");
612
613 return 0;
614}
615
617{
618 ast_debug(2, "Reloading Websocket Client Configuration\n");
619 if (sorcery) {
621 }
622
623 return 0;
624}
625
626static int unload_module(void)
627{
628 ast_debug(2, "Unloading Websocket Client Configuration\n");
629 if (sorcery) {
631 sorcery = NULL;
632 }
633 return 0;
634}
635
637 .support_level = AST_MODULE_SUPPORT_CORE,
638 .load = load_module,
639 .unload = unload_module,
641 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
642 .requires = "res_http_websocket",
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
static PGresult * result
Definition: cel_pgsql.c:84
@ OPT_NOOP_T
Type for a default handler that should do nothing.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct ast_websocket * ast_websocket_client_create_with_options(struct ast_websocket_client_options *options, enum ast_websocket_result *result)
Create, and connect, a websocket client using given options.
const char * ast_websocket_result_to_str(enum ast_websocket_result result)
Convert a websocket result code to a string.
ast_websocket_result
Result code for a websocket client.
@ WS_OK
@ AST_WS_TYPE_CLIENT_PER_CALL_CONFIG
@ AST_WS_TYPE_CLIENT_PERSISTENT
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
int errno
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:340
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
static int reload(void)
struct @474 callbacks
static int websocket_client_connection_type_to_str(const void *obj, const intptr_t *args, char **buf)
void ast_websocket_client_add_uri_params(struct ast_websocket_client *wc, const char *uri_params)
Add additional parameters to the URI.
struct ao2_container * ast_websocket_client_retrieve_all(void)
Retrieve a container of all websocket client objects.
int ast_websocket_client_reload(void)
Force res_websocket_client to reload its configuration.
static void * wc_alloc(const char *id)
enum ast_ws_client_fields ast_websocket_client_get_field_diff(struct ast_websocket_client *old_wc, struct ast_websocket_client *new_wc)
Detect changes between two websocket client configurations.
static int wc_apply(const struct ast_sorcery *sorcery, void *obj)
struct ast_websocket_client * ast_websocket_client_retrieve_by_id(const char *id)
Retrieve a websocket client object by ID.
static int reload_module(void)
static struct ast_sorcery * sorcery
static int websocket_client_connection_type_from_str(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int load_module(void)
#define DEFAULT_RECONNECT_ATTEMPTS
void ast_websocket_client_observer_remove(const struct ast_sorcery_observer *callbacks)
Remove sorcery observers for websocket client events.
int ast_websocket_client_observer_add(const struct ast_sorcery_observer *callbacks)
Add sorcery observers for websocket client events.
static int unload_module(void)
static void wc_dtor(void *obj)
struct ast_websocket * ast_websocket_client_connect(struct ast_websocket_client *wc, void *lock_obj, const char *display_name, enum ast_websocket_result *result)
Connect to a websocket server using the configured authentication, retry and TLS options.
#define NULL
Definition: resample.c:96
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2380
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2486
#define ast_sorcery_register_cust(object, option, def_value)
Register a custom field within an object.
Definition: sorcery.h:1767
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1440
int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
Create a changeset of two objects.
Definition: sorcery.c:1868
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1916
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1471
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2454
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1791
#define ast_sorcery_register_int(object, structure, option, field, def_value)
Register an int field as type OPT_INT_T within an object.
Definition: sorcery.h:1710
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
#define ast_sorcery_register_bool(object, structure, option, field, def_value)
Register a boolean field as type OPT_YESNO_T within an object.
Definition: sorcery.h:1684
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1960
#define ast_sorcery_register_sf(object, structure, option, field, def_value)
Register a stringfield field as type OPT_STRINGFIELD_T within an object.
Definition: sorcery.h:1746
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
Definition: stringfields.h:401
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Generic container type.
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Full structure for sorcery.
Definition: sorcery.c:231
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Options used for a websocket client.
unsigned int reconnect_interval
const ast_string_field uri
enum ast_websocket_type connection_type
const ast_string_field ca_list_path
const ast_string_field cert_file
const ast_string_field password
const ast_string_field username
const ast_string_field ca_list_file
const ast_string_field protocols
const ast_string_field priv_key_file
unsigned int reconnect_attempts
Structure definition for session.
@ AST_SSL_DONT_VERIFY_SERVER
Definition: tcptls.h:69
@ AST_SSL_IGNORE_COMMON_NAME
Definition: tcptls.h:71
const char * args
static struct test_options options
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
Vector container support.
ast_ws_client_fields
@ AST_WS_CLIENT_FIELD_RECONNECT_INTERVAL
@ AST_WS_CLIENT_FIELD_NONE
@ AST_WS_CLIENT_FIELD_URI
@ AST_WS_CLIENT_FIELD_PROTOCOLS
@ AST_WS_CLIENT_FIELD_CA_LIST_PATH
@ AST_WS_CLIENT_FIELD_TLS_ENABLED
@ AST_WS_CLIENT_FIELD_CA_LIST_FILE
@ AST_WS_CLIENT_FIELD_USERNAME
@ AST_WS_CLIENT_FIELD_VERIFY_SERVER_CERT
@ AST_WS_CLIENT_FIELD_PASSWORD
@ AST_WS_CLIENT_FIELD_CONNECTION_TIMEOUT
@ AST_WS_CLIENT_FIELD_RECONNECT_ATTEMPTS
@ AST_WS_CLIENT_FIELD_CONNECTION_TYPE
@ AST_WS_CLIENT_FIELD_VERIFY_SERVER_HOSTNAME
@ AST_WS_CLIENT_FIELD_CERT_FILE
@ AST_WS_CLIENT_FIELD_PRIV_KEY_FILE