-sub _send {
- my ($conn, $flush) = @_;
- my $sock = $conn->{sock};
- return unless defined($sock);
- my ($rq) = $conn->{outqueue};
-
- # If $flush is set, set the socket to blocking, and send all
- # messages in the queue - return only if there's an error
- # If $flush is 0 (deferred mode) make the socket non-blocking, and
- # return to the event loop only after every message, or if it
- # is likely to block in the middle of a message.
-
- $flush ? $conn->set_blocking() : $conn->set_non_blocking();
- my $offset = (exists $conn->{send_offset}) ? $conn->{send_offset} : 0;
-
- while (@$rq) {
- my $msg = $rq->[0];
- my $mlth = length($msg);
- my $bytes_to_write = $mlth - $offset;
- my $bytes_written = 0;
- confess("Negative Length! msg: '$msg' lth: $mlth offset: $offset") if $bytes_to_write < 0;
- while ($bytes_to_write > 0) {
- $bytes_written = syswrite ($sock, $msg,
- $bytes_to_write, $offset);
- if (!defined($bytes_written)) {
- if (_err_will_block($!)) {
- # Should happen only in deferred mode. Record how
- # much we have already sent.
- $conn->{send_offset} = $offset;
- # Event handler should already be set, so we will
- # be called back eventually, and will resume sending
- return 1;
- } else { # Uh, oh
- delete $conn->{send_offset};
- $conn->handle_send_err($!);
- $conn->disconnect;
- return 0; # fail. Message remains in queue ..
- }
- }
- $offset += $bytes_written;
- $bytes_to_write -= $bytes_written;
- }
- delete $conn->{send_offset};
- $offset = 0;
- shift @$rq;
- last unless $flush; # Go back to select and wait
- # for it to fire again.
- }
- # Call me back if queue has not been drained.
- if (@$rq) {
- set_event_handler ($sock, "write" => sub {$conn->_send(0)});
- } else {
- set_event_handler ($sock, "write" => undef);
- }
- 1; # Success
-}
-
-sub _err_will_block {
- if ($blocking_supported) {
- return ($_[0] == EAGAIN());
- }
- return 0;
-}
-sub set_non_blocking { # $conn->set_blocking
- if ($blocking_supported) {
- # preserve other fcntl flags
- my $flags = fcntl ($_[0], F_GETFL(), 0);
- fcntl ($_[0], F_SETFL(), $flags | O_NONBLOCK());
- }
-}
-sub set_blocking {
- if ($blocking_supported) {
- my $flags = fcntl ($_[0], F_GETFL(), 0);
- $flags &= ~O_NONBLOCK(); # Clear blocking, but preserve other flags
- fcntl ($_[0], F_SETFL(), $flags);
- }