Asterisk - The Open Source Telephony Project GIT-master-a358458
pjsip_cli.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Fairview 5 Engineering, LLC
5 *
6 * George Joseph <george.joseph@fairview5.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 <pjsip.h>
22#include <pjsip_ua.h>
23
24#include "asterisk/res_pjsip.h"
27#include "asterisk/acl.h"
28#include "asterisk/cli.h"
29#include "asterisk/astobj2.h"
30#include "asterisk/hashtab.h"
31#include "asterisk/utils.h"
32#include "asterisk/sorcery.h"
33
35
36int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
37{
38 struct ast_sip_cli_context *context = arg;
39 struct ast_variable *i;
40 int max_name_width = 13;
41 int max_value_width = 14;
42 int width;
43 char *separator;
44 struct ast_variable *objset;
45
46 if (!context->output_buffer) {
47 return -1;
48 }
49
51 if (!objset) {
52 return -1;
53 }
54
55 for (i = objset; i; i = i->next) {
56 if (i->name) {
57 width = strlen(i->name);
58 max_name_width = width > max_name_width ? width : max_name_width;
59 }
60 if (i->value) {
61 width = strlen(i->value);
62 max_value_width = width > max_value_width ? width : max_value_width;
63 }
64 }
65
66 separator = ast_alloca(max_name_width + max_value_width + 8);
67
68 memset(separator, '=', max_name_width + max_value_width + 3);
69 separator[max_name_width + max_value_width + 3] = 0;
70
71 ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, "ParameterName", "ParameterValue");
72 ast_str_append(&context->output_buffer, 0, " %s\n", separator);
73
74 objset = ast_variable_list_sort(objset);
75
76 for (i = objset; i; i = i->next) {
77 ast_str_append(&context->output_buffer, 0, " %-*s : %s\n", max_name_width, i->name, i->value);
78 }
79
81
82 return 0;
83}
84
86 struct ast_sip_cli_formatter_entry *formatter_entry,
87 const char *word)
88{
89 size_t wordlen = strlen(word);
90 void *object;
92
93 while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) {
94 const char *id = formatter_entry->get_id(object);
95 if (!strncasecmp(word, id, wordlen)) {
97 }
98 ao2_t_ref(object, -1, "toss iterator endpoint ptr before break");
99 }
101}
102
103static void dump_str_and_free(int fd, struct ast_str *buf)
104{
105 ast_cli(fd, "%s", ast_str_buffer(buf));
106 ast_free(buf);
107}
108
110{
112 RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
113 RAII_VAR(void *, object, NULL, ao2_cleanup);
114 int is_container = 0;
115 const char *cmd1;
116 const char *cmd2;
117 const char *object_id;
118 char formatter_type[64];
119 const char *regex;
120
122 .indent_level = 0,
123 .show_details = 0,
124 .show_details_only_level_0 = 0,
125 .recurse = 0,
126 };
127
128 if (cmd == CLI_INIT) {
129 return NULL;
130 }
131
132 cmd1 = e->cmda[1];
133 cmd2 = e->cmda[2];
134 object_id = a->argv[3];
135
136 if (!ast_ends_with(cmd2, "s")) {
137 ast_copy_string(formatter_type, cmd2, sizeof(formatter_type));
138 is_container = 0;
139 } else if (ast_ends_with(cmd2, "ies")) {
140 /* Take the plural "ies" off of the object name and re[place with "y". */
141 int l = strlen(cmd2);
142 snprintf(formatter_type, 64, "%*.*sy", l - 3, l - 3, cmd2);
143 is_container = 1;
144 } else {
145 /* Take the plural "s" off of the object name. */
146 ast_copy_string(formatter_type, cmd2, strlen(cmd2));
147 is_container = 1;
148 }
149
150 if (!strcmp(cmd1, "show")) {
151 context.show_details_only_level_0 = !is_container;
152 context.recurse = 1;
153 } else {
154 is_container = 1;
155 }
156
157 if (cmd != CLI_GENERATE
158 && is_container
159 && a->argc >= 4
160 && strcmp(object_id, "like") == 0) {
161 if (ast_strlen_zero(a->argv[4])) {
162 return CLI_SHOWUSAGE;
163 }
164 regex = a->argv[4];
165 } else {
166 regex = "";
167 }
168
169 if (cmd == CLI_GENERATE
170 && (is_container
171 || a->argc > 4
172 || (a->argc == 4 && ast_strlen_zero(a->word)))) {
173 return CLI_SUCCESS;
174 }
175
176 context.output_buffer = ast_str_create(256);
177 if (!context.output_buffer) {
178 return CLI_FAILURE;
179 }
180
181 formatter_entry = ast_sip_lookup_cli_formatter(formatter_type);
182 if (!formatter_entry) {
183 ast_log(LOG_ERROR, "No formatter registered for object type %s.\n",
184 formatter_type);
185 ast_free(context.output_buffer);
186 return CLI_FAILURE;
187 }
188 ast_str_append(&context.output_buffer, 0, "\n");
189 formatter_entry->print_header(NULL, &context, 0);
190 ast_str_append(&context.output_buffer, 0,
191 "==========================================================================================\n\n");
192
193 if (is_container || cmd == CLI_GENERATE) {
194 container = formatter_entry->get_container(regex);
195 if (!container) {
196 ast_cli(a->fd, "No container returned for object type %s.\n",
197 formatter_type);
198 ast_free(context.output_buffer);
199 return CLI_FAILURE;
200 }
201 }
202
203 if (cmd == CLI_GENERATE) {
204 ast_free(context.output_buffer);
205 complete_show_sorcery_object(container, formatter_entry, a->word);
206 return NULL;
207 }
208
209 if (is_container) {
211 ast_free(context.output_buffer);
212 ast_cli(a->fd, "No objects found.\n\n");
213 return CLI_SUCCESS;
214 }
215 ao2_callback(container, OBJ_NODATA, formatter_entry->print_body, &context);
216 ast_str_append(&context.output_buffer, 0, "\nObjects found: %d\n", ao2_container_count(container));
217
218 } else {
219 if (ast_strlen_zero(object_id)) {
220 ast_free(context.output_buffer);
221 ast_cli(a->fd, "No object specified.\n");
222 return CLI_FAILURE;
223 }
224
225 object = formatter_entry->retrieve_by_id(object_id);
226 if (!object) {
227 ast_free(context.output_buffer);
228 ast_cli(a->fd, "Unable to find object %s.\n\n", object_id);
229 return CLI_SUCCESS;
230 }
231 formatter_entry->print_body(object, &context, 0);
232 }
233
234 ast_str_append(&context.output_buffer, 0, "\n");
235 dump_str_and_free(a->fd, context.output_buffer);
236 return CLI_SUCCESS;
237}
238
239static int formatter_sort(const void *obj, const void *arg, int flags)
240{
241 const struct ast_sip_cli_formatter_entry *left_obj = obj;
242 const struct ast_sip_cli_formatter_entry *right_obj = arg;
243 const char *right_key = arg;
244 int cmp = 0;
245
246 switch (flags & OBJ_SEARCH_MASK) {
248 right_key = right_obj->name;
249 /* Fall through */
250 case OBJ_SEARCH_KEY:
251 cmp = strcmp(left_obj->name, right_key);
252 break;
254 cmp = strncmp(left_obj->name, right_key, strlen(right_key));
255 break;
256 default:
257 cmp = 0;
258 break;
259 }
260
261 return cmp;
262}
263
264static int formatter_compare(void *obj, void *arg, int flags)
265{
266 const struct ast_sip_cli_formatter_entry *left_obj = obj;
267 const struct ast_sip_cli_formatter_entry *right_obj = arg;
268 const char *right_key = arg;
269 int cmp = 0;
270
271 switch (flags & OBJ_SEARCH_MASK) {
273 right_key = right_obj->name;
274 /* Fall through */
275 case OBJ_SEARCH_KEY:
276 if (strcmp(left_obj->name, right_key) == 0) {;
277 cmp = CMP_MATCH | CMP_STOP;
278 }
279 break;
281 if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
282 cmp = CMP_MATCH;
283 }
284 break;
285 default:
286 cmp = 0;
287 break;
288 }
289
290 return cmp;
291}
292
293static int formatter_hash(const void *obj, int flags)
294{
295 const struct ast_sip_cli_formatter_entry *left_obj = obj;
296 if (flags & OBJ_SEARCH_OBJECT) {
297 return ast_str_hash(left_obj->name);
298 } else if (flags & OBJ_SEARCH_KEY) {
299 return ast_str_hash(obj);
300 }
301
302 return -1;
303}
304
306{
308}
309
311{
312 ast_assert(formatter != NULL);
313 ast_assert(formatter->name != NULL);
314 ast_assert(formatter->print_body != NULL);
315 ast_assert(formatter->print_header != NULL);
316 ast_assert(formatter->get_container != NULL);
317 ast_assert(formatter->iterate != NULL);
318 ast_assert(formatter->get_id != NULL);
319 ast_assert(formatter->retrieve_by_id != NULL);
320
321 ao2_link(formatter_registry, formatter);
322
323 return 0;
324}
325
327{
328 if (formatter) {
330 if (ao2_ref(formatter, -1) == 2) {
332 }
334 }
335 return 0;
336}
337
338static char *handle_pjsip_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
339{
340 switch(cmd) {
341 case CLI_INIT:
342 e->command = "pjsip show version";
343 e->usage =
344 "Usage: pjsip show version\n"
345 " Show the version of pjproject that res_pjsip is running against\n";
346 return NULL;
347 case CLI_GENERATE:
348 return NULL;
349 }
350
351 ast_cli(a->fd, "PJPROJECT version currently running against: %s\n", pj_get_version());
352
353 return CLI_SUCCESS;
354}
355
356static struct ast_cli_entry pjsip_cli[] = {
357 AST_CLI_DEFINE(handle_pjsip_show_version, "Show the version of pjproject in use"),
358};
359
361{
364
365 if (!formatter_registry) {
366 ast_log(LOG_ERROR, "Unable to create formatter_registry.\n");
367 return -1;
368 }
369
371
372 return 0;
373}
374
376{
379}
Access Control of various sorts.
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
#define ao2_wrlock(a)
Definition: astobj2.h:719
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#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.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#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
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2756
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Generic (perhaps overly so) hashtable implementation Hash Table support in Asterisk.
struct ast_variable * ast_variable_list_sort(struct ast_variable *head)
Performs an in-place sort on the variable list by ascending name.
Definition: main/config.c:620
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define LOG_ERROR
static char * handle_pjsip_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:338
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Unregisters a CLI formatter.
Definition: pjsip_cli.c:326
static struct ast_cli_entry pjsip_cli[]
Definition: pjsip_cli.c:356
static void dump_str_and_free(int fd, struct ast_str *buf)
Definition: pjsip_cli.c:103
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object's ast_variable list.
Definition: pjsip_cli.c:36
struct ast_sip_cli_formatter_entry * ast_sip_lookup_cli_formatter(const char *name)
Looks up a CLI formatter by type.
Definition: pjsip_cli.c:305
static int formatter_sort(const void *obj, const void *arg, int flags)
Definition: pjsip_cli.c:239
void ast_sip_destroy_cli(void)
Definition: pjsip_cli.c:375
static struct ao2_container * formatter_registry
Definition: pjsip_cli.c:34
static void complete_show_sorcery_object(struct ao2_container *container, struct ast_sip_cli_formatter_entry *formatter_entry, const char *word)
Definition: pjsip_cli.c:85
static int formatter_hash(const void *obj, int flags)
Definition: pjsip_cli.c:293
static int formatter_compare(void *obj, void *arg, int flags)
Definition: pjsip_cli.c:264
char * ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:109
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
int ast_sip_initialize_cli(void)
Definition: pjsip_cli.c:360
struct ao2_container * container
Definition: res_fax.c:501
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Checks whether a string ends with another.
Definition: strings.h:116
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
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
descriptor for a cli entry.
Definition: cli.h:171
const char *const cmda[AST_MAX_CMD_LEN]
Definition: cli.h:172
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
static struct test_val a
Utility functions.
#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_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666