Exemplo n.º 1
0
RequestMap bridge::InterfaceManager::generateDifferentialRequests(bool killSwitchActive) {
    RequestMap diff;

    for (auto &newRequest : *(interface->getRequestMap())) {
        if (previousRequests.find(newRequest.first) == previousRequests.end()) {
            logger.debug("Key '%s' not in the previous state. Adding.", newRequest.first.c_str());
            diff[newRequest.first] = newRequest.second;
        }
        else {
            if (previousRequests[newRequest.first].equals(newRequest.second)) {
                logger.debug("Key '%s' identical to the previous one. Skipping.", newRequest.first.c_str());
            } else {
                logger.debug("Key '%s' differs from previous state's one. Adding.", newRequest.first.c_str());
                diff[newRequest.first] = newRequest.second;
            }
        }
    }

    previousRequests.clear();

    for (auto req : *(interface->getRequestMap())) {
        previousRequests.insert(req);
    }

    if (killSwitchActive) {
        for (auto &r : *(interface->getRequestMap())) {
            if (r.second.isKillSwitchDependent()) {
                logger.debug("Removing key '%s' because kill switch is active.", r.first.c_str());
                diff.erase(r.first);
                previousRequests.erase(r.first);
            }
        }
    }
    return diff;
}
//-----------------------------------------------------------------------------
/// RemoveRequest
///
/// Provides a way for the Server to remove a request that it will not be
/// responding to. This is typical if the request is passed on to a plugin
/// in a different process which will be sending a response.
///
/// \param requestID a requestID returned by a call to CreateRequest
//-----------------------------------------------------------------------------
void RemoveRequest(CommunicationID requestID)
{
    // protect the maps from being changed by other threads using the mutex
    ScopeLock lock(s_mutex);

    RequestMap::iterator iter = g_requestMap.find(requestID);

    if (iter != g_requestMap.end())
    {
        HTTPRequestHeader* pRequest = iter->second;
        delete pRequest;
        g_requestMap.erase(iter);
    }
}
//-----------------------------------------------------------------------------
/// GetRequestBinary
///
/// This provides a method of accessing any binary data of a request. Requests
/// that have binary data as the primary means of communication will have the
/// string "binary" returned by GetRequestText(...); other commands may or may
/// not have associated binary data, as determined by the client.
///
/// \param requestID An ID for a particular request; the plugin will get this
///  id as a parameter to the ProcessRequest( ) function
///
/// \return pointer to the binary data that is associated with the request;
///  NULL if no binary data exists
//-----------------------------------------------------------------------------
void* GetRequestBinary(CommunicationID requestID)
{
    // protect the maps from being changed by other threads using the mutex
    ScopeLock lock(s_mutex);

    HTTPRequestHeader* pRequest = NULL;

    RequestMap::iterator iterRequest = g_requestMap.find(requestID);

    if (iterRequest != g_requestMap.end())
    {
        pRequest = iterRequest->second;
    }

    return pRequest;
}
CommunicationID CreateRequest(HTTPRequestHeader* pRequest, bool bReceivedOverSocket)
{
    // protect the maps from being changed by other threads using the mutex
    ScopeLock lock(s_mutex);

    CommunicationID requestID = CommunicationID(pRequest->GetClientSocket());

    pRequest->SetReceivedOverSocket(bReceivedOverSocket);

    if (g_requestMap.find(requestID) != g_requestMap.end())
    {
        Log(logWARNING, "RequestID %u already exists from request: %s\n", requestID, pRequest->GetUrl());
        // Remove the pre-existing request (required to cleanup memory).
        RemoveRequest(requestID);
    }

    g_requestMap[requestID] = pRequest;

    return requestID;
}
//-----------------------------------------------------------------------------
/// InitCommunication
///
/// This function only needs to be called by wrapper plugins. It sets up the
/// inter-process communication between the wrapper (which is in the app's
/// process space) and the PerfServer.
//-----------------------------------------------------------------------------
bool InitCommunication(const char* strShortDescription, ProcessRequest_type pProcessRequestCallback)
{
    unsigned long pid = osGetCurrentProcessId();
#ifdef _WIN32
    sprintf_s(g_strSharedMemoryName, PS_MAX_PATH, "%lu/%s", pid, strShortDescription);
#else
    // the '/' character can't be used as a filename in Linux, so just use the plugin name as the shared memory name
    // (ignore the process ID)
    sprintf_s(g_strSharedMemoryName, PS_MAX_PATH, "%lu %s", pid, strShortDescription);
#endif

    if (smCreate(g_strSharedMemoryName, 100, sizeof(HTTPRequestHeader)) == false)
    {
        Log(logERROR, "InitCommunication: Can't open or create SharedMemory for %s.\n", strShortDescription);
        return false;
    }

    if (smOpen("PLUGINS_TO_GPS") == false)
    {
        smClose(g_strSharedMemoryName);
        Log(logERROR, "InitCommunication: Can't open SharedMemory for PLUGINS_TO_GPS.\n");
        return false;
    }

    // store a local pointer to the ProcessRequest function
    g_processRequest = pProcessRequestCallback;

    if (g_processRequest == NULL)
    {
        smClose(g_strSharedMemoryName);
        Log(logERROR, "InitCommunication: ProcessRequest is NULL\n");
        return false;
    }

    // protect the maps from being changed by other threads using the mutex
    ScopeLock lock(s_mutex);

    g_requestMap.clear();
    g_pBufferedResponse = NULL;
    g_uBufferedResponseSize = 0;

    return true;
}
//-----------------------------------------------------------------------------
bool MakeResponse(CommunicationID requestID, Response** ppResponse)
{
    // protect the maps from being changed by other threads using the mutex
    ScopeLock lock(s_mutex);

    PsAssert(ppResponse != NULL);

    // first see if we already have this ID as a streaming response
    ResponseMap::iterator iterResponse = g_streamingResponseMap.find(requestID);

    if (iterResponse != g_streamingResponseMap.end())
    {
        *ppResponse = iterResponse->second;
        return true;
    }

    // otherwise we need to create a new response based on the original request
    // so get the request
    RequestMap::iterator iterRequest = g_requestMap.find(requestID);

    if (iterRequest == g_requestMap.end())
    {
        // the original request couldn't be found, so return failure
        return false;
    }

    // need to create a new response
    if (PsNew(*ppResponse) == false)
    {
        return false;
    }

    HTTPRequestHeader* pRequest = iterRequest->second;
    PsAssert(pRequest != NULL);

    if (pRequest->GetReceivedOverSocket() == true)
    {
        (*ppResponse)->client_socket = pRequest->GetClientSocket();
    }
    else
    {
#if defined (_WIN32)
        (*ppResponse)->client_socket = NetSocket::CreateFromDuplicate(pRequest->GetProtoInfo());
#else
        // create a new socket and connect to the streamSocket on the server
        (*ppResponse)->client_socket = NetSocket::Create();

        if ((*ppResponse)->client_socket != NULL)
        {
            osPortAddress portAddress((unsigned short)pRequest->GetPort());
            (*ppResponse)->client_socket->Connect(portAddress);
        }

#endif
    }

    if ((*ppResponse)->client_socket == NULL)
    {
        int Err = NetSocket::LastError();
        Log(logERROR, "Could not create socket: NetSocket failed with error: %ld\n", Err);
        return false;
    }

    // see if this should be added as a streaming response
    gtASCIIString strUrl(pRequest->GetUrl());
    int32 iStream = strUrl.find(STR_STREAM_TOKEN);

    if (iStream >= 0)
    {
        const char* pBuf = strUrl.asCharArray();
        const char* pRate = &pBuf[ iStream + strlen(STR_STREAM_TOKEN)];
        unsigned int uRate = 0;

        // try to get the rate from the command;
        if (sscanf_s(pRate, "%u", &uRate) < 1)
        {
            // default to max rate
            uRate = COMM_MAX_STREAM_RATE;
        }

        // set the response as streaming with the specified rate
        (*ppResponse)->m_bStreamingEnabled = true;
        (*ppResponse)->m_dwMaxStreamsPerSecond = uRate;
        g_streamingResponseMap[ requestID ] = *ppResponse;
    }
    else
    {
        // streaming requests need to be kept around so that
        // additional responses can be directed to the right place,
        // HOWEVER, non-streaming requests only get a single response
        // and we just created the response for it, so it is safe
        // to remove the request from the requestMap. This will
        // help keep communication quick as the number of incoming
        // requests grows.
        RemoveRequest(requestID);
    }

    return true;
}