int async_socket_notify_io_async()

in linux/src/async_socket_linux.c [855:927]


int async_socket_notify_io_async(ASYNC_SOCKET_HANDLE async_socket, ASYNC_SOCKET_NOTIFY_IO_TYPE io_type, ON_ASYNC_SOCKET_NOTIFY_IO_COMPLETE on_notify_io_complete, void* on_notify_io_complete_context)
{
    int result;

    // Codes_SRS_ASYNC_SOCKET_LINUX_04_012: [ If async_socket is NULL, async_socket_notify_io_async shall fail and return a non-zero value. ]
    // Codes_SRS_ASYNC_SOCKET_LINUX_04_013: [ If on_notify_io_complete is NULL, async_socket_notify_io_async shall fail and return a non-zero value. ]
    // Codes_SRS_ASYNC_SOCKET_LINUX_04_014: [ If io_type has an invalid value, then async_socket_notify_io_async shall fail and return a non-zero value. ]
    // Codes_SRS_ASYNC_SOCKET_LINUX_04_016: [ on_notify_io_complete_context is allowed to be NULL. ]
    if (async_socket == NULL || on_notify_io_complete == NULL || (io_type != ASYNC_SOCKET_NOTIFY_IO_TYPE_IN && io_type != ASYNC_SOCKET_NOTIFY_IO_TYPE_OUT))
    {
        LogError(
            "Invalid arguments: ASYNC_SOCKET_HANDLE async_socket=%p, ASYNC_SOCKET_NOTIFY_IO_TYPE io_type=%" PRI_MU_ENUM
            ", ON_ASYNC_SOCKET_NOTIFY_IO_COMPLETE on_io_complete=%p, void* on_io_complete_context=%p",
            async_socket, MU_ENUM_VALUE(ASYNC_SOCKET_NOTIFY_IO_TYPE, io_type), on_notify_io_complete, on_notify_io_complete_context);
        result = MU_FAILURE;
    }
    else
    {
        (void)interlocked_increment(&async_socket->pending_api_calls);

        // Codes_SRS_ASYNC_SOCKET_LINUX_04_015: [ If the async socket's current state is not ASYNC_SOCKET_LINUX_STATE_OPEN then async_socket_notify_io_async shall fail and return a non-zero value. ]
        ASYNC_SOCKET_LINUX_STATE current_state;
        if ((current_state = interlocked_add(&async_socket->state, 0)) != ASYNC_SOCKET_LINUX_STATE_OPEN)
        {
            LogWarning("Not open, current state is %" PRI_MU_ENUM "", MU_ENUM_VALUE(ASYNC_SOCKET_LINUX_STATE, current_state));
            result = MU_FAILURE;
        }
        else
        {
            // Codes_SRS_ASYNC_SOCKET_LINUX_04_017: [ Otherwise async_socket_notify_io_async shall create a context for the notify where the on_notify_io_complete and on_notify_io_complete_context shall be stored. ]
            ASYNC_SOCKET_IO_CONTEXT* io_context = malloc(sizeof(ASYNC_SOCKET_IO_CONTEXT));
            if (io_context == NULL)
            {
                // Codes_SRS_ASYNC_SOCKET_LINUX_04_020: [ If any error occurs, async_socket_notify_io_async shall fail and return a non-zero value. ]
                LogError("failure in malloc(sizeof(ASYNC_SOCKET_IO_CONTEXT)=%zu) failed", sizeof(ASYNC_SOCKET_IO_CONTEXT));
                result = MU_FAILURE;
            }
            else
            {
                io_context->io_type = ASYNC_SOCKET_IO_TYPE_NOTIFY;
                io_context->on_notify_io_complete = on_notify_io_complete;
                io_context->callback_context = on_notify_io_complete_context;
                io_context->async_socket = async_socket;

                int epoll_op = (io_type == ASYNC_SOCKET_NOTIFY_IO_TYPE_IN) ? EPOLLIN : EPOLLOUT;

                // Codes_SRS_ASYNC_SOCKET_LINUX_04_018: [ Then the context shall then be added to the completion port system by calling completion_port_add with EPOLLIN if io_type is ASYNC_SOCKET_NOTIFY_IO_TYPE_IN and EPOLLOUT otherwise and event_complete_callback as the callback. ]
                if (completion_port_add(async_socket->completion_port, epoll_op, async_socket->socket_handle, event_complete_callback, io_context) != 0)
                {
                    // Codes_SRS_ASYNC_SOCKET_LINUX_04_020: [ If any error occurs, async_socket_notify_io_async shall fail and return a non-zero value. ]
                    LogWarning("failure with completion_port_add");
                    result = MU_FAILURE;
                }
                else
                {
                    // Codes_SRS_ASYNC_SOCKET_LINUX_04_019: [ On success, async_socket_notify_io_async shall return 0. ]
                    result = 0;
                    (void)interlocked_increment(&async_socket->added_to_completion_port);
                    goto all_ok;
                }

                free(io_context);
            }
        }
all_ok:
        if (interlocked_decrement(&async_socket->pending_api_calls) == 0)
        {
            wake_by_address_single(&async_socket->pending_api_calls);
        }
    }

    return result;
}