Asterisk - The Open Source Telephony Project GIT-master-f36a736
resource_endpoints.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012 - 2013, Digium, Inc.
5 *
6 * David M. Lee, II <dlee@digium.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/*! \file
20 *
21 * \brief /api-docs/endpoints.{format} implementation- Endpoint resources
22 *
23 * \author David M. Lee, II <dlee@digium.com>
24 */
25
26#include "asterisk.h"
27
28#include "resource_endpoints.h"
29
30#include "asterisk/astobj2.h"
31#include "asterisk/stasis.h"
32#include "asterisk/stasis_app.h"
34#include "asterisk/channel.h"
35#include "asterisk/message.h"
36#include "asterisk/refer.h"
37
40 struct ast_ari_response *response)
41{
43 RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
44 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
45 struct ao2_iterator i;
46 void *obj;
47
49 if (!cache) {
51 response, 500, "Internal Server Error",
52 "Message bus not initialized");
53 return;
54 }
55 ao2_ref(cache, +1);
56
58 if (!snapshots) {
60 return;
61 }
62
63 json = ast_json_array_create();
64 if (!json) {
66 return;
67 }
68
69 i = ao2_iterator_init(snapshots, 0);
70 while ((obj = ao2_iterator_next(&i))) {
71 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
72 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
73 struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
74
75 if (!json_endpoint || ast_json_array_append(json, json_endpoint)) {
78 return;
79 }
80 }
82
83 ast_ari_response_ok(response, ast_json_ref(json));
84}
85
88 struct ast_ari_response *response)
89{
91 RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
92 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
93 struct ast_endpoint *tech_endpoint;
94 struct ao2_iterator i;
95 void *obj;
96
97 tech_endpoint = ast_endpoint_find_by_id(args->tech);
98 if (!tech_endpoint) {
99 ast_ari_response_error(response, 404, "Not Found",
100 "No Endpoints found - invalid tech %s", args->tech);
101 return;
102 }
103 ao2_ref(tech_endpoint, -1);
104
106 if (!cache) {
108 response, 500, "Internal Server Error",
109 "Message bus not initialized");
110 return;
111 }
112 ao2_ref(cache, +1);
113
115 if (!snapshots) {
117 return;
118 }
119
120 json = ast_json_array_create();
121 if (!json) {
123 return;
124 }
125
126 i = ao2_iterator_init(snapshots, 0);
127 while ((obj = ao2_iterator_next(&i))) {
128 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
129 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
130 struct ast_json *json_endpoint;
131 int r;
132
133 if (strcasecmp(args->tech, snapshot->tech) != 0) {
134 continue;
135 }
136
137 json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
138 if (!json_endpoint) {
139 continue;
140 }
141
143 json, json_endpoint);
144 if (r != 0) {
147 return;
148 }
149 }
151 ast_ari_response_ok(response, ast_json_ref(json));
152}
153
156 struct ast_ari_response *response)
157{
158 struct ast_json *json;
159 RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
160
161 snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
162 if (!snapshot) {
163 ast_ari_response_error(response, 404, "Not Found",
164 "Endpoint not found");
165 return;
166 }
167
169 if (!json) {
171 return;
172 }
173
174 ast_ari_response_ok(response, json);
175}
176
177static void send_message(const char *to, const char *from, const char *body, struct ast_variable *variables, struct ast_ari_response *response)
178{
179 struct ast_variable *current;
180 struct ast_msg *msg;
181 int res = 0;
182
183 if (ast_strlen_zero(to)) {
184 ast_ari_response_error(response, 400, "Bad Request",
185 "To must be specified");
186 return;
187 }
188
189 msg = ast_msg_alloc();
190 if (!msg) {
192 return;
193 }
194
195 res |= ast_msg_set_from(msg, "%s", from);
196 res |= ast_msg_set_to(msg, "%s", to);
197
198 if (!ast_strlen_zero(body)) {
199 res |= ast_msg_set_body(msg, "%s", body);
200 }
201
202 for (current = variables; current; current = current->next) {
203 res |= ast_msg_set_var_outbound(msg, current->name, current->value);
204 }
205
206 if (res) {
208 ast_msg_destroy(msg);
209 return;
210 }
211
212 if (ast_msg_send(msg, to, from)) {
213 ast_ari_response_error(response, 404, "Not Found",
214 "Endpoint not found");
215 return;
216 }
217
218 response->message = ast_json_null();
219 response->response_code = 202;
220 response->response_text = "Accepted";
221}
222
223/*!
224 * \internal
225 * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
226 * \since 13.3.0
227 *
228 * \param[out] response HTTP response if error
229 * \param json_variables The JSON blob containing the variable
230 * \param[out] variables An out reference to the variables to populate.
231 *
232 * \retval 0 on success.
233 * \retval -1 on error.
234 */
235static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
236{
238
239 res = ast_json_to_ast_variables(json_variables, variables);
240 switch (res) {
242 return 0;
244 ast_ari_response_error(response, 400, "Bad Request",
245 "Only string values in the 'variables' object allowed");
246 break;
249 break;
250 }
251 ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
252
253 return -1;
254}
255
258 struct ast_ari_response *response)
259{
260 struct ast_variable *variables = NULL;
261
262 if (args->variables) {
263 struct ast_json *json_variables;
264
266 json_variables = ast_json_object_get(args->variables, "variables");
267 if (json_variables
268 && json_to_ast_variables(response, json_variables, &variables)) {
269 return;
270 }
271 }
272
273 send_message(args->to, args->from, args->body, variables, response);
274 ast_variables_destroy(variables);
275}
276
279 struct ast_ari_response *response)
280{
281 struct ast_variable *variables = NULL;
282 struct ast_endpoint_snapshot *snapshot;
283 char msg_to[128];
284 char *tech = ast_strdupa(args->tech);
285
286 /* Really, we just want to know if this thing exists */
287 snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
288 if (!snapshot) {
289 ast_ari_response_error(response, 404, "Not Found",
290 "Endpoint not found");
291 return;
292 }
293 ao2_ref(snapshot, -1);
294
295 if (args->variables) {
296 struct ast_json *json_variables;
297
299 json_variables = ast_json_object_get(args->variables, "variables");
300 if (json_variables
301 && json_to_ast_variables(response, json_variables, &variables)) {
302 return;
303 }
304 }
305
306 snprintf(msg_to, sizeof(msg_to), "%s:%s", ast_str_to_lower(tech), args->resource);
307
308 send_message(msg_to, args->from, args->body, variables, response);
309 ast_variables_destroy(variables);
310}
311
312static void send_refer(const char *to, const char *from, const char *refer_to, int to_self, struct ast_variable *variables, struct ast_ari_response *response)
313{
314 struct ast_variable *current;
315 struct ast_refer *refer;
316 int res = 0;
317
318 if (ast_strlen_zero(to)) {
319 ast_ari_response_error(response, 400, "Bad Request",
320 "To must be specified");
321 return;
322 }
323
324 refer = ast_refer_alloc();
325 if (!refer) {
327 return;
328 }
329
330 ast_refer_set_to(refer, "%s", to);
332
333 if (!ast_strlen_zero(from)) {
334 ast_refer_set_from(refer, "%s", from);
335 }
337 ast_refer_set_refer_to(refer, "%s", refer_to);
338 }
339
340 for (current = variables; current; current = current->next) {
341 res |= ast_refer_set_var_outbound(refer, current->name, current->value);
342 }
343
344 if (res) {
346 ast_refer_destroy(refer);
347 return;
348 }
349
350 if (ast_refer_send(refer)) {
351 ast_ari_response_error(response, 404, "Not Found",
352 "Endpoint not found");
353 return;
354 }
355
356 response->message = ast_json_null();
357 response->response_code = 202;
358 response->response_text = "Accepted";
359}
360
361static int parse_refer_json(struct ast_json *body,
362 struct ast_ari_response *response,
363 struct ast_variable **variables)
364{
365 const char *known_variables[] = { "display_name" };
366 const char *value;
367 struct ast_variable *new_var;
368 struct ast_json *json_variable;
369 int err = 0;
370 int i;
371
372 if (!body) {
373 return 0;
374 }
375
376 json_variable = ast_json_object_get(body, "variables");
377 if (json_variable) {
378 err = json_to_ast_variables(response, json_variable, variables);
379 if (err) {
380 return err;
381 }
382 }
383
384 for (i = 0; i < sizeof(known_variables) / sizeof(*known_variables); ++i) {
385 json_variable = ast_json_object_get(body, known_variables[i]);
386 if (json_variable && ast_json_typeof(json_variable) == AST_JSON_STRING) {
387 value = ast_json_string_get(json_variable);
388 new_var = ast_variable_new(known_variables[i], value, "");
389 if (new_var) {
390 ast_variable_list_append(variables, new_var);
391 }
392 }
393 }
394
395 return err;
396}
397
400 struct ast_ari_response *response)
401{
402 struct ast_variable *variables = NULL;
403
405
406 if (parse_refer_json(args->variables, response, &variables)) {
407 return;
408 }
409
410 send_refer(args->to, args->from, args->refer_to, args->to_self, variables, response);
411 ast_variables_destroy(variables);
412}
413
416 struct ast_ari_response *response)
417{
418 struct ast_variable *variables = NULL;
419 struct ast_endpoint_snapshot *snapshot;
420 char to[128];
421 char *tech = ast_strdupa(args->tech);
422
423 /* Really, we just want to know if this thing exists */
424 snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
425 if (!snapshot) {
426 ast_ari_response_error(response, 404, "Not Found",
427 "Endpoint not found");
428 return;
429 }
430 ao2_ref(snapshot, -1);
431
433
434 if (parse_refer_json(args->variables, response, &variables)) {
435 return;
436 }
437
438 snprintf(to, sizeof(to), "%s:%s", ast_str_to_lower(tech), args->resource);
439
440 send_refer(to, args->from, args->refer_to, args->to_self, variables, response);
441 ast_variables_destroy(variables);
442}
void ast_ari_response_error(struct ast_ari_response *response, int response_code, const char *response_text, const char *message_fmt,...)
Fill in an error ast_ari_response.
Definition: res_ari.c:259
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
Definition: res_ari.c:276
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
Definition: res_ari.c:298
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
General Asterisk PBX channel definitions.
struct ast_endpoint * ast_endpoint_find_by_id(const char *id)
Finds the endpoint with the given tech[/resource] id.
struct stasis_message_type * ast_endpoint_snapshot_type(void)
Message type for ast_endpoint_snapshot.
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
struct stasis_cache * ast_endpoint_cache(void)
Backend cache for ast_endpoint_topic_all_cached().
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define AST_LOG_ERROR
enum ast_json_type ast_json_typeof(const struct ast_json *value)
Get the type of value.
Definition: json.c:78
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:362
@ AST_JSON_STRING
Definition: json.h:166
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
ast_json_to_ast_vars_code
Definition: json.h:1109
@ AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE
Conversion failed because invalid value type supplied.
Definition: json.h:1116
@ AST_JSON_TO_AST_VARS_CODE_SUCCESS
Conversion successful.
Definition: json.h:1111
@ AST_JSON_TO_AST_VARS_CODE_OOM
Conversion failed because of allocation failure. (Out Of Memory)
Definition: json.h:1118
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
Convert a ast_json list of key/value pair tuples into a ast_variable list.
Definition: json.c:818
size_t current
Definition: main/cli.c:113
Out-of-call text message support.
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the 'from' URI of a message.
Definition: main/message.c:479
int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
Send a msg directly to an endpoint.
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
Definition: main/message.c:462
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
Definition: main/message.c:432
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the 'body' text of a message (in UTF-8)
Definition: main/message.c:490
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the 'to' URI of a message.
Definition: main/message.c:468
int ast_msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message being sent to a message tech directly.
Definition: main/message.c:624
struct ao2_container * cache
Definition: pbx_realtime.c:77
Out-of-call refer support.
struct ast_refer * ast_refer_alloc(void)
Allocate a refer.
Definition: refer.c:122
int ast_refer_set_var_outbound(struct ast_refer *refer, const char *name, const char *value)
Set a variable on the refer being sent to a refer tech directly.
Definition: refer.c:310
int ast_refer_set_from(struct ast_refer *refer, const char *fmt,...)
Set the 'from' URI of a refer.
Definition: refer.c:169
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition: refer.c:152
int ast_refer_set_refer_to(struct ast_refer *refer, const char *fmt,...)
Set the 'refer_to' URI of a refer.
Definition: refer.c:180
int ast_refer_set_to_self(struct ast_refer *refer, int val)
Set the 'to_self' value of a refer.
Definition: refer.c:191
int ast_refer_send(struct ast_refer *refer)
Send a refer directly to an endpoint.
Definition: refer.c:411
int ast_refer_set_to(struct ast_refer *refer, const char *fmt,...)
Set the 'to' URI of a refer.
Definition: refer.c:158
#define NULL
Definition: resample.c:96
void ast_ari_endpoints_refer(struct ast_variable *headers, struct ast_ari_endpoints_refer_args *args, struct ast_ari_response *response)
Refer an endpoint or technology URI to some technology URI or endpoint.
void ast_ari_endpoints_send_message(struct ast_variable *headers, struct ast_ari_endpoints_send_message_args *args, struct ast_ari_response *response)
Send a message to some technology URI or endpoint.
void ast_ari_endpoints_list_by_tech(struct ast_variable *headers, struct ast_ari_endpoints_list_by_tech_args *args, struct ast_ari_response *response)
List available endoints for a given endpoint technology.
void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers, struct ast_ari_endpoints_send_message_to_endpoint_args *args, struct ast_ari_response *response)
Send a message to some endpoint in a technology.
void ast_ari_endpoints_refer_to_endpoint(struct ast_variable *headers, struct ast_ari_endpoints_refer_to_endpoint_args *args, struct ast_ari_response *response)
Refer an endpoint or technology URI to some technology URI or endpoint.
static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
void ast_ari_endpoints_get(struct ast_variable *headers, struct ast_ari_endpoints_get_args *args, struct ast_ari_response *response)
Details for an endpoint.
void ast_ari_endpoints_list(struct ast_variable *headers, struct ast_ari_endpoints_list_args *args, struct ast_ari_response *response)
List all endpoints.
static void send_refer(const char *to, const char *from, const char *refer_to, int to_self, struct ast_variable *variables, struct ast_ari_response *response)
static int parse_refer_json(struct ast_json *body, struct ast_ari_response *response, struct ast_variable **variables)
static void send_message(const char *to, const char *from, const char *body, struct ast_variable *variables, struct ast_ari_response *response)
Generated file - declares stubs to be implemented in res/ari/resource_endpoints.c.
int ast_ari_endpoints_send_message_parse_body(struct ast_json *body, struct ast_ari_endpoints_send_message_args *args)
Body parsing function for /endpoints/sendMessage.
int ast_ari_endpoints_refer_to_endpoint_parse_body(struct ast_json *body, struct ast_ari_endpoints_refer_to_endpoint_args *args)
Body parsing function for /endpoints/{tech}/{resource}/refer.
int ast_ari_endpoints_send_message_to_endpoint_parse_body(struct ast_json *body, struct ast_ari_endpoints_send_message_to_endpoint_args *args)
Body parsing function for /endpoints/{tech}/{resource}/sendMessage.
int ast_ari_endpoints_refer_parse_body(struct ast_json *body, struct ast_ari_endpoints_refer_args *args)
Body parsing function for /endpoints/refer.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct ao2_container * stasis_cache_dump(struct stasis_cache *cache, struct stasis_message_type *type)
Dump cached items to a subscription for the ast_eid_default entity.
Definition: stasis_cache.c:736
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
Stasis Application API. See Stasis Application API for detailed documentation.
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2267
Endpoint abstractions.
struct ast_json * ast_endpoint_snapshot_to_json(const struct ast_endpoint_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_endpoint_snapshot.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1321
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
struct ast_json * message
Definition: ari.h:94
int response_code
Definition: ari.h:99
const char * response_text
Definition: ari.h:103
A snapshot of an endpoint's state.
const ast_string_field tech
Abstract JSON element (object, array, string, int, ...).
A message.
Definition: main/message.c:247
const ast_string_field from
Definition: main/message.c:263
const ast_string_field to
Definition: main/message.c:263
const ast_string_field body
Definition: main/message.c:263
A refer.
Definition: refer.c:57
int to_self
Definition: refer.c:71
const ast_string_field from
Definition: refer.c:69
const ast_string_field refer_to
Definition: refer.c:69
const ast_string_field to
Definition: refer.c:69
Structure for variables, used for configurations and for channel variables.
int value
Definition: syslog.c:37
const char * args
#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