package IO::Socket::TIPC;
use IO::Socket::TIPC::Sockaddr ':all';
use strict;
use Carp;
use IO::Socket;
use Scalar::Util qw(looks_like_number);
use AutoLoader;
use Exporter;

our @ISA = qw(Exporter IO::Socket);

our $VERSION = '1.05';

=head1 NAME

IO::Socket::TIPC - TIPC sockets for Perl

=head1 SYNOPSIS

	use IO::Socket::TIPC;
	my $sock = IO::Socket::TIPC->new(
		SocketType => "stream",
		Peer       => "{1000, 100}"
	);
	die "Could not connect to {1000, 100}: $!\n" unless $sock;

More in-depth examples are available in the B<EXAMPLES> section, below.


=head1 DESCRIPTION

TIPC stands for Transparent Inter-Process Communication.  See
http://tipc.sf.net/ for details.

This perl module subclasses IO::Socket, in order to use TIPC sockets
in the customary (and convenient) Perl fashion.

TIPC supports 4 types of socket: I<SOCK_STREAM>, I<SOCK_SEQPACKET>,
I<SOCK_RDM> and I<SOCK_DGRAM>.  These are all available through this
perl API, though the usage varies depending on which kind of socket
you use.

I<SOCK_STREAM> and I<SOCK_SEQPACKET> are connection-based sockets.
These sockets are strictly client/server.  For servers, B<new>() will
call B<bind>() for you, to bind to a I<Local>* name, and you then
B<accept>() connections from clients, each of which get their own
socket (returned from B<accept>).  For clients, B<new>() will call
B<connect>() for you, to connect to the specified I<Peer>* name, and
once that succeeds, you can do I/O on the socket directly.  In this
respect, usage details are very similar to I<TCP> over I<IPv4>.

See the B<EXAMPLES> section, for an example of connection-based socket
use.

I<SOCK_RDM> and I<SOCK_DGRAM> are connectionless sockets.  You cannot
use the normal send/recv/print/getline methods on them, because the
network stack will not know which host on the network to send or
receive from.  Instead, once you have called B<new>() to create the
socket, you use B<sendto> and B<recvfrom> to send and receive
individual packets to/from a specified peer, indicated using an
IO::Socket::TIPC::Sockaddr class object.

Connectionless sockets (I<SOCK_RDM> and I<SOCK_DGRAM>) are often
bind()ed to a particular I<Name> or I<Nameseq> address, in order to
allow them to listen for packets sent to a well-known destination
(the I<Name>).  You can use I<LocalName> or I<LocalNameseq> parameters
to B<new>(), to select a name or name-sequence to bind to.  As above,
these parameters internally become I<Name> and I<Nameseq> arguments to
IO::Socket::TIPC::Sockaddr->B<new>(), and the result is passed to
B<bind>().  This is very similar to typical uses of I<UDP> over
I<IPv4>.

Since connectionless sockets are not linked to a particular peer, you
can use B<sendto> to send a packet to some peer with a given Name in
the network, and B<recvfrom> to receive replies from a peer in the
network who sends a packet to your I<Name> (or I<Nameseq>).  You can
also use I<Nameseq> addressses to send multicast packets to *every*
peer with a given name.  Please see the I<Programmers_Guide.txt>
document (linked in B<REFERENCES>) for more details.

See the B<EXAMPLES> section, for an example of connection-less socket
use.

=cut


sub AUTOLOAD {
    # This AUTOLOAD is used to 'autoload' constants from the constant()
    # XS function.

    my $constname;
    our $AUTOLOAD;
    ($constname = $AUTOLOAD) =~ s/.*:://;
    croak "&IO::Socket::TIPC::constant not defined" if $constname eq 'constant';
    my ($error, $val) = constant($constname);
    if ($error) { $val = undef; } # undefined constants just return undef.
    {
	no strict 'refs';
	    *$AUTOLOAD = sub { $val };
    }
    goto &$AUTOLOAD;
}

=head1 CONSTRUCTOR

B<new> returns a TIPC socket object.  This object inherits from
IO::Socket, and thus inherits all the methods of that class.  

This module was modeled specifically after I<IO::Socket::INET>, and
shares some things in common with that class.  Specifically, the
I<Listen> parameter, the I<Peer>* and I<Loca>l* nomenclature, and the
behind-the-scenes calls to B<socket>(), B<bind>(), B<listen>(),
B<connect>(), and so on.

Connection-based sockets (I<SOCK_STREAM> and I<SOCK_SEQPACKET>) come
in "server" and "client" varieties.  To create a server socket,
specify the I<Listen> argument to B<new>().  You can bind a
name to the socket, thus making your server easier to find, by
providing one or more I<Local>* parameters.  To create a client
socket, do B<NOT> provide the I<Listen> argument.  Instead, provide
one or more I<Peer>* parameters, and B<new> will call B<connect>()
for you.

All I<Local>* parameters are passed directly to
IO::Socket::TIPC::Sockaddr->B<new>(), minus the "Local" prefix, and the
resulting sockaddr is passed to B<bind>().  Similarly, all I<Peer>*
parameters are passed directly to IO::Socket::TIPC::Sockaddr->B<new>(),
minus the "Peer" prefix, and the result is passed to B<connect>().  The
keywords I<Local> and I<Peer> themselves become the first string
parameter to IO::Socket::TIPC::Sockaddr->B<new>(); see the
IO::Socket::TIPC::Sockaddr documentation for details.

=head2 ARGUMENTS to new()

=head2 SocketType

This field is B<required>.  It tells the system what type of socket
to use.  The following constants will work, if they were imported:
I<SOCK_STREAM>, I<SOCK_SEQPACKET>, I<SOCK_RDM>, or I<SOCK_DGRAM>.
Otherwise, you can just use the following text strings: "stream",
"seqpacket", "rdm", or "dgram".

=head2 Listen

This field is only valid for connection-based B<SocketType>s.  Its
existence specifies that this is a server socket.  It is common to
also specify some I<Local>* arguments, so B<new>() can B<bind> your
shiny new server socket to a well-known name.

=head2 Importance

This field informs the TIPC network stack  of what priority it should
consider delivering your messages to be.  It corresponds to the 
I<TIPC_IMPORTANCE> option, from B<setsockopt>.  If you provide this
field, ->B<new>() will call B<setsockopt> for you to set the value.

Default is I<TIPC_LOW_IMPORTANCE>.  Valid arguments are any of:

  TIPC_LOW_IMPORTANCE
  TIPC_MEDIUM_IMPORTANCE
  TIPC_HIGH_IMPORTANCE
  TIPC_CRITICAL_IMPORTANCE

See I<Programmers_Guide.txt> (linked in B<REFERENCES>) for details.


=head2 ConnectTimeout

This field specifies the B<connect>() timeout, in milliseconds.  If
you provide this field, ->B<new>() will call B<setsockopt> to set
the I<TIPC_CONN_TIMEOUT> value on your socket.

See I<Programmers_Guide.txt> (linked in B<REFERENCES>) for details.

B<Careful>: I<ConnectTimeout> should not be confused with I<Timeout>,
which is handled internally by IO::Socket and means something else.


=head2 Local*

This field is valid (and recommended) for all connectionless socket
types, and for all servers using connection-type sockets.  The
I<Local>* parameter(s) determine which address your socket will get
B<bind>()ed to.

Any arguments prefixed with "Local" will be passed to
IO::Socket::TIPC::Sockaddr->B<new>(), with the "Local" prefix
removed.  If you specify the word I<Local>, itself, the argument
will be passed as the first string parameter to
IO::Socket::TIPC::Sockaddr->B<new>(); all other I<Local>* arguments
end up in the hash parameter list.  See the documentation for
IO::Socket::TIPC::Sockaddr, for details.  Also, skip to the
B<EXAMPLES> section to see what this stuff looks like.

=head2 Peer*

This field is only valid for B<clients> (as opposed to B<servers>)
using connection-type sockets, and is required for this case.  The
I<Peer>* parameter(s) determine which address your socket will get
B<connect>()ed to.

Any arguments prefixed with "Peer" will be passed to
IO::Socket::TIPC::Sockaddr->B<new>(), with the "Peer" prefix
removed.  If you specify the word I<Peer>, itself, the argument
will be passed as the first string parameter to
IO::Socket::TIPC::Sockaddr->B<new>(); all other I<Peer>* arguments
end up in the hash parameter list.  See the documentation for
IO::Socket::TIPC::Sockaddr, for details.  Also, skip to the
B<EXAMPLES> section to see what this stuff looks like.

=cut

sub new {
	# pass it down to IO::Socket
	my $class = shift;
	return IO::Socket::new($class,@_);
}

sub configure {
	# IO::Socket calls us back via this method call, from IO::Socket->new().
	my($socket, $args) = @_;
	my (%local, %peer, $local, $peer);
	# move Local* args into %local, Peer* args into %peer.
	# keys "Local" and "Peer" themselves go into $local and $peer.
	# These become arguments to IO::Socket::TIPC::Sockaddr->new().
	foreach my $key (sort keys %$args) {
		if($key =~ /^local/i) {
			my $newkey = substr($key,5);
			if(length($newkey)) {
				$local{$newkey} = $$args{$key};
			} else {
				$local = $$args{$key};
			}
			delete($$args{$key});
		}
		if($key =~ /^peer/i) {
			my $newkey = substr($key,4);
			if(length($newkey)) {
				$peer{$newkey} = $$args{$key};
			} else {
				$peer = $$args{$key};
			}
			delete($$args{$key});
		}
	}
	return undef unless fixup_args($args);
	return undef unless enforce_required_args($args);
	my $connectionless = 0;
	my $listener       = 0;
	my $connector      = (scalar keys %peer)  || (defined $peer);
	my $binder         = (scalar keys %local) || (defined $local);
	$listener = 1 if(exists($$args{Listen}) && $$args{Listen});
	unless(looks_like_number($$args{SocketType})) {
		my %socket_types = (
			stream    => SOCK_STREAM,
			seqpacket => SOCK_SEQPACKET,
			rdm       => SOCK_RDM,
			dgram     => SOCK_DGRAM,
		);
		if(exists($socket_types{lc($$args{SocketType})})) {
			$$args{SocketType} = $socket_types{lc($$args{SocketType})};
		} else {
			croak "unknown SocketType $$args{SocketType}!";
		}
		$connectionless = 1 if $$args{SocketType} == SOCK_RDM;
		$connectionless = 1 if $$args{SocketType} == SOCK_DGRAM;
	}
	croak "Connectionless socket types cannot listen(), but you've told me to Listen."
		if($connectionless && $listener);
	croak "Connectionless socket types cannot connect(), but you've given me a Peer address."
		if($connectionless && $connector);
	croak "Listener sockets cannot connect, but you've given me a Peer address."
		if($listener && $connector);
	croak "Connect()ing sockets cannot bind, but you've given me a Local address."
		if($connector && $binder);

	# If we've gotten this far, I figure everything is ok.
	# unless Sockaddr barfs, of course.
	$socket->socket(PF_TIPC(), $$args{SocketType}, 0)
		or croak "Could not create socket: $!";

	# setsockopt/fcntl stuff goes here.
	if(exists $$args{ConnectTimeout}) {
		$socket->setsockopt(SOL_TIPC(), TIPC_CONN_TIMEOUT(), $$args{ConnectTimeout})
			or croak "TIPC_CONN_TIMEOUT: $!";
	}
	if(exists $$args{Importance}) {
		$socket->setsockopt(SOL_TIPC(), TIPC_IMPORTANCE()  , $$args{Importance})
			or croak "TIPC_IMPORTANCE: $!";
	}
	if($binder) {
		my $baddr;
		if(defined($local)) {
			if(ref($local) && ref($local) eq "IO::Socket::TIPC::Sockaddr") {
				$baddr = $local;
			} else {
				$baddr = IO::Socket::TIPC::Sockaddr->new($local, %local);
			}
		} else {
			$baddr = IO::Socket::TIPC::Sockaddr->new(%local);
		}
		$socket->bind($baddr)
			or croak "Could not bind socket: $!";
	}
	if($connector) {
		my $caddr;
		if(defined($peer)) {
			if(ref($peer) && ref($peer) eq "IO::Socket::TIPC::Sockaddr") {
				$caddr = $peer;
			} else {
				$caddr = IO::Socket::TIPC::Sockaddr->new($peer, %peer);
			}
		} else {
			$caddr = IO::Socket::TIPC::Sockaddr->new(%peer);
		}
		$socket->connect($caddr)
			or croak "Could not connect socket: $!";
	}
	if($listener) {
		$socket->listen()
			or croak "Could not listen: $!";
	}
	return $socket;
}

# a "0" denotes an optional value.  a "1" is required.
my %valid_args = (
	Listen     => 0,
	SocketType => 1,
	Importance => 0,
	ConnectTimeout    => 0,
);

sub enforce_required_args {
	my $args = shift;
	foreach my $key (sort keys %$args) {
		if($valid_args{$key}) {
			# argument is required.
			unless(exists($$args{$key})) {
				# argument not provided!
				croak "argument $key is REQUIRED.";
			}
		}
	}
	return 1;
}

sub fixup_args {
	my $args = shift;
	# Validate hash-key arguments to IO::Socket::TIPC->new()
	foreach my $key (sort keys %$args) {
		if(!exists($valid_args{$key})) {
			# This key needs to be fixed up.  Search for it.
			my $lckey = lc($key);
			my $fixed = 0;
			foreach my $goodkey (sort keys %valid_args) {
				if($lckey eq lc($goodkey)) {
					# Found it.  Fix it up.
					$$args{$goodkey} = $$args{$key};
					delete($$args{$key});
					$fixed = 1;
					last;
				}
			}
			croak("unknown argument $key")
				unless $fixed;
		}
	}
	return 1;
}


=head1 METHODS

=head2 sendto(addr, message [, flags])

B<sendto> is used with connectionless sockets, to send a message to a
given address.  The addr parameter should be an
IO::Socket::TIPC::Sockaddr object.

	my $addr = IO::Socket::TIPC::Sockaddr->new("{4242, 100}");
	$sock->sendto($addr, "Hello there!\n");

The third parameter, I<flags>, defaults to 0 when not specified.  The
TIPC I<Programmers_Guide.txt> says: "TIPC supports the I<MSG_DONTWAIT>
flag when sending; all other flags are ignored."

You may have noticed that B<sendto> and the B<send> builtin do more
or less the same thing with the order of arguments changed.  The main
reason to use B<sendto> is because you can pass it a
IO::Socket::TIPC::Sockaddr object directly, where B<send> requires you
to dereference the blessed reference to get at the raw binary "struct
sockaddr_tipc" bits.  So, B<sendto> is just a matter of convenience.

Ironically, this B<sendto> method calls the B<send> builtin, which in
turn calls the C B<sendto> function.

=cut

sub sendto {
	my ($self, $addr, $message, $flags) = @_;
	croak "sendto given an undef message" unless defined $message;
	croak "sendto given a non-address?"
		unless ref($addr) eq "IO::Socket::TIPC::Sockaddr";
	$flags = 0 unless defined $flags;
	return $self->send($message, $flags, $$addr);
}


=head2 recvfrom(buffer [, length [, flags]])

B<recvfrom> is used with connectionless sockets, to receive a message
from a peer.  It returns a IO::Socket::TIPC::Sockaddr object,
containing the address of whoever sent the message.  It will write
the received packet (up to $length bytes) in $buffer.

	my $buffer;
	my $sender = $sock->recvfrom($buffer, 30);
	$sock->sendto($sender, "I got your message.");

The second parameter, I<length>, defaults to I<TIPC_MAX_USER_MSG_SIZE>
when not specified.  The third parameter, I<flags>, defaults to 0 when
not specified.

The TIPC I<Programmers_Guide.txt> says: "TIPC supports the I<MSG_PEEK>
flag when receiving, as well as the I<MSG_WAITALL> flag when receiving
on a I<SOCK_STREAM> socket; all other flags are ignored."

You may have noticed that B<recvfrom> and the B<recv> builtin do
more or less the same thing with the order of arguments changed.
The main reason to use B<recvfrom> is because it will return a
IO::Socket::TIPC::Sockaddr object, where B<recv> just returns a
binary blob containing the C "struct sockaddr_tipc" data, which, by
itself, cannot be inspected or modified.  So, B<recvfrom> is just a
matter of convenience.

Ironically, this B<recvfrom> method calls the B<recv> builtin, which
in turn calls the C B<recvfrom> function.

=cut

sub recvfrom {
	# note: the $buffer argument is written to by recv().
	my ($self, $buffer, $length, $flags) = @_;
	$flags = 0 unless defined $flags;
	$length = TIPC_MAX_USER_MSG_SIZE() unless defined $length;
	croak "how am I supposed to recvfrom() a packet of length 0?"
		unless $length > 0;
	my $rv = $self->recv($_[1], $length, $flags);
	return IO::Socket::TIPC::Sockaddr->new_from_data($rv);
}


=head2 bind(addr)

B<bind> attaches a well-known "name" to an otherwise random (and hard
to find) socket port.  It is possible to bind more than one name to a
socket.  B<bind> is useful for all connectionless sockets, and for 
"server" sockets (the one you get from B<new>(I<Listen> => 1), not the
ones returned from B<accept>).

This method is really just a wrapper around the Perl B<bind> builtin,
which dereferences IO::Socket::TIPC::Sockaddr class instances when
necessary.

=cut

sub bind {
	my ($sock, $addr) = @_;
	$addr = $$addr while ref $addr;
	return $sock->SUPER::bind($addr);
}


=head2 connect(addr)

B<connect> seeks out a server socket (which was B<bind>ed to a 
well-known "name") and connects to it.  B<connect> is only valid for
connection-type sockets which have not already had B<listen> or
B<bind> called on them.  In practice, you should not ever need this
method; B<new> calls it for you when you specify one or more
I<Peer> arguments.

This method is really just a wrapper around the Perl B<connect>
builtin, which dereferences IO::Socket::TIPC::Sockaddr class
instances when necessary.

=cut

sub connect {
	my ($sock, $addr) = @_;
	$addr = $$addr while ref $addr;
	return $sock->SUPER::connect($addr);
}


=head2 getpeername

B<getpeername> returns the sockaddr of the peer you're connected
to.  Compare B<getsockname>.  Use this if you've just B<accept>()ed
a new connection, and you're curious who you're talking to.

	my $client = $server->accept();
	my $caddr = $client->getpeername();
	print("Got connection from ", $caddr->stringify(), "\n");

B<getpeername> doesn't actually return a I<name> sockaddr, it returns
an I<id>.  Thus, B<getpeerid> is an alias for B<getpeername>, to aid
readability.  I<Programmers_Guide.txt> has the following comment: The
use of "name" in getpeername() can be confusing, as the routine does
not actually return the TIPC names or name sequences that have been
bound to the peer socket.

This method is really just a wrapper around the Perl B<getpeername>
builtin, to wrap return values into IO::Socket::TIPC::Sockaddr class
instances for you.


=cut

sub getpeername {
	my ($self) = @_;
	my $rv = CORE::getpeername($self);
	return $rv unless defined $rv;
	return IO::Socket::TIPC::Sockaddr->new_from_data($rv);
}
sub getpeerid { my $self = shift; return $self->getpeername(@_) };

=head2 getsockname

B<getsockname> returns the sockaddr of your own socket, this is the
address your peer sees you coming from.  Compare B<getpeername>.

	my $client = $server->accept();
	my $caddr = $client->getsockname();
	print("The client connected to me as ", $caddr->stringify(), "\n");

B<getsockname> doesn't actually return a I<name> sockaddr, it returns
an I<id>.  Thus, B<getsockid> is an alias for B<getsockname>, to aid
readability.  I<Programmers_Guide.txt> has the following comment: The
use of "name" in getsockname() can be confusing, as the routine does
not actually return the TIPC names or name sequences that have been
bound to the peer socket.

This method is really just a wrapper around the Perl B<getsockname>
builtin, to wrap return values into IO::Socket::TIPC::Sockaddr class
instances for you.


=cut

sub getsockname {
	my ($self) = @_;
	my $rv = CORE::getsockname($self);
	return $rv unless defined $rv;
	return IO::Socket::TIPC::Sockaddr->new_from_data($rv);
}
sub getsockid { my $self = shift; return $self->getsockname(@_) };


=head2 listen

B<listen> tells the operating system that this is a server socket,
and that you will be B<accept>()ing client connections on it.  It is
only valid for connection-type sockets, and only if B<connect> has
not been called on it.  It is much more useful if you have B<bind>ed
the socket to a well-known name; otherwise, most clients will have
difficulty knowing what to B<connect> to.

This module does not actually implement a B<listen> method; when you
call it, you are really just calling the Perl builtin.  See the
perlfunc manpage for more details.

=head2 accept

B<accept> asks the operating system to return a session socket, for
communicating with a client which has just B<connect>ed to you.  It is
only valid for connection-type sockets, which you have previously
called B<listen> on.

This module does not actually implement an B<accept> method; when you
call it, you are really just calling the Perl builtin.  See the
perlfunc manpage for more details.


=head2 getsockopt(level, optname)

Query a socket option.  For TIPC-level stuff, I<level> should be
I<SOL_TIPC>.

The TIPC I<Programmers_Guide.txt> (linked in B<REFERENCES>) says:
	- TIPC does not currently support socket options for level
	  SOL_SOCKET, such as SO_SNDBUF.
	- TIPC does not currently support socket options for level
	  IPPROTO_TCP, such	as TCP_MAXSEG.  Attempting to get the value
	  of these options on a SOCK_STREAM	socket returns the value 0.

See B<setsockopt>(), below, for a list of I<SOL_TIPC> options.

This module does not actually implement a B<getsockopt> method; when
you call it, you are really just calling the Perl builtin.  See the
perlfunc manpage for more details.


=head2 setsockopt(level, optname, optval)

Set a socket option.  For TIPC-level stuff, I<level> should be
I<SOL_TIPC>.

The TIPC I<Programmers_Guide.txt> (linked in B<REFERENCES>) says:
	- TIPC does not currently support socket options for level
	  SOL_SOCKET, such as SO_SNDBUF.
	- TIPC does not currently support socket options for level
	  IPPROTO_TCP, such	as TCP_MAXSEG.  Attempting to get the value
	  of these options on a SOCK_STREAM	socket returns the value 0.

For level I<SOL_TIPC>, the following options are available:

	TIPC_IMPORTANCE
	TIPC_SRC_DROPPABLE
	TIPC_DEST_DROPPABLE
	TIPC_CONN_TIMEOUT

These are documented in detail in I<Programmers_Guide.txt>.  See also,
->B<new>()'s I<Importance> and I<ConnectTimeout> options.

This module does not actually implement a B<setsockopt> method; when
you call it, you are really just calling the Perl builtin.  See the
perlfunc manpage for more details.


=head1 EXAMPLES

Examples of connection-based socket use:

	# SERVER PROCESS
	# create a server listening on Name {4242, 100}.
	$sock1 = IO::Socket::TIPC->new(
		SocketType => "seqpacket",
		Listen => 1,
		Local => "{4242, 100}",
		LocalScope => "zone",
	);
	$client = $sock1->accept();
	# Wait for the client to say something intelligent
	$something_intelligent = $client->getline();


	# CLIENT PROCESS
	# connect to the above server
	$sock2 = IO::Socket::TIPC->new(
		SocketType => "seqpacket",
		Peer => "{4242, 100}",
	);
	# Say something intelligent
	$sock2->print("Dah, he is Olle, you are Sven.\n");
	
Examples of connectionless socket use:

	# NODE 1
	# Create a server listening on Name {4242, 101}.
	$sock1 = IO::Socket::TIPC->new(
		SocketType => "rdm",
		Local => "{4242, 101}",
		LocalScope => "zone",
	);
	$data = "TAG!  You are \"it\".\n";
	# send a hello packet from sock1 to sock2
	$addr2 = IO::Socket::TIPC::Sockaddr->new("{4242, 102}");
	$sock1->sendto($addr2, $data);


	# NODE 2
	# Create another server listening on Name {4242, 102}.
	$sock2 = IO::Socket::TIPC->new(
		SocketType => "rdm",
		Local => "{4242, 102}",
		LocalScope => "zone",
	);
	# receive that first hello packet
	$sender = $sock2->recvfrom($rxdata, 256);
	# Reply
	$sock2->sendto($sender, "Me too.\n");
	
	# send a multicast packet to all sock1s in the world
	$maddr1 = IO::Socket::TIPC::Sockaddr->new("{4242,101,101}");
	$sock2->sendto($maddr2, "My brain hurts!\n");


=head1 EXPORT

None by default.

=head2 Exportable constants and macros

  ":tipc" tag (defines from tipc.h, loosely grouped by function):
  AF_TIPC, PF_TIPC, SOL_TIPC
  TIPC_ADDR_ID, TIPC_ADDR_MCAST, TIPC_ADDR_NAME, TIPC_ADDR_NAMESEQ
  TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, TIPC_NODE_SCOPE
  TIPC_ERRINFO, TIPC_RETDATA, TIPC_DESTNAME
  TIPC_IMPORTANCE, TIPC_SRC_DROPPABLE, TIPC_DEST_DROPPABLE,
  TIPC_CONN_TIMEOUT
  TIPC_LOW_IMPORTANCE, TIPC_MEDIUM_IMPORTANCE, TIPC_HIGH_IMPORTANCE,
  TIPC_CRITICAL_IMPORTANCE
  TIPC_MAX_USER_MSG_SIZE
  TIPC_OK, TIPC_ERR_NO_NAME, TIPC_ERR_NO_NODE, TIPC_ERR_NO_PORT,
  TIPC_ERR_OVERLOAD, TIPC_CONN_SHUTDOWN  
  TIPC_PUBLISHED, TIPC_WITHDRAWN, TIPC_SUBSCR_TIMEOUT
  TIPC_SUB_NO_BIND_EVTS, TIPC_SUB_NO_UNBIND_EVTS,
  TIPC_SUB_PORTS, TIPC_SUB_SERVICE, TIPC_SUB_SINGLE_EVT
  TIPC_CFG_SRV, TIPC_TOP_SRV, TIPC_RESERVED_TYPES
  TIPC_WAIT_FOREVER
  tipc_addr, tipc_zone, tipc_cluster, tipc_node

(Those last 4 are re-exports from the Sockaddr module.  See the
IO::Socket::TIPC::Sockaddr documentation.)

  ":sock" tag (re-exports from IO::Socket):
  SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RDM
  MSG_DONTWAIT, MSG_PEEK, MSG_WAITALL, MSG_CTRUNC

To get all of the above constants, say:

  use IO::Socket::TIPC ":all";

To get all of the tipc stuff, say:

  use IO::Socket::TIPC ":tipc";

To get only the socket stuff, say:

  use IO::Socket::TIPC ":sock";

To get only the constants you plan to use, say something like:

  use IO::Socket::TIPC qw(SOCK_RDM TIPC_NODE_SCOPE TIPC_ADDR_NAMESEQ);

Despite supporting all the above constants, please note that some
effort was made so normal users will never actually need any of
them.  For instance, in place of the I<SOCK_>* socktypes, you can
just specify "stream", "dgram", "seqpacket" or "rdm".  In place
of the I<TIPC_>*I<_SCOPE> defines, given to
IO::Socket::TIPC::Sockaddr->B<new>() as the I<Scope> parameter, you
can simply say I<"zone">, I<"cluster"> or I<"node">.

=cut



use XSLoader;
XSLoader::load('IO::Socket::TIPC', $VERSION);

IO::Socket::TIPC->register_domain(PF_TIPC());

my @TIPC_STUFF = ( qw(
	AF_TIPC PF_TIPC SOL_TIPC TIPC_ADDR_ID TIPC_ADDR_MCAST TIPC_ADDR_NAME
	TIPC_ADDR_NAMESEQ TIPC_CFG_SRV TIPC_CLUSTER_SCOPE TIPC_CONN_SHUTDOWN
	TIPC_CONN_TIMEOUT TIPC_CRITICAL_IMPORTANCE TIPC_DESTNAME
	TIPC_DEST_DROPPABLE TIPC_ERRINFO TIPC_ERR_NO_NAME TIPC_ERR_NO_NODE
	TIPC_ERR_NO_PORT TIPC_ERR_OVERLOAD TIPC_HIGH_IMPORTANCE TIPC_IMPORTANCE
	TIPC_LOW_IMPORTANCE TIPC_MAX_USER_MSG_SIZE TIPC_MEDIUM_IMPORTANCE
	TIPC_NODE_SCOPE TIPC_OK TIPC_PUBLISHED TIPC_RESERVED_TYPES TIPC_RETDATA
	TIPC_SRC_DROPPABLE TIPC_SUBSCR_TIMEOUT TIPC_SUB_NO_BIND_EVTS
	TIPC_SUB_NO_UNBIND_EVTS TIPC_SUB_PORTS TIPC_SUB_SERVICE TIPC_SUB_SINGLE_EVT
	TIPC_TOP_SRV TIPC_WAIT_FOREVER TIPC_WITHDRAWN TIPC_ZONE_SCOPE
	tipc_addr tipc_zone tipc_cluster tipc_node
) );
my @SOCK_STUFF = ( qw(
	SOCK_STREAM SOCK_DGRAM SOCK_SEQPACKET SOCK_RDM
	MSG_DONTWAIT MSG_PEEK MSG_WAITALL MSG_CTRUNC
) );

our @EXPORT    = qw();
our @EXPORT_OK = qw();

our %EXPORT_TAGS = ( 
	'all'  => [ @TIPC_STUFF, @SOCK_STUFF ],
	'tipc' => [ @TIPC_STUFF ],
	'sock' => [ @SOCK_STUFF ],
);
Exporter::export_ok_tags('all');

1;
__END__

=head1 BUGS

Probably many.  Please report any bugs you find to the author.  A TODO file
exists, which lists known unimplemented and broken stuff.


=head1 REFERENCES

See also:

IO::Socket, IO::Socket::TIPC::Sockaddr, http://tipc.sf.net/.

The I<Programmers_Guide.txt> is particularly helpful, and is available
off the SourceForge site.  See http://tipc.sf.net/doc/Programmers_Guide.txt,
or http://tipc.sf.net/documentation.html.


=head1 AUTHOR

Mark Glines <mark-tipc@glines.org>


=head1 ACKNOWLEDGEMENTS

Thanks to Ericcson and Wind River, of course, for open-sourcing their (very
useful!) network code, and performing the enormous maintenance task of getting
it into the stock Linux kernel.  Respect.

More specifically, thanks to the TIPC maintainers, for doing all the work
bringing TIPC to linux, and making all of this possible.  And thanks
especially to Allan Stephens for patiently testing all of my pathetic, 
bug-ridden alpha releases. :)

Hrm, who else... thanks Larry Wall, thanks Linus Torvalds, etc etc, these
ACKNOWLEDGEMENTS sections do tend to drone on and on.


=head1 COPYRIGHT AND LICENSE

This module is licensed under a dual BSD/GPL license, the same terms as TIPC
itself.

=cut
