- Native restconf: use cligen buffers instead of libevent for replies
This commit is contained in:
parent
05009aed67
commit
0d7e644335
6 changed files with 250 additions and 117 deletions
|
|
@ -63,6 +63,7 @@
|
|||
|
||||
#include "restconf_lib.h"
|
||||
#include "restconf_api.h" /* Virtual api */
|
||||
#include "restconf_native.h"
|
||||
|
||||
/*! Add HTTP header field name and value to reply, evhtp specific
|
||||
* @param[in] req Evhtp http request handle
|
||||
|
|
@ -81,8 +82,9 @@ restconf_reply_header(void *req0,
|
|||
size_t vlen;
|
||||
char *value = NULL;
|
||||
va_list ap;
|
||||
evhtp_header_t *evhdr;
|
||||
|
||||
evhtp_connection_t *conn;
|
||||
restconf_conn_h *rc;
|
||||
|
||||
if (req == NULL || name == NULL || vfmt == NULL){
|
||||
clicon_err(OE_CFG, EINVAL, "req, name or value is NULL");
|
||||
return -1;
|
||||
|
|
@ -103,11 +105,18 @@ restconf_reply_header(void *req0,
|
|||
goto done;
|
||||
}
|
||||
va_end(ap);
|
||||
if ((evhdr = evhtp_header_new(name, value, 0, 1)) == NULL){ /* 1: free after use */
|
||||
clicon_err(OE_CFG, errno, "evhttp_header_new");
|
||||
if ((conn = evhtp_request_get_connection(req)) == NULL){
|
||||
clicon_err(OE_DAEMON, EFAULT, "evhtp_request_get_connection");
|
||||
goto done;
|
||||
}
|
||||
if ((rc = conn->arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EFAULT, "Internal error: restconf-conn-h is NULL: shouldnt happen");
|
||||
goto done;
|
||||
}
|
||||
if (cvec_add_string(rc->rc_outp_hdrs, (char*)name, value) < 0){
|
||||
clicon_err(OE_RESTCONF, errno, "cvec_add_string");
|
||||
goto done;
|
||||
}
|
||||
evhtp_headers_add_header(req->headers_out, evhdr);
|
||||
retval = 0;
|
||||
done:
|
||||
if (value)
|
||||
|
|
@ -115,6 +124,60 @@ restconf_reply_header(void *req0,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Send reply
|
||||
* @see htp__create_reply_
|
||||
*/
|
||||
#define rc_parser conn->parser /* XXX */
|
||||
static int
|
||||
native_send_reply(restconf_conn_h *rc,
|
||||
evhtp_request_t *request,
|
||||
evhtp_res code)
|
||||
{
|
||||
int retval = -1;
|
||||
unsigned char major;
|
||||
unsigned char minor;
|
||||
cg_var *cv;
|
||||
|
||||
switch (request->proto) {
|
||||
case EVHTP_PROTO_10:
|
||||
if (request->flags & EVHTP_REQ_FLAG_KEEPALIVE) {
|
||||
/* protocol is HTTP/1.0 and clients wants to keep established */
|
||||
if (restconf_reply_header(request, "Connection", "keep-alive") < 0)
|
||||
goto done;
|
||||
}
|
||||
major = htparser_get_major(request->rc_parser); /* XXX Look origin */
|
||||
minor = htparser_get_minor(request->rc_parser);
|
||||
break;
|
||||
case EVHTP_PROTO_11:
|
||||
if (!(request->flags & EVHTP_REQ_FLAG_KEEPALIVE)) {
|
||||
/* protocol is HTTP/1.1 but client wanted to close */
|
||||
if (restconf_reply_header(request, "Connection", "keep-alive") < 0)
|
||||
goto done;
|
||||
}
|
||||
major = htparser_get_major(request->rc_parser);
|
||||
minor = htparser_get_minor(request->rc_parser);
|
||||
break;
|
||||
default:
|
||||
/* this sometimes happens when a response is made but paused before
|
||||
* the method has been parsed */
|
||||
major = 1;
|
||||
minor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
cprintf(rc->rc_outp_buf, "HTTP/%u.%u %u %s\r\n", major, minor, code, restconf_code2reason(code));
|
||||
|
||||
/* Loop over headers */
|
||||
cv = NULL;
|
||||
while ((cv = cvec_each(rc->rc_outp_hdrs, cv)) != NULL)
|
||||
cprintf(rc->rc_outp_buf, "%s: %s\r\n", cv_name_get(cv), cv_string_get(cv));
|
||||
cprintf(rc->rc_outp_buf, "\r\n");
|
||||
// cvec_reset(rc->rc_outp_hdrs); /* Is now done in restconf_connection but can be done here */
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send HTTP reply with potential message body
|
||||
* @param[in] req Evhtp http request handle
|
||||
* @param[in] cb Body as a cbuf, send if
|
||||
|
|
@ -130,13 +193,13 @@ restconf_reply_send(void *req0,
|
|||
int retval = -1;
|
||||
const char *reason_phrase;
|
||||
evhtp_connection_t *conn;
|
||||
struct evbuffer *eb = NULL;
|
||||
|
||||
restconf_conn_h *rc;
|
||||
|
||||
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
|
||||
req->status = code;
|
||||
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
||||
reason_phrase="";
|
||||
#if 0 /* XXX remove status header för evhtp? */
|
||||
#if 0 /* XXX remove status header for evhtp? */
|
||||
if (restconf_reply_header(req, "Status", "%d %s", code, reason_phrase) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
|
|
@ -144,33 +207,29 @@ restconf_reply_send(void *req0,
|
|||
clicon_err(OE_DAEMON, EFAULT, "evhtp_request_get_connection");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If body, add a content-length header */
|
||||
if (cb != NULL && cbuf_len(cb)){
|
||||
cprintf(cb, "\r\n");
|
||||
if (restconf_reply_header(req, "Content-Length", "%d", cbuf_len(cb)) < 0)
|
||||
goto done;
|
||||
}
|
||||
evhtp_send_reply(req, req->status);
|
||||
|
||||
else
|
||||
if (restconf_reply_header(req, "Content-Length", "0") < 0)
|
||||
goto done;
|
||||
if ((rc = conn->arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EFAULT, "Internal error: restconf-conn-h is NULL: shouldnt happen");
|
||||
goto done;
|
||||
}
|
||||
/* Create reply and write headers */
|
||||
if (native_send_reply(rc, req, code) < 0)
|
||||
goto done;
|
||||
req->flags |= EVHTP_REQ_FLAG_FINISHED; /* Signal to evhtp to read next request */
|
||||
/* Write a body if cbuf is nonzero */
|
||||
if (cb != NULL && cbuf_len(cb)){
|
||||
/* Suboptimal, copy from cbuf to evbuffer */
|
||||
if ((eb = evbuffer_new()) == NULL){
|
||||
clicon_err(OE_RESTCONF, errno, "evbuffer_new");
|
||||
goto done;
|
||||
}
|
||||
if (evbuffer_add(eb, cbuf_get(cb), cbuf_len(cb)) < 0){
|
||||
clicon_err(OE_CFG, errno, "evbuffer_add");
|
||||
goto done;
|
||||
}
|
||||
evhtp_send_reply_body(req, eb); /* conn->bev = eb, body is different */
|
||||
cprintf(rc->rc_outp_buf, "%s", cbuf_get(cb));
|
||||
}
|
||||
evhtp_send_reply_end(req); /* just flag finished */
|
||||
retval = 0;
|
||||
done:
|
||||
if (eb)
|
||||
evhtp_safe_free(eb, evbuffer_free);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@
|
|||
#include "restconf_api.h" /* generic not shared with plugins */
|
||||
#include "restconf_err.h"
|
||||
#include "restconf_root.h"
|
||||
#include "restconf_openssl.h" /* Restconf-openssl mode specific headers*/
|
||||
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:ro:"
|
||||
|
|
@ -188,37 +188,36 @@
|
|||
/* Forward */
|
||||
static int restconf_connection(int s, void* arg);
|
||||
|
||||
/*! Get restconf openssl global handle
|
||||
/*! Get restconf native handle
|
||||
* @param[in] h Clicon handle
|
||||
* @retval rh Openssl global handle
|
||||
* @retval rh Restconf native handle
|
||||
*/
|
||||
static restconf_handle *
|
||||
restconf_handle_get(clicon_handle h)
|
||||
static restconf_native_handle *
|
||||
restconf_native_handle_get(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
if ((p = clicon_hash_value(cdat, "restconf_openssl_handle", &len)) != NULL)
|
||||
return *(restconf_handle **)p;
|
||||
if ((p = clicon_hash_value(cdat, "restconf-native-handle", &len)) != NULL)
|
||||
return *(restconf_native_handle **)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Set restconf openssl global handle
|
||||
/*! Set restconf native handle
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] rh Openssl handle (malloced pointer)
|
||||
* @see clicon_config_yang_set for the configuration yang
|
||||
* @param[in] rh Restconf native handle (malloced pointer)
|
||||
*/
|
||||
static int
|
||||
openspec_handle_set(clicon_handle h,
|
||||
restconf_handle *rh)
|
||||
restconf_native_handle_set(clicon_handle h,
|
||||
restconf_native_handle *rh)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
/* It is the pointer to ys that should be copied by hash,
|
||||
so we send a ptr to the ptr to indicate what to copy.
|
||||
*/
|
||||
if (clicon_hash_add(cdat, "restconf_openssl_handle", &rh, sizeof(rh)) == NULL)
|
||||
if (clicon_hash_add(cdat, "restconf-native-handle", &rh, sizeof(rh)) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -237,7 +236,7 @@ buf_write(char *buf,
|
|||
ssize_t totlen = 0;
|
||||
int er;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clicon_debug(1, "%s buflen:%lu buf:%s", __FUNCTION__, buflen, buf);
|
||||
while (totlen < buflen){
|
||||
if (ssl){
|
||||
if ((len = SSL_write(ssl, buf+totlen, buflen-totlen)) <= 0){
|
||||
|
|
@ -276,6 +275,13 @@ buf_write(char *buf,
|
|||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
#if 1
|
||||
else if (errno == ECONNRESET) {/* Connection reset by peer */
|
||||
close(s);
|
||||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
goto ok; /* Close socket and ssl */
|
||||
}
|
||||
#endif
|
||||
else{
|
||||
clicon_err(OE_UNIX, errno, "write");
|
||||
goto done;
|
||||
|
|
@ -819,6 +825,23 @@ restconf_ssl_context_configure(clixon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Free clixon/cbuf resources related to an evhtp connection
|
||||
*/
|
||||
static int
|
||||
restconf_conn_free(evhtp_connection_t *conn)
|
||||
{
|
||||
restconf_conn_h *rc;
|
||||
|
||||
if ((rc = conn->arg) != NULL){
|
||||
if (rc->rc_outp_hdrs)
|
||||
cvec_free(rc->rc_outp_hdrs);
|
||||
if (rc->rc_outp_buf)
|
||||
cbuf_free(rc->rc_outp_buf);
|
||||
free(rc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Utility function to close restconf server ssl/evhtp socket.
|
||||
* There are many variants to closing, one could probably make this more generic
|
||||
* and always use this function, but it is difficult.
|
||||
|
|
@ -831,9 +854,10 @@ close_ssl_evhtp_socket(int s,
|
|||
int retval = -1;
|
||||
int ret;
|
||||
SSL *ssl;
|
||||
|
||||
|
||||
ssl = conn->ssl;
|
||||
clicon_debug(1, "%s conn-free (%p) 1", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
if (ssl != NULL){
|
||||
if (shutdown && (ret = SSL_shutdown(ssl)) < 0){
|
||||
|
|
@ -896,6 +920,7 @@ restconf_connection(int s,
|
|||
char buf[BUFSIZ]; /* from stdio.h, typically 8K */
|
||||
clicon_handle h;
|
||||
int readmore = 1;
|
||||
restconf_conn_h *rc;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((conn = (evhtp_connection_t*)arg) == NULL){
|
||||
|
|
@ -918,7 +943,13 @@ restconf_connection(int s,
|
|||
}
|
||||
else{
|
||||
if ((n = read(conn->sock, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
|
||||
clicon_err(OE_XML, errno, "SSL_read");
|
||||
if (errno == ECONNRESET) {/* Connection reset by peer */
|
||||
close(conn->sock);
|
||||
restconf_conn_free(conn);
|
||||
clixon_event_unreg_fd(conn->sock, restconf_connection);
|
||||
goto ok; /* Close socket and ssl */
|
||||
}
|
||||
clicon_err(OE_XML, errno, "read");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -943,47 +974,34 @@ restconf_connection(int s,
|
|||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
conn->ssl = NULL;
|
||||
clicon_debug(1, "%s conn-free (%p) 2", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn);
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||
if (conn->bev != NULL){
|
||||
char *buf = NULL;
|
||||
size_t buflen;
|
||||
struct evbuffer *ev;
|
||||
|
||||
size_t buflen;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((rc = conn->arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EFAULT, "Internal error: restconf-conn-h is NULL: shouldnt happen");
|
||||
goto done;
|
||||
}
|
||||
if ((ev = bufferevent_get_output(conn->bev)) != NULL){
|
||||
buflen = evbuffer_get_length(ev);
|
||||
if (buflen){
|
||||
#ifdef RESTCONF_LIBEVENT_POS_PATCH
|
||||
size_t pos;
|
||||
|
||||
pos = (size_t)conn->arg;
|
||||
#endif
|
||||
if ((buflen = evbuffer_get_length(ev)) != 0){
|
||||
// assert(0); /* 100 Cont ? */
|
||||
buf = (char*)evbuffer_pullup(ev, -1);
|
||||
clicon_debug(1, "%s buf:%s", __FUNCTION__, buf);
|
||||
#ifdef RESTCONF_LIBEVENT_POS_PATCH
|
||||
if (buf_write(buf+pos, buflen, conn->sock, conn->ssl) < 0)
|
||||
if (cbuf_append_buf(rc->rc_outp_buf, buf, buflen) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_append_buf");
|
||||
goto done;
|
||||
pos += buflen;
|
||||
conn->arg = (void*)pos;
|
||||
#else
|
||||
/* Does not work w multiple requests */
|
||||
if (buf_write(buf, buflen, conn->sock, conn->ssl) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
/* Return 0 from evhtp parser can be that it needs more data.
|
||||
*/
|
||||
readmore = 1; /* Readmore */
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "%s bev is NULL 2", __FUNCTION__);
|
||||
if (send_badrequest(h, s, conn->ssl) < 0) /* actually error */
|
||||
goto done;
|
||||
}
|
||||
if (buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf)+1, conn->sock, conn->ssl) < 0)
|
||||
goto done;
|
||||
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
|
||||
cbuf_reset(rc->rc_outp_buf);
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "%s bev is NULL 3", __FUNCTION__);
|
||||
|
|
@ -1075,7 +1093,8 @@ restconf_accept_client(int fd,
|
|||
{
|
||||
int retval = -1;
|
||||
restconf_socket *rsock = (restconf_socket *)arg;
|
||||
restconf_handle *rh = NULL;
|
||||
restconf_native_handle *rh = NULL;
|
||||
restconf_conn_h *rc = NULL;
|
||||
clicon_handle h;
|
||||
int s;
|
||||
struct sockaddr from = {0,};
|
||||
|
|
@ -1096,7 +1115,7 @@ restconf_accept_client(int fd,
|
|||
goto done;
|
||||
}
|
||||
h = rsock->rs_h;
|
||||
if ((rh = restconf_handle_get(h)) == NULL){
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1168,6 +1187,7 @@ restconf_accept_client(int fd,
|
|||
clixon_event_unreg_fd(s, restconf_connection);
|
||||
conn->ssl = NULL;
|
||||
clicon_debug(1, "%s conn-free (%p) 3", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
goto ok;
|
||||
break;
|
||||
|
|
@ -1223,6 +1243,7 @@ restconf_accept_client(int fd,
|
|||
if (send_badrequest(h, s, ssl) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s conn-free (%p) 5", __FUNCTION__, conn);
|
||||
restconf_conn_free(conn);
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
if (ssl){
|
||||
if ((ret = SSL_shutdown(ssl)) < 0){
|
||||
|
|
@ -1254,12 +1275,19 @@ restconf_accept_client(int fd,
|
|||
/*
|
||||
* Register callbacks for actual data socket
|
||||
*/
|
||||
#ifdef RESTCONF_LIBEVENT_POS_PATCH
|
||||
/* patch to keep track os position in output buffer
|
||||
* cannot use drain/copyout since the start position is "freezed" in bufferevent_socket_new
|
||||
*/
|
||||
conn->arg = (void*)0;
|
||||
#endif
|
||||
if ((rc = (restconf_conn_h*)malloc(sizeof(restconf_conn_h))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
if ((rc->rc_outp_hdrs = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
if ((rc->rc_outp_buf = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
conn->arg = rc;
|
||||
if (clixon_event_reg_fd(s, restconf_connection, (void*)conn, "restconf client socket") < 0)
|
||||
goto done;
|
||||
ok:
|
||||
|
|
@ -1272,13 +1300,13 @@ restconf_accept_client(int fd,
|
|||
}
|
||||
|
||||
static int
|
||||
restconf_openssl_terminate(clicon_handle h)
|
||||
restconf_native_terminate(clicon_handle h)
|
||||
{
|
||||
restconf_handle *rh;
|
||||
restconf_native_handle *rh;
|
||||
restconf_socket *rsock;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((rh = restconf_handle_get(h)) != NULL){
|
||||
if ((rh = restconf_native_handle_get(h)) != NULL){
|
||||
while ((rsock = rh->rh_sockets) != NULL){
|
||||
clixon_event_unreg_fd(rsock->rs_ss, restconf_accept_client);
|
||||
close(rsock->rs_ss);
|
||||
|
|
@ -1385,7 +1413,7 @@ openssl_init_socket(clicon_handle h,
|
|||
uint16_t ssl = 0;
|
||||
uint16_t port = 0;
|
||||
int ss = -1;
|
||||
restconf_handle *rh = NULL;
|
||||
restconf_native_handle *rh = NULL;
|
||||
restconf_socket *rsock = NULL; /* openssl per socket struct */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
|
@ -1403,7 +1431,7 @@ openssl_init_socket(clicon_handle h,
|
|||
&ss
|
||||
) < 0)
|
||||
goto done;
|
||||
if ((rh = restconf_handle_get(h)) == NULL){
|
||||
if ((rh = restconf_native_handle_get(h)) == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No openssl handle");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1449,7 +1477,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
char *server_cert_path = NULL;
|
||||
char *server_key_path = NULL;
|
||||
char *server_ca_cert_path = NULL;
|
||||
restconf_handle *rh;
|
||||
restconf_native_handle *rh;
|
||||
clixon_auth_type_t auth_type;
|
||||
int dbg;
|
||||
char *bstr;
|
||||
|
|
@ -1510,7 +1538,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
if (restconf_ssl_context_configure(h, ctx, server_cert_path, server_key_path, server_ca_cert_path) < 0)
|
||||
goto done;
|
||||
}
|
||||
rh = restconf_handle_get(h);
|
||||
rh = restconf_native_handle_get(h);
|
||||
rh->rh_ctx = ctx;
|
||||
/* evhtp stuff */ /* XXX move this to global level */
|
||||
if ((evbase = event_base_new()) == NULL){
|
||||
|
|
@ -1747,7 +1775,7 @@ main(int argc,
|
|||
int dbg = 0;
|
||||
int logdst = CLICON_LOG_SYSLOG;
|
||||
int drop_privileges = 1;
|
||||
restconf_handle *rh = NULL;
|
||||
restconf_native_handle *rh = NULL;
|
||||
int ret;
|
||||
cxobj *xrestconf = NULL;
|
||||
|
||||
|
|
@ -1896,7 +1924,7 @@ main(int argc,
|
|||
goto done;
|
||||
}
|
||||
memset(rh, 0, sizeof *rh);
|
||||
if (openspec_handle_set(h, rh) < 0)
|
||||
if (restconf_native_handle_set(h, rh) < 0)
|
||||
goto done;
|
||||
/* Openssl inits */
|
||||
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
|
||||
|
|
@ -1916,7 +1944,7 @@ main(int argc,
|
|||
clicon_debug(1, "restconf_main_openssl done");
|
||||
if (xrestconf)
|
||||
xml_free(xrestconf);
|
||||
restconf_openssl_terminate(h);
|
||||
restconf_native_terminate(h);
|
||||
restconf_terminate(h);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,20 +53,29 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _RESTCONF_OPENSSL_H_
|
||||
#define _RESTCONF_OPENSSL_H_
|
||||
#ifndef _RESTCONF_NATIVE_H_
|
||||
#define _RESTCONF_NATIVE_H_
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
/* Restconf connection handle
|
||||
* Per connection request
|
||||
*/
|
||||
typedef struct {
|
||||
// qelem_t rs_qelem; /* List header */
|
||||
cvec *rc_outp_hdrs; /* List of output headers */
|
||||
cbuf *rc_outp_buf; /* Output buffer */
|
||||
} restconf_conn_h;
|
||||
|
||||
/* Restconf request handle
|
||||
* Per socket request
|
||||
*/
|
||||
typedef struct {
|
||||
qelem_t rs_qelem; /* List header */
|
||||
clicon_handle rs_h; /* Clixon handle */
|
||||
int rs_ss; /* Server socket (ready for accept) */
|
||||
int rs_ssl; /* 0: Not SSL socket, 1:SSL socket */
|
||||
qelem_t rs_qelem; /* List header */
|
||||
clicon_handle rs_h; /* Clixon handle */
|
||||
int rs_ss; /* Server socket (ready for accept) */
|
||||
int rs_ssl; /* 0: Not SSL socket, 1:SSL socket */
|
||||
} restconf_socket;
|
||||
|
||||
/* Restconf handle
|
||||
|
|
@ -76,14 +85,14 @@ typedef struct {
|
|||
SSL_CTX *rh_ctx; /* SSL context */
|
||||
evhtp_t *rh_evhtp; /* Evhtp struct */
|
||||
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
||||
} restconf_handle;
|
||||
} restconf_native_handle;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int restconf_parse(void *req, const char *buf, size_t buflen);
|
||||
|
||||
#endif /* _RESTCONF_OPENSSL_H_ */
|
||||
#endif /* _RESTCONF_NATIVE_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
@ -93,14 +93,3 @@
|
|||
/* Name of default netns for clixon-restconf.yang socket/namespace field
|
||||
*/
|
||||
#define RESTCONF_NETNS_DEFAULT "default"
|
||||
|
||||
/* Patch to keep track os position in output buffer for native restconf using libevent
|
||||
* It addresses that multiple requests in a single TCP HTTP session will only reply first
|
||||
* reply again
|
||||
* Cannot use drain/copyout since the start position is "freezed" in bufferevent_socket_new
|
||||
* Strange thing is that evbuffer_drain / evbuffer_copyout cannot be used due to freeze set
|
||||
* One could have thought freeze was in place for writing only?
|
||||
* Note may not wrap-around correctly at size-t boundary
|
||||
|
||||
*/
|
||||
#define RESTCONF_LIBEVENT_POS_PATCH
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ APPNAME=example
|
|||
|
||||
cfg=$dir/scaling-conf.xml
|
||||
fyang=$dir/scaling.yang
|
||||
fconfig=$dir/large.xml
|
||||
fconfig2=$dir/large2.xml
|
||||
fconfig=$dir/large.xml
|
||||
fconfigonly=$dir/config.xml # only config for test
|
||||
ftest=$dir/test.xml
|
||||
fconfig2=$dir/large2.xml # leaf-list
|
||||
foutput=$dir/output.xml
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module scaling{
|
||||
|
|
@ -87,12 +90,17 @@ fi
|
|||
new "waiting"
|
||||
wait_backend
|
||||
|
||||
# Check this later with committed data
|
||||
new "generate config with $perfnr list entries"
|
||||
echo -n "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns=\"urn:example:clixon\">" > $fconfig
|
||||
echo -n "<x xmlns=\"urn:example:clixon\">" > $fconfigonly
|
||||
for (( i=0; i<$perfnr; i++ )); do
|
||||
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfig
|
||||
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfigonly
|
||||
done
|
||||
echo "</x></config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
echo -n "</x>" >> $fconfigonly # No CR
|
||||
|
||||
echo -n "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>" > $fconfig
|
||||
cat $fconfigonly >> $fconfig
|
||||
echo "</config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
|
||||
# Now take large config file and write it via netconf to candidate
|
||||
new "test time exists"
|
||||
|
|
@ -107,6 +115,19 @@ expecteof_file "time -p $clixon_netconf -qf $cfg" 0 "$fconfig" "^<rpc-reply $DEF
|
|||
new "netconf commit large config"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 2>&1 | awk '/real/ {print $2}'
|
||||
|
||||
new "Check running-db contents"
|
||||
echo "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>]]>]]>" | $clixon_netconf -qf $cfg > $foutput
|
||||
|
||||
# Create a file to compare with
|
||||
echo -n "<rpc-reply $DEFAULTNS><data>" > $ftest
|
||||
cat $fconfigonly >> $ftest
|
||||
echo -n "</data></rpc-reply>]]>]]>" >> $ftest
|
||||
|
||||
ret=$(diff $ftest $foutput)
|
||||
if [ $? -ne 0 ]; then
|
||||
err1 "Matching running-db with $fconfigonly"
|
||||
fi
|
||||
|
||||
# Now commit it again from candidate (validation takes time when
|
||||
# comparing to existing)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@ APPNAME=example
|
|||
|
||||
cfg=$dir/scaling-conf.xml
|
||||
fyang=$dir/scaling.yang
|
||||
fconfigonly=$dir/config.xml # only config for test
|
||||
ftest=$dir/test.xml
|
||||
fconfig=$dir/large.xml
|
||||
fconfig2=$dir/large2.xml
|
||||
fconfig2=$dir/large2.xml # leaf-list
|
||||
foutput=$dir/output.xml
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module scaling{
|
||||
|
|
@ -76,7 +79,6 @@ cat <<EOF > $cfg
|
|||
</clixon-config>
|
||||
EOF
|
||||
|
||||
|
||||
new "test params: -f $cfg"
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
|
|
@ -103,12 +105,17 @@ if [ $RC -ne 0 ]; then
|
|||
wait_restconf
|
||||
fi
|
||||
|
||||
# Check this later with committed data
|
||||
new "generate config with $perfnr list entries"
|
||||
echo -n "<rpc><edit-config><target><candidate/></target><config><x xmlns=\"urn:example:clixon\">" > $fconfig
|
||||
echo -n "<x xmlns=\"urn:example:clixon\">" > $fconfigonly
|
||||
for (( i=0; i<$perfnr; i++ )); do
|
||||
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfig
|
||||
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfigonly
|
||||
done
|
||||
echo "</x></config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
echo -n "</x>" >> $fconfigonly # No CR
|
||||
|
||||
echo -n "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>" > $fconfig
|
||||
cat $fconfigonly >> $fconfig
|
||||
echo "</config></edit-config></rpc>]]>]]>" >> $fconfig
|
||||
|
||||
# Now take large config file and write it via netconf to candidate
|
||||
new "test time exists"
|
||||
|
|
@ -123,6 +130,26 @@ expecteof_file "time -p $clixon_netconf -qf $cfg" 0 "$fconfig" "^<rpc-reply $DEF
|
|||
new "netconf commit large config"
|
||||
expecteof "time -p $clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 2>&1 | awk '/real/ {print $2}'
|
||||
|
||||
new "Check running-db contents"
|
||||
curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=config > $foutput
|
||||
|
||||
# Remove Content-Length line
|
||||
sed -i '/Content-Length:/d' $foutput
|
||||
|
||||
# Create a file to compare with
|
||||
echo "HTTP/1.1 200 OK
" > $ftest
|
||||
echo "Content-Type: application/yang-data+xml
" >> $ftest
|
||||
echo "Cache-Control: no-cache
" >> $ftest
|
||||
echo "
">> $ftest
|
||||
echo -n "<data>">> $ftest
|
||||
cat $fconfigonly >> $ftest
|
||||
echo "</data>
" >> $ftest
|
||||
|
||||
ret=$(diff $ftest $foutput)
|
||||
if [ $? -ne 0 ]; then
|
||||
err1 "Matching running-db with $fconfigonly"
|
||||
fi
|
||||
|
||||
# RESTCONF get
|
||||
new "restconf get $perfreq small config 1 key index"
|
||||
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue