2 * Copyright (c) 2009-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
22 %module "Amanda::IPC::Binary"
23 %include "amglue/amglue.swg"
24 %include "exception.i"
26 %include "Amanda/IPC/Binary.pod"
30 #include "ipc-binary.h"
36 typedef struct ipc_binary_proto_t ipc_binary_proto_t;
37 typedef struct ipc_binary_cmd_t ipc_binary_cmd_t;
38 typedef struct ipc_binary_channel_t ipc_binary_channel_t;
39 typedef struct ipc_binary_message_t ipc_binary_message_t;
45 %typemap(out) ipc_binary_message_t * {
46 static HV *amanda_xfer_msg_stash = NULL;
54 rv = newRV_noinc((SV *)hash);
56 /* bless the rv as an Amanda::Xfer::Msg object */
57 if (!amanda_xfer_msg_stash) {
58 amanda_xfer_msg_stash = gv_stashpv("Amanda::IPC::Binary::Message", GV_ADD);
60 sv_bless(rv, amanda_xfer_msg_stash);
63 hv_store(hash, "cmd_id", 6, newSViv($1->cmd_id), 0);
64 hv_store(hash, "args", 4, newRV_noinc((SV *)args), 0);
66 /* loop over all messages, using av_store to insert the args which are present;
67 * this will fill in undef's where necessary */
68 for (i = 0; i < $1->n_args; i++) {
69 if ($1->args[i].data == NULL)
73 av_store(args, i, newSVpvn($1->args[i].data, $1->args[i].len)));
76 /* we don't need the C data any more */
77 ipc_binary_free_message($1);
84 %typemap(in) ipc_binary_message_t * {
89 ipc_binary_channel_t *chan = NULL;
90 ipc_binary_message_t *msg;
93 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVHV
94 || !sv_isa($input, "Amanda::IPC::Binary::Message"))
95 SWIG_exception(SWIG_TypeError, "Expected an Amanda::IPC::Binary::Message");
97 hv = (HV *)SvRV($input);
100 svp = hv_fetch(hv, "cmd_id", 6, FALSE);
101 if (!svp || !SvIOK(*svp))
102 SWIG_exception(SWIG_TypeError, "'cmd_id' key missing or not numeric");
106 svp = hv_fetch(hv, "chan", 4, FALSE);
107 if (!svp || SWIG_ConvertPtr(*svp, (void **)&chan,
108 $descriptor(ipc_binary_channel_t *), 0) == -1
110 SWIG_exception(SWIG_TypeError, "'chan' key missing or incorrect");
113 svp = hv_fetch(hv, "args", 4, FALSE);
114 if (!svp || !SvROK(*svp) || SvTYPE(SvRV(*svp)) != SVt_PVAV)
115 SWIG_exception(SWIG_TypeError, "'args' key missing or not an arrayref");
116 av = (AV *)SvRV(*svp);
118 msg = ipc_binary_new_message(chan, cmd_id);
121 for (i = 0; i <= len; i++) {
122 SV **elt = av_fetch(av, i, 0);
126 if (elt && SvPOK(*elt)) {
127 data = (gpointer)SvPV(*elt, datasize);
128 ipc_binary_add_arg(msg, i, datasize, data, 0);
139 ipc_binary_proto_t *ipc_binary_proto_new(
142 ipc_binary_cmd_t *ipc_binary_proto_add_cmd(
143 ipc_binary_proto_t *proto,
146 void ipc_binary_cmd_add_arg(
147 ipc_binary_cmd_t *cmd,
151 /* flag symbols for use in perl; values don't matter */
157 $IPC_BINARY_STRING $IPC_BINARY_OPTIONAL);
159 ipc_binary_channel_t *ipc_binary_new_channel(
160 ipc_binary_proto_t *proto);
162 void ipc_binary_free_channel(
163 ipc_binary_channel_t *channel);
165 ipc_binary_message_t *ipc_binary_read_message(
166 ipc_binary_channel_t *chan,
169 int ipc_binary_write_message(
170 ipc_binary_channel_t *chan,
172 ipc_binary_message_t *msg);
174 void ipc_binary_feed_data(
175 ipc_binary_channel_t *chan,
179 void ipc_binary_data_transmitted(
180 ipc_binary_channel_t *chan,
183 ipc_binary_message_t *ipc_binary_poll_message(
184 ipc_binary_channel_t *chan);
186 void ipc_binary_queue_message(
187 ipc_binary_channel_t *chan,
188 ipc_binary_message_t *msg);
198 push @EXPORT, qw( magic command new message );
200 # a map from package name to protocol
207 croak "magic already set for this protocol"
208 if (exists $protos_by_pkg{$caller});
210 $protos_by_pkg{$caller} = ipc_binary_proto_new($magic);
214 my ($cmd_id, @args) = @_;
217 croak "magic not set for this protocol"
218 unless (exists $protos_by_pkg{$caller});
220 croak "command args must be specified in pairs"
221 unless (@args % 2 == 0);
223 my $proto = $protos_by_pkg{$caller};
224 $cmd = ipc_binary_proto_add_cmd($proto, $cmd_id);
227 my $arg = shift @args;
228 my $flags = shift @args;
229 ipc_binary_cmd_add_arg($cmd, $arg, $flags);
240 chan => ipc_binary_new_channel($protos_by_pkg{$class}),
246 my ($cmd_id, @args) = @_;
250 chan => $self->{'chan'},
252 }, "Amanda::IPC::Binary::Message";
256 my $arg = shift @args;
257 my $val = shift @args;
258 $self->{'args'}[$arg] = $val;
265 if ($self->{'chan'}) {
266 ipc_binary_free_channel($self->{'chan'});
267 $self->{'chan'} = undef;
280 return ipc_binary_read_message($self->{'chan'}, $fd);
287 if (ipc_binary_write_message($self->{'chan'}, $fd, $msg) < 0) {
294 # Nonblocking interface -- TODO
299 package Amanda::IPC::Binary::Message;
301 # (constructor is the protocol's C<message> method)
304 # { cmd_id => $cmd_id,
306 # args => [ $arg0, $arg1, .. ],
310 return $self->{'cmd_id'};
314 my ($self, $arg_id) = @_;
316 return $self->{'args'}[$arg_id];
320 my ($self, $arg_id, $value) = @_;
321 $self->{'args'}[$arg_id] = $value;
324 package Amanda::IPC::Binary;