in win32/src/async_socket_win32.c [84:207]
static VOID WINAPI on_io_complete(PTP_CALLBACK_INSTANCE instance, PVOID context, PVOID overlapped, ULONG io_result, ULONG_PTR number_of_bytes_transferred, PTP_IO io)
{
if (overlapped == NULL)
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_063: [ If overlapped is NULL, on_io_complete shall return. ]*/
LogError("Invalid arguments: PTP_CALLBACK_INSTANCE instance=%p, PVOID context=%p, PVOID overlapped=%p, ULONG io_result=%lu, ULONG_PTR number_of_bytes_transferred=%p, PTP_IO io=%p",
instance, context, overlapped, io_result, (void*)number_of_bytes_transferred, io);
}
else
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_064: [ overlapped shall be used to determine the context of the IO. ]*/
ASYNC_SOCKET_IO_CONTEXT* io_context = (ASYNC_SOCKET_IO_CONTEXT*)(((unsigned char*)overlapped) - offsetof(ASYNC_SOCKET_IO_CONTEXT, overlapped));
switch (io_context->io_type)
{
default:
LogError("Unknown IO type: %" PRI_MU_ENUM "", MU_ENUM_VALUE(ASYNC_SOCKET_IO_TYPE, io_context->io_type));
break;
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_065: [ If the context of the IO indicates that a send has completed: ]*/
case ASYNC_SOCKET_IO_TYPE_SEND:
{
ASYNC_SOCKET_SEND_RESULT send_result;
if (io_result == NO_ERROR)
{
uint32_t bytes_sent = (uint32_t)number_of_bytes_transferred;
#ifdef ENABLE_SOCKET_LOGGING
LogVerbose("Asynchronous send of %" PRIu32 " bytes completed at %lf", bytes_sent, timer_global_get_elapsed_us());
#endif
if (bytes_sent != io_context->total_buffer_bytes)
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_102: [ If io_result is NO_ERROR, but the number of bytes send is different than the sum of all buffer sizes passed to async_socket_send_async, the on_send_complete callback passed to async_socket_send_async shall be called with on_send_complete_context as context and ASYNC_SOCKET_SEND_ERROR. ]*/
send_result = ASYNC_SOCKET_SEND_ERROR;
}
else
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_066: [ If io_result is NO_ERROR, the on_send_complete callback passed to async_socket_send_async shall be called with on_send_complete_context as argument and ASYNC_SOCKET_SEND_OK. ]*/
send_result = ASYNC_SOCKET_SEND_OK;
}
}
else
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_067: [ If io_result is not NO_ERROR, the on_send_complete callback passed to async_socket_send_async shall be called with on_send_complete_context as argument and ASYNC_SOCKET_SEND_ERROR. ]*/
LogError("Send IO completed with error %lu", io_result);
send_result = ASYNC_SOCKET_SEND_ERROR;
}
io_context->io.send.on_send_complete(io_context->io.send.on_send_complete_context, send_result);
break;
}
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_071: [ If the context of the IO indicates that a receive has completed: ]*/
case ASYNC_SOCKET_IO_TYPE_RECEIVE:
{
ASYNC_SOCKET_RECEIVE_RESULT receive_result;
uint32_t bytes_received;
switch (io_result)
{
default:
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_070: [ If io_result is not NO_ERROR, the on_receive_complete callback passed to async_socket_receive_async shall be called with on_receive_complete_context as context, ASYNC_SOCKET_RECEIVE_ERROR as result and 0 for bytes_received. ]*/
LogError("Receive IO completed with error %lu", io_result);
receive_result = ASYNC_SOCKET_RECEIVE_ERROR;
bytes_received = 0;
break;
}
case ERROR_NETNAME_DELETED:
case ERROR_CONNECTION_ABORTED:
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_42_001: [ If io_result is ERROR_NETNAME_DELETED or ERROR_CONNECTION_ABORTED, the on_receive_complete callback passed to async_socket_receive_async shall be called with on_receive_complete_context as context, ASYNC_SOCKET_RECEIVE_ABANDONED as result and 0 for bytes_received. ]*/
LogError("Receive IO completed with error %lu (socket seems to be closed)", io_result);
receive_result = ASYNC_SOCKET_RECEIVE_ABANDONED;
bytes_received = 0;
break;
}
case NO_ERROR:
{
bytes_received = (uint32_t)number_of_bytes_transferred;
#ifdef ENABLE_SOCKET_LOGGING
LogVerbose("Asynchronous receive of %" PRIu32 " bytes completed at %lf", bytes_received, timer_global_get_elapsed_us());
#endif
if (bytes_received > io_context->total_buffer_bytes)
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_095: [If io_result is NO_ERROR, but the number of bytes received is greater than the sum of all buffer sizes passed to async_socket_receive_async, the on_receive_complete callback passed to async_socket_receive_async shall be called with on_receive_complete_context as context, ASYNC_SOCKET_RECEIVE_ERROR as result and number_of_bytes_transferred for bytes_received. ]*/
LogError("Invalid number of bytes received: %" PRIu32 " expected max: %" PRIu32,
bytes_received, io_context->total_buffer_bytes);
receive_result = ASYNC_SOCKET_RECEIVE_ERROR;
}
else if (bytes_received == 0)
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_42_003: [ If io_result is NO_ERROR, but the number of bytes received is 0, the on_receive_complete callback passed to async_socket_receive_async shall be called with on_receive_complete_context as context, ASYNC_SOCKET_RECEIVE_ABANDONED as result and 0 for bytes_received. ]*/
LogError("Socket received 0 bytes, assuming socket is closed");
receive_result = ASYNC_SOCKET_RECEIVE_ABANDONED;
}
else
{
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_069: [ If io_result is NO_ERROR, the on_receive_complete callback passed to async_socket_receive_async shall be called with on_receive_complete_context as context, ASYNC_SOCKET_RECEIVE_OK as result and number_of_bytes_transferred as bytes_received. ]*/
receive_result = ASYNC_SOCKET_RECEIVE_OK;
}
break;
}
}
io_context->io.receive.on_receive_complete(io_context->io.receive.on_receive_complete_context, receive_result, bytes_received);
break;
}
}
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_068: [ on_io_complete shall close the event handle created in async_socket_send_async/async_socket_receive_async. ]*/
if (!CloseHandle(io_context->overlapped.hEvent))
{
LogLastError("CloseHandle failed");
}
/* Codes_SRS_ASYNC_SOCKET_WIN32_01_072: [ on_io_complete shall free the IO context. ]*/
free(io_context);
}
}