From e4adec413a53f28e383e81ce272b2de64ad151b7 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 29 Oct 2018 22:38:34 +0100 Subject: [PATCH] test stream util function --- example/example_backend.c | 3 +- lib/src/clixon_stream.c | 3 +- util/Makefile.in | 6 +- util/clixon_util_stream.c | 224 +++++++++++++++++++++++++++++ yang/clixon-config@2018-10-21.yang | 2 +- 5 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 util/clixon_util_stream.c diff --git a/example/example_backend.c b/example/example_backend.c index 084863f9..3feb0409 100644 --- a/example/example_backend.c +++ b/example/example_backend.c @@ -304,8 +304,7 @@ clixon_plugin_init(clicon_handle h) */ if (clicon_option_exists(h, "CLICON_STREAM_RETENTION")) retention.tv_sec = clicon_option_int(h, "CLICON_STREAM_RETENTION"); - if (stream_add(h, "EXAMPLE", "Example event stream", 1, - retention.tv_sec?&retention:NULL) < 0) + if (stream_add(h, "EXAMPLE", "Example event stream", 1, &retention) < 0) goto done; /* assumes: CLIXON_PUBLISH_STREAMS, eg configure --enable-publish */ diff --git a/lib/src/clixon_stream.c b/lib/src/clixon_stream.c index 3bf3dea1..c9b7c143 100644 --- a/lib/src/clixon_stream.c +++ b/lib/src/clixon_stream.c @@ -199,7 +199,8 @@ stream_get_xml(clicon_handle h, cprintf(cb, "%s", es->es_name); if (es->es_description) cprintf(cb, "%s", es->es_description); - cprintf(cb, "false"); + cprintf(cb, "%s", + es->es_replay_enabled?"true":"false"); if (access){ cprintf(cb, ""); cprintf(cb, "xml"); diff --git a/util/Makefile.in b/util/Makefile.in index b6581003..d04af611 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -57,7 +57,7 @@ INSTALL = @INSTALL@ INSTALL_LIB = @INSTALL@ INSTALLFLAGS = @INSTALLFLAGS@ LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ +LIBS = @LIBS@ CPPFLAGS = @CPPFLAGS@ @@ -70,6 +70,7 @@ APPSRC = clixon_util_xml.c APPSRC += clixon_util_json.c APPSRC += clixon_util_yang.c APPSRC += clixon_util_xpath.c +# APPSRC += clixon_util_stream.c # Needs curl APPS = $(APPSRC:.c=) @@ -91,6 +92,9 @@ clixon_util_yang: clixon_util_yang.c $(MYLIB) clixon_util_xpath: clixon_util_xpath.c $(MYLIB) $(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -o $@ +clixon_util_stream: clixon_util_stream.c $(MYLIB) + $(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lcurl -o $@ + distclean: clean rm -f Makefile *~ .depend diff --git a/util/clixon_util_stream.c b/util/clixon_util_stream.c new file mode 100644 index 00000000..2cff755a --- /dev/null +++ b/util/clixon_util_stream.c @@ -0,0 +1,224 @@ +/* + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + + * Stream restconf support functions. + * (Original in grideye) + * Example: clixon_util_stream http://localhost/streams/EXAMPLE 10 + */ + +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clixon */ +#include "clixon/clixon.h" + +/* + * Types (curl) + */ +struct curlbuf{ + size_t b_len; + char *b_buf; +}; + +/* + * For the asynchronous case. I think we must handle the case where of many of these + * come in before we can handle them in the upper-level polling routine. + * realloc. Therefore, we append new data to the userdata buffer. + */ +static size_t +curl_get_cb(void *ptr, + size_t size, + size_t nmemb, + void *userdata) +{ + struct curlbuf *buf = (struct curlbuf *)userdata; + int len; + + len = size*nmemb; + if ((buf->b_buf = realloc(buf->b_buf, buf->b_len+len+1)) == NULL) + return 0; + memcpy(buf->b_buf+buf->b_len, ptr, len); + buf->b_len += len; + buf->b_buf[buf->b_len] = '\0'; + // fprintf(stderr, "%s\n", buf->b_buf); + return len; +} + +/*! Given an URL and data to post, do a (curl) get request with data. + * + * If getdata is set, return the (malloced) data (which should be freed). + * + * @param[in] query 'q' parameter that should be URL-encoded, ie ?q= + * XXX: dont add q=, there may be more parameters. + * @retval -1 fatal error + * @retval 1 ok + * + * @note curl_easy_perform blocks + * @note New handle is created every time, the handle can be re-used for + * better TCP performance + */ +int +url_get(char *url, + char *query, + int timeout, + char **getdata) +{ + int retval = -1; + CURL *curl; + char *err = NULL; + char *encoded = NULL; + struct curlbuf cb = {0, }; + cbuf *cbf = NULL; + struct curl_slist *list = NULL; + int ret; + + clicon_debug(1, "%s: curl -G %s", __FUNCTION__, url); + /* Set up curl for doing the communication with the controller */ + if ((curl = curl_easy_init()) == NULL) { + clicon_err(OE_PLUGIN, errno, "curl_easy_init"); + goto done; + } + if ((cbf = cbuf_new()) == NULL) + goto done; + + if (query){ + if ((encoded = curl_easy_escape(curl, query, 0)) == NULL){ + clicon_debug(1, "curl_easy_escape"); + goto done; + } + } + if ((err = malloc(CURL_ERROR_SIZE)) == NULL) { + clicon_debug(1, "%s: malloc", __FUNCTION__); + goto done; + } + /* specify URL to get */ + if (query) + cprintf(cbf, "%s?q=%s", url, encoded); + else + cprintf(cbf, "%s", url); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + list = curl_slist_append(list, "Accept: text/event-stream"); + list = curl_slist_append(list, "Cache-Control: no-cache"); + list = curl_slist_append(list, "Connection: keep-alive"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + + /* For reference, this url works + "http://192.36.171.239:8086/db/nordunet/series?q=select%20tcmp2%20from%20%22dk-ore%22%20limit%201" + */ + clicon_debug(1, "url: %s\n", cbuf_get(cbf)); + curl_easy_setopt(curl, CURLOPT_URL, cbuf_get(cbf)); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_get_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cb); + + /* some servers don't like requests that are made without a user-agent + field, so we provide one */ + + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err); + // curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + // curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + ret = curl_easy_perform(curl); + if (ret != CURLE_OPERATION_TIMEDOUT && ret != CURLE_OK){ + fprintf(stderr, "curl: %s %d", err, ret); + goto done; + } + if (getdata && cb.b_buf){ + *getdata = cb.b_buf; + cb.b_buf = NULL; + } + retval = 1; + done: + if (cbf) + cbuf_free(cbf); + if (err) + free(err); + if (encoded) + curl_free(encoded); + if (cb.b_buf) + free(cb.b_buf); + if (curl) + curl_easy_cleanup(curl); /* cleanup */ + return retval; +} + +static int +usage(char *argv0) +{ + fprintf(stderr, "usage:%s .\n\tInput on stdin\n", argv0); + exit(0); +} + +int +main(int argc, char **argv) +{ + cbuf *cb = cbuf_new(); + char *url; + char *query = NULL; + char *getdata = NULL; + int timeout; + + if (argc != 3){ + usage(argv[0]); + return 0; + } + url = argv[1]; + timeout = atoi(argv[2]); + if (url_get(url, query, timeout, &getdata) < 0) + goto done; + fprintf(stdout, "%s", getdata); + fflush(stdout); + done: + if (getdata) + free(getdata); + if (cb) + cbuf_free(cb); + return 0; +} + + diff --git a/yang/clixon-config@2018-10-21.yang b/yang/clixon-config@2018-10-21.yang index 6f7bf38a..fb07efa1 100644 --- a/yang/clixon-config@2018-10-21.yang +++ b/yang/clixon-config@2018-10-21.yang @@ -420,7 +420,7 @@ module clixon-config { } leaf CLICON_STREAM_RETENTION { type uint32; - default 0; + default 3600; units s; description "Retention for stream replay buffers in seconds, ie how much data to store before dropping. 0 means no retention";