ibc / AsyncEngine

Ruby asynchronous event driven framework on top of libuv
6 stars 1 forks source link

libuv TCP considerations #16

Open ibc opened 12 years ago

ibc commented 12 years ago

From the IRC:

[15:16:32]  is it possible for a TCP write req to fail (callback with error) while the
connection remains alive?
[15:17:04]  ibc: well, yes that's possible in theory
[15:17:09]  although unlikely
[15:17:16]  in which cases?
[15:17:49]  ibc: hmm, when the os is very low on resources for example
[15:18:22]  ibc: but for all intents and purposes you should just assume
that a socket is dead when uv_write() fails
[15:18:41]  so the callback error status says us that the data could not be sent, but the
socket remains connected, am I right?  If so, which ERRNO would UV generate in the write
callback?
[15:19:19]  ibc: that's not defined. The errno is just whatever the actual
error is that happened :-0
[15:19:30]  yes, but in my case I always enable "receiving" so the way in which
I expect to detect that the socket is dead is by receiving nread=-1 in read callback, hope
this is right
[15:20:10]  ibc: yes, I think that's okay
[15:20:31]  thanks a lot
[15:20:33]  ibc: alternatively you could just cut the connection whenever 
the write fails
[15:20:41]  is that safe then?
[15:21:02]  ibc: so
[15:21:02]  if (status == -1) {
[15:21:02]    if (!uv_is_closing(handle)) uv_close(handle, close_cb);
[15:21:02]  }
[15:21:11]  oh I forgot "return"
[15:21:30]  if for example I try to send lot of data over a slow socket, couldn't the
Kernel return error once its buffer is full or whatever?
[15:21:31]  ibc: the same would be in the recv callback although you 
should probably check the buf and free it if appropriate
[15:21:50]  ibc: yes the kernel could do that, but libuv normally handles
that
[15:21:57]  ok
[15:22:24]  the typical error you would get is EAGAIN, and libuv will
make sure to attempt to send it at a later point in time
[15:22:31]  (this is more or less the purpose of libuv in the first place)
[15:22:51]  about the recv callback, I assume that if I receive nread=-1 it means
that data has NOT been received, so my read_alloc cb has not been called and I
don't have to free the buf, am  I wrong?
[15:23:04]  ibc: that's not correct
[15:23:12]  sure, I understand, and yes, I hope libuv does that for me :)
[15:23:14]  ibc: it *may* be called
[15:23:58]  ibc: in case your alloc cb was not called buf.base will be NULL
and buf.len will be 0
[15:24:20]  ibc: so you can just check that.
[15:24:35]  aja, good point! otherwise I should mantain some kind of state!
[15:24:54]  ibc: this behaviour is guaranteed
[15:25:02]  so you can just rely on it
ibc commented 12 years ago

NOTE: Check the same in UDP !

ibc commented 12 years ago

More stuf about TCP for receiving and disconnection:

[18:18:41]  hi, easy question (I think there must be some bug in my code):
[18:19:42]  outbound TCP connection done and I call uv_close(handle),
should the read cb be called with nread==-1 or not?
[18:23:26]  note: in my question I did start_read()
[18:23:48]  ibc: no.
[18:23:55]  ibc: uv_close will implicitly call read_stop
[18:24:06]  ibc: but in theory it may make the read callback once more
with nread==0
[18:24:22]  which might happen if it already called alloc_cb and wants
you to give the buffer bacl
[18:24:31]  "it may" does not seem a very robust mechanism :)
[18:24:40]  aha, I understand
[18:25:15]  so if I call uv_close() in a connected socket, then I should call my
"on_disconnection" callback by myself, am I right?
[18:25:43]  ibc: ehm... yes, if that's what you want to do :-)
[18:25:53]  clear, thanks a lot
[18:26:07]  ibc: normally you'll get -1/UV_EOF only if the remote
gracefully closed the connection

[19:11:02]  hi, can I be sure that if I call uv_close() for a established connection,
I won't be called to read cb with nread==-1 ?
[19:11:43]  I do know that it should not occur, I just want to be sure that it will
never happen
[19:14:42]  ibc: should not happen.
ibc commented 12 years ago

Consider this also (found in a UV test unit):

    if (req->handle->write_queue_size >= size * 2) {
      break;
    }