0

I'm playing with libuv and I'm trying to have a simple server that listens on localhost and whenever a client connects, just send a "Hello".

The problem is, the server seems to work, but after the first connection the write callback keeps getting called in a loop, never to let go.

Here is a complete code example. What is going wrong?

#include <iostream>
#include <uv.h>

class Server
{
public:
Server() : m_connectionCount(0)
{
    struct sockaddr_in addr;

    int status = uv_tcp_init(uv_default_loop(), &m_socket);
    if(status)
    {
        exit(1);
    }

    uv_ip4_addr("0.0.0.0", 8888, &addr);

    status = uv_tcp_bind(&m_socket, (const struct sockaddr*) &addr, 0);
    if (status)
    {
        exit(1);
    }

    m_socket.data = this;

    status = uv_listen((uv_stream_t*)&m_socket, 128, [](uv_stream_t* server, int status)
    {
        Server* pServer = (Server*)server->data;
        if(pServer->m_connectionCount >= 2)
            return;

        uv_tcp_t* client = &(pServer->m_connections[pServer->m_connectionCount]);
        int error = uv_tcp_init(uv_default_loop(), client);
        if(error)
            exit(1);

        client->data = pServer;

        error = uv_accept(server, (uv_stream_t*)client);
        if(error)
            exit(1);

        auto allocate = [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
        {
            buf->base = (char*)malloc(suggested_size);
            buf->len = suggested_size;
        };

        auto onRead = [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
        {
        };

        error = uv_read_start((uv_stream_t*)client, allocate, onRead);
        if(error)
            return;

        pServer->m_connectionCount++;
        for(size_t i=0; i<pServer->m_connectionCount; ++i)
        {
            uv_stream_t* stream = (uv_stream_t*)&(pServer->m_connections[i]);

            uv_buf_t buffer = {.len = 6, .base = "Hello"};
            uv_write_t req;
            uv_write(&req, stream, &buffer, 1,
                     [](uv_write_t* request, int status)
                     {
                         /*** PROBLEM: After the second client connects this keeps getting called in a loop ... ?***/
                         printf("Write completed\n");
                     });

        }
    });

    if (status)
    {
        exit(1);
    }

    uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}

private:
     uv_tcp_t m_socket;
     uv_tcp_t m_connections[2];
     uint32_t m_connectionCount;
};

int main(int argc, const char * argv[])
{
    Server testServer;
}

P.S. nevermind the leaks and such, this is just put together to illustrate the write callback problem.

bitwise
  • 541
  • 6
  • 16

1 Answers1

0

I figured it out. The problem is that the uv_write_t in the loop needs to be dynamically allocated so that when it goes out of scope it doesn't get deleted. I was (incorrectly) assuming that the request is copied.

Curiously enough the buffer structure does not seem to need to be dynamically allocated.

Posting this if anyone else runs into the issue

bitwise
  • 541
  • 6
  • 16
  • You are correct, the `uv_buf_t` array can be allocated on the stack (and be larger than required) as long as `uv_write` is called in the same scope. I assumed the buffers were like every other libuv object at first and was managing their life cyle. – Seth Dec 08 '16 at 18:31