+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 2.0.4
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+package Amanda::IPC::Binary;
+use base qw(Exporter);
+use base qw(DynaLoader);
+package Amanda::IPC::Binaryc;
+bootstrap Amanda::IPC::Binary;
+package Amanda::IPC::Binary;
+@EXPORT = qw();
+
+# ---------- BASE METHODS -------------
+
+package Amanda::IPC::Binary;
+
+sub TIEHASH {
+ my ($classname,$obj) = @_;
+ return bless $obj, $classname;
+}
+
+sub CLEAR { }
+
+sub FIRSTKEY { }
+
+sub NEXTKEY { }
+
+sub FETCH {
+ my ($self,$field) = @_;
+ my $member_func = "swig_${field}_get";
+ $self->$member_func();
+}
+
+sub STORE {
+ my ($self,$field,$newval) = @_;
+ my $member_func = "swig_${field}_set";
+ $self->$member_func($newval);
+}
+
+sub this {
+ my $ptr = shift;
+ return tied(%$ptr);
+}
+
+
+# ------- FUNCTION WRAPPERS --------
+
+package Amanda::IPC::Binary;
+
+*ipc_binary_proto_new = *Amanda::IPC::Binaryc::ipc_binary_proto_new;
+*ipc_binary_proto_add_cmd = *Amanda::IPC::Binaryc::ipc_binary_proto_add_cmd;
+*ipc_binary_cmd_add_arg = *Amanda::IPC::Binaryc::ipc_binary_cmd_add_arg;
+*ipc_binary_new_channel = *Amanda::IPC::Binaryc::ipc_binary_new_channel;
+*ipc_binary_free_channel = *Amanda::IPC::Binaryc::ipc_binary_free_channel;
+*ipc_binary_read_message = *Amanda::IPC::Binaryc::ipc_binary_read_message;
+*ipc_binary_write_message = *Amanda::IPC::Binaryc::ipc_binary_write_message;
+*ipc_binary_feed_data = *Amanda::IPC::Binaryc::ipc_binary_feed_data;
+*ipc_binary_data_transmitted = *Amanda::IPC::Binaryc::ipc_binary_data_transmitted;
+*ipc_binary_poll_message = *Amanda::IPC::Binaryc::ipc_binary_poll_message;
+*ipc_binary_queue_message = *Amanda::IPC::Binaryc::ipc_binary_queue_message;
+
+# ------- VARIABLE STUBS --------
+
+package Amanda::IPC::Binary;
+
+*IPC_BINARY_STRING = *Amanda::IPC::Binaryc::IPC_BINARY_STRING;
+*IPC_BINARY_OPTIONAL = *Amanda::IPC::Binaryc::IPC_BINARY_OPTIONAL;
+
+@EXPORT_OK = ();
+%EXPORT_TAGS = ();
+
+
+=head1 NAME
+
+Amanda::IPC::Binary - binary-framed message-based communication
+
+=head1 SYNOPSIS
+
+See below.
+
+=head1 DESCRIPTION
+
+This package is an interface to the C-level protocol library declared in
+C<common-src/ipc-binary.h>. It enables two-way message-based communication,
+using a binary framing that permits direct inclusion of non-string data.
+
+Unlike the line protocol (see L<Amanda::IPC::LineProtocol>), this package does
+not yet support asynchronous operation.
+
+=head2 DEFINING A PROTOCOL
+
+There are two parts to any use of this package. First, define the protocol by
+creating a subclass and populating it. This subclass represents the protocol,
+composed of a set of commands or messages and arguments that are attached to
+those commands.
+
+Begin with the subclass:
+
+ package TestProtocol;
+ use base "Amanda::IPC::Binary";
+ use Amanda::IPC::Binary;
+
+Then define the constants for each command. Note that the C<constant> pragma did
+not support the hash syntax in Perl-5.6, so this must be written as individual
+invocations of the constant:
+
+ use constant CMD1 => 1;
+ use constant CMD2 => 2;
+
+Then the constants for each argument:
+
+ use constant USERNAME => 1;
+ use constant PASSWORD => 2;
+ use constant RESOURCE => 3;
+ use constant USE_OVERDRIVE => 4;
+
+Next, give the magic value for the protocol:
+
+ magic(0x9812);
+
+Then begin defining each command, along with its arguments:
+
+ command(CMD1,
+ RESOURCE, 0,
+ USERNAME, $IPC_BINARY_STRING,
+ PASSWORD, $IPC_BINARY_STRING|$IPC_BINARY_OPTIONAL);
+
+The first argument to C<command> specifies the command ID. The remaining
+arguments are taken in pairs, and specify the argument and a bitfield of
+flags. The available flags are:
+
+ $IPC_BINARY_STRING argument is a printable string
+ $IPC_BINARY_OPTIONAL argument is not required
+
+If $IPC_BINARY_STRING is not specified, the argument can contain any sequence of
+bytes (including nuls). In either case, a perl string is used to represent it.
+
+=head2 USING A PROTOCOL
+
+Once a protocol is defined, it forms a class which can be used to run the
+protocol. Multiple instances of this class can be created to handle
+simultaneous uses of the protocol over different channels.
+
+The constructor takes no parameters, but establishs a new channel, complete with
+buffers for partially-read commands:
+
+ my $chan = TestProtocol->new();
+
+To write a message, call the C<write_message> method, passing a filehandle, a
+command id, and argument/value pairs:
+
+ if (!$chan->write_message($fh, TestProtocol::CMD1,
+ TestProtocol::RESOURCE => $res,
+ TestProtocol::USERNAME => "dustin")) {
+ # ...
+ }
+
+It is not valid to omit an argument value, and all values must be perl strings
+-- C<undef> is not alloewd, even for optional arguments. If C<write_message>
+fails, it returns false and C<$!> is set appropriately. The function does not
+return until the message has been written to the file.
+
+To read a message, call C<read_message>, again passing a filehandle:
+
+ my $msg = $chan->read_message($fh);
+
+Note that this will block until a full message has been read. The resulting
+message object has a C<cmd_id> key that identifies the command and an C<args>
+key that references a list of argument values, keyed by their argument ID:
+
+ if ($msg->{'cmd_id'} == TestProtocol::CMD2) { ... }
+ print $msg->{'args'}[TestProtocol::USERNAME], "\n";
+
+The C<close> method will flush any open buffers and close a channel. In the
+synchronous case, this is essentially a no-op since all output buffers are
+flushed at each call to C<write_message>.
+
+=cut
+
+
+push @EXPORT, qw($IPC_BINARY_STRING $IPC_BINARY_OPTIONAL);
+
+
+use Carp;
+push @EXPORT, qw( magic command new message );
+
+# a map from package name to protocol
+my %protos_by_pkg;
+
+sub magic {
+ my ($magic) = @_;
+ my $caller = caller;
+
+ croak "magic already set for this protocol"
+ if (exists $protos_by_pkg{$caller});
+
+ $protos_by_pkg{$caller} = ipc_binary_proto_new($magic);
+}
+
+sub command {
+ my ($cmd_id, @args) = @_;
+ my $caller = caller;
+
+ croak "magic not set for this protocol"
+ unless (exists $protos_by_pkg{$caller});
+
+ croak "command args must be specified in pairs"
+ unless (@args % 2 == 0);
+
+ my $proto = $protos_by_pkg{$caller};
+ $cmd = ipc_binary_proto_add_cmd($proto, $cmd_id);
+
+ while (@args) {
+ my $arg = shift @args;
+ my $flags = shift @args;
+ ipc_binary_cmd_add_arg($cmd, $arg, $flags);
+ }
+}
+
+##
+# Class Methods
+
+sub new {
+ my $class = shift;
+
+ my $self = bless {
+ chan => ipc_binary_new_channel($protos_by_pkg{$class}),
+ }, $class;
+}
+
+sub message {
+ my $self = shift;
+ my ($cmd_id, @args) = @_;
+
+ $self = bless {
+ cmd_id => $cmd_id,
+ chan => $self->{'chan'},
+ args => [],
+ }, "Amanda::IPC::Binary::Message";
+
+
+ while (@args) {
+ my $arg = shift @args;
+ my $val = shift @args;
+ $self->{'args'}[$arg] = $val;
+ }
+
+ return $self;
+}
+
+sub close {
+ if ($self->{'chan'}) {
+ ipc_binary_free_channel($self->{'chan'});
+ $self->{'chan'} = undef;
+ }
+}
+
+*DESTROY = *close;
+
+##
+# Blocking interface
+
+sub read_message {
+ my $self = shift;
+ my ($fd) = @_;
+
+ return ipc_binary_read_message($self->{'chan'}, $fd);
+}
+
+sub write_message {
+ my $self = shift;
+ my ($fd, $msg) = @_;
+
+ if (ipc_binary_write_message($self->{'chan'}, $fd, $msg) < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+##
+# Nonblocking interface -- TODO
+
+##
+# Message structure
+
+package Amanda::IPC::Binary::Message;
+
+# (constructor is the protocol's C<message> method)
+
+# format:
+# { cmd_id => $cmd_id,
+# chan => $channel,
+# args => [ $arg0, $arg1, .. ],
+# }
+
+sub get_cmd {
+ return $self->{'cmd_id'};
+}
+
+sub get_arg {
+ my ($self, $arg_id) = @_;
+
+ return $self->{'args'}[$arg_id];
+}
+
+sub set_arg {
+ my ($self, $arg_id, $value) = @_;
+ $self->{'args'}[$arg_id] = $value;
+}
+
+package Amanda::IPC::Binary;
+
+1;