Beispiel #1
0
bool ThreadPoolWorker::ThreadFunction(void *port)
{
#if defined(CAT_OS_WINDOWS)

	DWORD bytes;
	void *key = 0;
	AsyncBuffer *buffer = 0;
	int error;

	// Initialize ThreadPool Local Storage (CSPRNG, math library)
	ThreadPoolLocalStorage tls;

	if (!tls.Valid())
	{
		FATAL("ThreadPool") << "Unable to initialize thread local storage objects";

		return false;
	}

	for (;;)
	{
		error = GetQueuedCompletionStatus((HANDLE)port, &bytes,
			(PULONG_PTR)&key, (OVERLAPPED**)&buffer, INFINITE)
			? 0 : GetLastError();

		// Terminate thread when we receive a zeroed completion packet
		if (!bytes && !key && !buffer)
			return true;

		// If completion object is NOT specified,
		ThreadRefObject *obj = reinterpret_cast<ThreadRefObject*>( key );
		if (!obj)
		{
			// Release memory for overlapped object
			buffer->Release();
		}
		else
		{
			// If completion object callback returns TRUE,
			if (buffer->Call(&tls, error, buffer, bytes))
			{
				// Release memory for overlapped object
				buffer->Release();
			}

			// Release reference held on completion object
			obj->ReleaseRef();
		}
	}

#else // CAT_OS_WINDOWS
#error TODO
#endif // CAT_OS_WINDOWS

	return true;
}
Beispiel #2
0
bool ThreadPoolWorker::ThreadFunction(void *port)
{
#if defined(CAT_OS_WINDOWS)

	DWORD bytes;
	void *key = 0;
	AsyncBuffer *buffer = 0;
	int error;

	// Initialize ThreadPool Local Storage (CSPRNG, math library)
	ThreadPoolLocalStorage tls;

	if (!tls.Valid())
	{
		FATAL("ThreadPool") << "Unable to initialize thread local storage objects";

		return false;
	}

	for (;;)
	{
		error = GetQueuedCompletionStatus((HANDLE)port, &bytes,
			(PULONG_PTR)&key, (OVERLAPPED**)&buffer, INFINITE)
			? 0 : GetLastError();

		// Terminate thread when we receive a zeroed completion packet
		if (!bytes && !key && !buffer)
			return true;

		// If completion object is NOT specified,
		ThreadRefObject *obj = reinterpret_cast<ThreadRefObject*>( key );
		if (!obj)
		{
			// Release memory for overlapped object
			buffer->Release();
		}
		else
		{
			// If completion object callback returns TRUE,
			if (buffer->Call(&tls, error, buffer, bytes))
			{
				// Release memory for overlapped object
				buffer->Release();
			}

			// Release reference held on completion object
			obj->ReleaseRef();
		}
	}

#else

	epoll_event ev_buf[EPOLL_QUEUE_LEN];

	for (;;)
	{
		int n;

		for (;;)
		{
			n = epoll_wait(_port, ev_buf, EPOLL_QUEUE_LEN, -1);

			if (!n == -1 && errno == EINTR))
			{
				FATAL("ThreadPool") << "epoll_wait failure";
				break;
			}
		}

		if (!n)
		{
			FATAL("ThreadPool") << "epoll_wait timeout expired";
			continue;
		}

		for (int ii = 0; ii < n; ++ii)
		{
			poll_entry_t *pe = (poll_entry_t*)ev_buf[ii].data.ptr;

			if (pe->fd == INVALID_SOCKET)
				continue;

			if (ev_buf [i].events & (EPOLLERR | EPOLLHUP))
				pe->events->in_event ();

			if (pe->fd == INVALID_SOCKET)
				continue;

			if (ev_buf [i].events & EPOLLOUT)
				pe->events->out_event ();

			if (pe->fd == INVALID_SOCKET)
				continue;

			if (ev_buf [i].events & EPOLLIN)
				pe->events->in_event ();
		}
	}

#endif

	return true;
}
bool Client::ThreadFunction(void *)
{
	ThreadPoolLocalStorage tls;

	if (!tls.Valid())
	{
		WARN("Client") << "Unable to create thread pool local storage";
		return false;
	}

	u32 start_time = Clock::msec_fast();
	u32 first_hello_post = start_time;
	u32 last_hello_post = start_time;
	u32 hello_post_interval = INITIAL_HELLO_POST_INTERVAL;

	// While still not connected,
	while (!_connected)
	{
		// Wait for quit signal
		if (_kill_flag.Wait(HANDSHAKE_TICK_RATE))
			return false;

		// If now connected, break out
		if (_connected)
			break;

		u32 now = Clock::msec_fast();

		// If connection timed out,
		if (now - first_hello_post >= CONNECT_TIMEOUT)
		{
			// NOTE: Connection can complete before or after OnConnectFail()
			WARN("Client") << "Unable to connect: Timeout";
			Close();
			return false;
		}

		// If time to repost hello packet,
		if (now - last_hello_post >= hello_post_interval)
		{
			if (!PostHello())
			{
				WARN("Client") << "Unable to connect: Post failure";
				Close();
				return false;
			}

			last_hello_post = now;
			hello_post_interval *= 2;
		}

		OnTick(&tls, now);
	}

	// Begin MTU probing after connection completes
	u32 overhead = (Is6() ? IPV6_HEADER_BYTES : IPV4_HEADER_BYTES) + UDP_HEADER_BYTES + AuthenticatedEncryption::OVERHEAD_BYTES;
	u32 mtu_discovery_time = Clock::msec();
	int mtu_discovery_attempts = 2;

	if (!DontFragment())
	{
		WARN("Client") << "Unable to detect MTU: Unable to set DF bit";
		mtu_discovery_attempts = 0;
	}
	else if (!PostMTUProbe(&tls, MAXIMUM_MTU - overhead) ||
			 !PostMTUProbe(&tls, MEDIUM_MTU - overhead))
	{
		WARN("Client") << "Unable to detect MTU: First probe post failure";
	}

	// Time synchronization begins right away
	u32 next_sync_time = Clock::msec();
	u32 sync_attempts = 0;

	// Set last receive time to avoid disconnecting due to timeout too soon
	_last_recv_tsc = next_sync_time;

	// While waiting for quit signal,
	while (!_kill_flag.Wait(Transport::TICK_RATE))
	{
		u32 now = Clock::msec();

		TickTransport(&tls, now);

		// If it is time for time synch,
		if ((s32)(now - next_sync_time) >= 0)
		{
			PostTimePing();

			// Increase synch interval after the first 8 data points
			if (sync_attempts >= 8)
				next_sync_time = now + 20000; // 20 seconds from now
			else
			{
				next_sync_time = now + 5000; // 5 seconds from now
				++sync_attempts;
			}
		}

		// If MTU discovery attempts continue,
		if (mtu_discovery_attempts > 0)
		{
			// If it is time to reprobe the MTU,
			if (now - mtu_discovery_time >= MTU_PROBE_INTERVAL)
			{
				// If payload bytes already maxed out,
				if (_max_payload_bytes >= MAXIMUM_MTU - overhead)
				{
					// Stop posting probes
					mtu_discovery_attempts = 0;

					// On final attempt set DF=0
					DontFragment(false);
				}
				else
				{
					// If not on final attempt,
					if (mtu_discovery_attempts > 1)
					{
						// Post probes
						if (!PostMTUProbe(&tls, MAXIMUM_MTU - overhead) ||
							!PostMTUProbe(&tls, MEDIUM_MTU - overhead))
						{
							WARN("Client") << "Unable to detect MTU: Probe post failure";
						}

						mtu_discovery_time = now;
						--mtu_discovery_attempts;
					}
					else
					{
						// Stop posting probes
						mtu_discovery_attempts = 0;

						// On final attempt set DF=0
						DontFragment(false);
					}
				}
			}
		}

		// If no packets have been received,
		if ((s32)(now - _last_recv_tsc) >= TIMEOUT_DISCONNECT)
		{
			Disconnect();
			return true;
		}

		// Tick subclass
		OnTick(&tls, now);

		// Send a keep-alive after the silence limit expires
		if ((s32)(now - _last_send_mstsc) >= SILENCE_LIMIT)
		{
			PostTimePing();
			next_sync_time = now + 20000; // 20 seconds from now
		}
	}

	return true;
}