int32_t
ppb_host_resolver_resolve(PP_Resource host_resolver, const char *host, uint16_t port,
                          const struct PP_HostResolver_Private_Hint *hint,
                          struct PP_CompletionCallback callback)
{
    struct pp_host_resolver_s *hr = pp_resource_acquire(host_resolver, PP_RESOURCE_HOST_RESOLVER);
    if (!hr) {
        trace_error("%s, bad resource\n", __func__);
        return PP_ERROR_BADRESOURCE;
    }

    hr->host = nullsafe_strdup(host);

    struct async_network_task_s *task = async_network_task_create();

    task->type =        ASYNC_NETWORK_HOST_RESOLVE;
    task->resource =    host_resolver;
    task->host =        nullsafe_strdup(host);
    task->port =        port;
    task->callback =    callback;
    task->callback_ml = ppb_message_loop_get_current();

    pp_resource_release(host_resolver);
    async_network_task_push(task);

    return PP_OK_COMPLETIONPENDING;
}
void
ppb_tcp_socket_destroy(void *ptr)
{
    struct pp_tcp_socket_s *ts = ptr;
    if (!ts->destroyed) {
        struct async_network_task_s *task = async_network_task_create();

        ts->destroyed = 1;
        ts->is_connected = 0;

        task->type = ASYNC_NETWORK_DISCONNECT;
        task->resource = ts->self_id;
        task->sock = ts->sock;
        async_network_task_push(task);
    }
}
int32_t
ppb_tcp_socket_private_read(PP_Resource tcp_socket, char *buffer, int32_t bytes_to_read,
                            struct PP_CompletionCallback callback)
{
    if (bytes_to_read <= 0) {
        trace_error("%s, bytes_to_read <= 0\n", __func__);
        return PP_ERROR_BADARGUMENT;
    }

    struct pp_tcp_socket_s *ts = pp_resource_acquire(tcp_socket, PP_RESOURCE_TCP_SOCKET);
    if (!ts) {
        trace_error("%s, bad resource\n", __func__);
        return PP_ERROR_BADRESOURCE;
    }

    if (!ts->is_connected) {
        trace_error("%s, not connected\n", __func__);
        pp_resource_release(tcp_socket);
        return PP_ERROR_FAILED;
    }

    if (ts->seen_eof) {
        trace_error("%s, seen eof\n", __func__);
        pp_resource_release(tcp_socket);
        return PP_ERROR_FAILED;
    }

    if (bytes_to_read > 1024 * 1024)
        bytes_to_read = 1024 * 1024;

    struct async_network_task_s *task = async_network_task_create();

    task->type = ASYNC_NETWORK_TCP_READ;
    task->resource = tcp_socket;
    task->instance = ts->instance;
    task->buffer = buffer;
    task->bufsize = bytes_to_read;
    task->callback = callback;
    pp_resource_release(tcp_socket);

    async_network_task_push(task);
    return PP_OK_COMPLETIONPENDING;
}
int32_t
ppb_tcp_socket_connect(PP_Resource tcp_socket, const char *host, uint16_t port,
                       struct PP_CompletionCallback callback)
{
    struct pp_tcp_socket_s *ts = pp_resource_acquire(tcp_socket, PP_RESOURCE_TCP_SOCKET);
    if (!ts) {
        trace_error("%s, bad resource\n", __func__);
        return PP_ERROR_BADRESOURCE;
    }
    struct async_network_task_s *task = async_network_task_create();

    task->type = ASYNC_NETWORK_TCP_CONNECT;
    task->resource = tcp_socket;
    task->sock = ts->sock;
    task->host = nullsafe_strdup(host);
    task->port = port;
    task->callback = callback;
    pp_resource_release(tcp_socket);

    async_network_task_push(task);
    return PP_OK_COMPLETIONPENDING;
}
int32_t
ppb_tcp_socket_connect_with_net_address(PP_Resource tcp_socket,
                                        const struct PP_NetAddress_Private *addr,
                                        struct PP_CompletionCallback callback)
{
    struct pp_tcp_socket_s *ts = pp_resource_acquire(tcp_socket, PP_RESOURCE_TCP_SOCKET);
    if (!ts) {
        trace_error("%s, bad resource\n", __func__);
        return PP_ERROR_BADRESOURCE;
    }
    struct async_network_task_s *task = async_network_task_create();

    task->type = ASYNC_NETWORK_TCP_CONNECT_WITH_NETADDRESS;
    task->resource = tcp_socket;
    task->sock = ts->sock;
    task->netaddr = *addr;
    task->callback = callback;
    pp_resource_release(tcp_socket);

    async_network_task_push(task);
    return PP_OK_COMPLETIONPENDING;
}