diff options
author | Jacob Smith <jake.smith@hdfgroup.org> | 2020-03-13 22:13:17 (GMT) |
---|---|---|
committer | Jacob Smith <jake.smith@hdfgroup.org> | 2020-03-13 22:13:17 (GMT) |
commit | b65405439d88be6c09fe94360e7fea9856697926 (patch) | |
tree | f81fc8aa14e58a3b500cdf64a6a53b7150d8ac3e /src/H5FDmirror.c | |
parent | 7613f7e1aa89210bb625d59d79a6220c49a1f22c (diff) | |
download | hdf5-b65405439d88be6c09fe94360e7fea9856697926.zip hdf5-b65405439d88be6c09fe94360e7fea9856697926.tar.gz hdf5-b65405439d88be6c09fe94360e7fea9856697926.tar.bz2 |
Add Splitter VFD to library.
* "Simultaneous and equivalent" Read-Write and Write-Only channels for
file I/O.
* Only supports drivers with the H5FD_FEAT_DEFAULT_VFD_COMPATIBLE flag for
now, preventing issues with multi-file drivers.
Add Mirror VFD to library.
* Write-only operations over a network.
* Uses TCP/IP sockets.
* Server and auxiliary server-shutdown programs provided in a new directory,
`utils/mirror_vfd`.
* Automated testing via loopback ("remote" of localhost).
Diffstat (limited to 'src/H5FDmirror.c')
-rw-r--r-- | src/H5FDmirror.c | 1991 |
1 files changed, 1991 insertions, 0 deletions
diff --git a/src/H5FDmirror.c b/src/H5FDmirror.c new file mode 100644 index 0000000..ea1f516 --- /dev/null +++ b/src/H5FDmirror.c @@ -0,0 +1,1991 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Transmit write-only operations to a receiver/writer process on + * a remote host. + */ + +#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */ + +#include "H5private.h" /* Generic Functions */ + +#ifdef H5_HAVE_MIRROR_VFD + +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDmirror.h" /* "Mirror" definitions */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ + +/* The driver identification number, initialized at runtime */ +static hid_t H5FD_MIRROR_g = 0; + +/* Virtual file structure for a Mirror Driver */ +typedef struct H5FD_mirror_t { + H5FD_t pub; /* Public stuff, must be first */ + H5FD_mirror_fapl_t fa; /* Configuration structure */ + haddr_t eoa; /* End of allocated region */ + haddr_t eof; /* End of file; current file size */ + int sock_fd; /* Handle of socket to remote operator */ + H5FD_mirror_xmit_t xmit; /* Primary communication header */ + uint32_t xmit_i; /* Counter of transmission sent and rec'd */ +} H5FD_mirror_t; + +/* + * These macros check for overflow of various quantities. These macros + * assume that HDoff_t is signed and haddr_t and size_t are unsigned. + * + * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' + * is too large to be represented by the second argument + * of the file seek function. + * + * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too + * large to be represented by the `size_t' type. + * + * REGION_OVERFLOW: Checks whether an address and size pair describe data + * which can be addressed entirely by the second + * argument of the file seek function. + */ +#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1) +#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR)) + +#define _BSWAP_64(X) \ + (uint64_t)( (((X) & 0x00000000000000FF) << 56) \ + | (((X) & 0x000000000000FF00) << 40) \ + | (((X) & 0x0000000000FF0000) << 24) \ + | (((X) & 0x00000000FF000000) << 8) \ + | (((X) & 0x000000FF00000000) >> 8) \ + | (((X) & 0x0000FF0000000000) >> 24) \ + | (((X) & 0x00FF000000000000) >> 40) \ + | (((X) & 0xFF00000000000000) >> 56)) + +/* Debugging flabs for verbose tracing -- nonzero to enable */ +#define MIRROR_DEBUG_OP_CALLS 0 +#define MIRROR_DEBUG_XMIT_BYTES 0 + +#if MIRROR_DEBUG_XMIT_BYTES +#define LOG_XMIT_BYTES(label, buf, len) do { \ + ssize_t bytes_written = 0; \ + const unsigned char *b = NULL; \ + \ + HDfprintf(stdout, "%s bytes:\n```\n", (label)); \ + \ + /* print whole lines */ \ + while ((len - bytes_written) >= 32) { \ + b = (const unsigned char *)(buf) + bytes_written; \ + HDfprintf(stdout, \ + "%04zX %02X%02X%02X%02X %02X%02X%02X%02X" \ + " %02X%02X%02X%02X %02X%02X%02X%02X" \ + " %02X%02X%02X%02X %02X%02X%02X%02X" \ + " %02X%02X%02X%02X %02X%02X%02X%02X\n", \ + bytes_written, \ + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], \ + b[8], b[9], b[10],b[11], b[12],b[13],b[14],b[15], \ + b[16],b[17],b[18],b[19], b[20],b[21],b[22],b[23], \ + b[24],b[25],b[26],b[27], b[28],b[29],b[30],b[31]); \ + bytes_written += 32; \ + } \ + \ + /* start partial line */ \ + if (len > bytes_written) { \ + HDfprintf(stdout, "%04zX ", bytes_written); \ + } \ + \ + /* partial line blocks */ \ + while ((len - bytes_written) >= 4) { \ + HDfprintf(stdout, " %02X%02X%02X%02X", \ + (buf)[bytes_written], (buf)[bytes_written+1], \ + (buf)[bytes_written+2], (buf)[bytes_written+3]); \ + bytes_written += 4; \ + } \ + \ + /* block separator before partial block */ \ + if (len > bytes_written) { \ + HDfprintf(stdout, " "); \ + } \ + \ + /* partial block individual bytes */ \ + while (len > bytes_written) { \ + HDfprintf(stdout, "%02X", (buf)[bytes_written++]); \ + } \ + \ + /* end partial line */ \ + HDfprintf(stdout, "\n"); \ + HDfprintf(stdout, "```\n"); \ + HDfflush(stdout); \ +} while (0) +#else +#define LOG_XMIT_BYTES(label, buf, len) /* no-op */ +#endif /* MIRROR_DEBUG_XMIT_BYTE */ + +#if MIRROR_DEBUG_OP_CALLS +#define LOG_OP_CALL(name) do { \ + HDprintf("called %s()\n", (name)); \ + fflush(stdout); \ +} while (0) +#else +#define LOG_OP_CALL(name) /* no-op */ +#endif /* MIRROR_DEBUG_OP_CALLS */ + +/* Prototypes */ +static herr_t H5FD_mirror_term(void); +static void *H5FD_mirror_fapl_get(H5FD_t *_file); +static void *H5FD_mirror_fapl_copy(const void *_old_fa); +static herr_t H5FD_mirror_fapl_free(void *_fa); +static haddr_t H5FD_mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD_mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); +static haddr_t H5FD_mirror_get_eof(const H5FD_t *_file, H5FD_mem_t type); +static H5FD_t *H5FD_mirror_open(const char *name, unsigned flags, \ + hid_t fapl_id, haddr_t maxaddr); +static herr_t H5FD_mirror_close(H5FD_t *_file); +static herr_t H5FD_mirror_query(const H5FD_t *_file, unsigned long *flags); +static herr_t H5FD_mirror_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, \ + haddr_t addr, size_t size, const void *buf); +static herr_t H5FD_mirror_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, + haddr_t addr, size_t size, void *buf); +static herr_t H5FD_mirror_truncate(H5FD_t *_file, hid_t dxpl_id, \ + hbool_t closing); +static herr_t H5FD_mirror_lock(H5FD_t *_file, hbool_t rw); +static herr_t H5FD_mirror_unlock(H5FD_t *_file); + +static herr_t H5FD__mirror_verify_reply(H5FD_mirror_t *file); + +static const H5FD_class_t H5FD_mirror_g = { + "mirror", /* name */ + MAXADDR, /* maxaddr */ + H5F_CLOSE_WEAK, /* fc_degree */ + H5FD_mirror_term, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + 0, /* fapl_size */ + H5FD_mirror_fapl_get, /* fapl_get */ + H5FD_mirror_fapl_copy, /* fapl_copy */ + H5FD_mirror_fapl_free, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD_mirror_open, /* open */ + H5FD_mirror_close, /* close */ + NULL, /* cmp */ + H5FD_mirror_query, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + H5FD_mirror_get_eoa, /* get_eoa */ + H5FD_mirror_set_eoa, /* set_eoa */ + H5FD_mirror_get_eof, /* get_eof */ + NULL, /* get_handle */ + H5FD_mirror_read, /* read */ + H5FD_mirror_write, /* write */ + NULL, /* flush */ + H5FD_mirror_truncate, /* truncate */ + H5FD_mirror_lock, /* lock */ + H5FD_mirror_unlock, /* unlock */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/* Declare a free list to manage the H5FD_mirror_t struct */ +H5FL_DEFINE_STATIC(H5FD_mirror_t); + + +/*------------------------------------------------------------------------- + * Function: H5FD__init_package + * + * Purpose: Initializes any interface-specific data or routines. + * + * Return: Non-negative on success/Negative on failure + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__init_package(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + LOG_OP_CALL("H5FD__init_package"); + + if (H5FD_mirror_init() < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "unable to initialize mirror VFD"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD__init_package() */ + + +/* ------------------------------------------------------------------------- + * Function: H5FD_mirror_init + * + * Purpose: Initialize this driver by registering the driver with the + * library. + * + * Return: Success: The driver ID for the mirror driver. + * Failure: Negative + * ------------------------------------------------------------------------- + */ +hid_t +H5FD_mirror_init(void) +{ + hid_t ret_value = H5I_INVALID_HID; + + FUNC_ENTER_NOAPI(FAIL) + + LOG_OP_CALL("H5FD_mirror_init"); + + if (H5I_VFL != H5I_get_type(H5FD_MIRROR_g)) { + H5FD_MIRROR_g = H5FD_register(&H5FD_mirror_g, sizeof(H5FD_class_t), + FALSE); + } + + ret_value = H5FD_MIRROR_g; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_init() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_term + * + * Purpose: Shut down the VFD + * + * Returns: SUCCEED (Can't fail) + * --------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_term(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Reset VFL ID */ + H5FD_MIRROR_g = 0; + + LOG_OP_CALL("H5FD_mirror_term"); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_mirror_term() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_decode_uint16 + * + * Purpose: Extract a 16-bit integer in "network" (Big-Endian) word order + * from the byte-buffer and return it with the local word order at + * the destination pointer. + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * Return: The number of bytes read from the buffer (2). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_decode_uint16(uint16_t *out, const unsigned char *_buf) +{ + uint16_t n = 0; + LOG_OP_CALL("H5FD__mirror_xmit_decode_uint16"); + HDassert(_buf && out); + HDmemcpy(&n, _buf, sizeof(n)); + *out = (uint16_t)HDntohs(n); + return 2; /* number of bytes eaten */ +} /* end H5FD__mirror_xmit_decode_uint16() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_decode_uint32 + * + * Purpose: Extract a 32-bit integer in "network" (Big-Endian) word order + * from the byte-buffer and return it with the local word order at + * the destination pointer. + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * Return: The number of bytes read from the buffer (4). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_decode_uint32(uint32_t *out, const unsigned char *_buf) +{ + uint32_t n = 0; + LOG_OP_CALL("H5FD__mirror_xmit_decode_uint32"); + HDassert(_buf && out); + HDmemcpy(&n, _buf, sizeof(n)); + *out = (uint32_t)HDntohl(n); + return 4; /* number of bytes eaten */ +} /* end H5FD__mirror_xmit_decode_uint32() */ + + + +/* --------------------------------------------------------------------------- + * Function: is_host_little_endian + * + * Purpose: Determine whether the host machine is is little-endian. + * + * Store an intger with a known value, re-map the memory to a + * character array, and inspect the array's contents. + * + * Return: The number of bytes written to the buffer (8). + * + * Programmer: Jacob Smith + * 2020-03-05 + * --------------------------------------------------------------------------- + */ +static hbool_t +is_host_little_endian(void) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } echeck; + echeck.u32 = 0xA1B2C3D4; + if (echeck.u8[0] == 0xD4) { + return TRUE; + } + else { + return FALSE; + } +} /* end is_host_little_endian() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_decode_uint64 + * + * Purpose: Extract a 64-bit integer in "network" (Big-Endian) word order + * from the byte-buffer and return it with the local word order. + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * WARNING: Does not accommodate other forms of endianness, + * e.g. "middle-endian". + * + * Return: The number of bytes written to the buffer (8). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_decode_uint64(uint64_t *out, const unsigned char *_buf) +{ + uint64_t n = 0; + LOG_OP_CALL("H5FD__mirror_xmit_decode_uint64"); + HDassert(_buf && out); + HDmemcpy(&n, _buf, sizeof(n)); + if (TRUE == is_host_little_endian()) { + *out = _BSWAP_64(n); + } + else { + *out = n; + } + return 8; +} /* end H5FD__mirror_xmit_decode_uint64() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_decode_uint8 + * + * Purpose: Extract a 8-bit integer in "network" (Big-Endian) word order + * from the byte-buffer and return it with the local word order at + * the destination pointer. + * (yes, it's one byte). + * + * Return: The number of bytes read from the buffer (1). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_decode_uint8(uint8_t *out, const unsigned char *_buf) +{ + LOG_OP_CALL("H5FD__mirror_xmit_decode_uint8"); + HDassert(_buf && out); + HDmemcpy(out, _buf, sizeof(uint8_t)); + return 1; /* number of bytes eaten */ +} /* end H5FD__mirror_xmit_decode_uint8() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_encode_uint16 + * + * Purpose: Encode a 16-bit integer in "network" (Big-Endian) word order + * in place in the destination bytes-buffer. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer (2). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_encode_uint16(unsigned char *_dest, uint16_t v) +{ + uint16_t n = 0; + LOG_OP_CALL("H5FD__mirror_xmit_encode_uint16"); + HDassert(_dest); + n = (uint16_t)HDhtons(v); + HDmemcpy(_dest, &n, sizeof(n)); + return 2; +} /* end H5FD__mirror_xmit_encode_uint16() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_encode_uint32 + * + * Purpose: Encode a 32-bit integer in "network" (Big-Endian) word order + * in place in the destination bytes-buffer. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer (4). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_encode_uint32(unsigned char *_dest, uint32_t v) +{ + uint32_t n = 0; + LOG_OP_CALL("H5FD__mirror_xmit_encode_uint32"); + HDassert(_dest); + n = (uint32_t)HDhtonl(v); + HDmemcpy(_dest, &n, sizeof(n)); + return 4; +} /* end H5FD__mirror_xmit_encode_uint32() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_encode_uint64 + * + * Purpose: Encode a 64-bit integer in "network" (Big-Endian) word order + * in place in the destination bytes-buffer. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer (8). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_encode_uint64(unsigned char *_dest, uint64_t v) +{ + uint64_t n = v; + LOG_OP_CALL("H5FD__mirror_xmit_decode_uint64"); + HDassert(_dest); + if (TRUE == is_host_little_endian()) { + n = _BSWAP_64(v); + } + HDmemcpy(_dest, &n, sizeof(n)); + return 8; +} /* H5FD__mirror_xmit_encode_uint64() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD__mirror_xmit_encode_uint8 + * + * Purpose: Encode a 8-bit integer in "network" (Big-Endian) word order + * in place in the destination bytes-buffer. + * (yes, it's one byte). + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes read from the buffer (1). + * --------------------------------------------------------------------------- + */ +size_t +H5FD__mirror_xmit_encode_uint8(unsigned char *dest, uint8_t v) +{ + LOG_OP_CALL("H5FD__mirror_xmit_encode_uint8"); + HDassert(dest); + HDmemcpy(dest, &v, sizeof(v)); + return 1; +} /* end H5FD__mirror_xmit_encode_uint8() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_header + * + * Purpose: Extract a mirror_xmit_t "header" from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_xmit() before use. + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * Return: The number of bytes consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_header(H5FD_mirror_xmit_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_header"); + HDassert(out && buf); + n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->magic), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->version), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->session_token), + &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->xmit_count), + &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->op), &buf[n_eaten]); + HDassert(n_eaten == H5FD_MIRROR_XMIT_HEADER_SIZE); + return n_eaten; +} /* end H5FD_mirror_xmit_decode_header() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_lock + * + * Purpose: Extract a mirror_xmit_lock_t from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_lock() before use. + * + * Return: The number of bytes consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_lock(H5FD_mirror_xmit_lock_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_lock"); + HDassert(out && buf); + n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->rw), &buf[n_eaten]); + HDassert(n_eaten == H5FD_MIRROR_XMIT_LOCK_SIZE); + return n_eaten; +} /* end H5FD_mirror_xmit_decode_lock() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_open + * + * Purpose: Extract a mirror_xmit_open_t from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_open() before use. + * + * Return: The maximum number of bytes that this decoding operation might + * have consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_open(H5FD_mirror_xmit_open_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_open"); + HDassert(out && buf); + n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf); + n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->flags), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->maxaddr), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size_t_blob), + &buf[n_eaten]); + HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX) + == n_eaten); + HDstrncpy(out->filename, (const char *)&buf[n_eaten], + H5FD_MIRROR_XMIT_FILEPATH_MAX-1); + out->filename[H5FD_MIRROR_XMIT_FILEPATH_MAX-1] = 0; /* force final NULL */ + return H5FD_MIRROR_XMIT_OPEN_SIZE; +} /* end H5FD_mirror_xmit_decode_open() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_reply + * + * Purpose: Extract a mirror_xmit_reply_t from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_reply() before use. + * + * Return: The maximum number of bytes that this decoding operation might + * have consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_reply(H5FD_mirror_xmit_reply_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_reply"); + HDassert(out && buf); + n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf); + n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->status), &buf[n_eaten]); + HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX) + == n_eaten); + HDstrncpy(out->message, (const char *)&buf[n_eaten], + H5FD_MIRROR_STATUS_MESSAGE_MAX-1); + out->message[H5FD_MIRROR_STATUS_MESSAGE_MAX-1] = 0; /* force NULL term */ + return H5FD_MIRROR_XMIT_REPLY_SIZE; +} /* end H5FD_mirror_xmit_decode_reply() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_set_eoa + * + * Purpose: Extract a mirror_xmit_eoa_t from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_set_eoa() before use. + * + * Return: The number of bytes consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_set_eoa(H5FD_mirror_xmit_eoa_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_set_eoa"); + HDassert(out && buf); + n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf); + n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->eoa_addr), &buf[n_eaten]); + HDassert(n_eaten == H5FD_MIRROR_XMIT_EOA_SIZE); + return n_eaten; +} /* end H5FD_mirror_xmit_decode_set_eoa() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_decode_write + * + * Purpose: Extract a mirror_xmit_write_t from the bytes-buffer. + * + * Fields will be lifted from the buffer and stored in the + * target structure, using in the correct location (different + * systems may insert different padding between components) and + * word order (Big- vs Little-Endian). + * + * The programmer must ensure that the received buffer holds + * at least the expected size of data. + * + * The resulting structure should be sanity-checked with + * H5FD_mirror_xmit_is_write() before use. + * + * Return: The number of bytes consumed from the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_decode_write(H5FD_mirror_xmit_write_t *out, + const unsigned char *buf) +{ + size_t n_eaten = 0; + LOG_OP_CALL("H5FD_mirror_xmit_decode_write"); + HDassert(out && buf); + n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf); + n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->offset), &buf[n_eaten]); + n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size), &buf[n_eaten]); + HDassert(n_eaten == H5FD_MIRROR_XMIT_WRITE_SIZE); + return n_eaten; +} /* end H5FD_mirror_xmit_decode_write() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_header + * + * Purpose: Encode a mirror_xmit_t "header" to the bytes-buffer. + * + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_header(unsigned char *dest, + const H5FD_mirror_xmit_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_header"); + HDassert(dest && x); + n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->magic); + n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->version); + n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->session_token); + n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->xmit_count); + n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->op); + HDassert(n_writ == H5FD_MIRROR_XMIT_HEADER_SIZE); + return n_writ; +} /* end H5FD_mirror_xmit_encode_header() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_lock + * + * Purpose: Encode a mirror_xmit_lock_t to the bytes-buffer. + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_lock(unsigned char *dest, + const H5FD_mirror_xmit_lock_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_lock"); + HDassert(dest && x); + n_writ += H5FD_mirror_xmit_encode_header(dest, + (const H5FD_mirror_xmit_t *)&(x->pub)); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->rw); + HDassert(n_writ == H5FD_MIRROR_XMIT_LOCK_SIZE); + return n_writ; +} /* end H5FD_mirror_xmit_encode_lock() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_open + * + * Purpose: Encode a mirror_xmit_open_t to the bytes-buffer. + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The maximum number of bytes that this decoding operation might + * have written into the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_open(unsigned char *dest, + const H5FD_mirror_xmit_open_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_open"); + HDassert(dest && x); + HDbzero(dest, H5FD_MIRROR_XMIT_OPEN_SIZE); + n_writ += H5FD_mirror_xmit_encode_header(dest, + (const H5FD_mirror_xmit_t *)&(x->pub)); + n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->flags); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->maxaddr); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size_t_blob); + HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX) + == n_writ); + HDstrncpy((char *)&dest[n_writ], x->filename, + H5FD_MIRROR_XMIT_FILEPATH_MAX); + return H5FD_MIRROR_XMIT_OPEN_SIZE; +} /* end H5FD_mirror_xmit_encode_open() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_reply + * + * Purpose: Encode a mirror_xmit_reply_t to the bytes-buffer. + * + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The maximum number of bytes that this decoding operation might + * have written into the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_reply(unsigned char *dest, + const H5FD_mirror_xmit_reply_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_reply"); + HDassert(dest && x); + HDbzero(dest, H5FD_MIRROR_XMIT_REPLY_SIZE); + n_writ += H5FD_mirror_xmit_encode_header(dest, + (const H5FD_mirror_xmit_t *)&(x->pub)); + n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->status); + HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX) + == n_writ); + HDstrncpy((char *)&dest[n_writ], x->message, + H5FD_MIRROR_STATUS_MESSAGE_MAX); + return H5FD_MIRROR_XMIT_REPLY_SIZE; +} /* end H5FD_mirror_xmit_encode_reply() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_set_eoa + * + * Purpose: Encode a mirror_xmit_eoa_t to the bytes-buffer. + * + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_set_eoa(unsigned char *dest, + const H5FD_mirror_xmit_eoa_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_set_eoa"); + HDassert(dest && x); + n_writ += H5FD_mirror_xmit_encode_header(dest, + (const H5FD_mirror_xmit_t *)&(x->pub)); + n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->eoa_addr); + HDassert(n_writ == H5FD_MIRROR_XMIT_EOA_SIZE); + return n_writ; +} /* end H5FD_mirror_xmit_encode_set_eoa() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_encode_write + * + * Purpose: Encode a mirror_xmit_write_t to the bytes-buffer. + * + * Fields will be packed into the buffer in a predictable manner, + * any numbers stored in "network" (Big-Endian) word order. + * + * The programmer must ensure that the destination buffer is + * large enough to hold the expected data. + * + * Return: The number of bytes written to the buffer. + * --------------------------------------------------------------------------- + */ +size_t +H5FD_mirror_xmit_encode_write(unsigned char *dest, + const H5FD_mirror_xmit_write_t *x) +{ + size_t n_writ = 0; + LOG_OP_CALL("H5FD_mirror_xmit_encode_write"); + HDassert(dest && x); + n_writ += H5FD_mirror_xmit_encode_header(dest, + (const H5FD_mirror_xmit_t *)&(x->pub)); + n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->offset); + n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size); + HDassert(n_writ == H5FD_MIRROR_XMIT_WRITE_SIZE); + return n_writ; +} /* end H5FD_mirror_xmit_encode_write() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_close + * + * Purpose: Verify that a mirror_xmit_t is a valid CLOSE xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_close(const H5FD_mirror_xmit_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_close"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(xmit)) && + (H5FD_MIRROR_OP_CLOSE == xmit->op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_close() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_lock + * + * Purpose: Verify that a mirror_xmit_lock_t is a valid LOCK xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_lock(const H5FD_mirror_xmit_lock_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_lock"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && + (H5FD_MIRROR_OP_LOCK == xmit->pub.op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_lock() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_open + * + * Purpose: Verify that a mirror_xmit_open_t is a valid OPEN xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_open(const H5FD_mirror_xmit_open_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_open"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && + (H5FD_MIRROR_OP_OPEN == xmit->pub.op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_open() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_eoa + * + * Purpose: Verify that a mirror_xmit_eoa_t is a valid SET-EOA xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_set_eoa(const H5FD_mirror_xmit_eoa_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_set_eoa"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && + (H5FD_MIRROR_OP_SET_EOA == xmit->pub.op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_eoa() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_reply + * + * Purpose: Verify that a mirror_xmit_reply_t is a valid REPLY xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_reply(const H5FD_mirror_xmit_reply_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_reply"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && + (H5FD_MIRROR_OP_REPLY == xmit->pub.op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_reply() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_write + * + * Purpose: Verify that a mirror_xmit_write_t is a valid WRITE xmit. + * + * Checks header validity and op code. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_write(const H5FD_mirror_xmit_write_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_write"); + HDassert(xmit); + if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) && + (H5FD_MIRROR_OP_WRITE == xmit->pub.op) ) + { + return TRUE; + } + return FALSE; +} /* end H5FD_mirror_xmit_is_write() */ + + +/* --------------------------------------------------------------------------- + * Function: H5FD_mirror_xmit_is_xmit + * + * Purpose: Verify that a mirror_xmit_t is well-formed. + * + * Checks magic number and structure version. + * + * Return: TRUE if valid; else FALSE. + * --------------------------------------------------------------------------- + */ +hbool_t +H5FD_mirror_xmit_is_xmit(const H5FD_mirror_xmit_t *xmit) +{ + LOG_OP_CALL("H5FD_mirror_xmit_is_xmit"); + HDassert(xmit); + if ( (H5FD_MIRROR_XMIT_MAGIC != xmit->magic) || + (H5FD_MIRROR_XMIT_CURR_VERSION != xmit->version) ) + { + return FALSE; + } + return TRUE; +} /* end H5FD_mirror_xmit_is_xmit() */ + + +/* ---------------------------------------------------------------------------- + * Function: H5FD__mirror_verify_reply + * + * Purpose: Wait for and read reply data from remote processes. + * Sanity-check that a reply is well-formed and valid. + * If all checks pass, inspect the reply contents and handle + * reported error, if not an OK reply. + * + * Return: SUCCEED if ok, else FAIL. + * ---------------------------------------------------------------------------- + */ +herr_t +H5FD__mirror_verify_reply(H5FD_mirror_t *file) +{ + char xmit_buf[H5FD_MIRROR_XMIT_REPLY_SIZE]; + struct H5FD_mirror_xmit_reply_t reply; + ssize_t read_ret = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT; + + LOG_OP_CALL("H5FD__mirror_verify_reply"); + + HDassert(file && file->sock_fd); + + read_ret = HDread(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_REPLY_SIZE); + if (read_ret < 0) { + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unable to read reply"); + } + if (read_ret != H5FD_MIRROR_XMIT_REPLY_SIZE) { + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unexpected read size"); + } + + LOG_XMIT_BYTES("reply", xmit_buf, read_ret); + + if (H5FD_mirror_xmit_decode_reply(&reply, (const unsigned char *)xmit_buf) + != H5FD_MIRROR_XMIT_REPLY_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to decode reply xmit"); + } + + if (H5FD_mirror_xmit_is_reply(&reply) != TRUE) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "xmit op code was not REPLY"); + } + + if (reply.pub.session_token != file->xmit.session_token) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "wrong session"); + } + + if (reply.pub.xmit_count != (file->xmit_i)++) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "xmit out of sync"); + } + + if (reply.status != H5FD_MIRROR_STATUS_OK) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, + "%s", (const char *)(reply.message)); + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD__mirror_verify_reply() */ + + +/* ------------------------------------------------------------------------- + * Function: H5FD_mirror_fapl_get + * + * Purpose: Get the file access propety list which could be used to create + * an identical file. + * + * Return: Success: pointer to the new file access property list value. + * Failure: NULL + * ------------------------------------------------------------------------- + */ +static void * +H5FD_mirror_fapl_get(H5FD_t *_file) +{ + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + H5FD_mirror_fapl_t *fa = NULL; + void *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_fapl_get"); + + fa = (H5FD_mirror_fapl_t *)H5MM_calloc(sizeof(H5FD_mirror_fapl_t)); + if (NULL == fa) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "calloc failed"); + } + + HDmemcpy(fa, &(file->fa), sizeof(H5FD_mirror_fapl_t)); + + ret_value = fa; + +done: + if (ret_value == NULL) { + if (fa != NULL) { + H5MM_xfree(fa); + } + } + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_fapl_get() */ + + +/* ------------------------------------------------------------------------- + * Function: H5FD_mirror_fapl_copy + * + * Purpose: Copies the mirror vfd-specific file access properties. + * + * Return: Success: Pointer to a new property list + * Failure: NULL + * ------------------------------------------------------------------------- + */ +static void * +H5FD_mirror_fapl_copy(const void *_old_fa) +{ + const H5FD_mirror_fapl_t *old_fa = (const H5FD_mirror_fapl_t *)_old_fa; + H5FD_mirror_fapl_t *new_fa = NULL; + void *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_fapl_copy"); + + new_fa = (H5FD_mirror_fapl_t *)H5MM_malloc(sizeof(H5FD_mirror_fapl_t)); + if (new_fa == NULL) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, + "memory allocation failed"); + } + + HDmemcpy(new_fa, old_fa, sizeof(H5FD_mirror_fapl_t)); + ret_value = new_fa; + +done: + if (ret_value == NULL) { + if (new_fa != NULL) { + H5MM_xfree(new_fa); + } + } + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_fapl_copy() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_fapl_free + * + * Purpose: Frees the mirror VFD-specific file access properties. + * + * Return: SUCCEED (cannot fail) + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_fapl_free(void *_fa) +{ + H5FD_mirror_fapl_t *fa = (H5FD_mirror_fapl_t*)_fa; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + LOG_OP_CALL("H5FD_mirror_fapl_free"); + + /* sanity check */ + HDassert(fa != NULL); + HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC); + + fa->magic += 1; /* invalidate */ + H5MM_xfree(fa); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FD_mirror_fapl_free() */ + + +/* ------------------------------------------------------------------------- + * Function: H5Pget_fapl_mirror + * + * Purpose: Get the configuration information for this fapl. + * Data is memcopied into the fa_out pointer. + * + * Return: SUCCEED/FAIL + * ------------------------------------------------------------------------- + */ +herr_t +H5Pget_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa_out) +{ + const H5FD_mirror_fapl_t *fa = NULL; + H5P_genplist_t *plist = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", fapl_id, fa_out); + + LOG_OP_CALL("H5Pget_fapl_mirror"); + + if (NULL == fa_out) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "fa_out is NULL"); + } + + plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS); + if (NULL == plist) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a file access property list"); + } + + if (H5P_peek_driver(plist) != H5FD_MIRROR) { + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver"); + } + + fa = (const H5FD_mirror_fapl_t *)H5P_peek_driver_info(plist); + if (NULL == fa) { + HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info"); + } + + HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC); /* sanity check */ + + HDmemcpy(fa_out, fa, sizeof(H5FD_mirror_fapl_t)); + +done: + FUNC_LEAVE_API(ret_value); +} /* end H5Pget_fapl_mirror() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pset_fapl_mirror + * + * Purpose: Modify the file access property list to use the mirror + * driver (H5FD_MIRROR) defined in this source file. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa) +{ + H5P_genplist_t *plist = NULL; + herr_t ret_value = FAIL; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*x", fapl_id, fa); + + LOG_OP_CALL("H5Pset_fapl_mirror"); + + plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS); + if (NULL == plist) { + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a file access property list"); + } + if (NULL == fa) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null fapl_t pointer"); + } + if (H5FD_MIRROR_FAPL_MAGIC != fa->magic) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fapl_t magic"); + } + if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa->version) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown fapl_t version"); + } + + ret_value = H5P_set_driver(plist, H5FD_MIRROR, (const void *)fa); + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pset_fapl_mirror() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_open + * + * Purpose: Create and/or opens a file as an HDF5 file. + * + * Initiate connection with remote Server/Writer. + * If successful, the remote file is open. + * + * Return: Success: A pointer to a new file data structure. The + * public fields will be initialized by the + * caller, which is always H5FD_open(). + * Failure: NULL + *------------------------------------------------------------------------- + */ +static H5FD_t * +H5FD_mirror_open(const char *name, + unsigned flags, + hid_t fapl_id, + haddr_t maxaddr) +{ +#define MIRR_OPEN_MAXBUF 16 /* local symbol to give meaning to magic number */ + /* #defined because it is needed at compile time */ + /* Large enough to hold a port number string */ + int live_socket = -1; + struct sockaddr_in target_addr; + socklen_t addr_size; + char xmit_buf[H5FD_MIRROR_XMIT_OPEN_SIZE]; + H5FD_mirror_fapl_t fa; + H5FD_mirror_t *file = NULL; + H5FD_mirror_xmit_open_t open_xmit; + H5FD_t *ret_value = NULL; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_open"); + + /* --------------- */ + /* Check arguments */ + /* --------------- */ + + if (!name || !*name) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name"); + } + if (HDstrlen(name) >= H5FD_MIRROR_XMIT_FILEPATH_MAX) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "filename is too long"); + } + if (0 == maxaddr || HADDR_UNDEF == maxaddr) { + HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr"); + } + if (ADDR_OVERFLOW(maxaddr)) { + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr"); + } + + if (H5Pget_fapl_mirror(fapl_id, &fa) == FAIL) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't get config info"); + } + + if (H5FD_MIRROR_FAPL_MAGIC != fa.magic) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl magic"); + } + + if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa.version) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl version"); + } + + /* --------------------- */ + /* Handshake with remote */ + /* --------------------- */ + + live_socket = HDsocket(AF_INET, SOCK_STREAM, 0); + if (live_socket < 0) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't create socket"); + } + + target_addr.sin_family = AF_INET; + target_addr.sin_port = HDhtons((uint16_t)fa.handshake_port); + target_addr.sin_addr.s_addr = HDinet_addr(fa.remote_ip); + HDmemset(target_addr.sin_zero, '\0', sizeof target_addr.sin_zero); + + addr_size = sizeof(target_addr); + if (HDconnect(live_socket, (struct sockaddr *)&target_addr, addr_size) < 0) + { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, + "can't connect to remote server"); + } + + /* ------------- */ + /* Open the file */ + /* ------------- */ + + file = (H5FD_mirror_t *)H5FL_CALLOC(H5FD_mirror_t); + if (NULL == file) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, + "unable to allocate file struct"); + } + + file->sock_fd = live_socket; + file->xmit_i = 0; + + file->xmit.magic = H5FD_MIRROR_XMIT_MAGIC; + file->xmit.version = H5FD_MIRROR_XMIT_CURR_VERSION; + file->xmit.xmit_count = file->xmit_i++; + file->xmit.session_token = (uint32_t)(0x01020304 ^ file->sock_fd); /* TODO: hashing? */ + /* int --> uint32_t may truncate on some systems... shouldn't matter? */ + + file->xmit.op = H5FD_MIRROR_OP_OPEN; + open_xmit.pub = file->xmit; + open_xmit.flags = (uint32_t)flags; + open_xmit.maxaddr = (uint64_t)maxaddr; + open_xmit.size_t_blob = (uint64_t)((size_t)(-1)); + HDsnprintf(open_xmit.filename, H5FD_MIRROR_XMIT_FILEPATH_MAX-1, "%s", name); + + if (H5FD_mirror_xmit_encode_open((unsigned char *)xmit_buf, + (const H5FD_mirror_xmit_open_t *)&open_xmit) + != H5FD_MIRROR_XMIT_OPEN_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to encode open"); + } + + LOG_XMIT_BYTES("open", xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to transmit open"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "invalid reply"); + } + + ret_value = (H5FD_t *)file; + +done: + if (NULL == ret_value) { + if (file) { + file = H5FL_FREE(H5FD_mirror_t, file); + } + if (live_socket >= 0 && HDclose(live_socket) < 0) { + HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, NULL, + "can't close socket"); + } + } + FUNC_LEAVE_NOAPI(ret_value) +#undef MIRR_OPEN_MAXBUF +} /* end H5FD_mirror_open() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_close + * + * Purpose: Closes the HDF5 file. + * + * Tries to send a CLOSE op to the remote Writer and expects + * a valid reply, then closes the socket. + * In error, attempts to send a deliberately invalid xmit to the + * Writer to get it to close/abort, then attempts to close the + * socket. + * + * Return: Success: SUCCEED + * Failure: FAIL, file possibly not closed but resources freed. + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_close(H5FD_t *_file) +{ + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE]; + int xmit_encoded = 0; /* monitor point of failure */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_close"); + + /* Sanity check */ + HDassert(file); + HDassert(file->sock_fd >= 0); + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_CLOSE; + + if (H5FD_mirror_xmit_encode_header(xmit_buf, + (const H5FD_mirror_xmit_t *)&(file->xmit)) + != H5FD_MIRROR_XMIT_HEADER_SIZE) + { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to encode close"); + } + xmit_encoded = 1; + + LOG_XMIT_BYTES("close", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to transmit close"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + + if (HDclose(file->sock_fd) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "can't close socket"); + } + +done: + if (ret_value == FAIL) { + if (xmit_encoded == 0) { + /* Encode failed; send GOODBYE to force writer halt. + * We can ignore any response from the writer, if we receive + * any reply at all. + */ + if (HDwrite(file->sock_fd, "GOODBYE", HDstrlen("GOODBYE")) < 0) { + HDONE_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "unable to transmit close"); + if (HDclose(file->sock_fd) < 0) { + HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, + "can't close socket"); + } + file->sock_fd = -1; /* invalidate for later */ + } /* end if problem writing goodbye; go down hard */ + else + if (HDshutdown(file->sock_fd, SHUT_WR) < 0) { + HDONE_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, + "can't shutdown socket write: %s", + HDstrerror(errno)); + } /* end else-if problem shutting down socket */ + } /* end if xmit encode failed */ + + if (file->sock_fd >= 0) { + if (HDclose(file->sock_fd) < 0) { + HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, + "can't close socket"); + } + } /* end if socket not closed by going down hard */ + } /* end if error */ + + file = H5FL_FREE(H5FD_mirror_t, file); /* always release resources */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_close() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_query + * + * Purpose: Get the driver feature flags implemented by the driver. + * + * Return: SUCCEED (non-negative) (can't fail) + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_query(const H5FD_t H5_ATTR_UNUSED *_file, unsigned long *flags) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR; + + LOG_OP_CALL("H5FD_mirror_query"); + + /* Notice: the Mirror VFD Writer currently uses only the Sec2 driver as + * the underying driver -- as such, the Mirror VFD implementation copies + * the Sec2 feature flags as its own. + * + * File pointer is always NULL/unused -- the H5FD_FEAT_IGNORE_DRVRINFO flag + * is never included. + * -- JOS 2020-01-13 + */ + if (flags) { + *flags = 0 \ + | H5FD_FEAT_AGGREGATE_METADATA \ + | H5FD_FEAT_ACCUMULATE_METADATA \ + | H5FD_FEAT_DATA_SIEVE \ + | H5FD_FEAT_AGGREGATE_SMALLDATA \ + | H5FD_FEAT_POSIX_COMPAT_HANDLE \ + | H5FD_FEAT_SUPPORTS_SWMR_IO \ + | H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; + } + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* end H5FD_mirror_query() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_get_eoa + * + * Purpose: Gets the end-of-address marker for the file. The EOA marker + * is the first address past the last byte allocated in the + * format address space. + * + * Required to register the driver. + * + * Return: The end-of-address marker. + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + LOG_OP_CALL("H5FD_mirror_get_eoa"); + + HDassert(file); + + FUNC_LEAVE_NOAPI(file->eoa) +} /* end H5FD_mirror_get_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_set_eoa + * + * Purpose: Set the end-of-address marker for the file. This function is + * called shortly after an existing HDF5 file is opened in order + * to tell the driver where the end of the HDF5 data is located. + * + * Return: SUCCEED / FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr) +{ + H5FD_mirror_xmit_eoa_t xmit_eoa; + unsigned char xmit_buf[H5FD_MIRROR_XMIT_EOA_SIZE]; + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_set_eoa"); + + HDassert(file); + + file->eoa = addr; /* local copy */ + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_SET_EOA; + + xmit_eoa.pub = file->xmit; + xmit_eoa.type = (uint8_t)type; + xmit_eoa.eoa_addr = (uint64_t)addr; + + if (H5FD_mirror_xmit_encode_set_eoa(xmit_buf, + (const H5FD_mirror_xmit_eoa_t *)&xmit_eoa) + != H5FD_MIRROR_XMIT_EOA_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode set-eoa"); + } + + LOG_XMIT_BYTES("set-eoa", xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, + "unable to transmit set-eoa"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_set_eoa() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_get_eof + * + * Purpose: Returns the end-of-file marker, which is the greater of + * either the filesystem end-of-file or the HDF5 end-of-address + * markers. + * + * Required to register the driver. + * + * Return: End of file address, the first address past the end of the + * "file", either the filesystem file or the HDF5 file. + *------------------------------------------------------------------------- + */ +static haddr_t +H5FD_mirror_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + LOG_OP_CALL("H5FD_mirror_get_eof"); + + HDassert(file); + + FUNC_LEAVE_NOAPI(file->eof) +} /* end H5FD_mirror_get_eof() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_read + * + * Purpose: Required to register the driver. + * If called, MUST fail. + * + * Return: FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_read(H5FD_t H5_ATTR_UNUSED *_file, + H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED fapl_id, + haddr_t H5_ATTR_UNUSED addr, + size_t H5_ATTR_UNUSED size, + void H5_ATTR_UNUSED *buf) +{ + herr_t ret_value = FAIL; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + LOG_OP_CALL("H5FD_mirror_read"); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_write + * + * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR + * from buffer BUF according to data transfer properties in + * DXPL_ID. + * + * Send metadata regarding the write (location, size) to the + * remote Writer, then separately transmits the data. + * Both transmission expect an OK reply from the Writer. + * This two-exchange approach incurs significant overhead, + * but is a simple and modular approach. + * Start optimizations here. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_write(H5FD_t *_file, + H5FD_mem_t type, + hid_t H5_ATTR_UNUSED dxpl_id, + haddr_t addr, + size_t size, + const void *buf) +{ + H5FD_mirror_xmit_write_t xmit_write; + unsigned char xmit_buf[H5FD_MIRROR_XMIT_WRITE_SIZE]; + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_write"); + + HDassert(file); + HDassert(buf); + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_WRITE; + + xmit_write.pub = file->xmit; + xmit_write.size = (uint64_t)size; + xmit_write.offset = (uint64_t)addr; + xmit_write.type = (uint8_t)type; + + + /* Notify Writer of incoming data to write. */ + if (H5FD_mirror_xmit_encode_write(xmit_buf, + (const H5FD_mirror_xmit_write_t *)&xmit_write) + != H5FD_MIRROR_XMIT_WRITE_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode write"); + } + + LOG_XMIT_BYTES("write", xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit write"); + } + + /* Check that our write xmission was received */ + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + + /* Send the data to be written */ + if (HDwrite(file->sock_fd, buf, size) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit data"); + } + + /* Writer should reply that it got the data and is still okay/ready */ + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_truncate + * + * Purpose: Makes sure that the true file size is the same (or larger) + * than the end-of-address. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_truncate(H5FD_t *_file, + hid_t H5_ATTR_UNUSED dxpl_id, + hbool_t H5_ATTR_UNUSED closing) +{ + unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE]; + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + LOG_OP_CALL("H5FD_mirror_truncate"); + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_TRUNCATE; + + if (H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit)) + != H5FD_MIRROR_XMIT_HEADER_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode truncate"); + } + + LOG_XMIT_BYTES("truncate", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, + "unable to transmit truncate"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD_mirror_truncate() */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_lock + * + * Purpose: To place an advisory lock on a file. + * The lock type to apply depends on the parameter "rw": + * TRUE--opens for write: an exclusive lock + * FALSE--opens for read: a shared lock + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_lock(H5FD_t *_file, hbool_t rw) +{ + H5FD_mirror_xmit_lock_t xmit_lock; + unsigned char xmit_buf[H5FD_MIRROR_XMIT_LOCK_SIZE]; + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT; + + LOG_OP_CALL("H5FD_mirror_lock"); + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_LOCK; + + xmit_lock.pub = file->xmit; + xmit_lock.rw = (uint64_t)rw; + + if (H5FD_mirror_xmit_encode_lock(xmit_buf, + (const H5FD_mirror_xmit_lock_t *)&xmit_lock) + != H5FD_MIRROR_XMIT_LOCK_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode lock"); + } + + LOG_XMIT_BYTES("lock", xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit lock"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD_mirror_lock */ + + +/*------------------------------------------------------------------------- + * Function: H5FD_mirror_unlock + * + * Purpose: Remove the existing lock on the file. + * + * Return: SUCCEED/FAIL + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_mirror_unlock(H5FD_t *_file) +{ + unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE]; + H5FD_mirror_t *file = (H5FD_mirror_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT; + + LOG_OP_CALL("H5FD_mirror_unlock"); + + file->xmit.xmit_count = (file->xmit_i)++; + file->xmit.op = H5FD_MIRROR_OP_UNLOCK; + + if (H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit)) + != H5FD_MIRROR_XMIT_HEADER_SIZE) + { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode unlock"); + } + + LOG_XMIT_BYTES("unlock", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE); + + if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) { + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit unlock"); + } + + if (H5FD__mirror_verify_reply(file) == FAIL) { + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply"); + } + +done: + FUNC_LEAVE_NOAPI(ret_value); +} /* end H5FD_mirror_unlock */ + +#endif /* H5_HAVE_MIRROR_VFD */ + |