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

📄 hxnetapi.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
STDMETHODIMP HXTCPSocket::Read(UINT16 uSize)
{
    HX_RESULT	theErr	= HXR_OK;
    HX_RESULT	lResult = HXR_OK;

    if (m_bReadPending)
    {
	return HXR_UNEXPECTED;
    }

    m_bReadPending  = TRUE;
    m_nRequired	    = uSize;

    m_pMutex->Lock();
    theErr  = DoRead();
    m_pMutex->Unlock();
    lResult = ConvertNetworkError(theErr);

    return lResult;
}

STDMETHODIMP HXTCPSocket::Write(IHXBuffer* pBuffer)
{
    HX_RESULT	theErr	= HXR_OK;
    HX_RESULT	lResult = HXR_OK;

#ifdef _MACINTOSH
	if (m_pInterruptSafeMacWriteQueue)
		m_pInterruptSafeMacWriteQueue->AddTail(pBuffer); // AddRef called inside
#else
	pBuffer->AddRef();
	m_PendingWriteBuffers.AddTail((void*) pBuffer);
    /* Transfer pending buffers to TCP send queue */
    TransferBuffers();
#endif

	m_pMutex->Lock();
    theErr = DoWrite();
    m_pMutex->Unlock();
    lResult = ConvertNetworkError(theErr);

    return lResult;
}

STDMETHODIMP HXTCPSocket::WantWrite()
{
    if (mSendTCP->GetQueuedItemCount() == 0)
    {
	m_pTCPResponse->WriteReady(HXR_OK);
    }
    else
    {
	m_bWantWritePending = TRUE;
    }

    return HXR_OK;
}

STDMETHODIMP HXTCPSocket::GetLocalAddress(ULONG32& lAddress)
{
    return HXR_NOTIMPL;
}

STDMETHODIMP HXTCPSocket::GetForeignAddress(ULONG32& lAddress)
{
    if(m_bConnected && m_lForeignAddress)
    {
	lAddress = m_lForeignAddress;
	return HXR_OK;
    }
    return HXR_FAIL;
}

STDMETHODIMP HXTCPSocket::GetLocalPort(UINT16& port)
{
    return HXR_NOTIMPL;
}

STDMETHODIMP HXTCPSocket::GetForeignPort(UINT16& port)
{
    if(m_bConnected)
    {
	port = m_nForeignPort;
	return HXR_OK;
    }
    return HXR_FAIL;
}

// the tcp socket will still need to be inited
STDMETHODIMP
HXTCPSocket::AcceptConnection(conn* pNewConn)
{
    HX_ASSERT(!m_bConnected);
    HX_ASSERT(!m_bInitComplete);
    HX_ASSERT(m_pCtrl == NULL);
    m_pCtrl = pNewConn;
    m_pCtrl->AddRef();
    m_pCtrl->nonblocking();

    if ( m_pCallback )
    {
	HX_DELETE(m_pCallback);
    }
    m_pCallback = new TCPSocketCallback;
    if ( !m_pCallback )
    {
	return HXR_OUTOFMEMORY;
    }
    m_pCallback->m_pContext = this;
    m_pCtrl->set_callback(m_pCallback);
    m_lForeignAddress = DwToHost(m_pCtrl->get_addr());

    m_bInitComplete = TRUE;
    m_bConnected = TRUE;

    return HXR_OK;
}

HX_RESULT
HXTCPSocket::DoRead()
{
#ifdef _MACINTOSH
	if (m_bInDoRead)
	{
		return HXR_OK; // whatever needs to be done will be done by the caller that's already here.

		// xxxbobclark the m_bInDoRead flag is hacked around calling ReadDone(), because
		//             ReadDone() may call Read() which in turn calls us here, and we do
		//             not want to bail out in that instance. (Otherwise we only remove
		//             one packet at a time, which, given the scheduler granularity and
		//             high bit rates, implies that our bandwidth would be too low.)
	}
#endif
	m_bInDoRead = TRUE;

    HX_RESULT theErr = HXR_OK;
    // check how much room we have in TCP receive queue
    UINT16 count = mReceiveTCP->GetMaxAvailableElements();

    if (count > 0)
    {
#if !defined(THREADS_SUPPORTED) && !defined(_UNIX_THREADED_NETWORK_IO)
	UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);

	if (ulBytesToRead > 0)
	{
	    if ((UINT32)count > ulBytesToRead)
	    {
		count = (UINT16)ulBytesToRead;
	    }

	    // attempt to read data from TCP link
	    theErr = m_pCtrl->read(m_pBuffer, &count);
	    if (!theErr && count > 0)
	    {
		conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
		mReceiveTCP->EnQueue(m_pBuffer, count);
	    }
	    else if (theErr)
	    {
		theErr = ConvertNetworkError(theErr);
	    }
	}
#elif defined(_UNIX_THREADED_NETWORK_IO)
        //XXXgfw duplicated code. Clean this up...
        if( ReadNetworkThreadingPref((IUnknown*)m_pContext) )
        {
            // in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
            // attempt to read data from TCP link
            theErr = m_pCtrl->read(m_pBuffer, &count);
            if (!theErr && count > 0)
            {
                mReceiveTCP->EnQueue(m_pBuffer, count);
            }
            else if (theErr)
            {
                theErr = ConvertNetworkError(theErr);
            }
        }
        else
        {
            UINT32 ulBytesToRead = conn::bytes_to_preparetcpread(m_pCtrl);

            if (ulBytesToRead > 0)
            {
                if ((UINT32)count > ulBytesToRead)
                {
                    count = (UINT16)ulBytesToRead;
                }

                // attempt to read data from TCP link
                theErr = m_pCtrl->read(m_pBuffer, &count);
                if (!theErr && count > 0)
                {
                    conn::bytes_to_actualtcpread(m_pCtrl, (UINT32)count);
                    mReceiveTCP->EnQueue(m_pBuffer, count);
                }
                else if (theErr)
                {
                    theErr = ConvertNetworkError(theErr);
                }
            }

        }
#else
	// in THREADS_SUPPORTED mode, this will be taken care by the thrdconn.cpp
	// attempt to read data from TCP link
	theErr = m_pCtrl->read(m_pBuffer, &count);
	if (!theErr && count > 0)
	{
	    mReceiveTCP->EnQueue(m_pBuffer, count);
	}
	else if (theErr)
	{
	    theErr = ConvertNetworkError(theErr);
	}
#endif /* !THREADS_SUPPORTED */
    }

    count = mReceiveTCP->GetQueuedItemCount();
    if (m_bReadPending && count > 0)
    {
	/* If we are at interrupt time and the response object is not interrupt safe,
	 * schedule a callback to return back the data
	 */
	if (!IsSafe())
	{
		m_bInDoRead = FALSE;
	    return HXR_OK;
	}

	m_bReadPending = FALSE;
	if (m_nRequired < count)
	{
	    // XXXAAK -- UINT32 down to UINT16 - possible truncation???
	    count = (UINT16)m_nRequired;
	}

	CHXBuffer* pBuffer = new CHXBuffer;
	pBuffer->AddRef();
	mReceiveTCP->DeQueue(m_pBuffer, count);
	pBuffer->Set((UCHAR*) m_pBuffer, count);

	m_bInDoRead = FALSE;
	theErr = m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
	m_bInDoRead = TRUE;

	pBuffer->Release();

	/* mask any kind of errors */
        // Huh??? Don't mask OUTOFMEMORY errors!
        if( theErr != HXR_OUTOFMEMORY )
        {
	    theErr = HXR_OK;
        }
    }

    if (theErr && m_bReadPending)
    {
	/* If we are at interrupt time and the response object is not interrupt safe,
	 * schedule a callback to return back the data
	 */
	if (!IsSafe())
	{
		m_bInDoRead = FALSE;
	    return HXR_OK;
	}

#ifdef _MACINTOSH
	if (m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_READ_DONE_COMMAND, m_pScheduler, 0, theErr))
	{
	    m_bReadPending = FALSE;
    	    m_bInDoRead = FALSE;
	    return HXR_OK;
	}
	else
	{
	    // failed to schedule a callback, notify the responser with error directly
	    m_bReadPending = FALSE;
	    m_pTCPResponse->ReadDone(theErr, NULL);
	}
#else
	m_bReadPending = FALSE;
	m_pTCPResponse->ReadDone(theErr, NULL);
#endif
    }

    if (!theErr		    &&
	m_bReadPending	    &&
	m_pSchedulerReadCallback)
	{
	    m_pSchedulerReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
    }

 	m_bInDoRead = FALSE;
    return theErr;
}

HX_RESULT
HXTCPSocket::DoWrite()
{
    HX_RESULT theErr = HXR_OK;

    if (m_bInWrite) return HXR_OK;
    m_bInWrite = TRUE;

#ifdef _MACINTOSH
	if (m_pInterruptSafeMacWriteQueue)
		m_pInterruptSafeMacWriteQueue->TransferToSimpleList(m_PendingWriteBuffers);
	TransferBuffers(); // PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
#endif

    // check how data we have in TCP send queue
    UINT16 count    = mSendTCP->GetQueuedItemCount();
    UINT16 actual   = count;

    if(count > 0)
    {
	mSendTCP->DeQueue(m_pBuffer,count);
	theErr = m_pCtrl->write(m_pBuffer, &actual);
    }

    switch(theErr)
    {
	case HXR_AT_INTERRUPT:
	case HXR_WOULD_BLOCK:
	case HXR_OK:
	    // enqueue the data that was not sent
	    if(actual != count)
	    {
		mSendTCP->EnQueue(m_pBuffer + actual, count - actual);
	    }

	    // mask out these errors
	    theErr = HXR_OK;
	    break;
	default:
	    theErr = ConvertNetworkError(theErr);
	    break;
    }

    if (!theErr && m_bWantWritePending && mSendTCP->GetQueuedItemCount() == 0)
    {
	m_bWantWritePending = FALSE;
	m_pTCPResponse->WriteReady(HXR_OK);
    }

#ifndef _MACINTOSH
	// m_PendingWriteBuffers will always be empty due to the full buffer transfer at the top of this routine.
	// see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
    if (!theErr && m_PendingWriteBuffers.GetCount()  > 0)
    {
	TransferBuffers();
    }
#endif

    if (!theErr &&
	((mSendTCP && mSendTCP->GetQueuedItemCount() > 0) ||
	m_PendingWriteBuffers.GetCount() > 0)) // see PENDING_BUFFERS_ARE_EMPTIED_AT_START_OF_DO_WRITE
    {
	if (m_pSchedulerWriteCallback)
	{
	    m_pSchedulerWriteCallback->ScheduleCallback(TCP_WRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
	}
    }

    if (m_bWriteFlushPending &&
	((mSendTCP->GetQueuedItemCount() == 0 &&
	 m_PendingWriteBuffers.GetCount() == 0)	||
	 theErr))
    {
	m_bWriteFlushPending	= FALSE;
	Release();
    }
    else if (!theErr && !m_bWriteFlushPending &&
	(mSendTCP->GetQueuedItemCount() > 0 || m_PendingWriteBuffers.GetCount() > 0))
    {
	m_bWriteFlushPending	= TRUE;
	AddRef();
    }

    m_bInWrite = FALSE;
    return theErr;
}

/* If we are at interrupt time and the response object is not interrupt safe,
 * schedule a callback to return back the data
 */
BOOL
HXTCPSocket::IsSafe()
{
    if (m_pInterruptState && m_pInterruptState->AtInterruptTime() &&
	(!m_pResponseInterruptSafe ||
	 !m_pResponseInterruptSafe->IsInterruptSafe()))
    {
	if (m_pNonInterruptReadCallback)
	{
	    m_pNonInterruptReadCallback->ScheduleCallback(TCP_READ_COMMAND, m_pScheduler, 0);
	}

	return FALSE;
    }

    return TRUE;
}


void
HXTCPSocket::ConnectDone(BOOL bResult)
{
    AddRef();
    if (bResult == TRUE)
    {
	m_bConnected = TRUE;
	//XXX need to set m_lForeignAddr here
	//XXXJR hack!
	m_lForeignAddress = DwToHost(m_pCtrl->get_addr());
	m_pTCPResponse->ConnectDone(HXR_OK);
    }
    else
    {
#ifdef _MACINTOSH
	if (!(m_pMacCommandCallback && m_pMacCommandCallback->ScheduleCallback(TCP_CONNECT_DONE_COMMAND, m_pScheduler, 0, HXR_NET_CONNECT)))
	{
		//note: only happens when there's a problem (e.g. macleod 1/2 server problem)
		m_pTCPResponse->ConnectDone(HXR_NET_CONNECT); // couldn't use the delayed callback... take our chances.
	}
#else
	m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
#endif
    }
    Release();
}

void
HXTCPSocket::CloseDone()
{
    m_pTCPResponse->Closed(HXR_OK);
}

void
HXTCPSocket::DNSDone(BOOL bSuccess)
{
    AddRef();
    if (!bSuccess)
    {
	m_pTCPResponse->ConnectDone(HXR_DNR);
    }
    Release();
}

void
HXTCPSocket::TransferBuffers()
{
    IHXBuffer* pBuffer = 0;

    while (m_PendingWriteBuffers.GetCount() > 0)
    {
	pBuffer = (IHXBuffer*) m_PendingWriteBuffers.GetHead();
	if ((UINT16) pBuffer->GetSize() < mSendTCP->GetMaxAvailableElements())
	{
	    mSendTCP->EnQueue(	pBuffer->GetBuffer(),
				(UINT16) pBuffer->GetSize());
	    pBuffer->Release();
	    m_PendingWriteBuffers.RemoveHead();
	}
	else
	{
	    break;
	}
    }
}

STDMETHODIMP
HXTCPSocket::SetOption(HX_SOCKET_OPTION option, UINT32 ulValue)
{
    HX_RESULT res = HXR_OK;

    switch(option)
    {
    case HX_SOCKOPT_REUSE_ADDR:
	m_bReuseAddr = (BOOL)ulValue;
    break;
    case HX_SOCKOPT_REUSE_PORT:
	m_bReusePort = (BOOL)ulValue;
    break;
    case HX_SOCKOPT_MULTICAST_IF:
	res = HXR_UNEXPECTED;
    break;
    default:
	HX_ASSERT(!"I don't know this option");
	res = HXR_FAIL;
    }

    return res;
}

STDMETHODIMP
HXTCPSocket::SetSecure(BOOL bSecure)
{
    HX_RESULT res = HXR_OK;

    m_bSecureSocket = bSecure;

    return res;
}

STDMETHODIMP HXTCPSocket::HandleCallback(INT32 theCommand, HX_RESULT theError)
{
    HX_RESULT theErr = HXR_OK;
    if (!m_bInDestructor)
    {
	AddRef();
	m_pMutex->Lock();
	if (!m_bInDestructor)
	{
		switch(theCommand)
		{
			case TCP_READ_COMMAND:
			    theErr = DoRead();
			    break;

			case TCP_WRITE_COMMAND:
			    DoWrite(); // protected from re-entry by m_bInWrite
			    break;

			case TCP_READ_DONE_COMMAND:
		    	m_bReadPending = FALSE;
				m_pTCPResponse->ReadDone(theError, NULL);
			    break;

			case TCP_CONNECT_DONE_COMMAND:

⌨️ 快捷键说明

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