//--------------------------------------------------------- /// SendResponse /// /// Sends the response either over sockets or shared memory /// /// \param requestID the requestID to send the response to /// \param cpsMimeType the mimetype to send the response as /// \param cpsResponse the response to send /// \param uResponseSize the size of the response being sent /// \param bStreaming indicates that the response it to a streaming request /// /// \return true if the response is 'sent' correctly; false otherwise //--------------------------------------------------------- bool SendResponse(CommunicationID requestID, const char* cpsMimeType, const char* cpsResponse, unsigned int uResponseSize, bool bStreaming) { // find out if this is a streaming response if (bStreaming) { Log(logTRACE, "Sending response over socket\n"); // this is a streaming response // use the socket for comms return SendMimeResponse(requestID, cpsMimeType, cpsResponse, uResponseSize); } // use Shared memory if this is not a streaming response if (smLockPut("PLUGINS_TO_GPS", sizeof(requestID) + ((unsigned long) strlen(cpsMimeType) * sizeof(const char)) + uResponseSize, 3) == false) { Log(logASSERT, "Not enough space in shared memory for response.\n"); return false; } NamedSemaphore semaphore; bool opened = semaphore.Open("PLUGINS_TO_GPS_SEMAPHORE"); if (opened) { if (semaphore.Signal() == false) { Log(logWARNING, "Failed to signal PLUGINS_TO_GPS_SEMAPHORE. Response may be lost. Error is %d, Previous count is 0\n", osGetLastSystemError()); } semaphore.Close(); } else { Log(logWARNING, "Failed to open PLUGINS_TO_GPS_SEMAPHORE. Response may be delayed.\n"); } bool bResult = (smPut("PLUGINS_TO_GPS", &requestID, sizeof(requestID)) && smPut("PLUGINS_TO_GPS", (void*)cpsMimeType, (unsigned long) strlen(cpsMimeType) * sizeof(const char)) && smPut("PLUGINS_TO_GPS", (void*)cpsResponse, uResponseSize)); smUnlockPut("PLUGINS_TO_GPS"); if (bResult == false) { Log(logASSERT, "Failed to put part of the response into shared memory\n"); } else { // remove the request RemoveRequest(requestID); } return bResult; }
//-------------------------------------------------------------- /// Create the shared memory needed to communicate between the /// web server and the plugin /// \return true if successful, false if error //-------------------------------------------------------------- bool ProcessTracker::CreateSharedMemory() { #ifdef _WIN32 if (smExists("GPS_TO_MDLL")) { if (smOpen("GPS_TO_MDLL")) { if (smLockGet("GPS_TO_MDLL")) { //the shared memory already exists, so we need to read everything from it, to make sure it's empty // closing and recreated the shared memory does not work because the MicroDLL has it open // so that it can inject into any spawned processes (via CreateProcess). If MicroDLL doesn't keep // a handle to the shared memory, it could be closed by everyone, get destroyed and then it wouldn't // be able to follow CreateProcess. char tmp[ PS_MAX_PATH ]; while (smGet("GPS_TO_MDLL", NULL, 0) != 0) { // the smGet call will clear the shared memory smGet("GPS_TO_MDLL", tmp, PS_MAX_PATH); } smUnlockGet("GPS_TO_MDLL"); } } } // now write the plugin info into the shared memory // Put wrapper info into a shared memory for micro DLL // make the shared memory big enough for all the wrappers that are known about // even though we're only going to write in the wrappers that are allowed if (smCreate("GPS_TO_MDLL", (unsigned long)GetWrapperMap().size() * 3, PS_MAX_PATH)) { // lock the buffer if it has enough space for 3 strings for each of the allowed wrappers unsigned long ulNumBuffers = (unsigned long) g_allowedWrappersMap.size() * 3; if (smLockPut("GPS_TO_MDLL", ulNumBuffers * PS_MAX_PATH, ulNumBuffers)) { char strPath[PS_MAX_PATH]; char strName[PS_MAX_PATH]; char strDlls[PS_MAX_PATH]; for (WrapperMap::const_iterator iter = g_allowedWrappersMap.begin(); iter != g_allowedWrappersMap.end(); ++iter) { strcpy_s(strPath, PS_MAX_PATH, iter->second.strPluginPath.asCharArray()); strcpy_s(strName, PS_MAX_PATH, iter->second.strPluginName.asCharArray()); strcpy_s(strDlls, PS_MAX_PATH, iter->second.strWrappedDll.asCharArray()); if (smPut("GPS_TO_MDLL", (void*) strPath, PS_MAX_PATH) == false || smPut("GPS_TO_MDLL", (void*) strName, PS_MAX_PATH) == false || smPut("GPS_TO_MDLL", (void*) strDlls, PS_MAX_PATH) == false) { Log(logERROR, "Couldn't put wrapper info into shared memory.\n"); smUnlockPut("GPS_TO_MDLL"); return false; } } smUnlockPut("GPS_TO_MDLL"); } else { Log(logERROR, "There is not enough space in the shared memory for the desired content.\n"); return false; } } else { Log(logERROR, "Couldn't create shared memory to pass wrapper registration\n"); return false; } #else for (WrapperMap::const_iterator iter = g_allowedWrappersMap.begin(); iter != g_allowedWrappersMap.end(); ++iter) { // On Linux, Create the shared memory from the PerfStudio server so that // it is cleaned up properly. if (smCreate(iter->second.strPluginShortDesc.asCharArray(), 100, sizeof(HTTPRequestHeader)) == false) { Log(logERROR, "Couldn't create shared memory for plugin.\n"); return false; } } #endif // def _WIN32 return true; }
//////////////////////////////////////////////////////////////////////////////////////////// /// Passes the supplied request header to the specifed plugin /// \param strDestination the short description of the plugin to pass the request to /// \param pRequestHeader the request header to pass to the plugin /// \param pid the process id to pass the request to. /// \param pClientSocket the socket used to read the request /// \return true if the request was passed to the plugin; false otherwise //////////////////////////////////////////////////////////////////////////////////////////// bool ProcessTracker::PassRequestToPlugin(const char* strDestination, HTTPRequestHeader* pRequestHeader, unsigned long pid, NetSocket* pClientSocket) { if (strstr(pRequestHeader->GetHeaderData()->url, STR_STREAM_TOKEN) != NULL) { Log(logTRACE, "Duplicating Socket for request: %s\n", pRequestHeader->GetHeaderData()->url); // this is a streaming request, duplicate the socket // to reduce the overhead incurred by the shared memory approach #if defined (_WIN32) if (pClientSocket->DuplicateToPID(pid, &pRequestHeader->GetHeaderData()->ProtoInfo) != 0) #else PS_UNREFERENCED_PARAMETER(pid); if (CreateStreamSocket(pRequestHeader, pClientSocket) == false) #endif { Log(logERROR, "Failed to duplicate socket for streaming request. Error %lu\n", osGetLastSystemError()); return false; } } bool bResult = false; if (smLockPut(strDestination, sizeof(HTTPRequestHeader), 1)) { // Check to see if the postdata failed to come over in some way. if (pRequestHeader->GetPostDataSize() > 0 && pRequestHeader->GetPostData() == NULL) { Log(logERROR, "PostData size is %d, but PostData is NULL\n", pRequestHeader->GetPostDataSize()); // Force the data size to zero pRequestHeader->SetPostDataSize(0); } // Create a new record of this request // We will check to see when it comes back from the server. //RequestInFlight* pNewRequest = new RequestInFlight(pRequestHeader, pClientSocket); // Add the new record to the DB. //RequestsInFlightDatabase::Instance()->Add(pClientSocket, pNewRequest); bResult = smPut(strDestination, pRequestHeader->GetHeaderData(), sizeof(HTTPHeaderData)); // Keep in for debugging //StreamLog::Ref() << "1) smPut HTTPRequestHeader\n" ; // If there is POST data we must send that too. if (pRequestHeader->GetPostDataSize() > 0 && pRequestHeader->GetPostData() != NULL) { bResult = smPut(strDestination, pRequestHeader->GetPostData(), pRequestHeader->GetPostDataSize()); // Keep in for debugging //StreamLog::Ref() << "2) smPut Shader Code: " << pRequestHeader->pPostData << "\n"; } smUnlockPut(strDestination); #ifdef DEBUG_COMMS_PERFORMANCE CommandTimingManager::Instance()->IncrementServerLoadingCount(1) ; #endif } #ifdef DEBUG_COMMS_PERFORMANCE // Record the time now that we have sent the command over the shared memory. CommandTiming* cmdTiming = CommandTimingManager::Instance()->GetTimingFromPendingList(pClientSocket); if (cmdTiming != NULL) { LARGE_INTEGER nPerformanceCount; QueryPerformanceCounter(&nPerformanceCount); cmdTiming->SetPostSharedMemorySend(nPerformanceCount); // Set the current server loading value cmdTiming->SetServerLoadingCount(CommandTimingManager::Instance()->GetServerLoadingCount()); } #endif return bResult; }