Windows-Server-2003/inetcore/urlmon/download/packet.cxx

529 lines
13 KiB
C++
Raw Normal View History

2024-08-04 01:28:15 +02:00
// ===========================================================================
// File: PACKET.CXX
//
// Packet Manager for Code Downloader
// A Packet is a unit of work that takes time eg. trust verifcation of a piece
// setup of a piece or INF processing of one piece. To be able to have the
// client be responsive with UI and abort capabilty we need to split out work
// into as small units as possible and queue up these CDLPackets
// CDLPackets get run on a timer per thread.
#include <cdlpch.h>
//+---------------------------------------------------------------------------
//
// Function: CDL_PacketProcessProc
//
// Synopsis: the timer proc to process packet
//
// Arguments: [hWnd] --
// [WPARAM] --
// [idEvent] --
// [dwTime] --
//
// Returns:
//----------------------------------------------------------------------------
VOID CALLBACK CDL_PacketProcessProc(HWND hWnd, UINT msg, UINT_PTR idEvent, DWORD dwTime)
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CDL_PacketProcessProc",
"%#x, #x, %#x, %#x",
hWnd, msg, idEvent, dwTime
));
HRESULT hr = NO_ERROR;
CUrlMkTls tls(hr); // hr passed by reference!
Assert(SUCCEEDED(hr));
Assert(msg == WM_TIMER);
Assert(idEvent);
if (SUCCEEDED(hr)) { // if tls ctor passed above
Assert(tls->pCDLPacketMgr);
// give the packet mgr a time slice
// so a packet can be processed.
if (tls->pCDLPacketMgr)
hr = tls->pCDLPacketMgr->TimeSlice();
Assert(SUCCEEDED(hr));
}
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::CCDLPacketMgr
//----------------------------------------------------------------------------
CCDLPacketMgr::CCDLPacketMgr()
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CCDLPacketMgr::CCDLPacketMgr",
"this=%#x",
this
));
m_Timer = 0;
m_PacketList.RemoveAll();
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::~CCDLPacketMgr
//----------------------------------------------------------------------------
CCDLPacketMgr::~CCDLPacketMgr()
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CCDLPacketMgr::~CCDLPacketMgr",
"this=%#x",
this
));
if (m_Timer) {
KillTimer(NULL, m_Timer);
}
m_PacketList.RemoveAll();
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::AbortPackets(CDownload *pdl)
//
// Aborts all packets on the thread that are to do with pdl or
// its parent codedownload (pdl->GetCodeDownload())
//----------------------------------------------------------------------------
HRESULT
CCDLPacketMgr::AbortPackets(CDownload *pdl)
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacketMgr::AbortPackets",
"this=%#x, %#x",
this, pdl
));
HRESULT hr = S_FALSE; //assume none found to be killed
int iNumPkts;
LISTPOSITION pos;
if (!pdl) {
DEBUG_LEAVE(E_INVALIDARG);
return E_INVALIDARG;
}
iNumPkts = m_PacketList.GetCount();
pos = m_PacketList.GetHeadPosition();
for (int i=0; i < iNumPkts; i++) {
CCDLPacket *pPkt = m_PacketList.GetNext(pos); // pass ref!
if ( (pdl == pPkt->GetDownload()) ||
(pdl->GetCodeDownload() == pPkt->GetCodeDownload()) ) {
// AbortPackekts is only called from DoSetup. There should
// normally be no packets left to kill.
// Assert that this is a NOP.
UrlMkDebugOut((DEB_CODEDL, "CODE DL:AbortPackets URL:(%ws)\n", pdl->GetURL()));
Assert(pPkt == NULL);
Kill(pPkt);
hr = S_OK; // indicate killed atleast one
}
}
// here is no more packets in this thread that match CDownload* pdl
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::Kill(CCDLPacket *pPkt)
//
// kills packet (removes it from the thread list and deletes it
//----------------------------------------------------------------------------
HRESULT
CCDLPacketMgr::Kill(CCDLPacket *pPkt)
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacketMgr::Kill",
"this=%#x, %#x",
this, pPkt
));
LISTPOSITION pos = m_PacketList.Find(pPkt);
if(pos != NULL)
m_PacketList.RemoveAt(pos);
delete pPkt;
DEBUG_LEAVE(S_OK);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::Post(CCDLPacket *pPkt, ULONG pri)
//
// Adds the packet to the list. The packet will get processed
// on a subsequent timer in the order it appears on the list
// Also kicks off a timer if none exists already
//----------------------------------------------------------------------------
HRESULT
CCDLPacketMgr::Post(CCDLPacket *pPkt, ULONG pri)
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacketMgr::Post",
"this=%#x, %#x, %#x",
this, pPkt, pri
));
HRESULT hr = S_OK;
UINT_PTR idEvent = (UINT_PTR) this;
if (!m_Timer) {
m_Timer = SetTimer(NULL, idEvent,
PROCESS_PACKET_INTERVAL, CDL_PacketProcessProc);
if (!m_Timer) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
}
//BUGBUG: if we want priority classes then we soudl really have
// multiple lists! This will also affect the order if
// any sequencing is involved
if (pri == PACKET_PRIORITY_HIGH) {
m_PacketList.AddHead(pPkt);
} else {
m_PacketList.AddTail(pPkt);
}
Exit:
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacketMgr::TimeSlice()
//
// called from the timer proc.
// This is like a simple light weight thread machinery that executes/processes
// one packet per timer msg.
// Kills the timer if there are no other code downloads on thread.
//----------------------------------------------------------------------------
HRESULT
CCDLPacketMgr::TimeSlice()
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacketMgr::TimeSlice",
"this=%#x",
this
));
HRESULT hr = S_OK;
int iNumPkts = m_PacketList.GetCount();
if (!iNumPkts) {
// nothing to do. This may happen when processing the previous
// packet yields and so we re-enter the timer proc without
// ever completing the first.
DEBUG_LEAVE(hr);
return hr;
}
// have work to do!
CCDLPacket* pPkt = m_PacketList.RemoveHead();
Assert(pPkt);
hr = pPkt->Process();
// need to refresh this value as the procesing of current pkt
// may have posted other packets!
iNumPkts = m_PacketList.GetCount();
if (!iNumPkts &&
(CCodeDownload::AnyCodeDownloadsInThread() == S_FALSE)) {
if (m_Timer) {
KillTimer(NULL, m_Timer);
m_Timer = 0;
}
}
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacket::CCDLPacket(DWORD type, CDownload *pdl, DWORD param)
//
// twin constructors that take either CDownload or CCodeDownload obj
//----------------------------------------------------------------------------
CCDLPacket::CCDLPacket(DWORD type, CDownload *pdl, DWORD_PTR param)
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CCDLPacket::CCDLPacket",
"this=%#x, %#x, %#x, %#x",
this, type, pdl, param
));
m_signature = CPP_SIGNATURE;
m_type = type;
m_param = param;
Assert ((GETMSGTYPE(m_type) == MSG_CDOWNLOAD_OBJ));
Assert(pdl);
m_obj.pdl = pdl;
DEBUG_LEAVE(0);
};
//+---------------------------------------------------------------------------
//
// Function:CCDLPacket::CCDLPacket(DWORD type, CCodeDownload *pcdl,DWORD param)
//----------------------------------------------------------------------------
CCDLPacket::CCDLPacket(DWORD type, CCodeDownload *pcdl, DWORD_PTR param)
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CCDLPacket::CCDLPacket",
"this=%#x, %#x, %#x, %#x",
this, type, pcdl, param
));
m_signature = CPP_SIGNATURE;
m_type = type;
m_param = param;
Assert ((GETMSGTYPE(m_type) == MSG_CCODEDOWNLOAD_OBJ));
Assert(pcdl);
m_obj.pcdl = pcdl;
DEBUG_LEAVE(0);
};
//+---------------------------------------------------------------------------
//
// Function: CCDLPacket::~CCDLPacket()
//----------------------------------------------------------------------------
CCDLPacket::~CCDLPacket()
{
DEBUG_ENTER((DBG_DOWNLOAD,
None,
"CCDLPacket::~CCDLPacket",
"this=%#x",
this
));
m_signature = 0;
DEBUG_LEAVE(0);
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacket::Post(ULONG pri)
//
// just punts the posting work to the packet mgr.
//----------------------------------------------------------------------------
HRESULT
CCDLPacket::Post(ULONG pri)
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacket::Post",
"this=%#x, %#x",
this, pri
));
HRESULT hr = S_OK;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) { // if tls ctor failed above
goto Exit;
}
Assert(m_obj.pcdl);
Assert(tls->pCDLPacketMgr);
if (tls->pCDLPacketMgr)
hr = tls->pCDLPacketMgr->Post(this, pri);
Exit:
DEBUG_LEAVE(hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacket::Process()
//
// Called from the packet manager's TimeSlice to process packet.
//----------------------------------------------------------------------------
HRESULT
CCDLPacket::Process()
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacket::Process",
"this=%#x",
this
));
HRESULT hr = S_OK;
// Code Download messages, arrive in this order
// First a binding completes and needs to be trusted
// Next the trusted piece gets processed in ProcessPiece
// Next if the piece arrived was a CAB and had an INF in it
// the INF gets processed piece by piece
// initiating new downloads if necessary or extracting out of
// already arrived CAB
// After all pieces are processed and all bindings completed
// we enter the setup phase, setting up one piece per message.
// The reason we break it up into some many messages is to make the
// browser be as responsive during code download and installation as
// possible and keep the clouds animation smooth.
Assert(m_signature == CPP_SIGNATURE);
switch(m_type) {
case CODE_DOWNLOAD_TRUST_PIECE:
{
CDownload *pdl = m_obj.pdl;
if (pdl)
pdl->VerifyTrust();
}
break;
case CODE_DOWNLOAD_PROCESS_PIECE:
{
CDownload *pdl = m_obj.pdl;
if (pdl)
pdl->ProcessPiece();
}
break;
case CODE_DOWNLOAD_PROCESS_INF:
{
CCodeDownload *pcdl = m_obj.pcdl;
if (pcdl)
pcdl->ProcessInf( (CDownload *) m_param);
}
break;
case CODE_DOWNLOAD_SETUP:
{
CCodeDownload *pcdl = m_obj.pcdl;
if (pcdl)
pcdl->DoSetup();
}
break;
case CODE_DOWNLOAD_WAIT_FOR_EXE:
{
CCodeDownload *pcdl = m_obj.pcdl;
if (pcdl) {
hr = pcdl->SelfRegEXETimeout();
Assert(SUCCEEDED(hr));
}
}
break;
}
DEBUG_LEAVE(S_OK);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: CCDLPacket::Kill()
//----------------------------------------------------------------------------
HRESULT
CCDLPacket::Kill()
{
DEBUG_ENTER((DBG_DOWNLOAD,
Hresult,
"CCDLPacket::Kill",
"this=%#x",
this
));
HRESULT hr = S_OK;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) { // if tls ctor failed above
goto Exit;
}
Assert(tls->pCDLPacketMgr);
if (tls->pCDLPacketMgr)
hr = tls->pCDLPacketMgr->Kill(this);
Exit:
DEBUG_LEAVE(S_OK);
return S_OK;
}