2 * Copyright (c) 2009-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 %module "Amanda::IPC::Binary"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
25 %include "Amanda/IPC/Binary.pod"
29 #include "ipc-binary.h"
35 typedef struct ipc_binary_proto_t ipc_binary_proto_t;
36 typedef struct ipc_binary_cmd_t ipc_binary_cmd_t;
37 typedef struct ipc_binary_channel_t ipc_binary_channel_t;
38 typedef struct ipc_binary_message_t ipc_binary_message_t;
44 %typemap(out) ipc_binary_message_t * {
45 static HV *amanda_xfer_msg_stash = NULL;
53 rv = newRV_noinc((SV *)hash);
55 /* bless the rv as an Amanda::Xfer::Msg object */
56 if (!amanda_xfer_msg_stash) {
57 amanda_xfer_msg_stash = gv_stashpv("Amanda::IPC::Binary::Message", GV_ADD);
59 sv_bless(rv, amanda_xfer_msg_stash);
62 hv_store(hash, "cmd_id", 6, newSViv($1->cmd_id), 0);
63 hv_store(hash, "args", 4, newRV_noinc((SV *)args), 0);
65 /* loop over all messages, using av_store to insert the args which are present;
66 * this will fill in undef's where necessary */
67 for (i = 0; i < $1->n_args; i++) {
68 if ($1->args[i].data == NULL)
72 av_store(args, i, newSVpvn($1->args[i].data, $1->args[i].len)));
75 /* we don't need the C data any more */
76 ipc_binary_free_message($1);
83 %typemap(in) ipc_binary_message_t * {
88 ipc_binary_channel_t *chan = NULL;
89 ipc_binary_message_t *msg;
92 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVHV
93 || !sv_isa($input, "Amanda::IPC::Binary::Message"))
94 SWIG_exception(SWIG_TypeError, "Expected an Amanda::IPC::Binary::Message");
96 hv = (HV *)SvRV($input);
99 svp = hv_fetch(hv, "cmd_id", 6, FALSE);
100 if (!svp || !SvIOK(*svp))
101 SWIG_exception(SWIG_TypeError, "'cmd_id' key missing or not numeric");
105 svp = hv_fetch(hv, "chan", 4, FALSE);
106 if (!svp || SWIG_ConvertPtr(*svp, (void **)&chan,
107 $descriptor(ipc_binary_channel_t *), 0) == -1
109 SWIG_exception(SWIG_TypeError, "'chan' key missing or incorrect");
112 svp = hv_fetch(hv, "args", 4, FALSE);
113 if (!svp || !SvROK(*svp) || SvTYPE(SvRV(*svp)) != SVt_PVAV)
114 SWIG_exception(SWIG_TypeError, "'args' key missing or not an arrayref");
115 av = (AV *)SvRV(*svp);
117 msg = ipc_binary_new_message(chan, cmd_id);
120 for (i = 0; i <= len; i++) {
121 SV **elt = av_fetch(av, i, 0);
125 if (elt && SvPOK(*elt)) {
126 data = (gpointer)SvPV(*elt, datasize);
127 ipc_binary_add_arg(msg, i, datasize, data, 0);
138 ipc_binary_proto_t *ipc_binary_proto_new(
141 ipc_binary_cmd_t *ipc_binary_proto_add_cmd(
142 ipc_binary_proto_t *proto,
145 void ipc_binary_cmd_add_arg(
146 ipc_binary_cmd_t *cmd,
150 /* flag symbols for use in perl; values don't matter */
156 $IPC_BINARY_STRING $IPC_BINARY_OPTIONAL);
158 ipc_binary_channel_t *ipc_binary_new_channel(
159 ipc_binary_proto_t *proto);
161 void ipc_binary_free_channel(
162 ipc_binary_channel_t *channel);
164 ipc_binary_message_t *ipc_binary_read_message(
165 ipc_binary_channel_t *chan,
168 int ipc_binary_write_message(
169 ipc_binary_channel_t *chan,
171 ipc_binary_message_t *msg);
173 void ipc_binary_feed_data(
174 ipc_binary_channel_t *chan,
178 void ipc_binary_data_transmitted(
179 ipc_binary_channel_t *chan,
182 ipc_binary_message_t *ipc_binary_poll_message(
183 ipc_binary_channel_t *chan);
185 void ipc_binary_queue_message(
186 ipc_binary_channel_t *chan,
187 ipc_binary_message_t *msg);
197 push @EXPORT, qw( magic command new message );
199 # a map from package name to protocol
206 croak "magic already set for this protocol"
207 if (exists $protos_by_pkg{$caller});
209 $protos_by_pkg{$caller} = ipc_binary_proto_new($magic);
213 my ($cmd_id, @args) = @_;
216 croak "magic not set for this protocol"
217 unless (exists $protos_by_pkg{$caller});
219 croak "command args must be specified in pairs"
220 unless (@args % 2 == 0);
222 my $proto = $protos_by_pkg{$caller};
223 $cmd = ipc_binary_proto_add_cmd($proto, $cmd_id);
226 my $arg = shift @args;
227 my $flags = shift @args;
228 ipc_binary_cmd_add_arg($cmd, $arg, $flags);
239 chan => ipc_binary_new_channel($protos_by_pkg{$class}),
245 my ($cmd_id, @args) = @_;
249 chan => $self->{'chan'},
251 }, "Amanda::IPC::Binary::Message";
255 my $arg = shift @args;
256 my $val = shift @args;
257 $self->{'args'}[$arg] = $val;
264 if ($self->{'chan'}) {
265 ipc_binary_free_channel($self->{'chan'});
266 $self->{'chan'} = undef;
279 return ipc_binary_read_message($self->{'chan'}, $fd);
286 if (ipc_binary_write_message($self->{'chan'}, $fd, $msg) < 0) {
293 # Nonblocking interface -- TODO
298 package Amanda::IPC::Binary::Message;
300 # (constructor is the protocol's C<message> method)
303 # { cmd_id => $cmd_id,
305 # args => [ $arg0, $arg1, .. ],
309 return $self->{'cmd_id'};
313 my ($self, $arg_id) = @_;
315 return $self->{'args'}[$arg_id];
319 my ($self, $arg_id, $value) = @_;
320 $self->{'args'}[$arg_id] = $value;
323 package Amanda::IPC::Binary;