header file, FUNC_ENTER / LEAVE, etc). Removed remaining personal email addresses from library source code (still needs cleaned from other directories). Misc. warning, style, and whitespace cleanup.
2018 lines
71 KiB
C
2018 lines
71 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* 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 "H5FDmirror_priv.h" /* Private header for the mirror VFD */
|
||
#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))
|
||
|
||
#ifndef BSWAP_64
|
||
#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))
|
||
#endif /* BSWAP_64 */
|
||
|
||
/* 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)); \
|
||
HDfflush(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 transmission buffers */
|
||
H5FL_BLK_DEFINE_STATIC(xmit);
|
||
|
||
/* Declare a free list to manage the H5FD_mirror_t struct */
|
||
H5FL_DEFINE_STATIC(H5FD_mirror_t);
|
||
|
||
/* Declare a free list to manage the H5FD_mirror_xmit_open_t struct */
|
||
H5FL_DEFINE_STATIC(H5FD_mirror_xmit_open_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(FUNC);
|
||
|
||
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(FUNC);
|
||
|
||
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_STATIC_NOERR
|
||
|
||
/* Reset VFL ID */
|
||
H5FD_MIRROR_g = 0;
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
HDassert(dest && x);
|
||
|
||
/* clear entire structure, but especially its filepath string area */
|
||
HDmemset(dest, 0, 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(__func__);
|
||
|
||
HDassert(dest && x);
|
||
|
||
/* clear entire structure, but especially its message string area */
|
||
HDmemset(dest, 0, 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(__func__);
|
||
|
||
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(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_close(const H5FD_mirror_xmit_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_lock(const H5FD_mirror_xmit_lock_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_open(const H5FD_mirror_xmit_open_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_set_eoa(const H5FD_mirror_xmit_eoa_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_reply(const H5FD_mirror_xmit_reply_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_write(const H5FD_mirror_xmit_write_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ---------------------------------------------------------------------------
|
||
*/
|
||
H5_ATTR_PURE hbool_t
|
||
H5FD_mirror_xmit_is_xmit(const H5FD_mirror_xmit_t *xmit)
|
||
{
|
||
LOG_OP_CALL(__func__);
|
||
|
||
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.
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5FD__mirror_verify_reply(H5FD_mirror_t *file)
|
||
{
|
||
unsigned char *xmit_buf = NULL;
|
||
struct H5FD_mirror_xmit_reply_t reply;
|
||
ssize_t read_ret = 0;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
HDassert(file && file->sock_fd);
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
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, 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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
fa = (H5FD_mirror_fapl_t *)H5MM_calloc(sizeof(H5FD_mirror_fapl_t));
|
||
if(NULL == fa)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, 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_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
new_fa = (H5FD_mirror_fapl_t *)H5MM_malloc(sizeof(H5FD_mirror_fapl_t));
|
||
if(new_fa == NULL)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, 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_STATIC_NOERR
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
/* 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(FUNC);
|
||
|
||
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(FUNC);
|
||
|
||
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)
|
||
{
|
||
int live_socket = -1;
|
||
struct sockaddr_in target_addr;
|
||
socklen_t addr_size;
|
||
unsigned char *xmit_buf = NULL;
|
||
H5FD_mirror_fapl_t fa;
|
||
H5FD_mirror_t *file = NULL;
|
||
H5FD_mirror_xmit_open_t *open_xmit = NULL;
|
||
H5FD_t *ret_value = NULL;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
/* --------------- */
|
||
/* 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_VFL, H5E_CANTALLOC, 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? */
|
||
|
||
open_xmit = (H5FD_mirror_xmit_open_t *)H5FL_CALLOC(H5FD_mirror_xmit_open_t);
|
||
if(NULL == open_xmit)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate open_xmit struct");
|
||
|
||
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);
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate xmit buffer");
|
||
|
||
if(H5FD_mirror_xmit_encode_open(xmit_buf, 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");
|
||
}
|
||
|
||
if(open_xmit)
|
||
open_xmit = H5FL_FREE(H5FD_mirror_xmit_open_t, open_xmit);
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* 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 = NULL;
|
||
int xmit_encoded = 0; /* monitor point of failure */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
/* Sanity check */
|
||
HDassert(file);
|
||
HDassert(file->sock_fd >= 0);
|
||
|
||
file->xmit.xmit_count = (file->xmit_i)++;
|
||
file->xmit.op = H5FD_MIRROR_OP_CLOSE;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
if(H5FD_mirror_xmit_encode_header(xmit_buf, &(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 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 error */
|
||
|
||
file = H5FL_FREE(H5FD_mirror_t, file); /* always release resources */
|
||
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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_STATIC_NOERR;
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
/* 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 = 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_STATIC_NOERR
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
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 = NULL;
|
||
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
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;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
if(H5FD_mirror_xmit_encode_set_eoa(xmit_buf, &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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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_STATIC_NOERR
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
HDassert(file);
|
||
|
||
FUNC_LEAVE_NOAPI(file->eof)
|
||
} /* end H5FD__mirror_get_eof() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5FD__mirror_read
|
||
*
|
||
* Purpose: Required to register the driver, but 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)
|
||
{
|
||
FUNC_ENTER_STATIC_NOERR
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
FUNC_LEAVE_NOAPI(FAIL)
|
||
} /* 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 = NULL;
|
||
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
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;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
/* Notify Writer of incoming data to write. */
|
||
if(H5FD_mirror_xmit_encode_write(xmit_buf, &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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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 = NULL;
|
||
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
file->xmit.xmit_count = (file->xmit_i)++;
|
||
file->xmit.op = H5FD_MIRROR_OP_TRUNCATE;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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 = NULL;
|
||
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
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;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
if(H5FD_mirror_xmit_encode_lock(xmit_buf, &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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
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 = NULL;
|
||
H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_STATIC
|
||
|
||
LOG_OP_CALL(FUNC);
|
||
|
||
file->xmit.xmit_count = (file->xmit_i)++;
|
||
file->xmit.op = H5FD_MIRROR_OP_UNLOCK;
|
||
|
||
xmit_buf = H5FL_BLK_MALLOC(xmit, H5FD_MIRROR_XMIT_BUFFER_MAX);
|
||
if(NULL == xmit_buf)
|
||
HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate xmit buffer");
|
||
|
||
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:
|
||
if(xmit_buf)
|
||
xmit_buf = H5FL_BLK_FREE(xmit, xmit_buf);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value);
|
||
} /* end H5FD__mirror_unlock */
|
||
|
||
#endif /* H5_HAVE_MIRROR_VFD */
|
||
|