DWORD EnqueueReceive ( IN PHTTP_LISTENER listener ) { DWORD result; // Create the listener overlapped. PHTTP_IO_CONTEXT pListenerRequest = GetIOContext(); if (pListenerRequest == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // Initalize the overlapped fields. pListenerRequest->RequestSize = REQUEST_BUFFER_SIZE; pListenerRequest->listener = listener; pListenerRequest->RequestSize = REQUEST_BUFFER_SIZE; HTTP_SET_NULL_ID(&pListenerRequest->requestId); pListenerRequest->operationState = HTTP_LISTENER_STATE_REQUEST; // Enqueue async IO Request. StartThreadpoolIo(listener->pthreadPoolIO); result = HttpReceiveHttpRequest( listener->hRequestQueue, // Req Queue pListenerRequest->requestId, // Req ID 0, // Flags &pListenerRequest->Request, // HTTP request buffer pListenerRequest->RequestSize, // req buffer length NULL, // bytes received pListenerRequest // LPOVERLAPPED ); if(result != NO_ERROR && result != ERROR_IO_PENDING) { // need to call this whenever an async I/O operation fails synchronously CancelThreadpoolIo(listener->pthreadPoolIO); LOG_ERROR(L"\nSycnhronous request processing completion error - %lu", result); return result; } else if(result == NO_ERROR) { // Synchronous completion CancelThreadpoolIo(listener->pthreadPoolIO); HttpInputQueueEnqueue(listener, pListenerRequest); } else { DEBUG_ASSERT(result == ERROR_IO_PENDING) } return NO_ERROR; }
void Server::PostSend(Client* client, Packet* packet) { assert(client); assert(packet); WSABUF recvBufferDescriptor; recvBufferDescriptor.buf = reinterpret_cast<char*>(packet->GetData()); recvBufferDescriptor.len = packet->GetSize(); DWORD sendFlags = 0; IOEvent* event = IOEvent::Create(IOEvent::SEND, client, packet); assert(event); StartThreadpoolIo(client->GetTPIO()); if (WSASend(client->GetSocket(), &recvBufferDescriptor, 1, NULL, sendFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { CancelThreadpoolIo(client->GetTPIO()); ERROR_CODE(error, "WSASend() failed."); RemoveClient(client); } } else { // In this case, the completion callback will have already been scheduled to be called. } }
CF_PRIVATE Boolean _CFWriteBytesToFileAsync(CFURLRef url, const void *bytes, CFIndex length) { char path[CFMaxPathSize]; if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize)) { return false; } wchar_t wpath[CFMaxPathSize]; int convertedLength = MultiByteToWideChar(CP_UTF8, 0, path, CFMaxPathSize, wpath, CFMaxPathSize); if (0 == convertedLength) { unsigned error = GetLastError(); CFLog(kCFLogLevelWarning, CFSTR("_CFWriteBytesToFileAsync failed to convert the path (error %u)"), error); return false; } HANDLE fileHandle = NULL; CREATEFILE2_EXTENDED_PARAMETERS createExParams; createExParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; createExParams.dwFileFlags = FILE_FLAG_OVERLAPPED; createExParams.dwSecurityQosFlags = 0; createExParams.lpSecurityAttributes = NULL; createExParams.hTemplateFile = NULL; OVERLAPPED* overlapped = (OVERLAPPED*)calloc(1, sizeof(OVERLAPPED)); if ((fileHandle = CreateFile2(wpath, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, &createExParams)) == INVALID_HANDLE_VALUE) { unsigned error = GetLastError(); CFLog(kCFLogLevelWarning, CFSTR("_CFWriteBytesToFileAsync failed to open the file (error %u)"), error); free(overlapped); return false; } PTP_IO threadPoolIo = CreateThreadpoolIo(fileHandle, _threadpoolCallback, NULL, NULL); StartThreadpoolIo(threadPoolIo); if (!WriteFile(fileHandle, bytes, length, NULL, overlapped)) { unsigned error = GetLastError(); if (ERROR_IO_PENDING != error) { CFLog(kCFLogLevelWarning, CFSTR("_CFWriteBytesToFileAsync failed to write to the file (error %u)"), error); CloseHandle(fileHandle); CancelThreadpoolIo(threadPoolIo); CloseThreadpoolIo(threadPoolIo); free(overlapped); return false; } } CloseHandle(fileHandle); return true; }
void Server::PostAccept() { // If the number of clients is too big, we can just stop posting accept. // That's one of the benefits from AcceptEx. int count = m_MaxPostAccept - m_NumPostAccept; if (count > 0) { int i = 0; for (; i < count; ++i) { Client* client = new Client(); if (!client->Create()) { delete client; break; } IOEvent* event = IOEvent::Create(IOEvent::ACCEPT, client); assert(event); StartThreadpoolIo(m_pTPIO); if (!Network::AcceptEx(m_listenSocket, client->GetSocket(), &event->GetOverlapped())) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { CancelThreadpoolIo(m_pTPIO); ERROR_CODE(error, "AcceptEx() failed."); delete client; IOEvent::Destroy(event); break; } } else { OnAccept(event); IOEvent::Destroy(event); } } InterlockedExchangeAdd(&m_NumPostAccept, i); TRACE("[%d] Post AcceptEx : %d", GetCurrentThreadId(), m_NumPostAccept); } }
void Server::PostRecv(Client* client) { assert(client); WSABUF recvBufferDescriptor; recvBufferDescriptor.buf = reinterpret_cast<char*>(client->GetRecvBuff()); recvBufferDescriptor.len = Client::MAX_RECV_BUFFER; DWORD numberOfBytes = 0; DWORD recvFlags = 0; IOEvent* event = IOEvent::Create(IOEvent::RECV, client); assert(event); StartThreadpoolIo(client->GetTPIO()); if (WSARecv(client->GetSocket(), &recvBufferDescriptor, 1, &numberOfBytes, &recvFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { CancelThreadpoolIo(client->GetTPIO()); ERROR_CODE(error, "WSARecv() failed."); OnClose(event); IOEvent::Destroy(event); } } else { // In this case, the completion callback will have already been scheduled to be called. } }
DWORD SendHttpResponse( IN PHTTP_REQUEST pRequest, IN PHTTP_IO_CONTEXT pContext, IN USHORT StatusCode, IN PSTR pReason, IN PSTR pEntityString, IN PSTR pContentLength ) { HTTP_DATA_CHUNK dataChunk; DWORD result; PHTTP_LISTENER listener = pContext->listener; PHTTP_IO_CONTEXT pResponseContext = GetIOContext(); // // Initialize the HTTP response structure. // pResponseContext->Reponse.StatusCode = (StatusCode); pResponseContext->Reponse.pReason = (pReason); pResponseContext->Reponse.ReasonLength = (USHORT) strlen(pReason); // // Add a known header. // //ADD_KNOWN_HEADER pResponseContext->Reponse.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = "text/html"; pResponseContext->Reponse.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen("text/html"); DEBUG_ASSERT(pEntityString); dataChunk.DataChunkType = HttpDataChunkFromMemory; dataChunk.FromMemory.pBuffer = pEntityString; dataChunk.FromMemory.BufferLength = (ULONG) strlen(pEntityString); pResponseContext->Reponse.EntityChunkCount = 1; pResponseContext->Reponse.pEntityChunks = &dataChunk; // // Since we are sending all the entity body in one call, we don't have // to specify the Content-Length. // pResponseContext->operationState = HTTP_LISTENER_STATE_RESPONSE; // Enqueue async IO Request. StartThreadpoolIo(listener->pthreadPoolIO); result = HttpSendHttpResponse( listener->hRequestQueue, // ReqQueueHandle pRequest->RequestId, // Request ID 0, // Flags &pResponseContext->Reponse, // HTTP response NULL, // cache policy NULL, // bytes sent (OPTIONAL) NULL, // pReserved2 (must be NULL) 0, // Reserved3 (must be 0) pResponseContext, // LPOVERLAPPED (OPTIONAL) NULL // pReserved4 (must be NULL) ); if(result != NO_ERROR && result != ERROR_IO_PENDING) { // need to call this whenever an async I/O operation fails synchronously CancelThreadpoolIo(listener->pthreadPoolIO); LOG_ERROR(L"\nSynchronous completion response processing error - %lu", result); return result; } else if(result == NO_ERROR) { // Synchronous completion CancelThreadpoolIo(listener->pthreadPoolIO); HttpInputQueueEnqueue(listener, pResponseContext); } else { DEBUG_ASSERT(result == ERROR_IO_PENDING) } return NO_ERROR; }
void NamedPipe::OnRequested(PTP_WORK work) { lock_.Acquire(); auto request = std::move(queue_.front()); queue_.pop_front(); if (!queue_.empty()) SubmitThreadpoolWork(work); do { base::AutoLock guard(lock_, base::AutoLock::AlreadyAcquired()); if (request->command == Command::kNotify) break; if (pipe_ == INVALID_HANDLE_VALUE || io_ == nullptr) { request->Internal = static_cast<ULONG_PTR>(E_HANDLE); break; } StartThreadpoolIo(io_); auto succeeded = false; switch (request->command) { case Command::kAccept: succeeded = ConnectNamedPipe(pipe_, request.get()) != FALSE; break; case Command::kRead: succeeded = ReadFile(pipe_, request->buffer, static_cast<DWORD>(request->InternalHigh), nullptr, request.get()) != FALSE; break; case Command::kWrite: succeeded = WriteFile(pipe_, request->buffer, static_cast<DWORD>(request->InternalHigh), nullptr, request.get()) != FALSE; break; default: CHECK(false) << "This must not occur."; } auto error = GetLastError(); if (succeeded || error == ERROR_IO_PENDING) { request.release(); return; } if (request->command == Command::kAccept && error == ERROR_PIPE_CONNECTED) error = ERROR_SUCCESS; CancelThreadpoolIo(io_); request->Internal = HRESULT_FROM_WIN32(error); request->completed_command = request->command; request->command = Command::kNotify; } while (false); switch (request->completed_command) { case Command::kAccept: request->listener->OnAccepted(this, static_cast<HRESULT>(request->Internal)); break; case Command::kRead: request->listener->OnRead(this, static_cast<HRESULT>(request->Internal), request->buffer, request->InternalHigh); break; case Command::kWrite: request->listener->OnWritten(this, static_cast<HRESULT>(request->Internal), request->buffer, request->InternalHigh); break; default: CHECK(false) << "This must not occur."; } }
void NamedPipeChannel::OnRequested(PTP_WORK work) { lock_.Acquire(); auto request = std::move(queue_.front()); queue_.pop(); if (!queue_.empty()) SubmitThreadpoolWork(work); do { base::AutoLock guard(lock_, base::AutoLock::AlreadyAcquired()); if (request->command == Command::kNotify) break; if (handle_ == INVALID_HANDLE_VALUE || io_ == nullptr) { request->result = E_HANDLE; break; } StartThreadpoolIo(io_); bool succeeded; switch (request->command) { case Command::kConnectAsync: succeeded = ConnectNamedPipe(handle_, request.get()) != FALSE; break; case Command::kReadAsync: succeeded = ReadFile(handle_, request->output, request->output_length, &request->length, request.get()) != FALSE; break; case Command::kWriteAsync: succeeded = WriteFile(handle_, request->input, request->input_length, &request->length, request.get()) != FALSE; break; case Command::kTransactAsync: succeeded = TransactNamedPipe(handle_, request->input, request->input_length, request->output, request->output_length, &request->length, request.get()) != FALSE; break; default: LOG(FATAL) << "Invalid command: " << static_cast<int>(request->command); succeeded = false; SetLastError(HRESULT_CODE(E_UNEXPECTED)); break; } auto error = GetLastError(); if (succeeded || error == ERROR_IO_PENDING || error == ERROR_MORE_DATA) { request.release(); return; } request->result = HRESULT_FROM_WIN32(error); CancelThreadpoolIo(io_); } while (false); if (request->command != Command::kNotify) { request->completed_command = request->command; request->command = Command::kNotify; } switch (request->completed_command) { case Command::kConnectAsync: if (HRESULT_CODE(request->result) == ERROR_PIPE_CONNECTED) request->result = HRESULT_CODE(request->result); request->listener->OnConnected(this, request->result); break; case Command::kReadAsync: if (HRESULT_CODE(request->result) == ERROR_MORE_DATA) request->result = HRESULT_CODE(request->result); request->channel_listener->OnRead(this, request->result, request->output, request->length); break; case Command::kWriteAsync: request->channel_listener->OnWritten(this, request->result, request->input, request->length); break; case Command::kTransactAsync: if (HRESULT_CODE(request->result) == ERROR_MORE_DATA) request->result = HRESULT_CODE(request->result); request->listener->OnTransacted(this, request->result, request->input, request->output, request->length); break; default: LOG(FATAL) << "Invalid command: " << static_cast<int>(request->completed_command); break; } }