Beispiel #1
0
void __cdecl CIcqProto::KeepAliveThread(void *arg)
{
	serverthread_info *info = (serverthread_info*)arg;
	icq_packet packet;
	DWORD dwInterval = getDword("KeepAliveInterval", KEEPALIVE_INTERVAL);

	debugLogA("Keep alive thread starting.");

	info->hKeepAliveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	for (;;)
	{
		DWORD dwWait = ICQWaitForSingleObject(info->hKeepAliveEvent, dwInterval);
		if (serverThreadHandle == NULL) // connection lost, end
			break;
		if (dwWait == WAIT_TIMEOUT)
		{
			// Send a keep alive packet to server
			packet.wLen = 0;
			write_flap(&packet, ICQ_PING_CHAN);
			sendServPacket(&packet);
		}
		else if (dwWait == WAIT_IO_COMPLETION)
			// Possible shutdown in progress
			if (Miranda_Terminated()) break;
			else
				break;
	}

	debugLogA("Keep alive thread ended.");

	CloseHandle(info->hKeepAliveEvent);
	info->hKeepAliveEvent = NULL;
}
Beispiel #2
0
void CIcqProto::icq_serverDisconnect(BOOL bBlock)
{
	if (hServerConn)
	{
		NetLog_Server("Server shutdown requested");
		Netlib_Shutdown(hServerConn);

		if (serverThreadHandle)
		{
			// Not called from network thread?
			if (bBlock && GetCurrentThreadId() != serverThreadId)
				while (ICQWaitForSingleObject(serverThreadHandle, INFINITE) != WAIT_OBJECT_0);

			CloseHandle(serverThreadHandle);
			serverThreadHandle = NULL;
		}
	}
}
void __cdecl CIcqProto::InfoUpdateThread( void* )
{
	int i;
	DWORD dwWait = WAIT_OBJECT_0;

	debugLogA("%s thread starting.", "Info-Update");

	bInfoUpdateRunning = TRUE;

	while (bInfoUpdateRunning)
	{
		if (!nInfoUserCount && bInfoPendingUsers) // whole queue processed, check if more users needs updating
			icq_RescanInfoUpdate();

		if (!nInfoUserCount || !bInfoUpdateEnabled || !icqOnline())
		{
			dwWait = WAIT_TIMEOUT;
			while (bInfoUpdateRunning && dwWait == WAIT_TIMEOUT)
			{ // wait for new work or until we should end
				dwWait = ICQWaitForSingleObject(hInfoQueueEvent, 10000);
			}
		}
		if (!bInfoUpdateRunning) break;

		switch (dwWait) {
		case WAIT_IO_COMPLETION:
			// Possible shutdown in progress
			break;

		case WAIT_OBJECT_0:
		case WAIT_TIMEOUT:
			// Time to check for new users
			if (!bInfoUpdateEnabled) continue; // we can't send requests now      

			if (nInfoUserCount && icqOnline())
			{
				time_t now = time(NULL);
				BOOL bNotReady = FALSE, bTimeOuted = FALSE;

				// Check the list, take only users that were there for at least 5sec
				// wait if any user is there shorter than 5sec and not a single user is there longer than 20sec
				infoUpdateMutex->Enter();
				for (i = 0; i<LISTSIZE; i++)
				{
					if (m_infoUpdateList[i].hContact)
					{
						if (m_infoUpdateList[i].queued + 20 < now)
						{
							bTimeOuted = TRUE;
							break;
						}
						else if (m_infoUpdateList[i].queued + 5 >= now)
							bNotReady = TRUE;
					}
				}
				infoUpdateMutex->Leave();

				if (!bTimeOuted && bNotReady)
				{
					SleepEx(1000, TRUE);
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					continue;
				}

				if (FindCookie(dwInfoActiveRequest, NULL, NULL))
				{ // only send another request, when the previous is completed
#ifdef _DEBUG
					debugLogA("Info-Update: Request 0x%x still in progress.", dwInfoActiveRequest);
#endif
					SleepEx(1000, TRUE);
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					continue;
				}

#ifdef _DEBUG
				debugLogA("Info-Update: Users %u in queue.", nInfoUserCount);
#endif
				// Either some user is waiting long enough, or all users are ready (waited at least the minimum time)
				m_ratesMutex->Enter();
				if (!m_rates)
				{ // we cannot send info request - icq is offline
					m_ratesMutex->Leave();
					break;
				}
				WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST);
				while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_IDLE_30))
				{ // we are over rate, need to wait before sending
					int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_50);

					m_ratesMutex->Leave();
#ifdef _DEBUG
					debugLogA("Rates: InfoUpdate delayed %dms", nDelay);
#endif
					SleepEx(nDelay, TRUE); // do not keep things locked during sleep
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					m_ratesMutex->Enter();
					if (!m_rates) // we lost connection when we slept, go away
						break;
				}
				if (!m_rates)
				{ // we cannot send info request - icq is offline
					m_ratesMutex->Leave();
					break;
				}
				m_ratesMutex->Leave();

				userinfo *hContactList[LISTSIZE];
				int nListIndex = 0;
				BYTE *pRequestData = NULL;
				int nRequestSize = 0;

				infoUpdateMutex->Enter();
				for (i = 0; i<LISTSIZE; i++)
				{
					if (m_infoUpdateList[i].hContact)
					{
						// check TS again, maybe it has been updated while we slept
						if (IsMetaInfoChanged(m_infoUpdateList[i].hContact))
						{
							if (m_infoUpdateList[i].queued + 5 < now)
							{
								BYTE *pItem = NULL;
								int nItemSize = 0;
								DBVARIANT dbv = {DBVT_DELETED};

								if (!getSetting(m_infoUpdateList[i].hContact, DBSETTING_METAINFO_TOKEN, &dbv))
								{ // retrieve user details using privacy token
									ppackTLV(&pItem, &nItemSize, 0x96, dbv.cpbVal, dbv.pbVal);
									db_free(&dbv);
								}
								// last updated time
								ppackTLVDouble(&pItem, &nItemSize, 0x64, getSettingDouble(m_infoUpdateList[i].hContact, DBSETTING_METAINFO_TIME, 0));

								ppackTLVUID(&pItem, &nItemSize, 0x32, m_infoUpdateList[i].dwUin, NULL);
								ppackWord(&pRequestData, &nRequestSize, (WORD)nItemSize);
								ppackBuffer(&pRequestData, &nRequestSize, nItemSize, pItem);
								// take a reference
								SAFE_FREE((void**)&pItem);
								hContactList[nListIndex++] = &m_infoUpdateList[i];
							}
						}
						else
						{
#ifdef _DEBUG
							debugLogA("Dequeued absolete user %u", m_infoUpdateList[i].dwUin);
#endif
							// Dequeue user and find another one
							m_infoUpdateList[i].dwUin = 0;
							m_infoUpdateList[i].hContact = NULL;
							nInfoUserCount--;
							// continue for loop
						}
					}
				}

#ifdef _DEBUG
				debugLogA("Request info for %u user(s).", nListIndex);
#endif
				if (!nListIndex)
				{ // no users to request info for
					infoUpdateMutex->Leave();
					break;
				}
				if (!(dwInfoActiveRequest = sendUserInfoMultiRequest(pRequestData, nRequestSize, nListIndex)))
				{ // sending data packet failed
					SAFE_FREE((void**)&pRequestData);
					infoUpdateMutex->Leave();
					break;
				}
				SAFE_FREE((void**)&pRequestData);

				for (i = 0; i<nListIndex; i++)
				{ // Dequeue users and go back to sleep
					hContactList[i]->dwUin = 0;
					hContactList[i]->hContact = NULL;
					hContactList[i]->queued = 0;
					nInfoUserCount--;
				}
				infoUpdateMutex->Leave();
			}
			break;

		default:
			// Something strange happened. Exit
			bInfoUpdateRunning = FALSE;
			break;
		}
	}

	debugLogA("%s thread ended.", "Info-Update");

LBL_Exit:
	SAFE_DELETE(&infoUpdateMutex);
	CloseHandle(hInfoQueueEvent);
}