// =========================================================================== // 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 //+--------------------------------------------------------------------------- // // 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; }