Skip to content

Loading…

I have added 'connected' method to Feersum::Connection::Handle #11

Closed
wants to merge 3 commits into from

2 participants

@luben

It is standard feature for socket handles. I find it useful in order to clean up connections closed from clients. It is meaningful only on write handles but I do not know how to make work only on writers.

@stash
Owner

Hi,

Thanks for sending me a pull request! :)

Even though getpeername() can result in ENOTCONN, I'm pretty sure that the only reliable way to test if a socket is "connected" is to try write to it and detect EPIPE/ENOTCONN/etc. That being said, if you know that getpeername() works cross-platform and can point me to some documentation, I'd stand happily corrected.

If you could also add unit tests and documentation to Feersum::Connection::Handle, I'd appreciate it.

Cheers,
~stash

@luben

I have looked in IO::Socket and it uses getpeername. This does not detect sockets in CLOSE_WAIT state but detects sockets that look like this in lsof output:

perl 5455 nobody 2183u sock 0,5 0t0 122379659 can't identify protocol

I suspect that after some time (tcp timeout maybe) sockets in CLOSE_WAIT state are closed and not associated with TCP any more.

I have tried another approach: use recv with MSG_PEEK in order to see if the socket is in CLOSE_WAIT state. It works but I am not sure how cross-platform it is. Also the current approach with getpeername is consistent with IO::Socket so it is least surprising option.

I will write docs for the feature. Also I will write test for the connected state, it will be difficult to test disconnected state.

I will ping you with another pull request for docs and tests.

Best regards
luben

@luben

I have added the test and documentation.

@luben luben closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Showing with 29 additions and 1 deletion.
  1. +18 −0 Feersum.xs
  2. +9 −0 lib/Feersum/Connection/Handle.pm
  3. +2 −1 t/05-streaming.t
View
18 Feersum.xs
@@ -2511,6 +2511,24 @@ seek (feer_conn_handle *hdl, ssize_t offset, ...)
RETVAL
int
+connected (feer_conn_handle *hdl)
+ PROTOTYPE: $
+ CODE:
+{
+ assert(ix);
+ socklen_t addrlen;
+ int res;
+ res = getpeername(hdl->fd, hdl->sa, &addrlen);
+ if (res == 0) {
+ RETVAL = 1;
+ } else {
+ RETVAL = 0;
+ }
+}
+ OUTPUT:
+ RETVAL
+
+int
close (feer_conn_handle *hdl)
PROTOTYPE: $
ALIAS:
View
9 lib/Feersum/Connection/Handle.pm
@@ -57,6 +57,8 @@ For write handles:
$w->poll_cb(sub {
# use $_[0] instead of $w to avoid a closure
$_[0]->write(\"some data");
+ # check if the socket is connected
+ $_[0]->connected();
# can close() or unregister the poll_cb in here
$_[0]->close();
});
@@ -138,6 +140,13 @@ Pass in an array-ref and it works much like the two C<write()> calls above,
except it's way more efficient than calling C<write()> over and over.
Undefined elements of the array are ignored.
+=item C<< $w->connected() >>
+
+Uses getpeername in order to determine if the underlying socket is connected.
+It will return true even if the socket is in CLOSE_WAIT state. If the TCP
+socket is closed (after TCP timeout) by the system it will return false
+value. The implementations is consistent with IO::Handle.
+
=item C<< $w->close() >>
Close the HTTP response (which triggers the "T-E: chunked" terminating chunk
View
3 t/05-streaming.t
@@ -5,7 +5,7 @@ use constant HARDER => $ENV{RELEASE_TESTING} ? 10 : 1;
use constant CLIENTS_11 => HARDER * 2;
use constant CLIENTS_10 => HARDER * 2;
use constant CLIENTS => CLIENTS_11 + CLIENTS_10;
-use Test::More tests => 7 + 21 * CLIENTS_11 + 22 * CLIENTS_10;
+use Test::More tests => 7 + 22 * CLIENTS_11 + 23 * CLIENTS_10;
use Test::Fatal;
use lib 't'; use Utils;
@@ -45,6 +45,7 @@ $evh->request_handler(sub {
$started++;
isa_ok($w, 'Feersum::Connection::Writer', "got a writer $cnum");
isa_ok($w, 'Feersum::Connection::Handle', "... it's a handle $cnum");
+ ok $w->connected, "connected method works on write handle";
my $n = 0;
my $wrote_third = 0;
my $t; $t = AE::timer rand()/5,rand()/5, sub {
Something went wrong with that request. Please try again.