Пример #1
0
bool TCPClient::Post(u8 *data, u32 data_bytes, u32 skip_bytes)
{
	AsyncBuffer *buffer = AsyncBuffer::Promote(data);

	if (_disconnecting)
	{
		buffer->Release();
		return false;
	}

	buffer->Reset(fastdelegate::MakeDelegate(this, &TCPClient::OnWrite));

	WSABUF wsabuf;
	wsabuf.buf = reinterpret_cast<CHAR*>( data + skip_bytes );
	wsabuf.len = data_bytes;

	AddRef();

	// Fire off a WSASend() and forget about it
	int result = WSASend(_socket, &wsabuf, 1, 0, 0, buffer->GetOv(), 0);

	// This overlapped operation will always complete unless
	// we get an error code other than ERROR_IO_PENDING.
	if (result && WSAGetLastError() != ERROR_IO_PENDING)
	{
		FATAL("TCPClient") << "WSASend error: " << SocketGetLastErrorString();
		buffer->Release();
		ReleaseRef();
		return false;
	}

	return true;
}
Пример #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 // CAT_OS_WINDOWS
#error TODO
#endif // CAT_OS_WINDOWS

	return true;
}
Пример #3
0
bool TCPClient::ConnectEx(const NetAddr &remoteServerAddress)
{
    // Get ConnectEx() interface
    GUID GuidConnectEx = WSAID_CONNECTEX;
    LPFN_CONNECTEX lpfnConnectEx;
    DWORD copied;

    if (WSAIoctl(_socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidConnectEx,
                 sizeof(GuidConnectEx), &lpfnConnectEx, sizeof(lpfnConnectEx), &copied, 0, 0))
    {
        FATAL("TCPClient") << "Unable to get ConnectEx interface: " << SocketGetLastErrorString();
        return false;
    }

	// Unwrap NetAddr
	NetAddr::SockAddr addr_out;
	int addr_len;
	if (!remoteServerAddress.Unwrap(addr_out, addr_len, _ipv6))
	{
		FATAL("TCPClient") << "Unable to execute ConnectEx: Server address invalid";
		return false;
	}

	// If unable to get an AsyncServerAccept object,
	AsyncBuffer *buffer;
	if (!AsyncBuffer::Acquire(buffer))
	{
		FATAL("TCPClient") << "Out of memory: Unable to allocate ConnectEx overlapped structure";
		return false;
	}

	buffer->Reset(fastdelegate::MakeDelegate(this, &TCPClient::OnConnectEx));

    AddRef();

    // Queue up a ConnectEx()
    BOOL result = lpfnConnectEx(_socket, reinterpret_cast<sockaddr*>( &addr_out ),
                                addr_len, 0, 0, 0, buffer->GetOv()); 

    // This overlapped operation will always complete unless
    // we get an error code other than ERROR_IO_PENDING.
    if (!result && WSAGetLastError() != ERROR_IO_PENDING)
    {
        FATAL("TCPClient") << "ConnectEx error: " << SocketGetLastErrorString();
        buffer->Release();
        ReleaseRef();
        return false;
    }

    return true;
}
Пример #4
0
bool TCPClientQueued::Post(u8 *data, u32 data_bytes, u32 skip_bytes)
{
    // Try not to hold a lock if we can help it
    if (!_queuing) return TCPClient::Post(data, data_bytes, skip_bytes);

    AutoMutex lock(_queueLock);

    // Check to make sure we're still queuing
    if (!_queuing)
    {
        lock.Release();

		return TCPClient::Post(data, data_bytes, skip_bytes);
    }

	AsyncBuffer *buffer = AsyncBuffer::Promote(data);

	// If queue buffer has not been created,
    if (!_queueBuffer)
	{
		_queueBuffer = buffer;
	}
	else
    {
		// Otherwise append to the end of the queue buffer,
		u32 queue_bytes = _queueBuffer->GetDataBytes();
		u32 bytes = buffer->GetDataBytes();

        _queueBuffer = _queueBuffer->Resize(queue_bytes + bytes);

		if (_queueBuffer)
		{
			memcpy(_queueBuffer->GetData() + queue_bytes, data, bytes);
		}

		buffer->Release();

		return !!_queueBuffer;
	}

    return true;
}
Пример #5
0
bool UDPEndpoint::Post(const NetAddr &addr, u8 *data, u32 data_bytes, u32 skip_bytes)
{
	AsyncBuffer *buffer = AsyncBuffer::Promote(data);

	if (_closing)
	{
		buffer->Release();
		return false;
	}

	// Unwrap NetAddr object to something sockaddr-compatible
	NetAddr::SockAddr out_addr;
	int addr_len;
	if (!addr.Unwrap(out_addr, addr_len))
	{
		buffer->Release();
		return false;
	}

	WSABUF wsabuf;
	wsabuf.buf = reinterpret_cast<CHAR*>( data + skip_bytes );
	wsabuf.len = data_bytes;

	buffer->Reset(fastdelegate::MakeDelegate(this, &UDPEndpoint::OnWriteComplete));

	AddRef();

	// Fire off a WSASendTo() and forget about it
	int result = WSASendTo(_socket, &wsabuf, 1, 0, 0,
						   reinterpret_cast<const sockaddr*>( &out_addr ),
						   addr_len, buffer->GetOv(), 0);

	// This overlapped operation will always complete unless
	// we get an error code other than ERROR_IO_PENDING.
	if (result && WSAGetLastError() != ERROR_IO_PENDING)
	{
		FATAL("UDPEndpoint") << "WSASendTo error: " << SocketGetLastErrorString();
		buffer->Release();
		ReleaseRef();
		return false;
	}

	return true;
}
Пример #6
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;
}