summaryrefslogtreecommitdiffstats
path: root/servercomm
diff options
context:
space:
mode:
authorConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
committerConstantin Jucovschi <cj@ubuntu.localdomain>2009-04-24 07:20:22 -0400
commit8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 (patch)
treebd328a4dd4f92d32202241b5e3a7f36177792c5f /servercomm
downloadrasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.gz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.tar.xz
rasdaman-upstream-8f27e65bddd7d4b8515ce620fb485fdd78fcdf89.zip
Initial commitv8.0
Diffstat (limited to 'servercomm')
-rw-r--r--servercomm/Makefile.am50
-rw-r--r--servercomm/callbackmgr.cc172
-rw-r--r--servercomm/callbackmgr.hh136
-rw-r--r--servercomm/httpserver.cc1371
-rw-r--r--servercomm/httpserver.hh173
-rw-r--r--servercomm/httpserver.icc31
-rw-r--r--servercomm/manager.cc1885
-rw-r--r--servercomm/servercomm.cc1399
-rw-r--r--servercomm/servercomm.hh1120
-rw-r--r--servercomm/servercomm.icc31
-rw-r--r--servercomm/servercomm2.cc4051
-rw-r--r--servercomm/test/Makefile117
-rw-r--r--servercomm/test/template_inst.hh138
-rw-r--r--servercomm/test/test_dbcontent.cc161
-rw-r--r--servercomm/test/test_oid.cc229
-rw-r--r--servercomm/test/test_servercomm.cc128
16 files changed, 11192 insertions, 0 deletions
diff --git a/servercomm/Makefile.am b/servercomm/Makefile.am
new file mode 100644
index 0000000..07e962f
--- /dev/null
+++ b/servercomm/Makefile.am
@@ -0,0 +1,50 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community 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 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module servercomm
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+noinst_LIBRARIES=libservercomm.a
+libservercomm_a_SOURCES=../clientcomm/rpcif_xdr.c ../clientcomm/rpcif_svc.cc servercomm.cc \
+ servercomm2.cc manager.cc callbackmgr.cc httpserver.cc \
+ ../mymalloc/mymalloc_svc.cc ../mymalloc/mymalloc.h \
+ ../clientcomm/rpcif.h callbackmgr.hh httpserver.hh httpserver.icc \
+ servercomm.hh servercomm.icc
+BUILT_SOURCES=../clientcomm/rpcif_xdr.c ../clientcomm/rpcif.h ../clientcomm/rpcif_svc.cc
+
+.PHONY: ../clientcomm/rpcif_xdr.c ../clientcomm/rpcif.h ../clientcomm/rpcif_svc.cc
+../clientcomm/rpcif_xdr.c:
+ cd ../clientcomm ; $(MAKE) rpcif_xdr.c
+
+../clientcomm/rpcif.h:
+ cd ../clientcomm ; $(MAKE) rpcif.h
+
+../clientcomm/rpcif_svc.cc:
+ cd ../clientcomm ; $(MAKE) rpcif_svc.cc
diff --git a/servercomm/callbackmgr.cc b/servercomm/callbackmgr.cc
new file mode 100644
index 0000000..ff5cb08
--- /dev/null
+++ b/servercomm/callbackmgr.cc
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: callbackmgr.hh
+ *
+ * MODULE: servercomm
+ * CLASS: CallBackManager
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+#include "servercomm/callbackmgr.hh"
+
+
+CallBackManager::CallBackManager(unsigned int size)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "CallBackManager(" << size << ")" )
+
+ callbacks = new callback_desc_t[size];
+ maxCallbacks = size;
+ numPending = 0;
+ overflowDetected = 0;
+}
+
+
+CallBackManager::~CallBackManager(void)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "~CallBackManager()" )
+
+ delete [] callbacks;
+}
+
+
+void CallBackManager::setMaximumSize(unsigned int size)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "setMaximumSize(" << size << ")" )
+
+ callback_desc_t *newcb = new callback_desc_t[size];
+
+ if (callbacks != NULL)
+ {
+ if (numPending != 0)
+ {
+ unsigned int copysize = (numPending > size) ? size : numPending;
+ memcpy(newcb, callbacks, copysize * sizeof(callback_desc_t));
+ if (copysize < numPending)
+ overflowDetected = 1;
+ }
+ delete [] callbacks;
+ }
+ callbacks = newcb;
+ maxCallbacks = size;
+}
+
+
+int CallBackManager::findCallback(callback_f function, void *context) const
+{
+ unsigned int i;
+
+ // No system calls from this function!
+ for (i=0; i<numPending; i++)
+ {
+ if ((callbacks[i].function == function) && (callbacks[i].context == context))
+ return (int)i;
+ }
+ return -1;
+}
+
+
+int CallBackManager::registerCallback(callback_f function, void *context)
+{
+ // No mallocs, debug output, system calls, ... in this function!!!
+ if (numPending >= maxCallbacks)
+ {
+ overflowDetected = 1;
+ return -1;
+ }
+
+ callbacks[numPending].function = function;
+ callbacks[numPending].context = context;
+
+ numPending++;
+
+ return 0;
+}
+
+
+int CallBackManager::registerUniqueCallback(callback_f function, void *context)
+{
+ if (findCallback(function, context) == -1)
+ return registerCallback(function, context);
+ else
+ return -1;
+}
+
+
+int CallBackManager::removeCallback(callback_f function, void *context)
+{
+ int i;
+
+ // restrictive environment here too, no system calls!
+ i = findCallback(function, context);
+ if (i != -1)
+ {
+ if (i < (int)numPending-1)
+ memmove(callbacks+i, callbacks+(i+1), (numPending-i-1)*sizeof(callback_desc_t));
+ numPending--;
+ return 0;
+ }
+ return -1;
+}
+
+
+unsigned int CallBackManager::getNumCallbacks(void) const
+{
+ return numPending;
+}
+
+
+int CallBackManager::executePending(void)
+{
+ unsigned int i;
+
+ RMDBGENTER(2, RMDebug::module_servercomm, "CallBackManager", "executePending()" )
+
+ for (i=0; i<numPending; i++)
+ {
+ RMDBGMIDDLE(3, RMDebug::module_servercomm, "CallBackManager", "callback function " << i << "..." );
+ callbacks[i].function(callbacks[i].context);
+ }
+
+ if (overflowDetected)
+ {
+ TALK( "CallBackManager::executePending(): overflow detected, number of pending calls: " << numPending );
+ RMInit::logOut << "Internal error: callback overflow." << endl;
+ overflowDetected = 0;
+ }
+
+ i = numPending;
+ numPending = 0;
+
+ return i;
+}
diff --git a/servercomm/callbackmgr.hh b/servercomm/callbackmgr.hh
new file mode 100644
index 0000000..81effcb
--- /dev/null
+++ b/servercomm/callbackmgr.hh
@@ -0,0 +1,136 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: callbackmgr.hh
+ *
+ * MODULE: servercomm
+ * CLASS: CallBackManager
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+
+#ifndef _CALLBACK_MANAGER_
+#define _CALLBACK_MANAGER_
+
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class CallBackManager stores function- and context pointers
+ that are executed in the order they were registered in when
+ calling executePending(). This system replaces the alarm handler
+ approach formerly used which suffered from a restrictive
+ environment where mallocs and printfs were not legal. Since
+ neither call must happen when a callback function is registered
+ the maximum number of callbacks must be fixed in the constructor.
+*/
+
+class CallBackManager
+{
+ public:
+ /// constructor
+ CallBackManager(unsigned int size=1024);
+ /**
+ Constructor; size is the maximum number of callback slots to
+ reserve.
+ */
+
+ /// destructor
+ ~CallBackManager(void);
+
+ /// Resizes the number of callback slots at run-time
+ void setMaximumSize(unsigned int size);
+
+ /// callback function type
+ typedef void (*callback_f)(void*);
+ /**
+ The type of a callback function is void f(void *context). The
+ value of context is the one specified when registering. It's
+ up to the function to cast the value.
+ */
+
+ /// register new callback
+ int registerCallback(callback_f function, void *context);
+ /**
+ Register a new callback function. Returns 0 for OK, -1 if
+ the callback table had an overflow. Since it must be possible
+ to call this function from an alarm handler there may not be
+ any mallocs or prints here.
+ */
+
+ /// register new callback, ensuring uniqueness
+ int registerUniqueCallback(callback_f function, void *context);
+ /**
+ Same as registerCallback, but makes sure this callback isn't
+ pending already in which case it does nothing.
+ */
+
+ /// remove callback
+ int removeCallback(callback_f function, void *context);
+ /**
+ Deregister a callback function. Returns 0 for OK, -1 for
+ not found.
+ */
+
+ /// Get the number of callback functions registered.
+ unsigned int getNumCallbacks(void) const;
+
+ /// execute pending callbacks
+ int executePending(void);
+ /**
+ Execute all pending callback functions and clear the list
+ afterwards. Returns the number of callback functions executed.
+ */
+
+
+ private:
+
+ /// find a matching function/context pair
+ int findCallback(callback_f function, void *context) const;
+ /**
+ Searches the pending callbacks for the one specified by the
+ function parameters and returns its index if found, -1 otherwise.
+ */
+
+ //@{ Internal storage structure for callbacks.
+ typedef struct callback_desc_s {
+ callback_f function;
+ void *context;
+ } callback_desc_t;
+ //@}
+
+ callback_desc_t *callbacks;
+
+ /// Maximum size of callback list
+ unsigned int maxCallbacks;
+
+ /// Currently occupied callback slots
+ unsigned int numPending;
+
+ /// Flag that's set to 1 if the callback table overflowed.
+ int overflowDetected;
+};
+
+#endif
diff --git a/servercomm/httpserver.cc b/servercomm/httpserver.cc
new file mode 100644
index 0000000..514f6b8
--- /dev/null
+++ b/servercomm/httpserver.cc
@@ -0,0 +1,1371 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: httpserver.cc
+ *
+ * MODULE: httpserver
+ * CLASS: HttpServer
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)servercomm, HttpServer: $Id: httpserver.cc,v 1.54 2005/09/03 21:05:14 rasdev Exp $";
+
+#include <iostream>
+#include <malloc.h>
+#include <time.h> // for time()
+#include <string.h>
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm(), gethostname()
+#include <iomanip>
+
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/endian.hh"
+#include "raslib/basetype.hh"
+
+#include "servercomm/httpserver.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtdata.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "mddmgr/mddcoll.hh"
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+#ifdef RMANBENCHMARK
+ // to control ZLibCompression::decompTimer and ZLibCompression::compTimer
+ #include "zlibcompression.hh"
+#endif
+
+#include "httpserver/httpserver.h"
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtstringdata.hh"
+
+#define UNEXPECTED_INTERNAL_ERROR 10000
+
+// ok message for log output; should go into a central file
+#define MSG_OK "ok"
+
+// include and extern declarations for the query parsing
+#include "qlparser/querytree.hh"
+extern int yyparse();
+extern void yyreset();
+extern QueryTree* parseQueryTree;
+extern ParseInfo* parseError;
+extern char* beginParseString;
+extern char* iterParseString;
+extern unsigned long maxTransferBufferSize;
+extern char* dbSchema;
+extern MDDColl* mddConstants;
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+
+#ifdef RMANBENCHMARK
+#if BASEDB == 1
+static o2_ClientStat newO2Stats;
+static o2_ClientStat oldO2Stats;
+#endif
+#endif
+
+// defined in servercomm2.cc
+extern char globalHTTPSetTypeStructure[];
+
+// This currently represents the one and only client active at one time.
+static HttpServer::ClientTblElt globalClientContext(ServerComm::HTTPCLIENT, 1);
+
+// At the beginning, no servercomm object exists.
+HttpServer* HttpServer::actual_httpserver = 0;
+
+// This is a local inline function to enable encoding of longs into chars
+static inline void encodeLong(char* res, const r_Long* val)
+{
+ *res = *(char*)val;
+ *(res+1) = *((char*)val+1);
+ *(res+2) = *((char*)val+2);
+ *(res+3) = *((char*)val+3);
+}
+
+static inline void encodeULong(char* res, const r_ULong* val)
+{
+ *res = *(char*)val;
+ *(res+1) = *((char*)val+1);
+ *(res+2) = *((char*)val+2);
+ *(res+3) = *((char*)val+3);
+}
+
+// This function takes a binary data block and returns a vector of mddTransferEncodings
+void
+getMDDs(int binDataSize, char *binData, int Endianess, vector<HttpServer::MDDEncoding*> &resultVector)
+{
+ char *currentPos;
+ char *stringBuffer;
+ char *binDataBuffer = NULL;
+ r_Long intValue;
+ HttpServer::MDDEncoding *currentMDD;
+ r_Endian::r_Endianness myEndianess = r_Endian::get_endianness();
+
+ //RMInit::logOut << "Starting getMDDs , binDataSize is " << binDataSize << endl;
+
+ stringBuffer = (char*)mymalloc(1024);
+ currentPos = binData;
+ // Examine the whole array...
+ while(currentPos < (binData+binDataSize))
+ {
+ // Create new MDDEncoding object
+ currentMDD = new HttpServer::MDDEncoding();
+ // get objectType
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ // intValue = *(int *)intValue;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setObjectType(intValue);
+ currentPos+=4;
+ //RMInit::logOut << "object type is " << intValue << endl;
+
+ // get objectTypeName
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setObjectTypeName(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "objectTypeName is " << stringBuffer << endl;
+
+ // get typeStructure
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setTypeStructure(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "typeStructure is " << stringBuffer << endl;
+
+ // get typeLength
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ //intValue = *(int *)currentPos;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setTypeLength(intValue);
+ currentPos+=sizeof(r_Long);
+ //RMInit::logOut << "type length is " << intValue << endl;
+
+ // get domain
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setDomain(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "domain is " << stringBuffer << endl;
+
+ // get tileSize - later this will be the storage_layout
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setTileSize(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "tileSize is " << stringBuffer << endl;
+ // get oid
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setOID(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "OID is " << stringBuffer << endl;
+ // get dataSize
+ /* RMInit::logOut << "Byte1: " << (short)*currentPos << endl;
+ RMInit::logOut << "Byte2: " << (short)*(currentPos+1) << endl;
+ RMInit::logOut << "Byte3: " << (short)*(currentPos+2) << endl;
+ RMInit::logOut << "Byte4: " << (short)*(currentPos+3) << endl;*/
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ //intValue = *(int *)currentPos;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setDataSize(intValue);
+ currentPos+=sizeof(r_Long);
+ //RMInit::logOut << "Data size is " << intValue << endl;
+
+ // get binData
+ binDataBuffer = (char*)mymalloc(intValue+1);
+ memcpy(binDataBuffer,currentPos,intValue);
+ currentMDD->setBinData(binDataBuffer);
+ currentPos += intValue;
+
+ // Put object into result vector
+ resultVector.insert(resultVector.begin(),currentMDD);
+ }
+ // free Buffer
+ free(stringBuffer);
+
+ //RMInit::logOut << "vector has " << resultVector.size() << " entries." << endl;
+
+}
+
+
+/**********************************************************************
+ * Class MDDEncoding
+ *
+ * IMPORTANT: This class does not copy its parameters for performance reasons!
+ * So the memory allocated for the parameters must not be freed in
+ * the calling functions or methods, this is done by the destructor
+ * of this class!
+ *
+ *********************************************************************/
+HttpServer::MDDEncoding::MDDEncoding()
+{
+ objectType = 0;
+ objectTypeName = NULL;
+ typeStructure = NULL;
+ typeLength = 0;
+ domain = NULL;
+ tileSize = NULL;
+ oidString = NULL;
+ dataSize = 0;
+ binData = NULL;
+ stringRepresentation = (char*)mymalloc(4096);
+};
+
+HttpServer::MDDEncoding::~MDDEncoding()
+{
+ if (objectTypeName != NULL)
+ free(objectTypeName);
+ if (typeStructure != NULL)
+ free(typeStructure);
+ if (domain != NULL)
+ free(domain);
+ if (tileSize != NULL)
+ free(tileSize);
+ if (oidString != NULL)
+ free(oidString);
+ // binData is freed elsewhere!
+ free(stringRepresentation);
+}
+
+void HttpServer::MDDEncoding::setObjectType(int type)
+{
+ objectType = type;
+}
+
+void HttpServer::MDDEncoding::setObjectTypeName(char *name)
+{
+ if(objectTypeName)
+ free(objectTypeName);
+ objectTypeName = name;
+}
+
+void HttpServer::MDDEncoding::setTypeStructure(char *type)
+{
+ if(typeStructure)
+ free(typeStructure);
+ typeStructure = type;
+}
+
+void HttpServer::MDDEncoding::setTypeLength(int len)
+{
+ typeLength = len;
+}
+
+void HttpServer::MDDEncoding::setDomain(char *dom)
+{
+ if(domain)
+ free(domain);
+ domain = dom;
+}
+
+void HttpServer::MDDEncoding::setTileSize(char *size)
+{
+ if(tileSize)
+ free(tileSize);
+ tileSize = size;
+}
+
+void HttpServer::MDDEncoding::setOID(char *o)
+{
+ if(oidString)
+ free(oidString);
+ oidString = o;
+}
+
+void HttpServer::MDDEncoding::setDataSize(int size)
+{
+ dataSize = size;
+}
+
+void HttpServer::MDDEncoding::setBinData(char *data)
+{
+ if(binData)
+ free(binData);
+ binData = data;
+}
+
+const char* HttpServer::MDDEncoding::toString()
+{
+ char *intBuffer = (char*)mymalloc(128);
+
+ strcpy(stringRepresentation,"\n\n MDD information: \n ObjectTypeName: ");
+ strcat(stringRepresentation,objectTypeName);
+ strcat(stringRepresentation,"\n ObjectType: ");
+ sprintf(intBuffer,"%d",objectType);
+ strcat(stringRepresentation,intBuffer);
+ strcat(stringRepresentation,"\n OID: ");
+ strcat(stringRepresentation,oidString);
+ strcat(stringRepresentation,"\n Domain: ");
+ strcat(stringRepresentation,domain);
+ strcat(stringRepresentation,"\n TypeStructure: ");
+ strcat(stringRepresentation,typeStructure);
+ strcat(stringRepresentation,"\n tileSize: ");
+ strcat(stringRepresentation,tileSize);
+ strcat(stringRepresentation,"\n DataSize: ");
+ sprintf(intBuffer,"%d",dataSize);
+ strcat(stringRepresentation,intBuffer);
+
+ free(intBuffer);
+ return stringRepresentation;
+}
+
+
+/*************************************************************************
+ * Method name...: HttpServer() (constructor)
+ ************************************************************************/
+HttpServer::HttpServer()
+{
+ if( actual_httpserver )
+ {
+ std::cerr << "Internal Error: Tried to instantiate more than one HttpServer object." << endl;
+ exit(1);
+ }
+
+ // So that it should be never freed
+ globalClientContext.currentUsers++;
+ actual_httpserver = this;
+ flagInformRasMgr = false;
+ isHttpServer = true;
+}
+
+HttpServer::HttpServer( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName)
+:ServerComm( timeOut, managementInterval, listenPort, rasmgrHost, rasmgrPort,serverName)
+{
+ if( actual_httpserver )
+ {
+ std::cerr << "Internal Error: Tried to instantiate more than one HTTPServer object." << endl;
+ exit(1);
+ }
+
+ actual_httpserver = this;
+
+ flagInformRasMgr = false;
+
+ // So that it should be never freed
+ globalClientContext.currentUsers++;
+
+ isHttpServer = true;
+}
+
+/*************************************************************************
+ * Method name...: ~HttpServer() (destructor)
+ ************************************************************************/
+HttpServer::~HttpServer()
+{
+ // delete communication object
+ if( admin ) delete admin;
+
+ actual_httpserver = 0;
+}
+
+
+
+/*************************************************************************
+ * Method name...: startHttpServer()
+ ************************************************************************/
+void termSignalHandler(int sig);
+
+
+void
+HttpServer::startRpcServer()
+ throw( r_Error )
+{
+ // create administraion object (O2 session is initialized)
+ admin = AdminIf::instance();
+ if( !admin )
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ // simulating command line arguments
+ const char* dummy[] = { "rasserver", "-c", "httpserver.conf" };
+
+ signal (SIGTERM, termSignalHandler);
+ cout << "RasDaMan server "<<serverName<<" is up." << endl;
+ RMInit::logOut << "RasDaMan server "<<serverName<<" is up." << endl;
+
+ doIt_httpserver( 3, const_cast<char**>(dummy));
+
+}
+
+void termSignalHandler(int sig)
+ {
+ static int in_progress=0;
+
+ if (in_progress) return;
+
+ in_progress = 1;
+
+ if(HttpServer::actual_httpserver)
+ {
+ HttpServer::actual_httpserver->stopRpcServer();
+ }
+
+ }
+
+void clearLastClient(); // is down at end of file
+
+
+void
+HttpServer::stopRpcServer()
+{
+ RMInit::logOut << " Shutdown request received." << endl;
+ // RMInit::logOut << "Unregistering interface...";
+ // has to be adapted for HTTP server
+ // svc_unregister( RPCIF, RPCIFVERS );
+ // RMInit::logOut << "ok" << endl;
+
+ RMInit::logOut << "Clearing clients..." << endl;
+
+ clearLastClient();
+ RMInit::logOut << "informing rasmgr..." << endl;
+ informRasMGR(SERVER_DOWN);
+ cout << "rasdaman server " << serverName << " is down." << endl;
+
+ exit(0);
+ // svc_exit();
+}
+
+HttpServer::ClientTblElt*
+HttpServer::getClientContext( unsigned long clientId )
+{
+ // this is a simplification and only works for one client
+ globalClientContext.currentUsers++;
+ return &globalClientContext;
+}
+
+/*************************************************************************
+ * Method name...: printServerStatus( )
+ ************************************************************************/
+void
+HttpServer::printServerStatus( ostream& s )
+{
+ unsigned long currentTime = time(NULL);
+
+ s << endl;
+ s << "HTTP Server state information at " << endl; // << ctime((time_t*)&currentTime) << endl;
+ s << " Transaction active.............: " << ( transactionActive ? "yes" : "no" ) << endl;
+ s << " Max. transfer buffer size......: " << maxTransferBufferSize << " bytes" << endl;
+ s << endl;
+
+ // Purify?
+ /*
+ s << "memory map----------------------------------------------------" << endl;
+
+ // memorymap(1);
+
+ struct mallinfo meminfo = mallinfo();
+
+ s << "space in arena : " << meminfo.arena << endl;
+ s << "number of small blocks : " << meminfo.smblks << endl;
+ s << "number of ordinary blocks : " << meminfo.ordblks << endl;
+ s << "space in free ordinary blocks : " << meminfo.fordblks << endl;
+ s << "space in used ordinary blocks : " << meminfo.uordblks << endl;
+
+ s << "additional space from last call: " << meminfo.uordblks - memUsed << endl;
+
+ memUsed = meminfo.uordblks;
+
+ s << "end memory map------------------------------------------------" << endl << endl;
+ */
+}
+
+//For future, to make this shit nicer
+
+#ifdef LITTLE_ENDIAN
+ const int systemEndianess = 1;
+#else
+ const int systemEndianess = 0;
+#endif
+
+int encodeAckn(char*&result, int ackCode = 99) // 99 is the 'OK', but we have other ack to
+ {
+ result = (char*)mymalloc(1);
+ *result = ackCode;
+ return 1;
+ }
+
+void cleanExecuteQueryRes(ExecuteQueryRes& res) {
+ if(res.typeStructure){
+ free(res.typeStructure);
+ res.typeStructure=NULL;
+ }
+ if(res.token){
+ free(res.token);
+ res.token=NULL;
+ }
+ if(res.typeName){
+ free(res.typeName);
+ res.typeName=NULL;
+ }
+}
+
+int encodeError(char*&result, const r_ULong errorNo, const r_ULong lineNo,const r_ULong columnNo, const char *text)
+ {
+ int totalLength = 14 + strlen(text) + 1;
+ result = (char*)mymalloc(totalLength);
+ char *currentPos = result;
+ // fill it with data
+ *currentPos = 0; // result is error
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ encodeULong(currentPos, &errorNo);
+ currentPos += sizeof(r_ULong);
+ encodeULong(currentPos, &lineNo);
+ currentPos += sizeof(r_ULong);
+ encodeULong(currentPos, &columnNo);
+ currentPos += sizeof(r_ULong);
+ strcpy(currentPos, text);
+
+ return totalLength;
+ }
+
+//a dirty hack:
+static long lastCallingClientId=-1;
+// this is needed to get a died client lost. Who designed this should do it better
+
+
+long
+HttpServer::processRequest( unsigned long callingClientId, char* baseName, int rascommand,
+ char* query, int binDataSize, char* binData, int Endianess, char*& result, char *capability )
+{
+
+lastCallingClientId=callingClientId;
+
+ //RMInit::logOut << "Start Method Processrequest ... " << endl;
+try
+ { // put to catch all errors which come up here, so HTTP-Server doesn't crush because of them
+
+ long returnValue=0;
+ unsigned short execResult=0;
+ unsigned short dummy=0;
+ ExecuteQueryRes resultError;
+ // needed for result type MDD collection
+ r_Minterval resultDom;
+ char* typeName;
+ char* typeStructure;
+ char* currentPos;
+ r_OId oid;
+ bool valid;
+ unsigned short currentFormat;
+ // vector with mdds in transfer encoding
+ vector<HttpServer::MDDEncoding*> transferredMDDs;
+ Tile* resultTile; // temporary tile with the whole MDD
+ int i;
+ unsigned short objType;
+ r_OId *roid;
+ int totalLength;
+ long l;
+ ClientTblElt* context;
+ // server endianess
+ r_Endian::r_Endianness serverEndian;
+ if(capability)
+ { unsigned long resultCode;
+ resultCode=accessControl.crunchCapability(capability);
+
+ if(resultCode)
+ {
+ flagInformRasMgr = true; // Used in doIt_http...
+
+ return encodeError(result, resultCode,0,0, "");
+ }
+ }
+
+
+ switch (rascommand)
+ {
+ case 1:
+ // commOpenDB
+ // call openDB (userName initialized with "")
+ openDB(callingClientId, baseName, "");
+ return encodeAckn(result);
+ break;
+
+ case 2:
+ // commCloseDB
+ // call closeDB
+ flagInformRasMgr = true; // Used in doIt_http...
+ closeDB(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 3:
+ // commBTreadOnly
+ // call beginTA
+ beginTA(callingClientId, 1);
+ return encodeAckn(result);
+ break;
+
+ case 4:
+ // commBTreadWrite
+ // call beginTA
+ beginTA(callingClientId, 0);
+ return encodeAckn(result);
+ break;
+
+ case 5:
+ // commCT
+ // call commitTA
+ commitTA(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 6:
+ // commAT
+ // call abortTA
+ abortTA(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 7:
+ // commIsOpenTA
+ return encodeAckn(result, (transactionActive==callingClientId) ? 99 : 98);
+ break;
+
+ case 8:
+ // commQueryExec
+ // call executeQuery (result contains error information)
+ resultError.token=NULL;
+ resultError.typeName=NULL;
+ resultError.typeStructure=NULL;
+ execResult = executeQuery(callingClientId, query, resultError);
+ // now we distinguish between different result types
+ if(execResult == 0) {
+ // MDD results
+ int totalLength = 6; // total length of result in bytes
+ r_Long numMDD = 0; // number of MDD objects in the result
+ ClientTblElt* context;
+ vector<Tile*> resultTiles; // contains all TransTiles representing the resulting MDDs
+ resultTiles.reserve(20);
+ vector<char*> resultTypes;
+ resultTypes.reserve(20);
+ vector<char*> resultDomains;
+ resultDomains.reserve(20);
+ vector<r_OId> resultOIDs;
+ resultOIDs.reserve(20);
+ // Here should be something like the following. Unfortunately,
+ // context->transferColl seems to be 0 here. I don't know why.
+ // Thats why a global variable was introduced in
+ // servercomm2.cc.
+ // CollectionType* collectionType =
+ // (CollectionType*) context->transferColl->getMDDCollType();
+ // char* collTypeStructure = collectionType->getTypeStructure();
+
+ while(getNextMDD(callingClientId, resultDom, typeName, typeStructure, oid,
+ currentFormat) == 0) {
+ numMDD++;
+ // create TransTile for whole data from the tiles stored in context->transTiles
+ context = getClientContext( callingClientId );
+ // that should be enough, just transfer the whole thing ;-)
+ resultTile = new Tile( context->transTiles );
+
+ // server endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+
+ // This currently represents the one and only client active at one time.
+ // stupid!!! if((context->clientId == 1) && (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ if(serverEndian != r_Endian::r_Endian_Big)
+ {
+ // RMInit::logOut << "Changing endianness..." << flush;
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ char *tpstruct;
+ r_Base_Type *useType;
+ tpstruct = resultTile->getType()->getTypeStructure();
+ useType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ char* tempT = (char*)mymalloc(sizeof(char) * resultTile->getSize());
+
+ // change the endianness of the entire tile for identical domains for src and dest
+ r_Endian::swap_array(useType, resultDom, resultDom, resultTile->getContents(), tempT);
+ resultTile->setContents(tempT);
+
+ delete useType;
+ free(tpstruct);
+
+ // RMInit::logOut << MSG_OK << endl;
+ }
+
+ resultTiles.push_back(resultTile);
+ resultTypes.push_back(typeStructure);
+ resultDomains.push_back(resultDom.get_string_representation());
+ resultOIDs.push_back(oid);
+ //oid.print_status(RMInit::logOut);
+
+ // this is normally done in getNextTile(). But this is not called, so we do it here.
+ (*(context->transferDataIter))++;
+ if( *(context->transferDataIter) != context->transferData->end() ) {
+ // clean context->transtile if necessary
+ if( context->transTiles ){
+ delete context->transTiles;
+ context->transTiles = 0;
+ }
+ // clean context->tileIter if necessary
+ if( context->tileIter ){
+ delete context->tileIter;
+ context->tileIter = 0;
+ }
+ }
+
+ // clean typeName if necessary
+ if( typeName ){
+ free(typeName);
+ typeName = 0;
+ }
+ }
+
+ // clean typeName if necessary
+ if( typeName ){
+ free(typeName);
+ typeName = 0;
+ }
+
+ // prepare for transfer
+ // calculate total length of the result array
+ for(i = 0; i < numMDD; i++) {
+ totalLength += strlen(resultTypes[i]) + 1;
+ totalLength += strlen(resultDomains[i]) + 1;
+ // OID might be NULL
+ if(resultOIDs[i].get_string_representation() != NULL)
+ totalLength += strlen(resultOIDs[i].get_string_representation()) + 1;
+ else
+ totalLength++;
+ totalLength += resultTiles[i]->getSize();
+ totalLength += 4;
+ }
+ // for the type of the collection
+ totalLength += strlen(globalHTTPSetTypeStructure) + 1;
+
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 1; // result is MDD collection
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // type of the collection
+ strcpy(currentPos, globalHTTPSetTypeStructure);
+ currentPos += strlen(globalHTTPSetTypeStructure) + 1;
+ encodeLong(currentPos, &numMDD);
+ currentPos += sizeof(r_Long);
+ // encode MDDs
+ for(i = 0; i < numMDD; i++) {
+ r_Long dummy = resultTiles[i]->getSize();
+ strcpy(currentPos, resultTypes[i]);
+ currentPos += strlen(resultTypes[i]) + 1;
+ strcpy(currentPos, resultDomains[i]);
+ currentPos += strlen(resultDomains[i]) + 1;
+ // OID might be NULL
+ if(resultOIDs[i].get_string_representation() != NULL)
+ {
+ strcpy(currentPos, resultOIDs[i].get_string_representation());
+ currentPos += strlen(resultOIDs[i].get_string_representation()) + 1;
+ }
+ else
+ {
+ *currentPos = '\0';
+ currentPos++;
+ }
+ encodeLong(currentPos, &dummy);
+ currentPos += sizeof(r_Long);
+ memcpy(currentPos, resultTiles[i]->getContents(), dummy);
+ currentPos += dummy;
+ }
+
+ // delete all the temporary storage
+ for(i = 0; i < numMDD; i++) {
+ delete resultTiles[i];
+ free(resultTypes[i]);
+ free(resultDomains[i]);
+ }
+
+ returnValue = totalLength;
+
+ } else if(execResult == 1) {
+ // the result is a collection of scalars.
+ int totalLength = 6; // total length of result in bytes
+ r_Long numElem = 0; // number of MDD objects in the result
+ ClientTblElt* context;
+ vector<char*> resultElems; // contains all TransTiles representing the resulting MDDs
+ resultElems.reserve(20);
+ vector<unsigned int> resultLengths;
+ resultLengths.reserve(20);
+
+ // we have to get the type of the collection
+ totalLength += strlen(resultError.typeStructure) + 1;
+
+ // then we have to get all elements in the collection
+ unsigned short dummyRes;
+ char* buffer;
+ unsigned int bufferSize;
+ // This will probably not work for empty collections. Only if getNextElement
+ // returns 2 in this case. I really don't get it.
+ unsigned short moreElems = 0;
+
+ while( moreElems == 0 ) {
+ moreElems = getNextElement(callingClientId, buffer, bufferSize);
+
+ //RMInit::logOut << "More elems is " << moreElems << endl;
+ numElem++;
+ resultElems.push_back(buffer);
+ resultLengths.push_back(bufferSize);
+ // length of data
+ totalLength += bufferSize;
+ // this will be length of type
+ totalLength += 1;
+ // size of each element
+ totalLength += sizeof(r_Long);
+ }
+
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 2; // result is collection of other types
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // type of the collection
+ strcpy(currentPos, resultError.typeStructure);
+ currentPos += strlen(resultError.typeStructure) + 1;
+ // number of elements
+ encodeLong(currentPos, &numElem);
+ currentPos += sizeof(r_Long);
+
+ // and finally copy them together
+ for(i = 0; i < numElem; i++) {
+ // This should be the type of the element
+ *currentPos = '\0';
+ currentPos++;
+ // length in bytes of the element
+ r_ULong convDummy = resultLengths[i];
+ encodeULong(currentPos, &convDummy);
+ currentPos += sizeof(r_ULong);
+ // actual data
+ memcpy(currentPos, resultElems[i], resultLengths[i]);
+ currentPos += resultLengths[i];
+ }
+
+ // delete all the temporary storage
+ for(i = 0; i < numElem; i++) {
+ free(resultElems[i]);
+ }
+
+ returnValue = totalLength;
+
+ } else if(execResult == 2) {
+ int totalLength = 7; // total length of result in bytes
+ // the result collection is empty. It is returned as an empty MDD collection.
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 1; // result is MDD collection
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // here the type of the collection should be added, currently empty string!
+ *currentPos = '\0';
+ currentPos++;
+ // now set the number of results to zero
+ r_Long dummy=0;
+ encodeLong(currentPos, &dummy);
+
+ returnValue = totalLength;
+
+ } else if(execResult == 4 || execResult == 5) {
+ // parse error or execution error
+ returnValue = encodeError(result, resultError.errorNo,resultError.lineNo, resultError.columnNo, resultError.token);
+
+ } else {
+ // unknow error
+ returnValue = -10;
+ }
+
+ cleanExecuteQueryRes(resultError);
+
+ // insert error handling here
+ return returnValue;
+ break;
+
+ case 9:
+ // commUpdateExec
+ // empty transfer structures (only to be sure, this case probably cannot occur :-)
+ returnValue = 0;
+ valid = false;
+ while(!transferredMDDs.empty())
+ {
+ RMInit::logOut << "Freeing old transfer structures..." << std::flush;
+ free(transferredMDDs.back()->binData);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ RMInit::logOut << MSG_OK << endl;
+ }
+
+ // do we have an insert statement?
+ if(binDataSize > 0)
+ {
+ // yes, it is an insert statement => analyze and prepare the MDDs
+ // create an empty MDD-Set in the client context
+ initExecuteUpdate(callingClientId);
+
+ // Analyze the binData array (the uploaded mdds)
+ getMDDs(binDataSize,binData,Endianess,transferredMDDs);
+
+ // Store all MDDs
+ //RMInit::logOut << "vector has " << transferredMDDs.size() << " entries." << endl;
+ returnValue = 0;
+ while(!transferredMDDs.empty() && (returnValue == 0))
+ {
+ //RMInit::logOut << "Element:" << transferredMDDs.back()->toString() << endl;
+ // insert MDD into MDD-Set of client context
+ r_Minterval tempStorage(transferredMDDs.back()->domain);
+
+ roid = new r_OId(transferredMDDs.back()->oidString);
+ // OID valid
+ valid = roid->is_valid();
+ if(valid)
+ {
+ // parse the query string to get the collection name
+ char* collection;
+ char* startPtr;
+ char* endPtr;
+ startPtr = endPtr = query;
+ collection = new char[ endPtr - startPtr + 1 ];
+ // one for insert, one for into and one for the collection name
+ for(int i = 0; i<3; i++)
+ {
+ // delete spaces, tabs ...
+ while((*endPtr == ' ' || *endPtr == '\t' || *endPtr == '\r' || *endPtr == '\n') && *endPtr != '\0') endPtr++;
+ startPtr = endPtr;
+ // parse next word
+ while(*endPtr != ' ' && *endPtr != '\t' && *endPtr != '\r' && *endPtr != '\n' && *endPtr != '\0') endPtr++;
+ if(endPtr - startPtr >= 1)
+ {
+ collection = new char[endPtr - startPtr + 1];
+ strncpy(collection, startPtr, endPtr - startPtr);
+ collection[endPtr - startPtr] = '\0';
+ }
+ }
+ //RMInit::logOut << "collection: " << collection << endl;
+
+ //RMInit::logOut << "OID is valid: " << endl;
+ //roid->print_status(RMInit::logOut);
+ execResult = startInsertPersMDD( callingClientId, collection, tempStorage,
+ transferredMDDs.back()->typeLength,
+ transferredMDDs.back()->objectTypeName, *roid);
+ }
+ // OID not valid
+ else
+ {
+ //RMInit::logOut << "OID is NOT valid" << endl;
+
+ execResult = startInsertTransMDD( callingClientId, tempStorage,
+ transferredMDDs.back()->typeLength,
+ transferredMDDs.back()->objectTypeName );
+ }
+
+ //clean roid, we don't needed anymore
+ if(roid) {
+ delete roid;
+ roid = NULL;
+ }
+
+ if(execResult != 0)
+ {
+ // no or wrong mdd type - return error message
+ unsigned long errNo;
+ if(strlen(transferredMDDs.back()->objectTypeName) < 1)
+ errNo=966;
+ else
+ {
+ switch(execResult)
+ {
+ case 2:
+ errNo = 965;
+ break;
+ case 3:
+ errNo = 959;
+ break;
+ case 4:
+ errNo = 952;
+ break;
+ case 5:
+ errNo = 957;
+ break;
+ default:
+ errNo = 350;
+ }
+ RMInit::logOut << "Error: while inserting MDD" << endl;
+ }
+
+ returnValue = encodeError(result, errNo, 0, 0, transferredMDDs.back()->objectTypeName);
+
+ //clean up
+ while(!transferredMDDs.empty())
+ {
+ RMInit::logOut << "Freeing old transfer structures..." << std::flush;
+ free(transferredMDDs.back()->binData);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ RMInit::logOut << MSG_OK << endl;
+ }
+
+
+
+ return returnValue;
+ }
+ else
+ {
+ // create RPCMarray data structure - formats are currently hardcoded (r_Array)
+ RPCMarray *rpcMarray = (RPCMarray*)mymalloc( sizeof(RPCMarray) );
+ rpcMarray->domain = strdup(transferredMDDs.back()->domain);
+ rpcMarray->cellTypeLength = transferredMDDs.back()->typeLength;
+ rpcMarray->currentFormat = r_Array;
+ rpcMarray->storageFormat = r_Array;
+ rpcMarray->data.confarray_len = transferredMDDs.back()->dataSize;
+ rpcMarray->data.confarray_val = transferredMDDs.back()->binData;
+
+ /*
+ RMInit::logOut << "Creating RPCMarray with domain " << rpcMarray->domain << ", size " <<
+ rpcMarray->data.confarray_len << ", typeLength " << rpcMarray->cellTypeLength << " ..."
+ << flush;
+ */
+
+ // split tile if a tileSize (an MInterval) has been specified
+ r_Minterval* splitInterval = NULL;
+ if(transferredMDDs.back()->tileSize != NULL)
+ {
+ splitInterval = new r_Minterval(transferredMDDs.back()->tileSize);
+ RMInit::logOut << "Splitinterval is " << splitInterval << endl;
+ }
+ // now insert the tile(s)
+ if(valid)
+ {
+ insertTileSplitted( callingClientId, 1, rpcMarray, splitInterval );
+ }
+ else
+ {
+ insertTileSplitted( callingClientId, 0, rpcMarray, splitInterval );
+ }
+
+ // free the stuff
+ free(rpcMarray->domain);
+ free(rpcMarray);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ delete(splitInterval);
+ }
+ }
+
+ // end insertion into client structure
+ if(valid)
+ endInsertMDD(callingClientId, 1);
+ else
+ endInsertMDD( callingClientId, 0 );
+ }
+
+ if(returnValue == 0)
+ {
+ //RMInit::logOut << "Executing query: " << query << flush;
+ // until now now error has occurred => execute the query
+ ExecuteUpdateRes returnStructure;
+ returnStructure.token=NULL;
+ if(!valid)
+ execResult = executeUpdate( callingClientId, (const char*)query , returnStructure );
+ // query was executed successfully
+ if (execResult == 0) {
+ // allocate the result
+ result = (char*)mymalloc(1);
+ currentPos = result;
+ *currentPos = 99; // result is an acknowledgement
+ returnValue = 1;
+ }
+ // parsing or execution error
+ else if( execResult == 2 || execResult == 3 ) {
+ returnValue = encodeError(result, returnStructure.errorNo,returnStructure.lineNo, returnStructure.columnNo, returnStructure.token);
+ }
+ else {
+ // unknow error
+ returnValue = -10;
+ }
+
+ if(returnStructure.token) {
+ free(returnStructure.token);
+ returnStructure.token=NULL;
+ }
+ }
+ return returnValue;
+ break;
+ case 10:
+ // getnewoid
+ accessControl.wantToWrite();
+ objType = 1;
+ roid = new r_OId();
+ ServerComm::getNewOId(lastCallingClientId, objType, *roid);
+ //roid->print_status(RMInit::logOut);
+
+ // prepare returnValue
+ totalLength = 9; // total length of result in bytes
+ totalLength += strlen(roid->get_system_name()) + 1;
+ totalLength += strlen(roid->get_base_name()) + 1;
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 4; // result is a OID
+ currentPos++;
+
+ // system
+ strcpy(currentPos, roid->get_system_name());
+ currentPos += strlen(roid->get_system_name()) + 1;
+
+ // base
+ strcpy(currentPos, roid->get_base_name());
+ currentPos += strlen(roid->get_base_name()) + 1;
+
+
+ context = getClientContext( callingClientId );
+ // server endianess
+ serverEndian = r_Endian::get_endianness();
+ // This currently represents the one and only client active at one time.
+ if((context->clientId == 1) &&
+ (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) &&
+ (serverEndian != r_Endian::r_Endian_Big))
+ {
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ double tmp = roid->get_local_oid();
+ *(double*)currentPos = r_Endian::swap(tmp);
+ }
+ else
+ *(double*)currentPos = roid->get_local_oid();
+ //currentPos += 8;
+ returnValue = totalLength;
+
+ //clean up we don't need roid anymore
+ if(roid) {
+ delete roid;
+ roid=NULL;
+ }
+
+ return returnValue;
+ break;
+ default:
+ return -10;
+ break;
+ }
+ }
+ catch(r_Eno_permission &e) // this shouldn't be here, but ...
+ {
+ return encodeError(result, e.get_errorno(),0,0, "");
+ }
+ catch(...)
+ {
+ // really? flagInformRasMgr = true; // client should ask for a new server
+
+ return encodeError(result, UNEXPECTED_INTERNAL_ERROR,0,0, "");
+ }
+
+}
+
+//**********************************************************************
+
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+#include "httpserver/defs.h"
+#include "httpserver/protos.h"
+#include "httpserver/types.h"
+#include "httpserver/server.h"
+
+
+extern struct ServerBase Server;
+
+extern struct Logging *LogBase;
+
+void Select(int socket); // wrap around to put timeout in it
+
+int HttpServer::doIt_httpserver( int argc, char *argv[] )
+{
+ pid_t ChildPId; /* -> Server.ChildInfo */
+
+ RMInit::logOut << "Initialising parameters for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ Initialize( argc, argv, &Server );
+
+ RMInit::logOut << "Initialising server socket for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ listen( Server.SockFD, 5 );
+ RMInit::logOut << "Waiting for client calls... " << endl;
+ RMInit::logOut.flush();
+
+ informRasMGR(SERVER_AVAILABLE);
+
+ for(;;)
+ {
+ Select( Server.SockFD);
+ Accept( Server.SockFD, &Server.Client );
+ strcpy( Server.Client.Host.IPAddrString, inet_ntoa( Server.Client.Socket.sin_addr ) );
+
+ if( Server.Client.Host.IPAddrString == NULL )
+ strcpy( Server.Client.Host.IPAddrString, "0.0.0.0" );
+
+ Server.Client.Host.IPAddress = inet_addr( Server.Client.Host.IPAddrString );
+ Server.Client.Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Server.Client.Response );
+ InitReqInfo( &Server.Client.Request );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== Connection from %s accepted...",
+ Server.Client.Host.IPAddrString );
+
+ HandleRequest( &Server.Client );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== EOT. Disconnecting." );
+
+ close( Server.Client.SockFD );
+
+ if(flagInformRasMgr == true)
+ { informRasMGR(SERVER_AVAILABLE);
+ flagInformRasMgr = false;
+ }
+
+#ifdef PURIFY
+ purify_printf( "Request finished." );
+ purify_new_leaks();
+#endif
+
+ }
+ // otherwise Exit(OK) should have been called
+ return -1;
+}
+
+extern int noTimeOut;
+void Select(int socket)
+ {
+ static time_t lastEntry =0; // last time we entered here
+
+ fd_set read_fd_set, http_fd_set;
+
+ FD_ZERO(&http_fd_set);
+ FD_SET(socket,&http_fd_set);
+
+ const int checkTimeOutInterval=30;
+
+ struct timeval timeout;
+ timeout.tv_sec=checkTimeOutInterval;
+ timeout.tv_usec=0 ;
+
+ lastEntry = time(NULL);
+ while(1)
+ { read_fd_set=http_fd_set;
+ //cout<<"HTTP Server is waiting..."<<endl;
+ timeout.tv_sec=checkTimeOutInterval;
+ timeout.tv_usec=0;
+
+ int rasp=select(FD_SETSIZE,&read_fd_set,NULL,NULL,&timeout);
+ //cout<<"rasp="<<rasp<<endl;
+ if(rasp>0)
+ {
+ break; // means client call
+ }
+
+ if(rasp<=0)
+ {
+ if(accessControl.isClient()==false)
+ { // regularly tell the rasmgr that we are available. There is a scenario for DoS-attack (or bug, or firewall-problem)
+ // when a client allocates itself a server and never calls, so the server is not usable any more.
+ // but we have to find a smarter way of doing this, we need rasmgr-rasserver communication!
+ ServerComm::actual_servercomm->informRasMGR(SERVER_REGULARSIG);
+ }
+
+ //cout<<"Timeout...noTimeout="<<noTimeOut<<endl; // or a signal
+ //unsigned long clientTimeout=(ServerComm::actual_servercomm)->clientTimeout;
+ //cout<<"clientTimeout="<<clientTimeout<<" have Client="<<accessControl.isClient()<<endl;
+
+ if(!noTimeOut && lastCallingClientId !=-1)
+ {
+ time_t now=time(NULL);
+ unsigned long clientTimeOut=(ServerComm::actual_servercomm)->clientTimeout;
+ if((now - lastEntry) > clientTimeOut && accessControl.isClient())
+ {
+ RMInit::logOut <<"Timeout: after " << clientTimeOut << ", freeing client "<<lastCallingClientId<< "..." << std::flush;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ ServerComm::ClientTblElt *clnt= sc-> getClientContext( lastCallingClientId );
+ clnt->transaction.abort();
+ clnt->database.close();
+ sc->informRasMGR(SERVER_AVAILABLE);
+ // cout<<"Http server, client timeout, available again..."<<endl;
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ }
+
+ }
+ }
+
+ }
+
+// used at exit, but put here for some compiling reason
+void clearLastClient()
+ {
+ if(accessControl.isClient())
+ {
+ RMInit::logOut << "Freeing client " << lastCallingClientId << "..." << std::flush;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ ServerComm::ClientTblElt *clnt= sc-> getClientContext( lastCallingClientId );
+ clnt->transaction.abort();
+ clnt->database.close();
+ RMInit::logOut << MSG_OK << endl;
+ }
+ }
+
diff --git a/servercomm/httpserver.hh b/servercomm/httpserver.hh
new file mode 100644
index 0000000..47d64ba
--- /dev/null
+++ b/servercomm/httpserver.hh
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: httpserver.hh
+ *
+ * MODULE: servercomm
+ * CLASS: HttpServer
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#ifndef _HTTPSERVER_
+#define _HTTPSERVER_
+
+#include "servercomm/servercomm.hh"
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class HttpServer describes the one and only server communication object
+ that can exist in a RasDaMan server. It manages listening for clients and
+ maps incoming calls to the respective procedures (which reside in the
+ file manager.cc).
+
+ This class implements the functions useful for HTTP communication
+ and is based on a copy of servercomm.hh (Version 1.48).
+*/
+
+
+class HttpServer : public ServerComm
+{
+public:
+
+ /// the class represents an MDD in HTTP transfer encoding
+ class MDDEncoding
+ {
+ public:
+
+ int objectType;
+ char *objectTypeName;
+ char *typeStructure;
+ int typeLength;
+ char *domain;
+ char *tileSize;
+ char *oidString;
+ int dataSize;
+ char *binData;
+ char *stringRepresentation;
+
+ /// default constructor
+ MDDEncoding();
+
+ /// destructor
+ ~MDDEncoding();
+
+ // set objectType
+ void setObjectType(int type);
+
+ // set objectTypeName
+ void setObjectTypeName(char *name);
+
+ // set typeStructure
+ void setTypeStructure(char* type);
+
+ // set typeLength
+ void setTypeLength(int len);
+
+ // set domain
+ void setDomain(char *dom);
+
+ // set oid
+ void setOID(char *o);
+
+ // set tile size
+ void setTileSize(char *size);
+
+ // set dataSize
+ void setDataSize(int size);
+
+ // set binData
+ void setBinData(char *data);
+
+ // print Values
+ const char* toString();
+ };
+
+
+ /// stores a pointer to the actual servercomm object, only one can exist at a time
+ static HttpServer* actual_httpserver;
+
+ // the class uses the class ClientTblElt from ServerComm because it is used
+ // in some other files of the server, e.g., qlparser/qtmddaccess.cc or
+ // qlparser/qtcommand.cc or qlparser/qtinsert.cc all include servercomm.hh
+
+ /// default constructor
+ HttpServer();
+
+ // the acual constructor
+ HttpServer( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName);
+
+ /// destructor
+ virtual ~HttpServer();
+
+ /// forces the server to listen for client calls
+ virtual void startRpcServer() throw( r_Error );
+
+ /// stops the server
+ virtual void stopRpcServer();
+
+ /// print server status to {\tt s}
+ virtual void printServerStatus( ostream& s=cout );
+
+ /// Executes a retrieval query and prepare the result for HTTP transer.
+ virtual long processRequest( unsigned long callingClientId, char* baseName,
+ int rascommand, char* query, int binDataSize, char *binData,
+ int Endianess, char* &result, char *capability );
+ /**
+ Executes a query and prepares the complete result for transfer via
+ HTTP. The length of the result is returned. The first parameter is
+ the unique client id for which the query should be executed. The
+ second parameter The third parameter is the query itself represented
+ as a string. {\tt result} will contain a pointer to the result as
+ needed for HTTP transfer. This pointer has to be freed by the caller
+ using free.
+
+ Return values on Error:
+ \begin{tabular}{lll}
+ -1 && parse errror\\
+ -2 && execution error\\
+ -3 && unknown error\\
+ \end{tabular}
+
+ Question: How to transfer the result?
+ */
+
+ /// returns a pointer to the context of the calling client, 0 it there is no context
+ virtual ClientTblElt* getClientContext( unsigned long ClientId );
+ /**
+ Returns a pointer to the context of the calling client. Currently always
+ the same global context is returned.
+ */
+ private:
+ int doIt_httpserver( int argc, char *argv[] );
+
+
+ bool flagInformRasMgr; // used to trigger informRasMGR(SERVERAVAILABLE)
+
+};
+
+#include "httpserver.icc"
+
+#endif
diff --git a/servercomm/httpserver.icc b/servercomm/httpserver.icc
new file mode 100644
index 0000000..d1b00bd
--- /dev/null
+++ b/servercomm/httpserver.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: httpserver.icc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * No Comments
+*/
diff --git a/servercomm/manager.cc b/servercomm/manager.cc
new file mode 100644
index 0000000..8177919
--- /dev/null
+++ b/servercomm/manager.cc
@@ -0,0 +1,1885 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: manager.cc
+ *
+ * MODULE: servercomm
+ * CLASS: -
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#include "mymalloc/mymalloc.h"
+static const char rcsid[] = "@(#)manager, ServerComm: $Id: manager.cc,v 1.92 2005/09/03 21:05:14 rasdev Exp $";
+
+#include <iostream>
+using namespace std;
+
+#include <string.h> // for strcat()
+#include <time.h> // for time()
+#include <malloc.h>
+
+// server option for switching off garbageCollection (Formerly there were problems
+// because of illegal functions called in signal handler, see man 5 attributes;
+// these are no longer relevant since the introduction of the CallBackManager)
+extern int noTimeOut;
+
+
+// Put it in front of any typedef bool ... because o2 is using bool as a variable.
+// #include "o2template_CC.hxx"
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm()
+
+#ifndef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#ifndef _RPCIF_
+ #define _RPCIF_
+ #include "clientcomm/rpcif.h"
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/oid.hh"
+#include "raslib/endian.hh"
+
+#include "servercomm/servercomm.hh"
+
+
+extern "C" {
+void garbageCollection( int );
+void garbageCollectionDummy ( int );
+}
+
+
+//
+// Section for global variables pointing to RPC return data.
+//
+static GetExtendedErrorInfo rpcExtendedErrorInfo = { 0, 0};
+static ServerVersionRes rpcServerVersionRes = { 0, 0};
+static u_short rpcDummy = 0;
+static OpenDBRes rpcOpenDBRes = { 0, 0};
+
+static ServerStatRes rpcServerStatRes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0 } };
+static ExecuteQueryRes rpcExecuteQueryRes = { 0, 0, 0, 0, 0, 0, 0 };
+static GetMDDRes rpcGetMDDRes = { 0, 0, 0, 0, 0 };
+static GetElementRes rpcGetElementRes = { 0, { 0, 0 } };
+static GetTileRes rpcGetTileRes = { 0, 0 };
+static ExecuteUpdateRes rpcExecuteUpdateRes = { 0, 0, 0, 0, 0 };
+static GetCollRes rpcGetCollRes = { 0, 0, 0, 0, 0 };
+static GetCollOIdsRes rpcGetCollOidsRes = { 0, 0, 0, 0, 0, { 0, 0 } };
+static OIdRes rpcOidRes = { 0, 0 };
+static GetTypeStructureRes rpcGetTypeStructureRes = { 0, 0 };
+static ObjectTypeRes procResult = { 0, 0 };
+
+extern char *secureResultBufferForRPC;
+
+void freeDynamicRPCData()
+{
+ // rpcserverstat
+ if( rpcServerStatRes.clientTable.clientTable_len )
+ {
+ for( int i=0; i<rpcServerStatRes.clientTable.clientTable_len; i++ )
+ {
+ free( rpcServerStatRes.clientTable.clientTable_val[i].clientIdText );
+ free( rpcServerStatRes.clientTable.clientTable_val[i].userName );
+ free( rpcServerStatRes.clientTable.clientTable_val[i].baseName );
+ }
+
+ free( rpcServerStatRes.clientTable.clientTable_val );
+
+ rpcServerStatRes.clientTable.clientTable_len = 0;
+ rpcServerStatRes.clientTable.clientTable_val = 0;
+ }
+
+ // rpcexecutequery
+ if( rpcExecuteQueryRes.token ) free( rpcExecuteQueryRes.token );
+ if( rpcExecuteQueryRes.typeName ) free( rpcExecuteQueryRes.typeName );
+ if( rpcExecuteQueryRes.typeStructure ) free( rpcExecuteQueryRes.typeStructure );
+ rpcExecuteQueryRes.token = 0;
+ rpcExecuteQueryRes.status = 0;
+ rpcExecuteQueryRes.errorNo = 0;
+ rpcExecuteQueryRes.lineNo = 0;
+ rpcExecuteQueryRes.columnNo = 0;
+ rpcExecuteQueryRes.typeName = 0;
+ rpcExecuteQueryRes.typeStructure = 0;
+
+ // rpcgetnextmdd, rpcgetmddbyoid
+ if( rpcGetMDDRes.domain ) free( rpcGetMDDRes.domain );
+ if( rpcGetMDDRes.typeName ) free( rpcGetMDDRes.typeName );
+ if( rpcGetMDDRes.typeStructure ) free( rpcGetMDDRes.typeStructure );
+ if( rpcGetMDDRes.oid ) free( rpcGetMDDRes.oid );
+ rpcGetMDDRes.typeStructure = 0;
+ rpcGetMDDRes.typeName = 0;
+ rpcGetMDDRes.domain = 0;
+ rpcGetMDDRes.oid = 0;
+
+ // rpcgetnextelement
+ if( rpcGetElementRes.data.confarray_val ) free( rpcGetElementRes.data.confarray_val );
+ rpcGetElementRes.data.confarray_val = 0;
+
+ // rpcgetnexttile
+ if( rpcGetTileRes.marray )
+ {
+ if( rpcGetTileRes.marray->domain ) free( rpcGetTileRes.marray->domain );
+ // if( rpcGetTileRes.marray->data ) free( rpcGetTileRes.marray->data );
+ free( rpcGetTileRes.marray );
+ rpcGetTileRes.marray = 0;
+ }
+
+ // rpcexecuteupdate
+ if( rpcExecuteUpdateRes.token ) free( rpcExecuteUpdateRes.token );
+ rpcExecuteUpdateRes.token = 0;
+ rpcExecuteUpdateRes.status = 0;
+ rpcExecuteUpdateRes.errorNo = 0;
+ rpcExecuteUpdateRes.lineNo = 0;
+ rpcExecuteUpdateRes.columnNo = 0;
+
+ // rpcgetcollbyname, rpcgetcollbyoid
+ if( rpcGetCollRes.typeName ) free( rpcGetCollRes.typeName );
+ if( rpcGetCollRes.typeStructure ) free( rpcGetCollRes.typeStructure );
+ if( rpcGetCollRes.oid ) free( rpcGetCollRes.oid );
+ if( rpcGetCollRes.collName ) free( rpcGetCollRes.collName );
+ rpcGetCollRes.oid = 0;
+ rpcGetCollRes.typeStructure = 0;
+ rpcGetCollRes.typeName = 0;
+ rpcGetCollRes.collName = 0;
+
+ // rpcgetcolloidsbyname, rpcgetcolloidsbyoid
+ if( rpcGetCollOidsRes.typeName ) free( rpcGetCollOidsRes.typeName );
+ if( rpcGetCollOidsRes.typeStructure ) free( rpcGetCollOidsRes.typeStructure );
+ if( rpcGetCollOidsRes.oid ) free( rpcGetCollOidsRes.oid );
+ if( rpcGetCollOidsRes.collName ) free( rpcGetCollOidsRes.collName );
+ rpcGetCollOidsRes.oid = 0;
+ rpcGetCollOidsRes.typeStructure = 0;
+ rpcGetCollOidsRes.typeName = 0;
+ rpcGetCollOidsRes.collName = 0;
+
+ if( rpcGetCollOidsRes.oidTable.oidTable_len )
+ {
+ for( int i=0; i<rpcGetCollOidsRes.oidTable.oidTable_len; i++ )
+ free( rpcGetCollOidsRes.oidTable.oidTable_val[i].oid );
+
+ free( rpcGetCollOidsRes.oidTable.oidTable_val );
+
+ rpcGetCollOidsRes.oidTable.oidTable_len = 0;
+ rpcGetCollOidsRes.oidTable.oidTable_val = 0;
+ }
+
+ // rpcgetnewoid
+ if( rpcOidRes.oid ) free( rpcOidRes.oid );
+ rpcOidRes.oid = 0;
+
+ // rpcgettypestructure
+ if( rpcGetTypeStructureRes.typeStructure ) free( rpcGetTypeStructureRes.typeStructure );
+ rpcGetTypeStructureRes.typeStructure = 0;
+
+ // execute all pending callbacks. Redirect alarm signal first to make sure no
+ // reentrancy is possible!
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ signal( SIGALRM, garbageCollection );
+}
+
+
+/*************************************************************
+ *
+ *
+ * SOURCE: manager.cc
+ *
+ * MODULE: servercomm
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifdef LINUX
+#define RPCFUNCTIONDEF(name, param) name##_svc( param, struct svc_req* )
+#define RPCFUNCTIONDEFP(name, param) *name##_svc( param, struct svc_req* )
+#else
+#define RPCFUNCTIONDEF(name, param) name##_svc( param, struct svc_req* )
+#define RPCFUNCTIONDEFP(name, param) *name##_svc( param, struct svc_req* )
+#endif
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcgetserverversion_1} is called by a client to determine
+ version numbers of the server.
+*/
+
+ServerVersionRes*
+RPCFUNCTIONDEF( rpcgetserverversion_1, int* )
+{
+ freeDynamicRPCData();
+
+ rpcServerVersionRes.serverVersionNo = RMANVERSION / 1000.0;
+ rpcServerVersionRes.rpcInterfaceVersionNo = RPCVERSION / 1000.0;
+
+ return &rpcServerVersionRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcshutdown_1} is called by a client to shut
+ down the server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcshutdown_1, int* )
+{
+ rpcDummy = 0;
+ freeDynamicRPCData();
+ // we don't allow the client to shut down the server. This is done thru rasmgr
+ // may be is would be better to redesign this server interface and drop several
+ // functions
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcServerStat_1} is called by a clientcomm
+ object on the client system to display server statistics.
+*/
+
+ServerStatRes*
+RPCFUNCTIONDEF( rpcserverstat_1, int* )
+{
+ secureResultBufferForRPC = (char*)&rpcServerStatRes;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // log server status
+#ifdef RMANDEBUG
+ sc->printServerStatus( RMInit::dbgOut );
+#endif
+
+ // get server status
+ sc->getServerStatus( rpcServerStatRes );
+
+ return &rpcServerStatRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpckilltableentry_1} is called by a clientcomm
+ object on the client system to kill a specific client table entry on the server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpckilltableentry_1, unsigned long* killId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+ rpcDummy = 0;
+ unsigned long kId = *killId;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ RMInit::logOut << " Kill specific table entry request received for client ID " << kId << "." << endl;
+
+ if( sc && !sc->clientTbl.empty() )
+ {
+
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ iter = sc->clientTbl.begin();
+
+ while ( *iter != NULL )
+ {
+ if( (*iter)->clientId == kId )
+ {
+ RMInit::logOut << "ID " << (*iter)->clientId << " found, deleting..." << endl;
+
+ sc->deleteClientTblEntry( (*iter)->clientId );
+
+ // if this dead client has locked the transaction semaphor, unlock it
+ if( sc->transactionActive == kId )
+ sc->transactionActive = 0;
+
+ // client IDs are unique, so this was the only one...
+ break;
+ }
+ else
+ iter++;
+ }
+ // The following is a necessary dummy command for ONC RPC for not
+ // misinterpreting the above break command as a return
+ iter = sc->clientTbl.begin();
+ }
+return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcalive_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+ rpcDummy = 0;
+ unsigned long cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->aliveSignal( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcopendb_1()} is called by a clientcomm
+ object on the client system to open a database on a RasDaMan server.
+*/
+
+OpenDBRes*
+RPCFUNCTIONDEF( rpcopendb_1, OpenDBParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcOpenDBRes;
+
+ unsigned long* clientId = new unsigned long;
+
+ freeDynamicRPCData();
+
+ char client[256];
+ client[0] = '\0';
+ strcat( client, "unknown" );
+
+ const char* dbName = params->dbName;
+ const char* userName = params->userName;
+
+ RMInit::logOut << "Client called ... ";
+
+ //
+ // Create a new entry in the client table (should be moved to ServerComm):
+ //
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Create a new client table element and initialize it.
+ ServerComm::ClientTblElt* contextStore;
+ contextStore = new ServerComm::ClientTblElt( client, ++(sc->clientCount) );
+
+ // give the client id back to to client via the pointer variable
+ *clientId = sc->clientCount;
+ // Put the context information in the static control list
+ sc->clientTbl.push_back( contextStore );
+
+ // RMInit::logOut << "assigned id " << *clientId << endl;
+
+ // check acces permission
+
+ rpcOpenDBRes.status=accessControl.crunchCapability(params->capability);
+ //
+ // Open the database: (only if acces control is OK)
+ //
+ if(rpcOpenDBRes.status==0)
+ rpcOpenDBRes.status = sc->openDB( *clientId, dbName, userName );
+
+ rpcOpenDBRes.clientID = *clientId;
+ delete clientId;
+
+ // If database is not successfully opened, the client table entry is deleted again.
+ if( rpcOpenDBRes.status != 0 )
+ sc->deleteClientTblEntry( rpcOpenDBRes.clientID );
+
+ return &rpcOpenDBRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcclosedb_1()} is called by a clientcomm
+ object on the client system to close a database on a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcclosedb_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->closeDB( cci );
+
+ if( rpcDummy == 0 )
+ sc->deleteClientTblEntry( cci );
+
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpccreatedb_1()} is called by a clientcomm
+ object on the client system to create a database on a RasDaMan server.
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpccreatedb_1, char** name )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ char* dbname = *name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method. (createDB doesn't actually return something
+ // other than 0, so this can be used in later extensions)
+ rpcDummy = sc->createDB( dbname );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdestroydb_1()} is called by a clientcomm
+ object on the client system to destroy a database on a RasDaMan server.
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcdestroydb_1, char** name )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ char* dbname = *name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method. (createDB doesn't actually return something
+ // other than 0, so this can be used in later extensions)
+ rpcDummy = sc->destroyDB( dbname );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcBeginTA()} is called by a clientcomm
+ object on the client system to begin a new transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcbeginta_1, BeginTAParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // check acces permission
+ rpcDummy = accessControl.crunchCapability(params->capability);
+
+ // Call the corresponding method. (only if acces control is OK)
+ if(rpcDummy==0)
+ rpcDummy = sc->beginTA( params->clientID, params->readOnly );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcCommitTA()} is called by a clientcomm
+ object on the client system to commit the current transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpccommitta_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->commitTA( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcAbortTA()} is called by a clientcomm
+ object on the client system to abort the current transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcabortta_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->abortTA( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcexecutequery_1()} is called by a clientcomm
+ object on the client system to initiate a retrieval query execution on a RasDaMan
+ server.
+*/
+
+ExecuteQueryRes*
+RPCFUNCTIONDEF( rpcexecutequery_1, ExecuteQueryParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcExecuteQueryRes;
+
+ unsigned short returnValue;
+ unsigned long callingClientId = params->clientID;
+ const char* query = params->query;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers in case of exceptions
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ rpcExecuteQueryRes.token = prev1;
+ rpcExecuteQueryRes.typeName = prev2;
+ rpcExecuteQueryRes.typeStructure = prev3;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ returnValue = sc->executeQuery( callingClientId, (const char*) query, rpcExecuteQueryRes );
+
+ // if no exception was thrown we are here, first check if the pointers have changed
+ if( rpcExecuteQueryRes.token != prev1 ) free(prev1);
+ if( rpcExecuteQueryRes.typeName != prev2 ) free(prev2);
+ if( rpcExecuteQueryRes.typeStructure != prev3 ) free(prev3);
+
+ // than check if the pointers are NULL
+ if( !rpcExecuteQueryRes.token ) rpcExecuteQueryRes.token = strdup("");
+ if( !rpcExecuteQueryRes.typeName ) rpcExecuteQueryRes.typeName = strdup("");
+ if( !rpcExecuteQueryRes.typeStructure ) rpcExecuteQueryRes.typeStructure = strdup("");
+
+ // set missing parts of return structure
+ rpcExecuteQueryRes.status = returnValue;
+
+
+ return &rpcExecuteQueryRes;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnextmdd_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a MDD collection
+ from a RasDaMan server.
+*/
+
+GetMDDRes*
+RPCFUNCTIONDEF( rpcgetnextmdd_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnextmdd_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetMDDRes;
+
+ r_Minterval mddDomain;
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+
+ rpcGetMDDRes.typeName = prev1;
+ rpcGetMDDRes.typeStructure = prev2;
+ rpcGetMDDRes.domain = prev3;
+ rpcGetMDDRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetMDDRes.status = sc->getNextMDD( *callingClientId, mddDomain,
+ rpcGetMDDRes.typeName,
+ rpcGetMDDRes.typeStructure, oid,
+ rpcGetMDDRes.currentFormat );
+ rpcGetMDDRes.domain = mddDomain.get_string_representation();
+ rpcGetMDDRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // if no exceptions...
+ if( rpcGetMDDRes.typeName != prev1 ) free(prev1);
+ if( rpcGetMDDRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetMDDRes.domain != prev3 ) free(prev3);
+ if( rpcGetMDDRes.oid != prev4 ) free(prev4);
+
+ // prevent RPC from NULL pointers
+ if( !rpcGetMDDRes.typeName ) rpcGetMDDRes.typeName = strdup("");
+ if( !rpcGetMDDRes.typeStructure ) rpcGetMDDRes.typeStructure = strdup("");
+ // the other 2 are not null
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnextmdd_1" )
+ return &rpcGetMDDRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnextelement_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a non-MDD collection
+ from a RasDaMan server.
+*/
+
+GetElementRes*
+RPCFUNCTIONDEF( rpcgetnextelement_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnextelement_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetElementRes;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetElementRes.status = sc->getNextElement( *callingClientId, rpcGetElementRes.data.confarray_val,
+ rpcGetElementRes.data.confarray_len );
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnextelement_1" )
+ return &rpcGetElementRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure \Ref{rpcgetmddbyoid_1} is called by a clientcomm
+ object on the client system to receive an MDD by its oid.
+*/
+
+GetMDDRes*
+RPCFUNCTIONDEF( rpcgetmddbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetmddbyoid_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetMDDRes;
+
+ r_Minterval mddDomain;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+ // prevent RPC from NULL pointers if exception occur
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+
+ rpcGetMDDRes.typeName = prev1;
+ rpcGetMDDRes.typeStructure = prev2;
+ rpcGetMDDRes.domain = prev3;
+ rpcGetMDDRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetMDDRes.status = sc->getMDDByOId( params->clientID, oid, mddDomain,
+ rpcGetMDDRes.typeName,
+ rpcGetMDDRes.typeStructure,
+ rpcGetMDDRes.currentFormat );
+ rpcGetMDDRes.domain = mddDomain.get_string_representation();
+ rpcGetMDDRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetMDDRes.typeName != prev1) free(prev1);
+ if( rpcGetMDDRes.typeStructure != prev2) free(prev2);
+ if( rpcGetMDDRes.domain != prev3 ) free(prev3);
+ if( rpcGetMDDRes.oid != prev4 ) free(prev4);
+
+ if( !rpcGetMDDRes.typeName ) rpcGetMDDRes.typeName = strdup("");
+ if( !rpcGetMDDRes.typeStructure ) rpcGetMDDRes.typeStructure = strdup("");
+ // the other 2 are not null
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetmddbyoid_1" )
+ return &rpcGetMDDRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnexttile_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a MDD collection
+ from a RasDaMan server.
+*/
+
+GetTileRes*
+RPCFUNCTIONDEF( rpcgetnexttile_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnexttile_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetTileRes;
+
+ freeDynamicRPCData();
+
+ // fake data for security
+ RPCMarray *secureRpcMarray = (RPCMarray*)mymalloc(sizeof(RPCMarray));
+ secureRpcMarray->domain = strdup("");
+ secureRpcMarray->cellTypeLength = 1;
+ secureRpcMarray->currentFormat = 1;
+ secureRpcMarray->storageFormat = 1;
+ secureRpcMarray->data.confarray_len = 1;
+ secureRpcMarray->data.confarray_val = strdup("");
+
+ rpcGetTileRes.marray = secureRpcMarray;
+
+ RPCMarray *tempRpcMarray;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetTileRes.status = sc->getNextTile( *callingClientId, &tempRpcMarray); //&rpcGetTileRes.marray );
+ // if this throws, secure... is nice initialized
+
+ rpcGetTileRes.marray = tempRpcMarray;
+
+ free(secureRpcMarray->data.confarray_val);
+ free(secureRpcMarray->domain);
+ free(secureRpcMarray);
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnexttile_1" )
+ return &rpcGetTileRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcendtransfer_1, unsigned long* callingClientId )
+{
+ unsigned long cci = *callingClientId;
+
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->endTransfer( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcinitexecuteupdate_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->initExecuteUpdate( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcexecuteupdate_1()} is called by a clientcomm
+ object on the client system to initiate an update query execution on a RasDaMan
+ server.
+*/
+
+ExecuteUpdateRes*
+RPCFUNCTIONDEF( rpcexecuteupdate_1, ExecuteQueryParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcExecuteUpdateRes;
+
+ unsigned short returnValue;
+ unsigned long callingClientId = params->clientID;
+ const char* query = params->query;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ rpcExecuteUpdateRes.token = prev1;
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ returnValue = sc->executeUpdate( callingClientId, (const char*) query, rpcExecuteUpdateRes );
+
+ // set missing parts of return structure
+ rpcExecuteUpdateRes.status = returnValue;
+
+ // prevent RPC from NULL pointers
+ if( rpcExecuteUpdateRes.token != prev1 ) free(prev1);
+
+ if( !rpcExecuteUpdateRes.token ) rpcExecuteUpdateRes.token = strdup("");
+
+ return &rpcExecuteUpdateRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcstartinserttransmdd_1, InsertTransMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ // const char* collName = params->collName; // not used
+ const char* typeName = params->typeName;
+ unsigned long typeLength = params->typeLength;
+ r_Minterval mddDomain( params->domain );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->startInsertTransMDD( callingClientId, mddDomain, typeLength, typeName );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcstartinsertpersmdd_1, InsertPersMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+ unsigned long typeLength = params->typeLength;
+ r_Minterval mddDomain( params->domain );
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->startInsertPersMDD( callingClientId, (const char*) collName, mddDomain, typeLength, typeName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcinserttile_1, InsertTileParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertTile( params->clientID, params->isPersistent, params->marray );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcendinsertmdd_1, EndInsertMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->endInsertMDD( params->clientID, params->isPersistent );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcInsertMDD()} is called by a clientcomm
+ object on the client system to insert a MDD object in an existing MDD
+ collection on a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcinsertmdd_1, InsertMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+ RPCMarray* rpcMarray = params->marray;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertMDD( callingClientId, collName, rpcMarray, typeName, oid );
+
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcollbyname_1()} is called by a clientcomm
+ object on the client system to initiate the lookup of a MDD collection by its name
+ on a RasDaMan server.
+*/
+
+GetCollRes*
+RPCFUNCTIONDEF( rpcgetcollbyname_1, NameSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollRes;
+
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollRes.typeName = prev1;
+ rpcGetCollRes.typeStructure = prev2;
+ rpcGetCollRes.oid = prev3;
+ rpcGetCollRes.collName = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollRes.status = sc->getCollByName( callingClientId, collName,
+ rpcGetCollRes.typeName,
+ rpcGetCollRes.typeStructure, oid );
+
+ rpcGetCollRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ rpcGetCollRes.collName = params->name ? strdup( params->name ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollRes.typeName != prev1) free(prev1);
+ if( rpcGetCollRes.typeStructure != prev2) free(prev2);
+ if( rpcGetCollRes.oid != prev3) free(prev3);
+ if( rpcGetCollRes.collName != prev4) free(prev4);
+
+ if( !rpcGetCollRes.typeName ) rpcGetCollRes.typeName = strdup("");
+ if( !rpcGetCollRes.typeStructure ) rpcGetCollRes.typeStructure = strdup("");
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyname_1" )
+ return &rpcGetCollRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcollbyoid_1()} is called by a clientcomm
+ object on the client system to initiate the lookup of a MDD collection by its oid
+ on a RasDaMan server.
+*/
+
+GetCollRes*
+RPCFUNCTIONDEF( rpcgetcollbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyoid_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollRes;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollRes.typeName = prev1;
+ rpcGetCollRes.typeStructure = prev2;
+ rpcGetCollRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollRes.status = sc->getCollByOId( callingClientId, oid, rpcGetCollRes.typeName,
+ rpcGetCollRes.typeStructure, rpcGetCollRes.collName );
+
+ rpcGetCollRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollRes.typeName != prev1) free(prev1);
+ if( rpcGetCollRes.typeStructure != prev2) free(prev2);
+ if( rpcGetCollRes.collName != prev3) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollRes.typeName ) rpcGetCollRes.typeName = strdup("");
+ if( !rpcGetCollRes.typeStructure ) rpcGetCollRes.typeStructure = strdup("");
+ if( !rpcGetCollRes.collName ) rpcGetCollRes.collName = strdup("");
+ // oid is not null,
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyoid_1" )
+ return &rpcGetCollRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcolloidsbyname_1()} is called by a clientcomm
+ object on the client system to retrieve the collection of oids by the collection's name.
+*/
+
+GetCollOIdsRes*
+RPCFUNCTIONDEF( rpcgetcolloidsbyname_1, NameSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollOidsRes;
+
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollOidsRes.typeName = prev1;
+ rpcGetCollOidsRes.typeStructure = prev2;
+ rpcGetCollOidsRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollOidsRes.status = sc->getCollOIdsByName( callingClientId, collName, rpcGetCollOidsRes.typeName,
+ rpcGetCollOidsRes.typeStructure, oid,
+ rpcGetCollOidsRes.oidTable.oidTable_val, rpcGetCollOidsRes.oidTable.oidTable_len );
+
+ rpcGetCollOidsRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ rpcGetCollOidsRes.collName = params->name ? strdup( params->name ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollOidsRes.typeName != prev1 ) free(prev1);
+ if( rpcGetCollOidsRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetCollOidsRes.collName != prev3 ) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollOidsRes.typeName ) rpcGetCollOidsRes.typeName = strdup("");
+ if( !rpcGetCollOidsRes.typeStructure ) rpcGetCollOidsRes.typeStructure = strdup("");
+ if( !rpcGetCollOidsRes.collName ) rpcGetCollOidsRes.collName = strdup("");
+ // oid is not null
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+ return &rpcGetCollOidsRes;
+}
+
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcolloidsbyoid_1()} is called by a clientcomm
+ object on the client system to retrieve the collection of oids by the collection's oid.
+*/
+
+GetCollOIdsRes*
+RPCFUNCTIONDEF( rpcgetcolloidsbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollOidsRes;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollOidsRes.typeName = prev1;
+ rpcGetCollOidsRes.typeStructure = prev2;
+ rpcGetCollOidsRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollOidsRes.status = sc->getCollOIdsByOId( callingClientId, oid,
+ rpcGetCollOidsRes.typeName,
+ rpcGetCollOidsRes.typeStructure,
+ rpcGetCollOidsRes.oidTable.oidTable_val,
+ rpcGetCollOidsRes.oidTable.oidTable_len,
+ rpcGetCollOidsRes.collName );
+
+ rpcGetCollOidsRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollOidsRes.typeName != prev1 ) free(prev1);
+ if( rpcGetCollOidsRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetCollOidsRes.collName != prev3 ) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollOidsRes.typeName ) rpcGetCollOidsRes.typeName = strdup("");
+ if( !rpcGetCollOidsRes.typeStructure ) rpcGetCollOidsRes.typeStructure = strdup("");
+ if( !rpcGetCollOidsRes.collName ) rpcGetCollOidsRes.collName = strdup("");
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+ return &rpcGetCollOidsRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcinsertcoll_1()} is called by a clientcomm
+ object on the client system to create a MDD collection for further use on
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcinsertcoll_1, InsertCollParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ r_OId oid( params->oid );
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertColl( callingClientId, collName, typeName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdeletecollbyname_1()} is called by a clientcomm
+ object on the client system to delete a existing MDD collection.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcdeletecollbyname_1, NameSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->deleteCollByName( callingClientId, collName );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdeleteobjbyoid_1()} is called by a clientcomm
+ object on the client system to delete an object specified by oid.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcdeleteobjbyoid_1, OIdSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->deleteObjByOId( callingClientId, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcremoveobjfromcoll_1()} is called by a clientcomm
+ object on the client system to delete an object from a collection.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcremoveobjfromcoll_1, RemoveObjFromCollParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->removeObjFromColl( callingClientId, collName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+*/
+
+ObjectTypeRes*
+RPCFUNCTIONDEF( rpcgetobjecttype_1, OIdSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&procResult;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToRead();
+
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ r_OId oid( params->oid );
+
+ procResult.status = sc->getObjectType( params->clientID, oid, procResult.objType );
+
+ // Return the result
+ return &procResult;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+*/
+
+OIdRes*
+RPCFUNCTIONDEF( rpcgetnewoid_1, NewOIdParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcOidRes;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ rpcOidRes.oid = prev1;
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ r_OId oid;
+
+ rpcOidRes.status = sc->getNewOId( params->clientID, params->objType, oid );
+ rpcOidRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ free(prev1);
+
+ // Return the result
+ return &rpcOidRes;
+}
+
+
+// Callback for callback manager, performs actual garbage collection.
+// The context points to the ServerComm object (see registering call in
+// garbageCollection() )
+static void callback_garbage_collection(void *context)
+{
+ ServerComm *sc = (ServerComm*)context;
+
+ if( sc && !sc->clientTbl.empty() )
+ {
+ RMInit::dbgOut << "Garbage Collection ... " << flush;
+
+#ifdef RMANDEBUG
+ sc->printServerStatus( RMInit::dbgOut );
+#endif
+
+ if (!noTimeOut)
+ {
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ iter = sc->clientTbl.begin();
+ unsigned long now = time( NULL );
+
+ RMDBGONCE(2, RMDebug::module_servercomm, "Manager", "checking " << sc->clientTbl.size() << " clients..." );
+ while ( iter != sc->clientTbl.end() )
+ {
+ if( now - (*iter)->lastActionTime >= sc->clientTimeout )
+ {
+ RMInit::logOut << "Message: Found timed-out client with id " << (*iter)->clientId
+ << " (" << (*iter)->clientIdText << ", "
+ << now - (*iter)->lastActionTime << "s)..." << flush;
+
+ if( sc->deleteClientTblEntry( (*iter)->clientId ) == 0 )
+ {
+ RMInit::logOut << "deleted." << endl;
+
+ sc->informRasMGR(SERVER_AVAILABLE);
+ // reset the iterator (otherwise, it would skip one object
+ // because one was deleted)
+ iter = sc->clientTbl.begin();
+ }
+ else
+ {
+ RMInit::logOut << "deletion postponed." << endl;
+ iter++;
+ }
+ }
+ else
+ iter++;
+ }
+ }
+ RMInit::dbgOut << "garbage collection done." << endl;
+ }
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+void
+garbageCollection( int )
+{
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ /*
+ * Just register the callbacks because we're not allowed to do any
+ * mallocs or prints in the alarm handler environment. The pending
+ * callbacks will be executed whenever there's RPC activity.
+ */
+ sc->callback_mgr.registerUniqueCallback(callback_garbage_collection, (void*)sc);
+
+ // Re-initialize the signal handler to point to this function
+ signal( SIGALRM, garbageCollection);
+
+ // Reset the alarm
+ alarm( (unsigned int)sc->garbageCollectionInterval );
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+void
+garbageCollectionDummy( int )
+{
+ /* Dummy garbage collection function for avoiding reentrance of the callback manager.
+ Does nothing but reinstall the signal. */
+ signal( SIGALRM, garbageCollection);
+ alarm( (unsigned int)(ServerComm::actual_servercomm->garbageCollectionInterval) );
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+GetTypeStructureRes*
+RPCFUNCTIONDEF( rpcgettypestructure_1, GetTypeStructureParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcGetTypeStructureRes;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ rpcGetTypeStructureRes.typeStructure = prev1;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetTypeStructureRes.status = sc->getTypeStructure( params->clientID, params->typeName,
+ params->typeType, rpcGetTypeStructureRes.typeStructure );
+
+ // prevent RPC from NULL pointers
+ if( rpcGetTypeStructureRes.typeStructure != prev1 ) free(prev1);
+
+ if( !rpcGetTypeStructureRes.typeStructure ) rpcGetTypeStructureRes.typeStructure = strdup("");
+
+ // Return the result
+ return &rpcGetTypeStructureRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+int*
+RPCFUNCTIONDEF( rpcgetserverendian_1, int * )
+{
+ freeDynamicRPCData();
+
+ static int result;
+
+#ifdef LITTLE_ENDIAN
+ result = 1;
+#else
+ result = 0;
+#endif
+
+ return &result;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+unsigned short*
+RPCFUNCTIONDEF( rpcsetservertransfer_1, SetServerTransferParams* params )
+{
+ freeDynamicRPCData();
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcDummy = (unsigned short)(sc->setTransferMode( params->clientID, params->format, params->formatParams ));
+
+ return &rpcDummy;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+GetExtendedErrorInfo *
+RPCFUNCTIONDEF( rpcgeterrorinfo_1, void * params )
+{
+ freeDynamicRPCData();
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcExtendedErrorInfo.errorText = (char*) sc->getExtendedErrorInfo();
+
+ return &rpcExtendedErrorInfo;
+}
+
+#ifdef LINUX
+extern "C"
+#endif
+unsigned short*
+RPCFUNCTIONDEF( rpcsetserverstorage_1, SetServerTransferParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcDummy = (unsigned short)(sc->setStorageMode(params->clientID, params->format, params->formatParams ));
+
+ return &rpcDummy;
+}
+
diff --git a/servercomm/servercomm.cc b/servercomm/servercomm.cc
new file mode 100644
index 0000000..5982453
--- /dev/null
+++ b/servercomm/servercomm.cc
@@ -0,0 +1,1399 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: servercomm.cc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+// --- these defs should go into a central constant definition section,
+// as they define externally observable behavior -- PB 2003-nov-15
+
+// waiting period until client is considered dead [secs]
+#define CLIENT_TIMEOUT 3600
+
+// timeout for select() call at server startup [secs]
+#define TIMEOUT_SELECT 30
+
+// period after which the next garbage collection is scheduled [secs]
+#define GARBCOLL_INTERVAL 600
+
+// console output describing successful/unsuccessful actions
+#define MSG_OK "ok"
+#define MSG_FAILED "failed"
+
+// rasserver exit codes (selection of value sometimes unclear :-(
+#define EXITCODE_ZERO 0
+#define EXITCODE_ONE 1
+#define EXITCODE_RASMGR_FAILED 10 // Why 10 ?
+// ---
+
+static const char rcsid[] = "@(#)servercomm, ServerComm: $Id: servercomm.cc,v 1.146 2006/01/03 00:23:53 rasdev Exp $";
+
+#include<openssl/evp.h>
+
+#include <iostream>
+#include <malloc.h>
+#include <time.h> // for time()
+#include <string.h>
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm(), gethostname()
+#include <iomanip>
+
+#ifdef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+
+ int _rpcpmstart = 0;
+
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#include <rpc/pmap_clnt.h>
+
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/parseparams.hh"
+#include "compression/tilecompression.hh"
+
+#include "servercomm/servercomm.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtdata.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "mddmgr/mddobj.hh"
+
+#include "debug.hh"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+#include<stdio.h>
+#include<stdlib.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<iostream>
+
+using namespace std;
+// init globals for server initialization
+// RMINITGLOBALS('S')
+
+// Once again a function prototype. The first one is for the RPC dispatcher
+// function located in the server stub file rpcif_svc.c and the second one
+// is for the garbage collection function pointed to by the signal handler.
+extern "C"
+{
+ // void rpcif_1( struct svc_req*, register SVCXPRT* );
+ void garbageCollection( int );
+}
+extern char* rpcif_1( struct svc_req*, register SVCXPRT* );
+extern bool bMemFailed;
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+extern unsigned long maxTransferBufferSize;
+
+// At the beginning, no servercomm object exists.
+ServerComm* ServerComm::actual_servercomm = 0;
+
+list<ServerComm::ClientTblElt*> ServerComm::clientTbl;
+unsigned long ServerComm::clientCount = 0;
+
+#include "rnprotocol/srvrasmgrcomm.hh"
+
+extern SrvRasmgrComm rasmgrComm;
+
+/*************************************************************************
+ * Method name...: ServerComm() (constructor)
+ ************************************************************************/
+ServerComm::ServerComm()
+ : clientTimeout( rasmgrComm.getTimeout() ),
+ garbageCollectionInterval( GARBCOLL_INTERVAL ),
+ transactionActive( 0 ),
+ memUsed( 0 ),
+ admin( 0 ),
+ errorText( 0 )
+{
+ if( actual_servercomm )
+ {
+ RMInit::logOut << "Internal Error: Tried to instantiate more than one ServerComm object." << endl;
+ exit( EXITCODE_ONE );
+ }
+
+ // uniqueClientContext = NULL;
+ isHttpServer = false;
+
+ actual_servercomm = this;
+}
+
+ServerComm::ServerComm( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName)
+ : clientTimeout( timeOut ),
+ garbageCollectionInterval( managementInterval ),
+ transactionActive( 0 ),
+ memUsed( 0 ),
+ admin( 0 ),
+ errorText( 0 )
+{
+ if( actual_servercomm )
+ {
+ RMInit::logOut << "Internal Error: Tried to instantiate more than one ServerComm object." << endl;
+ exit( EXITCODE_ONE );
+ }
+
+ actual_servercomm = this;
+ this->listenPort = listenPort;
+ this->rasmgrHost = rasmgrHost;
+ this->rasmgrPort = rasmgrPort;
+ this->serverName = serverName;
+
+ isHttpServer = false;
+ //uniqueClientContext = NULL;
+}
+
+
+
+/*************************************************************************
+ * Method name...: ~ServerComm() (destructor)
+ ************************************************************************/
+ServerComm::~ServerComm()
+{
+ // delete communication object
+ if( admin ) delete admin;
+
+ actual_servercomm = 0;
+}
+
+/*************************************************************************
+ * Method name...: startRpcServer()
+ ************************************************************************/
+void rpcSignalHandler(int sig);
+void our_svc_run();
+
+void
+ServerComm::startRpcServer()
+ throw( r_Error )
+{
+ // create administraion object (O2 session is initialized)
+ admin = AdminIf::instance();
+ if( !admin )
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ register SVCXPRT *transp;
+
+ // install a signal handler to catch alarm signals for garbage collection
+ signal( SIGALRM, garbageCollection );
+
+ RMInit::logOut << "Testing if no other rasdaman RPC server with my listenPort (0x"<< hex << listenPort << dec <<") is already running on this CPU..." << flush;
+
+
+ char* myName = new char[256];
+
+ if( gethostname( myName, 256 ) )
+ RMInit::logOut << endl << "Unable to determine my own hostname. Skipping this test." << endl;
+ else
+ if( clnt_create( myName, listenPort, RPCIFVERS, "tcp" ) )
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ exit( EXITCODE_ZERO );
+ }
+ else
+ RMInit::logOut << MSG_OK << endl;
+
+ delete[] myName;
+
+ (void) pmap_unset(listenPort, RPCIFVERS);
+
+ RMInit::logOut << "Creating UDP services..." << flush;
+ transp = svcudp_create(RPC_ANYSOCK);
+ if (transp == NULL)
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ RMInit::logOut << "registering UDP interface..." << flush;
+ if (!svc_register(transp, listenPort, RPCIFVERS, rpcif_1_caller, IPPROTO_UDP))
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Creating TCP services..." << flush;
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (transp == NULL)
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ RMInit::logOut << "registering TCP interface..." << flush;
+ if (!svc_register(transp, listenPort, RPCIFVERS, rpcif_1_caller, IPPROTO_TCP))
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Setting alarm clock for next garbage collection to " << garbageCollectionInterval
+ << " secs..."; RMInit::logOut.flush();
+ alarm( (unsigned int)garbageCollectionInterval );
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Global query optimization level is " << globalOptimizationLevel << "." << endl;
+
+ signal (SIGTERM, rpcSignalHandler);
+ informRasMGR(SERVER_AVAILABLE);
+ RMInit::logOut << "rasdaman server "<<serverName<<" is up." << endl;
+
+ // now wait for client calls (exception guarded)
+#ifdef PURIFY
+ purify_printf( "Server startup finished." );
+ purify_new_leaks();
+#endif
+ // svc_run();
+ our_svc_run();
+}
+
+extern "C" {
+ void garbageCollection( int );
+ void garbageCollectionDummy ( int );
+}
+
+void our_svc_run()
+{
+ ENTER( "our_svc_run" );
+
+ fd_set read_fd_set;
+
+ // TALK( "tcp_socket="<<get_socket(&svc_fdset,0) );
+
+ struct timeval timeout;
+ timeout.tv_sec= TIMEOUT_SELECT;
+ timeout.tv_usec=0;
+
+ while(1)
+ {
+ read_fd_set=svc_fdset;
+ TALK( "RPC Server is waiting..." );
+
+ int rasp=select(FD_SETSIZE,&read_fd_set,NULL,NULL,&timeout);
+ TALK( "RPC select returns: " << rasp );
+ if(rasp>0)
+ {
+ svc_getreqset(&read_fd_set);
+ TALK( "RPC Request executed." );
+ }
+
+ if(rasp<=0)
+ {
+ TALK( "our_svc_run(): Error: Timeout." ); // or a signal
+ // execute all pending callbacks. Redirect alarm signal first to make sure no
+ // reentrance is possible!
+
+ // these should abort any pending transaction
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ signal( SIGALRM, garbageCollection );
+ timeout.tv_sec= TIMEOUT_SELECT;
+ timeout.tv_usec=0;
+
+ if(accessControl.isClient()==false)
+ {
+ // regularly tell the rasmgr that we are available. There is a scenario for DoS-attack (or bug, or firewall-problem)
+ // when a client allocates itself a server and never calls, so the server is not usable any more.
+ // but we have to find a smarter way of doing this, we need rasmgr-rasserver communication!
+ ServerComm::actual_servercomm->informRasMGR(SERVER_REGULARSIG);
+ }
+ if(bMemFailed)
+ {
+ // no reason to continue
+ RMInit::logOut << "Internal error: rasserver: memory exhausted." << endl << flush;
+ exit( EXITCODE_ONE );
+ }
+ }
+ }
+
+ LEAVE( "our_svc_run" );
+}
+
+
+void rpcSignalHandler(int sig)
+{
+ static int in_progress=0; // our sema to prevent signal-in-signal
+
+ if (in_progress)
+ return;
+
+ in_progress = 1;
+
+ // busy wait
+#define SIGNAL_WAIT_CYCLES 1000000
+ for(long j=0;j<SIGNAL_WAIT_CYCLES;j++)
+ ;
+
+ // if we have a valid server, stop it
+ if(ServerComm::actual_servercomm)
+ {
+ ServerComm::actual_servercomm->stopRpcServer();
+ }
+} // rpcSignalHandler()
+
+void
+ServerComm::stopRpcServer()
+{
+ RMInit::logOut << "Shutdown request received." << endl;
+
+ // Determine when next garbage collection would have occured
+ unsigned long nextGarbColl = time( NULL );
+ struct itimerval rttimer;
+ getitimer( ITIMER_REAL, &rttimer );
+ nextGarbColl += rttimer.it_value.tv_sec;
+ RMInit::logOut << "Next garbage collection would have been in " << rttimer.it_value.tv_sec << " sec, at "
+ << ctime((time_t*)&nextGarbColl);
+
+ RMInit::logOut << "Unregistering interface...";
+ svc_unregister( listenPort, RPCIFVERS );
+
+ RMInit::logOut << "shutting down services...";
+ abortEveryThingNow();
+
+ RMInit::logOut << "informing rasmgr...";
+ informRasMGR(SERVER_DOWN);
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "rasdaman server " << serverName <<" is down." << endl;
+
+ exit(0);
+ // svc_exit();
+}
+
+// quick hack function used when stopping server to abort transaction and close db
+void
+ServerComm::abortEveryThingNow()
+{
+ ENTER( "ServerComm::abortEveryThingNow()" );
+
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ iter = sc->clientTbl.begin();
+
+ while ( iter != sc->clientTbl.end() )
+ {
+ ServerComm::ClientTblElt *clnt = *iter;
+
+ clnt->transaction.abort();
+ clnt->database.close();
+
+ iter++;
+ }
+
+ LEAVE( "ServerComm::abortEveryThingNow()" );
+}
+
+/*************************************************************************
+ * rpcif_1_caller(struct svc_req *rqstp, SVCXPRT *transp)
+ * indirect caller for rpcif_1, which is automaticaly generated and can't
+ * be hand-edited. It provides services for parallel-processing
+ *************************************************************************/
+void rpcif_1_caller(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ ENTER( "rpcif_1_caller(_,_)" );
+
+ bool flagTransactionReady=false;
+
+ bool isGetExtendedError=false;
+
+ switch (rqstp->rq_proc)
+ {
+ //case RPCCOMMITTA: no, closeDB only, because abortTA and commitTA
+ //case RPCABORTTA: do automatically a closeDB and both reporting to RasMGR "available" brings problems
+
+ case RPCCLOSEDB: flagTransactionReady=true; break;
+
+ case RPCGETERRORINFO: isGetExtendedError = true; break;
+ }
+
+ if(isGetExtendedError == false) ServerComm::actual_servercomm->clearExtendedErrorInfo();
+
+ char* errTxt = rpcif_1(rqstp,transp);
+
+ if(isGetExtendedError && bMemFailed) {
+ // the client got the message
+ // no reason to continue
+
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ RMInit::logOut << "Internal error: rasserver panic: memory exhausted, terminating forcefully." << endl << flush;
+ exit(1);
+ }
+
+ if (errTxt)
+ {
+ // this is not necessary, since the client gets an error code '42'
+ //RMInit::logOut << "rasserver: general exception from server caught by rpcif_1_caller!" << endl << errTxt << endl;
+ //RMInit::logOut.flush();
+ //cerr << "rasserver: general exception from server caught by rpcif_1_caller!" << endl << errTxt << endl;
+ ServerComm::actual_servercomm->setExtendedErrorInfo(errTxt);
+ free(errTxt);
+ errTxt = 0;
+
+ //Answer "Remote system error " to the client
+ //svcerr_systemerr (transp); don't think that's necessary any more, for the same reason
+ }
+
+ ServerComm::actual_servercomm->clientEndRequest();
+
+ if(flagTransactionReady)
+ ServerComm::actual_servercomm->informRasMGR(SERVER_AVAILABLE);
+
+ LEAVE( "rpcif_1_caller()" );
+}
+
+
+/*************************************************************************
+ * Method name...: informRasMGR( int what ) with a helper function
+ ************************************************************************/
+#include <errno.h>
+
+// writeWholeMessage:
+// send message via (open, connected) socket to rasmgr
+// called by informRasMGR.
+// return values:
+// -1 error
+// >0 success
+
+int writeWholeMessage(int socket,char *destBuffer,int buffSize)
+{
+ ENTER( "writeWholeMessage( socket=" << socket << ", destBuffer=" << (destBuffer?destBuffer:"(null)") << ", buffSize=" << buffSize << " )" );
+
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ {
+ TALK( "writeWholeMessage: bad socket write returned " << writeNow << ", errno=" << errno );
+ if(errno == EINTR)
+ continue; // read was interrupted by signal (on bad SO's)
+ LEAVE( "writeWholeMessage(): error, errno=" << errno );
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize )
+ break; // THE END
+ }
+
+ LEAVE( "writeWholeMessage() -> " << totalLength );
+ return totalLength;
+}
+
+
+long infCount=0; // for debug only
+
+// ServerComm::informRasMGR:
+// send message code to rasmgr (e.g., "still alive"), incl socket management
+// return code:
+// none, but function does exit() on error 8-()
+void ServerComm::informRasMGR( int what )
+{
+ ENTER( "ServerComm::informRasMGR, what=" << what );
+ TALK( "Informing dispatcher " << rasmgrHost << " port=" << rasmgrPort << " that server is available" );
+ //what: 0 - going down
+ // 1 - available
+ // 2 - regular signal
+
+ if (what == SERVER_AVAILABLE)
+ accessControl.resetForNewClient();
+
+ struct protoent* getprotoptr = getprotobyname("tcp");
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+ if (hostinfo==NULL)
+ {
+ cerr<< serverName<<": informRasMGR: cannot locate RasMGR host "<<rasmgrHost<<" ("<<strerror(errno)<<')'<<endl;
+ RMInit::logOut << "informRasMGR: cannot locate RasMGR host "<<rasmgrHost<<" ("<<strerror(errno)<<')'<<endl;
+ LEAVE( "ServerComm::informRasMGR: cannot locate RasMGR host "<<rasmgrHost << ": " << strerror(errno) );
+ return;
+ }
+
+ sockaddr_in internetSocketAddress;
+ internetSocketAddress.sin_family = AF_INET;
+ internetSocketAddress.sin_port=htons(rasmgrPort);
+ internetSocketAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ int sock; // socket for rasmgr communication
+ bool ok=false; // did we get a socket?
+
+ // FIXME: This is _extremely_ ugly. Should be something like
+ // 10 retries, with exponentially growing waits, such as 0, 1ms, 2ms, 4ms, ...
+ // have prepared defs, but code is the original one. -- PB 2003-nov-15
+ // long maxRetry = NUM_RETRIES_SERVER_ALIVE;
+ // #define NUM_RETRIES_SERVER_ALIVE 10
+
+ long retry =0;
+ long maxRetry=10000000; // ten millions!
+ long talkInterval=100000;
+ // creating socket
+ for(retry=0;retry<maxRetry;retry++)
+ {
+ int result;
+
+ // BEWARE, is this relevant? -- PB 2003-nov-15
+ // man 7 socket says:
+ // "Under some circumstances (e.g. multiple processes
+ // accessing a single socket), the condition that caused
+ // the SIGIO may have already disappeared when the process
+ // reacts to the signal. If this happens, the process
+ // should wait again because Linux will resend the signal later."
+
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ TALK( "Socket=" << sock << " protocol(tcp)=" << getprotoptr->p_proto );
+
+ if(sock<0)
+ {
+ // if ( (retry%talkInterval) == 0)
+ {
+ cerr << "Error in server '" << serverName << "': cannot open socket to rasmgr, (" << strerror(errno) << ')' << " still retrying..." << endl;
+ TALK( "ServerComm::informRasMGR: cannot open socket to RasMGR: " << strerror(errno) << "; retry " << retry << " of " << maxRetry );
+ RMInit::logOut << "Error: cannot open socket to rasmgr, (" << strerror(errno) << ')'<<endl;
+ }
+ continue;
+ }
+ result = connect(sock,(struct sockaddr*)&internetSocketAddress,sizeof(internetSocketAddress));
+ TALK( "connect(socket=" << sock << ",htons(" << rasmgrPort << ")=" << internetSocketAddress.sin_port << ",in_addr=" << internetSocketAddress.sin_addr.s_addr << ")->" << result );
+ if (result < 0)
+ {
+ // if( (retry%talkInterval) == 0)
+ {
+ cerr << "Error in server '" << serverName << "': Connection to rasmgr failed (still retrying): "<<strerror(errno);
+ cerr << ". retry #" << retry << " of " << maxRetry << endl;
+ TALK( "ServerComm::informRasMGR: cannot connect to RasMGR: " << strerror(errno) << "; retry " << retry << " of " << maxRetry );
+ RMInit::logOut <<"Error: Cannot connect to rasmgr ("<<strerror(errno)<<')';
+ RMInit::logOut << " retry #" << retry << " of " << maxRetry << endl;
+ }
+ close(sock); //yes, some SO require this, like Tru64
+ continue;
+ }
+ ok = true;
+ break;
+ } // for
+
+ if ( !ok )
+ {
+ cerr << "Error in server '" << serverName << "': Giving up on connecting, terminating." << endl;
+ RMInit::logOut << "Error: Giving up on connecting, terminating." << endl;
+ if (sock)
+ close(sock);
+
+ // FIXME: see below
+ exit( EXITCODE_RASMGR_FAILED );
+ }
+
+ // create HTTP message
+ char message[200];
+ sprintf(message,"%s%d\r\n\r\n%s %d %ld ","POST rasservernewstatus HTTP/1.1\r\nUserAgent: RasServer/1.0\r\nContent-length: ",strlen(serverName)+3,serverName,what,infCount++);
+
+ // writing message;
+ if(writeWholeMessage(sock,message,strlen(message)+1)<0)
+ {
+ RMInit::logOut <<"Error: Connection to rasmgr failed. ("<<strerror(errno)<<')'<<endl;
+ close(sock);
+
+ // FIXME: extremely ugly. replace by retcode which
+ // prevents rasserver from going into svc_run loop
+ // -- PB 2003-nov-15
+ exit( EXITCODE_RASMGR_FAILED );
+ }
+ close(sock);
+
+ LEAVE( "ServerComm::informRasMGR, ok=" << ok << ", retries=" << retry );
+} // ServerComm::informRasMGR()
+
+
+/*************************************************************************
+ * Method name...: getClientContext( unsigned long clientId )
+ ************************************************************************/
+ServerComm::ClientTblElt*
+ServerComm::getClientContext( unsigned long clientId )
+{
+ ENTER( "ServerComm::getClientContext( " << clientId << " )" );
+
+ ClientTblElt* returnValue=0;
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+
+ iter = clientTbl.begin();
+ while( iter != clientTbl.end() && (*iter)->clientId != clientId )
+ {
+ TALK( " inspecting entry with clientID " << (*iter)->clientId );
+ iter++;
+ }
+
+ if( iter != clientTbl.end() && clientId && (*iter)->clientId == clientId )
+ {
+ returnValue = *iter;
+
+ // Valid entry was found, so increase the number of current users and
+ // reset the client's lastActionTime to now.
+
+ (*iter)->currentUsers++;
+ (*iter)->lastActionTime = time( NULL );
+ TALK( "valid entry found, current users now: " << (*iter)->currentUsers );
+ }
+ }
+
+ // this output will be done lateron, in the caller:
+ // if( returnValue == 0 )
+ // RMInit::logOut << "Error: client not registered." << endl;
+
+ // this trick did not work, broke the HTTP server
+ // if(isHttpServer==false ) uniqueClientContext = returnValue;
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // pretty verbose
+#endif
+
+ LEAVE( "ServerComm::getClientContext()" );
+ return returnValue;
+}
+
+void
+ServerComm::clientEndRequest()
+{
+ ENTER( "ServerComm::clientEndRequest()" );
+
+#ifdef RMANDEBUG
+ printServerStatus( RMInit::dbgOut ); // pretty verbose
+#endif
+
+ // this trick did not work, broke the HTTp server
+
+ // if(isHttpServer==false && uniqueClientContext != NULL)
+ // uniqueClientContext->endRequest();
+
+ LEAVE( "ServerComm::clientEndRequest()" );
+}
+
+/*************************************************************************
+ * Method name...: printServerStatus( )
+ ************************************************************************/
+void
+ServerComm::printServerStatus( ostream& s )
+{
+ unsigned long currentTime = time(NULL);
+
+ s << "Server state information at " << endl; // << ctime((time_t*)&currentTime) << endl;
+ s << " Inactivity time out of clients.: " << clientTimeout << " sec" << endl;
+ s << " Server management interval.....: " << garbageCollectionInterval << " sec" << endl;
+ s << " Transaction active.............: " << ( transactionActive ? "yes" : "no" ) << endl;
+ s << " Max. transfer buffer size......: " << maxTransferBufferSize << " bytes" << endl;
+ s << " Next available cliend id.......: " << clientCount+1 << endl;
+ s << " No. of client table entries....: " << clientTbl.size() << endl << endl;
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+
+ // display contents of client table
+ s << "client table dump---------------------------------------------" << endl;
+ for( iter = clientTbl.begin(); iter != clientTbl.end(); iter++ )
+ {
+ if (*iter==NULL)
+ {
+ s << "Error: null context found." << endl;
+ RMInit::logOut << "Error: null context found." << endl;
+ continue;
+ }
+
+ s << "Client ID : " << (*iter)->clientId << endl
+ << "Current Users : " << (*iter)->currentUsers << endl
+ << "Client location: " << (*iter)->clientIdText << endl
+ << "User name : " << (*iter)->userName << endl
+ << "Database in use: " << (*iter)->baseName << endl
+ << "Creation time : " << endl // ctime((time_t*)&(*iter)->creationTime)
+ << "Last action at : " << endl // ctime((time_t*)&(*iter)->lastActionTime)
+ << "MDD collection : " << (*iter)->transferColl << endl
+ << "MDD iterator : " << (*iter)->transferCollIter << endl
+ << "Current PersMDD: " << (*iter)->assembleMDD << endl
+ << "Current MDD : " << (*iter)->transferMDD << endl
+ << "Tile vector : " << (*iter)->transTiles << endl
+ << "Tile iterator : " << (*iter)->tileIter << endl
+ << "Block byte cntr: " << (*iter)->bytesToTransfer << endl << endl;
+ }
+ s << "end client table dump-----------------------------------------" << endl;
+
+ }
+
+ /*
+ s << "memory map----------------------------------------------------" << endl;
+
+ // memorymap(1);
+
+ struct mallinfo meminfo = mallinfo();
+
+ s << "space in arena : " << meminfo.arena << endl;
+ s << "number of small blocks : " << meminfo.smblks << endl;
+ s << "number of ordinary blocks : " << meminfo.ordblks << endl;
+ s << "space in free ordinary blocks : " << meminfo.fordblks << endl;
+ s << "space in used ordinary blocks : " << meminfo.uordblks << endl;
+
+ s << "additional space from last call: " << meminfo.uordblks - memUsed << endl;
+
+ memUsed = meminfo.uordblks;
+
+ s << "end memory map------------------------------------------------" << endl << endl;
+*/
+}
+
+
+
+/*************************************************************************
+ * Method name...: getServerStatus( )
+ ************************************************************************/
+void
+ServerComm::getServerStatus( ServerStatRes& returnStruct )
+{
+ returnStruct.inactivityTimeout = clientTimeout;
+ returnStruct.managementInterval = garbageCollectionInterval;
+ returnStruct.transactionActive = transactionActive;
+ returnStruct.maxTransferBufferSize = maxTransferBufferSize;
+ returnStruct.nextClientId = clientCount+1;
+ returnStruct.clientNumber = clientTbl.size();
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+ int i;
+
+ returnStruct.clientTable.clientTable_len = clientTbl.size();
+ returnStruct.clientTable.clientTable_val = (RPCClientEntry*) mymalloc( sizeof(RPCClientEntry) * clientTbl.size() );
+
+ for( iter = clientTbl.begin(), i=0; iter != clientTbl.end(); iter++, i++ )
+ {
+ returnStruct.clientTable.clientTable_val[i].clientId = (*iter)->clientId;
+ returnStruct.clientTable.clientTable_val[i].clientIdText = strdup( (*iter)->clientIdText );
+ returnStruct.clientTable.clientTable_val[i].userName = strdup( (*iter)->userName );
+ returnStruct.clientTable.clientTable_val[i].baseName = strdup( (*iter)->baseName );
+ returnStruct.clientTable.clientTable_val[i].creationTime = (*iter)->creationTime;
+ returnStruct.clientTable.clientTable_val[i].lastActionTime = (*iter)->lastActionTime;
+ returnStruct.clientTable.clientTable_val[i].transferColl = (unsigned long)((*iter)->transferColl);
+ returnStruct.clientTable.clientTable_val[i].transferIter = (unsigned long)((*iter)->transferCollIter);
+ returnStruct.clientTable.clientTable_val[i].assembleMDD = (unsigned long)((*iter)->assembleMDD);
+ returnStruct.clientTable.clientTable_val[i].transferMDD = (unsigned long)((*iter)->transferMDD);
+ returnStruct.clientTable.clientTable_val[i].transTiles = (unsigned long)((*iter)->transTiles);
+ returnStruct.clientTable.clientTable_val[i].tileIter = (unsigned long)((*iter)->tileIter);
+ returnStruct.clientTable.clientTable_val[i].bytesToTransfer = (*iter)->bytesToTransfer;
+ }
+ }
+
+ struct mallinfo meminfo = mallinfo();
+
+ returnStruct.memArena = meminfo.arena;
+ returnStruct.memSmblks = meminfo.smblks;
+ returnStruct.memOrdblks = meminfo.ordblks;
+ returnStruct.memFordblks = meminfo.fordblks;
+ returnStruct.memUordblks = meminfo.uordblks;
+}
+
+
+/*************************************************************************
+ * Method name...: addClientTblEntry( ClientTblElt *context )
+ ************************************************************************/
+void
+ServerComm::addClientTblEntry( ClientTblElt *context ) throw ( r_Error )
+{
+ ENTER( "addClientTblEntry()" );
+
+ if (context==NULL)
+ {
+ RMInit::logOut << "Error: ServerComm::addClientTblEntry(): client context is NULL." << endl;
+ throw r_Error( r_Error::r_Error_RefNull );
+ }
+
+ clientTbl.push_back( context );
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // quite verbose
+#endif
+
+ LEAVE( "addClientTblEntry()" );
+}
+
+
+/*************************************************************************
+ * Method name...: deleteClientTblEntry( unsigned long clientId )
+ ************************************************************************/
+unsigned short
+ServerComm::deleteClientTblEntry( unsigned long clientId )
+{
+ ENTER( "deleteClientTblEntry( " << clientId << " )" );
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( clientId );
+
+ if( !context )
+ {
+ TALK( "Warning: in ServerComm::deleteClientTblEntry(): null context, " << "client " << clientId << " not found." );
+ return 1; // desired client id was not found in the client table
+ }
+
+ if( context->currentUsers > 1 )
+ {
+ // In this case, the client table entry was under use before our getClientContext() call.
+ context->release();
+ TALK( "Client context of user "<<clientId<<" has current users ="<<context->currentUsers );
+ return 2;
+ }
+
+ // The transaction contained in the client table element is aborted here.
+ // This is reasonable because at this point, the transaction is either
+ // already committed (This is the case if an rpcCloseDB call arrives.
+ // In this case, abort doesn't do anything harmful.) or the communication
+ // has broken down before a rpcCommitTA or a rpcAbortTA (In this case this
+ // function is called by the garbage collection and aborting the transaction
+ // is advisable.).
+
+ context->releaseTransferStructures();
+
+ // If the current transaction belongs to this client, abort it.
+ if( transactionActive == clientId )
+ {
+ RMInit::logOut << "aborting transaction..." << RMInit::logOut.flush();
+ context->transaction.abort();
+ transactionActive = 0;
+ }
+
+ // close the database if it isn't already closed
+ // (e.g. after connection breakdowns)
+ if( strcmp( context->baseName, "none" ) != 0 )
+ {
+ RMInit::logOut << "closing database..." << RMInit::logOut.flush();
+
+ context->database.close();
+
+ // reset database name
+ delete[] context->baseName;
+ context->baseName = new char[5];
+ strcpy( context->baseName, "none" );
+ }
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // can be pretty verbose
+#endif
+
+ // remove the entry from the client table
+ list<ClientTblElt*>::iterator iter;
+ for( iter=clientTbl.begin(); iter != clientTbl.end() && (*iter)->clientId != clientId; iter++ )
+ ;
+ if ( iter != clientTbl.end() )
+ clientTbl.erase( iter );
+
+ // delete the client table entry data itself
+ // (delete is controlled by the destructor of the ClientTblElt object)
+ delete context;
+
+ TALK( "client table now has " << clientTbl.size() << " entries." );
+
+ LEAVE( "deleteClientTblEntry()" );
+ return returnValue;
+}
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+const char *
+ServerComm::getExtendedErrorInfo()
+{
+ if(errorText == NULL)
+ return "(no error info)";
+
+ return errorText;
+}
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+void ServerComm::setExtendedErrorInfo(const char *newErrorText)
+{
+ clearExtendedErrorInfo();
+
+ errorText = new char [strlen(newErrorText)+1];
+ strcpy(errorText,newErrorText);
+}
+
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+void ServerComm::clearExtendedErrorInfo()
+{
+ if(errorText) delete[] errorText;
+
+ errorText = NULL;
+}
+
+/*************************************************************************
+ * Method name...: ClientTblElt( const char* clientText,
+ * unsigned long client ) (constructor)
+ ************************************************************************/
+ServerComm::ClientTblElt::ClientTblElt( const char* clientText, unsigned long client )
+ : clientId( client ),
+ currentUsers(0),
+ clientIdText(0),
+ userName(0),
+ baseName(0),
+ creationTime(0),
+ lastActionTime(0),
+ transferFormat(r_Array),
+ transferFormatParams(0),
+ exactFormat(1),
+ storageFormat(r_Array),
+ storageFormatParams(0),
+ encodedData(0),
+ encodedSize(0),
+ totalRawSize(0),
+ totalTransferedSize(0),
+ transferColl(0),
+ transferCollIter(0),
+ transferData(0),
+ transferDataIter(0),
+ assembleMDD(0),
+ transferMDD(0),
+ transTiles(0),
+ tileIter(0),
+ deletableTiles(0),
+ bytesToTransfer(0),
+ persMDDCollections(0),
+ taTimer(0),
+ transferTimer(0),
+ evaluationTimer(0),
+ clientParams(0)
+{
+ ENTER( "ServerComm::ClientTblElt::ClientTblElt( clientText=" << (clientText?clientText:"(null)") << ", client=0x" << hex << client << dec << " )" );
+
+ creationTime = time( NULL );
+
+ clientIdText = new char[strlen(clientText)+1];
+ strcpy( clientIdText, clientText );
+
+ baseName = new char[5];
+ strcpy( baseName, "none" );
+
+ userName = new char[8];
+ strcpy( userName, "unknown" );
+
+ clientParams = new r_Parse_Params();
+ clientParams->add("exactformat", &exactFormat, r_Parse_Params::param_type_int);
+
+ LEAVE( "ServerComm::ClientTblElt::ClientTblElt()" );
+}
+
+
+ServerComm::ClientTblElt::~ClientTblElt()
+{
+ releaseTransferStructures();
+
+ // delete the clientIdText member
+ delete[] clientIdText;
+ // delete the baseName member
+ delete[] baseName;
+ // delete user name
+ delete[] userName;
+ // delete transfer format parameters
+ if (transferFormatParams != NULL)
+ delete [] transferFormatParams;
+
+ if (storageFormatParams != NULL)
+ delete [] storageFormatParams;
+
+ if(clientParams)
+ delete clientParams;
+}
+
+
+void
+ServerComm::ClientTblElt::release()
+{
+ if( currentUsers == 0 )
+ RMInit::logOut << "Warning: releasing a non-active client." << endl;
+
+ currentUsers--;
+ lastActionTime = time( NULL );
+}
+
+void
+ServerComm::ClientTblElt::endRequest()
+{
+ if(currentUsers != 0)
+ RMInit::logOut << "Warning: Client ended request without releasing context. Forcing release now." << endl;
+
+ currentUsers=0;
+ lastActionTime = time( NULL );
+}
+
+void
+ServerComm::ClientTblElt::releaseTransferStructures()
+{
+ ENTER( "ServerComm::ClientTblElt::releaseTransferStructures()" );
+ RMDBGENTER(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "releaseTransferStructures()")
+ // delete the transfer iterator
+
+ if( transferCollIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferCollIter" )
+ delete transferCollIter;
+ transferCollIter = 0;
+ }
+
+ // delete transfer data
+ if( transferData )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferData" )
+
+ QtNode::QtDataList::iterator dataIter;
+
+ // delete list elements
+ for( dataIter=transferData->begin(); dataIter!=transferData->end(); dataIter++ )
+ if( *dataIter )
+ {
+ // Note: The following consistency check does not hold for the case when data objects occur
+ // more than once in the result set (e.g., constants).
+
+ // Consistency Check: should be the last reference.
+ // if( (*dataIter)->getRefNo() > 1 )
+ // {
+ // RMInit::logOut << endl << "Internal error in releaseTransferStructures: references left, object " << RMInit::logOut.flush();
+ // (*dataIter)->printStatus( RMInit::logOut );
+ // RMInit::logOut << endl;
+ // }
+
+ // Just tupel elements which are not further referenced are deleted.
+ if (*dataIter)
+ {
+ (*dataIter)->deleteRef();
+ (*dataIter) = 0;
+ }
+ }
+ delete transferData;
+ transferData = 0;
+ }
+
+ // delete the transfer collection
+ // the transferData will check objects because of the bugfix. therefore the objects may deleted only after the check.
+ if( transferColl )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferColl" )
+ transferColl->releaseAll();
+ delete transferColl;
+ transferColl = 0;
+ }
+
+ // delete transfer data iterator
+ if( transferDataIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferDataIter" )
+ delete transferDataIter;
+ transferDataIter = 0;
+ }
+
+ // delete the temporary PersMDDObj
+ if( assembleMDD )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release assembleMDD" )
+ delete assembleMDD;
+ assembleMDD = 0;
+ }
+
+ // delete the transfer MDDobj
+ if( transferMDD )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferMDD" )
+ delete transferMDD;
+ transferMDD = 0;
+ }
+
+ // vector< Tile* >* transTiles;
+ if( transTiles )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transTiles" )
+ // Tiles are deleted by the MDDObject owing them.
+ // release( transTiles->begin(), transTiles->end() );
+ delete transTiles;
+ transTiles = 0;
+ }
+
+ // vector< Tile* >::iterator* tileIter;
+ if( tileIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release tileIter" )
+ delete tileIter;
+ tileIter = 0;
+ }
+
+ // delete deletable tiles
+ if( deletableTiles )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release deletableTiles" )
+
+ vector<Tile*>::iterator iter;
+
+ for( iter=deletableTiles->begin(); iter!=deletableTiles->end(); iter++ )
+ if( *iter )
+ delete *iter;
+
+ delete deletableTiles;
+ deletableTiles = 0;
+ }
+
+ // delete persistent MDD collections
+ if( persMDDCollections )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release persMDDCollections" )
+
+ vector<MDDColl*>::iterator collIter;
+
+ for( collIter=persMDDCollections->begin(); collIter!=persMDDCollections->end(); collIter++ )
+ if( *collIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "before PersMDDColl::releaseAll()" )
+ (*collIter)->releaseAll();
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "after PersMDDColl::releaseAll()" )
+ delete *collIter;
+ }
+
+ delete persMDDCollections;
+ persMDDCollections = 0;
+ }
+
+ // transfer compression
+ if (encodedData != NULL)
+ {
+ free(encodedData);
+ encodedData = NULL; encodedSize = 0;
+ }
+
+#ifdef RMANBENCHMARK
+ // Attention: taTimer is deleted in either commitTA() or abortTA().
+
+ if( evaluationTimer ) delete evaluationTimer;
+ evaluationTimer = 0;
+
+ if( transferTimer ) delete transferTimer;
+ transferTimer = 0;
+#endif
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "releaseTransferStructures()")
+ LEAVE( "ServerComm::ClientTblElt::releaseTransferStructures()" );
+}
+
+
+/******************************************************************************************
+*** This class shouldn't be here, later it will be put in its own file
+******************************************************************************************/
+
+// learned from license.cc
+#ifdef LINUX
+extern "C" {
+ extern char *strptime __P ((__const char *__s, __const char *__fmt, struct tm *__tp));
+}
+#endif
+
+AccessControl accessControl;
+
+
+AccessControl::AccessControl()
+{
+ initDeltaT=0;
+ resetForNewClient();
+}
+
+AccessControl::~AccessControl()
+{
+}
+
+void AccessControl::setServerName(const char *serverName)
+{
+ strcpy(this->serverName,serverName);
+}
+
+void AccessControl::initSyncro(const char *syncroString)
+{
+ struct tm brokentime;
+ strptime(syncroString,"%d:%m:%Y:%H:%M:%S",&brokentime);
+ initDeltaT= difftime (time(NULL) ,mktime(&brokentime) );
+ // cout<<"DeltaT="<<initDeltaT<<endl;
+}
+
+void AccessControl::resetForNewClient()
+{
+ okToRead=false;
+ okToWrite=false;
+ weHaveClient=false;
+}
+
+bool AccessControl::isClient()
+{
+ return weHaveClient;
+}
+
+int AccessControl::crunchCapability(const char *capability)
+{
+ ENTER( "AccessControl::crunchCapability( capability=" << (capability?capability:"(null)") << " )" );
+
+ // verify capability is original
+ char capaQ[200];
+ strcpy(capaQ,"$Canci"); strcat(capaQ,capability);
+
+ char *digest=strstr(capaQ,"$D");
+ if(digest==NULL)
+ {
+ LEAVE( "AccessControl::crunchCapability(): error: digest not found -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED;
+ }
+
+ *digest=0;
+ digest++;digest++;
+ digest[32]=0;
+ TALK( "Digest="<<digest );
+
+ char testdigest[50];
+ messageDigest(capaQ,testdigest,"MD5");
+ TALK( "testdg="<<testdigest );
+ if(strcmp(testdigest,digest)!=0)
+ {
+ LEAVE( "AccessControl::crunchCapability() digest error on '" << digest << "' -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED;
+ }
+
+ char *rights=strstr(capaQ,"$E")+2;
+ char *timeout=strstr(capaQ,"$T")+2;
+ char *cServerName=strstr(capaQ,"$N")+2;
+ // end of cServername is $D, $->0 by digest
+
+ struct tm brokentime;
+ strptime(timeout,"%d:%m:%Y:%H:%M:%S",&brokentime);
+ double DeltaT= difftime (mktime(&brokentime),time(NULL) );
+
+ //for the moment, DEC makes trouble
+ // if(DeltaT < initDeltaT) return CAPABILITY_REFUSED; //!!! Capability too old
+ // cout<<"DeltaT="<<DeltaT<<" initDeltaT="<<initDeltaT<<(DeltaT >= initDeltaT ? " ok":" fail")<<endl;
+
+ if(strcmp(serverName,cServerName)!=0)
+ {
+ LEAVE( "AccessControl::crunchCapability() -> server name doesn't match, got: " << cServerName << ", need: " << serverName << " -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED; //!!! Call is not for me
+ }
+
+ okToRead = false; // looks like a 'true' never gets reset: -- PB 2006-jan-02
+ okToWrite = false; // -dito-
+ for(int i=0;*rights!='$' && *rights && i<2; rights++,i++)
+ {
+ //We only have 2 rights defined now
+ if(*rights=='R')
+ okToRead = true;
+ if(*rights=='W')
+ okToWrite= true;
+ }
+
+ weHaveClient=true;
+
+ TALK( "capability crunched: digest=" << digest << ", rights=" << rights << ", timeout=" << timeout << "(remaining time: " << DeltaT << "), cServerName=" << cServerName << ", okToRead=" << okToRead << ", okToWrite=" << okToWrite << "" );
+
+ LEAVE( "AccessControl::crunchCapability() -> 0 (ok)" );
+ return 0; // OK for now
+}
+
+int AccessControl::messageDigest(const char *input,char *output,const char *mdName)
+{
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len, i;
+ unsigned char md_value[100];
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);
+
+ if(!md)
+ return 0;
+
+ EVP_DigestInit(&mdctx, md);
+ EVP_DigestUpdate(&mdctx,input, strlen(input));
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ for(i = 0; i < md_len; i++)
+ sprintf(output+i+i,"%02x", md_value[i]);
+
+ return strlen(output);
+}
+
+void AccessControl::wantToRead()
+{
+ if(okToRead==false)
+ {
+ TALK( "AccessControl::wantToRead(): error: no permission for read operation." );
+ throw r_Eno_permission(); //r_Error(NO_PERMISSION_FOR_OPERATION);
+ }
+}
+
+void AccessControl::wantToWrite()
+{
+ if(okToWrite==false)
+ {
+ TALK( "AccessControl::wantToWrite(): error: no permission for write operation." );
+ throw r_Eno_permission(); //r_Error(NO_PERMISSION_FOR_OPERATION);
+ }
+
+}
+
+
diff --git a/servercomm/servercomm.hh b/servercomm/servercomm.hh
new file mode 100644
index 0000000..2d34e69
--- /dev/null
+++ b/servercomm/servercomm.hh
@@ -0,0 +1,1120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: servercomm.hh
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _SERVERCOMM_
+#define _SERVERCOMM_
+
+// Put it in front of any typedef bool ... because o2 is using bool as a variable.
+// #include "o2template_CC.hxx"
+
+#include <list>
+
+#include <rpc/rpc.h>
+#include "raslib/error.hh"
+#include "raslib/oid.hh"
+#include "raslib/minterval.hh"
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+#include "relcatalogif/basetype.hh"
+
+#include "servercomm/callbackmgr.hh"
+
+#ifndef _RPCIF_
+ #define _RPCIF_
+ #include "clientcomm/rpcif.h"
+#endif
+
+#ifdef DECALPHA
+#include <rpc/svc.h>
+#endif
+
+// forward declarations
+class QtData;
+class MDDObj;
+class MDDCollIter;
+class MDDColl;
+class RMTimer;
+class r_Parse_Params;
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class servercomm describes the one and only server communication object
+ that can exist in a RasDaMan RPC server. It manages listening for client and
+ maps incoming calls to the respective remote procedures (which reside in the
+ file manager.cc). These remote procedures are global functions
+ which mainly concern with RPC call processing and finally call the methods
+ of this servercomm class to forward client requests.
+*/
+
+class ServerComm
+{
+ public:
+
+ /// the class defines an entry of the client table
+ class ClientTblElt
+ {
+ public:
+ /// default constructor
+ ClientTblElt( const char* clientIdText, unsigned long clientId );
+ /**
+ Default constructor that takes the information to be placed in the
+ clientIdText field of the client table entry and the unique ID to
+ be placed in the clientId field.
+ */
+
+ /// destructor
+ ~ClientTblElt();
+
+ /// release client context
+ void release();
+ /**
+ Releasing the client context means to decrease the currentUsers counter
+ and to update lastActionTime.
+ */
+
+ void endRequest();
+
+ /// releases transfer collection/iterator
+ void releaseTransferStructures();
+ /**
+ The method releases transfer collection and iterator. As the collection is a
+ persistent one, care has to be taken that creation and deletion is done
+ within the same transaction.
+ */
+
+ /// unique client identification assigned by the server
+ unsigned long clientId;
+
+ /// counter indicating the number of current users
+ unsigned int currentUsers;
+
+ /// binding information about the client (IP address and TCP port number)
+ char* clientIdText;
+
+ /// Name of the client user name (if available)
+ char* userName;
+
+ /// Name of the actual database (if one is open)
+ char* baseName;
+
+ /// time when the database was opened (for curiosity purposes)
+ unsigned long creationTime;
+
+ /// time of the client's last action (for garbage collection purposes)
+ unsigned long lastActionTime;
+
+ /// convert raw array data to this data format before transfer
+ r_Data_Format transferFormat;
+ char* transferFormatParams;
+ /// send data to client in the exact transfer format
+ int exactFormat;
+ /// store array data in this data format in the database
+ r_Data_Format storageFormat;
+ char* storageFormatParams;
+
+ /// the tile data converted into the transfer format, if required
+ void* encodedData;
+ unsigned long encodedSize;
+ /// for establishing the compression ratio
+ unsigned long totalRawSize;
+ unsigned long totalTransferedSize;
+
+ /// pointer to an MDD collection
+ MDDColl* transferColl;
+ /**
+ For collection of MDD constants with an update query.
+ */
+
+ /// pointer to an iterator for collection transferColl
+ MDDCollIter* transferCollIter;
+
+ /// pointer to the query result which is currently in transfer
+ std::vector<QtData*>* transferData;
+ /**
+ For the result of the last query (NULL if the result is completely delivered to the client).
+ */
+
+ /// point to an iterator for transfer data
+ std::vector<QtData*>::iterator* transferDataIter;
+
+ /// pointer to a persistent MDD object for tile based transfers
+ MDDObj* assembleMDD;
+
+ /// pointer to an MDD object for tile base transfer
+ MDDObj* transferMDD;
+
+ /// std::vector storing tiles of actual MDD for transfer
+ std::vector< Tile* >* transTiles;
+
+ /// iterator for the std::vector above
+ std::vector< Tile* >::iterator* tileIter;
+
+ /// std::vector storing pointers to transient tiles
+ std::vector< Tile* >* deletableTiles;
+ /**
+ The tiles referenced by these pointers are border tiles dynamically created in getNextMDD().
+ They do not belong to any MDD object, and, therefore, they have to be deleted explicitly.
+ */
+
+ /// bytes to transfer in actual tile (valid only if tile is larger than {\tt MAXTRANSBYTES})
+ unsigned long bytesToTransfer;
+
+ /// std::vector of persistent MDD collections in use
+ std::vector< MDDColl* >* persMDDCollections;
+
+ /// object representing the actual database
+ DatabaseIf database;
+
+ /// object representing the actual transaction (only one at a time possible)
+ TransactionIf transaction;
+
+ /// pointer to a timer for recording transaction time
+ RMTimer* taTimer;
+
+ /// pointer to a timer for recording transfer time
+ RMTimer* transferTimer;
+
+ /// pointer to a timer for recording evaluation time
+ RMTimer* evaluationTimer;
+
+ /// parameter object
+ r_Parse_Params *clientParams;
+
+ private:
+ /// empty private definition prevents of using the copy constructor
+ ClientTblElt( const ClientTblElt& ){};
+ };
+
+ /// default constructor
+ ServerComm();
+
+ /// constructor getting the client time out and the time interval for management routines, together with listen port, rasmgr host and port and the server name
+ ServerComm( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort, char* serverName);
+
+ /// destructor
+ virtual ~ServerComm();
+
+ /// forces the server to listen for client calls
+ virtual void startRpcServer() throw( r_Error );
+
+ /// stops the server
+ virtual void stopRpcServer();
+
+ // informs RasMGR:
+ void informRasMGR(int);
+ #define SERVER_DOWN 0
+ #define SERVER_AVAILABLE 1
+ // 2 is server crushed, but it's generated by rasmgr!
+ // regularly signal the rasmgr that we are available
+ #define SERVER_REGULARSIG 3
+
+ /// adds an entry to the client table (used in RasServerEntry)
+ void addClientTblEntry( ClientTblElt *context ) throw ( r_Error );
+ /**
+ Adds the context entry passed to the client table.
+ Throws an exception if context==NULL.
+ */
+
+ /// deletes an entry of the client table (must be public because it is used in the global garbage collection function)
+ unsigned short deleteClientTblEntry( unsigned long ClientId );
+ /**
+ Deletes the entry of the client table corresponding to the given client id.
+ If no corresponding id is found, false is returned.
+ */
+
+ // quick hack function used when stopping server to abort transaction and close db
+ void abortEveryThingNow();
+
+ /// print server status with client table content to {\tt s}
+ virtual void printServerStatus( ostream& s=cout );
+
+ /// get server status
+ virtual void getServerStatus( ServerStatRes &returnStruct );
+
+ /// the client table which holds information about the calling clients
+ static std::list<ClientTblElt*> clientTbl;
+
+ /// last used client ID (this is increased by one to get the clientId for the next client)
+ static unsigned long clientCount;
+
+ /// inactivity timeout in seconds after which pending client data is deleted
+ const unsigned long clientTimeout;
+
+ /// do a garbage collection every {\tt garbageCollectionInterval} seconds (ONC RPC only)
+ const unsigned long garbageCollectionInterval;
+
+ /// flag for active o2 transaction (stores the clientID of the owner of the active transaction, or 0 if none open)
+ unsigned long transactionActive;
+
+ /// memory used by malloc in ordinary blocks (set in dumpClientTable)
+ long memUsed;
+
+ /// stores a pointer to the actual servercomm object, only one can exist at a time
+ static ServerComm* actual_servercomm;
+
+ /**
+ the callback manager object for garbage collection, license check, ...
+ Always instantiated with default size, resized on startup if required.
+ */
+ CallBackManager callback_mgr;
+
+ //@Man: Communication methods
+ //@{
+ ///
+
+ /// process the client's alive signal
+ virtual unsigned short aliveSignal( unsigned long client );
+ /**
+ The method take the alive signal of a client and updates the last action time.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successfull\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// open database
+ virtual unsigned short openDB( unsigned long callingClientId, const char* dbName, const char* userName );
+ /**
+ The method opens the database with {\tt dbName}. The return value means the following:
+
+ \begin{tabular}{lll}
+ 0 && database successfully opened\\
+ 1 && client context not found\\
+ 2 && database does not exist\\
+ 3 && database is already open\\
+ \end{tabular}
+ */
+
+ /// close current database
+ virtual unsigned short closeDB( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ /// create a database
+ virtual unsigned short createDB( char* name );
+
+ /// destroy a database
+ virtual unsigned short destroyDB( char* name );
+
+ ///
+ /// open transaction
+ virtual unsigned short beginTA( unsigned long callingClientId, unsigned short readOnly=0 );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && other transaction already active\\
+ \end{tabular}
+ */
+
+
+ /// commit current transaction
+ virtual unsigned short commitTA( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+
+ /// abort current transaction
+ virtual unsigned short abortTA( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ /// is transaction open currently?
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ true && a transaction is open\\
+ false && no transaction is open\\
+ \end{tabular}
+ */
+
+ virtual bool isTAOpen( unsigned long callingClientId );
+
+ ///
+ /// executes a retrieval query and prepares the result for transfer with \Ref{getNextMDD}.
+ virtual unsigned short executeQuery( unsigned long callingClientId, const char* query, ExecuteQueryRes &returnStructure );
+ /**
+ Executes a query and puts the result in the actual transfer collection.
+ The first parameter is the unique client id
+ for which the query should be executed. The second parameter is the
+ query itself represented as a string.
+
+ Return values
+ \begin{tabular}{lll}
+ 0 && operation was successful - result collection holds MDD elements\\
+ 1 && operation was successful - result collection holds non-MDD elements\\
+ 2 && operation was successful - result collection has no elements\\
+ 3 && client context not found\\
+ 4 && parse errror\\
+ 5 && execution error\\
+ \end{tabular}
+
+ Communication protocol (return value = 0)
+ \begin{tabular}{lll}
+ \Ref{executeQuery} && \\
+ -> && \Ref{getNextMDD} \\
+ && -> && \Ref{getNextTile} \\
+ && && : \\
+ && :\\
+ \Ref{endTransfer} \\
+ \end{tabular}
+
+ Communication protocol (return value = 1)
+ \begin{tabular}{lll}
+ \Ref{executeQuery} && \\
+ -> && \Ref{getNextElement} \\
+ && :\\
+ \Ref{endTransfer} \\
+ \end{tabular}
+ */
+
+ ///
+ /// get the domain of the next MDD of the actual transfer collection
+ virtual unsigned short getNextMDD( unsigned long callingClientId,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ unsigned short &currentFormat );
+ /**
+ The Method gets the domain of the next MDD of the actual transfer collection.
+ The first parameter is the unique client id. The second parameter returns the
+ domain of the MDD to be transfered. {\tt typeName} returns the name of the
+ MDD type and its structure.
+ Transfer of MDD data is tile-based using the method \Ref{getNextTile}.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, at least one MDD is left in the transfer collection\\
+ 1 && nothing left in the transfer collection\\
+ 2 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ \end{tabular}
+ */
+
+ /// get the next scalar element in the actual transfer collection.
+ virtual unsigned short getNextElement( unsigned long callingClientId,
+ char* &buffer,
+ unsigned int &bufferSize );
+ /**
+ The Method gets the next non-MDD element in the actual transfer collection.
+ The first parameter is the unique client id. The second parameter returns a
+ pointer to the memory occupied by the next element and the third one delivers
+ the size of the buffer.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, at least one element is left in the transfer collection\\
+ 1 && operation succesful, nothing left in the transfer collection\\
+ 2 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ \end{tabular}
+ */
+
+ /// get an MDD by OId
+ virtual unsigned short getMDDByOId( unsigned long callingClientId,
+ r_OId &oid,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ unsigned short &currentFormat );
+ /**
+ The Method gets an MDD by OId {\tt oid}. If the MDD is found, it is initialized as transfer
+ object and can be picked up by \Ref{getNextTile} calls (tile-based transfer).
+
+ Additionally, the method returns domain, type name, and type structure of the found MDD
+ object by reference parameters.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && object with this oid not found\\
+ 3 && object has no tiles
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{getMDDByOId} \\
+ -> && \Ref{getNextTile} \\
+ && : \\
+ \Ref{endTransfer} \\
+ \end{tabular}
+ */
+
+ /// get next tile of the actual MDD of the actual transfer collection
+ virtual unsigned short getNextTile( unsigned long callingClientId,
+ RPCMarray** rpcMarray );
+ /**
+ The Method gets the next tile of the actual MDD of the actual transfer collection.
+ The first parameter is the unique client id. The second parameter is the
+ RPC representation of the Marray representing the tile. If a tile is too large to be
+ transferred in one piece, the data is split. To get the rest of the data, consecutively
+ use this method.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, no further MDDs are left\\
+ 1 && operation was successful, at least one MDD is left in the transfer collection\\
+ 2 && operation was successful, at least one tile is left in the actual MDD\\
+ 3 && operation was successful, at least one block is left in the actual tile\\
+ 4 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ && or nothing left in the collection\\
+ \end{tabular}
+
+ Examples of valid return value chains:
+ \begin{itemize}
+ \item To be transferred: 1 MDD consisting of 1 tile (which is too large)\\
+ \begin{verbatim}
+ 3 ->...-> 3 -> 0
+ \end{verbatim}
+ \item To be transferred: 1 MDD consisting of 2 tiles (the first is too large)\\
+ \begin{verbatim}
+ 3 ->...-> 3 -> 2 -> 0
+ |--------------| |
+ 1st tile 2nd tile
+ \end{verbatim}
+ \item To be transferred: 2 MDDs, each consisting of 1 tile (none too large)\\
+ \begin{verbatim}
+ 1 -> 0
+ \end{verbatim}
+ \item To be transferred: 3 MDDs, the first (A) consisting of 1 tile (not too large),\\
+ the second (B) consisting of 2 tiles (B1, B2, of which the first is too large),
+ the third (C) consisting of 2 tiles (C1, C2, of which the second is too large),
+ \begin{verbatim}
+ 1 -> 3 ->...-> 3 -> 2 -> 1 -> 2 -> 3 ->...-> 3 -> 0
+ | |--------------| | | |--------------|
+ | B1 B2 C1 C2
+ | |-------------------| |-------------------|
+ A B C
+ \end{verbatim}
+ \end{itemize}
+ */
+
+ /// process the client's alive signal
+ virtual unsigned short endTransfer( unsigned long client );
+ /**
+ The method terminates a transfer session and releases all transfer structures.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successfull\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepares transfer of MDD constants and execution of update query
+ virtual unsigned short initExecuteUpdate( unsigned long callingClientId );
+ /**
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{initExecuteUpdate} && \\
+ -> && \Ref{startInsertTransMDD} \\
+ && -> && \Ref{insertTile} \\
+ && && :\\
+ && \Ref{endInsertMDD}\\
+ && :\\
+ \Ref{executeUpdate} && \\
+ \end{tabular}
+
+ Note: Method \Ref{executeUpdate} can be invoked without the \Ref{initExecuteUpdate}
+ prolog in case of no constant MDD objects.
+ */
+
+ /// executes an update query
+ virtual unsigned short executeUpdate( unsigned long callingClientId, const char* query, ExecuteUpdateRes &returnStructure );
+ /**
+ Executes an update query.
+ The first parameter is the unique client id
+ for which the query should be executed. The second parameter is the
+ query itself represented as a string.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && parse errror\\
+ 3 && execution error\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepares an MDD (transient) for transfer of tiles
+ virtual unsigned short startInsertTransMDD( unsigned long callingClientId,
+ r_Minterval &domain,
+ unsigned long typeLength,
+ const char* typeName );
+ /**
+ Creates an object for tile based transfer with method \Ref{insertTile}.
+
+ The first parameter is the unique client id for which the MDD should be created.
+ The second parameter is the
+ name of the collection to insert the MDD object. The third parameter holds the
+ spatial domain of the following MDD object and {\tt typeLength} specifies the size of
+ the base type in bytes. The last one gives the type structure as string representation.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && MDD and its type are incompatible\\
+ \end{tabular}
+ */
+
+ /// create a new persistent MDD object for tile based transfers
+ virtual unsigned short startInsertPersMDD( unsigned long callingClientId,
+ const char* collName,
+ r_Minterval& domain,
+ unsigned long typeLength,
+ const char* typeName,
+ r_OId& oid );
+ /**
+ Creates an object for tile based transfer with method \Ref{insertTile} to be
+ inserted into the specified MDD collection.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to insert the MDD object\\
+ {\tt domain} && spatial domain\\
+ {\tt typeLength} && size of base type in bytes\\
+ {\tt typeName} && type structure as string representation\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && types of MDD and collection are incompatible\\
+ 4 && MDD and its type are incompatible\\
+ 5 && collection does not exist\\
+ 6 && creation of persistent object failed\\
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{startInsertPersMDD} && \\
+ -> && \Ref{insertTile} \\
+ && :\\
+ \Ref{endInsertMDD} && \\
+ \end{tabular}
+ */
+
+ /// insert a tile into a persistent MDD object
+ virtual unsigned short insertTile( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray );
+ /**
+ Inserts a tile into the current MDD object.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient tile\\
+ {\tt rpcMarray} && RPC representation of the tile\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && base type name of inserting tile is not supported\\
+ \end{tabular}
+ */
+
+
+
+ // inserts a tile into a persistent MDD object splitting it up according to
+ // parameter tileSize
+ virtual unsigned short insertTileSplitted( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray,
+ r_Minterval* tileSize );
+ /**
+ Splits and inserts a tile into the current MDD object.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient tile\\
+ {\tt rpcMarray} && RPC representation of the tile\\
+ {\tt tileSize} && r_Minterval specifying the tile-size\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && base type name of inserting tile is not supported\\
+ \end{tabular}
+ */
+
+ /// finnishes the MDD creation and inserts the MDD into the collection
+ virtual unsigned short endInsertMDD( unsigned long callingClientId,
+ int isPersistent );
+ /**
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient MDD\\
+ \end{tabular}
+ */
+
+ ///
+ /// insert object into collection
+ virtual unsigned short insertMDD( unsigned long callingClientId,
+ const char* collName,
+ RPCMarray *rpcMarray,
+ const char* typeName, r_OId& oid );
+ /**
+ Inserts an object into an MDD collection. It is transfered in one piece.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to insert the MDD object\\
+ {\tt rpcMarray} && RPC representation of the MDD object\\
+ {\tt typeName} && type structure as string representation\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && types of MDD and collection are incompatible\\
+ 4 && MDD and its type are incompatible\\
+ 5 && collection does not exist\\
+ 6 && creation of persistent object failed\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepare an MDD collection for transfer with getNextMDD()
+ virtual unsigned short getCollByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid );
+ /**
+ ATTENTION: This function is not used at the moment. It hast
+ to be adapted to transferData.
+
+ Prepares an MDD collection for transfer with getNextMDD().
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oid} && returns oid of the collection\\
+ \end{tabular}
+
+ The first parameter is the unique client id. The second parameter is the
+ name of the collection to get. {\tt typeName} returns the name of the
+ collection type and {\tt typeStructure} its type structure.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// prepare an MDD collection for transfer with getNextMDD()
+ virtual unsigned short getCollByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ char* &collName );
+ /**
+ ATTENTION: This function is not used at the moment. It hast
+ to be adapted to transferData.
+
+ Prepares an MDD collection for transfer with \Ref{getNextMDD}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt oid} && oid of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt collName} && returns name of collection\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// gets oids of the collection specified by name
+ virtual unsigned short getCollOIdsByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize );
+ /**
+ Gets the collection of oids of the collection with {\tt collName}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oid} && returns object identifier\\
+ {\tt oidTable} && returns an array of pointers to oids\\
+ {\tt oidTableSize} && returns the no of elements in the table\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// gets oids of the collection specified by name
+ virtual unsigned short getCollOIdsByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize,
+ char* &collName );
+ /**
+ Gets the collection of oids of the collection with {\tt collName}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt oid} && oid of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oidTable} && returns an array of pointers to oids\\
+ {\tt oidTableSize} && returns the no of elements in the table\\
+ {\tt collName} && returns name of collection\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// create new MDD collection
+ virtual unsigned short insertColl( unsigned long callingClientId,
+ const char* collName,
+ const char* typeName,
+ r_OId& oid );
+ /**
+ Creates a new MDD collection.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be created\\
+ {\tt typeName} && name of the collection type\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && collection type name not found\\
+ 3 && collection name exists already in the db
+ \end{tabular}
+ */
+
+ ///
+ /// delete MDD collection
+ virtual unsigned short deleteCollByName( unsigned long callingClientId,
+ const char* collName );
+ /**
+ Deletes an MDD collection. The first parameter is the unique client id
+ for which the collection should be deleted. The second parameter is the
+ name for the collection to be deleted.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && collection with name does not exist\\
+ \end{tabular}
+ */
+
+ /// delete object by oid
+ virtual unsigned short deleteObjByOId( unsigned long callingClientId, r_OId& oid );
+ /**
+ Deletes the object with {\tt oid}.
+ The first parameter is the unique client id for which the object should be
+ deleted.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && object with oid does not exist\\
+ \end{tabular}
+ */
+
+ ///
+ /// remove object specified by oid from collection specified by name
+ virtual unsigned short removeObjFromColl( unsigned long callingClientId,
+ const char* collName, r_OId& oid );
+ /**
+ The method removes the object with {\\t oid} from collection with {\tt collName}.
+ The first parameter is the unique client id for which the object should be removed.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && specified collection does not exist\\
+ 3 && specified object does not exist in the collection\\
+ \end{tabular}
+ */
+
+ ///
+ /// get new object identifier
+ virtual unsigned short getNewOId( unsigned long callingClientId,
+ unsigned short objType, r_OId& oid );
+ /**
+ Creates a new oid and gives it back by the refernce parameter {\tt oid}.
+ {\tt objType} determines the type of object for which that oid is allocated. The folowing
+ values are supported: 1 = MDD, 2 = Collection.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && error while creating oid\\
+ \end{tabular}
+ */
+
+ /// get type of object by oid
+ virtual unsigned short getObjectType( unsigned long callingClientId,
+ r_OId& oid, unsigned short &objType );
+ /**
+ Determines the type of the object indicated by {\tt oid}. The type is returned by the
+ reference parameter {\tt objType}. The folowing types are supported: 1 = MDD, 2 = Collection.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && oid not found\\
+ \end{tabular}
+ */
+
+ /// get type structure of a type name
+ virtual unsigned short getTypeStructure( unsigned long callingClientId,
+ const char* typeName,
+ unsigned short typeType,
+ char* &typeStructure);
+ /**
+ Determines the type structure of the type specified by {\tt typeName}. The type
+ either can be a set type (typeType=1), an mdd type (typeType=2), or a base type
+ (typeType = 3).
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && type name not found\\
+ \end{tabular}
+ */
+
+ /// set the data format used for transferring data to the client
+ virtual unsigned short setTransferMode( unsigned long callingClientId,
+ unsigned short format, const char* formatParams );
+ /**
+ Sets the data format used by the server to transfer data to the client to
+ format which is of type r_Data_Format.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && unknown or unsupported data format\\
+ \end{tabular}
+ */
+
+ /// set the data format for storing data into the database
+ virtual unsigned short setStorageMode( unsigned long callingClientId,
+ unsigned short format, const char *formatParams );
+ /**
+ return values exactly like setTransferMode()
+ */
+ ///
+ //@}
+
+ /// returns a pointer to the context of the calling client, 0 it there is no context
+ virtual ClientTblElt* getClientContext( unsigned long ClientId );
+ /**
+ Returns a pointer to the context of the calling client. This is done by
+ searching the client table maintained by the server for the given client id.
+ If there is no context corresponding to the client id, 0 is returned.
+
+ Attention: After a client context was successfully received it has to be
+ released using its member function release();
+ */
+
+ // get, set and clear extended error info.
+ const char *getExtendedErrorInfo();
+
+ void setExtendedErrorInfo(const char*);
+
+ void clearExtendedErrorInfo();
+
+ void clientEndRequest();
+
+ // constant for clientID
+ static const char* HTTPCLIENT;
+
+ private:
+ /// copy constructor is private and therefore can not be used
+ ServerComm( const ServerComm& );//and then why this? : clientTimeout(3600), garbageCollectionInterval(600){;};
+
+ protected:
+ /// make sure a tile has the correct data format, converting if necessary
+ static int ensureTileFormat( r_Data_Format &hasFmt, r_Data_Format needFmt,
+ const r_Minterval &dom, const BaseType *type,
+ char *&data, unsigned long &size, int repack,
+ int owner, const char *params = NULL);
+ ///returns the following:
+ static const int ENSURE_TILE_FORMAT_OK;
+ static const int ENSURE_TILE_FORMAT_BAD;
+
+ /// pointer to the actual administration interface object
+ AdminIf* admin;
+
+ char *errorText;
+
+ unsigned long listenPort;
+ char* rasmgrHost;
+ unsigned int rasmgrPort;
+ char* serverName;
+
+ bool isHttpServer;
+ //this trick didn't work and we are out of time
+ // ClientTblElt *uniqueClientContext;
+};
+
+
+/// indirect caller for rpcif_1
+void rpcif_1_caller(struct svc_req *rqstp,SVCXPRT *transp);
+
+
+/******************************************************************************************
+*** This class shouldn't be here, later it will be put in its own file
+******************************************************************************************/
+
+
+class AccessControl
+ {
+ public:
+ AccessControl();
+ ~AccessControl();
+ void initSyncro(const char *);
+ void setServerName(const char *serverName);
+
+ void resetForNewClient();
+ int crunchCapability(const char*);
+ /* 0 - ok
+ 804 - capability refused
+ */
+
+ void wantToRead(); // both throw
+ void wantToWrite();
+ bool isClient();
+ private:
+ int messageDigest(const char *input,char *output,const char *mdName);
+ double initDeltaT;
+ char serverName[100];
+
+ bool okToRead;
+ bool okToWrite;
+ bool weHaveClient;
+ };
+extern AccessControl accessControl;
+
+#include "servercomm.icc"
+
+#endif
diff --git a/servercomm/servercomm.icc b/servercomm/servercomm.icc
new file mode 100644
index 0000000..ebc1d6c
--- /dev/null
+++ b/servercomm/servercomm.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: servercomm.icc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
diff --git a/servercomm/servercomm2.cc b/servercomm/servercomm2.cc
new file mode 100644
index 0000000..7fcbef2
--- /dev/null
+++ b/servercomm/servercomm2.cc
@@ -0,0 +1,4051 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: servercomm2.cc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * - FIXME: catch exceptions in all operations
+ * - return values & their meaning see servercomm.hh
+ * - FIXME: "client not registered" delivers sometimes 1, sometimes 3
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)servercomm2, ServerComm: $Id: servercomm2.cc,v 1.121 2005/09/07 23:23:31 rasdev Exp $";
+
+// after some time please take this and everything related to it out (26.06.2001)
+#define ANDREAS_2306
+
+#include <iostream>
+#include <malloc.h>
+#include <string.h>
+#include <math.h> // for log(), exp(), floor()
+#include <ctime> // time
+#include <iomanip>
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+#ifdef RMANBENCHMARK
+ // to control GenericCompression::decompTimer and GenericCompression::compTimer
+ #include "gencompression.hh"
+ #include "zlibcompression.hh"
+#endif
+
+#ifdef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+
+ extern int _rpcpmstart;
+
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#include <rpc/pmap_clnt.h>
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/basetype.hh"
+#include "raslib/endian.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/parseparams.hh"
+// for transfer compression
+#include "compression/tilecompression.hh"
+
+#include "servercomm/servercomm.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "reladminif/eoid.hh"
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtstringdata.hh"
+
+// console output describing successful/unsuccessful actions
+#define MSG_OK "ok"
+#define MSG_FAILED "failed"
+
+// include and extern declarations for the query parsing
+#include "qlparser/querytree.hh"
+extern int yyparse(void *);
+extern void yyreset();
+#ifdef NOPRE
+char* ppInBuf = 0;
+char* ppOutBuf = 0;
+void ppreset()
+{
+ RMInit::logOut << "Error: Preprocessor not compiled in." << std::endl;
+ RMInit::dbgOut << "Error: Preprocessor not compiled in." << std::endl;
+ throw r_Error(ILLEGALSTATEREACHED);
+}
+
+int ppparse()
+{
+ RMInit::logOut << "Error: Preprocessor not compiled in." << std::endl;
+ RMInit::dbgOut << "Error: Preprocessor not compiled in." << std::endl;
+ throw r_Error(ILLEGALSTATEREACHED);
+}
+#else
+extern char* ppInBuf;
+extern char* ppOutBuf;
+extern void ppreset();
+extern int ppparse();
+#endif
+extern bool udfEnabled;
+
+extern QueryTree* parseQueryTree;
+extern ParseInfo* parseError;
+extern char* beginParseString;
+extern char* iterParseString;
+extern unsigned long maxTransferBufferSize;
+extern char* dbSchema;
+
+MDDColl* mddConstants=0;
+
+ServerComm::ClientTblElt* currentClientTblElt=0;
+
+// Once again a function prototype. The first one is for the RPC dispatcher
+// function located in the server stub file rpcif_svc.c and the second one
+// is for the garbage collection function pointed to by the signal handler.
+extern "C"
+{
+ // static void rpcif_1( struct svc_req*, register SVCXPRT* );
+ char* rpcif_1( struct svc_req*, register SVCXPRT* );
+ void garbageCollection( int );
+}
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+
+// This is needed in httpserver.cc
+char globalHTTPSetTypeStructure[4096];
+
+// constant for clientID
+const char* ServerComm::HTTPCLIENT = "HTTPClient";
+
+///ensureTileFormat returns the following:
+const int ServerComm::ENSURE_TILE_FORMAT_OK=0;
+const int ServerComm::ENSURE_TILE_FORMAT_BAD=-1;
+
+/*************************************************************************
+ * Method name...: openDB( unsigned long callingClientId,
+ * const char* dbName ,
+ * const char* userName )
+ ************************************************************************/
+unsigned short
+ServerComm::openDB( unsigned long callingClientId,
+ const char* dbName,
+ const char* userName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "openDB" )
+
+ unsigned short returnValue=0;
+
+ RMInit::logOut << "Request: openDB '" << dbName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // open the database
+ try
+ {
+ context->database.open( dbName );
+ }
+ catch(r_Error& err)
+ {
+ if(err.get_kind() == r_Error::r_Error_DatabaseUnknown)
+ {
+ RMInit::logOut << "Error: database does not exist." << endl;
+ returnValue = 2;
+ }
+ else if(err.get_kind() == r_Error::r_Error_DatabaseOpen)
+ {
+ // ignore re-open to be fault tolerant -- PB 2004-dec-16
+ // RMInit::logOut << "Error: database is already open." << endl;
+ returnValue = 3;
+ }
+ else
+ {
+ RMInit::logOut << "Error: exception " << err.get_errorno() << ": " << err.what() << endl;
+ //should be something else. but better than no message about the problem at all
+ returnValue = 2;
+ }
+ }
+
+ if( returnValue == 0 )
+ {
+ // database was successfully opened, so assign db and user name
+ delete[] context->baseName;
+ context->baseName = new char[strlen( dbName )+1];
+ strcpy( context->baseName, dbName );
+
+ delete[] context->userName;
+ context->userName = new char[strlen( userName )+1];
+ strcpy( context->userName, userName );
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+
+ context->release();
+
+ // ignore "already open" error to be more fault tolerant -- PB 2004-dec-16
+ if( returnValue == 3 )
+ {
+ RMInit::logOut << "Warning: database already open for user '" << userName << "', ignoring command." << endl;
+ returnValue = 0;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "openDB" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: closeDB( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::closeDB( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "closeDB" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: closeDB..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // If the current transaction belongs to this client, abort it.
+ if( transactionActive == callingClientId )
+ {
+ RMInit::logOut << "Warning: transaction is open; aborting this transaction..." << std::flush;
+
+ context->transaction.abort();
+ transactionActive = 0;
+ }
+
+ // close the database
+ context->database.close();
+
+ // reset database name
+ delete[] context->baseName;
+ context->baseName = new char[5];
+ strcpy( context->baseName, "none" );
+
+ returnValue = 0;
+
+ context->release();
+
+#ifdef PURIFY
+ purify_new_leaks();
+#endif
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "closeDB" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: createDB( char* name )
+ ************************************************************************/
+unsigned short
+ServerComm::createDB( char* name )
+{
+ unsigned short returnValue;
+
+ // FIXME: what about client id? -- PB 2005-aug-27
+
+ RMInit::logOut << "Request: createDB '" << name << "'..." << std::flush;
+
+ DatabaseIf* tempDbIf = new DatabaseIf;
+
+ // create the database
+ try
+ {
+ tempDbIf->createDB( name, dbSchema );
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch(r_Error& myErr)
+ {
+ RMInit::logOut << "Error: exception " << myErr.get_errorno() << ": " << myErr.what() << std::endl;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << std::endl << "Error: Unspecified exception." << std::endl;
+ }
+
+ delete tempDbIf;
+
+ // FIXME: set proper return value on failure (update .hh!) -- PB 2005-aug-27
+ returnValue = 0;
+
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: destroyDB( char* name )
+ ************************************************************************/
+unsigned short
+ServerComm::destroyDB( char* name )
+{
+ // Note: why no check for client id here? -- PB 2005-aug-25
+
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: destroyDB '" << name << "'..." << std::flush;
+
+ DatabaseIf* tempDbIf = new DatabaseIf;
+
+ // begin a temporary transaction because persistent data (as databases)
+ // can only be manipulated within active transactions.
+ // tempTaIf->begin(tempDbIf);
+
+ // destroy the database
+ tempDbIf->destroyDB( name );
+
+ // commit the temporary transaction
+ // tempTaIf->commit();
+
+ delete tempDbIf;
+
+ RMInit::logOut << MSG_OK << std::endl;
+
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: beginTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::beginTA( unsigned long callingClientId,
+ unsigned short readOnly )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "beginTA" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: beginTA (" << ( readOnly ? "read" : "write" ) << ")..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context == 0 )
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+ else if ( transactionActive )
+ {
+ RMInit::logOut << "Error: transaction already active." << std::endl;
+ returnValue = 2;
+ context->release();
+ }
+ else
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ context->taTimer = new RMTimer("ServerComm", "transaction time ");
+#endif
+ try
+ {
+ // start the transaction
+ context->transaction.begin( &(context->database), readOnly );
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "Error: exception " << err.get_errorno() << ": " << err.what() << std::endl;
+ context->release();
+ throw;
+ }
+
+ // lock the semaphor
+ transactionActive = callingClientId;
+ returnValue = 0;
+
+ context->release();
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "beginTA" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: commitTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::commitTA( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "commitTA" )
+ unsigned short returnValue;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ RMInit::logOut << "Request: commitTA..." << std::flush;
+
+ if( context != 0 )
+ {
+#ifdef RMANBENCHMARK
+ RMTimer* commitTimer = 0;
+
+ if( RManBenchmark > 0 )
+ commitTimer = new RMTimer("ServerComm", "commit time ");
+#endif
+
+ // release transfer collection/iterator within the transaction they are created
+ context->releaseTransferStructures();
+
+ // commit the transaction
+ context->transaction.commit();
+
+ // unlock the semaphor
+ transactionActive = 0;
+
+ returnValue = 0;
+
+#ifdef RMANBENCHMARK
+ if( commitTimer ) delete commitTimer;
+#endif
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+#ifdef RMANBENCHMARK
+ if( context->taTimer )
+ delete context->taTimer;
+ context->taTimer = 0;
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "commitTA" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: abortTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::abortTA( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "abortTA" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: abortTA..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator within the transaction they are created
+ context->releaseTransferStructures();
+
+ // abort the transaction
+ context->transaction.abort();
+
+ // unlock the semaphor
+ transactionActive = 0;
+
+ returnValue = 0;
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+#ifdef RMANBENCHMARK
+ if( context->taTimer ) delete context->taTimer;
+ context->taTimer = 0;
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "abortTA" )
+ return returnValue;
+}
+
+
+/*************************************************************************
+ * Method name...: isTAOpen()
+ * as right now only one transaction can be active per server,
+ * we only have to check the sema.
+ * returns:
+ * true iff a transaction is open
+ ************************************************************************/
+bool
+ServerComm::isTAOpen( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "isTAOpen" )
+
+ RMInit::logOut << "Request: isTAOpen..." << std::flush;
+
+ bool returnValue = transactionActive;
+
+ RMInit::logOut << MSG_OK << (transactionActive?", is active.":", is not active.") << endl;
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "isTAOpen" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::insertColl( unsigned long callingClientId,
+ const char* collName,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertColl" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertColl '" << collName << "' with type '" << typeName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // create the collenction
+ //
+
+ // get collection type
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( typeName );
+
+ if( collType )
+ {
+ try
+ {
+ MDDColl* coll = MDDColl::createMDDCollection(collName, OId(oid.get_local_oid()), collType);
+ delete coll;
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch( r_Error& obj )
+ {
+ if (obj.get_kind() == r_Error::r_Error_NameNotUnique)
+ {
+ RMInit::logOut << "Error: collection exists already." << std::endl;
+ returnValue = 3;
+ }
+ else
+ {
+ RMInit::logOut << "Error: cannot create collection: " << obj.get_errorno() << " " << obj.what() << std::endl;
+ //this should be another code...
+ returnValue = 3;
+ }
+ }
+
+ }
+ else
+ {
+ RMInit::logOut << "Error: unknown collection type: '" << typeName << "'." << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertColl" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: deleteCollByName( unsigned long callingClientId,
+ * const char* collName )
+ ************************************************************************/
+unsigned short
+ServerComm::deleteCollByName( unsigned long callingClientId,
+ const char* collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "deleteCollByName(" << callingClientId << ", " << collName << ")")
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: deleteCollByName '" << collName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // delete collenction
+ //
+
+ // delete root object with collection name
+ if (MDDColl::dropMDDCollection(collName))
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "collection dropped")
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+ }
+ else
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "did not drop collection")
+ RMInit::logOut << "Error: collection does not exist." << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "deleteCollByName(" << callingClientId << ", " << collName << ") " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::deleteObjByOId( unsigned long callingClientId,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "deleteObjByOId(" << callingClientId << ", " << oid << ")");
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: deleteObjByOId " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ // determine type of object
+ OId oidIf( oid.get_local_oid() );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "OId of object " << oidIf)
+ OId::OIdType objType = oidIf.getType();
+
+ switch( objType )
+ {
+ case OId::MDDOID:
+ // FIXME: why not deleted?? -- PB 2005-aug-27
+ RMInit::logOut << "found MDD object; NOT deleted yet..." << MSG_OK << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "not deleting mdd object")
+ returnValue = 0;
+ break;
+ case OId::MDDCOLLOID:
+ RMInit::logOut << "deleting collection..." << std::flush;
+ // delete root object with collection name
+ if (MDDColl::dropMDDCollection(oidIf))
+ {
+ RMInit::logOut << MSG_OK << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "deleted mdd coll")
+ returnValue = 0;
+ }
+ else
+ {
+ RMInit::logOut << "Error: Collection does not exist." << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "did not delete mdd coll")
+ returnValue = 2;
+ }
+ break;
+ default:
+ RMInit::logOut << "Error: object has unknown type: " << objType << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "deleteObjByOId(" << callingClientId << ", " << oid << ")" << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::removeObjFromColl( unsigned long callingClientId,
+ const char* collName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "removeObjFromColl(" << callingClientId << ", " << collName << ", " << oid << ")")
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: removeObjFromColl '" << collName << "', oid " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ OId oidIf( oid.get_local_oid() );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "mdd object oid " << oidIf)
+
+ // open collection
+ MDDColl* coll = 0;
+
+ try
+ {
+ coll = MDDColl::getMDDCollection(collName);
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "retrieved mdd coll")
+ }
+ catch(r_Error& obj)
+ {
+ // collection name invalid
+ if (obj.get_kind() == r_Error::r_Error_ObjectUnknown)
+ {
+ RMInit::logOut << "Error: collection not found." << std::endl;
+ returnValue = 2;
+ }
+ else
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ // there should be another return code
+ returnValue = 2;
+ }
+ coll = NULL;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ // collection name invalid
+ RMInit::logOut << "Error: unspecified exception." << std::endl;
+ returnValue = 2;
+ }
+
+ if( coll )
+ {
+ if (coll->isPersistent())
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "retrieved persistent mdd coll")
+
+ OId collId;
+ coll->getOId(collId);
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "mdd coll oid " << collId)
+ MDDColl::removeMDDObject(collId, oidIf);
+
+ // no error management yet -> returnValue = 3
+
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+
+ delete coll;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "removeObjFromColl(" << callingClientId << ", " << collName << ", " << oid << ") " << returnValue)
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertMDD( unsigned long callingClientId,
+ const char* collName,
+ RPCMarray* rpcMarray,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertMDD type='" << typeName << "' into collection '" << collName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+ r_Data_Format myDataFmt = r_Array;
+ r_Data_Format myCurrentFmt = r_Array;
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // insert the object into the collection
+ //
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ //
+ // open the collection
+ //
+
+ MDDColl* collection=0;
+ MDDColl* almost = 0;
+
+ try
+ {
+ almost = MDDColl::getMDDCollection( collName );
+ if (almost->isPersistent())
+ collection = (MDDColl*)almost;
+ else
+ {
+ RMInit::logOut << "Error: inserting into system collection is illegal." << std::endl;
+ context->release(); //!!!
+ throw r_Error(SYSTEM_COLLECTION_NOT_WRITABLE);
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 5;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 5;
+ RMInit::logOut << "Error: unspecific exception during collection read." << std::endl;
+ context->release();
+ return returnValue;
+ }
+
+ //
+ // check MDD and collection type for compatibility
+ //
+
+ r_Minterval domain( rpcMarray->domain );
+
+ RMDBGIF(4, RMDebug::module_servercomm, "ServerComm", \
+ char* collTypeStructure = collection->getCollectionType()->getTypeStructure(); \
+ char* mddTypeStructure = mddType->getTypeStructure(); \
+ RMInit::dbgOut << std::endl << "Collection type structure.: " << collTypeStructure << std::endl \
+ << "MDD type structure........: " << mddTypeStructure << std::endl \
+ << "MDD domain................: " << domain << std::endl; \
+ free( collTypeStructure ); \
+ free( mddTypeStructure ); )
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // free resources
+ collection->releaseAll();
+ delete collection;
+
+ // return error
+ returnValue = 4;
+ RMInit::logOut << "Error: MDD type is not compatible wrt. its domain: " << domain << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ if( !collection->getCollectionType()->compatibleWith( mddType ) )
+ {
+ // free resources
+ collection->releaseAll();
+ delete collection;
+
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: MDD and collection types are incompatible." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // create persistent MDD object
+ //
+
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+ char* dataPtr = rpcMarray->data.confarray_val;
+ unsigned long dataSize = rpcMarray->data.confarray_len;
+ // reset data area from rpc structure so that it is not deleted
+ // deletion is done by TransTile resp. Tile
+ rpcMarray->data.confarray_len = 0;
+ rpcMarray->data.confarray_val = 0;
+ int getMDDData=0;
+ const BaseType* baseType = mddBaseType->getBaseType();
+ unsigned long byteCount = domain.cell_count() * rpcMarray->cellTypeLength;
+ //r_Data_Format storageFormat = (r_Data_Format)(rpcMarray->storageFormat);
+
+ MDDObj* mddObj=0;
+ StorageLayout ms;
+ ms.setTileSize(StorageLayout::DefaultTileSize);
+ ms.setIndexType(StorageLayout::DefaultIndexType);
+ ms.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (domain.dimension() == StorageLayout::DefaultTileConfiguration.dimension())
+ ms.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+
+ try
+ {
+ mddObj = new MDDObj(mddBaseType, domain, OId(oid.get_local_oid()), ms);
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 6;
+ RMInit::logOut << "Error: unspecific exception during creation of persistent object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ myDataFmt = (r_Data_Format)(rpcMarray->storageFormat);
+ myCurrentFmt = (r_Data_Format)(rpcMarray->currentFormat);
+ RMInit::dbgOut << "oid " << oid
+ << ", domain " << domain
+ << ", cell length " << rpcMarray->cellTypeLength
+ << ", data size " << dataSize
+ << ", rpc storage " << myDataFmt
+ << ", rpc transfer " << myCurrentFmt << " " << std::flush;
+
+ // store in the specified storage format; the current tile format afterwards will be the
+ // requested format if all went well, but use the (new) current format to be sure.
+ // Don't repack here, however, because it might be retiled before storage.
+ if(ensureTileFormat(myCurrentFmt, myDataFmt, domain,
+ baseType, dataPtr, dataSize, 0, 1, context->storageFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 6;
+ RMInit::logOut << "Error: illegal tile format for creating object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ // if compressed, getMDDData is != 0
+ if (myCurrentFmt != r_Array)
+ getMDDData = dataSize;
+
+ // This should check the compressed size rather than the raw data size
+ if( RMInit::tiling && dataSize > StorageLayout::DefaultTileSize )
+ {
+ r_Range edgeLength = (r_Range)floor(exp((1/(r_Double)domain.dimension())*
+ log((r_Double)StorageLayout::DefaultTileSize/rpcMarray->cellTypeLength)));
+
+ if (edgeLength <1)
+ edgeLength=1;
+
+ r_Minterval tileDom( domain.dimension() );
+ for( int i=0; i<tileDom.dimension(); i++ )
+ tileDom << r_Sinterval( (r_Range)0, (r_Range)(edgeLength-1) );
+
+ Tile* entireTile = 0;
+
+ // compression intelligence moved somewhere else, but creation of
+ // compression object in tile constructor might throw an error.
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Warning: unsupported data format '" << myCurrentFmt << "', falling back to 'r_Array'..." << std::flush;
+ myCurrentFmt = r_Array;
+ }
+ entireTile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+
+ entireTile->setParameters(context->storageFormatParams);
+ vector< Tile *>* tileSet = entireTile->splitTile( tileDom );
+ if (entireTile->isPersistent())
+ entireTile->setPersistent(0);
+ delete entireTile;
+
+ RMInit::logOut << "creating " << tileSet->size() << " tile(s)..." << std::flush;
+
+ for( vector<Tile*>::iterator iter = tileSet->begin(); iter != tileSet->end(); iter++ )
+ mddObj->insertTile( *iter );
+
+ // delete the vector again
+ delete tileSet;
+ }
+ else
+ {
+ Tile* tile = 0;
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ tile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Error: Unsupported data format '" << myCurrentFmt << "', will ingore it..." << std::flush;
+ tile = new Tile( domain, baseType, dataPtr, getMDDData );
+ }
+
+ tile->setParameters(context->storageFormatParams);
+ RMInit::dbgOut << "one tile..." << std::flush;
+ mddObj->insertTile( tile );
+ }
+
+ collection->insert( mddObj );
+
+ // free transient memory
+ collection->releaseAll();
+
+ delete collection;
+
+ //
+ // done
+ //
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' has no base type." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertMDD " << returnValue)
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertTileSplitted( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray,
+ r_Minterval* tileSize)
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertTile..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ BaseType* baseType = NULL;
+
+ if( isPersistent )
+ baseType = (BaseType*)context->assembleMDD->getCellType();
+ else
+ baseType = (BaseType*)context->transferMDD->getCellType();
+
+ // The type of the tile has to be the one of the MDD.
+ // type check missing
+
+ if( baseType != NULL )
+ {
+ r_Minterval domain( rpcMarray->domain );
+ char* dataPtr = rpcMarray->data.confarray_val;
+ unsigned long dataSize = rpcMarray->data.confarray_len;
+ // reset data area from rpc structure so that it is not deleted
+ // deletion is done by TransTile resp. Tile
+ rpcMarray->data.confarray_len = 0;
+ rpcMarray->data.confarray_val = 0;
+ int getMDDData = 0;
+ r_Data_Format myDataFmt = (r_Data_Format)(rpcMarray->storageFormat);
+ r_Data_Format myCurrentFmt = (r_Data_Format)(rpcMarray->currentFormat);
+ RMDBGMIDDLE( 2, RMDebug::module_server, "ServerComm", "insertTileSplitted - rpc storage format : " << myDataFmt)
+ RMDBGMIDDLE( 2, RMDebug::module_server, "ServerComm", "insertTileSplitted - rpc transfer format : " << myCurrentFmt)
+ // store in specified storage format; use (new) current format afterwards
+ // Don't repack here because of possible retiling.
+ if(ensureTileFormat(myCurrentFmt, myDataFmt, domain,
+ baseType, dataPtr, dataSize, 0, 1, context->storageFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 1;
+
+ context->release();
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted - ensureTileFormat Failed" )
+
+ return returnValue;
+ }
+
+ if (myCurrentFmt != r_Array)
+ getMDDData = dataSize;
+
+ Tile* tile = 0;
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Warning: Unsupported data format '" << myCurrentFmt << "', will be ignored..." << std::flush;
+ myDataFmt = r_Array;
+ }
+ tile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+
+ // for java clients only: check endianness and split tile if necessary
+ if(strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0)
+ {
+ // check endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+ if(serverEndian != r_Endian::r_Endian_Big)
+ {
+ RMInit::dbgOut << "changing endianness..." << std::flush;
+
+ // we have to swap the endianess
+ char *tpstruct;
+ r_Base_Type *useType;
+ tpstruct = baseType->getTypeStructure();
+ useType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ char* tempT = (char*)mymalloc(sizeof(char) * tile->getSize());
+
+ // change the endianness of the entire tile for identical domains for src and dest
+ r_Endian::swap_array(useType, domain, domain, tile->getContents(), tempT);
+ tile->setContents(tempT);
+
+ delete useType;
+ free(tpstruct);
+ }
+
+ // Split the tile!
+ vector< Tile *>* tileSet = tile->splitTile( *tileSize );
+ RMInit::dbgOut << "Now inserting splitted tile...";
+ for( vector<Tile*>::iterator iter = tileSet->begin(); iter != tileSet->end(); iter++ )
+ {
+ (*iter)->setParameters(context->storageFormatParams);
+ if( isPersistent )
+ context->assembleMDD->insertTile( *iter );
+ else
+ context->transferMDD->insertTile( *iter );
+ }
+ // delete the vector again
+ delete tile;
+ delete tileSet;
+ }
+ // for c++ clients: insert tile
+ else
+ {
+ //insert one single tile
+ // later, we should take into consideration the default server tile-size!
+ RMInit::logOut << "Now inserting single tile...";
+ tile->setParameters(context->storageFormatParams);
+ if( isPersistent )
+ context->assembleMDD->insertTile( tile );
+ else
+ context->transferMDD->insertTile( tile );
+ //do not access tile again, because it was already deleted in insertTile
+ }
+ //
+ // done
+ //
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ RMInit::logOut << "Error: tile and MDD base type do not match." << std::endl;
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertTile( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray )
+{
+ // no log here, is done in RNP comm.
+
+ unsigned short returnValue = insertTileSplitted(callingClientId, isPersistent, rpcMarray, NULL);
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::startInsertPersMDD( unsigned long callingClientId,
+ const char* collName,
+ r_Minterval &domain,
+ unsigned long typeLength,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "startInsertPersMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: startInsertPersMDD type '" << typeName
+ << "', collection '" << collName << "', domain " << domain << ", cell length " << typeLength
+ << ", " << domain.cell_count()*typeLength << " bytes..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ try
+ {
+ // store PersMDDColl for insert operation at the end of the transfer
+ context->transferColl = MDDColl::getMDDCollection( collName );
+ if (!context->transferColl->isPersistent())
+ {
+ RMInit::logOut << "Error: inserting into system collection is illegal." << std::endl;
+ context->release(); //!!!
+ throw r_Error(SYSTEM_COLLECTION_NOT_WRITABLE);
+ }
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 5;
+ RMInit::logOut << "Error: unspecific exception while opening collection." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // check MDD and collection type for compatibility
+ //
+
+ RMDBGIF(4, RMDebug::module_servercomm, "ServerComm", \
+ char* collTypeStructure = context->transferColl->getCollectionType()->getTypeStructure(); \
+ char* mddTypeStructure = mddType->getTypeStructure(); \
+ RMInit::dbgOut << std::endl << "Collection type structure.: " << collTypeStructure << std::endl \
+ << "MDD type structure........: " << mddTypeStructure << std::endl \
+ << "MDD domain................: " << domain << std::endl; \
+ free( collTypeStructure ); \
+ free( mddTypeStructure ); )
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // free resources
+ context->transferColl->releaseAll();
+ delete context->transferColl;
+ context->transferColl = 0;
+
+ // return error
+ returnValue = 4;
+ RMInit::logOut << "Error: MDD type not compatible wrt. its domain: " << domain << MSG_FAILED << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ if( !context->transferColl->getCollectionType()->compatibleWith( mddType ) )
+ {
+ // free resources
+ context->transferColl->releaseAll();
+ delete context->transferColl;
+ context->transferColl = 0;
+
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: incompatible MDD and collection types." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // Create persistent MDD for further tile insertions
+ //
+
+ StorageLayout ms;
+ ms.setTileSize(StorageLayout::DefaultTileSize);
+ ms.setIndexType(StorageLayout::DefaultIndexType);
+ ms.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (domain.dimension() == StorageLayout::DefaultTileConfiguration.dimension())
+ ms.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+ try
+ {
+ context->assembleMDD = new MDDObj( mddBaseType, domain, OId( oid.get_local_oid() ), ms );
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: while creating persistent tile: " << err.get_errorno() << ": " << err.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 6;
+ RMInit::logOut << "Error: unspecific exception during creation of persistent object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type '" << typeName << "' has no base type..." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "startInsertPersMDD" )
+ return returnValue;
+}
+
+
+/*************************************************************************
+ * Method name...: executeQuery( unsigned long callingClientId,
+ * const char* query
+ * ExecuteQueryRes &returnStructure )
+ ************************************************************************/
+unsigned short
+ServerComm::executeQuery( unsigned long callingClientId,
+ const char* query,
+ ExecuteQueryRes &returnStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "executeQuery" )
+ unsigned short returnValue=0;
+
+ // set all to zero as default. They are not really applicable here.
+ returnStructure.errorNo = 0;
+ returnStructure.lineNo = 0;
+ returnStructure.columnNo = 0;
+
+ RMInit::logOut << "Request: executeQquery '" << query << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+#ifdef RMANBENCHMARK
+ RMTimer* queryOptimizationTimer = 0;
+
+ Tile::relTimer.start();
+ Tile::relTimer.pause();
+ Tile::opTimer.start();
+ Tile::opTimer.pause();
+ ZLibCompression::decompTimer.start();
+ ZLibCompression::decompTimer.pause();
+ ZLibCompression::compTimer.start();
+ ZLibCompression::compTimer.pause();
+
+ if( RManBenchmark > 0 )
+ RMInit::bmOut << "Query: " << query << std::endl;
+#endif
+
+#ifdef PURIFY
+ purify_printf( "%s\n", query );
+#endif
+
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ //
+ // execute the query
+ //
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ queryOptimizationTimer = new RMTimer("ServerComm", "optimization time");
+#endif
+
+
+
+ QueryTree* qtree = new QueryTree(); // create a query tree object...
+ parseQueryTree = qtree; // ...and assign it to the global parse query tree pointer;
+
+ currentClientTblElt = context; // assign current client table element (temporary)
+
+ int ppRet = 0;
+ int parserRet = 0;
+
+ udfEnabled = 0; // Forced for RNP, but only temporary...
+ if(udfEnabled)
+ {
+ //
+ // preprocess
+ //
+ RMInit::logOut << "preprocessing..." << std::flush;
+ ppInBuf = (char *)query;
+ ppreset();
+ ppRet = ppparse();
+
+ RMInit::dbgOut << "new query: '" << ppOutBuf << "'..." << std::flush;
+
+ // initialize the input string parameters
+ beginParseString = ppOutBuf;
+ iterParseString = ppOutBuf;
+ }
+ else
+ {
+ beginParseString = (char*)query;
+ iterParseString = (char*)query;
+ }
+
+ yyreset();
+
+ RMInit::logOut << "parsing..." << std::flush;
+
+ parserRet=yyparse(0);
+ if((ppRet == 0) && (parserRet == 0))
+ {
+ try
+ {
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeQuery", \
+ qtree->printTree( 2, RMInit::logOut);
+ );
+
+ RMInit::logOut << "checking semantics..." << std::flush;
+ qtree->checkSemantics();
+
+ unsigned int localOptimizationLevel = globalOptimizationLevel < qtree->getOptimizationLevel() ?
+ globalOptimizationLevel : qtree->getOptimizationLevel();
+
+ RMInit::logOut << "optimizing (level " << localOptimizationLevel << ")..." << std::flush;
+ qtree->optimize( localOptimizationLevel );
+
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeQuery", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ {
+ delete queryOptimizationTimer;
+ queryOptimizationTimer = 0;
+ }
+
+ if( RManBenchmark > 0 )
+ context->evaluationTimer = new RMTimer("ServerComm", "evaluation time ");
+#endif
+ qtree->printTree( 2, std::cout );
+ //qtree->checkSemantics();
+ //qtree->printTree( 2, std::cout );
+ RMInit::logOut << "evaluating..." << std::flush;
+ context->transferData = qtree->evaluateRetrieval();
+ }
+ catch( ParseInfo& info )
+ {
+ // this is the old error handling which has been here for quite some time
+ // dealing with errors when release data
+ context->releaseTransferStructures();
+
+ returnValue = 5; // execution error
+
+ // set the error values of the return structure
+ returnStructure.errorNo = info.getErrorNo();
+ returnStructure.lineNo = info.getLineNo();
+ returnStructure.columnNo = info.getColumnNo();
+ returnStructure.token = strdup( info.getToken().c_str() );
+
+ RMInit::logOut << "Error: cannot parse query (1)." << std::endl;
+ info.printStatus( RMInit::logOut );
+ }
+ catch( r_Ebase_dbms& myErr )
+ {
+ RMInit::logOut << "Error: base DBMS exception: " << myErr.what() << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 42; // general serialisable exception
+
+ throw;
+ }
+ catch( r_Error& myErr )
+ {
+ RMInit::logOut << "Error: " << myErr.get_errorno() << " " << myErr.what() << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 5;
+
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 5;
+
+ throw;
+ }
+
+ if( returnValue == 0 )
+ {
+ if( context->transferData != 0 )
+ {
+ // create the transfer iterator
+ context->transferDataIter = new vector<QtData*>::iterator;
+ *(context->transferDataIter) = context->transferData->begin();
+
+ //
+ // set typeName and typeStructure
+ //
+
+ // The type of first result object is used to determine the type of the result
+ // collection.
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ QtData* firstElement = (**(context->transferDataIter));
+
+ if( firstElement->getDataType() == QT_MDD )
+ {
+ QtMDD* mddObj = (QtMDD*)firstElement;
+ const BaseType* baseType = mddObj->getMDDObject()->getCellType();
+ r_Minterval domain = mddObj->getLoadDomain();
+
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, domain );
+ SetType* setType = new SetType( "tmp", mddType );
+
+ returnStructure.typeName = strdup( setType->getTypeName() );
+ returnStructure.typeStructure = setType->getTypeStructure(); // no copy
+
+ TypeFactory::addTempType( setType );
+ TypeFactory::addTempType( mddType );
+ }
+ else
+ {
+ returnValue = 1; // evaluation ok, non-MDD elements
+
+ returnStructure.typeName = strdup("");
+
+ // hack set type
+ char* elementType = firstElement->getTypeStructure();
+ returnStructure.typeStructure = (char*)mymalloc( strlen(elementType) + 6 );
+ sprintf( returnStructure.typeStructure, "set<%s>", elementType );
+ free( elementType );
+ }
+
+ strcpy(globalHTTPSetTypeStructure, returnStructure.typeStructure);
+
+ RMInit::logOut << MSG_OK << ", result type '" << returnStructure.typeStructure << "', " << context->transferData->size() << " element(s)." << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+
+ returnStructure.typeName = strdup("");
+ returnStructure.typeStructure = strdup("");
+ }
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+ }
+ }
+ }
+ else
+ {
+ if(ppRet)
+ {
+ RMInit::logOut << MSG_OK << ",result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+ }
+ else // parse error
+ {
+ if( parseError )
+ {
+ returnStructure.errorNo = parseError->getErrorNo();
+ returnStructure.lineNo = parseError->getLineNo();
+ returnStructure.columnNo = parseError->getColumnNo();
+ returnStructure.token = strdup( parseError->getToken().c_str() );
+
+ delete parseError;
+ parseError = 0;
+ }
+ else
+ {
+ returnStructure.errorNo = 309;
+ RMInit::logOut << "Internal Error: Unknown parse error.";
+ }
+
+ yyreset(); // reset the input buffer of the scanner
+
+ RMInit::logOut << "Error: cannot parse query (2)." << std::endl;
+ returnValue = 4;
+ }
+ }
+
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ //
+ // done
+ //
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ delete queryOptimizationTimer;
+
+ // Evaluation timer can not be stopped because some time spent in the transfer
+ // module is added to this phase.
+ if( context->evaluationTimer )
+ context->evaluationTimer->pause();
+
+ if( RManBenchmark > 0 )
+ context->transferTimer = new RMTimer("ServerComm", "transfer time ");
+#endif
+
+ // In case of an error or the result set is empty, no endTransfer()
+ // is called by the client.
+ // Therefore, some things have to be release here.
+ if( returnValue >= 2)
+ {
+#ifdef RMANBENCHMARK
+ Tile::o2Timer.stop();
+ Tile::opTimer.stop();
+ Tile::relTimer.stop();
+ Tile::opTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+ if( context->evaluationTimer )
+ delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+
+ if( context->transferTimer )
+ delete context->transferTimer;
+ context->transferTimer = 0;
+
+ RMTimer* releaseTimer = 0;
+
+ if( RManBenchmark > 0 )
+ releaseTimer = new RMTimer("ServerComm", "release time ");
+#endif
+
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( releaseTimer )
+ delete releaseTimer;
+#endif
+ }
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "executeQuery" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::initExecuteUpdate( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "initExecuteUpdate" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: initExecuteUpdate..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ MDDType* mddType = new MDDType( "tmp" );
+ SetType* setType = new SetType( "tmp", mddType );
+
+ TypeFactory::addTempType( mddType );
+ TypeFactory::addTempType( setType );
+
+ // create a transient collection for storing MDD constants
+ context->transferColl = new MDDColl( setType );
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "initExecuteUpdate" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::startInsertTransMDD( unsigned long callingClientId,
+ r_Minterval &domain, unsigned long typeLength,
+ const char* typeName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: startInsertTransMDD type '"
+ << typeName <<"', domain " << domain << ", cell length " << typeLength << ", "
+ << domain.cell_count()*typeLength << " bytes..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD(...) TRANSFER " << context->transferFormat << ", EXACT " << (bool)context->exactFormat);
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: MDD type incompatible wrt. domain: " << domain << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ // create for further insertions
+ context->transferMDD = new MDDObj( mddBaseType, domain );
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type has no base type." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::endInsertMDD( unsigned long callingClientId,
+ int isPersistent )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "endInsertMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: endInsertMDD..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ if( isPersistent )
+ {
+ // we are finished with this MDD Object, so insert it into the collection
+ context->transferColl->insert( context->assembleMDD );
+
+ // reset assembleMDD, because otherwise it is tried to be freed
+ context->assembleMDD = 0;
+
+ // free transfer structure
+ context->releaseTransferStructures();
+
+ // old: context->transferColl->releaseAll(); caused a crash because releaseAll() is not idempotent
+ }
+ else
+ {
+ // we are finished with this MDD Object, so insert it into the collection
+ context->transferColl->insert( context->transferMDD );
+
+ // reset transferMDD
+ context->transferMDD = 0;
+
+ // Do not delete the transfer structure because the transient set
+ // of MDD objects will be used as constants for executeUpdate().
+ }
+
+ RMInit::logOut << MSG_OK << std::endl;
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "endInsertMDD" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::executeUpdate( unsigned long callingClientId,
+ const char* query,
+ ExecuteUpdateRes &returnStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "executeUpdate" )
+
+ RMInit::logOut << "Request: executeUpdate query '" << query << "'..." << std::flush;
+
+#ifdef RMANBENCHMARK
+ RMTimer* queryOptimizationTimer = 0;
+ Tile::relTimer.start();
+ Tile::relTimer.pause();
+ Tile::opTimer.start();
+ Tile::opTimer.pause();
+ ZLibCompression::decompTimer.start();
+ ZLibCompression::decompTimer.pause();
+ ZLibCompression::compTimer.start();
+ ZLibCompression::compTimer.pause();
+
+ if( RManBenchmark > 0 )
+ RMInit::bmOut << "Query (update): " << query << std::endl;
+#endif
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+#ifdef PURIFY
+ purify_printf( "%s\n", query );
+#endif
+
+ //
+ // execute the query
+ //
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ queryOptimizationTimer = new RMTimer("ServerComm", "optimization time");
+#endif
+
+ QueryTree* qtree = new QueryTree(); // create a query tree object...
+ parseQueryTree = qtree; // ...and assign it to the global parse query tree pointer;
+
+ mddConstants = context->transferColl; // assign the mdd constants collection to the global pointer (temporary)
+ currentClientTblElt = context; // assign current client table element (temporary)
+
+ int ppRet = 0;
+ udfEnabled = false; // forced for RNP tests
+ if(udfEnabled)
+ {
+ //
+ // preprocess
+ //
+ RMInit::logOut << "preprocessing..." << std::flush;
+ ppInBuf = (char *)query;
+ ppreset();
+ ppRet = ppparse();
+
+ if(ppOutBuf)
+ RMInit::dbgOut << "new query: '" << ppOutBuf << "'" << std::endl;
+ else
+ RMInit::dbgOut << "new query: empty." << std::endl;
+
+ // initialize the input string parameters
+ beginParseString = ppOutBuf;
+ iterParseString = ppOutBuf;
+ }
+ else
+ {
+ beginParseString = (char*)query;
+ iterParseString = (char*)query;
+ }
+
+ yyreset();
+
+ RMInit::logOut << "parsing..." << std::flush;
+
+ if( ppRet == 0 && yyparse(0) == 0 )
+ {
+ try
+ {
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeUpdate", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+ RMInit::logOut << "checking semantics..." << std::flush;
+
+ qtree->checkSemantics();
+
+ // coman: Why is disabled optimization for update query?
+ // unsigned int localOptimizationLevel = globalOptimizationLevel < qtree->getOptimizationLevel() ?
+ // globalOptimizationLevel : qtree->getOptimizationLevel();
+
+ unsigned int localOptimizationLevel = 0;
+
+ RMInit::logOut << "optimizing (level " << localOptimizationLevel << ")..." << std::flush;
+ qtree->optimize( localOptimizationLevel );
+
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeUpdate", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ {
+ delete queryOptimizationTimer;
+ queryOptimizationTimer = 0;
+ }
+
+ if( RManBenchmark > 0 )
+ context->evaluationTimer = new RMTimer("ServerComm", "evaluation time ");
+#endif
+
+ RMInit::logOut << "evaluating..." << std::flush;
+ qtree->evaluateUpdate();
+
+ // release data
+ context->releaseTransferStructures();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ catch( ParseInfo& info )
+ {
+ // release data
+ context->releaseTransferStructures();
+
+ returnValue = 3; // evaluation error
+
+ // set the error values of the return structure
+ returnStructure.errorNo = info.getErrorNo();
+ returnStructure.lineNo = info.getLineNo();
+ returnStructure.columnNo = info.getColumnNo();
+ returnStructure.token = strdup( info.getToken().c_str() );
+
+ RMInit::logOut << "Error: cannot parse query (1)." << std::endl;
+ info.printStatus( RMInit::logOut );
+ }
+ catch(r_Error &err)
+ {
+ context->releaseTransferStructures();
+ context->release();
+ RMInit::logOut << "Error: " << err.get_errorno() << " " << err.what() << std::endl;
+ throw;
+ }
+ }
+ else
+ {
+ if(ppRet)
+ {
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+ }
+ else // parse error
+ {
+ if( parseError )
+ {
+ returnStructure.errorNo = parseError->getErrorNo();
+ returnStructure.lineNo = parseError->getLineNo();
+ returnStructure.columnNo = parseError->getColumnNo();
+ returnStructure.token = strdup( parseError->getToken().c_str() );
+
+ delete parseError;
+
+ RMInit::logOut << "Error: cannot parse query (2)." << std::endl;
+ parseError = 0;
+ }
+ else
+ {
+ returnStructure.errorNo = 309;
+ RMInit::logOut << "Error: unspecific internal parser error." << endl;
+ }
+
+ yyreset(); // reset the input buffer of the scanner
+
+ returnValue = 2;
+ }
+ }
+
+ parseQueryTree = 0;
+ mddConstants = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ // delete set of mdd constants
+ context->releaseTransferStructures();
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ delete queryOptimizationTimer;
+
+ // stop evaluation timer
+ if( context->evaluationTimer )
+ {
+ delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+ }
+
+ Tile::opTimer.stop();
+ Tile::relTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "executeUpdate" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "ServerComm::getCollByName" )
+
+ RMInit::logOut << "Request: getCollByName '" << collName << "'..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ //
+ // create the actual transfer collenction
+ //
+
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // create the transfer collection
+ try
+ {
+ context->transferColl = MDDColl::getMDDCollection( collName );
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved mdd collection" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << " " << err.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+ }
+
+ if( returnValue == 0 )
+ {
+ // create the transfer iterator
+ context->transferCollIter = context->transferColl->createIterator();
+ context->transferCollIter->reset();
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) context->transferColl->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid in case of a persistent collection
+ if( context->transferColl->isPersistent() )
+ {
+ EOId eOId;
+ if (context->transferColl->isPersistent())
+ {
+ if (context->transferColl->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ }
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Warning: cannot obtain collection type information." << endl;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( !context->transferCollIter->notDone() )
+ {
+ RMInit::logOut << MSG_OK << ", result empty.";
+ returnValue = 1;
+
+ // delete transfer collection/iterator
+ context->releaseTransferStructures();
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByName" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ char* &collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByOId" )
+
+ RMInit::logOut << "Request: getCollByOId " << oid << "..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDCOLLOID )
+ {
+ //
+ // get collection
+ //
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm",
+ std::endl << " execute new PersMDDColl(" << oid << ")" )
+ context->transferColl = MDDColl::getMDDCollection(oidIf);
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", " ok" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << " " << err.what() << std::endl;
+ throw;
+ }
+ catch(...) // not found (?)
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: unspecific exception." << endl;
+ }
+
+ //
+ // create the actual transfer collenction
+ //
+
+ if( returnValue == 0 )
+ {
+ // get collection name
+ collName = strdup(context->transferColl->getName());
+
+ // create the transfer iterator
+ context->transferCollIter = context->transferColl->createIterator();
+ context->transferCollIter->reset();
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) context->transferColl->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid in case of a persistent collection
+ if( context->transferColl->isPersistent() )
+ {
+ EOId eOId;
+
+ if (context->transferColl->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", but warning: cannot obtain type information." << endl;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( !context->transferCollIter->notDone() )
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+
+ // delete transfer collection/iterator
+ context->releaseTransferStructures();
+ }
+ }
+
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to a collection object
+ RMInit::logOut << "Error: oid does not belong to a collection object." << std::endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByOId" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollOIdsByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByName" )
+
+ RMInit::logOut << "Request: getCollOIdsByName '" << collName << "'..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ //
+ // get collection
+ //
+
+ MDDColl* coll = 0;
+ MDDColl* almost = 0;
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieving collection " << collName)
+ almost = MDDColl::getMDDCollection( collName );
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved collection " << collName)
+ if (!almost->isPersistent())
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved system collection")
+ RMInit::logOut << "Error: trying to get oid of system collection: " << collName << std::endl;
+ throw r_Error(SYSTEM_COLLECTION_HAS_NO_OID);
+ }
+ else
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved persistent collection")
+ coll = (MDDColl*)almost;
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "caught exception")
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 2; // collection name invalid
+ }
+ catch(...)
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "caught exception")
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+ }
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "after exception catching")
+
+ if( returnValue == 0 )
+ {
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) coll->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid
+ EOId eOId;
+
+ if (coll->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ else
+ {
+ RMInit::logOut << "Warning: no type information available..." << std::flush;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( coll->getCardinality() )
+ {
+ // create iterator
+ MDDCollIter* collIter = coll->createIterator();
+ int i;
+
+ oidTableSize = coll->getCardinality();
+ oidTable = (RPCOIdEntry*) mymalloc( sizeof(RPCOIdEntry) * oidTableSize );
+
+ TALK( oidTableSize << " elements..." );
+
+ for( collIter->reset(), i=0; collIter->notDone(); collIter->advance(), i++ )
+ {
+ MDDObj* mddObj = collIter->getElement();
+
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oidTable[i].oid = strdup( r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() ).get_string_representation() );
+ else
+ oidTable[i].oid = strdup("");
+ mddObj = 0;
+ }
+ else
+ oidTable[i].oid = strdup("");
+ }
+
+ delete collIter;
+
+ RMInit::logOut << MSG_OK << ", " << coll->getCardinality() << " result(s)." << endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+ }
+
+ delete coll;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByName " << returnValue)
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::getCollOIdsByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize,
+ char* &collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByOId" )
+
+ RMInit::logOut << "Request: getCollOIdsByOId " << oid << "..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDCOLLOID )
+ {
+ //
+ // get collection
+ //
+
+ MDDColl* coll = 0;
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "get mdd coll by oid " << oidIf)
+ coll = MDDColl::getMDDCollection(oidIf);
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved mdd coll" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 2; // collection name invalid
+ if (err.get_kind() != r_Error::r_Error_RefNull)
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unknown collection name." << std::endl;
+ }
+
+ if( returnValue == 0 )
+ {
+ // get collection name
+ collName = strdup(coll->getName());
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) coll->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid
+ EOId eOId;
+
+ if (coll->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ else
+ {
+ RMInit::logOut << "Warning: no type information available..." << std::flush;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( coll->getCardinality() )
+ {
+ // create iterator
+ MDDCollIter* collIter = coll->createIterator();
+ int i;
+
+ oidTableSize = coll->getCardinality();
+ oidTable = (RPCOIdEntry*) mymalloc( sizeof(RPCOIdEntry) * oidTableSize );
+
+ TALK( oidTableSize << " elements..." );
+
+ for( collIter->reset(), i=0; collIter->notDone(); collIter->advance(), i++ )
+ {
+ MDDObj* mddObj = collIter->getElement();
+
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oidTable[i].oid = strdup( r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() ).get_string_representation() );
+ else
+ oidTable[i].oid = strdup("");
+ }
+ else
+ oidTable[i].oid = strdup("");
+ }
+
+ delete collIter;
+ //coll->releaseAll();
+
+ RMInit::logOut << MSG_OK << ", " << coll->getCardinality() << " result(s)." << endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+ }
+
+ delete coll;
+ }
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to a collection object
+ RMInit::logOut << "Error: not a collection oid: " << oid << std::endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByOId " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNextMDD( unsigned long callingClientId,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ unsigned short &currentFormat )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNextMDD" )
+
+ RMInit::logOut << "Request: getNextMDD..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ try
+ {
+ if( context->transferData && context->transferDataIter && *(context->transferDataIter) != context->transferData->end() )
+ {
+ //
+ // convert the mdd to transfer to rpc data structures
+ //
+
+ // get the MDD object to be transfered
+ QtMDD* mddData = (QtMDD*) **(context->transferDataIter);
+ MDDObj* mddObj = mddData->getMDDObject();
+
+ // initialize mddDomain to give it back
+ mddDomain = mddData->getLoadDomain();
+
+ TALK( "domain " << mddDomain );
+
+ //
+ // initialize tiles to transfer
+ //
+
+#ifdef RMANBENCHMARK
+ // pause transfer timer and resume evaluation timer
+ if( context->transferTimer )
+ context->transferTimer->pause();
+ if( context->evaluationTimer )
+ context->evaluationTimer->resume();
+#endif
+
+ if( mddObj->getCurrentDomain() == mddData->getLoadDomain() )
+ context->transTiles = mddObj->getTiles();
+ else
+ {
+ // If the load domain is different from the current domain, we have
+ // a persitent MDD object. The border tiles have to be cut (and
+ // therefore copied) in order to be ready for transfering them.
+ // These temporary border tiles are added to the deletableTiles list
+ // which is deleted at the end.
+
+ context->transTiles = mddObj->intersect( mddData->getLoadDomain() );
+
+ // iterate over the tiles
+ for( vector<Tile*>::iterator iter = context->transTiles->begin(); iter != context->transTiles->end(); iter++ )
+ {
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain( mddData->getLoadDomain().create_intersection( (*iter)->getDomain() ) );
+
+ if( sourceTileDomain != (*iter)->getDomain() )
+ {
+ // create a new transient tile and copy the transient data
+ Tile* newTransTile = new Tile( sourceTileDomain, mddObj->getCellType() );
+ newTransTile->copyTile( sourceTileDomain, *iter, sourceTileDomain );
+
+ // replace the tile in the list with the new one
+ *iter = newTransTile;
+
+ // add the new tile to deleteableTiles
+ if( !(context->deletableTiles) )
+ context->deletableTiles = new vector<Tile*>();
+ context->deletableTiles->push_back( newTransTile );
+ }
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ // In order to be sure that reading tiles from disk is done
+ // in the evaluation phase, the contents pointers of each tile
+ // are got.
+ char* benchmarkPointer;
+
+ for( vector<Tile*>::iterator benchmarkIter = context->transTiles->begin();
+ benchmarkIter != context->transTiles->end(); benchmarkIter++ )
+ benchmarkPointer = (*benchmarkIter)->getContents();
+
+ // pause evaluation timer and resume transfer timer
+ if( context->evaluationTimer )
+ context->evaluationTimer->pause();
+ if( context->transferTimer )
+ context->transferTimer->resume();
+#endif
+
+ // initialize tile iterator
+ context->tileIter = new vector<Tile*>::iterator;
+ *(context->tileIter) = context->transTiles->begin();
+
+ const BaseType* baseType = mddObj->getCellType();
+
+ TALK( "cell length " << baseType->getSize() );
+
+ //
+ // set typeName and typeStructure
+ //
+ // old: typeName = strdup( mddObj->getCellTypeName() ); not known for the moment being
+ typeName = strdup("");
+
+ // create a temporary mdd type for the moment being
+ r_Minterval typeDomain( mddData->getLoadDomain() );
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, typeDomain );
+ TypeFactory::addTempType( mddType );
+
+ typeStructure = mddType->getTypeStructure(); // no copy !!!
+
+ // I'm not sure about this code...
+#if 0
+ // determine data format from the 1st tile
+ if( context->transTiles->size() && (*(context->transTiles))[0]->getDataFormat() == r_TIFF )
+ currentFormat = r_TIFF;
+ else
+ currentFormat = r_Array;
+#else
+ if (context->transTiles->size())
+ currentFormat = (*(context->transTiles))[0]->getDataFormat();
+ else
+ currentFormat = r_Array;
+#endif
+
+ // set oid in case of persistent MDD objects
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+
+ //
+ //
+ //
+
+ if( context->transTiles->size() > 0 )
+ {
+ RMInit::logOut << MSG_OK << ", " << context->transTiles->size() << " more tile(s)" << endl;
+ }
+ else // context->transTiles->size() == 0
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: no tiles in MDD object." << std::endl;
+ }
+
+ context->totalTransferedSize = 0;
+ context->totalRawSize = 0;
+ }
+ else
+ {
+ if( context->transferDataIter && *(context->transferDataIter) == context->transferData->end() )
+ {
+ returnValue = 1; // nothing left in the collection
+ RMInit::logOut << MSG_OK << ", no more tiles." << std::endl;
+ context->releaseTransferStructures();
+ }
+ else
+ {
+ returnValue = 2; // no actual transfer collection
+ RMInit::logOut << "Error: no transfer collection. " << std::endl;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ catch( r_Ebase_dbms& myErr )
+ {
+ RMInit::logOut << "Error: base DBMS exception (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ returnValue = 42;
+ throw;
+ }
+ catch( r_Error& myErr )
+ {
+ RMInit::logOut << "Error: (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: unspecified exception." << std::endl;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 2;
+ }
+
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNextMDD" )
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::getNextElement( unsigned long callingClientId,
+ char* &buffer,
+ unsigned int &bufferSize)
+{
+ RMDBGENTER(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...)")
+
+ RMInit::logOut << "Request: getNextElement..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...) TRANSFER " << context->transferFormat << ", EXACT " << (bool)context->exactFormat);
+
+ if( context->transferData && context->transferDataIter &&
+ *(context->transferDataIter) != context->transferData->end() )
+ {
+
+ //
+ // convert data element to rpc data structures
+ //
+ // Buffer is allocated and has to be freed by the caller using free().
+
+ // get next object to be transfered
+ try
+ {
+ QtData* dataObj = **(context->transferDataIter);
+
+ switch( dataObj->getDataType() )
+ {
+ case QT_STRING:
+ {
+ QtStringData* stringDataObj = (QtStringData*)dataObj;
+ bufferSize = stringDataObj->getStringData().length();
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringDataObj->getStringData().c_str(), bufferSize );
+ }
+ break;
+ case QT_INTERVAL:
+ {
+ QtIntervalData* intervalDataObj = (QtIntervalData*)dataObj;
+ char* stringData = intervalDataObj->getIntervalData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+ free( stringData );
+ }
+ break;
+ case QT_MINTERVAL:
+ {
+ QtMintervalData* mintervalDataObj = (QtMintervalData*)dataObj;
+ char* stringData = mintervalDataObj->getMintervalData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+ free( stringData );
+ }
+ break;
+ case QT_POINT:
+ {
+ QtPointData* pointDataObj = (QtPointData*)dataObj;
+ char* stringData = pointDataObj->getPointData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+
+ free( stringData );
+ }
+ break;
+ default:
+ if( dataObj->isScalarData() )
+ {
+ QtScalarData* scalarDataObj = (QtScalarData*)dataObj;
+ bufferSize = scalarDataObj->getValueType()->getSize();
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)scalarDataObj->getValueBuffer(), bufferSize );
+ // server endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+
+ // change endianess if necessary
+ // currently only one client is active at one time
+ // if((context->clientId == 1) && (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ if( (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ {
+ RMInit::logOut << "changing endianness..." << std::flush;
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ switch(scalarDataObj->getDataType())
+ {
+ case QT_USHORT:
+ {
+ r_UShort tmp = *(r_UShort*)buffer;
+ *(r_UShort*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_SHORT:
+ {
+ r_Short tmp = *(r_Short*)buffer;
+ *(r_Short*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_LONG:
+ {
+ r_Long tmp = *(r_Long*)buffer;
+ *(r_Long*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_ULONG:
+ {
+ r_ULong tmp = *(r_ULong*)buffer;
+ *(r_ULong*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_FLOAT:
+ {
+ r_Float tmp = *(r_Float*)buffer;
+ *(r_Float*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_DOUBLE:
+ {
+ r_Double tmp = *(r_Double*)buffer;
+ *(r_Double*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ default:
+ {
+ RMDBGENTER( 0, RMDebug::module_servercomm, "ServerComm", "getNextElement(...) bad dataType " << scalarDataObj->getDataType());
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ catch( r_Ebase_dbms& myErr)
+ {
+ RMInit::logOut << "Error: base BMS exception (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: exception (kind " << err.get_kind() << ", errno " << err.get_errorno() << ") " << err.what() << std::endl;
+ throw;
+ }
+
+ // increment list iterator
+ (*(context->transferDataIter))++;
+
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", some more tile(s) left." << endl;
+ }
+ else
+ {
+ returnValue = 1;
+ RMInit::logOut << MSG_OK << ", no more tiles." << std::endl;
+ }
+ }
+ else
+ {
+ if( context->transferDataIter && *(context->transferDataIter) == context->transferData->end() )
+ {
+ returnValue = 1; // nothing left in the collection
+ TALK( "nothing left..." << MSG_OK );
+ context->releaseTransferStructures();
+ }
+ else
+ {
+ returnValue = 2; // no actual transfer collection
+ RMInit::logOut << "Error: no transfer collection." << endl;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 2;
+ }
+
+ RMDBGEXIT(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...)")
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getMDDByOId( unsigned long callingClientId,
+ r_OId &oid,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ unsigned short &currentFormat )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getMDDByOId" )
+
+ RMInit::logOut << "Request: getMDDByOId with oid " << oid << "..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDOID )
+ {
+ // get MDD object
+ try
+ {
+ context->transferMDD = new MDDObj( oidIf );
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release();
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: (kind " << err.get_kind() << ", errno " << err.get_errorno() << ") " << err.what() << std::endl;
+ context->release();
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: unspecified exception." << endl;
+ }
+
+ if( !returnValue )
+ {
+ //
+ // convert the mdd to transfer to rpc data structures
+ //
+
+ // initialize mddDomain to give it back
+ mddDomain = context->transferMDD->getCurrentDomain();
+
+ TALK( "domain " << mddDomain );
+
+ // initialize context fields
+ context->transTiles = context->transferMDD->getTiles();
+ context->tileIter = new vector<Tile*>::iterator;
+ *(context->tileIter) = context->transTiles->begin();
+
+ const BaseType* baseType = context->transferMDD->getCellType();
+
+ TALK( "cell length " << baseType->getSize() );
+
+ //
+ // set typeName and typeStructure
+ //
+ // old: typeName = strdup( context->transferMDD->getCellTypeName() ); not known for the moment being
+
+ typeName = strdup("");
+
+ // create a temporary mdd type for the moment being
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, context->transferMDD->getCurrentDomain() );
+ TypeFactory::addTempType( mddType );
+
+ typeStructure = mddType->getTypeStructure(); // no copy !!!
+
+ // I'm not sure about this code either
+#if 0
+ // determine data format from the 1st tile
+ if( context->transTiles->size() && (*(context->transTiles))[0]->getDataFormat() == r_TIFF )
+ currentFormat = r_TIFF;
+ else
+ currentFormat = r_Array;
+#else
+ if (context->transTiles->size())
+ currentFormat = (*(context->transTiles))[0]->getDataFormat();
+ else
+ currentFormat = r_Array;
+#endif
+
+ // set oid in case of persistent MDD objects
+ if( context->transferMDD->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)(context->transferMDD))->getEOId( &eOId ) == 0 )
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+
+ //
+ //
+ //
+
+ if( context->transTiles->size() > 0 )
+ {
+ RMInit::logOut << MSG_OK << ", got " << context->transTiles->size() << " tile(s)." << endl;
+ }
+ else // context->transTiles->size() == 0
+ {
+ returnValue = 3;
+ RMInit::logOut << "Error: no tiles in MDD object." << endl;
+ }
+ }
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to an MDD object
+ RMInit::logOut << "Error: oid does not belong to an MDD object." << endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1; // client context not found
+ }
+
+ context->totalRawSize = 0;
+ context->totalTransferedSize = 0;
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getMDDByOId" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNextTile( unsigned long callingClientId,
+ RPCMarray** rpcMarray )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile" )
+
+ RMInit::logOut << "Request: getNextTile..." << std::flush;
+
+ unsigned long transOffset = 0;
+ unsigned long transSize = 0;
+ unsigned short statusValue = 0;
+ unsigned short returnValue = 0;
+
+ // initialize the result parameter for failure cases
+ *rpcMarray = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ if( context->transTiles && context->tileIter )
+ {
+ Tile* resultTile = **(context->tileIter);
+ r_Minterval mddDomain = resultTile->getDomain();
+ void* useTransData;
+ unsigned long totalSize;
+
+ // allocate memory for the output parameter rpcMarray
+ *rpcMarray = (RPCMarray*)mymalloc( sizeof( RPCMarray ) );
+
+ if ( context->bytesToTransfer == 0 )
+ {
+ // free old data
+ if (context->encodedData != NULL)
+ {
+ free(context->encodedData);
+ context->encodedData = NULL;
+ context->encodedSize = 0;
+ }
+
+ // Transfer compression...
+ // we have to repack the data if ((tf != cf) && exact) or ((tf != Array) && (cf == Array))
+ // where tf = transferFormat, cf = currentFormat.
+ r_Data_Format tf = context->transferFormat;
+ r_Data_Format cf = resultTile->getDataFormat();
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile CURRENT " << cf << ", TRANSFER " << tf << ", EXACT " << (bool)context->exactFormat);
+ if (((tf != cf) && (context->exactFormat != 0)) || ((tf != r_Array) && (cf == r_Array)))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "repack data from " << cf << " to " << tf)
+
+ //the cast from const char* to char* is okay because the owner flag is set correctly
+ char *encData = (char*)resultTile->getCompressedContents();
+ unsigned long encSize = resultTile->getCompressedSize();
+ //the data format could have changed during compression
+ cf = resultTile->getDataFormat();
+ // this method actually repacks everything as needed
+ if(ensureTileFormat(cf, tf, mddDomain, resultTile->getType(),
+ encData, encSize, 1, 0, context->transferFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 4;
+
+ RMInit::logOut << "Error: tile format mismatch while fetching next tile." << endl;
+ (*rpcMarray)->domain = mddDomain.get_string_representation();
+
+ // allocate memory for the output parameter data and assign its fields
+ (*rpcMarray)->data.confarray_len = 0;
+ (*rpcMarray)->data.confarray_val = NULL;
+ // 3. store cell type length
+ (*rpcMarray)->cellTypeLength = 0;
+
+ context->release();
+ return returnValue;
+ }
+ // if the new format is bigger than the old one and we're allowed to, revert to the old one
+ if ((encSize >= resultTile->getCompressedSize()) && (context->exactFormat == 0))
+ {
+ free( encData );
+ }
+ else
+ {
+ context->encodedData = encData;
+ context->encodedSize = encSize;
+ }
+ }
+ }
+
+ // note: transfer compression affects the current format, not the storage format.
+ if ( context->encodedData == NULL )
+ {
+ totalSize = resultTile->getCompressedSize();
+ //this is bad because useTransData is char* although it is not modified
+ useTransData = (char*)resultTile->getCompressedContents();
+ (*rpcMarray)->currentFormat = resultTile->getDataFormat();
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "using tile format " << (r_Data_Format)(*rpcMarray)->currentFormat)
+ }
+ else
+ {
+ totalSize = context->encodedSize;
+ useTransData = context->encodedData;
+ (*rpcMarray)->currentFormat = context->transferFormat;
+ //FILE *fp = fopen("trans_data.raw", "wb"); fwrite(useTransData, 1, totalSize, fp); fclose(fp);
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "using transfer format " << (r_Data_Format)(*rpcMarray)->currentFormat)
+ }
+ // Preserve storage format
+ (*rpcMarray)->storageFormat = resultTile->getDataFormat();
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "rpc storage " << (r_Data_Format)(*rpcMarray)->storageFormat)
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "rpc current " << (r_Data_Format)(*rpcMarray)->currentFormat)
+
+ transSize = totalSize;
+
+ if( totalSize > maxTransferBufferSize )
+ {
+ // if there is the rest of a tile to transfer, do it!
+ if( context->bytesToTransfer )
+ {
+ TALK( " resuming block transfer..." );
+ transOffset = totalSize - context->bytesToTransfer;
+ if( context->bytesToTransfer > maxTransferBufferSize )
+ {
+ transSize = maxTransferBufferSize;
+ statusValue = 1;
+ }
+ else
+ {
+ transSize = context->bytesToTransfer;
+ statusValue = 2;
+ }
+
+ context->bytesToTransfer -= transSize;
+ }
+ else // transfer first block of too large tile
+ {
+ TALK( " has to be split..." );
+ transSize = maxTransferBufferSize;
+ context->bytesToTransfer = totalSize - transSize;
+ statusValue = 1;
+ }
+ }
+ else // resultTile->getSize() <= maxTransferBufferSize
+ statusValue = 3;
+
+ context->totalTransferedSize += transSize;
+
+ // 1. convert domain
+ (*rpcMarray)->domain = mddDomain.get_string_representation();
+
+ // 2. copy data pointers
+ TALK( " domain " << mddDomain << ", " << transSize << " bytes" );
+
+ // allocate memory for the output parameter data and assign its fields
+ (*rpcMarray)->data.confarray_len = (unsigned int)transSize;
+ (*rpcMarray)->data.confarray_val = ((char*)useTransData) + transOffset;
+
+ // 3. store cell type length
+ (*rpcMarray)->cellTypeLength = resultTile->getType()->getSize();
+
+ // increment iterator only if tile is transferred completely
+ if( statusValue > 1 )
+ {
+ context->totalRawSize += resultTile->getSize();
+ (*context->tileIter)++;
+ }
+
+ // delete tile vector and increment transfer collection iterator if tile iterator is exhausted
+ if( (*context->tileIter) == context->transTiles->end() )
+ {
+
+ // delete tile vector transTiles (tiles are deleted when the object is deleted)
+ if( context->transTiles )
+ {
+ delete context->transTiles;
+ context->transTiles = 0;
+ }
+
+ // delete tile iterator
+ if( context->tileIter )
+ {
+ delete context->tileIter;
+ context->tileIter = 0;
+ }
+
+ if( context->transferDataIter )
+ {
+ (*(context->transferDataIter))++;
+
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ returnValue = 1;
+ TALK( " some MDDs left..." );
+ RMInit::logOut << MSG_OK << ", some MDD(s) left." << endl;
+ }
+ else
+ {
+ // no elements left -> delete collection and iterator
+
+ // Memory of last tile is still needed for the last byte transfer,
+ // therefore, do not release memory now, but with any next RPC call.
+ // context->releaseTransferStructures();
+
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", all MDDs fetched." << endl;
+ }
+ }
+ else
+ {
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", MDD transfer complete." << endl;
+ }
+
+ if ((context->totalTransferedSize != context->totalRawSize) && (context->totalRawSize != 0))
+ {
+ TALK( "(compressed using " << context->transferFormat << " to " << ((r_Double)(100 * context->totalTransferedSize)) / context->totalRawSize << "%) " );
+ }
+ }
+ else
+ {
+ if( statusValue == 1 ) // at least one block in actual tile is left
+ {
+ RMInit::logOut << MSG_OK << ", some block(s) left." << endl;
+ returnValue = 3;
+ }
+ else // tiles left in actual MDD
+ {
+ RMInit::logOut << MSG_OK << ", some tile(s) left." << endl;
+ returnValue = 2;
+ }
+ }
+ }
+ else // no actual transfer collection or nothing left in the collection
+ {
+ returnValue = 4;
+ RMInit::logOut << "Error: no transfer collection or nothing left in collection." << endl;
+ }
+
+ context->release();
+ }
+ else
+ { // client context not found
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 4;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::endTransfer( unsigned long client )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "endTransfer" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Client " << client << " called: endTransfer..." << std::flush;
+
+ ClientTblElt* context = getClientContext( client );
+
+ if( context )
+ {
+#ifdef RMANBENCHMARK
+ Tile::relTimer.stop();
+ Tile::opTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+ if( context->evaluationTimer ) delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+ if( context->transferTimer ) delete context->transferTimer;
+ context->transferTimer = 0;
+ RMTimer* releaseTimer = 0;
+
+ if( RManBenchmark > 0 )
+ releaseTimer = new RMTimer("ServerComm", "release time ");
+#endif
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( releaseTimer ) delete releaseTimer;
+#endif
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "endTransfer" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: aliveSignal( unsigned long client )
+ ************************************************************************/
+unsigned short
+ServerComm::aliveSignal( unsigned long client )
+{
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Client " << client << " called: endTransfer..." << std::flush;
+
+ ClientTblElt* context = getClientContext( client );
+
+ if( context )
+ {
+ // set the time of the client's last action to now
+ context->lastActionTime = time( NULL );
+
+ returnValue = 1;
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ }
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNewOId( unsigned long callingClientId,
+ unsigned short objType,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNewOId" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getNewOId of type "
+ << (objType==1?"MDD":"collection") << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ EOId eOId;
+
+ if( objType == 1 )
+ EOId::allocateEOId( eOId, OId::MDDOID );
+ else // objType == 2
+ EOId::allocateEOId( eOId, OId::MDDCOLLOID );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "allocated " << eOId)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNewOId " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getObjectType( unsigned long callingClientId,
+ r_OId& oid,
+ unsigned short &objType )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getObjectType" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getObjectType by oid " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ OId oidIf( oid.get_local_oid() );
+
+ objType = oidIf.getType();
+
+ if( objType == OId::INVALID )
+ {
+ // oid not found
+ RMInit::logOut << "Error: no type for this oid." << std::endl;
+ returnValue = 2;
+ }
+ else
+ {
+ RMInit::logOut << "type is " << (objType==1?"MDD":"collection") << "..." << MSG_OK << endl;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getObjectType" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getTypeStructure( unsigned long callingClientId,
+ const char* typeName,
+ unsigned short typeType,
+ char* &typeStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getTypeStructure" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getTypeStructure of type '" << typeName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+ if (context == 0)
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ if (returnValue==0 && !transactionActive)
+ {
+ RMInit::logOut << "Error: no transaction open." << endl;
+ returnValue = 1;
+ }
+
+ if (returnValue==0)
+ {
+ if( typeType == 1 )
+ {
+ // get collection type
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( (char*)typeName );
+
+ if( collType )
+ typeStructure = collType->getTypeStructure(); // no copy
+ else
+ returnValue = 2;
+ }
+ else if( typeType == 2 )
+ {
+ // get MDD type
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ typeStructure = mddType->getTypeStructure(); // no copy
+ else
+ returnValue = 2;
+ }
+ else // base type not implemented
+ {
+ returnValue = 2;
+ }
+
+ if( returnValue == 2 )
+ RMInit::logOut << "Error: unknown type." << endl;
+ else
+ RMInit::logOut << MSG_OK << endl;
+
+ context->release();
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getTypeStructure" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::setTransferMode( unsigned long callingClientId,
+ unsigned short format,
+ const char* formatParams )
+{
+ RMDBGENTER(4, RMDebug::module_servercomm, "ServerComm", "setTransferMode(" << callingClientId << ", " << format << ", " << formatParams)
+
+ RMInit::logOut << "Request: setTransferMode..." << std::flush;
+
+ unsigned short retval = 1;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if (context != 0)
+ {
+ r_Data_Format fmt = (r_Data_Format)format;
+ // query compression module whether this is a legal format for transfer compression
+ if (r_Tile_Compression::check_data_format(fmt) == r_Tile_Compression::INVALID)
+ {
+ RMInit::logOut << "Error: invalid transfer compression format: " << format << std::endl;
+ retval = 2;
+ }
+ else
+ {
+ if (context->transferFormatParams != NULL)
+ {
+ delete [] context->transferFormatParams;
+ context->transferFormatParams = NULL;
+ // revert the transfer format strictness
+ context->exactFormat = 0;
+ }
+ if (formatParams != NULL)
+ {
+ context->transferFormatParams = new char[strlen(formatParams)+1];
+ strcpy(context->transferFormatParams, formatParams);
+ // extract any occurrences of ``exactformat''
+ context->clientParams->process(context->transferFormatParams);
+ }
+ context->transferFormat = fmt;
+
+ RMInit::logOut << MSG_OK << std::endl;
+ retval = 0;
+ }
+ context->release();
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setTransferMode(...) current transfer format :" << context->transferFormat)
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setTransferMode(...)current transfer params :" << context->transferFormatParams );
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ retval = 1;
+ }
+
+ RMDBGEXIT(4, RMDebug::module_servercomm, "ServerComm", "setTransferMode " << retval)
+ return retval;
+}
+
+unsigned short
+ServerComm::setStorageMode( unsigned long callingClientId,
+ unsigned short format,
+ const char* formatParams )
+{
+ RMDBGENTER(4, RMDebug::module_servercomm, "ServerComm", "setStorageMode(" << callingClientId << ", " << format << ", " << formatParams)
+
+ RMInit::logOut << "Request: setStorageMode..." << std::flush;
+
+ unsigned short retval = 1;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if (context != 0)
+ {
+ r_Data_Format fmt = (r_Data_Format)format;
+ if (r_Tile_Compression::check_data_format(fmt) == r_Tile_Compression::INVALID)
+ {
+ RMInit::logOut << "Error: invalid storage compression format: " << format << std::endl;
+ retval = 2;
+ }
+ else
+ {
+ if (context->storageFormatParams != NULL)
+ {
+ delete [] context->storageFormatParams;
+ context->storageFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ context->storageFormatParams = new char[strlen(formatParams)+1];
+ strcpy(context->storageFormatParams, formatParams);
+ }
+ context->storageFormat = fmt;
+
+ RMInit::logOut << MSG_OK << std::endl;
+ retval = 0;
+ }
+ context->release();
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setStorageMode(...) current storage format :" << context->storageFormat)
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setStorageMode(...) current storage params :" << context->storageFormatParams)
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ retval = 1;
+ }
+
+ RMDBGEXIT(4, RMDebug::module_servercomm, "ServerComm", "setStorageMode " << retval)
+ return retval;
+}
+
+int
+ServerComm::ensureTileFormat( r_Data_Format &hasFmt,
+ r_Data_Format needFmt,
+ const r_Minterval &dom,
+ const BaseType *type,
+ char *&data,
+ unsigned long &size,
+ int repack,
+ int owner,
+ const char *params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(" << hasFmt << ", " << needFmt << ", " << dom << ", " << type->getName() << ", data, " << size << ", repack " << repack << ", owner " << owner << ", params " << params << ")")
+ int status = ENSURE_TILE_FORMAT_OK;
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 1=" << size);
+
+ // convert to storage format (this should go into a separate function)
+ if (hasFmt != needFmt)
+ {
+ r_Tile_Compression *engine = NULL;
+ r_ULong newSize=0;
+ char *newData=NULL;
+
+ char *tpstruct = type->getTypeStructure();
+ r_Base_Type *compType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ // decompress
+ try
+ {
+ engine = r_Tile_Compression::create(hasFmt, dom, compType);
+ // decompression doesn't change the size variable!
+ newData = (char*)(engine->decompress(data, size, params));
+ delete engine;
+
+ if (newData == NULL)
+ {
+ RMInit::logOut << "Error: decompression failed for format '" << hasFmt << "'." << endl;
+ size = dom.cell_count() * compType->size();
+ newData = (char*)mymalloc(size * sizeof(char));
+ memset(newData, 0, size);
+ // FIXME: make it an error!! --PB 2005-aug-25
+ RMInit::logOut << "Error fixed by returning empty data of length " << size << " bytes." << std::endl;
+ }
+ // do I actually own the data?
+ if (owner != 0)
+ free(data);
+ data = newData;
+ size = dom.cell_count() * (compType->size());
+ hasFmt = r_Array;
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "Error: cannot decompress format '" << hasFmt << "' (" << err.get_errorno() << "): " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 2=" << size);
+
+ if ((status == ENSURE_TILE_FORMAT_OK) && (repack != 0) && (needFmt != r_Array))
+ {
+ try
+ {
+ newSize = size;
+ engine = r_Tile_Compression::create(needFmt, dom, compType);
+ newData = (char*)(engine->compress(data, newSize, params));
+ delete engine;
+
+ if (newData == NULL)
+ {
+ RMInit::logOut << "Error: recompression failed for format '" << needFmt << "'." << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+ else
+ {
+ free(data);
+ data = newData; size = newSize;
+ hasFmt = needFmt;
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "recompressed to " << hasFmt << " size " << size)
+ }
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "Error: unsupported tile format '" << needFmt << "' (" << err.get_errorno() << "): " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+ }
+ else
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) do not recompress")
+ }
+ delete compType;
+ free(tpstruct);
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 3=" << size);
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_OK)
+ return status;
+}
diff --git a/servercomm/test/Makefile b/servercomm/test/Makefile
new file mode 100644
index 0000000..bf035b4
--- /dev/null
+++ b/servercomm/test/Makefile
@@ -0,0 +1,117 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community 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 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module servercomm
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX = test_servercomm.cc test_dbcontent.cc test_oid.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+# some additional flags for compiling and linking
+
+CXXFLAGS += -I$(RMANBASE)/servercomm
+LDFLAGS := -I$(RMANBASE)/servercomm $(LDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS)
+
+########################### Targets ##############################
+
+# test target for servercomm
+.PHONY : servercomm
+servercomm: adminif raslib test_module test_servercomm
+
+# test target for dbcontent
+.PHONY : dbcontent
+dbcontent: adminif raslib test_module test_dbcontent
+
+.PHONY : adminif
+adminif:
+ cd $(RMANBASE)/reladminif; $(MAKE)
+
+.PHONY : raslib
+raslib:
+ cd $(RMANBASE)/raslib; $(MAKE)
+
+.PHONY : qlparser
+qlparser:
+ cd $(RMANBASE)/qlparser; $(MAKE)
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/servercomm; $(MAKE)
+
+test_servercomm: test_servercomm.o \
+ $(QLPARSER) \
+ $(SERVERCOMM) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF) \
+ $(PREPROCESSOR) \
+ $(STORAGEMGR) \
+ $(TILEMGR) \
+ $(RASLIB) \
+ $(RELINDEX) \
+ $(INDEXIF)
+ $(CXX) $(LDFLAGS) -o $@ $^ $(QLPARSER) $(INDEXMGR) $(CACHETAMGR) $(RELINDEX) $(RELSTORAGEIF) $(RELADMINIF) $(STORAGEMGR) $(CONVERSION) $(INDEXIF) $(RELCATALOGIF) /usr/local/pgsql/lib/libpq.a /usr/local/pgsql/lib/libecpg.a -lssl -lcrypt /usr/local/pgsql/lib/libpgtypes.a -lm -ljpeg -ltiff -lpng -lmfhdf -ldf -lz -ldl -lcrypto
+
+test_dbcontent: test_dbcontent.o \
+ $(QLPARSER) \
+ $(SERVERCOMM) \
+ $(RASLIB) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF)
+ $(CXX) $(LDFLAGS) $(O2LDFLAGS) -o $@ $^ $(QLPARSER) $(INDEXMGR) $(CACHETAMGR) -lm
+
+test_oid: test_oid.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(O2LDFLAGS) $(LDFLAGS) -o $@ $^ \
+ $(RASLIB) -lm -L$(SUPPORT_BASE)/lib -lz
+
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/servercomm/test/template_inst.hh b/servercomm/test/template_inst.hh
new file mode 100644
index 0000000..569c0bf
--- /dev/null
+++ b/servercomm/test/template_inst.hh
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+//for rb_tree, select1st
+#include <function.h>
+#include <tree.h>
+#include <vector>
+#include <utility>
+#include <memory>
+
+#if(__GNUC__==2 &&__GNUC_MINOR__==95)
+using std::rb_tree;
+using std::select1st;
+#else
+using __gnu_cxx::rb_tree;
+using __gnu_cxx::select1st;
+#endif
+
+using std::vector;
+using std::pair;
+
+// commented by Constantin Jucovschi (gcc 3.4+ no longer supports __default_alloc_template)
+//using std::__default_alloc_template;
+using std::fill_n;
+
+#include "qlparser/symtab.hh"
+
+#include "raslib/attribute.hh"
+#include "raslib/itertype.hh"
+#include "raslib/dlist.hh"
+
+#include "tile.hh"
+
+#include "indexmgr/keyobject.hh"
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relblobif/blobtile.hh"
+#include "relblobif/dbtile.hh"
+#include "relblobif/inlinetile.hh"
+
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/inlineminterval.hh"
+#include "relcatalogif/dbminterval.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+#include "relstorageif/dbudfds.hh"
+#include "relstorageif/dbudfpackageds.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+template class SymbolTable<int>;
+
+template class r_IterType<r_Attribute>;
+
+template class DBRef<DBHierIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBTCIndex>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBMinterval>;
+template class DBRef<DBStorageLayout>;
+template class DBRef<DBUDFDS>;
+template class DBRef<DBUDFPackageDS>;
+//template class DBRef<DBMDDObj>;
+// template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+//template TypeIterator<StructType>;
+//template TypeIterator<SetType>;
+template class TypeIterator<MDDType>;
+template class DBRef<DBMDDObj>;
+template class DBRef<DBObject>;
+
+template class DBObjectIdIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDSet>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<SetType>;
+template class DBRef<StructType>;
+template class DBRef<SetType>;
+template class DBRef<MDDType>;
+
+template std::ostream& operator<< (const vector<KeyObject>&, std::ostream&);
+template std::ostream& operator<< (std::ostream &, const vector<KeyObject>&);
+template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+
+template class rb_tree<OId, pair<OId const, DBMDDObj *>, select1st<pair<OId const, DBMDDObj *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMinterval *>, select1st<pair<OId const, DBMinterval *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBRef<DBMDDObj> >, select1st<pair<OId const, DBRef<DBMDDObj> > >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMDDSet *>, select1st<pair<OId const, DBMDDSet *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, MDDType *>, select1st<pair<OId const, MDDType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, SetType *>, select1st<pair<OId const, SetType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, StructType *>, select1st<pair<OId const, StructType *> >, less<OId> >;
+template class rb_tree<long, pair<long const, BLOBTile *>, select1st<pair<long const, BLOBTile *> >, less<long> >;
+template class rb_tree<long, pair<long const, InlineTile *>, select1st<pair<long const, InlineTile *> >, less<long> >;
+template class vector<BaseType const * >;
+template class vector<OId >;
+template class vector<Tile * >;
+template class vector<Type * >;
+template class vector<char * >;
+template class vector<char >;
+template class vector<r_Data_Format >;
+template class vector<unsigned int >;
+
+template class Tile ** fill_n<Tile **, unsigned int, Tile *>(Tile **, unsigned int, Tile * const &);
+
diff --git a/servercomm/test/test_dbcontent.cc b/servercomm/test/test_dbcontent.cc
new file mode 100644
index 0000000..a0bd6da
--- /dev/null
+++ b/servercomm/test/test_dbcontent.cc
@@ -0,0 +1,161 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dbcontent.cc
+ *
+ * MODULE: test
+ *
+ * PURPOSE:
+ * Reads the contents of the specified collection and prints
+ * it on the screen.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "o2template_CC.hxx" // declaration of O2 ref and coll classes
+
+#include "ulongtype.hh"
+
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include <unistd.h>
+
+extern char* myExecArgv0 = "";
+
+static void testAccessing( const char* collName );
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+void
+main( int ac, char** av)
+{
+ char baseName[255];
+ char collName[255];
+
+ if( ac > 1 )
+ strcpy( baseName, av[1] );
+ else
+ strcpy( baseName, "RasDaBase" );
+
+ if( ac > 2 )
+ strcpy( collName, av[2] );
+ else
+ strcpy( collName, "Images" );
+
+ pid_t cpid;
+ cout << "Parent process id is " << getpid() << endl;
+
+ cpid = fork();
+
+ if( !cpid )
+ {
+ cout << "Child process id is " << getpid() << endl;
+ // sleep(1);
+ }
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = av[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << getpid() << " Connecting to database " << baseName << "..." << endl;
+ database.open( baseName );
+
+ // read coll and print contents
+ cout << getpid() << " Read collection and print contents..." << endl;
+ ta.begin();
+ testAccessing( collName );
+ ta.commit();
+
+ cout << getpid() << " closing db ... "; cout.flush();
+ database.close();
+ cout << getpid() << " OK" << endl;
+
+ cout << getpid() << " Ending O2 session..." << endl;
+ delete myAdmin;
+ cout << getpid() << " OK" << endl;
+
+ return;
+}
+
+
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ ************************************************************/
+
+static void testAccessing( const char* collName )
+{
+ PersMDDObj* accessedObj;
+
+ cout << getpid() << " ....testAccessing" << endl;
+ /*
+ PersMDDColl objsSet( collName );
+
+ // To test PersMDDColl::printStatus( )
+ objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << " --"<<i<<". MDD object in set:" << endl;
+ accessedObj->printStatus();
+ }
+ delete objsIt;
+ */
+}
+
+
diff --git a/servercomm/test/test_oid.cc b/servercomm/test/test_oid.cc
new file mode 100644
index 0000000..280b499
--- /dev/null
+++ b/servercomm/test/test_oid.cc
@@ -0,0 +1,229 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dbcontent.cc
+ *
+ * MODULE: test
+ *
+ * PURPOSE:
+ * Reads the contents of the specified collection and prints
+ * it on the screen.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "o2template_CC.hxx" // declaration of O2 ref and coll classes
+
+#include "ulongtype.hh"
+
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include <unistd.h>
+
+RMINITGLOBALS('C')
+
+extern char* myExecArgv0 = "";
+
+static void
+insertObj( char* dbName, OId o, char* cn )
+{
+ MDDBaseType* mddType = (MDDBaseType*)TypeFactory::mapMDDType( "GreyImage" );
+ r_Minterval domain( "[0:9,0:9]" );
+
+ // cout << " " << o << "," << cn << " ... " << flush;
+
+ PersMDDObj* obj = new PersMDDObj( mddType, domain, dbName, o );
+ PersMDDColl objsSet( cn );
+ objsSet.insert( obj );
+ delete obj;
+}
+
+
+static void removeObj( char* dbName, char* collName, OId o )
+{
+ // open collection
+ PersMDDColl* coll = 0;
+
+ char answer = 'n';
+ cout << endl << "SCAN (y/n) ?" << flush;
+ cin >> answer;
+
+ if( answer == 'y' )
+ {
+ coll = new PersMDDColl( collName );
+ MDDCollIter* collIter = coll->createIterator();
+ MDDObj* mddObj;
+ for( collIter->reset(); collIter->notDone(); collIter->advance() )
+ {
+ mddObj = collIter->getElement();
+ /*
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+ ((PersMDDObj*)mddObj)->getEOId( &eOId );
+
+ cout << "MDD " << eOId.getOId() << flush;
+ }
+ */
+
+ }
+ /*
+ cout << endl << "PRINT OBJECT (y/n) ?" << flush;
+ cin >> answer;
+ if( answer == 'y' )
+ mddObj->printStatus( );
+ */
+ delete collIter;
+
+ coll->releaseAll();
+ delete coll;
+
+ cout << endl << "SCAN end" << endl;
+ }
+
+ coll = new PersMDDColl( collName );
+
+ if( coll )
+ {
+ cout <<"o == " << o << " dbName == " << dbName << endl;
+ coll->remove( o, dbName );
+
+ coll->releaseAll();
+ delete coll;
+ }
+}
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int
+main( int ac, char** av)
+{
+ int optionValueIndex;
+ char dbName[255];
+ char collName[255];
+
+ if( ac < 3 || checkArguments( ac, av, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_oid base_name collection_name [options]" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( dbName, av[1] );
+ strcpy( collName, av[2] );
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = av[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << "Connecting to database " << dbName << "..." << flush;
+ database.open( dbName );
+ cout << "OK" << endl;
+
+ // create collection with one object
+ cout << "Create collection ... " << flush;
+ ta.begin( &database );
+ cout << "getting type ... " << flush;
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( "GreySet" );
+ cout << "getting oid ... " << flush;
+ OId oidColl;
+ if( !OId::allocateMDDCollOId( &oidColl ) ) cout << oidColl << " ... " << flush;
+ PersMDDColl* pc = PersMDDColl::createRoot( collName, oidColl, collType, &database );
+ delete pc;
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Insert object into collection ... " << flush;
+ ta.begin( &database );
+ cout << "getting oid ... " << flush;
+ OId oidMDD;
+ if( !OId::allocateMDDOId( &oidMDD ) ) cout << oidMDD << " ... " << flush;
+ cout << "inserting ..." << flush;
+ insertObj( dbName, oidMDD, collName );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Remove object again ... " << flush;
+ ta.begin( &database );
+ cout << "removing oid " << oidMDD << " ... " << flush;
+ removeObj( dbName, collName, oidMDD );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Delete collection ... " << flush;
+ ta.begin( &database );
+ cout << "destroying ... " << flush;
+ PersMDDColl::destroyRoot( collName, &database );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing db ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+
+ cout << "Ending O2 session ... " << flush;
+ delete myAdmin;
+ cout << "OK" << endl;
+
+ return 0;
+}
+
diff --git a/servercomm/test/test_servercomm.cc b/servercomm/test/test_servercomm.cc
new file mode 100644
index 0000000..0be4610
--- /dev/null
+++ b/servercomm/test/test_servercomm.cc
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_servercomm.cc
+ *
+ * MODULE: servercomm
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+
+#include <iostream.h>
+
+#define __EXECUTABLE__
+#define EARLY_TEMPLATE
+#define DEBUG_MAIN
+#define DEBUG
+#include "debug.hh"
+#include "template_inst.hh"
+
+#include "raslib/rmdebug.hh"
+#include "qlparser/qtscalardata.hh"
+
+#include "servercomm/servercomm.hh"
+
+
+extern char* myExecArgv0 = "";
+extern int tiling = 1;
+extern unsigned long maxTransferBufferSize = 4000000;
+extern int globalOptimizationLevel = 4;
+extern char* dbSchema = 0;
+extern int noTimeOut = 0;
+char globalConnectId[255] = {0};
+bool udfEnabled = true;
+
+RMINITGLOBALS('C');
+
+#include <signal.h>
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int main( int argc, char** argv )
+{
+ strcpy(globalConnectId, "tcp:postgresql://localhost:5432/RASBASE");
+
+ ServerComm server(300, 120, 7013, "rasmgr", 7001, "N1");
+ ExecuteQueryRes result;
+
+ DatabaseIf database;
+ TransactionIf ta;
+ AdminIf* myAdmin = AdminIf::instance();
+ database.open( "RASSERVICE");
+ ta.begin( &database );
+
+ ServerComm::ClientTblElt *r = new ServerComm::ClientTblElt("testclient", 2);
+
+ server.addClientTblEntry (r);
+
+ accessControl.setServerName("NT1");
+ accessControl.crunchCapability("$I1$ER.$BRASBASE$T1:3:2008:23:39:24$NNT1$D983893f406445a922cba0301bc5a85ec$K");
+ server.openDB(2, "RASBASE", "costea");
+ SET_OUTPUT(TRUE);
+
+ char *buff = new char[1000];
+ unsigned int size;
+
+ QtScalarData* t;
+
+ try
+ {
+ server.executeQuery(2, "SELECT a from RAS_COLLECTIONNAMES as a", result );
+ vector<QtData*>::iterator i;
+ /* for (i=r->transferData->begin(); i!=r->transferData->end(); ++i) {
+ // t = (QtScalarData*)(*i);
+ // t->printStatus();
+ }*/
+ }
+ catch ( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+ catch ( ... )
+ {
+ cerr << "Unknown exception caught in main." << endl;
+ return -1;
+ }
+
+ return 0;
+}