From 36b5e2040d00ec1ed9c9ef0bd5f22be3f695b90c Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 12 Sep 2012 15:44:07 +0200 Subject: [PATCH] junos: Introduced junos_invoke_method(). This function may be used to call an arbitrary JUNOScript method with any number and type of attributes and arguments. Attributes and arguments are specified using a variable argument list using tuples , [, ] where type is any of a list of constants defined in junos.h. The type of is determined from the specified type. The list has to be terminated by the constant JUNOS_NO_ARGS. junos_simple_method() has been "degraded" to a define calling junos_invoke_method(). --- src/junos.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/junos.h | 20 +++++- 2 files changed, 187 insertions(+), 11 deletions(-) diff --git a/src/junos.c b/src/junos.c index d254992..8608551 100644 --- a/src/junos.c +++ b/src/junos.c @@ -35,6 +35,7 @@ #include +#include #include #include @@ -71,6 +72,93 @@ struct junos { * private helper functions */ +static int +meth_append_arg(junos_strbuf_t *body, junos_strbuf_t *attrs, + int arg_type, va_list *ap) +{ + char *name = va_arg(*ap, char *); + ssize_t status; + + if (! name) { + errno = EINVAL; + return -1; + } + + switch (arg_type) { + case JUNOS_ARG_TOGGLE: /* fall thru */ + case JUNOS_ARG_TOGGLE_NO: + { + int value = va_arg(*ap, int); + if (value) + status = junos_strbuf_sprintf(body, + " <%s/>\n", name); + else if (arg_type == JUNOS_ARG_TOGGLE_NO) + status = junos_strbuf_sprintf(body, + " \n", name); + } + break; + case JUNOS_ARG_STRING: + { + char *value = va_arg(*ap, char *); + status = junos_strbuf_sprintf(body, + " <%s>%s\n", name, + value ? value : "", name); + } + break; + case JUNOS_ARG_INTEGER: + { + int value = va_arg(*ap, int); + status = junos_strbuf_sprintf(body, + " <%s>%i\n", + name, value, name); + } + break; + case JUNOS_ARG_DOUBLE: + { + double value = va_arg(*ap, double); + status = junos_strbuf_sprintf(body, + " <%s>%lf\n", + name, value, name); + } + break; + case JUNOS_ARG_DOM: + { + status = junos_strbuf_sprintf(body, + " %s\n", name); + } + break; + case JUNOS_ATTR_STRING: + { + char *value = va_arg(*ap, char *); + status = junos_strbuf_sprintf(attrs, + " %s=\"%s\"", + name, value ? value : ""); + } + break; + case JUNOS_ATTR_INTEGER: + { + int value = va_arg(*ap, int); + status = junos_strbuf_sprintf(attrs, + " %s=\"%s\"", name, value); + } + break; + case JUNOS_ATTR_DOUBLE: + { + double value = va_arg(*ap, double); + status = junos_strbuf_sprintf(attrs, + " %s=\"%s\"", name, value); + } + break; + default: + errno = EINVAL; + return -1; + break; + } + if (status < 0) + return -1; + return 0; +} /* meth_append_arg */ + static ssize_t read_lines(junos_t *junos, char *buf, size_t buf_len) { @@ -261,19 +349,29 @@ junos_disconnect(junos_t *junos) } /* junos_disconnect */ xmlDocPtr -junos_simple_method(junos_t *junos, const char *name) +junos_invoke_method(junos_t *junos, const char *name, ...) { - char method_string[1024]; + junos_strbuf_t *method_buf; + junos_strbuf_t *body_buf; + junos_strbuf_t *attr_buf; + + char *method_string; + size_t method_len; + char *body_string; + char *attr_string; + char recv_buf[4096]; ssize_t status; int xml_status; - xmlDocPtr doc; + va_list ap; + int arg_type; + if ((! junos) || (! name)) { junos_set_error(junos, JUNOS_SYS_ERROR, EINVAL, - "junos_simple_method() requires the " + "junos_invoke_method() requires the " "'junos' and 'name' arguments"); return NULL; } @@ -284,16 +382,76 @@ junos_simple_method(junos_t *junos, const char *name) return NULL; } - snprintf(method_string, sizeof(method_string), - "<%s/>", name); - status = junos_ssh_send(junos->access, - method_string, strlen(method_string)); - if (status != (ssize_t)strlen(method_string)) { + errno = 0; + method_buf = junos_strbuf_new(1024); + body_buf = junos_strbuf_new(1024); + attr_buf = junos_strbuf_new(1024); + +#define BUF_FREE() \ + do { \ + junos_strbuf_free(method_buf); \ + method_buf = NULL; \ + method_string = NULL; \ + method_len = 0; \ + junos_strbuf_free(body_buf); \ + body_buf = NULL; \ + body_string = NULL; \ + junos_strbuf_free(attr_buf); \ + attr_buf = NULL; \ + attr_string = NULL; \ + } while (0) + + if ((! method_buf) || (! body_buf) || (! attr_buf)) { + junos_set_error(junos, JUNOS_SYS_ERROR, errno, + "Failed to allocate string buffers"); + BUF_FREE(); + return NULL; + } + + va_start(ap, name); + while ((arg_type = va_arg(ap, int)) != JUNOS_NO_ARGS) { + if (meth_append_arg(body_buf, attr_buf, arg_type, &ap)) { + BUF_FREE(); + junos_set_error(junos, JUNOS_SYS_ERROR, errno, + "Failed to append argument (type %d) to method '%s'", + arg_type, name); + return NULL; + } + } + va_end(ap); + + body_string = junos_strbuf_string(body_buf); + attr_string = junos_strbuf_string(attr_buf); + + if (body_string[0]) + junos_strbuf_sprintf(method_buf, + "\n" + " <%s%s>\n%s" + " \n" + "", + name, attr_string, body_string, name); + else + junos_strbuf_sprintf(method_buf, + "\n" + " <%s%s/>\n" + "", + name, attr_string); + + method_string = junos_strbuf_string(method_buf); + method_len = junos_strbuf_len(method_buf); + + dprintf(" -> %s\n", method_string); + status = junos_ssh_send(junos->access, method_string, method_len); + + if (status != (ssize_t)method_len) { dprintf("Failed to send method '%s' (status %d)\n", method_string, (int)status); + BUF_FREE(); return NULL; } + BUF_FREE(); + errno = 0; junos->xml_ctx = xmlCreatePushParserCtxt(/* sax = */ NULL, /* user_data = */ NULL, @@ -345,7 +503,7 @@ junos_simple_method(junos_t *junos, const char *name) } return doc; -} /* junos_simple_method */ +} /* junos_invoke_method */ /* error handling */ diff --git a/src/junos.h b/src/junos.h index 055cd03..a122330 100644 --- a/src/junos.h +++ b/src/junos.h @@ -52,6 +52,21 @@ extern "C" { typedef struct junos junos_t; +/* method invocation */ + +enum { + JUNOS_NO_ARGS = 0, + JUNOS_ARG_TOGGLE, + JUNOS_ARG_TOGGLE_NO, + JUNOS_ARG_STRING, + JUNOS_ARG_INTEGER, + JUNOS_ARG_DOUBLE, + JUNOS_ARG_DOM, + JUNOS_ATTR_STRING, + JUNOS_ATTR_INTEGER, + JUNOS_ATTR_DOUBLE, +}; + /* string buffer */ typedef struct junos_strbuf junos_strbuf_t; @@ -110,7 +125,10 @@ int junos_connect(junos_t *junos); xmlDocPtr -junos_simple_method(junos_t *junos, const char *name); +junos_invoke_method(junos_t *junos, const char *name, ...); + +#define junos_simple_method(junos, name) \ + junos_invoke_method((junos), (name), JUNOS_NO_ARGS) int junos_disconnect(junos_t *junos); -- 2.30.2