//-----------------------------------------------------------------------------
/// GetPendingRequests
///
/// This is a non-blocking function that will iterate through the pending
/// requests and call ProcessRequest (See IProcessRequests.h) for each request.
/// Frame-based plugins should call this function at the start of each frame.
/// Global plugins do not need to call this function.
//-----------------------------------------------------------------------------
void GetPendingRequests()
{
    if (smLockGet(g_strSharedMemoryName) == false)
    {
        return;
    }

    HTTPHeaderData requestHeader;
    DWORD dwSize = sizeof(HTTPHeaderData);

    int nCount = 0;

    while (smGet(g_strSharedMemoryName, NULL, 0) > 0)
    {
        smGet(g_strSharedMemoryName, (void*)&requestHeader, dwSize);
        HTTPRequestHeader* pRequest = new HTTPRequestHeader(requestHeader);

        // Check to see if POST data is present.
        if (pRequest->GetPostDataSize() > 0)
        {
            string strError;
            bool bRes = pRequest->ReadPostData(strError, true, g_strSharedMemoryName);

            if (bRes == false)
            {
                Log(logERROR, "Failed to read POST data during smGet().\n");
            }

            // Debug code - leave in for now.
            //printf ( "%s\n", pRequest->GetPostData() );
        }

        CommunicationID requestID = CreateRequest(pRequest, false);
        nCount++;

        if (g_processRequest(requestID) == false)
        {
            SendHTTPErrorResponse(requestID, 404);
            break;
        }
    }

    smUnlockGet(g_strSharedMemoryName);

    if (nCount > 0)
    {
        Log(logMESSAGE, "Server loading: %d\n", nCount);
    }
}
gtASCIIString PeekPendingRequests()
{
    if (smLockGet(g_strSharedMemoryName) == false)
    {
        return "";
    }

    // Check to see if there is a command
    if (smGet(g_strSharedMemoryName, NULL, 0) == 0)
    {
        // There are no commands
        return "";
    }

    HTTPHeaderData requestHeaderData;
    DWORD dwSize = sizeof(HTTPHeaderData);

    // Get the header
    smPeek(g_strSharedMemoryName, (void*)&requestHeaderData, dwSize);
    HTTPRequestHeader* pRequest = new HTTPRequestHeader(requestHeaderData);

    gtASCIIString str = pRequest->GetUrl();

    smUnlockGet(g_strSharedMemoryName);

    // delete the header data
    delete pRequest;

    return str;
}
示例#3
0
////////////////////////////////////////////////////////////////////////////////////////////
/// Read the POST data section of a web request from shared memory
/// Both input streams read pointers must be set at the beginning of the POST data.
/// \param strError Output error string
/// \param pSharedMemoryName name of the shared memory to read
/// \return True if success, False if fail.
////////////////////////////////////////////////////////////////////////////////////////////
bool HTTPRequestHeader::ReadPostData(string& strError, const char* pSharedMemoryName)
{
    unsigned int nContentLength = StartReadPostData(strError);

    if (nContentLength == 0)
    {
        return false;
    }

    gtSize_t nRead = 0;

    // Read data from shared memory
    nRead = smGet(pSharedMemoryName, (void*)m_pPostData, nContentLength);

    // Terminate the buffer.
    m_pPostData[nRead] = '\0';

    //// Keep in for Debugging
    //StreamLog::Ref() << "READ IN SHADER:" << pPostDataBuffer << "\n";
    //printf ( "Read shader from web request: \n%s\n", m_pPostData);
    return true;
}
//--------------------------------------------------------------
/// Injects the application specified by the Inject command and
/// sends the results of the injection to the requester
/// \param requestID the ID of the incoming request
/// \param sCmd pointer to the string containing the request
/// \param pClientSocket the socket used to send the response
//--------------------------------------------------------------
void ProcessTracker::DoInjectCommand(CommunicationID requestID, char** sCmd, NetSocket* pClientSocket)
{
    // clear the previous data since it is about to get reset
    g_allowedWrappersMap.clear();
    m_injectedAppName = "";
    m_injectedAppArgs = "";

    // parse the command
    gtASCIIString strCmd(*sCmd);
    std::list< gtASCIIString > paramList;
    strCmd.Split("&", true, paramList);

    for (std::list< gtASCIIString >::const_iterator iter = paramList.begin();
         iter != paramList.end();
         ++iter)
    {
        char* pParam = (char*) iter->asCharArray();
        char** ppParam = &pParam;

        if (IsToken(ppParam, "plugins="))
        {
            // plugins= is followed by a list of comma separated short descriptions of wrappers
            gtASCIIString strPlugins(*ppParam);
            std::list< gtASCIIString > pluginList;
            strPlugins.Split(",", true, pluginList);

            for (std::list< gtASCIIString >::const_iterator iter1 = pluginList.begin();
                 iter1 != pluginList.end();
                 ++iter1)
            {
                if (*iter1 == "")
                {
                    Log(logERROR, "Failed to parse plugin name\n");
                    SendTextResponse(requestID, "Error: Failed to parse plugin name.", pClientSocket);
                    return;
                }

                WrapperMap::iterator iWrapper = GetWrapperMap().find(iter1->asCharArray());

                if (iWrapper == GetWrapperMap().end())
                {
                    Log(logERROR, "Invalid plugin requested, you requested plugin %s\n", (*iter1).asCharArray());
                    SendFormattedTextResponse(requestID, pClientSocket, "Error: Invalid plugin requested, you requested plugin %s\n", (*iter1).asCharArray());
                    return;
                }

                // we have a valid index
                g_allowedWrappersMap.insert(*iWrapper);
            }
        }
        else if (IsToken(ppParam, "app="))
        {
            m_injectedAppName = *ppParam;
        }
        else if (IsToken(ppParam, "args="))
        {
            m_injectedAppArgs = *ppParam;
        }
    }

    // make sure an app name was specified
    if (m_injectedAppName.empty() == true)
    {
        Log(logERROR, "Application name not specified\n");
        SendTextResponse(requestID, "Error: Application name not specified", pClientSocket);
        return;
    }

    // if no wrappers were specified, then use them all
    if (g_allowedWrappersMap.empty() == true)
    {
        g_allowedWrappersMap = GetWrapperMap();
    }

    // fix the path
    gtASCIIString appName = m_injectedAppName.c_str();
    appName.replace("%20", " ");
    appName.replace("%22", "\"");
    appName.replace("%5C", "\\");
    appName.replace("%E2%80%93", "-");
    appName.replace("%26", "&");
    appName.replace("%27", "'");
    appName.replace("%60", "`");
    appName.replace("%E2%80%98", "`");
    m_injectedAppName = appName.asCharArray();

    gtASCIIString appArgs = m_injectedAppArgs.c_str();
    appArgs.replace("%22", "\"");
    appArgs.replace("%20", " ");
    appArgs.replace("%5C", "\\");
    appArgs.replace("%E2%80%93", "-");
    appArgs.replace("%26", "&");
    appArgs.replace("%27", "'");
    appArgs.replace("%60", "`");
    appArgs.replace("%E2%80%98", "`");
    m_injectedAppArgs = appArgs.asCharArray();

    if (WritePluginsToSharedMemoryAndLaunchApp() == true)
    {
        // loop up to 500 times while checking to see if a
        // wrapper name has been written into the shared memory from MicroDLL
        unsigned int uTimeout = 500;

        while (smGet("ActivePlugins", NULL, 0) == 0 && uTimeout > 0)
        {
            uTimeout--;
            osSleep(10);
        }

        if (uTimeout > 0)
        {
            SendHTMLResponse(requestID, "<html>OK</html>", pClientSocket);
        }
        else
        {
            Log(logWARNING, "The server has timed out while trying to receive the current active plugins\n");
            gtASCIIString strErrorResponse;
            strErrorResponse = "<html>The server is taking a while to respond. <p/>Either the application does not use one of the selected APIs or it takes a while to load.<p/><br/>";
            strErrorResponse.appendFormattedString("Please <a href='/page/index.html'>try to reconnect</a> if you expect it to continue or<br/> <a href='/%d/Kill'>click here to kill the process</a></html>", m_injectedAppID);
            SendHTMLResponse(requestID, strErrorResponse.asCharArray(), pClientSocket);
        }
    }
    else
    {
        Log(logERROR, "The plugins could not be written to shared memory or the application could not be launched\n");
        SendTextResponse(requestID, "Error, see log file for more details", pClientSocket);
    }

    return;
}
//--------------------------------------------------------------
/// 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;
}
示例#6
0
//--------------------------------------------------------------
/// Creates and then waits for the PLUGINS_TO_GPS_SEMAPHORE to be
/// signaled, then reads the responses in PLUGINS_TO_GPS shared
/// memory and sends them to the requester.
/// \param pData should be NULL (it is ignored though)
//--------------------------------------------------------------
void PluginResponseThread::WaitForPluginResponses(void* pData)
{
    PS_UNREFERENCED_PARAMETER(pData);

    //create a semaphore which allows putting at most MAX_SEM_COUNT response into SM;
    NamedSemaphore semaphore;
    semaphore.Create("PLUGINS_TO_GPS_SEMAPHORE");

    bool bEvent;

    for (;;)    // loop forever
    {
        bEvent = semaphore.Wait();

        if (bEvent == false)
        {
            Log(logERROR, "Failed to wait on an event (Error %d). Closing response thread.\n", osGetLastSystemError());
            smClose("PLUGINS_TO_GPS");
            semaphore.Close();
            return;
        }

        // the PLUGINS_TO_GPS_EVENT was signaled
        // retrieve and send the response
        if (smLockGet("PLUGINS_TO_GPS"))
        {
            // read data from shared memory
            CommunicationID requestID = 0;
            char pcMimeType[PS_MAX_PATH];

            // the response was signaled, read out one response
            if (bEvent == true)
            {
                requestID = 0;
                memset(pcMimeType, 0, PS_MAX_PATH);
                char* pResponse = NULL;
                unsigned long uResponseSize = 0;

                LARGE_INTEGER nPreSharedMemoryGetTime;
                OSWrappers::QueryPerformanceCounter(&nPreSharedMemoryGetTime);

                if (smGet("PLUGINS_TO_GPS", &requestID, sizeof(CommunicationID)) == sizeof(CommunicationID))
                {
                    // successfully got the requestID

                    // Get the socket associated with this requestID and remove the socket since we're now donw with it.
                    NetSocket* client_socket = ProcessTracker::Instance()->GetSocketFromHandle(requestID);
                    ProcessTracker::Instance()->RemoveSocketFromMap(requestID);

#ifdef CODEXL_GRAPHICS
#ifdef USE_GRAPHICS_SERVER_STATUS_RETURN_CODES
                    // We can remove this message from the DB as we no longer need to monitor it anymore
                    RequestsInFlightDatabase::Instance()->Remove(client_socket);
#endif
#endif
                    // now try to get the mime type
                    if (smGet("PLUGINS_TO_GPS", &pcMimeType, PS_MAX_PATH) > 0)
                    {
                        // successfully got the mime type

                        // get response size
                        while (uResponseSize == 0)
                        {
                            uResponseSize = smGet("PLUGINS_TO_GPS", NULL, 0);
                        }

                        try
                        {
                            pResponse = new char[uResponseSize];
                            memset(pResponse, 0, uResponseSize * sizeof(char));
                        }
                        catch (std::bad_alloc)
                        {
                            Log(logERROR, "Failed to allocate memory for response of size: %lu\n", uResponseSize);
                            pResponse = NULL;
                        }

                        if (pResponse != NULL)
                        {
                            // Read from shared memory
                            if (smGet("PLUGINS_TO_GPS", pResponse, uResponseSize) == 0)
                            {
                                Log(logERROR, "Failed to get response from sharedMemory.\n");
                                smReset("PLUGINS_TO_GPS");
                            }

#ifdef DEBUG_COMMS_PERFORMANCE
                            // Record the time now
                            CommandTiming* pTiming = CommandTimingManager::Instance()->HandleResponse((NetSocket*)requestID);

                            if (pTiming != NULL)
                            {
                                LARGE_INTEGER nPerformanceCount;
                                QueryPerformanceCounter(&nPerformanceCount);
                                pTiming->SetWebServerRoundTripEnd(nPerformanceCount);    // Must set this one before SetPreSharedMemoryGet
                                pTiming->SetPreSharedMemoryGet(nPreSharedMemoryGetTime);
                                pTiming->SetResponseSize(uResponseSize);
                            }

#endif

                            // Send the data back to the client
                            SendMimeResponse(requestID, pcMimeType, pResponse, uResponseSize, client_socket);

#ifdef DEBUG_COMMS_PERFORMANCE
                            CommandTimingManager::Instance()->IncrementServerLoadingCount(-1);
#endif

                            SAFE_DELETE_ARRAY(pResponse);
                        }
                        else
                        {
                            smReset("PLUGINS_TO_GPS");
                            SendMimeResponse(requestID, "plain/text", "Error: Failed to get response from shared memory\n", 49 * sizeof(char), client_socket);
                        }

                    }
                    else
                    {
                        smReset("PLUGINS_TO_GPS");
                        SendMimeResponse(requestID, "plain/text", "Error: Could not read mime type\n", 32 * sizeof(char), client_socket);
                    }
                }
                else
                {
                    // in this case, we don't know socket the communication was on, so we can't send any errors or even close the socket
                    // just have to let the client time out.
                    smReset("PLUGINS_TO_GPS");
                    Log(logERROR, "Failed to get requestID from sharedMemory.\n");
                }

            } // end while sm has data or no responses have been read

            smUnlockGet("PLUGINS_TO_GPS");

        }
        else
        {
            Log(logERROR, "LockGet Failed\n");
        }
    }
}