/*****************************************************************************/ /* */ /* Copyright (c) 2008-2009 NetApp, Inc., All Rights Reserved */ /* Any use, modification, or distribution is prohibited */ /* without prior written consent from NetApp, Inc. */ /* */ /*****************************************************************************/ #include #include #include #include "STAF_fstream.h" #include "STAFString.h" #include "STAFError.h" #include "STAFException.h" #include "STAFRefPtr.h" #include "STAFMutexSem.h" #include "STAFRWSem.h" #include "STAFCommandParser.h" #include "STAFServiceInterface.h" #include "STAFUtil.h" #include "STAFInternalUtil.h" #include "STAFHandleReaperService.h" #include "STAFFileSystem.h" #include "STAFDataTypes.h" #include "STAFTrace.h" #define ReaperVersion "0.0.10" typedef STAFRefPtr STAFCommandParserPtr; // Command Data - contains data for an entry in a handle reaper struct CommandData { CommandData(const STAFString &aEndpoint, const STAFString &aService, const STAFString &aRequest, const bool aSync) : cleanupEndpoint(aEndpoint), cleanupService(aService), cleanupRequest(aRequest), synchronous(aSync) { /* Do Nothing */ } STAFString cleanupEndpoint; // endpoint value STAFString cleanupService; // service value STAFString cleanupRequest; // request value bool synchronous; // sync option STAFString orgUUID; // Originating request's STAF UUID STAFString orgMachine; // Originating request's machine name STAFString orgName; // Originating request's handle name STAFHandle_t orgHandle; // Originating request's handle STAFString orgUser; // Originating request's handle user STAFString orgEndpoint; // Originating request's endpoint }; // CommandList -- Ordered list of entries in a handle reaper typedef std::vector CommandList; // Command Reaper Data - contains all data for a handle reaper struct ReaperData { ReaperData() : accessSem(new STAFMutexSem(), STAFMutexSemPtr::INIT) { /* Do nothing */ } ReaperData(const STAFString &aReaperName, const STAFString &aReapedHandle,const STAFString &aReapedEndpoint) : reaperName(aReaperName), reapedHandle(aReapedHandle), reapedEndpoint(aReapedEndpoint), numCommands(0), accessSem(new STAFMutexSem(), STAFMutexSemPtr::INIT) { /* Do nothing */ } STAFString reaperName; // Reaper Name STAFString reapedHandle; // Handle to Reap STAFString reapedEndpoint; // Endpoint to Reap the Handle from unsigned int numCommands; // Total # of entries in CommandList CommandList commandList; // List of commands in a handle Reaper STAFMutexSemPtr accessSem; // Semaphore to control access to ReaperData }; typedef STAFRefPtr ReaperDataPtr; // ReaperMap -- KEY: Reaper name in upper case, // VALUE: Pointer to ReaperData information typedef std::map ReaperMap; // Read/Write File Return Codes enum ReadFileRC { kReadorWriteOk = 0, kReadEndOfFile = 1, kFileOpenError = 2 }; // HANDLEREAPER Service Data struct HandleReaperServiceData { STAFString fShortName; // Short service name STAFString fName; // Registered service name STAFString fLocalMachineName; // Logical identifier for the local // machine STAFString fReaperDir; // Reaper Directory STAFHandlePtr fHandlePtr; // HANDLEREAPER service's STAF handle STAFCommandParserPtr fCreateParser; // HANDLEREAPER CREATE command parser STAFCommandParserPtr fDeleteParser; // HANDLEREAPER DELETE command parser STAFCommandParserPtr fTriggerParser; // HANDLEREAPER Trigger command parser STAFCommandParserPtr fProxyParser; // HANDLEREAPER Proxy command parser STAFCommandParserPtr fQueryParser; // HANDLEREAPER QUERY command parser STAFCommandParserPtr fAddParser; // HANDLEREAPER ADD command parser STAFCommandParserPtr fRemoveParser; // HANDLEREAPER REMOVE command parser STAFCommandParserPtr fListParser; // HANDLEREAPER LIST command parser STAFCommandParserPtr fCallbackParser; // HANDLEREAPER STAF_CALLBACK command parser STAFCommandParserPtr fHelpParser; // HANDLEREAPER HELP command parser STAFCommandParserPtr fVersionParser; // HANDLEREAPER VERSION command parser STAFCommandParserPtr fParmsParser; // HANDLEREAPER PARMS command parser STAFRWSemPtr fReaperMapRWSem; // Read/Write semaphore to control // access to the ReaperMap ReaperMap fReaperMap; // Map of all handle Reapers // Map Class Definitions for marshalled results STAFMapClassDefinitionPtr fReaperClass; STAFMapClassDefinitionPtr fReaperInfoClass; STAFMapClassDefinitionPtr fSettingsClass; STAFMapClassDefinitionPtr fCommandClass; }; typedef STAFRefPtr HandleReaperServiceDataPtr; // Static Variables static STAFString sLineSep; static STAFString sReaperExt("nap"); static const STAFString sReaper("REAPER"); static const STAFString sHandle("HANDLE"); static const STAFString sEndpoint("ENDPOINT"); static const STAFString sCleanupService("SERVICE"); static const STAFString sCleanupEndpoint("ENDPOINT"); static const STAFString sCleanupRequest("REQUEST"); static const STAFString sDirectory("DIRECTORY"); static const STAFString sLeftCurlyBrace(kUTF8_LCURLY); static const STAFString sSemiColon(kUTF8_SCOLON); static const STAFString sColon(kUTF8_COLON); static const STAFString sSlash(kUTF8_SLASH); static const STAFString sSpecSeparator(sColon + sSlash + sSlash); static const STAFString sLocal("local"); static const STAFString sHelp("help"); static const STAFString sVar("var"); static const STAFString sResStrResolve("RESOLVE REQUEST "); static const STAFString sString(" STRING "); static const STAFString sNo("No"); // Prototypes static STAFResultPtr handleCreate(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleDelete(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleTrigger(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleProxy(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleQuery(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleAdd(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleRemove(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleSTAFCallback(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleList(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleHelp(STAFServiceRequestLevel30 *, HandleReaperServiceData *); static STAFResultPtr handleVersion(STAFServiceRequestLevel30 *, HandleReaperServiceData *); void trigger(ReaperDataPtr reaperPtr, STAFString reaperName, bool doUnregister, STAFString caller, HandleReaperServiceData *pData); void unregister(ReaperDataPtr reaperPtr, STAFString reaperName, STAFString caller, HandleReaperServiceData *pData); STAFResultPtr removeFromFile(STAFString reaperName, STAFString caller, HandleReaperServiceData *pData); STAFResultPtr resolveStr(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData, const STAFString &theString); STAFResultPtr resolveOp(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData, STAFCommandParseResultPtr &parsedResult, const STAFString &fOption, unsigned int optionIndex = 1); STAFResultPtr resolveOpLocal(HandleReaperServiceData *pData, STAFCommandParseResultPtr &parsedResult, const STAFString &fOption, unsigned int optionIndex = 1); void registerHelpData(HandleReaperServiceData *pData, unsigned int errorNumber, const STAFString &shortInfo, const STAFString &longInfo); void unregisterHelpData(HandleReaperServiceData *pData, unsigned int errorNumber); void readUIntFromFile(istream &input, unsigned int &data, unsigned int length = 4); void writeUIntToFile(ostream &output, unsigned int data, unsigned int length = 4); void readStringFromFile(istream &input, STAFString &inString); void writeStringToFile(ostream &output, STAFString &outString); unsigned int readReaperFile(const STAFString &fileName, ReaperData &reaperData); unsigned int writeReaperFile(const STAFString &fileName, ReaperData &reaperData); // Begin implementation STAFRC_t STAFServiceGetLevelBounds(unsigned int levelID, unsigned int *minimum, unsigned int *maximum) { switch (levelID) { case kServiceInfo: { *minimum = 30; *maximum = 30; break; } case kServiceInit: { *minimum = 30; *maximum = 30; break; } case kServiceAcceptRequest: { *minimum = 30; *maximum = 30; break; } case kServiceTerm: case kServiceDestruct: { *minimum = 0; *maximum = 0; break; } default: { return kSTAFInvalidAPILevel; } } return kSTAFOk; } STAFRC_t STAFServiceConstruct(STAFServiceHandle_t *pServiceHandle, void *pServiceInfo, unsigned int infoLevel, STAFString_t *pErrorBuffer) { STAFRC_t rc = kSTAFUnknownError; try { if (infoLevel != 30) return kSTAFInvalidAPILevel; STAFServiceInfoLevel30 *pInfo = reinterpret_cast(pServiceInfo); HandleReaperServiceData data; data.fShortName = pInfo->name; data.fName = "STAF/Service/"; data.fName += pInfo->name; // Set service handle *pServiceHandle = new HandleReaperServiceData(data); return kSTAFOk; } catch (STAFException &e) { *pErrorBuffer = getExceptionString(e, "STAFHandleReaperService.cpp: STAFServiceConstruct").adoptImpl(); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceConstruct: " "Caught unknown exception"); *pErrorBuffer = error.adoptImpl(); } return kSTAFUnknownError; } STAFRC_t STAFServiceInit(STAFServiceHandle_t serviceHandle, void *pInitInfo, unsigned int initLevel, STAFString_t *pErrorBuffer) { STAFRC_t retCode = kSTAFUnknownError; try { if (initLevel != 30) return kSTAFInvalidAPILevel; HandleReaperServiceData *pData = reinterpret_cast(serviceHandle); STAFServiceInitLevel30 *pInfo = reinterpret_cast(pInitInfo); retCode = STAFHandle::create(pData->fName, pData->fHandlePtr); if (retCode != kSTAFOk) return retCode; //CREATE options pData->fCreateParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fCreateParser->addOption("CREATE", 1, STAFCommandParser::kValueNotAllowed); pData->fCreateParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fCreateParser->addOption(sHandle, 1, STAFCommandParser::kValueRequired); pData->fCreateParser->addOption(sEndpoint, 1, STAFCommandParser::kValueRequired); pData->fCreateParser->addOptionNeed("CREATE", sReaper + " " + sHandle); pData->fCreateParser->addOptionNeed("CREATE " + sReaper, sHandle); //DELETE options pData->fDeleteParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fDeleteParser->addOption("DELETE", 1, STAFCommandParser::kValueNotAllowed); pData->fDeleteParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fDeleteParser->addOptionNeed("DELETE", sReaper); //TRIGGER options pData->fTriggerParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fTriggerParser->addOption("TRIGGER", 1, STAFCommandParser::kValueNotAllowed); pData->fTriggerParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fTriggerParser->addOptionNeed("TRIGGER", sReaper); //PROXY options pData->fProxyParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fProxyParser->addOption("PROXY", 1, STAFCommandParser::kValueNotAllowed); pData->fProxyParser->addOption("PROXYSERVICE", 1, STAFCommandParser::kValueRequired); pData->fProxyParser->addOption("PROXYREQUEST", 1, STAFCommandParser::kValueRequired); pData->fProxyParser->addOption("SYNC", 1, STAFCommandParser::kValueRequired); pData->fProxyParser->addOptionNeed("PROXY", "PROXYSERVICE PROXYREQUEST"); pData->fProxyParser->addOptionNeed("PROXY PROXYSERVICE", "PROXYREQUEST"); //QUERY options pData->fQueryParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fQueryParser->addOption("QUERY", 1, STAFCommandParser::kValueNotAllowed); pData->fQueryParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fQueryParser->addOptionNeed("QUERY", sReaper); //ADD options pData->fAddParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fAddParser->addOption("ADD", 1, STAFCommandParser::kValueNotAllowed); pData->fAddParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fAddParser->addOption(sCleanupEndpoint, 100, STAFCommandParser::kValueRequired); pData->fAddParser->addOption(sCleanupService, 1, STAFCommandParser::kValueRequired); pData->fAddParser->addOption(sCleanupRequest, 1, STAFCommandParser::kValueRequired); pData->fAddParser->addOption("SYNC", 1, STAFCommandParser::kValueRequired); pData->fAddParser->addOptionNeed("ADD", sReaper + " " + sCleanupEndpoint + " " + sCleanupService + " " + sCleanupRequest); pData->fAddParser->addOptionNeed("ADD " + sReaper, sCleanupEndpoint + " " + sCleanupService + " " + sCleanupRequest); pData->fAddParser->addOptionNeed("ADD " + sReaper + " " + sCleanupEndpoint, sCleanupService + " " + sCleanupRequest); pData->fAddParser->addOptionNeed("ADD " + sReaper + " " + sCleanupEndpoint + " " + sCleanupService, sCleanupRequest); //REMOVE options pData->fRemoveParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fRemoveParser->addOption("REMOVE", 1, STAFCommandParser::kValueNotAllowed); pData->fRemoveParser->addOption(sReaper, 1, STAFCommandParser::kValueRequired); pData->fRemoveParser->addOption(sCleanupEndpoint, 100, STAFCommandParser::kValueRequired); pData->fRemoveParser->addOption(sCleanupService, 1, STAFCommandParser::kValueRequired); pData->fRemoveParser->addOption(sCleanupRequest, 1, STAFCommandParser::kValueRequired); pData->fRemoveParser->addOption("SYNC", 1, STAFCommandParser::kValueRequired); pData->fRemoveParser->addOptionNeed("REMOVE", sReaper + " " + sCleanupEndpoint + " " + sCleanupService + " " + sCleanupRequest); pData->fRemoveParser->addOptionNeed("REMOVE " + sReaper, sCleanupEndpoint + " " + sCleanupService + " " + sCleanupRequest); pData->fRemoveParser->addOptionNeed("REMOVE " + sReaper + " " + sCleanupEndpoint, sCleanupService + " " + sCleanupRequest); pData->fRemoveParser->addOptionNeed("REMOVE " + sReaper + " " + sCleanupEndpoint + " " + sCleanupService, sCleanupRequest); //LIST options pData->fListParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fListParser->addOption("LIST", 1, STAFCommandParser::kValueNotAllowed); pData->fListParser->addOption("REAPERS", 1, STAFCommandParser::kValueNotAllowed); pData->fListParser->addOption("SETTINGS", 1, STAFCommandParser::kValueNotAllowed); pData->fListParser->addOptionNeed("REAPERS SETTINGS", "LIST"); pData->fListParser->addOptionGroup("REAPERS SETTINGS", 0, 1); //STAF_CALLBACK options pData->fCallbackParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fCallbackParser->addOption("STAF_CALLBACK", 1, STAFCommandParser::kValueNotAllowed); pData->fCallbackParser->addOption("HANDLEDELETED", 1, STAFCommandParser::kValueNotAllowed); pData->fCallbackParser->addOption("HANDLE", 1, STAFCommandParser::kValueRequired); pData->fCallbackParser->addOption("UUID", 1, STAFCommandParser::kValueRequired); pData->fCallbackParser->addOption("MACHINE", 1, STAFCommandParser::kValueRequired); pData->fCallbackParser->addOption("KEY", 1, STAFCommandParser::kValueRequired); //HELP options pData->fHelpParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fHelpParser->addOption("HELP", 1, STAFCommandParser::kValueNotAllowed); //VERSION options pData->fVersionParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fVersionParser->addOption("VERSION", 1, STAFCommandParser::kValueNotAllowed); // PARMS pData->fParmsParser = STAFCommandParserPtr(new STAFCommandParser, STAFCommandParserPtr::INIT); pData->fParmsParser->addOption("DIRECTORY", 1, STAFCommandParser::kValueRequired); STAFCommandParseResultPtr parsedResult = pData->fParmsParser->parse(pInfo->parms); if (parsedResult->rc != kSTAFOk) { *pErrorBuffer = parsedResult->errorBuffer.adoptImpl(); return parsedResult->rc; } if (parsedResult->optionTimes(sDirectory)) { STAFResultPtr dirResult = resolveOpLocal(pData, parsedResult, sDirectory); if (dirResult->rc != kSTAFOk) { *pErrorBuffer = dirResult->result.adoptImpl(); return dirResult->rc; } pData->fReaperDir = dirResult->result; } // Construct the map class for general reaper information output pData->fReaperClass = STAFMapClassDefinition::create( "STAF/Service/HandleReaper/Reaper"); pData->fReaperClass->addKey("reaperName", "Reaper Name"); pData->fReaperClass->addKey("handle", "Handle to Reap"); pData->fReaperClass->addKey("endpoint", "Endpoint to Reap"); // Construct the map class for listing service settings pData->fSettingsClass = STAFMapClassDefinition::create( "STAF/Service/HandleReaper/Settings"); pData->fSettingsClass->addKey("directory", "Directory"); // Construct the map class for detailed reaper information output pData->fReaperInfoClass = STAFMapClassDefinition::create( "STAF/Service/HandleReaper/ReaperInfo"); pData->fReaperInfoClass->addKey("reaperName", "Reaper Name"); pData->fReaperInfoClass->addKey("handle", "Handle to Reap"); pData->fReaperInfoClass->addKey("endpoint", "Endpoint to Reap"); pData->fReaperInfoClass->addKey("commandList", "Commands"); // Construct map class for a Cleanup command pData->fCommandClass = STAFMapClassDefinition::create( "STAF/Service/HandleReaper/Command"); pData->fCommandClass->addKey("cleanupEndpoint", "Cleanup Endpoint"); pData->fCommandClass->addKey("cleanupService", "Cleanup Service"); pData->fCommandClass->addKey("cleanupRequest", "Cleanup Request"); pData->fCommandClass->addKey("synchronous", "Synchronous"); // Get line separator STAFResultPtr result = pData->fHandlePtr->submit(sLocal, sVar, "RESOLVE STRING {STAF/Config/Sep/Line}"); if (result->rc != 0) { *pErrorBuffer = result->result.adoptImpl(); return result->rc; } else sLineSep = result->result; // Get local machine name (logical identifier) result = pData->fHandlePtr->submit(sLocal, sVar, "RESOLVE STRING {STAF/Config/Machine}"); if (result->rc != 0) { *pErrorBuffer = result->result.adoptImpl(); return result->rc; } else pData->fLocalMachineName = result->result; // Register Help Data registerHelpData(pData, kSTAFHandleReaperNoEntriesAvailable, STAFString("Handle Reaper has no entries available"), STAFString("The handle reaper has no entries.")); registerHelpData(pData, kSTAFHandleReaperCreateReaperPathError, STAFString("Error creating reaper path"), STAFString("The directory specified by the DIRECTORY parameter " "when registering the service or the default " "directory could not be created.")); // Determine the reaper directory STAFFSPath reaperFilePath; if (pData->fReaperDir != STAFString()) { // Set to reaper directory using DIRECTORY parameter from HANDLEREAPER // Service Configuration reaperFilePath.setRoot(pData->fReaperDir); } else { // Assign Default Reaper Directory value if no DIRECTORY parameter // - Use writeLocation>/ reaperFilePath.setRoot(pInfo->writeLocation); reaperFilePath.addDir("service"); reaperFilePath.addDir(pData->fShortName.toLowerCase()); pData->fReaperDir = reaperFilePath.asString(); } // Find all the reapers (*.nap files) in the resource directory STAFFSEntryType_t entryType = kSTAFFSFile; if (reaperFilePath.exists()) { STAFFSEnumPtr dirEnum = reaperFilePath.getEntry()->enumerate(kUTF8_STAR, sReaperExt, entryType); // Initialize each reaper for (; dirEnum->isValid(); dirEnum->next()) { STAFFSEntryPtr entry = dirEnum->entry(); STAFString fileName = entry->path().asString(); // Read the reaper file and store its data in ReaperData ReaperData reaperData; unsigned int status = readReaperFile(fileName, reaperData); if (status == kReadEndOfFile) { STAFString error( "STAFHandleReaperService.cpp: STAFServiceInit: " "Invalid file contents in handle reaper " + fileName); cout << error << endl; *pErrorBuffer = error.adoptImpl(); return kSTAFHandleReaperInvalidFileFormat; } else if (status == kFileOpenError) { STAFString error( "STAFHandleReaperService.cpp: STAFServiceInit: " "Error opening handle reaper file " + fileName); cout << error << endl; *pErrorBuffer = error.adoptImpl(); return kSTAFFileOpenError; } // Add the reaper data to the Reaper Map //reaperData.reapedHandle reaperData.reapedEndpoint bool found = false; STAFResultPtr notificationsResult = pData->fHandlePtr->submit(reaperData.reapedEndpoint, "HANDLE", "LIST NOTIFICATIONS HANDLE " + reaperData.reapedHandle + " LONG"); if (notificationsResult->rc == kSTAFOk) { STAFObjectPtr result_mc = STAFObject::unmarshall(notificationsResult->result); STAFObjectPtr notificationsList = result_mc->getRootObject(); STAFObjectIteratorPtr iter = notificationsList->iterate(); while (iter->hasNext()) { STAFObjectPtr entryMap = iter->next(); if ((entryMap->get("key")->asString() == reaperData.reaperName) && (entryMap->get("machine")->asString() == pData->fLocalMachineName)) { found = true; break; } } if (found) { pData->fReaperMap.insert(ReaperMap::value_type(reaperData.reaperName.toUpperCase(), ReaperDataPtr(new ReaperData(reaperData), ReaperDataPtr::INIT))); } } if (!found) { trigger(ReaperDataPtr(new ReaperData(reaperData), ReaperDataPtr::INIT), reaperData.reaperName, false, STAFString("STAFServiceInit"), pData); STAFTrace::trace(kSTAFTraceError, STAFString(reaperData.reaperName + " has been triggered at initialization since " + reaperData.reapedHandle+"@"+reaperData.reapedEndpoint + " was not found." + sLineSep)); } } } else { // Create the reaper directory try { STAFFSEntryPtr reaperdir = reaperFilePath.createDirectory(kSTAFFSCreatePath); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceInit: " "Invalid HandleReaper Directory: " + pData->fReaperDir); cout << error << endl; *pErrorBuffer = error.adoptImpl(); return kSTAFHandleReaperCreateReaperPathError; } } pData->fReaperMapRWSem = STAFRWSemPtr(new STAFRWSem, STAFRWSemPtr::INIT); } catch (STAFException &e) { *pErrorBuffer = getExceptionString(e, "STAFHandleReaperService.cpp: STAFServiceInit").adoptImpl(); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceInit: " "Caught unknown exception"); *pErrorBuffer = error.adoptImpl(); } return retCode; } STAFRC_t STAFServiceAcceptRequest(STAFServiceHandle_t serviceHandle, void *pRequestInfo, unsigned int reqLevel, STAFString_t *pResultBuffer) { if (reqLevel != 30) return kSTAFInvalidAPILevel; STAFRC_t retCode = kSTAFUnknownError; try { STAFResultPtr result(new STAFResult(kSTAFOk, STAFString()), STAFResultPtr::INIT); STAFServiceRequestLevel30 *pInfo = reinterpret_cast(pRequestInfo); HandleReaperServiceData *pData = reinterpret_cast(serviceHandle); STAFString request(pInfo->request); STAFString action = request.subWord(0, 1).toLowerCase(); // Call functions for the request if (action == "create") result = handleCreate(pInfo, pData); else if (action == "staf_callback") result = handleSTAFCallback(pInfo, pData); else if (action == "proxy") result = handleProxy(pInfo, pData); else if (action == "add") result = handleAdd(pInfo, pData); else if (action == "query") result = handleQuery(pInfo, pData); else if (action == "remove") result = handleRemove(pInfo, pData); else if (action == "list") result = handleList(pInfo, pData); else if (action == "delete") result = handleDelete(pInfo, pData); else if (action == "help") result = handleHelp(pInfo, pData); else if (action == "version") result = handleVersion(pInfo, pData); else if (action == "trigger") result = handleTrigger(pInfo, pData); else { result = STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, request.subWord(0, 1)), STAFResultPtr::INIT); } *pResultBuffer = result->result.adoptImpl(); retCode = result->rc; } catch (STAFException &e) { retCode = e.getErrorCode(); *pResultBuffer = getExceptionString( e, "STAFHandleReaperService.cpp: STAFServiceAcceptRequest").adoptImpl(); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceAcceptRequest: " "Caught unknown exception"); *pResultBuffer = error.adoptImpl(); } return retCode; } STAFRC_t STAFServiceTerm(STAFServiceHandle_t serviceHandle, void *pTermInfo, unsigned int termLevel, STAFString_t *pErrorBuffer) { if (termLevel != 0) return kSTAFInvalidAPILevel; STAFRC_t retCode = kSTAFUnknownError; try { retCode = kSTAFOk; HandleReaperServiceData *pData = reinterpret_cast(serviceHandle); // Un-register Help Data unregisterHelpData(pData, kSTAFHandleReaperNoEntriesAvailable); unregisterHelpData(pData, kSTAFHandleReaperCreateReaperPathError); } catch (STAFException &e) { *pErrorBuffer = getExceptionString(e, "STAFHandleReaperService.cpp: STAFServiceTerm").adoptImpl(); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceTerm: " "Caught unknown exception"); *pErrorBuffer = error.adoptImpl(); } return retCode; } STAFRC_t STAFServiceDestruct(STAFServiceHandle_t *serviceHandle, void *pDestructInfo, unsigned int destructLevel, STAFString_t *pErrorBuffer) { if (destructLevel != 0) return kSTAFInvalidAPILevel; STAFRC_t retCode = kSTAFUnknownError; try { HandleReaperServiceData *pData = reinterpret_cast(*serviceHandle); delete pData; *serviceHandle = 0; retCode = kSTAFOk; } catch (STAFException &e) { *pErrorBuffer = getExceptionString(e, "STAFHandleReaperService.cpp: STAFServiceDestruct").adoptImpl(); } catch (...) { STAFString error("STAFHandleReaperService.cpp: STAFServiceDestruct: " "Caught unknown exception"); *pErrorBuffer = error.adoptImpl(); } return retCode; } // Handles handle reaper creation requests STAFResultPtr handleCreate(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "CREATE", pData->fLocalMachineName); // Parse the result STAFCommandParseResultPtr parsedResult = pData->fCreateParser->parse(pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the reaperName variable (resolve the reaper Name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Set the reapedHandle variable (resolve the reaper Handle) resultPtr = resolveOp(pInfo, pData, parsedResult, sHandle); if (resultPtr->rc != 0) return resultPtr; STAFString reapedHandle = resultPtr->result; STAFString reapedEndpoint = sLocal; // Set the reapedEndpoint variable (resolve the reaper Endpoint) if(parsedResult->optionTimes(sEndpoint)) { resultPtr = resolveOp(pInfo, pData, parsedResult, sEndpoint); if (resultPtr->rc != 0) return resultPtr; reapedEndpoint = resultPtr->result; } // Get a write lock on the Reaper Map for the duration of this block STAFRWSemWLock wLock(*pData->fReaperMapRWSem); // Verify that the handle reaper does not already exist in the Reaper Map if ((pData->fReaperMap.find(reaperName.toUpperCase())) != pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFAlreadyExists, reaperName), STAFResultPtr::INIT); } // Register for notification when the handle ends STAFString request = STAFString("STAF_NOTIFY REGISTER") + " ONENDOFHANDLE " + reapedHandle + " MACHINE " + pData->fHandlePtr->wrapData(reapedEndpoint) + " UUID " + pInfo->stafInstanceUUID + " SERVICE " + pData->fShortName + " KEY " + pData->fHandlePtr->wrapData(reaperName); STAFResultPtr notifyResult = pData->fHandlePtr->submit(sLocal, "HANDLE", request); if (notifyResult->rc != kSTAFOk) { return notifyResult; } // Set the path for the Handle reaper file STAFFSPath reaperFilePath; reaperFilePath.setRoot(pData->fReaperDir); reaperFilePath.setName(reaperName); reaperFilePath.setExtension(sReaperExt); ReaperData reaperData(reaperName, reapedHandle, reapedEndpoint); // Write the reaper data STAFString fileName = reaperFilePath.asString(); if (writeReaperFile(fileName, reaperData) != kReadorWriteOk) { return STAFResultPtr(new STAFResult(kSTAFFileWriteError, fileName), STAFResultPtr::INIT); } // Update in memory data structures pData->fReaperMap.insert(ReaperMap::value_type(reaperData.reaperName.toUpperCase(), ReaperDataPtr(new ReaperData(reaperData), ReaperDataPtr::INIT) ) ); // Return an OK result return STAFResultPtr(new STAFResult(kSTAFOk, STAFString()), STAFResultPtr::INIT); } // Handles handle reaper deletion requests STAFResultPtr handleDelete(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { return STAFResultPtr( new STAFResult( kSTAFAccessDenied, "This is Not currently supported.\nContact dl-nate-dev@netapp.com for more information"), STAFResultPtr::INIT); STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "DELETE", pData->fLocalMachineName); // Parse the request STAFCommandParseResultPtr parsedResult = pData->fDeleteParser->parse( pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the reaperName variable (resolve the reaper name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Get a write lock on the Reaper Map for the duration of this block. // Don't need a lock on Reaper Data because I have a write lock on Reaper Map. STAFRWSemWLock wLock(*pData->fReaperMapRWSem); // Make sure the handle reaper is in the Reaper Map and get a pointer to it ReaperMap::iterator reaperIterator; ReaperDataPtr reaperPtr; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); } // Set a pointer to the handle reaper to be deleted reaperPtr = (*reaperIterator).second; //save this result for later. We don't want to return too early STAFResultPtr removeEntryResult = removeFromFile(reaperName, STAFString("handleDelete"), pData); // Remove the handle reaper from the Reaper Map before we check the result // because even if it failed, what can you do? pData->fReaperMap.erase(reaperIterator); unregister(reaperPtr, reaperName, STAFString("handleDelete"), pData); // Now that we're all done, process the results. if (removeEntryResult->rc != kSTAFOk) return removeEntryResult; // Return an Ok result return STAFResultPtr(new STAFResult(kSTAFOk, STAFString()), STAFResultPtr::INIT); } // Handles handle reaper trigger requests STAFResultPtr handleTrigger(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { return STAFResultPtr( new STAFResult( kSTAFAccessDenied, "This is Not currently supported.\nContact dl-nate-dev@netapp.com for more information"), STAFResultPtr::INIT); STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "TRIGGER", pData->fLocalMachineName); // Parse the request STAFCommandParseResultPtr parsedResult = pData->fTriggerParser->parse(pInfo->request); if (parsedResult->rc != kSTAFOk) return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); // Set the reaperName variable (resolve the reaper name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Get a write lock on the Reaper Map for the duration of this block. // Don't need a lock on Reaper Data because I have a write lock on Reaper Map. STAFRWSemWLock wLock(*pData->fReaperMapRWSem); // Make sure the handle reaper is in the Reaper Map and get a pointer to it ReaperMap::iterator reaperIterator; ReaperDataPtr reaperPtr; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); // Set a pointer to the handle reaper to be deleted reaperPtr = (*reaperIterator).second; trigger(reaperPtr, reaperName, true, STAFString("handleTrigger"), pData); // Remove the handle reaper the Reaper Map pData->fReaperMap.erase(reaperIterator); // Return an Ok result return STAFResultPtr(new STAFResult(kSTAFOk, STAFString()), STAFResultPtr::INIT); } STAFResultPtr handleProxy(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "PROXY", pData->fLocalMachineName); STAFRWSemRLock rLock(*pData->fReaperMapRWSem); // Parse the request STAFCommandParseResultPtr parsedResult = pData->fProxyParser->parse( pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the service variable STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, "PROXYSERVICE"); if (resultPtr->rc != 0) return resultPtr; STAFString service = resultPtr->result; // Set the request variable resultPtr = resolveOp(pInfo, pData, parsedResult, "PROXYREQUEST"); if (resultPtr->rc != 0) return resultPtr; STAFString request = resultPtr->result; // Set the sync type unsigned int sync; resultPtr = resolveOp(pInfo, pData, parsedResult, "SYNC"); if (resultPtr->rc != 0) return resultPtr; STAFString syncOption = resultPtr->result; sync = (syncOption.isEqualTo(sNo, kSTAFStringCaseInsensitive)) ? kSTAFReqFireAndForget : kSTAFReqSync; return pData->fHandlePtr->submit(sLocal, service, request, sync); } // Handles handle reaper add entry requests STAFResultPtr handleAdd(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "ADD", pData->fLocalMachineName); // Parse the result STAFCommandParseResultPtr parsedResult = pData->fAddParser->parse(pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the reaperName variable (resolve the reaper name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Get a write lock on the Reaper Map for the duration of this block STAFRWSemWLock wLock(*pData->fReaperMapRWSem); // Make sure the handle reaper is in the Reaper Map and get a pointer to it ReaperMap::iterator reaperIterator; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); } // Create a copy of the reaper to update ReaperDataPtr reaperPtr = (*reaperIterator).second; ReaperData newReaper = *(reaperPtr); // Get each entry to be added and check if entry is already in the reaper. // If there are any duplicate entries to be added, return an error and // do not update the handle reaper. unsigned int numEntriesToAdd = parsedResult->optionTimes(sCleanupEndpoint); unsigned int i; resultPtr = resolveOp(pInfo, pData, parsedResult, sCleanupService); if (resultPtr->rc != 0) return resultPtr; STAFString cleanupService = resultPtr->result; resultPtr = resolveOp(pInfo, pData, parsedResult, sCleanupRequest); if (resultPtr->rc != 0) return resultPtr; STAFString cleanupRequest = resultPtr->result; bool sync; resultPtr = resolveOp(pInfo, pData, parsedResult, "SYNC"); if (resultPtr->rc != 0) return resultPtr; STAFString syncOption = resultPtr->result; sync = (syncOption.isEqualTo(sNo, kSTAFStringCaseInsensitive)) ? false : true; for (i = 1; i <= numEntriesToAdd; i++) { STAFString thisEndpoint = parsedResult->optionValue(sCleanupEndpoint, i); // Add to the end of the new reaper's command list CommandData commandData(thisEndpoint, cleanupService, cleanupRequest, sync); newReaper.commandList.push_back(commandData); newReaper.numCommands++; } // Update the reaper in memory reaperPtr->commandList = newReaper.commandList; reaperPtr->numCommands = newReaper.numCommands; // Delete the old reaper file and write the new reaper file STAFFSPath reaperFilePath; reaperFilePath.setRoot(pData->fReaperDir); reaperFilePath.setName(reaperName); reaperFilePath.setExtension(sReaperExt); try { reaperFilePath.getEntry()->remove(); } catch (STAFException &e) { result = getExceptionString(e, "STAFHandleReaperService.cpp: Add ").adoptImpl(); return STAFResultPtr(new STAFResult(kSTAFFileDeleteError, result), STAFResultPtr::INIT); } STAFString fileName = reaperFilePath.asString(); if (writeReaperFile(fileName, newReaper) != kReadorWriteOk) { return STAFResultPtr(new STAFResult(kSTAFFileWriteError, fileName), STAFResultPtr::INIT); } // Return an Ok result return STAFResultPtr(new STAFResult(kSTAFOk, result), STAFResultPtr::INIT); } // Handles handle reaper remove entry requests STAFResultPtr handleRemove(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 4 VALIDATE_TRUST(4, pData->fShortName, "REMOVE", pData->fLocalMachineName); // Parse the result STAFCommandParseResultPtr parsedResult = pData->fRemoveParser->parse(pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the reaperName variable (resolve the reaper name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Get a write lock on the Reaper Map for the duration of this block STAFRWSemWLock wLock(*pData->fReaperMapRWSem); // Make sure the specified handle reaper exists in Reaper Map ReaperMap::iterator reaperIterator; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); } ReaperDataPtr reaperPtr = (*reaperIterator).second; STAFMutexSemLock lock(*reaperPtr->accessSem); if (reaperPtr->commandList.size() == 0) { return STAFResultPtr(new STAFResult(kSTAFHandleReaperNoEntriesAvailable, reaperName), STAFResultPtr::INIT); } unsigned int numEntriesToRemove = parsedResult->optionTimes(sCleanupEndpoint); resultPtr = resolveOp(pInfo, pData, parsedResult, sCleanupService); if (resultPtr->rc != 0) return resultPtr; STAFString cleanupService = resultPtr->result; resultPtr = resolveOp(pInfo, pData, parsedResult, sCleanupRequest); if (resultPtr->rc != 0) return resultPtr; STAFString cleanupRequest = resultPtr->result; bool synchronous; resultPtr = resolveOp(pInfo, pData, parsedResult, "SYNC"); if (resultPtr->rc != 0) return resultPtr; STAFString syncOption = resultPtr->result; synchronous = (syncOption.isEqualTo(sNo, kSTAFStringCaseInsensitive)) ? false : true; // Create a copy of the reaper to update ReaperData newReaper = *(reaperPtr); // Get each of the entries to be removed; If an invalid entry is found, // return with an appropriate error message and do not remove any other // valid entries specified on the request. for (unsigned int i = 1; i <= numEntriesToRemove; i++) { STAFString thisEndpoint = parsedResult->optionValue(sCleanupEndpoint, i); bool entryExists = false; unsigned int commandID; // Check if this entry is in the reaper - set commandID to its index for (unsigned int j = 0; j < newReaper.commandList.size() && !entryExists; j++) { if ((thisEndpoint == newReaper.commandList[j].cleanupEndpoint) && (cleanupService == newReaper.commandList[j].cleanupService) && (cleanupRequest == newReaper.commandList[j].cleanupRequest) && (synchronous == newReaper.commandList[j].synchronous)) { entryExists = true; commandID = j; } } if (entryExists) { newReaper.numCommands--; newReaper.commandList.erase(newReaper.commandList.begin() + commandID); } else if (!entryExists) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, "Doesn't Exist:" + sLineSep + "\t" + thisEndpoint + " " + cleanupService + " " + cleanupRequest), STAFResultPtr::INIT); } } // end for each entry specified // Delete the old reaper file and write the new reaper file STAFFSPath reaperFilePath; reaperFilePath.setRoot(pData->fReaperDir); reaperFilePath.setName(reaperName); reaperFilePath.setExtension(sReaperExt); // Update the reaper in memory reaperPtr->commandList = newReaper.commandList; reaperPtr->numCommands = newReaper.numCommands; try { reaperFilePath.getEntry()->remove(); } catch (STAFException &e) { result = getExceptionString(e, "STAFHandleReaperService.cpp: Remove ").adoptImpl(); return STAFResultPtr(new STAFResult(kSTAFFileDeleteError, result), STAFResultPtr::INIT); } STAFString fileName = reaperFilePath.asString(); if (writeReaperFile(fileName, newReaper) != kReadorWriteOk) { return STAFResultPtr(new STAFResult(kSTAFFileWriteError, fileName), STAFResultPtr::INIT); } // Result an Ok result return STAFResultPtr(new STAFResult(kSTAFOk, result), STAFResultPtr::INIT); } // Handles reaper list requests STAFResultPtr handleList(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { // Verify the requester has at least trust level 2 VALIDATE_TRUST(2, pData->fShortName, "LIST", pData->fLocalMachineName); // Parse the request STAFCommandParseResultPtr parsedResult = pData->fListParser->parse( pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } STAFRWSemRLock rLock(*pData->fReaperMapRWSem); STAFObjectPtr mc = STAFObject::createMarshallingContext(); if (parsedResult->optionTimes("SETTINGS")) { // LIST SETTINGS // Create a marshalled map containing settings for the service mc->setMapClassDefinition(pData->fSettingsClass->reference()); // Write the service settings to a map STAFObjectPtr outputMap = pData->fSettingsClass->createInstance(); outputMap->put("directory", pData->fReaperDir); mc->setRootObject(outputMap); } else { // LIST REAPERS (This is the default if only LIST is specified) // Create a marshalled list of maps containing reaper information mc->setMapClassDefinition(pData->fReaperClass->reference()); STAFObjectPtr outputList = STAFObject::createList(); // Get a read lock on the Reaper Map for the duration of this block STAFRWSemRLock rLock(*pData->fReaperMapRWSem); // Write all the reaper names to the result variable ReaperMap::iterator reaperIterator; for(reaperIterator = pData->fReaperMap.begin(); reaperIterator != pData->fReaperMap.end(); ++reaperIterator) { STAFObjectPtr reaperInfoMap = pData->fReaperClass->createInstance(); reaperInfoMap->put("reaperName", reaperIterator->second->reaperName); reaperInfoMap->put("handle", reaperIterator->second->reapedHandle); reaperInfoMap->put("endpoint", reaperIterator->second->reapedEndpoint); outputList->append(reaperInfoMap); } mc->setRootObject(outputList); } // Return an Ok result and the marshalled output for a list of the reapers return STAFResultPtr(new STAFResult(kSTAFOk, mc->marshall()), STAFResultPtr::INIT); } // Handles handle reaper query requests STAFResultPtr handleQuery(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { STAFString result; STAFRC_t rc = kSTAFOk; // Verify the requester has at least trust level 2 VALIDATE_TRUST(2, pData->fShortName, "QUERY", pData->fLocalMachineName); // Parse the request STAFCommandParseResultPtr parsedResult = pData->fQueryParser->parse( pInfo->request); if (parsedResult->rc != kSTAFOk) { return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); } // Set the reaperName variable (resolve the reaper name) STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, sReaper); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; // Create a marshalled map of general reaper information STAFObjectPtr mc = STAFObject::createMarshallingContext(); mc->setMapClassDefinition(pData->fReaperClass->reference()); mc->setMapClassDefinition(pData->fReaperInfoClass->reference()); mc->setMapClassDefinition(pData->fCommandClass->reference()); STAFObjectPtr reaperInfoMap = pData->fReaperInfoClass->createInstance(); // Get a read lock on the Reaper Map for the duration of this block STAFRWSemRLock rLock(*pData->fReaperMapRWSem); // Make sure the handle reaper is in the Reaper Map and get a pointer to it ReaperMap::iterator reaperIterator; ReaperDataPtr reaperPtr; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); } // Set a pointer to the handle reaper being queried reaperPtr = (*reaperIterator).second; reaperInfoMap->put("reaperName", reaperPtr->reaperName); reaperInfoMap->put("handle", reaperPtr->reapedHandle); reaperInfoMap->put("endpoint", reaperPtr->reapedEndpoint); // Create an empty list object for the marshalled list of the reaper's // ommand entries STAFObjectPtr commandList = STAFObject::createList(); if (reaperPtr->commandList.size() > 0) { // Append an entry to commandList for each command for (unsigned int i = 0; i < reaperPtr->commandList.size(); i++) { // Create a map of information about each command STAFObjectPtr commandMap = pData->fCommandClass->createInstance(); commandMap->put("cleanupEndpoint", reaperPtr->commandList[i].cleanupEndpoint); commandMap->put("cleanupService", reaperPtr->commandList[i].cleanupService); commandMap->put("cleanupRequest", reaperPtr->commandList[i].cleanupRequest); STAFString sync = (reaperPtr->commandList[i].synchronous)? "Yes" : "No"; commandMap->put("synchronous", sync); // Add the entry in a marshalling context as a map to commandList commandList->append(commandMap); } reaperInfoMap->put("commandList", commandList); } // Set the marshalling context's root object mc->setRootObject(reaperInfoMap); // Return the marshalled result of the query return STAFResultPtr(new STAFResult(kSTAFOk, mc->marshall()), STAFResultPtr::INIT); } STAFResultPtr handleSTAFCallback(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { STAFString result; STAFRC_t rc = kSTAFOk; //XXX This needs to be un-commented out when trigger and/or delete is fixed // Don't check the TRUST level, but make sure the requesting handle // is the STAFProc handle /*if (pInfo->handle != 1) { return STAFResultPtr( new STAFResult( kSTAFAccessDenied, "This request is only valid when submitted by STAFProc"), STAFResultPtr::INIT); }*/ STAFCommandParseResultPtr parsedResult = pData->fCallbackParser->parse(pInfo->request); if (parsedResult->rc != kSTAFOk) return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString, parsedResult->errorBuffer), STAFResultPtr::INIT); STAFResultPtr resultPtr = resolveOp(pInfo, pData, parsedResult, "HANDLE"); if (resultPtr->rc != 0) return resultPtr; STAFString handle = resultPtr->result; // Get a write lock on the Reaper Map for the duration of this block STAFRWSemWLock wLock(*pData->fReaperMapRWSem); resultPtr = resolveOp(pInfo, pData, parsedResult, "MACHINE"); if (resultPtr->rc != 0) return resultPtr; STAFString machine = resultPtr->result; resultPtr = resolveOp(pInfo, pData, parsedResult, "UUID"); if (resultPtr->rc != 0) return resultPtr; STAFString uuid = resultPtr->result; resultPtr = resolveOp(pInfo, pData, parsedResult, "KEY"); if (resultPtr->rc != 0) return resultPtr; STAFString reaperName = resultPtr->result; ReaperMap::iterator reaperIterator; // Make sure the handle reaper is in the Reaper Map and get a pointer to it ReaperDataPtr reaperPtr; reaperIterator = pData->fReaperMap.find(reaperName.toUpperCase()); if (reaperIterator == pData->fReaperMap.end()) { return STAFResultPtr(new STAFResult(kSTAFDoesNotExist, reaperName), STAFResultPtr::INIT); } // Set a pointer to the handle reaper being reaped reaperPtr = (*reaperIterator).second; trigger(reaperPtr, reaperName, false, STAFString("handleSTAFCallback"), pData); // Remove the handle reaper the Reaper Map pData->fReaperMap.erase(reaperIterator); return STAFResultPtr(new STAFResult(kSTAFOk, result), STAFResultPtr::INIT); } STAFResultPtr handleHelp(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { // Verify the requester has at least trust level 1 VALIDATE_TRUST(1, pData->fShortName, "HELP", pData->fLocalMachineName); // Return help text STAFString help("REAPER Service Help" + sLineSep + sLineSep); help += "CREATE REAPER HANDLE [ENDPOINT ]" + sLineSep + "DELETE REAPER " + sLineSep + "QUERY REAPER " + sLineSep + "ADD REAPER ENDPOINT ..." + sLineSep + " SERVICE " + sLineSep + " REQUEST " + sLineSep + " [SYNC ]" + sLineSep + "REMOVE REAPER ENDPOINT ..." + sLineSep + " SERVICE " + sLineSep + " REQUEST " + sLineSep + " [SYNC ]" + sLineSep + "TRIGGER REAPER " + sLineSep + "LIST [REAPERS | SETTINGS]" + sLineSep + "PROXY PROXYSERVICE PROXYREQUEST [SYNC ]" + sLineSep + "VERSION" + sLineSep + "HELP" + sLineSep; return STAFResultPtr(new STAFResult(kSTAFOk, help), STAFResultPtr::INIT); } STAFResultPtr handleVersion(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData) { // Verify the requester has at least trust level 1 VALIDATE_TRUST(1, pData->fShortName, "VERSION", pData->fLocalMachineName); return STAFResultPtr(new STAFResult(kSTAFOk, ReaperVersion), STAFResultPtr::INIT); } void trigger(ReaperDataPtr reaperPtr, STAFString reaperName, bool doUnregister, STAFString caller, HandleReaperServiceData *pData) { removeFromFile(reaperName, caller, pData); if(doUnregister) { unregister(reaperPtr, reaperName, caller, pData); } STAFMutexSemLock lock(*reaperPtr->accessSem); for (unsigned int i = 0; i < reaperPtr->commandList.size(); i++) { //Execute the Cleanup Request unsigned int sync = (reaperPtr->commandList[i].synchronous) ? kSTAFReqSync : kSTAFReqFireAndForget; STAFResultPtr cleanupResult = pData->fHandlePtr->submit(reaperPtr->commandList[i].cleanupEndpoint, reaperPtr->commandList[i].cleanupService, reaperPtr->commandList[i].cleanupRequest, sync); if ((cleanupResult->rc != kSTAFOk) || (STAFTrace::doTrace(kSTAFTraceDebug))) { STAFTracePoint_t flag = (cleanupResult->rc != kSTAFOk) ? kSTAFTraceError : kSTAFTraceDebug; STAFObjectPtr result_mc = STAFObject::unmarshall(cleanupResult->result); STAFTrace::trace(flag, STAFString("STAFHandleReaperService::" + caller + ":")+ sLineSep + STAFString("\tEndpoint=") + reaperPtr->commandList[i].cleanupEndpoint + sLineSep + STAFString("\tSERVICE=") + reaperPtr->commandList[i].cleanupService + sLineSep + STAFString("\tREQUEST=") + reaperPtr->commandList[i].cleanupRequest + sLineSep + sLineSep + STAFString("\tRC=") + STAFString(cleanupResult->rc) + sLineSep + STAFString("\tResult=") + result_mc->asFormattedString() + sLineSep); } } } void unregister(ReaperDataPtr reaperPtr, STAFString reaperName, STAFString caller, HandleReaperServiceData *pData) { STAFString proxyRequest("PROXY PROXYSERVICE HANDLE SYNC Yes PROXYREQUEST " + pData->fHandlePtr->wrapData(STAFString("STAF_NOTIFY UNREGISTER ONENDOFHANDLE " + reaperPtr->reapedHandle + " MACHINE " + pData->fLocalMachineName + //" UUID " + pInfo->stafInstanceUUID + " SERVICE " + pData->fShortName + " KEY " + pData->fHandlePtr->wrapData(reaperName)))); // This is a 'Best Effort' attempt. If it doesn't work ... oh well. STAFResultPtr unregisterResult = pData->fHandlePtr->submit(reaperPtr->reapedEndpoint, pData->fShortName, proxyRequest); if (unregisterResult->rc != kSTAFOk) { STAFObjectPtr result_mc = STAFObject::unmarshall(unregisterResult->result); STAFTrace::trace(kSTAFTraceError, proxyRequest + STAFString(" FAILED: ") + reaperPtr->reapedEndpoint + sLineSep + STAFString("\tRC=") + unregisterResult->rc + sLineSep + STAFString("\tResult=") + result_mc->asFormattedString() + sLineSep); } } STAFResultPtr removeFromFile(STAFString reaperName, STAFString caller, HandleReaperServiceData *pData) { STAFFSPath reaperFilePath; reaperFilePath.setRoot(pData->fReaperDir); reaperFilePath.setName(reaperName); reaperFilePath.setExtension(sReaperExt); STAFString result; STAFRC_t rc = kSTAFOk; try { reaperFilePath.getEntry()->remove(); } catch (STAFException &e) { unsigned int osRC = 0; unsigned int length = 0; const char *buffer = 0; STAFStringGetBuffer(STAFString("STAFHandleReaperSerice.cpp: " + caller + "Can Not delete entry").adoptImpl(), &buffer, &length, &osRC); result = getExceptionString(e, buffer).adoptImpl(); return STAFResultPtr(new STAFResult(kSTAFFileDeleteError, result), STAFResultPtr::INIT); } return STAFResultPtr(new STAFResult(kSTAFOk, STAFString()), STAFResultPtr::INIT); } STAFResultPtr resolveStr(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData, const STAFString &theString) { return pData->fHandlePtr->submit(sLocal, sVar, sResStrResolve + STAFString(pInfo->requestNumber) + sString + pData->fHandlePtr->wrapData(theString)); } STAFResultPtr resolveOp(STAFServiceRequestLevel30 *pInfo, HandleReaperServiceData *pData, STAFCommandParseResultPtr &parsedResult, const STAFString &fOption, unsigned int optionIndex) { STAFString optionValue = parsedResult->optionValue(fOption, optionIndex); if (optionValue.find(sLeftCurlyBrace) == STAFString::kNPos) { return STAFResultPtr(new STAFResult(kSTAFOk, optionValue), STAFResultPtr::INIT); } return resolveStr(pInfo, pData, optionValue); } STAFResultPtr resolveOpLocal(HandleReaperServiceData *pData, STAFCommandParseResultPtr &parsedResult, const STAFString &fOption, unsigned int optionIndex) { STAFString optionValue = parsedResult->optionValue(fOption, optionIndex); if (optionValue.find(sLeftCurlyBrace) == STAFString::kNPos) { return STAFResultPtr(new STAFResult(kSTAFOk, optionValue), STAFResultPtr::INIT); } return pData->fHandlePtr->submit(sLocal, sVar, sResStrResolve + sString + pData->fHandlePtr->wrapData(optionValue)); } void registerHelpData(HandleReaperServiceData *pData, unsigned int errorNumber, const STAFString &shortInfo, const STAFString &longInfo) { static STAFString regString("REGISTER SERVICE %C ERROR %d INFO %C " "DESCRIPTION %C"); pData->fHandlePtr->submit(sLocal, sHelp, STAFHandle::formatString(regString.getImpl(), pData->fShortName.getImpl(), errorNumber, shortInfo.getImpl(), longInfo.getImpl())); } void unregisterHelpData(HandleReaperServiceData *pData, unsigned int errorNumber) { static STAFString regString("UNREGISTER SERVICE %C ERROR %d"); pData->fHandlePtr->submit(sLocal, sHelp, STAFHandle::formatString(regString.getImpl(), pData->fShortName.getImpl(), errorNumber)); } void writeUIntToFile(ostream &output, unsigned int data, unsigned int length) { union { char bytes[4]; unsigned int uint; }; uint = STAFUtilSwapUInt(STAFUtilConvertNativeUIntToLE(data)); output.write(&bytes[4 - length], length); } void readUIntFromFile(istream &input, unsigned int &data, unsigned int length) { union { char bytes[4]; unsigned int uint; }; uint = 0; input.read(&bytes[4 - length], length); data = STAFUtilConvertLEUIntToNative(STAFUtilSwapUInt(uint)); } void readStringFromFile(istream &input, STAFString &inString) { // First read in the UTF-8 data unsigned int stringLength = 0; readUIntFromFile(input, stringLength); char *inputData = new char[stringLength]; input.read(inputData, stringLength); try { inString = STAFString(inputData, stringLength, STAFString::kUTF8); } catch(...) { delete [] inputData; throw; } delete [] inputData; } void writeStringToFile(ostream &output, STAFString &outString) { unsigned int stringLength = outString.length(); writeUIntToFile(output, stringLength); output.write(outString.buffer(), stringLength); } // Read a handle reaper file and store its contents in ReaperData. unsigned int readReaperFile(const STAFString &fileName, ReaperData &reaperData) { unsigned int rc = kReadorWriteOk; // Open the reaper file (in binary mode) fstream reaperfile(fileName.toCurrentCodePage()->buffer(), ios::in | STAF_ios_binary); if (!reaperfile) return kFileOpenError; if (reaperfile.eof()) return kReadEndOfFile; readStringFromFile(reaperfile, reaperData.reaperName); readStringFromFile(reaperfile, reaperData.reapedHandle); readStringFromFile(reaperfile, reaperData.reapedEndpoint); readUIntFromFile(reaperfile, reaperData.numCommands); STAFString cleanupEndpoint; STAFString cleanupService; STAFString cleanupRequest; unsigned int synchronous; for (unsigned int i = 0; i < reaperData.numCommands; i++) { readStringFromFile(reaperfile, cleanupEndpoint); readStringFromFile(reaperfile, cleanupService); readStringFromFile(reaperfile, cleanupRequest); readUIntFromFile(reaperfile, synchronous); CommandData commandData(cleanupEndpoint, cleanupService, cleanupRequest, synchronous); reaperData.commandList.push_back(commandData); } return rc; } // Write the handle reaper file. unsigned int writeReaperFile(const STAFString &fileName, ReaperData &reaperData) { // Open the reaper file fstream reaperfile(fileName.toCurrentCodePage()->buffer(), ios::out | STAF_ios_binary); if (!reaperfile) return kFileOpenError; // Write to the reaper file writeStringToFile(reaperfile, reaperData.reaperName); writeStringToFile(reaperfile, reaperData.reapedHandle); writeStringToFile(reaperfile, reaperData.reapedEndpoint); unsigned int numCommands = reaperData.commandList.size(); writeUIntToFile(reaperfile, numCommands); for (unsigned int i = 0; i < numCommands; i++) { writeStringToFile(reaperfile, reaperData.commandList[i].cleanupEndpoint); writeStringToFile(reaperfile, reaperData.commandList[i].cleanupService); writeStringToFile(reaperfile, reaperData.commandList[i].cleanupRequest); writeUIntToFile(reaperfile, reaperData.commandList[i].synchronous); } return kReadorWriteOk; }