int CCBServer::HandleRequestDisconnect( Stream * /*stream*/ ) { CCBServerRequest *request = (CCBServerRequest *)daemonCore->GetDataPtr(); RemoveRequest( request ); return KEEP_STREAM; }
void CCBServer::RemoveTarget( CCBTarget *target ) { // hang up on all requests for this target HashTable<CCBID,CCBServerRequest *> *trequests; while( (trequests = target->getRequests()) ) { CCBServerRequest *request = NULL; trequests->startIterations(); if( trequests->iterate(request) ) { RemoveRequest( request ); // note that trequests may point to a deleted hash table // at this point, so do not reference it anymore } else { break; } } if( m_targets.remove(target->getCCBID()) != 0 ) { EXCEPT("CCB: failed to remove target ccbid=%lu, %s", target->getCCBID(), target->getSock()->peer_description()); } dprintf(D_FULLDEBUG,"CCB: unregistered target daemon %s with ccbid %lu\n", target->getSock()->peer_description(), target->getCCBID()); delete target; }
void CServerBrowser::Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo) { CServerEntry *pEntry = 0; if(Type == IServerBrowser::SET_MASTER_ADD) { if(m_ServerlistType != IServerBrowser::TYPE_INTERNET) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_FAV_ADD) { if(m_ServerlistType != IServerBrowser::TYPE_FAVORITES) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_RECENT) { if(m_ServerlistType != IServerBrowser::TYPE_RECENT) return; if(!Find(Addr)) { pEntry = Add(Addr); QueueRequest(pEntry); } } else if(Type == IServerBrowser::SET_TOKEN) { if(Token != m_CurrentToken) return; pEntry = Find(Addr); if(!pEntry) pEntry = Add(Addr); if(pEntry) { SetInfo(pEntry, *pInfo); if(m_ServerlistType == IServerBrowser::TYPE_LAN) pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-m_BroadcastTime)*1000/time_freq()), 999); else pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-pEntry->m_RequestTime)*1000/time_freq()), 999); RemoveRequest(pEntry); } } Sort(); }
NS_IMETHODIMP nsGeolocationRequest::Cancel() { NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED); // remove ourselves from the locators callback lists. mLocator->RemoveRequest(this); return NS_OK; }
//--------------------------------------------------------- /// SendResponse /// /// Sends the response either over sockets or shared memory /// /// \param requestID the requestID to send the response to /// \param cpsMimeType the mimetype to send the response as /// \param cpsResponse the response to send /// \param uResponseSize the size of the response being sent /// \param bStreaming indicates that the response it to a streaming request /// /// \return true if the response is 'sent' correctly; false otherwise //--------------------------------------------------------- bool SendResponse(CommunicationID requestID, const char* cpsMimeType, const char* cpsResponse, unsigned int uResponseSize, bool bStreaming) { // find out if this is a streaming response if (bStreaming) { Log(logTRACE, "Sending response over socket\n"); // this is a streaming response // use the socket for comms return SendMimeResponse(requestID, cpsMimeType, cpsResponse, uResponseSize); } // use Shared memory if this is not a streaming response if (smLockPut("PLUGINS_TO_GPS", sizeof(requestID) + ((unsigned long) strlen(cpsMimeType) * sizeof(const char)) + uResponseSize, 3) == false) { Log(logASSERT, "Not enough space in shared memory for response.\n"); return false; } NamedSemaphore semaphore; bool opened = semaphore.Open("PLUGINS_TO_GPS_SEMAPHORE"); if (opened) { if (semaphore.Signal() == false) { Log(logWARNING, "Failed to signal PLUGINS_TO_GPS_SEMAPHORE. Response may be lost. Error is %d, Previous count is 0\n", osGetLastSystemError()); } semaphore.Close(); } else { Log(logWARNING, "Failed to open PLUGINS_TO_GPS_SEMAPHORE. Response may be delayed.\n"); } bool bResult = (smPut("PLUGINS_TO_GPS", &requestID, sizeof(requestID)) && smPut("PLUGINS_TO_GPS", (void*)cpsMimeType, (unsigned long) strlen(cpsMimeType) * sizeof(const char)) && smPut("PLUGINS_TO_GPS", (void*)cpsResponse, uResponseSize)); smUnlockPut("PLUGINS_TO_GPS"); if (bResult == false) { Log(logASSERT, "Failed to put part of the response into shared memory\n"); } else { // remove the request RemoveRequest(requestID); } return bResult; }
void CCBServer::RequestFinished( CCBServerRequest *request, bool success, char const *error_msg ) { RequestReply( request->getSock(), success, error_msg, request->getRequestID(), request->getTargetCCBID() ); RemoveRequest( request ); }
void AddrInfoResolver::HandleLoop() { if (!requests_.empty()) { while (true) { auto resolved = resolved_.TryRecv(); if (!resolved) break; auto request = *resolved; HandleResolve(*request); RemoveRequest(request); } } }
NS_IMETHODIMP nsGeolocationRequest::Notify(nsITimer* aTimer) { // If we haven't gotten an answer from the geolocation // provider yet, cancel the request. Same logic as // ::Cancel, just a different error if (!mHasSentData) { NotifyError(nsIDOMGeoPositionError::TIMEOUT); // remove ourselves from the locator's callback lists. mLocator->RemoveRequest(this); } mTimeoutTimer = nsnull; return NS_OK; }
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; }
void MediaSystemResourceService::ReleaseResource( media::MediaSystemResourceManagerParent* aParent, uint32_t aId, MediaSystemResourceType aResourceType) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(aParent); if (mDestroyed) { return; } MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType)); if (!resource || resource->mResourceCount == 0) { // Resource does not exit return; } RemoveRequest(aParent, aId, aResourceType); UpdateRequests(aResourceType); }
//----------------------------------------------------------------------------- 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; }
NS_IMETHODIMP nsLoadGroup::Cancel(nsresult status) { NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); nsresult rv; PRUint32 count = mRequests.entryCount; nsAutoTArray<nsIRequest*, 8> requests; PL_DHashTableEnumerate(&mRequests, AppendRequestsToArray, static_cast<nsTArray<nsIRequest*> *>(&requests)); if (requests.Length() != count) { for (PRUint32 i = 0, len = requests.Length(); i < len; ++i) { NS_RELEASE(requests[i]); } return NS_ERROR_OUT_OF_MEMORY; } // set the load group status to our cancel status while we cancel // all our requests...once the cancel is done, we'll reset it... // mStatus = status; // Set the flag indicating that the loadgroup is being canceled... This // prevents any new channels from being added during the operation. // mIsCanceling = PR_TRUE; nsresult firstError = NS_OK; while (count > 0) { nsIRequest* request = requests.ElementAt(--count); NS_ASSERTION(request, "NULL request found in list."); RequestMapEntry *entry = static_cast<RequestMapEntry *> (PL_DHashTableOperate(&mRequests, request, PL_DHASH_LOOKUP)); if (PL_DHASH_ENTRY_IS_FREE(entry)) { // |request| was removed already NS_RELEASE(request); continue; } #if defined(PR_LOGGING) nsCAutoString nameStr; request->GetName(nameStr); LOG(("LOADGROUP [%x]: Canceling request %x %s.\n", this, request, nameStr.get())); #endif // // Remove the request from the load group... This may cause // the OnStopRequest notification to fire... // // XXX: What should the context be? // (void)RemoveRequest(request, nsnull, status); // Cancel the request... rv = request->Cancel(status); // Remember the first failure and return it... if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv; NS_RELEASE(request); } #if defined(DEBUG) NS_ASSERTION(mRequests.entryCount == 0, "Request list is not empty."); NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active."); #endif mStatus = NS_OK; mIsCanceling = PR_FALSE; return firstError; }
void CServerBrowser::Update() { int64 Timeout = time_freq(); int64 Now = time_get(); int Count; CServerEntry *pEntry, *pNext; // do server list requests if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) { NETADDR Addr; CNetChunk Packet; int i; m_NeedRefresh = 0; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); Packet.m_pData = SERVERBROWSE_GETLIST; for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { Addr = m_pMasterServer->GetAddr(i); if(!Addr.ip[0] && !Addr.ip[1] && !Addr.ip[2] && !Addr.ip[3]) continue; Packet.m_Address = Addr; m_pNetClient->Send(&Packet); } if(g_Config.m_Debug) dbg_msg("client", "requesting server list"); } // do timeouts pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pNext = pEntry->m_pNextReq; if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) { // timeout RemoveRequest(pEntry); m_NumRequests--; } pEntry = pNext; } // do timeouts pEntry = m_pFirstReqServer; Count = 0; while(1) { if(!pEntry) // no more entries break; // no more then 10 concurrent requests if(Count == g_Config.m_BrMaxRequests) break; if(pEntry->m_RequestTime == 0) RequestImpl(pEntry->m_Addr, pEntry); Count++; pEntry = pEntry->m_pNextReq; } // check if we need to resort // TODO: remove the str_comp if(m_Sorthash != SortHash() || str_comp(m_aFilterString, g_Config.m_BrFilterString) != 0 || str_comp(m_aFilterGametypeString, g_Config.m_BrFilterGametype) != 0) Sort(); }
void CServerBrowser::Update(bool ForceResort) { int64 Timeout = time_freq(); int64 Now = time_get(); int Count; CServerEntry *pEntry, *pNext; // do server list requests if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) { NETADDR Addr; CNetChunk Packet; int i; m_NeedRefresh = 0; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); Packet.m_pData = SERVERBROWSE_GETLIST; for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Addr = m_pMasterServer->GetAddr(i); Packet.m_Address = Addr; m_pNetClient->Send(&Packet); } if(g_Config.m_Debug) m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "requesting server list"); } // do timeouts pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pNext = pEntry->m_pNextReq; if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) { // timeout RemoveRequest(pEntry); } pEntry = pNext; } // do timeouts pEntry = m_pFirstReqServer; Count = 0; while(1) { if(!pEntry) // no more entries break; // no more then 10 concurrent requests if(Count == g_Config.m_BrMaxRequests) break; if(pEntry->m_RequestTime == 0) RequestImpl(pEntry->m_Addr, pEntry); Count++; pEntry = pEntry->m_pNextReq; } // check if we need to resort if(m_Sorthash != SortHash() || ForceResort) Sort(); }
NS_IMETHODIMP nsLoadGroup::Cancel(nsresult status) { MOZ_ASSERT(NS_IsMainThread()); NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code"); nsresult rv; uint32_t count = mRequests.EntryCount(); AutoTArray<nsIRequest*, 8> requests; if (!AppendRequestsToArray(&mRequests, &requests)) { return NS_ERROR_OUT_OF_MEMORY; } // set the load group status to our cancel status while we cancel // all our requests...once the cancel is done, we'll reset it... // mStatus = status; // Set the flag indicating that the loadgroup is being canceled... This // prevents any new channels from being added during the operation. // mIsCanceling = true; nsresult firstError = NS_OK; while (count > 0) { nsIRequest* request = requests.ElementAt(--count); NS_ASSERTION(request, "NULL request found in list."); if (!mRequests.Search(request)) { // |request| was removed already NS_RELEASE(request); continue; } if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) { nsAutoCString nameStr; request->GetName(nameStr); LOG(("LOADGROUP [%x]: Canceling request %x %s.\n", this, request, nameStr.get())); } // // Remove the request from the load group... This may cause // the OnStopRequest notification to fire... // // XXX: What should the context be? // (void)RemoveRequest(request, nullptr, status); // Cancel the request... rv = request->Cancel(status); // Remember the first failure and return it... if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv; NS_RELEASE(request); } #if defined(DEBUG) NS_ASSERTION(mRequests.EntryCount() == 0, "Request list is not empty."); NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active."); #endif mStatus = NS_OK; mIsCanceling = false; return firstError; }
HRESULT COSPBackgroundRequest::ProcessRequest(COSPGraph* pGraph) { COMMAND_ID cmd = RemoveRequest(); switch (cmd) { case RID_GRAPHCREATION: pGraph->CreateFilterGraph(&m_spGraphBuilder); break; case RID_GRAPHDESTRUCTION: break; case RID_ASYNCOPEN: { pGraph->DoNotifyGraphStateChange(sgsOpening); m_requestResult = pGraph->DoRender(m_spGraphBuilder, m_url.c_str()); if (SUCCEEDED(m_requestResult)) { pGraph->DoNotifyGraphStateChange(sgsOpen); } } break; case RID_CLOSE: { pGraph->DoNotifyGraphStateChange(sgsClosing); m_requestResult = m_requestResult = pGraph->InternelClose(); if (SUCCEEDED(m_requestResult)) { pGraph->DoNotifyGraphStateChange(sgsClose); } } break; case RID_PLAY: { pGraph->DoNotifyGraphStateChange(sgsRunning); m_requestResult = pGraph->InternelPlay(); if (SUCCEEDED(m_requestResult)) { pGraph->DoNotifyGraphStateChange(sgsRun); } } break; case RID_PAUSE: { pGraph->DoNotifyGraphStateChange(sgsPausing); m_requestResult = pGraph->InternelPause(); if (SUCCEEDED(m_requestResult)) { pGraph->DoNotifyGraphStateChange(sgsPause); } } break; case RID_STOP: { pGraph->DoNotifyGraphStateChange(sgsStopping); m_requestResult = pGraph->InternelStop(); if (SUCCEEDED(m_requestResult)) { pGraph->DoNotifyGraphStateChange(sgsStop); } } break; default: break; } return S_OK; }
void CServerBrowser::Update(bool ForceResort) { int64 Timeout = time_freq(); int64 Now = time_get(); int Count; CServerEntry *pEntry, *pNext; // do server list requests if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) { CNetChunk Packet; m_NeedRefresh = 0; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); Packet.m_pData = SERVERBROWSE_GETLIST; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Packet.m_Address = m_pMasterServer->GetAddr(i); m_pNetClient->Send(&Packet); } if(g_Config.m_Debug) m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "requesting server list"); } // do timeouts pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pNext = pEntry->m_pNextReq; if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) { // timeout RemoveRequest(pEntry); } pEntry = pNext; } // do timeouts pEntry = m_pFirstReqServer; Count = 0; while(1) { if(!pEntry) // no more entries break; // no more then 10 concurrent requests if(Count == g_Config.m_BrMaxRequests) break; if(pEntry->m_RequestTime == 0) RequestImpl(pEntry->m_Addr, pEntry); Count++; pEntry = pEntry->m_pNextReq; } // update favorite const NETADDR *pFavAddr = m_ServerBrowserFavorites.UpdateFavorites(); if(pFavAddr) { for(int i = 0; i < NUM_TYPES; ++i) { CServerEntry *pEntry = Find(i, *pFavAddr); if(pEntry) pEntry->m_Info.m_Favorite = 1; if(i == m_ActServerlistType) ForceResort = true; } } m_ServerBrowserFilter.Sort(m_aServerlist[m_ActServerlistType].m_ppServerlist, m_aServerlist[m_ActServerlistType].m_NumServers, ForceResort ? CServerBrowserFilter::RESORT_FLAG_FORCE : 0); }
void CCBServer::HandleRequestResultsMsg( CCBTarget *target ) { // Reply from target daemon about whether it succeeded in // connecting to the requested client. Sock *sock = target->getSock(); ClassAd msg; sock->decode(); if( !msg.initFromStream( *sock ) || !sock->end_of_message() ) { // disconnect dprintf(D_FULLDEBUG, "CCB: received disconnect from target daemon %s " "with ccbid %lu.\n", sock->peer_description(), target->getCCBID() ); RemoveTarget( target ); return; } int command = 0; if( msg.LookupInteger( ATTR_COMMAND, command ) && command == ALIVE ) { SendHeartbeatResponse( target ); return; } target->decPendingRequestResults(); bool success = false; MyString error_msg; MyString reqid_str; CCBID reqid; MyString connect_id; msg.LookupBool( ATTR_RESULT, success ); msg.LookupString( ATTR_ERROR_STRING, error_msg ); msg.LookupString( ATTR_REQUEST_ID, reqid_str ); msg.LookupString( ATTR_CLAIM_ID, connect_id ); if( !CCBIDFromString( reqid, reqid_str.Value() ) ) { MyString msg_str; msg.sPrint(msg_str); dprintf(D_ALWAYS, "CCB: received reply from target daemon %s with ccbid %lu " "without a valid request id: %s\n", sock->peer_description(), target->getCCBID(), msg_str.Value()); RemoveTarget( target ); return; } CCBServerRequest *request = GetRequest( reqid ); if( request && request->getSock()->readReady() ) { // Request socket must have just closed. To avoid noise in // logs when we fail to write to it, delete the request now. RemoveRequest( request ); request = NULL; } char const *request_desc = "(client which has gone away)"; if( request ) { request_desc = request->getSock()->peer_description(); } if( success ) { dprintf(D_FULLDEBUG,"CCB: received 'success' from target daemon %s " "with ccbid %lu for " "request %s from %s.\n", sock->peer_description(), target->getCCBID(), reqid_str.Value(), request_desc); } else { dprintf(D_FULLDEBUG,"CCB: received error from target daemon %s " "with ccbid %lu for " "request %s from %s: %s\n", sock->peer_description(), target->getCCBID(), reqid_str.Value(), request_desc, error_msg.Value()); } if( !request ) { if( success ) { // expected: the client has gone away; it got what it wanted return; } dprintf( D_FULLDEBUG, "CCB: client for request %s to target daemon %s with ccbid " "%lu disappeared before receiving error details.\n", reqid_str.Value(), sock->peer_description(), target->getCCBID()); return; } if( connect_id != request->getConnectID() ) { MyString msg_str; msg.sPrint(msg_str); dprintf( D_FULLDEBUG, "CCB: received wrong connect id (%s) from target daemon %s " "with ccbid %lu for " "request %s\n", connect_id.Value(), sock->peer_description(), target->getCCBID(), reqid_str.Value()); RemoveTarget( target ); return; } RequestFinished( request, success, error_msg.Value() ); }
void CServerBrowser::Set(const NETADDR &Addr, int SetType, int Token, const CServerInfo *pInfo) { CServerEntry *pEntry = 0; switch(SetType) { case SET_MASTER_ADD: { if(!(m_RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET)) return; if(!Find(IServerBrowser::TYPE_INTERNET, Addr)) { pEntry = Add(IServerBrowser::TYPE_INTERNET, Addr); QueueRequest(pEntry); } } break; case SET_FAV_ADD: { if(!(m_RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET)) return; if(!Find(IServerBrowser::TYPE_INTERNET, Addr)) { pEntry = Add(IServerBrowser::TYPE_INTERNET, Addr); QueueRequest(pEntry); } } break; case SET_TOKEN: { int Type; // internet entry if(m_RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET) { Type = IServerBrowser::TYPE_INTERNET; pEntry = Find(Type, Addr); if(pEntry && (pEntry->m_InfoState != CServerEntry::STATE_PENDING || Token != pEntry->m_CurrentToken)) pEntry = 0; } // lan entry if(!pEntry && (m_RefreshFlags&IServerBrowser::REFRESHFLAG_LAN) && m_BroadcastTime+time_freq() >= time_get()) { Type = IServerBrowser::TYPE_LAN; pEntry = Add(Type, Addr); } // set info if(pEntry) { SetInfo(Type, pEntry, *pInfo); if(Type == IServerBrowser::TYPE_LAN) pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-m_BroadcastTime)*1000/time_freq()), 999); else pEntry->m_Info.m_Latency = min(static_cast<int>((time_get()-pEntry->m_RequestTime)*1000/time_freq()), 999); RemoveRequest(pEntry); } } } if(pEntry) m_ServerBrowserFilter.Sort(m_aServerlist[m_ActServerlistType].m_ppServerlist, m_aServerlist[m_ActServerlistType].m_NumServers, CServerBrowserFilter::RESORT_FLAG_FORCE); }
void CServerBrowser::Update(bool ForceResort) { if(m_ServerdataLocked) return; int64 Timeout = time_freq(); int64 Now = time_get(); int Count; CServerEntry *pEntry, *pNext; // do server list requests if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) { NETADDR Addr; CNetChunk Packet; int i = 0; m_NeedRefresh = 0; m_MasterServerCount = -1; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETCOUNT); Packet.m_pData = SERVERBROWSE_GETCOUNT; for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Addr = m_pMasterServer->GetAddr(i); m_pMasterServer->SetCount(i, -1); Packet.m_Address = Addr; m_pNetClient->Send(&Packet); if(g_Config.m_Debug) { dbg_msg("client_srvbrowse", "count-request sent to %d", i); } } } // check if all server counts arrived if(m_MasterServerCount == -1) { m_MasterServerCount = 0; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; int Count = m_pMasterServer->GetCount(i); if(Count == -1) { /* ignore Server m_MasterServerCount = -1; return; // we don't have the required server information */ } else m_MasterServerCount += Count; } // request serverlist NETADDR Addr; CNetChunk Packet; mem_zero(&Packet, sizeof(Packet)); Packet.m_ClientID = -1; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); Packet.m_pData = SERVERBROWSE_GETLIST; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; Addr = m_pMasterServer->GetAddr(i); Packet.m_Address = Addr; m_pNetClient->Send(&Packet); } if(g_Config.m_Debug) { dbg_msg("client_srvbrowse", "servercount: %d, requesting server list", m_MasterServerCount); } m_LastPacketTick = 0; } else if(m_MasterServerCount > -1) { m_MasterServerCount = 0; for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) { if(!m_pMasterServer->IsValid(i)) continue; int Count = m_pMasterServer->GetCount(i); if(Count == -1) { /* ignore Server m_MasterServerCount = -1; return; // we don't have the required server information */ } else m_MasterServerCount += Count; } //if(g_Config.m_Debug) //{ // dbg_msg("client_srvbrowse", "ServerCount2: %d", m_MasterServerCount); //} } if(m_MasterServerCount > m_NumRequests + m_LastPacketTick) { ++m_LastPacketTick; return; // wait for more packets } pEntry = m_pFirstReqServer; Count = 0; while(1) { if(!pEntry) // no more entries break; if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) { pEntry = pEntry->m_pNextReq; continue; } // no more than 10 concurrent requests if(Count >= m_CurrentMaxRequests) break; if(pEntry->m_RequestTime == 0) { if (pEntry->m_Is64) RequestImpl64(pEntry->m_Addr, pEntry); else RequestImpl(pEntry->m_Addr, pEntry); } Count++; pEntry = pEntry->m_pNextReq; } // no more current server requests if(m_pFirstReqServer && Count == 0 && m_CurrentMaxRequests > 1) { // reset old ones pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pEntry->m_RequestTime = 0; pEntry = pEntry->m_pNextReq; } // update max-requests m_CurrentMaxRequests /= 2; if(m_CurrentMaxRequests <= 3) { m_CurrentMaxRequests = 1; m_NeedRefresh = false; } } else if(Count == 0 && m_CurrentMaxRequests == 1) // we reached the limit, just release all left requests. If a server sends us a packet, a new request will be added automatically, so we can delete all { pEntry = m_pFirstReqServer; while(1) { if(!pEntry) // no more entries break; pNext = pEntry->m_pNextReq; RemoveRequest(pEntry); // release request pEntry = pNext; } } // check if we need to resort if(m_Sorthash != SortHash() || ForceResort) Sort(); }
// Async Read callback // TODO: Should we add a 'hint' here to let the reader know that we are waiting for // a certain number of additional bytes? (to prevent unecessary loops)... void CDSISession::OnReceive(CTCPPacketReader& reader) { DSIHeader hdr; // Technically, we should probably be locking more in here, but we know that there is only one read thread, so // there will never be concurrent calls into this method... // Ongoing Reply... ///////////////////////////////////////////////////// // TODO: Should we time out after some period...? if (m_pOngoingReply) // Do we have a previously-incomplete reply block? { int err = kNoError; // Continue working on the incomplete read... int bytesRead = m_pOngoingReply->AppendResponse(reader); if (bytesRead > 0) // All OK { if (m_pOngoingReply->GetBytesRemaining()) // Not quite done yet... return; // Wait some more } else if(!bytesRead) { XAFP_LOG(XAFP_LOG_FLAG_ERROR, "DSI Protocol: TCPPacketReader returned zero bytes (expected: %d)", reader.GetBytesLeft()); } else { XAFP_LOG(XAFP_LOG_FLAG_ERROR, "DSI Protocol: Unable to read response - Error: %d", bytesRead); err = kTCPReceiveError; } // We either completed the reply block, or an error occurred. Signal waiting caller XAFP_LOG(XAFP_LOG_FLAG_DSI_PROTO, "DSI Protocol: Finished receiving multi-PDU read response (expected: %d, read: %d, pieces: %d)",m_pOngoingReply->GetTotalBytes(), m_pOngoingReply->GetTotalBytes() - m_pOngoingReply->GetBytesRemaining(), m_pOngoingReply->GetPieces()); m_pOngoingReply->Complete(err); m_pOngoingReply = NULL; return; } // 'Standard' Message Block(s) or beginning of a multi-PDU reply ///////////////////////////////////////////////////// while (reader.GetBytesLeft()) { // Read the message header int err = reader.Read(&hdr, sizeof(DSIHeader)); if (err < 0) { XAFP_LOG(XAFP_LOG_FLAG_ERROR, "DSI Protocol: Unable to read response header - Error: %d", err); // TODO: Nothing after this is going to work...figure that out return; } translate_header(hdr); // Change from network to host representation if (!hdr.flags) // This is a server-initiated request (as opposed to a reply to one of our requests) { switch (hdr.command) { case DSITickle: // Used by server for 'heartbeat' monitoring // TODO: Track time since last notice to detect timeouts XAFP_LOG_0(XAFP_LOG_FLAG_DSI_PROTO, "DSI Protocol: Received Server 'Tickle'. Sending reply..."); SendMessage(DSITickle, GetNewRequestId()); // Send keep-alive reply to server break; case DSIAttention: // Used by server to notify clients of events uint16_t attData; // TODO: Implement reconnect handler and heed delay specified by server in AFPUserBytes // TODO: Skip unexpected bytes, if present // TODO: Retrieve quantum size during login if (hdr.totalDataLength > 2) XAFP_LOG(XAFP_LOG_FLAG_ERROR,"DSI Protocol: ****Unexpected Size for Attention Data**** (%d bytes)", hdr.totalDataLength); reader.Read(&attData, sizeof(uint16_t)); // TODO: Where should we handle read() failures attData = ntohs(attData); // Handle byte-ordering XAFP_LOG(XAFP_LOG_FLAG_INFO, "DSI Protocol: Received Server Attention. Flags - Shutdown:%s, ServerCrash:%s, Message:%s, NoReconnect:%s", (kShutDownNotifyMask & attData) ? "yes" : "no", (kAllowReconnectMask & attData) ? "yes" : "no", (kMsgNotifyMask & attData) ? "yes" : "no", (kDisconnectNotifyMask & attData) ? "yes" : "no" ); // TODO: Retrieve the server message when there is one OnAttention(attData); break; case DSICloseSession: // Notification from server that the session will be closed. // Signal all waiting callers and tell them something happened XAFP_LOG_0(XAFP_LOG_FLAG_INFO, "DSI Protocol: Server Closed Session. Canceling all pending requests"); SignalAll(kDSISessionClosed); // TODO: Clean-up session (and possibly re-open?) break; default: XAFP_LOG(XAFP_LOG_FLAG_ERROR,"DSI Protocol: Received unknown request - command: %d", hdr.command); } } else // This is a reply to a previously-sent message { CDSIRequest* pRequest = NULL; switch (hdr.command) { case DSICloseSession: // This should not happen, but handle it anyway... XAFP_LOG_0(XAFP_LOG_FLAG_ERROR, "DSI Protocol: Unexpected reply message - CloseSession"); // Signal all waiting callers and tell them something happened SignalAll(kDSISessionClosed); // TODO: Clean-up session (should already be done...) break; case DSIOpenSession: case DSICommand: case DSIWrite: case DSIGetStatus: XAFP_LOG(XAFP_LOG_FLAG_DSI_PROTO, "DSI Protocol: Received Reply - Message:%s, RequestId:%d, result:%d", DSIProtoCommandToString(hdr.command), hdr.requestID, hdr.errorCode); // Find the request in our request map pRequest = RemoveRequest(hdr.requestID); if (pRequest) { // Tranfer data into caller-supplied buffer, if one was provided // If not, they did not expect any data back, just a result code // TODO: Make sure all data in the message is read/skipped before moving on, to prevent // clogging-up the pipe... pRequest->SaveResponse(reader, hdr.totalDataLength); if (pRequest->IsOngoing()) { m_pOngoingReply = pRequest; return; // Wait for more data before signaling requestor... } // Signal waiting requestor // NOTE: This object may self-destruct (or go out of scope) immediately. Do not use the reference again after calling 'Complete' pRequest->Complete(hdr.errorCode); } else { XAFP_LOG(XAFP_LOG_FLAG_ERROR, "DSI Protocol: Unexpected reply - RequestId: %d", hdr.requestID); // TODO: Need a better flush/skip/seek method void* p = malloc(hdr.totalDataLength); reader.Read(p, hdr.totalDataLength); free(p); } break; default: // TODO: Skip payload data and try to recover XAFP_LOG(XAFP_LOG_FLAG_ERROR, "DSI Protocol: Received unknown reply - command: %d, payload: %d", hdr.command, hdr.totalDataLength); } } } }