/* * 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 . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * 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 #include #include // for time() #include #include // for signal() #include // for alarm(), gethostname() #include #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 #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 &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 "<(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*)¤tTime) << 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 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 resultTiles; // contains all TransTiles representing the resulting MDDs resultTiles.reserve(20); vector resultTypes; resultTypes.reserve(20); vector resultDomains; resultDomains.reserve(20); vector 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 resultElems; // contains all TransTiles representing the resulting MDDs resultElems.reserve(20); vector 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..."< getClientContext( lastCallingClientId ); clnt->transaction.abort(); clnt->database.close(); sc->informRasMGR(SERVER_AVAILABLE); // cout<<"Http server, client timeout, available again..."< getClientContext( lastCallingClientId ); clnt->transaction.abort(); clnt->database.close(); RMInit::logOut << MSG_OK << endl; } }