#include <string.h>
#include <signal.h>
#include <sys/types.h>
+#include <ctype.h>
#include <sys/socket.h>
#include <netdb.h>
#include "client.h"
#include "log.h"
+/* XML */
+#include <libxml2/libxml/parser.h>
+#include <libxml2/libxml/tree.h>
+#include <libxml2/libxml/xpath.h>
+#include <libxml2/libxml/xpathInternals.h>
+
+void xml_init () {
+ /* check the version. This calls xmlInitParser() */
+ /* braces to stop indent getting confused */
+ {LIBXML_TEST_VERSION}
+}
+
+void xml_deinit () {
+ xmlCleanupParser ();
+}
+
+xmlNodePtr xml_get_node (xmlDoc * pDoc, const char *xpathexpr) {
+ xmlChar *xpath_expr = (xmlChar *) xpathexpr;
+ xmlXPathContextPtr xpathCtx = NULL;
+ xmlXPathObjectPtr xpathObj = NULL;
+ xmlNodeSetPtr nodeSet = NULL;
+ int size;
+ xmlNodePtr myNode = NULL;
+
+ /* Create xpath evaluation context */
+ if (NULL == (xpathCtx = xmlXPathNewContext (pDoc)))
+ return NULL;
+
+ /* Evaluate xpath expression */
+ if (NULL == (xpathObj = xmlXPathEvalExpression (xpath_expr, xpathCtx))) {
+ xmlXPathFreeContext (xpathCtx);
+ return NULL;
+ }
+
+ nodeSet = xpathObj->nodesetval;
+ size = (nodeSet) ? nodeSet->nodeNr : 0;
+ if (size == 1)
+ myNode = nodeSet->nodeTab[0];
+
+ xmlXPathFreeObject (xpathObj);
+ xmlXPathFreeContext (xpathCtx);
+ return myNode;
+}
+
+char * xml_get_string (xmlDoc * pDoc, char *xpathexpr) {
+ xmlNodePtr config_node = NULL;
+ xmlChar *propval = NULL;
+
+ /* Find the node in question beneath the config node */
+ if (NULL == (config_node = xml_get_node (pDoc, xpathexpr)))
+ return NULL;
+
+ /* Find the property attached to that node; if it's not there, return 0 */
+ if (NULL == (propval = xmlNodeGetContent (config_node)))
+ return NULL;
+
+ /* We would like to just return propval here, but that's an xmlChar * allocated by
+ * libxml, and thus the caller can't just free() it - it would need to be xmlFree()'d.
+ * so we'll fiddle around and generate our own copy allocated with libc
+ */
+ char *value = strdup ((char *) propval);
+ xmlFree (propval); /* as xmlGetProp makes a copy of the string */
+ return value; /* caller's responsibility to free() this */
+}
+
void guacd_handle_connection(int fd) {
guac_client* client;
}
+void guacd_handle_connection_xml(int fd, char* xmlconfig) {
+
+ guac_client* client = NULL;
+ guac_client_plugin* plugin = NULL;
+ char ** protocol_argv = NULL;
+ int protocol_argc = 0;
+ xmlDoc * pDoc = NULL;
+ char * protocol = NULL;
+ guac_socket* socket = NULL;
+
+ if (NULL == (socket = guac_socket_open(fd))) {
+ guacd_log_guac_error("Could not open socket");
+ goto error;
+ }
+
+ if (NULL == (pDoc = xmlParseMemory (xmlconfig, strlen(xmlconfig)))) {
+ guacd_log_guac_error("Could not parse XML");
+ goto error;
+ }
+
+ if (NULL == (protocol = xml_get_string(pDoc, "/params/protocol"))) {
+ guacd_log_guac_error("Could not parse XML");
+ goto error;
+ }
+
+ guacd_log_info("Opening protocol '%s'", protocol);
+
+ /* Get plugin from protocol in select */
+ if (NULL == (plugin = guac_client_plugin_open(protocol))) {
+ guacd_log_guac_error("Error loading client plugin");
+ goto error;
+ }
+
+ /* Now parse protocol strings */
+ const char ** arg;
+ const char * params = "/params/";
+ int lparams = strlen(params);
+ for (arg = plugin->args; *arg && **arg; arg++)
+ protocol_argc++;
+ if (NULL == (protocol_argv = calloc(sizeof(char *), protocol_argc+1))) {
+ guacd_log_guac_error("Cannot allocate protocol arguments");
+ goto error;
+ }
+
+ int i;
+ for (i=0; i<protocol_argc; i++) {
+ const char * p;
+ char * q;
+ int l = strlen(plugin->args[i]);
+ char * argname = malloc(lparams+l+1);
+ if (!argname) {
+ guacd_log_guac_error("Error duplicating argument list");
+ goto error;
+ }
+ strncpy(argname, params, lparams);
+ /* replace non-alpha characters by '_' for XML */
+ for (p = plugin->args[i], q = argname+lparams; *p; p++, q++)
+ *q = isalnum(*p)?*p:'_';
+ *q='\0';
+ char * value = xml_get_string(pDoc, argname);
+ if (!value)
+ value = strdup("");
+ guacd_log_info("Argument '%s' set to '%s'", plugin->args[i], value);
+ protocol_argv[i]=value;
+ }
+
+ guacd_log_info("Starting protocol %s, %d arguments", protocol, protocol_argc);
+
+ /* Load and init client */
+ if (NULL == (client = guac_client_plugin_get_client(plugin, socket,
+ protocol_argc, protocol_argv,
+ guacd_client_log_info, guacd_client_log_error))) {
+ guacd_log_guac_error("Error instantiating client");
+ goto error;
+ }
+
+ /* Start client threads */
+ guacd_log_info("Starting client");
+ if (guacd_client_start(client))
+ guacd_log_error("Client finished abnormally");
+ else
+ guacd_log_info("Client finished normally");
+
+ error:
+ /* Clean up */
+ if (client)
+ guac_client_free(client);
+
+ if (plugin && guac_client_plugin_close(plugin))
+ guacd_log_error("Error closing client plugin");
+
+ if (protocol_argv) {
+ char **parg;
+ for (parg = protocol_argv ; *parg; parg++)
+ free(*parg);
+ free(protocol_argv);
+ }
+ if (pDoc)
+ xmlFreeDoc(pDoc);
+ if (protocol)
+ free (protocol);
+ if (socket)
+ guac_socket_close(socket);
+
+ return;
+}
+
int main(int argc, char* argv[]) {
/* Server */
char* pidfile = NULL;
int opt;
int foreground = 0;
+ char * xmlconfig = NULL;
/* General */
int retval;
/* Daemon Process */
pid_t daemon_pid;
+ xml_init();
+
/* Parse arguments */
- while ((opt = getopt(argc, argv, "l:b:p:f")) != -1) {
+ while ((opt = getopt(argc, argv, "l:b:p:x:f")) != -1) {
if (opt == 'l') {
listen_port = strdup(optarg);
}
listen_address = strdup(optarg);
}
else if (opt == 'f') {
- foreground = 1;
+ foreground++;
}
else if (opt == 'p') {
pidfile = strdup(optarg);
}
+ else if (opt == 'x') {
+ xmlconfig = strdup (optarg);
+ }
else {
fprintf(stderr, "USAGE: %s"
" [-l LISTENPORT]"
" [-b LISTENADDRESS]"
" [-p PIDFILE]"
- " [-f]\n", argv[0]);
+ " [-f]"
+ " [-x XMLCONFIG]\n", argv[0]);
exit(EXIT_FAILURE);
}
* particular client plugin.
*/
- child_pid = fork();
+ child_pid = (foreground>1)?0:fork();
/* If error, log */
if (child_pid == -1)
/* If child, start client, and exit when finished */
else if (child_pid == 0) {
- guacd_handle_connection(connected_socket_fd);
+ if (xmlconfig)
+ guacd_handle_connection_xml(connected_socket_fd, xmlconfig);
+ else
+ guacd_handle_connection(connected_socket_fd);
close(connected_socket_fd);
return 0;
}
return 3;
}
+ xml_deinit();
return 0;
}