Asterisk - The Open Source Telephony Project GIT-master-85241bd
transaction.c
Go to the documentation of this file.
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/astobj2.h"
22#include "asterisk/sched.h"
23#include "asterisk/utils.h"
24
25#include "asterisk/res_aeap.h"
27
28#include "general.h"
29#include "logger.h"
30#include "transaction.h"
31
33 /*! Pointer back to owner object */
34 struct ast_aeap *aeap;
35 /*! The container this transaction is in */
37 /*! Scheduler ID message timeout */
39 /*! Whether or not the handler has been executed */
41 /*! Used to sync matching received messages */
43 /*! The result of this transaction */
44 int result;
45 /*! The timeout data */
47 /*! The transaction identifier */
48 char id[0];
49};
50
51/*! \brief Number of transaction buckets */
52#define AEAP_TRANSACTION_BUCKETS 11
53
56
58{
59 if (tsx && tsx->sched_id != -1) {
61 return tsx->sched_id != -1;
62 }
63
64 return 0;
65}
66
68{
69 ao2_cleanup(params->msg);
70
71 if (params->obj_cleanup) {
72 params->obj_cleanup(params->obj);
73 }
74}
75
76static void transaction_destructor(void *obj)
77{
78 struct aeap_transaction *tsx = obj;
79
80 /* Ensure timer is canceled */
82
84
86}
87
88static struct aeap_transaction *transaction_create(const char *id,
89 struct ast_aeap_tsx_params *params, struct ast_aeap *aeap)
90{
91 struct aeap_transaction *tsx;
92
93 if (!id) {
94 aeap_error(aeap, "transaction", "missing transaction id");
96 return NULL;
97 }
98
99 tsx = ao2_alloc(sizeof(*tsx) + strlen(id) + 1, transaction_destructor);
100 if (!tsx) {
101 aeap_error(aeap, "transaction", "unable to create for '%s'", id);
103 return NULL;
104 }
105
106 strcpy(tsx->id, id); /* safe */
107 tsx->sched_id = -1;
108
110
111 /*
112 * Currently, transactions, and their lifetimes are fully managed by the given 'aeap'
113 * object, so do not bump its reference here as we want the 'aeap' object to stop
114 * transactions and not transactions potentially stopping the 'aeap' object.
115 */
116 tsx->aeap = aeap;
117 tsx->params = *params;
118
119 return tsx;
120}
121
122static void transaction_end(struct aeap_transaction *tsx, int timed_out, int result)
123{
124 if (!tsx) {
125 return;
126 }
127
128 ao2_lock(tsx);
129
130 tsx->result = result;
131
132 if (tsx->container) {
133 ao2_unlink(tsx->container, tsx);
134 tsx->container = NULL;
135 }
136
137 if (!timed_out) {
139 } else if (tsx->sched_id != -1) {
140 tsx->sched_id = -1;
141 }
142
143 if (!tsx->handled) {
144 if (timed_out) {
145 if (tsx->params.on_timeout) {
146 tsx->params.on_timeout(tsx->aeap, tsx->params.msg, tsx->params.obj);
147 } else {
148 aeap_error(tsx->aeap, "transaction", "message '%s' timed out",
150 }
151 }
152
153 tsx->handled = 1;
155 }
156
157 ao2_unlock(tsx);
158
159 ao2_ref(tsx, -1);
160}
161
162static int transaction_raise_timeout(const void *data)
163{
164 /* Ref added added at timer creation removed in end call */
165 transaction_end((struct aeap_transaction *)data, 1, -1);
166
167 return 0;
168}
169
171{
172 if (tsx->params.timeout <= 0 || tsx->sched_id != -1) {
173 return 0;
174 }
175
178 if (tsx->sched_id == -1) {
179 aeap_error(tsx->aeap, "transaction", "unable to schedule timeout for '%s'", tsx->id);
180 ao2_ref(tsx, -1);
181 return -1;
182 }
183
184 return 0;
185}
186
187static void transaction_wait(struct aeap_transaction *tsx)
188{
189 ao2_lock(tsx);
190
191 while (!tsx->handled) {
193 }
194
195 ao2_unlock(tsx);
196}
197
199{
200 if (transaction_sched_timer(tsx)) {
201 return -1;
202 }
203
204 if (tsx->params.wait) {
205 /* Wait until transaction completes, or times out */
206 transaction_wait(tsx);
207 }
208
209 return 0;
210}
211
212struct aeap_transaction *aeap_transaction_get(struct ao2_container *transactions, const char *id)
213{
214 return ao2_find(transactions, id, OBJ_SEARCH_KEY);
215}
216
218{
219 transaction_end(tsx, 0, result);
220}
221
223{
224 return tsx->result;
225}
226
228{
229 return tsx->params.obj;
230}
231
233 const char *id, struct ast_aeap_tsx_params *params, struct ast_aeap *aeap)
234{
235 struct aeap_transaction *tsx;
236
237 tsx = transaction_create(id, params, aeap);
238 if (!tsx) {
239 return NULL;
240 }
241
242 if (!ao2_link(transactions, tsx)) {
243 aeap_error(tsx->aeap, "transaction", "unable to add '%s' to container", id);
244 ao2_ref(tsx, -1);
245 return NULL;
246 }
247
248 /*
249 * Yes, this creates a circular reference. This reference is removed though
250 * upon transaction end. It's assumed here that the given transactions container
251 * takes "ownership", and ultimate responsibility of its contained transactions.
252 * Thus when the given container needs to be unref'ed/freed it must call
253 * aeap_transaction_end for each transaction prior to doing so.
254 */
255 /* tsx->container = ao2_bump(transactions); */
256
257 /*
258 * The transaction needs to know what container manages it, so it can remove
259 * itself from the given container under certain conditions (e.g. transaction
260 * timeout).
261 *
262 * It's expected that the given container will out live any contained transaction
263 * (i.e. the container will not itself be destroyed before ensuring all contained
264 * transactions are ended, and removed). Thus there is no reason to bump the given
265 * container's reference here.
266 */
267 tsx->container = transactions;
268
269 return tsx;
270}
271
273{
274 struct ao2_container *transactions;
275
277 aeap_transaction_hash_fn, NULL, aeap_transaction_cmp_fn);
278 if (!transactions) {
279 ast_log(LOG_ERROR, "AEAP transaction: unable to create container\n");
280 return NULL;
281 }
282
283 return transactions;
284}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#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
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Definition: astobj2.c:476
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#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
static PGresult * result
Definition: cel_pgsql.c:84
struct ast_sched_context * aeap_sched_context(void)
Retrieve the scheduling context.
Definition: general.c:29
#define LOG_ERROR
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_cond_init(cond, attr)
Definition: lock.h:201
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_cond_signal(cond)
Definition: lock.h:203
#define aeap_error(obj, name, fmt,...)
Log an Asterisk external application error.
Asterisk External Application Protocol API.
Asterisk External Application Protocol Message API.
const char * ast_aeap_message_name(const struct ast_aeap_message *message)
Retrieve a message name.
#define NULL
Definition: resample.c:96
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:82
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:567
ast_cond_t handled_cond
Definition: transaction.c:42
struct ao2_container * container
Definition: transaction.c:36
struct ast_aeap * aeap
Definition: transaction.c:34
struct ast_aeap_tsx_params params
Definition: transaction.c:46
Generic container type.
Parameters to be used when sending a transaction based message.
Definition: res_aeap.h:331
struct ast_aeap_message * msg
Definition: res_aeap.h:333
ast_aeap_user_obj_cleanup obj_cleanup
Definition: res_aeap.h:350
ast_aeap_on_timeout on_timeout
Definition: res_aeap.h:337
Definition: aeap.c:47
static void transaction_end(struct aeap_transaction *tsx, int timed_out, int result)
Definition: transaction.c:122
static int transaction_sched_timer(struct aeap_transaction *tsx)
Definition: transaction.c:170
void * aeap_transaction_user_obj(struct aeap_transaction *tsx)
Retrieve the user object associated with the transaction.
Definition: transaction.c:227
static struct aeap_transaction * transaction_create(const char *id, struct ast_aeap_tsx_params *params, struct ast_aeap *aeap)
Definition: transaction.c:88
int aeap_transaction_cancel_timer(struct aeap_transaction *tsx)
Cancel the transaction timer.
Definition: transaction.c:57
AO2_STRING_FIELD_CMP_FN(aeap_transaction, id)
#define AEAP_TRANSACTION_BUCKETS
Number of transaction buckets.
Definition: transaction.c:52
int aeap_transaction_result(struct aeap_transaction *tsx)
Get a transaction's result.
Definition: transaction.c:222
AO2_STRING_FIELD_HASH_FN(aeap_transaction, id)
struct ao2_container * aeap_transactions_create(void)
Create an Asterisk external application transactions container.
Definition: transaction.c:272
static void transaction_destructor(void *obj)
Definition: transaction.c:76
struct aeap_transaction * aeap_transaction_create_and_add(struct ao2_container *transactions, const char *id, struct ast_aeap_tsx_params *params, struct ast_aeap *aeap)
Create a transaction object, and add it to the given container.
Definition: transaction.c:232
static int transaction_raise_timeout(const void *data)
Definition: transaction.c:162
void aeap_transaction_end(struct aeap_transaction *tsx, int result)
End a transaction, and remove it from the given container.
Definition: transaction.c:217
struct aeap_transaction * aeap_transaction_get(struct ao2_container *transactions, const char *id)
Retrieve a transaction for the id from the container.
Definition: transaction.c:212
int aeap_transaction_start(struct aeap_transaction *tsx)
Start the transaction.
Definition: transaction.c:198
static void transaction_wait(struct aeap_transaction *tsx)
Definition: transaction.c:187
void aeap_transaction_params_cleanup(struct ast_aeap_tsx_params *params)
Clean up parameter references, and possibly call optional user object cleanup.
Definition: transaction.c:67
Utility functions.