diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c89b007..d0f3a50c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,17 @@
## 4.6.0
Expected: July 2020
+### C-API changes on existing features (For developers)
+
+* Due to name collision with libevent, all clixon event functions prepended with `clixon_`. You need to rename your event functions as follows:
+ * event_reg_fd() -> clixon_event_reg_fd()
+ * event_unreg_fd() -> clixon_event_unreg_fd()
+ * event_reg_timeout() -> clixon_event_reg_timeout()
+ * event_unreg_timeout() -> clixon_event_unreg_timeout()
+ * event_poll() -> clixon_event_poll()
+ * event_loop() -> clixon_event_loop()
+ * event_exit() -> clixon_event_exit()
+
### Minor changes
* Added new function `clicon_xml2str()` to complement xml_print and others that returns a malloced string.
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 4b445fc8..43c4f6b2 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -144,7 +144,7 @@ backend_client_rm(clicon_handle h,
for (c = *ce_prev; c; c = c->ce_next){
if (c == ce){
if (ce->ce_s){
- event_unreg_fd(ce->ce_s, from_client);
+ clixon_event_unreg_fd(ce->ce_s, from_client);
close(ce->ce_s);
ce->ce_s = 0;
}
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index acd17847..55fb6ac9 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -134,7 +134,7 @@ backend_terminate(clicon_handle h)
if (sockfamily==AF_UNIX && lstat(sockpath, &st) == 0)
unlink(sockpath);
backend_handle_exit(h); /* Also deletes streams. Cannot use h after this. */
- event_exit();
+ clixon_event_exit();
clicon_debug(1, "%s done", __FUNCTION__);
clicon_log_exit();
return 0;
@@ -150,7 +150,7 @@ backend_sig_term(int arg)
if (i++ == 0)
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
__PROGRAM__, __FUNCTION__, getpid(), arg);
- clicon_exit_set(); /* checked in event_loop() */
+ clicon_exit_set(); /* checked in clixon_event_loop() */
}
/*! Create backend server socket and register callback
@@ -168,7 +168,7 @@ backend_server_socket(clicon_handle h)
return -1;
/* ss is a server socket that the clients connect to. The callback
therefore accepts clients on ss */
- if (event_reg_fd(ss, backend_accept_client, h, "server socket") < 0) {
+ if (clixon_event_reg_fd(ss, backend_accept_client, h, "server socket") < 0) {
close(ss);
return -1;
}
@@ -923,7 +923,7 @@ main(int argc,
if (stream_timer_setup(0, h) < 0)
goto done;
- if (event_loop() < 0)
+ if (clixon_event_loop() < 0)
goto done;
ok:
retval = 0;
diff --git a/apps/backend/backend_socket.c b/apps/backend/backend_socket.c
index 5d6bc82f..75837e61 100644
--- a/apps/backend/backend_socket.c
+++ b/apps/backend/backend_socket.c
@@ -289,7 +289,7 @@ backend_accept_client(int fd,
/*
* Here we register callbacks for actual data socket
*/
- if (event_reg_fd(s, from_client, (void*)ce, "local netconf client socket") < 0)
+ if (clixon_event_reg_fd(s, from_client, (void*)ce, "local netconf client socket") < 0)
goto done;
retval = 0;
done:
diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c
index 6a691e79..3ab4115b 100644
--- a/apps/cli/cli_common.c
+++ b/apps/cli/cli_common.c
@@ -987,7 +987,7 @@ cli_notification_cb(int s,
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
close(s);
errno = ESHUTDOWN;
- event_unreg_fd(s, cli_notification_cb);
+ clixon_event_unreg_fd(s, cli_notification_cb);
goto done;
}
/* XXX pass yang_spec and use xerr*/
diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c
index 968d0fb8..376edd89 100644
--- a/apps/netconf/netconf_main.c
+++ b/apps/netconf/netconf_main.c
@@ -274,7 +274,7 @@ netconf_input_cb(int s,
}
}
/* poll==1 if more, poll==0 if none */
- if ((poll = event_poll(s)) < 0)
+ if ((poll = clixon_event_poll(s)) < 0)
goto done;
if (poll == 0)
break; /* No data to read */
@@ -338,7 +338,7 @@ netconf_terminate(clicon_handle h)
if ((x = clicon_conf_xml(h)) != NULL)
xml_free(x);
xpath_optimize_exit();
- event_exit();
+ clixon_event_exit();
clicon_handle_exit(h);
clicon_log_exit();
return 0;
@@ -590,7 +590,7 @@ main(int argc,
/* Send hello to northbound client */
if (!quiet)
send_hello(h, 1, id);
- if (event_reg_fd(0, netconf_input_cb, h, "netconf socket") < 0)
+ if (clixon_event_reg_fd(0, netconf_input_cb, h, "netconf socket") < 0)
goto done;
if (debug)
clicon_option_dump(h, debug);
@@ -598,10 +598,10 @@ main(int argc,
struct timeval t;
gettimeofday(&t, NULL);
timeradd(&t, &tv, &t);
- if (event_reg_timeout(t, timeout_fn, NULL, "timeout") < 0)
+ if (clixon_event_reg_timeout(t, timeout_fn, NULL, "timeout") < 0)
goto done;
}
- if (event_loop() < 0)
+ if (clixon_event_loop() < 0)
goto done;
retval = 0;
done:
diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c
index 39b003c1..ff9ba58a 100644
--- a/apps/netconf/netconf_rpc.c
+++ b/apps/netconf/netconf_rpc.c
@@ -437,7 +437,7 @@ netconf_notification_cb(int s,
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
close(s);
errno = ESHUTDOWN;
- event_unreg_fd(s, netconf_notification_cb);
+ clixon_event_unreg_fd(s, netconf_notification_cb);
goto done;
}
yspec = clicon_dbspec_yang(h);
@@ -520,7 +520,7 @@ netconf_create_subscription(clicon_handle h,
goto done;
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL)
goto ok;
- if (event_reg_fd(s,
+ if (clixon_event_reg_fd(s,
netconf_notification_cb,
h,
"notification socket") < 0)
diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in
index ce811dfa..92a9124b 100644
--- a/apps/restconf/Makefile.in
+++ b/apps/restconf/Makefile.in
@@ -86,11 +86,11 @@ APPL = clixon_restconf_$(with_restconf)
endif
# Common source - not accessible from plugin - independent of restconf package (fcgi|evhtp)
-APPSRC = restconf_lib.c
+#APPSRC = restconf_lib.c
# Fcgi-specific source including main
ifeq ($(with_restconf),fcgi)
-APPSRC += restconf_fcgi_lib.c
+APPSRC = restconf_fcgi_lib.c
APPSRC += restconf_fcgi_main.c
APPSRC += restconf_methods.c # These should be moved ^
APPSRC += restconf_methods_post.c
@@ -100,19 +100,30 @@ endif
# Evhtp-specific source including main
ifeq ($(with_restconf),evhtp)
-APPSRC += restconf_evhtp_main.c
+APPSRC = restconf_evhtp_main.c
endif
APPOBJ = $(APPSRC:.c=.o)
-all: $(APPL)
+# Accessible from plugin
+LIBSRC = restconf_lib.c
+LIBOBJ = $(LIBSRC:.c=.o)
+
+# This lib is very small but used for clixon restconf applications to access clixon restconf lib
+# functions. Mostly for future use
+MYNAME = clixon_restconf
+MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
+MYLIB = $(MYLIBLINK).$(CLIXON_MAJOR).$(CLIXON_MINOR)
+MYLIBSO = $(MYLIBLINK).$(CLIXON_MAJOR)
+
+all: $(MYLIB) $(APPL)
# Dependency of clixon library
$(top_srcdir)/lib/src/$(CLIXON_LIB):
(cd $(top_srcdir)/lib/src && $(MAKE) $(MFLAGS) $(CLIXON_LIB))
clean:
- rm -f *.core $(APPL) $(APPOBJ) *.o # extra .o to clean residue if with_restconf changes
+ rm -f $(LIBOBJ) *.core $(APPL) $(APPOBJ) *.o $(MYLIB) $(MYLIBSO) $(MYLIBLINK) # extra .o to clean residue if with_restconf changes
distclean: clean
rm -f Makefile *~ .depend
@@ -122,7 +133,7 @@ distclean: clean
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
# Also a rule for letting www-dir be owned by www-data, which only works for sudo
-install: $(APPL)
+install: install-lib $(APPL)
ifeq ($(shell whoami),root)
install -d -m 0755 -o $(wwwuser) -g $(wwwuser) $(DESTDIR)$(wwwdir)
else
@@ -130,10 +141,19 @@ else
endif
install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(wwwdir)
-install-include:
+install-lib: $(MYLIB)
+ install -d -m 0755 $(DESTDIR)$(libdir)
+ install -m 0644 $(INSTALLFLAGS) $(MYLIB) $(DESTDIR)$(libdir)
+ ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclixon_restconf.so.2
+ ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon_restconf.so
+
+install-include: clixon_restconf.h
+ install -d -m 0755 $(DESTDIR)$(includedir)/clixon
+ install -m 0644 $^ $(DESTDIR)$(includedir)/clixon
uninstall:
rm -f $(DESTDIR)$(wwwdir)/$(APPL)
+ rm -f $(DESTDIR)$(libdir)/$(MYLIBLINK)*
.SUFFIXES:
.SUFFIXES: .c .o
@@ -141,8 +161,18 @@ uninstall:
.c.o:
$(CC) $(INCLUDES) -D__PROGRAM__=\"clixon_restconf\" $(CPPFLAGS) $(CFLAGS) -c $<
-$(APPL) : $(APPOBJ)
- $(CC) $(LDFLAGS) $(APPOBJ) $(LIBS) -o $@
+$(APPL) : $(APPOBJ) $(MYLIBLINK) $(LIBDEPS)
+ $(CC) $(LDFLAGS) $(APPOBJ) -L. $(MYLIB) $(LIBS) -o $@
+
+$(MYLIB) : $(LIBOBJ) $(LIBDEPS)
+ifeq ($(HOST_VENDOR),apple)
+ $(CC) $(LDFLAGS) -shared -undefined dynamic_lookup -o $@ $(LIBOBJ) $(LIBS)
+else
+ $(CC) $(LDFLAGS) -shared -Wl,-soname,$(MYLIBSO) -o $@ $(LIBOBJ) $(LIBS) -Wl,-soname=$(MYLIBSO)
+endif
+
+# link-name is needed for application linking, eg for clixon_cli and clixon_config
+$(MYLIBLINK) : $(MYLIB)
TAGS:
find . -name '*.[chyl]' -print | etags -
diff --git a/apps/restconf/clixon_restconf.h b/apps/restconf/clixon_restconf.h
new file mode 100644
index 00000000..8cf332d0
--- /dev/null
+++ b/apps/restconf/clixon_restconf.h
@@ -0,0 +1,66 @@
+/*
+ *
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright (C) 2009-2019 Olof Hagsand
+
+ 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 *****
+
+ * The exported interface to plugins. External apps (eg frontend restconf plugins)
+ * should only include this file (not the restconf_*.h)
+ */
+
+#ifndef _CLIXON_RESTCONF_H_
+#define _CLIXON_RESTCONF_H_
+
+/*
+ * Types (also in restconf_lib.h)
+ */
+enum restconf_media{
+ YANG_DATA_JSON, /* "application/yang-data+json" */
+ YANG_DATA_XML, /* "application/yang-data+xml" */
+ YANG_PATCH_JSON, /* "application/yang-patch+json" */
+ YANG_PATCH_XML /* "application/yang-patch+xml" */
+};
+typedef enum restconf_media restconf_media;
+
+/*
+ * Prototypes (also in restconf_lib.h)
+ */
+int restconf_err2code(char *tag);
+const char *restconf_code2reason(int code);
+const restconf_media restconf_media_str2int(char *media);
+const char *restconf_media_int2str(restconf_media media);
+int get_user_cookie(char *cookiestr, char *attribute, char **val);
+int restconf_terminate(clicon_handle h);
+int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
+int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
+char *clixon_restconf_param_get(clicon_handle h, char *param);
+int clixon_restconf_param_set(clicon_handle h, char *param, char *val);
+
+#endif /* _CLIXON_RESTCONF_H_ */
diff --git a/apps/restconf/restconf_evhtp_main.c b/apps/restconf/restconf_evhtp_main.c
index ec499578..da646841 100644
--- a/apps/restconf/restconf_evhtp_main.c
+++ b/apps/restconf/restconf_evhtp_main.c
@@ -105,7 +105,7 @@ restconf_sig_term(int arg)
#endif
restconf_terminate(_CLICON_HANDLE);
}
- clicon_exit_set(); /* checked in event_loop() */
+ clicon_exit_set(); /* checked in clixon_event_loop() */
exit(-1);
}
@@ -240,7 +240,7 @@ usage(clicon_handle h,
exit(0);
}
-/*! Main routine for libhttp restconf
+/*! Main routine for libevhtp restconf
*/
int
main(int argc,
diff --git a/apps/restconf/restconf_fcgi_lib.c b/apps/restconf/restconf_fcgi_lib.c
index b817738d..ea2371d4 100644
--- a/apps/restconf/restconf_fcgi_lib.c
+++ b/apps/restconf/restconf_fcgi_lib.c
@@ -64,36 +64,16 @@
#include "restconf_lib.h"
#include "restconf_fcgi_lib.h"
-/*! Return media_in from Content-Type, -1 if not found or unrecognized
- * @note media-type syntax does not support parameters
- * @see RFC7231 Sec 3.1.1.1 for media-type syntax type:
- * media-type = type "/" subtype *( OWS ";" OWS parameter )
- * type = token
- * subtype = token
- *
- */
-restconf_media
-restconf_content_type(FCGX_Request *r)
-{
- char *str;
- restconf_media m;
-
- if ((str = FCGX_GetParam("HTTP_CONTENT_TYPE", r->envp)) == NULL)
- return -1;
- if ((int)(m = restconf_media_str2int(str)) == -1)
- return -1;
- return m;
-}
-
/*! HTTP error 400
* @param[in] r Fastcgi request handle
*/
int
-restconf_badrequest(FCGX_Request *r)
+restconf_badrequest(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_SetExitStatus(400, r->out);
FCGX_FPrintF(r->out, "Status: 400 Bad Request\r\n"); /* 400 bad request */
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
@@ -107,11 +87,12 @@ restconf_badrequest(FCGX_Request *r)
* @param[in] r Fastcgi request handle
*/
int
-restconf_unauthorized(FCGX_Request *r)
+restconf_unauthorized(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_SetExitStatus(401, r->out);
FCGX_FPrintF(r->out, "Status: 401 Unauthorized\r\n"); /* 401 unauthorized */
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
@@ -124,11 +105,12 @@ restconf_unauthorized(FCGX_Request *r)
* @param[in] r Fastcgi request handle
*/
int
-restconf_forbidden(FCGX_Request *r)
+restconf_forbidden(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_SetExitStatus(403, r->out);
FCGX_FPrintF(r->out, "Status: 403 Forbidden\r\n"); /* 403 forbidden */
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
@@ -141,11 +123,12 @@ restconf_forbidden(FCGX_Request *r)
* @param[in] r Fastcgi request handle
*/
int
-restconf_notfound(FCGX_Request *r)
+restconf_notfound(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_SetExitStatus(404, r->out);
FCGX_FPrintF(r->out, "Status: 404 Not Found\r\n"); /* 404 not found */
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
@@ -160,11 +143,12 @@ restconf_notfound(FCGX_Request *r)
* @param[in] r Fastcgi request handle
*/
int
-restconf_notacceptable(FCGX_Request *r)
+restconf_notacceptable(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_SetExitStatus(406, r->out);
FCGX_FPrintF(r->out, "Status: 406 Not Acceptable\r\n"); /* 406 not acceptible */
@@ -206,12 +190,13 @@ restconf_unsupported_media(FCGX_Request *r)
* @param[in] r Fastcgi request handle
*/
int
-restconf_internal_server_error(FCGX_Request *r)
+restconf_internal_server_error(clicon_handle h,
+ FCGX_Request *r)
{
char *path;
clicon_debug(1, "%s", __FUNCTION__);
- path = FCGX_GetParam("REQUEST_URI", r->envp);
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
FCGX_FPrintF(r->out, "Status: 500 Internal Server Error\r\n"); /* 500 internal server error */
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
FCGX_FPrintF(r->out, "
Internal server error when accessing %s
\n", path);
@@ -231,23 +216,6 @@ restconf_notimplemented(FCGX_Request *r)
return 0;
}
-/*!
- * @param[in] r Fastcgi request handle
- */
-static int
-printparam(FCGX_Request *r,
- char *e,
- int dbgp)
-{
- char *p = FCGX_GetParam(e, r->envp);
-
- if (dbgp)
- clicon_debug(1, "%s = '%s'", e, p?p:"");
- else
- FCGX_FPrintF(r->out, "%s = '%s'\n", e, p?p:"");
- return 0;
-}
-
/*! Print all FCGI headers
* @param[in] r Fastcgi request handle
* @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https
@@ -256,43 +224,73 @@ int
restconf_test(FCGX_Request *r,
int dbg)
{
- printparam(r, "QUERY_STRING", dbg);
- printparam(r, "REQUEST_METHOD", dbg);
- printparam(r, "CONTENT_TYPE", dbg);
- printparam(r, "CONTENT_LENGTH", dbg);
- printparam(r, "SCRIPT_FILENAME", dbg);
- printparam(r, "SCRIPT_NAME", dbg);
- printparam(r, "REQUEST_URI", dbg);
- printparam(r, "DOCUMENT_URI", dbg);
- printparam(r, "DOCUMENT_ROOT", dbg);
- printparam(r, "SERVER_PROTOCOL", dbg);
- printparam(r, "GATEWAY_INTERFACE", dbg);
- printparam(r, "SERVER_SOFTWARE", dbg);
- printparam(r, "REMOTE_ADDR", dbg);
- printparam(r, "REMOTE_PORT", dbg);
- printparam(r, "SERVER_ADDR", dbg);
- printparam(r, "SERVER_PORT", dbg);
- printparam(r, "SERVER_NAME", dbg);
- printparam(r, "HTTP_COOKIE", dbg);
- printparam(r, "HTTPS", dbg);
- printparam(r, "HTTP_HOST", dbg);
- printparam(r, "HTTP_ACCEPT", dbg);
- printparam(r, "HTTP_CONTENT_TYPE", dbg);
- printparam(r, "HTTP_AUTHORIZATION", dbg);
-#if 0 /* For debug */
+ char **environ = r->envp;
+ int i;
+
clicon_debug(1, "All environment vars:");
- {
- extern char **environ;
- int i;
- for (i = 0; environ[i] != NULL; i++){
- clicon_debug(1, "%s", environ[i]);
- }
+ for (i = 0; environ[i] != NULL; i++){
+ clicon_debug(1, "%s", environ[i]);
}
- clicon_debug(1, "End environment vars:");
-#endif
+ clicon_debug(1, "End environment vars");
return 0;
}
+/*! Convert FCGI parameters to clixon runtime data
+ * @param[in] h Clixon handle
+ * @param[in] envp Fastcgi request handle parameter array on the format "="
+ * @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https
+ */
+int
+clixon_restconf_params_set(clicon_handle h,
+ char **envp)
+{
+ int retval = -1;
+ int i;
+ char *param;
+ char *val;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ for (i = 0; envp[i] != NULL; i++){ /* on the form = */
+ if (clixon_strsplit(envp[i], '=', ¶m, &val) < 0)
+ goto done;
+ clicon_debug(1, "%s param:%s val:%s", __FUNCTION__, param, val);
+ if (clixon_restconf_param_set(h, param, val) < 0)
+ goto done;
+ }
+ retval = 0;
+ done:
+ clicon_debug(1, "%s %d", __FUNCTION__, retval);
+ return retval;
+}
+
+/*! Clear all FCGI parameters in an environment
+ * @param[in] h Clixon handle
+ * @param[in] envp Fastcgi request handle parameter array on the format "="
+ * @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https
+ */
+int
+clixon_restconf_params_clear(clicon_handle h,
+ char **envp)
+{
+ int retval = -1;
+ int i;
+ char *param;
+ char *val;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ for (i = 0; envp[i] != NULL; i++){ /* on the form = */
+ if (clixon_strsplit(envp[i], '=', ¶m, &val) < 0)
+ goto done;
+ clicon_debug(1, "%s param:%s val:%s", __FUNCTION__, param, val);
+ if (clixon_restconf_param_del(h, param) < 0)
+ goto done;
+ }
+ retval = 0;
+ done:
+ clicon_debug(1, "%s %d", __FUNCTION__, retval);
+ return retval;
+}
+
/*!
* @param[in] r Fastcgi request handle
*/
@@ -431,7 +429,8 @@ api_return_err(clicon_handle h,
* @note ports are ignored
*/
int
-http_location(FCGX_Request *r,
+http_location(clicon_handle h,
+ FCGX_Request *r,
cxobj *xobj)
{
int retval = -1;
@@ -440,9 +439,9 @@ http_location(FCGX_Request *r,
char *request_uri;
cbuf *cb = NULL;
- https = FCGX_GetParam("HTTPS", r->envp);
- host = FCGX_GetParam("HTTP_HOST", r->envp);
- request_uri = FCGX_GetParam("REQUEST_URI", r->envp);
+ https = clixon_restconf_param_get(h, "HTTPS");
+ host = clixon_restconf_param_get(h, "HTTP_HOST");
+ request_uri = clixon_restconf_param_get(h, "REQUEST_URI");
if (xobj != NULL){
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "cbuf_new");
@@ -468,23 +467,4 @@ http_location(FCGX_Request *r,
return retval;
}
-/*! Extract uri-encoded uri-path from fastcgi parameters
- * Use REQUEST_URI parameter and strip ?args
- * REQUEST_URI have args and is encoded
- * eg /interface=eth%2f0%2f0?insert=first
- * DOCUMENT_URI dont have args and is not encoded
- * eg /interface=eth/0/0
- * causes problems with eg /interface=eth%2f0%2f0
- */
-char *
-restconf_uripath(FCGX_Request *r)
-{
- char *path;
- char *q;
-
- path = FCGX_GetParam("REQUEST_URI", r->envp);
- if ((q = index(path, '?')) != NULL)
- *q = '\0';
- return path;
-}
diff --git a/apps/restconf/restconf_fcgi_lib.h b/apps/restconf/restconf_fcgi_lib.h
index 9d9ce829..23142089 100644
--- a/apps/restconf/restconf_fcgi_lib.h
+++ b/apps/restconf/restconf_fcgi_lib.h
@@ -40,21 +40,21 @@
/*
* Prototypes
*/
-restconf_media restconf_content_type(FCGX_Request *r);
-int restconf_badrequest(FCGX_Request *r);
-int restconf_unauthorized(FCGX_Request *r);
-int restconf_forbidden(FCGX_Request *r);
-int restconf_notfound(FCGX_Request *r);
-int restconf_notacceptable(FCGX_Request *r);
+int restconf_badrequest(clicon_handle h, FCGX_Request *r);
+int restconf_unauthorized(clicon_handle h, FCGX_Request *r);
+int restconf_forbidden(clicon_handle h, FCGX_Request *r);
+int restconf_notfound(clicon_handle h, FCGX_Request *r);
+int restconf_notacceptable(clicon_handle h, FCGX_Request *r);
int restconf_conflict(FCGX_Request *r);
int restconf_unsupported_media(FCGX_Request *r);
-int restconf_internal_server_error(FCGX_Request *r);
+int restconf_internal_server_error(clicon_handle h, FCGX_Request *r);
int restconf_notimplemented(FCGX_Request *r);
int restconf_test(FCGX_Request *r, int dbg);
+int clixon_restconf_params_set(clicon_handle h, char **envp);
+int clixon_restconf_params_clear(clicon_handle h, char **envp);
cbuf *readdata(FCGX_Request *r);
int api_return_err(clicon_handle h, FCGX_Request *r, cxobj *xerr,
int pretty, enum restconf_media media, int code);
-int http_location(FCGX_Request *r, cxobj *xobj);
-char *restconf_uripath(FCGX_Request *r);
+int http_location(clicon_handle h, FCGX_Request *r, cxobj *xobj);
#endif /* _RESTCONF_FCGI_LIB_H_ */
diff --git a/apps/restconf/restconf_fcgi_main.c b/apps/restconf/restconf_fcgi_main.c
index 118ad915..f5f07c23 100644
--- a/apps/restconf/restconf_fcgi_main.c
+++ b/apps/restconf/restconf_fcgi_main.c
@@ -114,7 +114,7 @@ api_data(clicon_handle h,
char *request_method;
clicon_debug(1, "%s", __FUNCTION__);
- request_method = FCGX_GetParam("REQUEST_METHOD", r->envp);
+ request_method = clixon_restconf_param_get(h, "REQUEST_METHOD");
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
if (strcmp(request_method, "OPTIONS")==0)
retval = api_data_options(h, r);
@@ -131,7 +131,7 @@ api_data(clicon_handle h,
else if (strcmp(request_method, "DELETE")==0)
retval = api_data_delete(h, r, api_path, pi, pretty, media_out);
else
- retval = restconf_notfound(r);
+ retval = restconf_notfound(h, r);
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@@ -161,7 +161,7 @@ api_operations(clicon_handle h,
char *request_method;
clicon_debug(1, "%s", __FUNCTION__);
- request_method = FCGX_GetParam("REQUEST_METHOD", r->envp);
+ request_method = clixon_restconf_param_get(h, "REQUEST_METHOD");
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
if (strcmp(request_method, "GET")==0)
retval = api_operations_get(h, r, path, pi, qvec, data, pretty, media_out);
@@ -169,7 +169,7 @@ api_operations(clicon_handle h,
retval = api_operations_post(h, r, path, pi, qvec, data,
pretty, media_out);
else
- retval = restconf_notfound(r);
+ retval = restconf_notfound(h, r);
return retval;
}
@@ -340,8 +340,8 @@ api_restconf(clicon_handle h,
cxobj *xerr;
clicon_debug(1, "%s", __FUNCTION__);
- path = restconf_uripath(r);
- query = FCGX_GetParam("QUERY_STRING", r->envp);
+ path = restconf_uripath(h);
+ query = clixon_restconf_param_get(h, "QUERY_STRING");
pretty = clicon_option_bool(h, "CLICON_RESTCONF_PRETTY");
/* Get media for output (proactive negotiation) RFC7231 by using
@@ -349,7 +349,7 @@ api_restconf(clicon_handle h,
* operation POST, etc
* If accept is * default is yang-json
*/
- if ((media_str = FCGX_GetParam("HTTP_ACCEPT", r->envp)) == NULL){
+ if ((media_str = clixon_restconf_param_get(h, "HTTP_ACCEPT")) == NULL){
// retval = restconf_unsupported_media(r);
// goto done;
}
@@ -367,15 +367,15 @@ api_restconf(clicon_handle h,
goto done;
/* Sanity check of path. Should be /restconf/ */
if (pn < 2){
- restconf_notfound(r);
+ restconf_notfound(h, r);
goto ok;
}
if (strlen(pvec[0]) != 0){
- retval = restconf_notfound(r);
+ retval = restconf_notfound(h, r);
goto done;
}
if (strcmp(pvec[1], RESTCONF_API)){
- retval = restconf_notfound(r);
+ retval = restconf_notfound(h, r);
goto done;
}
restconf_test(r, 1);
@@ -385,7 +385,7 @@ api_restconf(clicon_handle h,
goto done;
}
if ((method = pvec[2]) == NULL){
- retval = restconf_notfound(r);
+ retval = restconf_notfound(h, r);
goto done;
}
clicon_debug(1, "%s: method=%s", __FUNCTION__, method);
@@ -441,7 +441,7 @@ api_restconf(clicon_handle h,
else if (strcmp(method, "test") == 0)
restconf_test(r, 0);
else
- restconf_notfound(r);
+ restconf_notfound(h, r);
ok:
retval = 0;
done:
@@ -483,7 +483,7 @@ restconf_sig_term(int arg)
stream_child_freeall(_CLICON_HANDLE);
restconf_terminate(_CLICON_HANDLE);
}
- clicon_exit_set(); /* checked in event_loop() */
+ clicon_exit_set(); /* checked in clixon_event_loop() */
exit(-1);
}
@@ -790,8 +790,12 @@ main(int argc,
clicon_session_id_set(h, id);
start++;
}
-
- if ((path = FCGX_GetParam("REQUEST_URI", r->envp)) != NULL){
+ /* Translate from FCGI parameter form to Clixon runtime data
+ * XXX: potential name collision?
+ */
+ if (clixon_restconf_params_set(h, r->envp) < 0)
+ goto done;
+ if ((path = clixon_restconf_param_get(h, "REQUEST_URI")) != NULL){
clicon_debug(1, "path: %s", path);
if (strncmp(path, "/" RESTCONF_API, strlen("/" RESTCONF_API)) == 0)
api_restconf(h, r); /* This is the function */
@@ -803,11 +807,13 @@ main(int argc,
}
else{
clicon_debug(1, "top-level %s not found", path);
- restconf_notfound(r);
+ restconf_notfound(h, r);
}
}
else
clicon_debug(1, "NULL URI");
+ if (clixon_restconf_params_clear(h, r->envp) < 0)
+ goto done;
if (finish)
FCGX_Finish_r(r);
else{ /* A handler is forked so we initiate a new request after instead
@@ -817,7 +823,8 @@ main(int argc,
goto done;
}
}
- }
+
+ } /* while */
retval = 0;
done:
stream_child_freeall(h);
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index adf30863..a361f581 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -176,6 +176,27 @@ restconf_media_int2str(restconf_media media)
return clicon_int2str(http_media_map, media);
}
+/*! Return media_in from Content-Type, -1 if not found or unrecognized
+ * @note media-type syntax does not support parameters
+ * @see RFC7231 Sec 3.1.1.1 for media-type syntax type:
+ * media-type = type "/" subtype *( OWS ";" OWS parameter )
+ * type = token
+ * subtype = token
+ *
+ */
+restconf_media
+restconf_content_type(clicon_handle h)
+{
+ char *str;
+ restconf_media m;
+
+ if ((str = clixon_restconf_param_get(h, "HTTP_CONTENT_TYPE")) == NULL)
+ return -1;
+ if ((int)(m = restconf_media_str2int(str)) == -1)
+ return -1;
+ return m;
+}
+
/*! Parse a cookie string and return value of cookie attribute
* @param[in] cookiestr cookie string according to rfc6265 (modified)
* @param[in] attribute cookie attribute
@@ -389,3 +410,62 @@ restconf_main_extension_cb(clicon_handle h,
done:
return retval;
}
+
+/*! Get restconf http parameter
+ * @param[in] h Clicon handle
+ * @param[in] name Data name
+ * @retval val Data value as string
+ * Currently using clixon runtime data but there is risk for colliding names
+ */
+char *
+clixon_restconf_param_get(clicon_handle h,
+ char *param)
+{
+ char *val;
+ if (clicon_data_get(h, param, &val) < 0)
+ return NULL;
+ return val;
+}
+
+/*! Set restconf http parameter
+ * @param[in] h Clicon handle
+ * @param[in] name Data name
+ * @param[in] val Data value as null-terminated string
+ * @retval 0 OK
+ * @retval -1 Error
+ * Currently using clixon runtime data but there is risk for colliding names
+ */
+int
+clixon_restconf_param_set(clicon_handle h,
+ char *param,
+ char *val)
+{
+ return clicon_data_set(h, param, val);
+}
+
+int
+clixon_restconf_param_del(clicon_handle h,
+ char *param)
+{
+ return clicon_data_del(h, param);
+}
+
+/*! Extract uri-encoded uri-path from fastcgi parameters
+ * Use REQUEST_URI parameter and strip ?args
+ * REQUEST_URI have args and is encoded
+ * eg /interface=eth%2f0%2f0?insert=first
+ * DOCUMENT_URI dont have args and is not encoded
+ * eg /interface=eth/0/0
+ * causes problems with eg /interface=eth%2f0%2f0
+ */
+char *
+restconf_uripath(clicon_handle h)
+{
+ char *path;
+ char *q;
+
+ path = clixon_restconf_param_get(h, "REQUEST_URI");
+ if ((q = index(path, '?')) != NULL)
+ *q = '\0';
+ return path;
+}
diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h
index f1ac15e3..fa9f56bf 100644
--- a/apps/restconf/restconf_lib.h
+++ b/apps/restconf/restconf_lib.h
@@ -72,9 +72,14 @@ int restconf_err2code(char *tag);
const char *restconf_code2reason(int code);
const restconf_media restconf_media_str2int(char *media);
const char *restconf_media_int2str(restconf_media media);
-int get_user_cookie(char *cookiestr, char *attribute, char **val);
-int restconf_terminate(clicon_handle h);
-int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
-int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
+restconf_media restconf_content_type(clicon_handle h);
+int get_user_cookie(char *cookiestr, char *attribute, char **val);
+int restconf_terminate(clicon_handle h);
+int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
+int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
+char *clixon_restconf_param_get(clicon_handle h, char *param);
+int clixon_restconf_param_set(clicon_handle h, char *param, char *val);
+int clixon_restconf_param_del(clicon_handle h, char *param);
+char *restconf_uripath(clicon_handle h);
#endif /* _RESTCONF_LIB_H_ */
diff --git a/apps/restconf/restconf_libhttp_main.c b/apps/restconf/restconf_libhttp_main.c
deleted file mode 100644
index 74c214d4..00000000
--- a/apps/restconf/restconf_libhttp_main.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- *
- ***** BEGIN LICENSE BLOCK *****
-
- Copyright (C) 2009-2019 Olof Hagsand
- Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
-
- 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 *****
-
- */
-
-/* XXX temp constant should go away, */
-#undef _LIBHTTP_NYI
-
-#ifdef HAVE_CONFIG_H
-#include "clixon_config.h" /* generated by config & autoconf */
-#endif
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include /* chmod */
-
-/* libhttp */
-#include
-
-/* cligen */
-#include
-
-/* clicon */
-#include
-
-/* restconf */
-
-#include "restconf_lib.h"
-#if 0 /* These are all dependent on FCGX */
-#include "restconf_methods.h"
-#include "restconf_methods_get.h"
-#include "restconf_methods_post.h"
-#include "restconf_stream.h"
-#endif
-
-/* Command line options to be passed to getopt(3) */
-#define RESTCONF_OPTS "hD:f:l:p:d:y:a:u:o:P:"
-
-/* Need global variable to for signal handler XXX */
-static clicon_handle _CLICON_HANDLE = NULL;
-
-/*! Signall terminates process
- */
-static void
-restconf_sig_term(int arg)
-{
- static int i=0;
-
- if (i++ == 0)
- clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
- __PROGRAM__, __FUNCTION__, getpid(), arg);
- else
- exit(-1);
- if (_CLICON_HANDLE){
-#ifdef _LIBHTTP_NYI
- stream_child_freeall(_CLICON_HANDLE);
-#endif
- restconf_terminate(_CLICON_HANDLE);
- }
- clicon_exit_set(); /* checked in event_loop() */
- exit(-1);
-}
-
-static void
-restconf_sig_child(int arg)
-{
- int status;
- int pid;
-
- if ((pid = waitpid(-1, &status, 0)) != -1 && WIFEXITED(status))
-#ifdef _LIBHTTP_NYI
- stream_child_free(_CLICON_HANDLE, pid);
-#else
- ;
-#endif
-}
-
-/*! Usage help routine
- * @param[in] argv0 command line
- * @param[in] h Clicon handle
- */
-static void
-usage(clicon_handle h,
- char *argv0)
-
-{
- fprintf(stderr, "usage:%s [options]\n"
- "where options are\n"
- "\t-h \t\t Help\n"
- "\t-D \t Debug level\n"
- "\t-f \t Configuration file (mandatory)\n"
- "\t-l > \t Log on (s)yslog, (f)ile (syslog is default)\n"
- "\t-p \t Yang directory path (see CLICON_YANG_DIR)\n"
- "\t-d \t Specify restconf plugin directory dir (default: %s)\n"
- "\t-y \t Load yang spec file (override yang main module)\n"
- "\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
- "\t-u \t Internal socket domain path or IP addr (see -a)\n"
- "\t-o \"