static void CheckNewClient(__pmFdSet * fdset, int rfd, int family) { ClientInfo *cp; if (__pmFD_ISSET(rfd, fdset)) { if ((cp = AcceptNewClient(rfd)) == NULL) /* failed to negotiate, already cleaned up */ return; /* establish a new connection to pmcd */ if ((cp->pmcd_fd = __pmAuxConnectPMCDPort(cp->pmcd_hostname, cp->pmcd_port)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " oops!\n" "__pmAuxConnectPMCDPort(%s,%d) failed: %s\n", cp->pmcd_hostname, cp->pmcd_port, pmErrStr(-oserror())); #endif CleanupClient(cp, -oserror()); } else { if (cp->pmcd_fd > maxSockFd) maxSockFd = cp->pmcd_fd; __pmFD_SET(cp->pmcd_fd, &sockFds); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " fd=%d\n", cp->pmcd_fd); #endif } } }
void CClientMgr::Run() { idmgr_run(m_IDPool); AcceptNewClient(); ProcessAllClient(); CheckAndRemove(); }
bool CUploadQueue::AcceptNewClient(bool addOnNextConnect) { uint32 curUploadSlots = (uint32)uploadinglist.GetCount(); //We allow ONE extra slot to be created to accommodate lowID users. //This is because we skip these users when it was actually their turn //to get an upload slot.. if(addOnNextConnect && curUploadSlots > 0) curUploadSlots--; return AcceptNewClient(curUploadSlots); }
/** * Add a client to the waiting queue for uploads. * * @param client address of the client that should be added to the waiting queue * * @param bIgnoreTimelimit don't check time limit to possibly ban the client. */ void CUploadQueue::AddClientToQueue(CUpDownClient* client, bool bIgnoreTimelimit) { //This is to keep users from abusing the limits we put on lowID callbacks. //1)Check if we are connected to any network and that we are a lowID. //(Although this check shouldn't matter as they wouldn't have found us.. // But, maybe I'm missing something, so it's best to check as a precaution.) //2)Check if the user is connected to Kad. We do allow all Kad Callbacks. //3)Check if the user is in our download list or a friend.. //We give these users a special pass as they are helping us.. //4)Are we connected to a server? If we are, is the user on the same server? //TCP lowID callbacks are also allowed.. //5)If the queue is very short, allow anyone in as we want to make sure //our upload is always used. if (theApp.IsConnected() && theApp.IsFirewalled() && !client->GetKadPort() && client->GetDownloadState() == DS_NONE && !client->IsFriend() && theApp.serverconnect && !theApp.serverconnect->IsLocalServer(client->GetServerIP(),client->GetServerPort()) && GetWaitingUserCount() > 50) return; client->AddAskedCount(); client->SetLastUpRequest(); if (!bIgnoreTimelimit) client->AddRequestCount(client->GetUploadFileID()); if (client->IsBanned()) return; uint16 cSameIP = 0; // check for double POSITION pos1, pos2; for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;) { waitinglist.GetNext(pos1); CUpDownClient* cur_client= waitinglist.GetAt(pos2); if (cur_client == client) { if (client->m_bAddNextConnect && AcceptNewClient(client->m_bAddNextConnect)) { //Special care is given to lowID clients that missed their upload slot //due to the saving bandwidth on callbacks. if(thePrefs.GetLogUlDlEvents()) AddDebugLogLine(true, _T("Adding ****lowid when reconnecting. Client: %s"), client->DbgGetClientInfo()); client->m_bAddNextConnect = false; RemoveFromWaitingQueue(client, true); // statistic values // TODO: Maybe we should change this to count each request for a file only once and ignore reasks CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID()); if (reqfile) reqfile->statistic.AddRequest(); AddUpNextClient(_T("Adding ****lowid when reconnecting."), client); return; } client->SendRankingInfo(); theApp.emuledlg->transferwnd->queuelistctrl.RefreshClient(client); return; } else if ( client->Compare(cur_client) ) { theApp.clientlist->AddTrackClient(client); // in any case keep track of this client // another client with same ip:port or hash // this happens only in rare cases, because same userhash / ip:ports are assigned to the right client on connecting in most cases if (cur_client->credits != NULL && cur_client->credits->GetCurrentIdentState(cur_client->GetIP()) == IS_IDENTIFIED) { //cur_client has a valid secure hash, don't remove him if (thePrefs.GetVerbose()) AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName(), cur_client->GetUserName(), client->GetUserName()); return; } if (client->credits != NULL && client->credits->GetCurrentIdentState(client->GetIP()) == IS_IDENTIFIED) { //client has a valid secure hash, add him remove other one if (thePrefs.GetVerbose()) AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName(), cur_client->GetUserName(), cur_client->GetUserName()); RemoveFromWaitingQueue(pos2,true); if (!cur_client->socket) { if(cur_client->Disconnected(_T("AddClientToQueue - same userhash 1"))) delete cur_client; } } else { // remove both since we do not know who the bad one is if (thePrefs.GetVerbose()) AddDebugLogLine(false, GetResString(IDS_SAMEUSERHASH), client->GetUserName() ,cur_client->GetUserName(), _T("Both")); RemoveFromWaitingQueue(pos2,true); if (!cur_client->socket) { if(cur_client->Disconnected(_T("AddClientToQueue - same userhash 2"))) delete cur_client; } return; } } else if (client->GetIP() == cur_client->GetIP()) { // same IP, different port, different userhash cSameIP++; } } if (cSameIP >= 3) { // do not accept more than 3 clients from the same IP if (thePrefs.GetVerbose()) DEBUG_ONLY( AddDebugLogLine(false,_T("%s's (%s) request to enter the queue was rejected, because of too many clients with the same IP"), client->GetUserName(), ipstr(client->GetConnectIP())) ); return; } else if (theApp.clientlist->GetClientsFromIP(client->GetIP()) >= 3) { if (thePrefs.GetVerbose()) DEBUG_ONLY( AddDebugLogLine(false,_T("%s's (%s) request to enter the queue was rejected, because of too many clients with the same IP (found in TrackedClientsList)"), client->GetUserName(), ipstr(client->GetConnectIP())) ); return; } // done // statistic values // TODO: Maybe we should change this to count each request for a file only once and ignore reasks CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->GetUploadFileID()); if (reqfile) reqfile->statistic.AddRequest(); // emule collection will bypass the queue if (reqfile != NULL && CCollection::HasCollectionExtention(reqfile->GetFileName()) && reqfile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE && !client->IsDownloading() && client->socket != NULL && client->socket->IsConnected()) { client->SetCollectionUploadSlot(true); RemoveFromWaitingQueue(client, true); AddUpNextClient(_T("Collection Priority Slot"), client); return; } else client->SetCollectionUploadSlot(false); // cap the list // the queue limit in prefs is only a soft limit. Hard limit is 25% higher, to let in powershare clients and other // high ranking clients after soft limit has been reached uint32 softQueueLimit = thePrefs.GetQueueSize(); uint32 hardQueueLimit = thePrefs.GetQueueSize() + max(thePrefs.GetQueueSize()/4, 200); // if soft queue limit has been reached, only let in high ranking clients if ((uint32)waitinglist.GetCount() >= hardQueueLimit || (uint32)waitinglist.GetCount() >= softQueueLimit && // soft queue limit is reached (client->IsFriend() && client->GetFriendSlot()) == false && // client is not a friend with friend slot client->GetCombinedFilePrioAndCredit() < GetAverageCombinedFilePrioAndCredit()) { // and client has lower credits/wants lower prio file than average client in queue // then block client from getting on queue return; } if (client->IsDownloading()) { // he's already downloading and wants probably only another file if (thePrefs.GetDebugClientTCPLevel() > 0) DebugSend("OP__AcceptUploadReq", client); Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0); theStats.AddUpDataOverheadFileRequest(packet->size); client->SendPacket(packet, true); return; } if (waitinglist.IsEmpty() && ForceNewClient(true)) { AddUpNextClient(_T("Direct add with empty queue."), client); } else { waitinglist.AddTail(client); client->SetUploadState(US_ONUPLOADQUEUE); theApp.emuledlg->transferwnd->queuelistctrl.AddClient(client,true); theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount()); client->SendRankingInfo(); } }
bool CUploadQueue::ForceNewClient(bool allowEmptyWaitingQueue) { if(!allowEmptyWaitingQueue && waitinglist.GetSize() <= 0) return false; if (::GetTickCount() - m_nLastStartUpload < 1000 && datarate < 102400 ) return false; uint32 curUploadSlots = (uint32)uploadinglist.GetCount(); if (curUploadSlots < MIN_UP_CLIENTS_ALLOWED) return true; if(!AcceptNewClient(curUploadSlots) || !theApp.lastCommonRouteFinder->AcceptNewClient()) { // UploadSpeedSense can veto a new slot if USS enabled return false; } uint16 MaxSpeed; if (thePrefs.IsDynUpEnabled()) MaxSpeed = (uint16)(theApp.lastCommonRouteFinder->GetUpload()/1024); else MaxSpeed = thePrefs.GetMaxUpload(); uint32 upPerClient = UPLOAD_CLIENT_DATARATE; // if throttler doesn't require another slot, go with a slightly more restrictive method if( MaxSpeed > 20 || MaxSpeed == UNLIMITED) upPerClient += datarate/43; if( upPerClient > 7680 ) upPerClient = 7680; //now the final check if ( MaxSpeed == UNLIMITED ) { if (curUploadSlots < (datarate/upPerClient)) return true; } else{ uint16 nMaxSlots; if (MaxSpeed > 12) nMaxSlots = (uint16)(((float)(MaxSpeed*1024)) / upPerClient); else if (MaxSpeed > 7) nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 2; else if (MaxSpeed > 3) nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 1; else nMaxSlots = MIN_UP_CLIENTS_ALLOWED; // AddLogLine(true,"maxslots=%u, upPerClient=%u, datarateslot=%u|%u|%u",nMaxSlots,upPerClient,datarate/UPLOAD_CHECK_CLIENT_DR, datarate, UPLOAD_CHECK_CLIENT_DR); if ( curUploadSlots < nMaxSlots ) { return true; } } if(m_iHighestNumberOfFullyActivatedSlotsSinceLastCall > (uint32)uploadinglist.GetSize()) { // uploadThrottler requests another slot. If throttler says it needs another slot, we will allow more slots // than what we require ourself. Never allow more slots than to give each slot high enough average transfer speed, though (checked above). //if(thePrefs.GetLogUlDlEvents() && waitinglist.GetSize() > 0) // AddDebugLogLine(false, _T("UploadQueue: Added new slot since throttler needs it. m_iHighestNumberOfFullyActivatedSlotsSinceLastCall: %i uploadinglist.GetSize(): %i tick: %i"), m_iHighestNumberOfFullyActivatedSlotsSinceLastCall, uploadinglist.GetSize(), ::GetTickCount()); return true; } //nope return false; }
static void CheckNewClient(__pmFdSet * fdset, int rfd, int family) { int s, sts, accepted = 1; __uint32_t challenge; ClientInfo *cp; if (__pmFD_ISSET(rfd, fdset)) { if ((cp = AcceptNewClient(rfd)) == NULL) return; /* Accept failed and no client added */ sts = __pmAccAddClient(cp->addr, &cp->denyOps); #if defined(HAVE_STRUCT_SOCKADDR_UN) if (sts >= 0 && family == AF_UNIX) { if ((sts = __pmServerSetLocalCreds(cp->fd, &cp->attrs)) < 0) { __pmNotifyErr(LOG_ERR, "ClientLoop: error extracting local credentials: %s", pmErrStr(sts)); } } #endif if (sts >= 0) { memset(&cp->pduInfo, 0, sizeof(cp->pduInfo)); cp->pduInfo.version = PDU_VERSION; cp->pduInfo.licensed = 1; if (__pmServerHasFeature(PM_SERVER_FEATURE_SECURE)) cp->pduInfo.features |= (PDU_FLAG_SECURE | PDU_FLAG_SECURE_ACK); if (__pmServerHasFeature(PM_SERVER_FEATURE_COMPRESS)) cp->pduInfo.features |= PDU_FLAG_COMPRESS; if (__pmServerHasFeature(PM_SERVER_FEATURE_AUTH)) /*optional*/ cp->pduInfo.features |= PDU_FLAG_AUTH; if (__pmServerHasFeature(PM_SERVER_FEATURE_CREDS_REQD)) /*required*/ cp->pduInfo.features |= PDU_FLAG_CREDS_REQD; if (__pmServerHasFeature(PM_SERVER_FEATURE_CONTAINERS)) cp->pduInfo.features |= PDU_FLAG_CONTAINER; challenge = *(__uint32_t *)(&cp->pduInfo); sts = 0; } else { challenge = 0; accepted = 0; } pmcd_trace(TR_XMIT_PDU, cp->fd, PDU_ERROR, sts); /* reset (no meaning, use fd table to version) */ cp->pduInfo.version = UNKNOWN_VERSION; s = __pmSendXtendError(cp->fd, FROM_ANON, sts, htonl(challenge)); if (s < 0) { __pmNotifyErr(LOG_ERR, "ClientLoop: error sending Conn ACK PDU to new client %s\n", pmErrStr(s)); if (sts >= 0) /* * prefer earlier failure status if any, else * use the one from __pmSendXtendError() */ sts = s; accepted = 0; } if (!accepted) CleanupClient(cp, sts); } }