mirror of
https://github.com/MariaDB/server.git
synced 2025-07-08 17:02:21 +03:00
159 lines
3.2 KiB
Perl
159 lines
3.2 KiB
Perl
package NDB::Util::Socket;
|
|
|
|
use strict;
|
|
use Carp;
|
|
use Symbol;
|
|
use Socket;
|
|
use Errno;
|
|
|
|
require NDB::Util::IO;
|
|
|
|
use vars qw(@ISA);
|
|
@ISA = qw(NDB::Util::IO);
|
|
|
|
# constructors
|
|
|
|
my $log;
|
|
|
|
sub initmodule {
|
|
$log = NDB::Util::Log->instance;
|
|
}
|
|
|
|
NDB::Util::Socket->attributes(
|
|
domain => sub { $_ == PF_INET || $_ == PF_UNIX },
|
|
type => sub { $_ == SOCK_STREAM },
|
|
proto => sub { /^(0|tcp)$/ },
|
|
);
|
|
|
|
sub desc {
|
|
my $socket = shift;
|
|
return $socket->SUPER::desc;
|
|
}
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
@_ % 2 == 0 or confess 0+@_;
|
|
my(%attr) = @_;
|
|
my $socket = $class->SUPER::new(%attr);
|
|
$socket->setdomain($attr{domain})
|
|
or $log->push, return undef;
|
|
$socket->settype($attr{type})
|
|
or $log->push, return undef;
|
|
$socket->setproto($attr{proto})
|
|
or $log->push, return undef;
|
|
my $nproto;
|
|
if ($socket->getproto =~ /^\d+/) {
|
|
$nproto = $socket->getproto;
|
|
}
|
|
else {
|
|
$nproto = getprotobyname($socket->getproto);
|
|
unless (defined($nproto)) {
|
|
$log->put("%s: getprotobyname failed", $socket->getproto);
|
|
return undef;
|
|
}
|
|
}
|
|
my $fh = gensym();
|
|
if (! socket($fh, $socket->getdomain, $socket->gettype, $nproto)) {
|
|
$log->put("create socket failed: $!");
|
|
return undef;
|
|
}
|
|
$socket->setfh($fh)
|
|
or $log->push, return undef;
|
|
return $socket;
|
|
}
|
|
|
|
sub setopt {
|
|
my $socket = shift;
|
|
@_ >= 2 or confess 'oops';
|
|
my $level = shift;
|
|
my $optname = shift;
|
|
my $optval = @_ ? pack("l*", @_) : undef;
|
|
my $fh = $socket->getfh;
|
|
if (! setsockopt($fh, $level, $optname, $optval)) {
|
|
$log->put("setsockopt failed: $!")->push($socket);
|
|
return undef;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub connect {
|
|
my $socket = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($paddr) = @_;
|
|
my $fh = $socket->getfh;
|
|
if (! connect($fh, $paddr)) {
|
|
$log->put("connect failed: $!")->push($socket);
|
|
return undef;
|
|
}
|
|
$log->put("connect done")->push($socket)->debug;
|
|
return 1;
|
|
}
|
|
|
|
sub bind {
|
|
my $socket = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($paddr) = @_;
|
|
my $fh = $socket->getfh;
|
|
if (! bind($fh, $paddr)) {
|
|
$log->put("bind failed: $!")->push($socket);
|
|
return undef;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub listen {
|
|
my $socket = shift;
|
|
@_ == 0 or confess 0+@_;
|
|
my $fh = $socket->getfh;
|
|
if (! listen($fh, SOMAXCONN)) {
|
|
$log->put("listen failed: $!")->push($socket);
|
|
return undef;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub accept {
|
|
my $socket = shift;
|
|
@_ == 1 or confess 0+@_;
|
|
my($timeout) = @_;
|
|
$timeout =~ /^\d+$/ or confess 'oops';
|
|
my $fh = $socket->getfh;
|
|
my $gh = gensym();
|
|
my $paddr;
|
|
eval {
|
|
if ($^O ne 'MSWin32' && $timeout > 0) {
|
|
local $SIG{ALRM} = sub { die("timed out\n") };
|
|
alarm($timeout);
|
|
$paddr = accept($gh, $fh);
|
|
alarm(0);
|
|
}
|
|
else {
|
|
$paddr = accept($gh, $fh);
|
|
}
|
|
};
|
|
if ($@) {
|
|
$log->put("accept failed: $@")->push($socket);
|
|
return undef;
|
|
}
|
|
if (! $paddr) {
|
|
my $errno = 0+$!;
|
|
if ($errno == Errno::EINTR) {
|
|
$log->put("accept interrupted")->push($socket);
|
|
return 0;
|
|
}
|
|
$log->put("accept failed: $!")->push($socket);
|
|
return undef;
|
|
}
|
|
my $csocket = $socket->clone(fh => $gh);
|
|
$csocket->acceptaddr($paddr);
|
|
return $csocket;
|
|
}
|
|
|
|
sub DESTROY {
|
|
my $socket = shift;
|
|
$socket->close;
|
|
}
|
|
|
|
1;
|
|
# vim:set sw=4:
|