admin管理员组

文章数量:1319483

I'm making a simple socket proxy with GCD APIs, after my proxy server accepts() the client and connects() to the requested host, I'm forwarding data between them like this:

static void proxy_forward_fd(dispatch_queue_t queue, int fd_client, int fd_proxy) {
    dispatch_io_t io_client = dispatch_io_create(DISPATCH_IO_STREAM, fd_client, queue, ^(int error) {
        if (error) {
            printf("Error creating client IO for FD %d: %s (%d)\n", fd_client, strerror(error), error);
        }
        
        printf("Closing client FD %d\n", fd_client);
        close(fd_client);
    });

    dispatch_io_t io_proxy = dispatch_io_create(DISPATCH_IO_STREAM, fd_proxy, queue, ^(int error) {
        if (error) {
            printf("Error creating proxy IO for FD %d: %s (%d)\n", fd_proxy, strerror(error), error);
        }
        
        printf("Closing proxy FD %d\n", fd_proxy);
        close(fd_proxy);
    });

    dispatch_io_set_low_water(io_client, 1);
    dispatch_io_set_low_water(io_proxy, 1);

    dispatch_io_read(io_client, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error) {
        if (error) {
            printf("Error reading client IO for FD %d: %s (%d)\n", fd_client, strerror(error), error);
        }

        printf("Client (done=%d, data=%zu, error=%d)\n", done, data ? dispatch_data_get_size(data) : 0, error);

        // Client is sending data to proxy
        if (data) {
            dispatch_io_write(io_proxy, 0, data, queue, ^(bool done, dispatch_data_t data, int error) {});
        }

        // Client EOF, close both
        if (done) {
            dispatch_io_close(io_client, 0);
            dispatch_io_close(io_proxy, 0);
        }
    });

    dispatch_io_read(io_proxy, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error) {
        if (error) {
            printf("Error reading proxy IO for FD %d: %s (%d)\n", fd_proxy, strerror(error), error);
        }

        printf("Proxy (done=%d, data=%zu, error=%d)\n", done, data ? dispatch_data_get_size(data) : 0, error);

        // Proxy is sending data to client
        if (data) {
            dispatch_io_write(io_client, 0, data, queue, ^(bool done, dispatch_data_t data, int error) {});
        }
        
        // Proxy EOF, close both
        if (done) {
            dispatch_io_close(io_client, 0);
            dispatch_io_close(io_proxy, 0);
        }
    });
}

I'm testing this by sending a request to an HTTP server (python3 -mhttp.server --bind 127.0.0.1), the data is received but the client's end is never closed until the client itself disconnects:

Accepted client (fd=4)
Connected to proxy (fd=5)
Proxying (client_fd=4, proxy_fd=5)
Client (fd=4, done=0, data=18, error=0) # Sends "GET / HTTP/1.1\r\n\r\n"
Proxy (fd=5, done=0, data=936, error=0) # Sends "HTTP/1.1 200 OK..."
Proxy (fd=5, done=1, data=0, error=0) # Closes connection
Closing proxy (fd=5) # dispatch_io_close(io_proxy)
# Closing client never happens until client disconnects

If I add DISPATCH_IO_STOP flag to both of my dispatch_io_close calls, then it closes but data is not received by the client (it closes before write is finished).

Why is that and what is the correct way to implement a socket proxy with GCD?

本文标签: macosGCD dispatchioclose not closing IOStack Overflow