Asterisk - The Open Source Telephony Project  21.4.1
transport.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Sangoma Technologies Corporation
5  *
6  * Kevin Harwell <kharwell@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/utils.h"
22 
23 #include "logger.h"
24 #include "transport.h"
25 #include "transport_websocket.h"
26 
27 struct aeap_transport *aeap_transport_create(const char *type)
28 {
29  struct aeap_transport *transport = NULL;
30 
31  if (!strncasecmp(type, "ws", 2)) {
32  transport = (struct aeap_transport *)aeap_transport_websocket_create();
33  }
34 
35  if (!transport) {
36  ast_log(LOG_ERROR, "AEAP transport: failed to create for type '%s'\n", type);
37  return NULL;
38  }
39 
40  ast_mutex_init(&transport->read_lock);
41  ast_mutex_init(&transport->write_lock);
42 
43  transport->connected = 0;
44 
45  return transport;
46 }
47 
48 int aeap_transport_connect(struct aeap_transport *transport, const char *url,
49  const char *protocol, int timeout)
50 {
51  int res;
52 
53  SCOPED_MUTEX(rlock, &transport->read_lock);
54  SCOPED_MUTEX(wlock, &transport->write_lock);
55 
56  if (aeap_transport_is_connected(transport)) {
57  return 0;
58  }
59 
60  res = transport->vtable->connect(transport, url, protocol, timeout);
61  if (!res) {
62  transport->connected = 1;
63  }
64 
65  return res;
66 }
67 
68 struct aeap_transport *aeap_transport_create_and_connect(const char *type,
69  const char *url, const char *protocol, int timeout)
70 {
71  struct aeap_transport *transport = aeap_transport_create(type);
72 
73  if (!transport) {
74  return NULL;
75  }
76 
77  if (aeap_transport_connect(transport, url, protocol, timeout)) {
78  aeap_transport_destroy(transport);
79  return NULL;
80  }
81 
82  return transport;
83 }
84 
85 int aeap_transport_is_connected(struct aeap_transport *transport)
86 {
87  /*
88  * Avoid using a lock to 'read' the 'connected' variable in order to
89  * keep things slightly more efficient.
90  */
91  return ast_atomic_fetch_add(&transport->connected, 0, __ATOMIC_RELAXED);
92 }
93 
94 int aeap_transport_disconnect(struct aeap_transport *transport)
95 {
96  int res;
97 
98  SCOPED_MUTEX(rlock, &transport->read_lock);
99  SCOPED_MUTEX(wlock, &transport->write_lock);
100 
101  if (!aeap_transport_is_connected(transport)) {
102  return 0;
103  }
104 
105  res = transport->vtable->disconnect(transport);
106 
107  /*
108  * Even though the transport is locked here use atomics to set the value of
109  * 'connected' since it's possible the variable is being 'read' by another
110  * thread via the 'is_connected' call.
111  */
112  ast_atomic_fetch_sub(&transport->connected, 1, __ATOMIC_RELAXED);
113 
114  return res;
115 }
116 
117 void aeap_transport_destroy(struct aeap_transport *transport)
118 {
119  if (!transport) {
120  return;
121  }
122 
123  /* Ensure an orderly disconnect occurs before final destruction */
124  aeap_transport_disconnect(transport);
125 
126  transport->vtable->destroy(transport);
127 
128  ast_mutex_destroy(&transport->read_lock);
129  ast_mutex_destroy(&transport->write_lock);
130 
131  ast_free(transport);
132 }
133 
134 intmax_t aeap_transport_read(struct aeap_transport *transport, void *buf, intmax_t size,
135  enum AST_AEAP_DATA_TYPE *rtype)
136 {
137  SCOPED_MUTEX(lock, &transport->read_lock);
138 
139  if (!aeap_transport_is_connected(transport)) {
140  return 0;
141  }
142 
143  return transport->vtable->read(transport, buf, size, rtype);
144 }
145 
146 intmax_t aeap_transport_write(struct aeap_transport *transport, const void *buf, intmax_t size,
147  enum AST_AEAP_DATA_TYPE wtype)
148 {
149  SCOPED_MUTEX(lock, &transport->write_lock);
150 
151  if (!aeap_transport_is_connected(transport)) {
152  return 0;
153  }
154 
155  return transport->vtable->write(transport, buf, size, wtype);
156 }
void(* destroy)(struct aeap_transport *self)
Destroy a transport.
Definition: transport.h:60
Asterisk main include file. File version handling, generic pbx functions.
intmax_t(* read)(struct aeap_transport *self, void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE *rtype)
Read data from a transport.
Definition: transport.h:72
intmax_t(* write)(struct aeap_transport *self, const void *buf, intmax_t size, enum AST_AEAP_DATA_TYPE wtype)
Write data to a transport.
Definition: transport.h:85
#define ast_atomic_fetch_add(ptr, val, memorder)
Support for atomic instructions.
Definition: lock.h:669
ast_mutex_t read_lock
Definition: transport.h:104
int(* disconnect)(struct aeap_transport *self)
Disconnect a transport.
Definition: transport.h:53
Utility functions.
ast_mutex_t lock
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:589
#define ast_atomic_fetch_sub(ptr, val, memorder)
Definition: lock.h:673
unsigned int connected
Definition: transport.h:102
ast_mutex_t write_lock
Definition: transport.h:106
int(* connect)(struct aeap_transport *self, const char *url, const char *protocol, int timeout)
Connect a transport.
Definition: transport.h:44
AST_AEAP_DATA_TYPE
Supported Asterisk external application data types.
Definition: res_aeap.h:135
Asterisk external application transport structure to be "derived" by specific transport implementatio...
Definition: transport.h:98
struct aeap_transport_vtable * vtable
Definition: transport.h:100