⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connectionpoint.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
}


// GetBestIP
// gets HTTP URL and returns best IP address that can be used by device at this URL to call us back
static DWORD GetBestAddress(LPCSTR pszUrl, unsigned nPort, LPSTR pszAddress, int nSize)
{
    char                pszHost[INTERNET_MAX_HOST_NAME_LENGTH];
    URL_COMPONENTSA     urlComp = {0};
    DWORD               result;

    urlComp.dwStructSize = sizeof(URL_COMPONENTS);

    urlComp.lpszHostName = pszHost;
    urlComp.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;

    if(InternetCrackUrlA(pszUrl, 0, ICU_DECODE, &urlComp))
    {
        struct addrinfo hints = {0}, *ai = NULL;
        DWORD           dwIndex;

        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_DGRAM; 
        hints.ai_flags = AI_PASSIVE;

        if(ERROR_SUCCESS == (result = getaddrinfo(pszHost, "", &hints, &ai)) &&
           ERROR_SUCCESS == (result = GetBestInterfaceEx(ai->ai_addr, &dwIndex)))
        {
            PIP_ADAPTER_ADDRESSES   pAdapterAddresses = NULL;
            DWORD                   ulBufSize;

            // Find out size of returned buffer
            result = GetAdaptersAddresses(
                        ai->ai_addr->sa_family,
                        GAA_FLAG_SKIP_ANYCAST |GAA_FLAG_SKIP_DNS_SERVER,
                        NULL,
                        pAdapterAddresses,
                        &ulBufSize
                        );

            if(ulBufSize)
            {
                // Allocate sufficient Space
                pAdapterAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(ulBufSize));

                if(pAdapterAddresses !=NULL)
                {
                    // Get Adapter List
                    result = GetAdaptersAddresses(
                                ai->ai_addr->sa_family, 
                                GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST,
                                NULL,
                                pAdapterAddresses,
                                &ulBufSize
                                );

                    if(result == ERROR_SUCCESS)
                    {
                        for(PIP_ADAPTER_ADDRESSES pAdapterIter = pAdapterAddresses; pAdapterIter; pAdapterIter = pAdapterIter->Next)
                        {
                            if(ai->ai_addr->sa_family == AF_INET6 && pAdapterIter->Ipv6IfIndex != dwIndex ||
                               ai->ai_addr->sa_family == AF_INET && pAdapterIter->IfIndex != dwIndex)
                                continue;

                            PIP_ADAPTER_UNICAST_ADDRESS pUnicastAddress;

                            // found the adapter - get best address
                            for(pUnicastAddress = pAdapterIter->FirstUnicastAddress; pUnicastAddress; pUnicastAddress = pUnicastAddress->Next)
                            {
                                if(ai->ai_addr->sa_family == AF_INET)
                                {
                                    if(pUnicastAddress->Address.lpSockaddr->sa_family == AF_INET)
                                        // if device address is IPv4 use first IPv4 address for subscription callback
                                        break;
                                }
                                else
                                {
                                    ASSERT(ai->ai_addr->sa_family == AF_INET6);

                                    if(IN6_IS_ADDR_SITELOCAL(&((PSOCKADDR_IN6)ai->ai_addr)->sin6_addr))
                                        if(IN6_IS_ADDR_SITELOCAL(&((PSOCKADDR_IN6)pUnicastAddress->Address.lpSockaddr)->sin6_addr))
                                            // if device address is site-local use first site-local address for subscription callback
                                            break;
                                        else;
                                    else
                                        if(IN6_IS_ADDR_LINKLOCAL(&((PSOCKADDR_IN6)pUnicastAddress->Address.lpSockaddr)->sin6_addr))
                                            // if device address is other than site-local use first link-local address for subscription callback
                                            break;
                                }
                            }

                            if(pUnicastAddress)
                            {
                                wchar_t pwszAddress[256];

                                if(ai->ai_addr->sa_family == AF_INET6)
                                {
                                    ASSERT(pUnicastAddress->Address.lpSockaddr->sa_family == AF_INET6);

                                    ((PSOCKADDR_IN6)pUnicastAddress->Address.lpSockaddr)->sin6_port = htons(nPort);
                                    ((PSOCKADDR_IN6)pUnicastAddress->Address.lpSockaddr)->sin6_scope_id = 0;
                                }

                                if(ai->ai_addr->sa_family == AF_INET)
                                {
                                    ASSERT(pUnicastAddress->Address.lpSockaddr->sa_family == AF_INET);

                                    ((PSOCKADDR_IN)pUnicastAddress->Address.lpSockaddr)->sin_port = htons(nPort);
                                }

                                result = WSAAddressToString((LPSOCKADDR)pUnicastAddress->Address.lpSockaddr, pUnicastAddress->Address.iSockaddrLength, NULL, pwszAddress, &(ulBufSize = sizeof(pwszAddress)));

                                wcstombs(pszAddress, pwszAddress, nSize);
                            }
                            else
                            {
                                // couldn't find proper address - should never happen
                                result = ERROR_INVALID_DATA;
                            }

                            break;
                        }
                    }

                    free(pAdapterAddresses);
                }
                else
                {
                    result = ERROR_OUTOFMEMORY;
                }
            }
        }

        if(ai)
            freeaddrinfo(ai);
    }
    else
    {
        result = GetLastError();
    }

    return result;
}


// subscribe
HRESULT ConnectionPoint::sink::subscribe(LPCSTR pszEventsURL /*= NULL*/)
{
    assert(m_strSID.empty());

    HttpRequest request;
    char        pszCallback[INTERNET_MAX_URL_LENGTH];
    char        pszIP[256];
    DWORD       dw, result;

    if(pszEventsURL)
        m_strEventsURL = pszEventsURL;

    m_bInitialEventReceived = false;

    // format callback URL  
    if(ERROR_SUCCESS != (result = GetBestAddress(m_strEventsURL, upnp_config::port(), pszIP, sizeof(pszIP))))
        return HRESULT_FROM_WIN32(result);

    sprintf(pszCallback, "<http://%s/upnpisapi?%s>", pszIP, m_pchQueryString);

    // prepare SUBSCRIBE request
    if(!request.Open("SUBSCRIBE", m_strEventsURL, "HTTP/1.1"))
        return request.GetHresult();

    request.AddHeader("CALLBACK", pszCallback);
    request.AddHeader("NT", "upnp:event");
    request.AddHeader("TIMEOUT", "Second-1800"); // request subscription for 30 minutes

    // send request
    if(!request.Send())
        return request.GetHresult();

    if(HTTP_STATUS_OK != request.GetStatus())
        return E_FAIL; // TO DO: error

    char pszBuffer[50];

    if(!request.GetHeader("TIMEOUT", pszBuffer, &(dw = sizeof(pszBuffer)/sizeof(*pszBuffer))))
        return request.GetHresult();

    if(1 != sscanf(pszBuffer, "Second-%d", &m_dwTimeoutSeconds))
        return E_FAIL; // TO DO: error

    m_strSID.reserve(10);

    if(!request.GetHeader("SID", m_strSID.get_buffer(), &(dw = m_strSID.capacity())))
    {
        m_strSID.reserve(dw);

        if(!request.GetHeader("SID", m_strSID.get_buffer(), &(dw = m_strSID.capacity())))
            return request.GetHresult();
    }

    // leave 7% margin
    m_timerResubscribe.start(m_dwTimeoutSeconds * 930, this);

    return S_OK;
}


// resubscribe
HRESULT ConnectionPoint::sink::resubscribe()
{
    assert(!m_strSID.empty());

    HttpRequest request;

    // prepare SUBSCRIBE request
    if(!request.Open("SUBSCRIBE", m_strEventsURL, "HTTP/1.1"))
        return request.GetHresult();

    // add SID header
    request.AddHeader("SID", m_strSID);
    request.AddHeader("TIMEOUT", "Second-1800"); // request subscription for 30 minutes

    // send request
    if(!request.Send())
        return request.GetHresult();

    if(HTTP_STATUS_PRECOND_FAILED == request.GetStatus())
    {
        // looks like we lost our subscription
        m_strSID.resize(0);

        return subscribe();
    }
    
    if(HTTP_STATUS_OK != request.GetStatus())
        return E_FAIL; // TO DO: error

    DWORD   dw;
    char    pszBuffer[50];

    if(!request.GetHeader("TIMEOUT", pszBuffer, &(dw = sizeof(pszBuffer)/sizeof(*pszBuffer))))
        return request.GetHresult();

    if(1 != sscanf(pszBuffer, "Second-%d", &m_dwTimeoutSeconds))
        return E_FAIL; // TO DO: error

    // leave 7% margin
    m_timerResubscribe.start(m_dwTimeoutSeconds * 930, this);

    return S_OK;
}


// unsubscribe
HRESULT ConnectionPoint::sink::unsubscribe()
{
    if(!m_strSID.empty())
    {
        HttpRequest request;
        ce::string  strSID = m_strSID;

        m_timerResubscribe.stop();
        m_strSID.resize(0);

        // prepare UNSUBSCRIBE request
        if(!request.Open("UNSUBSCRIBE", m_strEventsURL, "HTTP/1.1"))
            return request.GetHresult();

        // add SID header
        request.AddHeader("SID", strSID);

        // send request
        if(!request.Send())
            return request.GetHresult();

        if(HTTP_STATUS_OK != request.GetStatus())
            return E_FAIL; // TO DO: error
    }

    assert(m_strSID.empty());

    return S_OK;
}


// ResubscribeTimerProc
DWORD WINAPI ConnectionPoint::sink::ResubscribeTimerProc(void* pvContext)
{
    sink* pThis = reinterpret_cast<sink*>(pvContext);

    if(FAILED(pThis->resubscribe()))
    {
        // "repair" subscription
        pThis->unsubscribe();

        if(FAILED(pThis->subscribe()))
            // notify application that service is not available
            pThis->byebye(pThis->m_strUSN);
    }

    return 0;
}


// event
void ConnectionPoint::sink::event(LPCWSTR pwszEventMessage, DWORD dwEventSEQ)
{
    if(dwEventSEQ == 0)
    {
        // initial event
        m_dwEventSEQ = 0;
        m_bInitialEventReceived = true;
    }
    else
    {
        m_dwEventSEQ++;

        // on overflow wrap to 1
        if(m_dwEventSEQ == 0)
            m_dwEventSEQ = 1;
    }

    // not consecutive event SEQ number -> we lost some events
    if(dwEventSEQ != m_dwEventSEQ || !m_bInitialEventReceived)
    {
        // "repair" subscription
        unsubscribe();

        if(FAILED(subscribe()))
            // notify application that service is not available
            byebye(m_strUSN);
    }
    else
        // parse event document
        if(m_pReader->valid())
        {
            (*m_pReader)->putContentHandler(this);

            HRESULT hr = (*m_pReader)->parse(ce::variant(pwszEventMessage));

            if(FAILED(hr))
                TraceTag(ttidError, "SAXXMLReader::parse returned error 0x%08x", hr);

            (*m_pReader)->putContentHandler(NULL);
        }
}


// alive
void ConnectionPoint::sink::alive(LPCWSTR pwszUSN, LPCWSTR pwszLocation, LPCWSTR pwszNLS, DWORD dwLifeTime)
{
    if(dwLifeTime)
    {
        m_timerAlive.stop();
        m_timerAlive.start(dwLifeTime * 1000, this);

        m_pCallback->AliveNotification(pwszUSN, pwszLocation, pwszNLS, dwLifeTime);
    }
}


// AliveTimerProc
DWORD WINAPI ConnectionPoint::sink::AliveTimerProc(VOID *pvContext)
{
    sink* pThis = reinterpret_cast<sink*>(pvContext);

    pThis->byebye(pThis->m_strUSN);

    return 0;
}


// byebye
void ConnectionPoint::sink::byebye(LPCWSTR pwszUSN)
{
    stop_timers();

    m_pCallback->ServiceInstanceDied(pwszUSN);
}


// startDocument
HRESULT STDMETHODCALLTYPE ConnectionPoint::sink::startDocument(void)
{
    SAXContentHandler::startDocument();

    m_bParsingVariable = false;
    m_bParsingProperty = false;

    return S_OK;
}


// startElement
HRESULT STDMETHODCALLTYPE ConnectionPoint::sink::startElement( 
    /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
    /* [in] */ int cchNamespaceUri,
    /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
    /* [in] */ int cchLocalName,
    /* [in] */ const wchar_t __RPC_FAR *pwchQName,
    /* [in] */ int cchQName,
    /* [in] */ ISAXAttributes __RPC_FAR *pAttributes)
{
    static wchar_t* pwszPropertyElement = 
        L"<urn:schemas-upnp-org:event-1-0>"
        L"<propertyset>"
        L"<urn:schemas-upnp-org:event-1-0>"
        L"<property>";

    SAXContentHandler::startElement(pwchNamespaceUri, cchNamespaceUri, pwchLocalName, cchLocalName, pwchQName, cchQName, pAttributes);

    if(m_bParsingProperty)
    {
        m_strName.assign(pwchLocalName, cchLocalName);
        m_strValue.resize(0);

        m_bParsingVariable = true;
        m_bParsingProperty = false;
    }

    if(pwszPropertyElement == m_strFullElementName)
    {
        assert(!m_bParsingVariable);

        m_bParsingProperty = true;
    }

    return S_OK;
}


// endElement
HRESULT STDMETHODCALLTYPE ConnectionPoint::sink::endElement( 
    /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
    /* [in] */ int cchNamespaceUri,
    /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
    /* [in] */ int cchLocalName,
    /* [in] */ const wchar_t __RPC_FAR *pwchQName,
    /* [in] */ int cchQName)
{
    if(m_bParsingVariable)
    {
        assert(!m_bParsingProperty);
        assert(m_strName.size());

        m_bParsingVariable = false;

        m_strValue.trim(L"\n\r\t ");

        m_pCallback->StateVariableChanged(m_strName, m_strValue);
    }

    return SAXContentHandler::endElement(pwchNamespaceUri, cchNamespaceUri, pwchLocalName, cchLocalName, pwchQName, cchQName);
}


// characters
HRESULT STDMETHODCALLTYPE ConnectionPoint::sink::characters( 
    /* [in] */ const wchar_t __RPC_FAR *pwchChars,
    /* [in] */ int cchChars)
{
    if(m_bParsingVariable)
        m_strValue.append(pwchChars, cchChars);

    return S_OK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -