Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

please implement fdwait(FDW_ERR) #183

Open
majek opened this issue Feb 22, 2018 · 0 comments
Open

please implement fdwait(FDW_ERR) #183

majek opened this issue Feb 22, 2018 · 0 comments

Comments

@majek
Copy link

majek commented Feb 22, 2018

I'm writing a simple TCP proxy. It's a pleasure to do that with libmill. But there is a corner case.

The design of proxy is rather straightforward. For every proxied connection I run something like this:

        cd = connection_to_client;
        rs  = connection_to_server;
	go(do_proxy_half_duplex(cd, rs, ch));
	go(do_proxy_half_duplex(rs, cd, ch));

Where the do_proxy_half_duplex is:

coroutine void do_proxy_half_duplex(int a, int b, chan ch)
{
	int err = 0;
	while (1) {
		char buf[BUF_SIZE];
		int more = 0;
		size_t nbytes = tcprecvpkt(a, buf, sizeof(buf), -1, &more);
		if (errno != 0) {
			err = errno;
			goto out;
		}

		size_t p = 0;
		while (p < nbytes) {
			size_t r = tcpsendpkt(b, &buf[p], nbytes - p, -1, more);
			if (errno != 0) {
				err = errno;
				goto out;
			}
			p += r;
		}
	}
out:
	if (err == ECONNRESET) {
		shutdown(a, SHUT_RDWR);
		shutdown(b, SHUT_RDWR);
	} else {
		shutdown(a, SHUT_RD);
		shutdown(b, SHUT_WR);
	}
	chs(ch, int, err);
}

It really can't be much simpler. One coroutine reads from the client and writes to the server. Another reads from the server and writes to the client. Tadam.

But there is an issue. Imagine a case that server does not do read() and client does fill the buffers with write().

In such case we have:

  • first coroutine is stuck on write(to_the_server)
  • second coroutine is stuck on read(from_the_server)

The problem? Client connection my ECONNRESET and go away and we won't notice!

Solution: I think the right solution is to start another coroutine that would wait on fdwait(FDW_ERR) and force shutdown() on both connections in case any ECONNRESETS.

Sadly, libmill doesn't allow me to run coroutine and hang on fdwait(FDW_ERR) only in current implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant