1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
|
/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
* Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Carbonite Inc., 756 N Pastoria Ave
* Sunnyvale, CA 94085, or: http://www.zmanda.com
*/
#ifndef IPC_BINARY_H
#define IPC_BINARY_H
#include "amanda.h"
/* This module implements bidirectional message-oriented protocols which use
* binary framing, allowing it to transmit significant quantities of binary
* data efficiently, at the cost of not being easily human-readable.
*
* A protocol is a set of messages (identified by distinct small integers),
* each of which has a variable number of arguments, identified by other small,
* nonzero integers which are unique within a particular message. Protocols
* are assumed to be known completely by both sides of a conversation -- no
* allowance is made for communication between different "versions" of a
* protocol. Arguments are limited to 2^32-1 bytes (just under 4 MB), and each
* message is similarly limited to a total of 2^32-1 bytes, including all
* protocol framing. Users are advised to choose smaller sizes (e.g., 2MB) for
* data blocks transmitted within arguments.
*
* On the wire, each message consists of a 16-bit magic number, followed by a
* 16-bit command id, a 32-bit message length, and a 32-bit argument count:
*
* +--------|--------|--------|--------+
* | magic | command |
* +--------|--------|--------|--------+
* | length |
* +-----------------|-----------------+
* | arg count | ...
* +-----------------+
*
* All integers are in network byte order, and the message length includes the
* length of the header. This header is followed by a sequence of argument
* records, each of which consists of a 32-bit length followed by a 16-bit
* argument id and the corresponding data. String arguments do not include the
* NUL terminator byte. Note that the argument length does not include the
* argument header.
*
* +--------|--------|--------|--------+
* | length |
* +--------|--------|--------|--------+
* | argid | data |
* +-----------------------------------+
* | data... |
* +-----------------------------------+
*/
/* To define a protocol, begin by enumerating the relevant message identifiers
* and argument identifiers. Then write an initialization function on the
* following format: */
#if 0
enum {
MY_PROTO_BACKUP = 1,
MY_PROTO_RESTORE = 2,
};
enum {
MY_PROTO_HOSTNAME = 1,
MY_PROTO_DISK = 2,
MY_PROTO_LEVEL = 3,
MY_PROTO_FILENAMES = 4,
};
ipc_binary_proto_t *
my_proto(void)
{
static ipc_binary_proto_t *proto = NULL;
if (!proto) {
ipc_binary_cmd_t *cmd;
proto = ipc_binary_proto_new(0xFACE);
cmd = ipc_binary_proto_add_cmd(proto, MY_PROTO_BACKUP);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_HOSTNAME, IPC_BINARY_STRING);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_DISK, IPC_BINARY_STRING);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_LEVEL, IPC_BINARY_STRING | IPC_BINARY_OPTIONAL);
cmd = ipc_binary_proto_add_cmd(proto, MY_PROTO_RESTORE);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_HOSTNAME, IPC_BINARY_STRING);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_DISK, IPC_BINARY_STRING);
ipc_binary_cmd_add_arg(cmd, MY_PROTO_FILENAMES, 0);
}
return proto;
}
#endif
/* Invoke my_proto in a thread-safe manner if necessary.
*
* Note that all of the constants are one-based. Internally, the module uses these values as
* array indices, so the constants should be assigned sequentially. Although C specifies that
* enumerations will auto-increment, it is best to add explicit values to avoid accidentally
* changing protocol values between revisions.
*/
/*
* Creating a new protocol
*/
/* opaque types */
typedef struct ipc_binary_proto_t ipc_binary_proto_t;
typedef struct ipc_binary_cmd_t ipc_binary_cmd_t;
/* Create a new, empty protocol object
*
* @param magic: magic number used to identify this protocol
* @returns: proto object
*/
ipc_binary_proto_t *ipc_binary_proto_new(
guint16 magic);
/* Create a new command in a protocol. The resulting object is only
* valid until the next call to this function for this proto.
*
* @param proto: the ipc_proto_t object to which to add this command
* @param id: the nonzero identifier for this command
* @returns: a new command object, already linked to PROTO
*/
ipc_binary_cmd_t *ipc_binary_proto_add_cmd(
ipc_binary_proto_t *proto,
guint16 id);
/* Flags for arguments */
/* This argument contains a string of non-null, printable characters and should
* be displayed in debugging messages. Arguments of this type will have a
* terminating NUL byte in the ipc_binary_message_t args array, for
* convenience, but will not count that byte in the length. */
#define IPC_BINARY_STRING (1 << 0)
/* This argument may be omitted */
#define IPC_BINARY_OPTIONAL (1 << 1)
/* Add an argument to a command
*
* @param cmd: the command object
* @param id: the argument identifier
* @param flags: bit flags for the command (see above)
*/
void ipc_binary_cmd_add_arg(
ipc_binary_cmd_t *cmd,
guint16 id,
guint8 flags);
/*
* Using a protocol
*/
typedef struct ipc_binary_buf_t {
gchar *buf;
gsize size;
gsize offset;
gsize length;
} ipc_binary_buf_t;
/* A channel represents a running protocol conversation, and encapsulates
* buffers for incoming and outgoing data, as well as a pointer to the protocol
* in use. */
typedef struct ipc_binary_channel_t {
/* protocol for this channel */
ipc_binary_proto_t *proto;
/* buffers for incoming and outgoing data */
ipc_binary_buf_t in, out;
} ipc_binary_channel_t;
/* Create a new channel, ready to send and receive messages.
*
* @param proto: protocol to use on this channel
* @returns: a new channel object
*/
ipc_binary_channel_t *ipc_binary_new_channel(
ipc_binary_proto_t *proto);
/* Free a channel completely.
*
* @param channel: the channel to free
*/
void ipc_binary_free_channel(
ipc_binary_channel_t *channel);
/* message format; use the argument id as an index into the args array. If
* DATA is NULL, then the argument wasn't present. */
typedef struct ipc_binary_message_t {
ipc_binary_channel_t *chan;
guint16 cmd_id;
ipc_binary_cmd_t *cmd;
guint16 n_args;
struct {
gsize len;
gpointer data;
} *args;
} ipc_binary_message_t;
/* Create a new, blank message which will later be sent.
*
* @param chan: the channel the message will be sent on
* @param cmd: the command id for this message
* @returns: new message struct
*/
ipc_binary_message_t *ipc_binary_new_message(
ipc_binary_channel_t *chan,
guint16 cmd_id);
/* Add an argument to a message. If the argument was defined with
* IPC_BINARY_STRING, then the size will be calculated using strlen. If
* TAKE_MEMORY is true, then this module takes ownership of the memory and will
* free it (with g_free) when the message is freed; otherwise, it will copy the
* data.
*
* @param msg: the message to change
* @param arg: the argument ID
* @param size: the argument size
* @param data: the argument data
* @param take_memory: take ownership of memory if TRUE
*/
void ipc_binary_add_arg(
ipc_binary_message_t *msg,
guint16 arg,
gsize size,
gpointer data,
gboolean take_memory);
/* Free a message structure (including all associated memory)
*
* @param msg: message to free
*/
void ipc_binary_free_message(
ipc_binary_message_t *msg);
/* Synchronous interface
*
* This interface assumes that communication takes place over file
* descriptors, and that blocking on network I/O is OK. It is much
* simpler than the asynchronous interface (below).
*/
/* Get the next message from the channel, optionally blocking until such a
* message is received. Returns NULL on EOF or on a protcol error. Errno is
* set to 0 for EOF, and contains an appropriate code for any other error.
*
* @param chan: channel on which to wait for a message
* @param fd: file descriptor to read from
* @returns: the message or NULL
*/
ipc_binary_message_t *ipc_binary_read_message(
ipc_binary_channel_t *chan,
int fd);
/* Send the given message, blocking until it is completely transmitted.
* This function automatically frees the message. Returns -1 on error,
* with errno set appropriately, or 0 on success.
*
* @param chan: channel on which to send the message
* @param fd: file descriptor to write to
* @param msg: message to send
*/
int ipc_binary_write_message(
ipc_binary_channel_t *chan,
int fd,
ipc_binary_message_t *msg);
/* Asynchronous interface
*
* This interface places data into and extracts data out of the buffers
* in a channel, but leaves it to the caller to handle sending and receiving
* data. */
/* Feed the given data into the channel. Call this when new data is
* available, and then check ipc_binary_poll_message(..) for any completed
* messages.
*
* @param chan: channel into which to feed data
* @param size: size of DATA
* @param data: the new data
*/
void ipc_binary_feed_data(
ipc_binary_channel_t *chan,
gsize size,
gpointer data);
/* Signal that some bytes have been transmitted and need not be kept in the
* outgoing buffer any longer
*
* @param chan: channel from which bytes were sent
* @param size: number of bytes transmitted
*/
void ipc_binary_data_transmitted(
ipc_binary_channel_t *chan,
gsize size);
/* Return the next complete incoming message in the channel, or NULL if there
* are no complete messages available. This also returns NULL on an invalid
* message, with errno set appropriately.
*
* @param chan: channel to poll
* @returns: message or NULL
*/
ipc_binary_message_t *ipc_binary_poll_message(
ipc_binary_channel_t *chan);
/* Queue the given message for later transmission. This function will free the
* message once it is in the outgoing data buffer. It is up to the caller to
* ensure that the
*
* @param chan: the channel to feed
* @param msg: the message to send
*/
void ipc_binary_queue_message(
ipc_binary_channel_t *chan,
ipc_binary_message_t *msg);
#endif /* IPC_BINARY_H */
|