static VOID WINAPI on_io_complete()

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