Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

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
This page is out of date. Refresh to see the latest.
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.