Пример #1
0
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;
}
Пример #2
0
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.
    }
}
Пример #3
0
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;
}
Пример #4
0
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);
    }
}
Пример #5
0
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.
    }
}
Пример #6
0
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;
}
Пример #7
0
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.";
  }
}
Пример #8
0
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;
  }
}