libamxb  4.8.2
Bus Agnostic C API
amxb_ba_connect.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <errno.h>
56 #include <fcntl.h>
57 
58 #include <uriparser/Uri.h>
59 
60 #include <amxc/amxc.h>
61 #include <amxp/amxp.h>
62 
63 #include <amxd/amxd_dm.h>
64 
65 #include <amxb/amxb_be_intf.h>
66 #include <amxb/amxb.h>
67 
68 #include "amxb_priv.h"
69 
70 static amxc_htable_t uri_bus_ctxs;
71 
72 static int amxb_uri_part_to_string(amxc_string_t* buffer,
73  UriTextRangeA* tr) {
74 
75  return amxc_string_append(buffer, tr->first, tr->afterLast - tr->first);
76 }
77 
78 static int amxb_uri_path_to_string(amxc_string_t* buffer,
79  UriPathSegmentA* ps) {
80 
81  const char* sep = "/";
82  while(ps) {
83  amxc_string_append(buffer, sep, strlen(sep));
84  amxb_uri_part_to_string(buffer, &ps->text);
85  sep = "/";
86  ps = ps->next;
87  }
88 
89  return 0;
90 }
91 
92 static int amxb_uri_parse(const char* uri,
93  char** scheme,
94  char** host,
95  char** port,
96  char** path) {
97  int retval = -1;
98  UriUriA parsed_uri;
99  amxc_string_t uri_part;
100  amxc_string_init(&uri_part, 0);
101 
102  when_failed(uriParseSingleUriA(&parsed_uri, uri, NULL), exit);
103  amxb_uri_part_to_string(&uri_part, &parsed_uri.scheme);
104  *scheme = amxc_string_take_buffer(&uri_part);
105  when_null(*scheme, exit_clean);
106  amxb_uri_part_to_string(&uri_part, &parsed_uri.hostText);
107  *host = amxc_string_take_buffer(&uri_part);
108  amxb_uri_part_to_string(&uri_part, &parsed_uri.portText);
109  *port = amxc_string_take_buffer(&uri_part);
110  amxb_uri_path_to_string(&uri_part, parsed_uri.pathHead);
111  *path = amxc_string_take_buffer(&uri_part);
112 
113  retval = 0;
114 
115 exit_clean:
116  uriFreeUriMembersA(&parsed_uri);
117 
118 exit:
119  amxc_string_clean(&uri_part);
120  return retval;
121 }
122 
124  int retval = -1;
125 
126  *ctx = (amxb_bus_ctx_t*) calloc(1, sizeof(amxb_bus_ctx_t));
127  when_null(*ctx, exit);
128 
129  (*ctx)->bus_fn = fns;
130  amxp_sigmngr_init(&(*ctx)->sigmngr);
131  amxc_htable_init(&(*ctx)->subscriptions, 5);
132  amxc_llist_init(&(*ctx)->client_subs);
133  (*ctx)->access = AMXB_PROTECTED;
134  (*ctx)->socket_type = AMXB_DATA_SOCK;
135 
136  retval = 0;
137 exit:
138  return retval;
139 }
140 
142  amxb_be_funcs_t** fns,
143  const char* uri,
144  char** scheme,
145  char** host,
146  char** port,
147  char** path) {
148  int retval = -1;
149 
150  when_null(ctx, exit);
151  when_not_null(*ctx, exit);
152  if(amxb_uri_parse(uri, scheme, host, port, path) != 0) {
153  retval = AMXB_ERROR_INVALID_URI;
154  goto exit;
155  }
156 
157  *fns = amxb_be_find(*scheme);
158  if(*fns == NULL) {
160  goto exit;
161  }
162 
163  retval = amxb_bus_ctx_init(ctx, *fns);
164 
165 exit:
166  return retval;
167 }
168 
170  amxb_be_funcs_t* fns,
172  const char* uri,
173  const char* host,
174  const char* port,
175  const char* path) {
176  int retval = -1;
177 
178  ctx->bus_ctx = fn(host, port, path, &ctx->sigmngr);
179  if(ctx->bus_ctx == NULL) {
180  retval = AMXB_ERROR_BACKEND_FAILED;
181  } else {
182  amxc_llist_append(&fns->connections, &ctx->it);
183  amxc_htable_insert(&uri_bus_ctxs, uri, &ctx->hit);
184  retval = 0;
185  }
186 
187  return retval;
188 }
189 
190 static void amxb_free_request(amxc_llist_it_t* it) {
191  amxb_req_t* req = amxc_container_of(it, amxb_req_t, it);
192  if(req->closed && !req->in_flight) {
193  free(req);
194  }
195 }
196 
197 int amxb_connect_intf(amxb_bus_ctx_t** ctx, const char* uri, const char* intf) {
198  int retval = -1;
199  amxb_be_funcs_t* fns = NULL;
200  char* scheme = NULL;
201  char* host = NULL;
202  char* port = NULL;
203  char* path = NULL;
204 
205  retval = amxb_bus_ctx_create(ctx, &fns, uri, &scheme, &host, &port, &path);
206  when_failed(retval, exit);
207  if((host != NULL) && (*host != 0) && (intf != NULL) && (*intf != 0)) {
208  // add the interface name/index prefixed with % to the host.
209  amxc_string_t host_intf;
210  amxc_string_init(&host_intf, 64);
211  amxc_string_setf(&host_intf, "%s%%%s", host, intf);
212  free(host);
213  host = amxc_string_take_buffer(&host_intf);
214  amxc_string_clean(&host_intf);
215  }
216 
217  if(amxb_is_valid_be_func(fns, connect, fns->connect)) {
218  retval = amxb_bus_ctx_be_init(*ctx, fns, fns->connect, uri, host, port, path);
219  } else {
221  }
222 
223  if(retval != 0) {
224  amxb_free(ctx);
225  }
226 
227 exit:
228  free(scheme);
229  free(port);
230  free(host);
231  free(path);
232  return retval;
233 }
234 
235 int amxb_connect(amxb_bus_ctx_t** ctx, const char* uri) {
236  return amxb_connect_intf(ctx, uri, NULL);
237 }
238 
239 int amxb_listen(amxb_bus_ctx_t** ctx, const char* uri) {
240  int retval = -1;
241  amxb_be_funcs_t* fns = NULL;
242  char* scheme = NULL;
243  char* host = NULL;
244  char* port = NULL;
245  char* path = NULL;
246 
247  retval = amxb_bus_ctx_create(ctx, &fns, uri, &scheme, &host, &port, &path);
248  when_failed(retval, exit);
249  (*ctx)->socket_type = AMXB_LISTEN_SOCK;
250  if(amxb_is_valid_be_func(fns, listen, fns->listen)) {
251  retval = amxb_bus_ctx_be_init(*ctx, fns, fns->listen, uri, host, port, path);
252  } else {
254  }
255 
256  if(retval != 0) {
257  amxb_free(ctx);
258  }
259 
260 exit:
261  free(scheme);
262  free(port);
263  free(host);
264  free(path);
265  return retval;
266 }
267 
268 int amxb_accept(amxb_bus_ctx_t* listen_ctx, amxb_bus_ctx_t** accepted_ctx) {
269  int retval = -1;
270  amxb_be_funcs_t* fns = NULL;
271  const char* uri = NULL;
272  char* scheme = NULL;
273  char* host = NULL;
274  char* port = NULL;
275  char* path = NULL;
276 
277  when_null(listen_ctx, exit);
278  uri = amxc_htable_it_get_key(&listen_ctx->hit);
279  when_null(listen_ctx, exit);
280  retval = amxb_bus_ctx_create(accepted_ctx, &fns, uri, &scheme, &host, &port, &path);
281  when_failed(retval, exit);
282  if(amxb_is_valid_be_func(fns, accept, fns->accept)) {
283  (*accepted_ctx)->bus_ctx = fns->accept(listen_ctx->bus_ctx, &listen_ctx->sigmngr);
284  if((*accepted_ctx)->bus_ctx == NULL) {
285  retval = AMXB_ERROR_BACKEND_FAILED;
286  } else {
287  (*accepted_ctx)->dm = listen_ctx->dm;
288  amxc_llist_append(&fns->connections, &(*accepted_ctx)->it);
289  retval = 0;
290  }
291  } else {
293  }
294 
295 exit:
296  free(scheme);
297  free(port);
298  free(host);
299  free(path);
300  return retval;
301 }
302 
304  int retval = -1;
305  const amxb_be_funcs_t* fns = NULL;
306 
307  when_null(ctx, exit);
308  when_null(ctx->bus_ctx, exit_clean);
309 
311 
312  amxc_llist_for_each(it, &ctx->client_subs) {
313  amxb_sub_t* sub = amxc_container_of(it, amxb_sub_t, it);
315  }
316 
317  fns = ctx->bus_fn;
318  if(amxb_is_valid_be_func(fns, disconnect, fns->disconnect)) {
319  retval = fns->disconnect(ctx->bus_ctx);
320  } else {
322  }
323 
324  if(fns->free != NULL) {
325  fns->free(ctx->bus_ctx);
326  }
327 
328 exit_clean:
329  amxc_llist_clean(&ctx->requests, amxb_free_request);
330  amxc_llist_clean(&ctx->invoke_ctxs, NULL);
331  amxc_llist_it_take(&ctx->it);
332  amxc_htable_it_clean(&ctx->hit, NULL);
333  ctx->bus_ctx = NULL;
334  ctx->bus_fn = NULL;
335 exit:
336  return retval;
337 }
338 
340  when_null(ctx, exit);
341  when_null(*ctx, exit);
342 
343  amxb_disconnect(*ctx);
344  amxp_sigmngr_clean(&(*ctx)->sigmngr);
345 
346  amxc_htable_for_each(it, &(*ctx)->subscriptions) {
347  amxp_slot_disconnect_with_priv(&(*ctx)->dm->sigmngr, amxb_dm_event_to_object_event, it);
348  amxc_htable_it_clean(it, NULL);
349  free(it);
350  }
351  amxc_htable_clean(&(*ctx)->subscriptions, NULL);
352 
353  free(*ctx);
354  *ctx = NULL;
355 
356 exit:
357  return;
358 }
359 
360 amxb_bus_ctx_t* amxb_find_uri(const char* uri) {
361  amxc_htable_it_t* hit = amxc_htable_get(&uri_bus_ctxs, uri);
362  amxb_bus_ctx_t* ctx = NULL;
363 
364  if(hit != NULL) {
365  ctx = amxc_htable_it_get_data(hit, amxb_bus_ctx_t, hit);
366  }
367  return ctx;
368 }
369 
370 amxc_array_t* amxb_list_uris(void) {
371  amxc_array_t* keys = amxc_htable_get_sorted_keys(&uri_bus_ctxs);
372  return keys;
373 }
374 
375 int amxb_get_fd(const amxb_bus_ctx_t* const ctx) {
376  int retval = -1;
377  const amxb_be_funcs_t* fns = NULL;
378 
379  when_null(ctx, exit);
380  when_null(ctx->bus_ctx, exit);
381 
382  fns = ctx->bus_fn;
383  if(amxb_is_valid_be_func(fns, get_fd, fns->get_fd)) {
384  retval = fns->get_fd(ctx->bus_ctx);
385  when_true(retval < 0, exit);
386  }
387 
388 exit:
389  return retval;
390 }
391 
392 int amxb_read(const amxb_bus_ctx_t* const ctx) {
393  int retval = -1;
394  const amxb_be_funcs_t* fns = NULL;
395 
396  when_null(ctx, exit);
397  when_null(ctx->bus_ctx, exit);
398 
399  fns = ctx->bus_fn;
400  if(amxb_is_valid_be_func(fns, read, fns->read)) {
401  retval = fns->read(ctx->bus_ctx);
402  }
403 
404 exit:
405  return retval;
406 }
407 
408 int amxb_read_raw(const amxb_bus_ctx_t* const ctx, void* buf, size_t count) {
409  int retval = -1;
410  const amxb_be_funcs_t* fns = NULL;
411 
412  when_null(ctx, exit);
413  when_null(ctx->bus_ctx, exit);
414  when_null(buf, exit);
415  when_true(count == 0, exit);
416 
417  fns = ctx->bus_fn;
418  if(amxb_is_valid_be_func(fns, read_raw, fns->read_raw)) {
419  retval = fns->read_raw(ctx->bus_ctx, buf, count);
420  }
421 
422 exit:
423  return retval;
424 }
425 
426 CONSTRUCTOR static void amxb_initialize_connections(void) {
427  amxc_htable_init(&uri_bus_ctxs, 10);
428 }
429 
430 DESTRUCTOR static void amxb_cleanup_connections(void) {
431  amxc_htable_clean(&uri_bus_ctxs, NULL);
432 }
Ambiorix bus agnostic API header file.
static int amxb_bus_ctx_be_init(amxb_bus_ctx_t *ctx, amxb_be_funcs_t *fns, amxb_be_connect_fn_t fn, const char *uri, const char *host, const char *port, const char *path)
static int amxb_uri_part_to_string(amxc_string_t *buffer, UriTextRangeA *tr)
static int amxb_bus_ctx_init(amxb_bus_ctx_t **ctx, amxb_be_funcs_t *fns)
static amxc_htable_t uri_bus_ctxs
static int amxb_uri_path_to_string(amxc_string_t *buffer, UriPathSegmentA *ps)
static DESTRUCTOR void amxb_cleanup_connections(void)
static int amxb_bus_ctx_create(amxb_bus_ctx_t **ctx, amxb_be_funcs_t **fns, const char *uri, char **scheme, char **host, char **port, char **path)
static int amxb_uri_parse(const char *uri, char **scheme, char **host, char **port, char **path)
static CONSTRUCTOR void amxb_initialize_connections(void)
static void amxb_free_request(amxc_llist_it_t *it)
Ambiorix Bus Backend Interface.
auto connect
Definition: test.odl:65
int PRIVATE amxb_subscription_remove(amxb_subscription_t *subscription)
#define amxb_is_valid_be_func(ft, member, ptr)
Definition: amxb_priv.h:78
void PRIVATE amxb_dm_event_to_object_event(const char *const sig_name, const amxc_var_t *const data, void *const priv)
Definition: amxb_ba_priv.c:76
#define AMXB_PROTECTED
Definition: amxb_types.h:74
#define AMXB_LISTEN_SOCK
Definition: amxb_types.h:77
#define AMXB_DATA_SOCK
Definition: amxb_types.h:76
void *(* amxb_be_connect_fn_t)(const char *host, const char *port, const char *path, amxp_signal_mngr_t *sigmngr)
Opens a bus connection or creates a socket connection.
Definition: amxb_be_intf.h:417
void amxb_be_cache_remove_ctx(amxb_bus_ctx_t *ctx)
Removes a bus context from the lookup cache.
amxb_be_funcs_t * amxb_be_find(const char *name)
Gets a backend function table using its name.
int amxb_connect_intf(amxb_bus_ctx_t **ctx, const char *uri, const char *intf)
Create a bus connection.
int amxb_accept(amxb_bus_ctx_t *listen_ctx, amxb_bus_ctx_t **accepted_ctx)
Accepts an incomming connection request.
int amxb_listen(amxb_bus_ctx_t **ctx, const char *uri)
Create a listen socket.
amxc_array_t * amxb_list_uris(void)
List all open connections by their uri.
int amxb_connect(amxb_bus_ctx_t **ctx, const char *uri)
Create a bus connection.
amxb_bus_ctx_t * amxb_find_uri(const char *uri)
Find the bus context for a given uri.
int amxb_read_raw(const amxb_bus_ctx_t *const ctx, void *buf, size_t count)
Attempts to read up to count bytes from the file descriptor into the buffer starting at buf.
void amxb_free(amxb_bus_ctx_t **ctx)
Frees allocated memory.
int amxb_get_fd(const amxb_bus_ctx_t *const ctx)
Get the connection file descriptor.
int amxb_disconnect(amxb_bus_ctx_t *ctx)
Disconnects a bus connection.
int amxb_read(const amxb_bus_ctx_t *const ctx)
Reads data from the file descriptor.
#define AMXB_ERROR_BACKEND_FAILED
Back-end failed.
Definition: amxb_error.h:128
#define AMXB_ERROR_NOT_SUPPORTED_OP
Function/operation not supported.
Definition: amxb_error.h:110
#define AMXB_ERROR_NOT_SUPPORTED_SCHEME
URI scheme not supported.
Definition: amxb_error.h:104
#define AMXB_ERROR_INVALID_URI
Invalid URI.
Definition: amxb_error.h:98
The back-end interface structure.
amxb_be_connect_fn_t connect
amxb_be_read_fn_t read
amxb_be_disconnect_fn_t disconnect
amxb_be_accept_fn_t accept
amxb_be_free_fn_t free
amxb_be_listen_fn_t listen
amxb_be_read_raw_fn_t read_raw
amxc_llist_t connections
amxb_be_get_fd_fn_t get_fd
const amxb_be_funcs_t * bus_fn
Definition: amxb_types.h:121
amxc_llist_t requests
Definition: amxb_types.h:118
amxc_llist_t client_subs
Definition: amxb_types.h:127
amxd_dm_t * dm
Definition: amxb_types.h:123
amxp_signal_mngr_t sigmngr
Definition: amxb_types.h:120
amxc_llist_t invoke_ctxs
Definition: amxb_types.h:119
amxc_htable_it_t hit
Definition: amxb_types.h:117
amxc_llist_it_t it
Definition: amxb_types.h:116
void * bus_ctx
Definition: amxb_types.h:122
Definition: amxb_priv.h:69
bool in_flight
Definition: amxb_priv.h:73
bool closed
Definition: amxb_priv.h:74
Definition: amxb_priv.h:64
amxb_subscription_t data
Definition: amxb_priv.h:66