Asterisk - The Open Source Telephony Project GIT-master-fe341c2
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 void *lock_obj, const char *display_name, enum ast_websocket_result *result)
242{
243 int reconnect_counter = wc->reconnect_attempts;
244
245 if (ast_strlen_zero(display_name)) {
246 display_name = ast_sorcery_object_get_id(wc);
247 }
248
249 while (1) {
250 struct ast_websocket *astws = NULL;
252 .uri = wc->uri,
253 .protocols = wc->protocols,
254 .username = wc->username,
255 .password = wc->password,
256 .timeout = wc->connect_timeout,
257 .suppress_connection_msgs = 1,
258 .tls_cfg = NULL,
259 };
260
261 if (lock_obj) {
262 ao2_lock(lock_obj);
263 }
264
265 if (wc->tls_enabled) {
266 /*
267 * tls_cfg and its contents are freed automatically
268 * by res_http_websocket when the connection ends.
269 * We create it even if tls is not enabled to we can
270 * suppress connection error messages and print our own.
271 */
272 options.tls_cfg = ast_calloc(1, sizeof(*options.tls_cfg));
273 if (!options.tls_cfg) {
274 if (lock_obj) {
275 ao2_unlock(lock_obj);
276 }
277 return NULL;
278 }
279 /* TLS options */
280 options.tls_cfg->enabled = wc->tls_enabled;
281 options.tls_cfg->cafile = ast_strdup(wc->ca_list_file);
282 options.tls_cfg->capath = ast_strdup(wc->ca_list_path);
283 options.tls_cfg->certfile = ast_strdup(wc->cert_file);
284 options.tls_cfg->pvtfile = ast_strdup(wc->priv_key_file);
287 }
288
290 if (astws && *result == WS_OK) {
291 if (lock_obj) {
292 ao2_unlock(lock_obj);
293 }
294 return astws;
295 }
296
297 reconnect_counter--;
298 if (reconnect_counter <= 0) {
301 "%s: Websocket connection to %s failed after %d tries: %s%s%s%s. Retrying in %d ms.\n",
302 display_name,
303 wc->uri,
306 errno ? " (" : "",
307 errno ? strerror(errno) : "",
308 errno ? ")" : "",
310 );
311 } else {
313 "%s: Websocket connection to %s failed after %d tries: %s%s%s%s. Hanging up after exhausting retries.\n",
314 display_name,
315 wc->uri,
318 errno ? " (" : "",
319 errno ? strerror(errno) : "",
320 errno ? ")" : ""
321 );
322 }
323 break;
324 }
325
326 if (lock_obj) {
327 ao2_lock(lock_obj);
328 }
329 usleep(wc->reconnect_interval * 1000);
330 }
331
332 return NULL;
333}
334
335
336
337static void wc_dtor(void *obj)
338{
339 struct ast_websocket_client *wc = obj;
340
341 ast_debug(3, "%s: Disposing of websocket client config\n",
344}
345
346static void *wc_alloc(const char *id)
347{
348 struct ast_websocket_client *wc = NULL;
349
350 wc = ast_sorcery_generic_alloc(sizeof(*wc), wc_dtor);
351 if (!wc) {
352 return NULL;
353 }
354
355 if (ast_string_field_init(wc, 1024) != 0) {
356 ao2_cleanup(wc);
357 return NULL;
358 }
359
360 ast_debug(2, "%s: Allocated websocket client config\n", id);
361 return wc;
362}
363
365 struct ast_variable *var, void *obj)
366{
367 struct ast_websocket_client *ws = obj;
368
369 if (strcasecmp(var->value, "persistent") == 0) {
371 } else if (strcasecmp(var->value, "per_call_config") == 0) {
373 } else {
374 return -1;
375 }
376
377 return 0;
378}
379
380static int websocket_client_connection_type_to_str(const void *obj, const intptr_t *args, char **buf)
381{
382 const struct ast_websocket_client *wc = obj;
383
385 *buf = ast_strdup("persistent");
387 *buf = ast_strdup("per_call_config");
388 } else {
389 return -1;
390 }
391
392 return 0;
393}
394
395/*
396 * Can't use INT_MIN because it's an expression
397 * and macro substitutions using stringify can't
398 * handle that.
399 */
400#define DEFAULT_RECONNECT_ATTEMPTS -2147483648
401
402static int wc_apply(const struct ast_sorcery *sorcery, void *obj)
403{
404 struct ast_websocket_client *wc = obj;
405 const char *id = ast_sorcery_object_get_id(wc);
406 int res = 0;
407
408 ast_debug(3, "%s: Applying config\n", id);
409
410 if (ast_strlen_zero(wc->uri)) {
411 ast_log(LOG_WARNING, "%s: Websocket client missing uri\n", id);
412 res = -1;
413 }
414
415 if (res != 0) {
416 ast_log(LOG_WARNING, "%s: Websocket client configuration failed\n", id);
417 } else {
418 ast_debug(3, "%s: Websocket client configuration succeeded\n", id);
419
422 wc->reconnect_attempts = INT_MAX;
423 } else {
424 wc->reconnect_attempts = 4;
425 }
426 }
427 }
428
429 return res;
430}
431
433{
434 if (!sorcery) {
435 return NULL;
436 }
437
438 return ast_sorcery_retrieve_by_fields(sorcery, "websocket_client",
440}
441
443{
444 if (!sorcery) {
445 return NULL;
446 }
447
448 return ast_sorcery_retrieve_by_id(sorcery, "websocket_client", id);
449}
450
452 struct ast_websocket_client *old_wc,
453 struct ast_websocket_client *new_wc)
454{
456 const char *new_id = ast_sorcery_object_get_id(new_wc);
457 RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
458 struct ast_variable *v = NULL;
459 int res = 0;
460 int changes_found = 0;
461
462 ast_debug(2, "%s: Detecting changes\n", new_id);
463
464 res = ast_sorcery_diff(sorcery, old_wc, new_wc, &changes);
465 if (res != 0) {
466 ast_log(LOG_WARNING, "%s: Failed to create changeset\n", new_id);
468 }
469
470 for (v = changes; v; v = v->next) {
471 changes_found = 1;
472 ast_debug(2, "%s: %s changed to %s\n", new_id, v->name, v->value);
473 if (ast_strings_equal(v->name, "connection_type")) {
475 } else if (ast_strings_equal(v->name, "uri")) {
476 changed |= AST_WS_CLIENT_FIELD_URI;
477 } else if (ast_strings_equal(v->name, "protocols")) {
479 } else if (ast_strings_equal(v->name, "username")) {
481 } else if (ast_strings_equal(v->name, "password")) {
483 } else if (ast_strings_equal(v->name, "tls_enabled")) {
485 } else if (ast_strings_equal(v->name, "ca_list_file")) {
487 } else if (ast_strings_equal(v->name, "ca_list_path")) {
489 } else if (ast_strings_equal(v->name, "cert_file")) {
491 } else if (ast_strings_equal(v->name, "priv_key_file")) {
493 } else if (ast_strings_equal(v->name, "reconnect_interval")) {
495 } else if (ast_strings_equal(v->name, "reconnect_attempts")) {
497 } else if (ast_strings_equal(v->name, "connection_timeout")) {
499 } else if (ast_strings_equal(v->name, "verify_server_cert")) {
501 } else if (ast_strings_equal(v->name, "verify_server_hostname")) {
503 } else {
504 ast_debug(2, "%s: Unknown change %s\n", new_id, v->name);
505 }
506 }
507
508 if (!changes_found) {
509 ast_debug(2, "%s: No changes found %p %p\n", new_id,
510 old_wc,new_wc);
511 }
512 return changed;
513
514}
515
517{
518 if (!sorcery || !callbacks) {
519 return -1;
520 }
521
522 if (ast_sorcery_observer_add(sorcery, "websocket_client", callbacks)) {
523 ast_log(LOG_ERROR, "Failed to register websocket client observers\n");
524 return -1;
525 }
526
527 return 0;
528}
529
531{
532 if (!sorcery || !callbacks) {
533 return;
534 }
535
536 ast_sorcery_observer_remove(sorcery, "websocket_client", callbacks);
537}
538
539
540static int load_module(void)
541{
542 ast_debug(2, "Initializing Websocket Client Configuration\n");
544 if (!sorcery) {
545 ast_log(LOG_ERROR, "Failed to open sorcery\n");
546 return -1;
547 }
548
549 ast_sorcery_apply_default(sorcery, "websocket_client", "config",
550 "websocket_client.conf,criteria=type=websocket_client");
551
552 if (ast_sorcery_object_register(sorcery, "websocket_client", wc_alloc,
553 NULL, wc_apply)) {
554 ast_log(LOG_ERROR, "Failed to register websocket_client object with sorcery\n");
556 sorcery = NULL;
557 return -1;
558 }
559
560 ast_sorcery_object_field_register(sorcery, "websocket_client", "type", "", OPT_NOOP_T, 0, 0);
561 ast_sorcery_register_cust(websocket_client, connection_type, "");
566 ast_sorcery_register_sf(websocket_client, ast_websocket_client, ca_list_file, ca_list_file, "");
567 ast_sorcery_register_sf(websocket_client, ast_websocket_client, ca_list_path, ca_list_path, "");
569 ast_sorcery_register_sf(websocket_client, ast_websocket_client, priv_key_file, priv_key_file, "");
570 ast_sorcery_register_bool(websocket_client, ast_websocket_client, tls_enabled, tls_enabled, "no");
571 ast_sorcery_register_bool(websocket_client, ast_websocket_client, verify_server_cert, verify_server_cert, "yes");
572 ast_sorcery_register_bool(websocket_client, ast_websocket_client, verify_server_hostname, verify_server_hostname, "yes");
573 ast_sorcery_register_int(websocket_client, ast_websocket_client, connection_timeout, connect_timeout, 500);
574 ast_sorcery_register_int(websocket_client, ast_websocket_client, reconnect_attempts, reconnect_attempts, 4);
575 ast_sorcery_register_int(websocket_client, ast_websocket_client, reconnect_interval, reconnect_interval, 500);
576
578
579 return 0;
580}
581
582static int reload_module(void)
583{
584 ast_debug(2, "Reloading Websocket Client Configuration\n");
586
587 return 0;
588}
589
591{
592 ast_debug(2, "Reloading Websocket Client Configuration\n");
593 if (sorcery) {
595 }
596
597 return 0;
598}
599
600static int unload_module(void)
601{
602 ast_debug(2, "Unloading Websocket Client Configuration\n");
603 if (sorcery) {
605 sorcery = NULL;
606 }
607 return 0;
608}
609
611 .support_level = AST_MODULE_SUPPORT_CORE,
612 .load = load_module,
613 .unload = unload_module,
615 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
616 .requires = "res_http_websocket",
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#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 @471 callbacks
static int websocket_client_connection_type_to_str(const void *obj, const intptr_t *args, char **buf)
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:2317
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:2423
#define ast_sorcery_register_cust(object, option, def_value)
Register a custom field within an object.
Definition: sorcery.h:1749
@ 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:1377
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:1805
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:1853
#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:1408
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:2391
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#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:1692
#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:1666
#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:1897
#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:1728
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#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
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:230
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:941
#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