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; }
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; }
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; }
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; }
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; }
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; }