summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/etc/pracrod.conf3
-rw-r--r--server/src/Makefile.am2
-rw-r--r--server/src/artefact.cc97
-rw-r--r--server/src/debug.cc2
-rw-r--r--server/src/entitylist.cc8
-rw-r--r--server/src/inotify.cc9
-rw-r--r--server/src/luaresume.cc34
-rw-r--r--server/src/luautil.cc312
-rw-r--r--server/src/luautil.h81
-rw-r--r--server/src/macrolist.cc5
-rw-r--r--server/src/saxparser.cc25
-rw-r--r--server/src/server.cc200
-rw-r--r--server/src/session.cc13
-rw-r--r--server/src/session.h8
-rw-r--r--server/src/templatelist.cc5
-rw-r--r--server/src/transactionhandler.cc27
-rw-r--r--server/src/transactionparser.cc73
17 files changed, 728 insertions, 176 deletions
diff --git a/server/etc/pracrod.conf b/server/etc/pracrod.conf
index 6d97619..5fb7494 100644
--- a/server/etc/pracrod.conf
+++ b/server/etc/pracrod.conf
@@ -2,3 +2,6 @@ port = 12345;
journal_commit_addr = "localhost";
journal_commit_port = 18112;
+
+artefact_addr = "localhost";
+artefact_port = 11108;
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index 1ff8a3a..afc72f9 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -27,6 +27,7 @@ pracrod_SOURCES = \
log.cc \
luaquerymapper.cc \
luaresume.cc \
+ luautil.cc \
macroheaderparser.cc \
macrolist.cc \
macroparser.cc \
@@ -102,6 +103,7 @@ EXTRA_DIST = \
log.h \
luaquerymapper.h \
luaresume.h \
+ luautil.h \
macroheaderparser.h \
macrolist.h \
macroparser.h \
diff --git a/server/src/artefact.cc b/server/src/artefact.cc
index cc29b77..24114f9 100644
--- a/server/src/artefact.cc
+++ b/server/src/artefact.cc
@@ -35,7 +35,7 @@
Artefact::Artefact()
{
#ifndef WITHOUT_PENTOMINOS
- PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d",
+ PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d\n",
Conf::artefact_addr.c_str(), Conf::artefact_port);
#endif/*WITHOUT_PENTOMINOS*/
@@ -54,47 +54,88 @@ Artefact::~Artefact()
atf_close(atfh);
}
+static QueryResult node2result(atf_result_node_t *node, time_t timestamp)
+{
+ QueryResult rnode;
+ rnode.timestamp = timestamp;
+ rnode.source = "pentominos";
+
+ if(!node) return rnode;
+
+ struct _atf_result_node_t *child = node->child;
+ while(child) {
+ if(child->value == NULL) {
+ rnode.groups[child->name] = node2result(child, timestamp);
+ } else {
+ rnode.values[child->name] = child->value;
+ }
+ child = child->next;
+ }
+
+ return rnode;
+}
+
QueryResult Artefact::exec(Query &query,
std::string patientid,
std::string user)
{
- QueryParser parser;
+ atf_transaction_t* atft = NULL;
+ atf_reply_t *reply = NULL;
+ atf_result_t *result = NULL;
+ atf_result_node_t *root = NULL;
+ atf_status_t status;
+ time_t timestamp;
+ atf_id id;
+
+ QueryResult rroot;
+ rroot.timestamp = 0;
+ rroot.source = "pentominos";
+
+ if(query.attributes.find("class") == query.attributes.end()) {
+ PRACRO_ERR(artefact, "Missing 'class' attribute!\n");
+ goto aaarg;
+ }
- atf_transaction_t *trans = atf_new_transaction(conn, patientid.c_str());
- atf_querylist_t *qlist = atf_new_querylist(trans, user.c_str());
+ atft = atf_new_transaction(conn, patientid.c_str());
+ if(!atft) goto aaarg;
- atf_id id = atf_add_query(qlist,
- query.attributes["class"].c_str(),
- 0/*oldest*/, "xml"/*replyformat*/);
+ id = atf_add_query(atft, query.attributes["class"].c_str(),
+ FILTER_LATEST, USE_NONE, 0, 0);
+ if(!atft) goto aaarg;
- atf_reply_t *reply = atf_commit(trans, NULL, qlist);
+ reply = atf_commit(atft);
+ if(!reply) goto aaarg;
- atf_status_t status = atf_get_reply_status(reply, id);
+ if(atf_get_num_results(reply, id) != 1) goto aaarg;
- switch(status) {
- case ATF_STATUS_OK:
- {
- size_t bufsize = atf_get_reply_size(reply, id);
- char *buf = new char[bufsize];
-
- ssize_t size = atf_get_reply_data(reply, id, buf, size);
- parser.parse(buf, size);
-
- delete[] buf;
- }
- break;
+ result = atf_get_result(reply, id, 0);
+ if(!result) goto aaarg;
+
+ status = atf_get_result_status(result, NULL, 0);
+ if(status != ATF_STATUS_OK) goto aaarg;
+
+ timestamp = atf_get_result_timestamp(result);
+ rroot.timestamp = timestamp;
- case ATF_STATUS_ERROR:
- PRACRO_ERR(artefact, "Error in artefact query.\n");
- break;
+ root = atf_get_result_node(result);
+ if(!root) goto aaarg;
+
+ {
+ QueryResult qresult = node2result(root, timestamp);
+ rroot.groups[query.attributes["class"]] = qresult;
}
- atf_free_reply(reply);
+ goto cleanup;
+
+ aaarg:
+ PRACRO_ERR(artefact, "Artefact comm error (%d)!\n", atf_get_last_error(atfh));
- atf_free_querylist(qlist);
- atf_free_transaction(trans);
+ cleanup:
+ if(root) atf_free_result_node(root);
+ if(reply) atf_free_reply(reply);
+ if(atft) atf_free_transaction(atft);
- return parser.result;
+ return rroot;
}
diff --git a/server/src/debug.cc b/server/src/debug.cc
index 54a2191..8bb45db 100644
--- a/server/src/debug.cc
+++ b/server/src/debug.cc
@@ -37,7 +37,7 @@
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
struct __pracro_debug_channel
{
- char name[16];
+ char name[64];
unsigned flags;
};
diff --git a/server/src/entitylist.cc b/server/src/entitylist.cc
index 04533c0..3ec15a5 100644
--- a/server/src/entitylist.cc
+++ b/server/src/entitylist.cc
@@ -197,11 +197,15 @@ std::string EntityList::getLatestVersion(std::string entity) throw(Exception)
updateList();
- if(find(entity) == end())
+ if(find(entity) == end()) {
throw Exception("Entity ("+entityname+") ["+entity+"] does not exist");
+ }
+
EntityListItem mli = (*this)[entity];
- if(mli.size() == 0)
+ if(mli.size() == 0) {
throw Exception("Entity ("+entityname+") ["+entity+"] does not exist.");
+ }
+
PRACRO_DEBUG(entitylist, "Search for %s - found %s v%s\n",
entity.c_str(),
mli.begin()->second.c_str(),
diff --git a/server/src/inotify.cc b/server/src/inotify.cc
index 5fb983e..1515387 100644
--- a/server/src/inotify.cc
+++ b/server/src/inotify.cc
@@ -264,10 +264,12 @@ void INotify::addDirectory(std::string name, depth_t depth, uint32_t mask)
struct dirent *dirent;
while( (dirent = readdir(dir)) != NULL ) {
- if(std::string(dirent->d_name) == "." || std::string(dirent->d_name) == "..")
+ if(std::string(dirent->d_name) == "." ||
+ std::string(dirent->d_name) == "..")
continue;
- if(isdir(name+"/"+dirent->d_name)) addDirectory(name+"/"+dirent->d_name, depth, mask);
+ if(isdir(name+"/"+dirent->d_name))
+ addDirectory(name+"/"+dirent->d_name, depth, mask);
}
closedir(dir);
@@ -348,7 +350,8 @@ void INotify::readEvents()
addDirectory(dirmap[event->wd].name + "/" + event->name,
dirmap[event->wd].depth, dirmap[event->wd].mask);
- if(TEST(event->mask, IN_CREATE) && !TEST(dirmap[event->wd].mask, IN_CREATE)) {
+ if(TEST(event->mask, IN_CREATE) &&
+ !TEST(dirmap[event->wd].mask, IN_CREATE)) {
// Ignore this event, it was not requested by the user.
} else {
eventlist.push_back(INotify::Event(event, dirmap[event->wd].name));
diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc
index 8ba5641..099c3bd 100644
--- a/server/src/luaresume.cc
+++ b/server/src/luaresume.cc
@@ -26,6 +26,8 @@
*/
#include "luaresume.h"
+#include "luautil.h"
+
#include "debug.h"
#include <stdio.h>
@@ -34,14 +36,9 @@
static int _getValue(lua_State *L)
{
- int n = lua_gettop(L); // number of arguments
- if(n != 1) {
- char errstr[512];
- sprintf(errstr, "Number of args expected 0, got %d", n);
- lua_pushstring(L, errstr);
- lua_error(L);
- return 1;
- }
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
std::string name = lua_tostring(L, lua_gettop(L));
@@ -65,7 +62,7 @@ LUAResume::LUAResume(Commit &c)
{
L = luaL_newstate();
if(L == NULL) {
- error("Could not create LUA state.");
+ PRACRO_ERR(luaresume, "Could not create LUA state.\n");
return;
}
@@ -85,7 +82,7 @@ LUAResume::~LUAResume()
std::string LUAResume::getValue(std::string name)
{
if(commit.fields.find(name) == commit.fields.end()) {
- error("LUAResume: No such field '" + name + "'");
+ PRACRO_ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str());
return "";
}
@@ -95,11 +92,11 @@ std::string LUAResume::getValue(std::string name)
std::string LUAResume::run(std::string program)
{
if(L == NULL) {
- error("LUA state not initialized!");
+ PRACRO_ERR(luaresume, "LUA state not initialized!");
return false;
}
- PRACRO_DEBUG(lua, "Running %s\n", program.c_str());
+ PRACRO_DEBUG(luaresume, "Running %s\n", program.c_str());
/*
lua_pushstring(L, value.toStdString().c_str());
@@ -111,24 +108,25 @@ std::string LUAResume::run(std::string program)
int top = lua_gettop(L);
- if(luaL_loadbuffer(L, program.c_str(), program.size(), "lua resume generator")) {
- error(lua_tostring(L, lua_gettop(L)));
+ if(luaL_loadbuffer(L, program.c_str(), program.size(),
+ "lua resume generator")) {
+ PRACRO_ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L)));
return false;
}
// Run the loaded code
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
- error(lua_tostring(L, lua_gettop(L)));
+ PRACRO_ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));
return false;
}
if(top != lua_gettop(L) - 1) {
- error("Program did not return a single value.\n");
+ PRACRO_ERR(luaresume, "Program did not return a single value.\n");
return false;
}
if(lua_isstring(L, lua_gettop(L)) == false) {
- error("Program did not return a string value.\n");
+ PRACRO_ERR(luaresume, "Program did not return a string value.\n");
return false;
}
@@ -140,5 +138,5 @@ std::string LUAResume::run(std::string program)
void LUAResume::error(std::string message)
{
- printf("LUA ERROR: %s\n", message.c_str());
+ PRACRO_ERR(luaresume, "LUA ERROR: %s\n", message.c_str());
}
diff --git a/server/src/luautil.cc b/server/src/luautil.cc
new file mode 100644
index 0000000..116d219
--- /dev/null
+++ b/server/src/luautil.cc
@@ -0,0 +1,312 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * luautil.cc
+ *
+ * Fri Apr 13 14:38:53 CEST 2007
+ * Copyright 2007 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "luautil.h"
+
+#include "debug.h"
+
+#include <string>
+
+#include <vector>
+
+std::vector< void * > pointers;
+
+// for ntohl and htonl
+#include <arpa/inet.h>
+
+#define GLOBAL_PREFIX "magic_global_"
+
+//
+// Get the (somewhat hacky) global pointer to the parser object.
+// It is set in the preload method.
+//
+void *Pracro::getGlobal(lua_State *L, std::string name)
+{
+ unsigned int top;
+ unsigned int index;
+
+ std::string var = std::string(GLOBAL_PREFIX) + name;
+
+ lua_getfield(L, LUA_GLOBALSINDEX, var.c_str());
+ top = lua_gettop(L);
+ index = lua_tointeger(L, top);
+
+ return pointers.at(index);
+}
+
+void Pracro::setGlobal(lua_State *L, std::string name, void *p)
+{
+ // Put the value of this in the globals
+ char value_of_this[256];
+
+ std::string val = std::string(GLOBAL_PREFIX) + name;
+
+ /*
+ unsigned int parser = (unsigned int)p;
+ parser = htonl(parser);
+ */
+
+ pointers.push_back(p);
+ unsigned int index = pointers.size() - 1;
+
+ sprintf(value_of_this, "%s = %u\n", val.c_str(), index);
+ int s = luaL_loadstring(L, value_of_this);
+ switch(s) {
+ case 0: //no errors;
+ break;
+ case LUA_ERRSYNTAX: //syntax error during pre-compilation;
+ case LUA_ERRMEM: //memory allocation error.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ default:
+ fprintf(stderr, "Unknown return value of luaL_loadstring.\n");
+ }
+
+ // Run program (init)
+ s = lua_pcall(L, 0, LUA_MULTRET, 0);
+ // Check for errors
+ switch(s) {
+ case 0: // Success
+ break;
+ case LUA_ERRRUN:// a runtime error.
+ case LUA_ERRMEM:// memory allocation error.
+ // For such errors, Lua does not call the error handler function.
+ case LUA_ERRERR:// error while running the error handler function.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown return value of lua_pcall.\n");
+ break;
+ }
+}
+
+void Pracro::call(lua_State *L, std::string function, int numargs)
+{
+ // Get function
+ lua_getglobal(L, function.c_str());
+
+ // Call it
+ int s = lua_pcall(L, numargs, LUA_MULTRET, 0);
+
+ // Check for errors
+ switch(s) {
+ case 0: // Success
+ break;
+ case LUA_ERRRUN:// a runtime error.
+ case LUA_ERRMEM:// memory allocation error.
+ // For such errors, Lua does not call the error handler function.
+ case LUA_ERRERR:// error while running the error handler function.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown return value of lua_pcall.\n");
+ break;
+ }
+}
+
+
+/*
+lua_isboolean
+lua_iscfunction
+lua_isfunction
+lua_islightuserdata
+lua_isnil
+lua_isnone
+lua_isnoneornil
+lua_isnumber
+lua_isstring
+lua_istable
+lua_isthread
+lua_isuserdata
+*/
+int Pracro::checkParameters(lua_State *L, ...)
+{
+ va_list ap;
+ va_start(ap, L);
+
+ size_t nargs = lua_gettop(L); // number of arguments
+
+ size_t size = 0;
+ int t;
+ while(1) {
+ t = va_arg(ap, int);
+ if(t == T_END) break;
+
+ switch(t) {
+ case T_STRING:
+ case T_NUMBER:
+ case T_BOOLEAN:
+ break;
+
+ default:
+ return luaL_error(L,"Unknown type specifier [%d] at position %d. "
+ "Missing TYPE_END?", t, size+1);
+ }
+
+ size++;
+ }
+
+ va_end(ap);
+
+ if(nargs != size) {
+ return luaL_error(L, "Number of args expected %d, got %d", size, nargs);
+ }
+
+ va_start(ap, L);
+
+ size_t idx = 0;
+ while(1) {
+ t = va_arg(ap, int);
+ if(t == T_END) break;
+
+ switch(t) {
+ case T_STRING:
+ if(lua_isstring(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type string.", idx+1);
+ }
+ break;
+
+ case T_NUMBER:
+ if(lua_isnumber(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type number.", idx+1);
+ }
+ break;
+
+ case T_BOOLEAN:
+ if(lua_isboolean(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type boolean.", idx+1);
+ }
+ break;
+
+ default:
+ va_end(ap);
+ return luaL_error(L,"Unknown type specifier [%d] at position %d. "
+ "Missing TYPE_END?", t, idx+1);
+ }
+
+ idx++;
+ }
+
+ va_end(ap);
+
+ return 0;
+}
+
+#ifdef TEST_LUAUTIL
+//deps:
+//cflags: $(LUA_CFLAGS) -I..
+//libs: $(LUA_LIBS)
+#include "test.h"
+
+#define LUAPROG \
+ "testfunc('a string', 42, true)"
+
+#define LUAPROG_BAD1 \
+ "testfunc('a string', 42)"
+
+#define LUAPROG_BAD2 \
+ "testfunc('a string', 42, true, 'another one')"
+
+#define LUAPROG_BAD3 \
+ "testfunc(false, 42, 'string')"
+
+#define LUAPROG_MISSING_END \
+ "testfunc_bad('a string', 42, true, 1)"
+
+static int testfunc(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_NUMBER,
+ Pracro::T_BOOLEAN,
+ Pracro::T_END);
+ return 0;
+}
+
+static int testfunc_bad(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_NUMBER,
+ Pracro::T_BOOLEAN,
+ Pracro::T_NUMBER);
+ return 0;
+}
+
+
+TEST_BEGIN;
+
+int a, b, c;
+
+lua_State *L;
+L = luaL_newstate();
+if(L == NULL) TEST_FATAL("Could not allocate lua state.");
+luaL_openlibs(L);
+
+Pracro::setGlobal(L, "a", &a);
+Pracro::setGlobal(L, "b", &b);
+Pracro::setGlobal(L, "c", &c);
+
+TEST_EQUAL(Pracro::getGlobal(L, "b"), &b, "Test get global");
+TEST_EQUAL(Pracro::getGlobal(L, "c"), &c, "Test get global");
+TEST_EQUAL(Pracro::getGlobal(L, "a"), &a, "Test get global");
+
+lua_register(L, "testfunc", testfunc);
+
+if(luaL_loadstring(L, LUAPROG)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_EQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Good one");
+
+if(luaL_loadstring(L, LUAPROG_BAD1)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too short one");
+
+if(luaL_loadstring(L, LUAPROG_BAD2)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too long one");
+
+if(luaL_loadstring(L, LUAPROG_BAD3)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Plain wrong");
+
+
+lua_register(L, "testfunc_bad", testfunc_bad);
+if(luaL_loadstring(L, LUAPROG_MISSING_END)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Missing T_END");
+
+lua_close(L);
+
+TEST_END;
+
+#endif/*TEST_LUAUTIL*/
diff --git a/server/src/luautil.h b/server/src/luautil.h
new file mode 100644
index 0000000..ebbba45
--- /dev/null
+++ b/server/src/luautil.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * luautil.h
+ *
+ * Fri Apr 13 14:38:53 CEST 2007
+ * Copyright 2007 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_LUAUTIL_H__
+#define __PRACRO_LUAUTIL_H__
+
+#include <lua.hpp>
+#include <lauxlib.h>
+
+#include <string>
+
+namespace Pracro {
+
+ /**
+ * Set a global pointer that can be reaced from the cFunctions at a later time,
+ * using the getGlobal function.
+ * @param L The lua_State (active program) from which to get the pointer.
+ * @param name The symbolic name in which to store the pointer.
+ * @param p The pointer to set.
+ */
+ void setGlobal(lua_State *L, std::string name, void *p);
+
+ /**
+ * Get a global pointer set by the setGlobal function.
+ * @param L The lua_State (active program) in which to set the pointer.
+ * @param name The symbolic name in which the pointer is stored.
+ * @return The pointer.
+ */
+ void *getGlobal(lua_State *L, std::string name);
+
+ /**
+ * Call a function in a lua program.
+ * @param L The lua_State (active program) in which to set the function resides.
+ * @param function The name of the function to be called.
+ */
+ void call(lua_State *L, std::string function, int numargs = 0);
+
+ typedef enum {
+ T_STRING,
+ T_NUMBER,
+ T_BOOLEAN,
+ T_END
+ } types_t;
+
+ /**
+ * Check parameter types and number.
+ * @param L The lua_State (active program) in which to set the function resides.
+ * @param types The type list (c-vector), describing the required types
+ * on the stack. The last type must be a terminating T_END.
+ * @return 0 on success. On error a long jump is made through lua_error, thus
+ * the function never returns.
+ */
+ // int checkParameters(lua_State *L, types_t types[]);
+ int checkParameters(lua_State *L, ...);
+
+};
+
+#endif/*__PRACRO_LUAUTIL_H__*/
diff --git a/server/src/macrolist.cc b/server/src/macrolist.cc
index 954149a..908de1e 100644
--- a/server/src/macrolist.cc
+++ b/server/src/macrolist.cc
@@ -42,6 +42,11 @@ MacroList::MacroList(std::string path)
void MacroList::addFile(std::string file)
{
+ if(file.substr(file.size() - 4) != ".xml") {
+ PRACRO_DEBUG(macrolist, "Skipping file: %s\n", file.c_str());
+ return;
+ }
+
PRACRO_DEBUG(macrolist, "Adding file: %s\n", file.c_str());
MacroHeaderParser parser(file);
try {
diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc
index fcdf4fa..f26c965 100644
--- a/server/src/saxparser.cc
+++ b/server/src/saxparser.cc
@@ -103,7 +103,8 @@ int SAXParser::parse()
do {
len = readData(buf, sizeof(buf) - 1);
if (! XML_Parse(p, buf, len, len == 0)) {
- parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return 1;
}
@@ -123,35 +124,43 @@ static bool iswhitespace(const char *buf, size_t size)
bool SAXParser::parse(const char *data, size_t size)
{
- PRACRO_DEBUG(sax, "parse %d bytes\n", size);
+ std::string xml;
+ xml.append(data, size);
+ PRACRO_DEBUG(sax, "parse %d bytes [%s]\n", size, xml.c_str());
bufferbytes = size;
totalbytes += bufferbytes;
if(! XML_Parse(p, data, size, false) ) {
if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true;
- if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true;
+ if(XML_GetErrorCode(p) == XML_ERROR_FINISHED &&
+ iswhitespace(data, size)) return true;
if(done && XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true;
- parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return false;
}
if(done) {
if(! XML_Parse(p, data, 0, true) ) {
if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true;
- if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true;
+ if(XML_GetErrorCode(p) == XML_ERROR_FINISHED &&
+ iswhitespace(data, size)) return true;
if(XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true;
- parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return false;
}
}
- if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", outertag.c_str(), XML_GetCurrentByteIndex(p));
+ if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n",
+ outertag.c_str(), XML_GetCurrentByteIndex(p));
return done;
}
-void SAXParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+void SAXParser::parseError(const char *buf, size_t len,
+ std::string error, int lineno)
{
fprintf(stderr, "SAXParser error at line %d: %s\n", lineno, error.c_str());
fprintf(stderr, "\tBuffer %u bytes: [", len);
diff --git a/server/src/server.cc b/server/src/server.cc
index 84c3463..4283a11 100644
--- a/server/src/server.cc
+++ b/server/src/server.cc
@@ -61,18 +61,18 @@ static std::string error_box(std::string message)
return errorbox;
}
-static std::string handleConnection(const char *buf, size_t size,
+static std::string handleConnection(const std::string &data,
Environment &env,
- char **sessionid,
- const char *sessioncommit)
+ std::string &sessionid,
+ bool sessioncommit)
{
std::string res;
Session *session = NULL;
- if(*sessionid == NULL) {
+ if(sessionid == "") {
session = env.sessions.newSession();
} else {
- session = env.sessions.session(*sessionid);
+ session = env.sessions.session(sessionid);
if(session == NULL) session = env.sessions.newSession();
}
@@ -81,51 +81,44 @@ static std::string handleConnection(const char *buf, size_t size,
return error_box(xml_encode("New session could not be created."));
}
- session->lock();
+ sessionid = session->id();
- if(asprintf(sessionid, "%s", session->id().c_str()) == -1) *sessionid = NULL;
+ {
+ SessionAutolock lock(*session);
- Transaction transaction;
- TransactionParser parser(&transaction);
+ if(data.length()) {
+ Transaction transaction;
+ TransactionParser parser(&transaction);
+
+ if(!parser.parse(data.c_str(), data.length())) {
+ PRACRO_ERR(server, "Failed to parse data!\n");
+ PRACRO_ERR(server, "DATA:[[%s]]\n", data.c_str());
+ res = error_box(xml_encode("XML Parse error."));
+ } else {
+ res = handleTransaction(transaction, env, *session);
+ }
+ }
- if(!parser.parse(buf, size)) {
- PRACRO_ERR(server, "Failed to parse data!\n");
- res = error_box(xml_encode("XML Parse error."));
- } else {
- res = handleTransaction(transaction, env, *session);
}
- session->unlock();
-
- if(sessioncommit != NULL) {
+ if(sessioncommit) {
session->commit();
env.sessions.deleteSession(session->id());
}
return res;
+}
- /*
- Transaction transaction;
- TransactionParser parser(&transaction);
-
- PRACRO_DEBUG(server, "Read %d bytes from network\n", size);
-
- std::string res;
- if(size) {
- if(parser.parse(buf, size)) {
- PRACRO_DEBUG(server, "Got complete XML document, %d bytes in current buffer.\n", size);
-
- res = handleTransaction(&transaction, pentominos_socket,
- *conn->db, session, macrolist, templatelist);
- } else {
- PRACRO_ERR(server, "Failed to parse data!\n");
- res = error_box(xml_encode("XML Parse error."));
- }
- }
- return res;
+struct condata {
+ std::map<std::string, std::string> headers;
+ std::string data;
+ size_t data_size;
+ std::string url;
+ std::string method;
+ std::string version;
+};
- */
-}
+//static std::map<struct MHD_Connection *, struct condata> condata;
static int handle_request_callback(void *cls,
struct MHD_Connection *con,
@@ -134,40 +127,116 @@ static int handle_request_callback(void *cls,
const char *version,
const char *data,
unsigned int *data_size,
- void **ptr)
+ void **con_cls)
{
- Environment *env = (Environment *)cls;
+ PRACRO_DEBUG(httpd, "handle_request_callback con:%p condata:%p\n",
+ con, *con_cls);
+
+ // Test for new connection
+ if(*con_cls == NULL) {
+ PRACRO_DEBUG(httpd,
+ "handle_request(url=\"%s\", method=\"%s\","
+ " version=\"%s\", data_size=\"%d\")\n",
+ url, method, version, *data_size);
+
+ struct condata *cd = new struct condata;
+ cd->url = url;
+ cd->method = method;
+ cd->version = version;
+ cd->data_size = 0;
+ cd->data = "";
+
+ const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionID");
+ if(sid) cd->headers["SessionID"] = sid;
+
+ const char *scm = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionCommit");
+ if(scm) cd->headers["SessionCommit"] = scm;
+
+ const char *csz = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "Content-Length");
+ if(csz) {
+ cd->headers["Content-Length"] = csz;
+ cd->data_size = atol(csz);
+ PRACRO_DEBUG(httpd, "Content-Length: %s (%d)\n", csz, cd->data_size);
+ }
- PRACRO_DEBUG(httpd,
- "handle_request(url=\"%s\", method=\"%s\","
- " version=\"%s\", data_size=\"%d\")\n",
- url, method, version, *data_size);
+ *con_cls = cd;
+ }
- const char *sessionid =
- MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionID");
- const char *sessioncommit =
- MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit");
+ struct condata *cd = (struct condata*)*con_cls;
+ cd->data.append(data, *data_size);
- std::string reply =
- handleConnection(data, *data_size, *env, (char**)&sessionid, sessioncommit);
-
- struct MHD_Response *rsp =
- MHD_create_response_from_data(reply.length(), (char*)reply.c_str(), MHD_NO, MHD_YES);
- MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain; charset=UTF-8");
+ int ret = MHD_YES;
- if(*sessionid) {
- MHD_add_response_header(rsp, "SessionID", sessionid);
- free((char*)sessionid);
- }
+ PRACRO_DEBUG(httpd, "Waiting for %d bytes of data. Got %d (total %d)\n",
+ cd->data_size, *data_size, cd->data.length());
+
+ if(cd->data.length() >= cd->data_size) {
+
+ Environment *env = (Environment *)cls;
+
+ const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionID");
+ std::string sessionid;
+ if(sid) sessionid = sid;
+
+ const char *sessioncommit =
+ MHD_lookup_connection_value(con, MHD_HEADER_KIND, "SessionCommit");
+
+ PRACRO_DEBUG(httpd, "Starting to handle SessionID: %s%s\n",
+ sessionid.c_str(),
+ sessioncommit != NULL?" COMMIT":"");
+
+ PRACRO_DEBUG(httpd, "Data: [%s]\n", cd->data.c_str());
+
+ std::string reply =
+ handleConnection(cd->data, *env, sessionid, sessioncommit != NULL);
+
+ struct MHD_Response *rsp =
+ MHD_create_response_from_data(reply.length(), (char*)reply.c_str(),
+ MHD_NO, MHD_YES);
+ MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/plain; charset=UTF-8");
+
+ if(sessionid != "") {
+ MHD_add_response_header(rsp, "SessionID", sessionid.c_str());
+ }
+
+ ret = MHD_queue_response(con, MHD_HTTP_OK, rsp);
+ MHD_destroy_response(rsp);
+
+ PRACRO_DEBUG(httpd, "Finished handling SessionID: %s%s\n",
+ sessionid.c_str(),
+ sessioncommit != NULL?" COMMIT":"");
- int ret = MHD_queue_response(con, MHD_HTTP_OK, rsp);
- MHD_destroy_response(rsp);
+
+ delete cd;
+ *con_cls = NULL;
+
+ }
*data_size = 0;
return ret;
}
+void requestCompletedCallback(void *cls,
+ struct MHD_Connection *con,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ PRACRO_DEBUG(httpd, "requestCompletedCallback %p\n", con);
+
+ // If connection was interrupted prematurely delete the content data here.
+ if(*con_cls) {
+ struct condata *cd = (struct condata*)*con_cls;
+ delete cd;
+ *con_cls = NULL;
+ }
+}
+
static void httpderr(void *arg, const char *fmt, va_list ap)
{
PRACRO_ERR_VA(server, fmt, ap);
@@ -181,7 +250,8 @@ void server()
bool forceshutdown = false;
port_t port = Conf::server_port;
- int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY; // | MHD_USE_PEDANTIC_CHECKS
+ int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY;
+ // | MHD_USE_PEDANTIC_CHECKS
#ifndef WITHOUT_SSL
if(Conf::use_ssl) flags |= MHD_USE_SSL;
#endif
@@ -193,7 +263,8 @@ void server()
struct MHD_Daemon *d;
d = MHD_start_daemon(flags, port, NULL, NULL,
handle_request_callback, &env,
- MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ requestCompletedCallback, NULL,
MHD_OPTION_CONNECTION_LIMIT, Conf::connection_limit,
#ifndef WITHOUT_SSL
MHD_OPTION_HTTPS_MEM_KEY, Conf::ssl_key.c_str(),
@@ -246,10 +317,11 @@ char request[] =
int main()
{
Conf::xml_basedir = "../xml/";
- Conf::server_port = 32100; // Make sure wo don't interrupt an already running server.
+ // Make sure wo don't interrupt an already running server.
+ Conf::server_port = 32100;
Conf::database_backend = "testdb";
pid_t pid = fork();
-
+
switch(pid) {
case -1: // error
perror("fork() failed!\n");
diff --git a/server/src/session.cc b/server/src/session.cc
index 675bf56..74adb32 100644
--- a/server/src/session.cc
+++ b/server/src/session.cc
@@ -66,7 +66,7 @@ void Session::commit()
JournalWriter *Session::journal()
{
if(_journal == NULL) {
- _journal =
+ _journal =
new JournalWriter(Conf::journal_commit_addr, Conf::journal_commit_port);
}
return _journal;
@@ -114,6 +114,17 @@ size_t Sessions::size()
return sessions.size();
}
+SessionAutolock::SessionAutolock(Session &s)
+ : session(s)
+{
+ session.lock();
+}
+
+SessionAutolock::~SessionAutolock()
+{
+ session.unlock();
+}
+
#ifdef TEST_SESSION
//deps: configuration.cc journalwriter.cc journal_commit.cc mutex.cc debug.cc
//cflags: -I.. $(PTHREAD_CFLAGS)
diff --git a/server/src/session.h b/server/src/session.h
index 12c831a..48c01d7 100644
--- a/server/src/session.h
+++ b/server/src/session.h
@@ -90,5 +90,13 @@ private:
std::map<std::string, Session *> sessions;
};
+class SessionAutolock {
+public:
+ SessionAutolock(Session &session);
+ ~SessionAutolock();
+
+private:
+ Session &session;
+};
#endif/*__PRACRO_SESSION_H__*/
diff --git a/server/src/templatelist.cc b/server/src/templatelist.cc
index b8e8462..af03586 100644
--- a/server/src/templatelist.cc
+++ b/server/src/templatelist.cc
@@ -39,6 +39,11 @@ TemplateList::TemplateList(std::string path)
void TemplateList::addFile(std::string file)
{
+ if(file.substr(file.size() - 4) != ".xml") {
+ PRACRO_DEBUG(templatelist, "Skipping file: %s\n", file.c_str());
+ return;
+ }
+
PRACRO_DEBUG(templatelist, "Adding file: %s\n", file.c_str());
TemplateHeaderParser parser(file);
try {
diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc
index a042a6b..7a45800 100644
--- a/server/src/transactionhandler.cc
+++ b/server/src/transactionhandler.cc
@@ -48,7 +48,8 @@ static std::string error_box(std::string message)
return errorbox;
}
-static std::string handleCommits(Transaction &transaction, Environment &env, Session &session)
+static std::string handleCommits(Transaction &transaction, Environment &env,
+ Session &session)
{
std::string answer;
@@ -66,7 +67,8 @@ static std::string handleCommits(Transaction &transaction, Environment &env, Ses
std::string resume = resume_parser(macro->resume, commit);
commit.fields["journal.resume"] = resume;
- db->commitTransaction(transaction.user, transaction.cpr, *macro, commit.fields);
+ db->commitTransaction(transaction.user, transaction.cpr, *macro,
+ commit.fields);
if(resume != "") {
@@ -84,7 +86,8 @@ static std::string handleCommits(Transaction &transaction, Environment &env, Ses
return answer;
}
-static std::string handleRequest(Transaction &transaction, Environment &env, Session &session)
+static std::string handleRequest(Transaction &transaction, Environment &env,
+ Session &session)
{
std::string answer;
@@ -120,7 +123,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
Macro &macro = (*mi2);
if(macro.isHeader) {
- answer += " <header caption=\"" + macro.attributes["caption"] + "\"/>\n";
+ answer += " <header caption=\"" + macro.attributes["caption"] +
+ "\"/>\n";
mi2++;
continue;
}
@@ -133,7 +137,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
if(completed) answer += "\"true\"";
else answer += "\"false\"";
- std::map< std::string, std::string >::iterator ai = macro.attributes.begin();
+ std::map< std::string, std::string >::iterator ai =
+ macro.attributes.begin();
while(ai != macro.attributes.end()) {
std::string name = ai->first;
std::string value = ai->second;
@@ -167,7 +172,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
if(service == "pentominos") {
// Send the queries to Pentominos (if any)
- QueryHandlerPentominos qh(*atf, transaction.cpr, "pracrod");
+ QueryHandlerPentominos qh(*atf, transaction.cpr,
+ "pracrod"/*user*/);
QueryResult queryresult = qh.exec(*qi);
lqm.addQueryResult(queryresult);
@@ -190,7 +196,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
std::vector< Script >::iterator spi = m->scripts.begin();
while(spi != m->scripts.end()) {
- answer += " <script language=\"" + spi->attributes["language"]
+ answer += " <script language=\"" +
+ spi->attributes["language"]
+ "\" name=\"" + spi->attributes["name"] + "\">\n";
answer += xml_encode(spi->attributes["code"]);
answer += "\n </script>\n";
@@ -212,7 +219,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
if(completed) {
answer += " <resume>";
- answer += db->getResume(transaction.cpr, macro, time(NULL) - Conf::db_max_ttl);
+ answer += db->getResume(transaction.cpr, macro, time(NULL) -
+ Conf::db_max_ttl);
answer += "</resume>\n";
}
@@ -233,7 +241,8 @@ static std::string handleRequest(Transaction &transaction, Environment &env, Ses
return answer;
}
-std::string handleTransaction(Transaction &transaction, Environment &env, Session &session)
+std::string handleTransaction(Transaction &transaction, Environment &env,
+ Session &session)
{
std::string answer;
diff --git a/server/src/transactionparser.cc b/server/src/transactionparser.cc
index f1f79c6..7422a13 100644
--- a/server/src/transactionparser.cc
+++ b/server/src/transactionparser.cc
@@ -36,31 +36,6 @@
#include "debug.h"
#include "exception.h"
-static void error(const char* fmt, ...)
-{
- PRACRO_ERR_LOG(transactionparser, "Error in TransactionParser: ");
-
- {
- va_list argp;
- va_start(argp, fmt);
- PRACRO_ERR_LOG_VA(macro, fmt, argp);
- va_end(argp);
-
- fprintf(stderr, "\n");
- }
-
- {
- char *p;
- va_list argp;
- va_start(argp, fmt);
- if(vasprintf(&p, fmt, argp) != -1) {
- throw Exception("Error in TransactionParser: " + std::string(p));
- free(p);
- }
- va_end(argp);
- }
-}
-
TransactionParser::TransactionParser(Transaction *transaction)
{
this->transaction = transaction;
@@ -68,8 +43,11 @@ TransactionParser::TransactionParser(Transaction *transaction)
totalbytes = 0;
}
-void TransactionParser::startTag(std::string name, std::map< std::string, std::string> attributes)
+void TransactionParser::startTag(std::string name,
+ std::map<std::string, std::string> attributes)
{
+ PRACRO_DEBUG(transactionparser, "<%s>\n", name.c_str());
+
if(name == "pracro") {
transaction->user = attributes["user"];
transaction->cpr = attributes["cpr"];
@@ -92,26 +70,37 @@ void TransactionParser::startTag(std::string name, std::map< std::string, std::s
}
if(name == "field") {
- if(!transaction->commits.size()) error("Field without a commit tag!");
- if(attributes.find("name") == attributes.end()) error("Field is missing 'name' attribute");
- if(attributes.find("value") == attributes.end()) error("Field is missing 'value' attribute");
- transaction->commits.back().fields[attributes["name"]] = attributes["value"];
+ if(!transaction->commits.size()) {
+ PRACRO_ERR(transactionparser, "Field without a commit tag!");
+ return;
+ }
+
+ if(attributes.find("name") == attributes.end()) {
+ PRACRO_ERR(transactionparser, "Field is missing 'name' attribute");
+ return;
+ }
+
+ if(attributes.find("value") == attributes.end()) {
+ PRACRO_ERR(transactionparser, "Field is missing 'value' attribute");
+ return;
+ }
+
+ transaction->commits.back().fields[attributes["name"]] =
+ attributes["value"];
}
}
-void TransactionParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+void TransactionParser::parseError(const char *buf, size_t len,
+ std::string error, int lineno)
{
- PRACRO_ERR_LOG(transactionparser, "TransactionParser error at line %d: %s\n",
- lineno, error.c_str());
- PRACRO_ERR_LOG(transactionparser, "\tBuffer %u bytes: [", len);
- if(fwrite(buf, len, 1, stderr) != len) {}
- PRACRO_ERR_LOG(transactionparser, "]\n");
-
- char *slineno;
- if(asprintf(&slineno, " at line %d\n", lineno) != -1) {
- throw Exception(error + slineno);
- free(slineno);
- }
+ PRACRO_ERR(transactionparser, "TransactionParser error at line %d: %s\n",
+ lineno, error.c_str());
+
+ std::string xml;
+ xml.append(buf, len);
+
+ PRACRO_ERR(transactionparser, "\tBuffer %u bytes: [%s]\n",
+ len, xml.c_str());
}
#ifdef TEST_TRANSACTIONPARSER