From f4771fcc1c3fda21a46d0cb85d8b29e012254696 Mon Sep 17 00:00:00 2001 From: Alessio Vanni Date: Thu, 14 May 2020 16:03:10 +0200 Subject: Improved BIO API BIO now supports reading from and writing to in-memory buffers. For reading, an allocated buffer (array) and a size is passed as arguments to the function opening the handle. For writing, a GNUNET_Buffer is created and used internally. The buffer contents can be extracted using the relevant function. There is a new API in addition to the existing read/write: this new API is more "declarative" in nature and is meant to mimic APIs like GNUNET_SQ. The read/write operations are defined in an array of specs which are then "commited" in a single (non-atomic) operation, rather than explicitly executing multiple function calls and checking their return value. Also there are small changes to GNUNET_Buffer to account for BIO's new features. Signed-off-by: Christian Grothoff --- src/util/bio.c | 1219 +++++++++++++++++++++++++++++++++++++++++++++------ src/util/buffer.c | 23 +- src/util/test_bio.c | 601 +++++++++++++------------ 3 files changed, 1428 insertions(+), 415 deletions(-) (limited to 'src/util') diff --git a/src/util/bio.c b/src/util/bio.c index e05258f73..ce15f073b 100644 --- a/src/util/bio.c +++ b/src/util/bio.c @@ -47,13 +47,38 @@ #define MAX_META_DATA (1024 * 1024) +/** + * Enum used internally to know how buffering is handled. + * + * The idea is that by using an enum, BIO can be extended to support other + * kinds of "backend" for buffering (or just formatted I/O.) + */ +enum IOType +{ + /** + * The handle uses a file to read/write data. + */ + IO_FILE = 0, + + /** + * The data is stored entirely in memory. + */ + IO_BUFFER, +}; + + /** * Handle for buffered reading. */ struct GNUNET_BIO_ReadHandle { /** - * Underlying file abstraction. + * The "backend" type. + */ + enum IOType type; + + /** + * Handle to a file on disk, if @e type is #IO_FILE. */ struct GNUNET_DISK_FileHandle *fd; @@ -63,12 +88,12 @@ struct GNUNET_BIO_ReadHandle char *emsg; /** - * I/O buffer. Allocated at the end of the struct, do not free! + * I/O buffer. Do @b not free! */ char *buffer; /** - * Number of bytes available in read @e buffer. + * Number of bytes available in @e buffer. */ size_t have; @@ -91,7 +116,7 @@ struct GNUNET_BIO_ReadHandle * @return IO handle on success, NULL on error */ struct GNUNET_BIO_ReadHandle * -GNUNET_BIO_read_open (const char *fn) +GNUNET_BIO_read_open_file (const char *fn) { struct GNUNET_DISK_FileHandle *fd; struct GNUNET_BIO_ReadHandle *h; @@ -100,6 +125,7 @@ GNUNET_BIO_read_open (const char *fn) if (NULL == fd) return NULL; h = GNUNET_malloc (sizeof(struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE); + h->type = IO_FILE; h->buffer = (char *) &h[1]; h->size = BIO_BUFFER_SIZE; h->fd = fd; @@ -108,11 +134,32 @@ GNUNET_BIO_read_open (const char *fn) /** - * Close an open file. Reports if any errors reading + * Create a handle from an existing allocated buffer. + * + * @param buffer the buffer to use as source + * @param size the total size in bytes of the buffer + * @return IO handle on sucess, NULL on error + */ +struct GNUNET_BIO_ReadHandle * +GNUNET_BIO_read_open_buffer (void *buffer, size_t size) +{ + struct GNUNET_BIO_ReadHandle *h; + + h = GNUNET_new (struct GNUNET_BIO_ReadHandle); + h->type = IO_BUFFER; + h->buffer = buffer; + h->size = size; + return h; +} + + +/** + * Close an open handle. Reports if any errors reading * from the file were encountered. * * @param h file handle - * @param emsg set to the error message + * @param emsg set to the (allocated) error message + * if the handle has an error message, the return value is #GNUNET_SYSERR * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ int @@ -121,60 +168,63 @@ GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg) int err; err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR; - if (emsg != NULL) + if (NULL != emsg) *emsg = h->emsg; else GNUNET_free_non_null (h->emsg); - GNUNET_DISK_file_close (h->fd); + switch (h->type) + { + case IO_FILE: + GNUNET_DISK_file_close (h->fd); + break; + case IO_BUFFER: + break; + default: + break; + } GNUNET_free (h); return err; } /** - * Read the contents of a binary file into a buffer. + * Function used internally to read the contents of a file into a buffer. * - * @param h handle to an open file + * @param h the IO handle to read from * @param what describes what is being read (for error message creation) - * @param result the buffer to write the result to + * @param result the buffer to write the data to * @param len the number of bytes to read - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ -int -GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, - const char *what, - void *result, - size_t len) +static int +read_from_file (struct GNUNET_BIO_ReadHandle *h, + const char *what, + char *result, + size_t len) { - char *dst = result; + size_t pos = 0; size_t min; - size_t pos; ssize_t ret; - if (NULL != h->emsg) - return GNUNET_SYSERR; - pos = 0; do { - /* first, use buffer */ min = h->have - h->pos; - if (min > 0) + if (0 < min) { - if (min > len - pos) + if (len - pos < min) min = len - pos; - GNUNET_memcpy (&dst[pos], &h->buffer[h->pos], min); + GNUNET_memcpy (&result[pos], &h->buffer[h->pos], min); h->pos += min; pos += min; } - if (pos == len) - return GNUNET_OK; /* done! */ + if (len == pos) + return GNUNET_OK; GNUNET_assert (((off_t) h->have) == h->pos); - /* fill buffer */ ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size); if (-1 == ret) { GNUNET_asprintf (&h->emsg, - _ ("Error reading `%s': %s"), + _ ("Error reading `%s' from file: %s"), what, strerror (errno)); return GNUNET_SYSERR; @@ -182,7 +232,7 @@ GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, if (0 == ret) { GNUNET_asprintf (&h->emsg, - _ ("Error reading `%s': %s"), + _ ("Error reading `%s' from file: %s"), what, _ ("End of file")); return GNUNET_SYSERR; @@ -190,41 +240,84 @@ GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, h->pos = 0; h->have = ret; } - while (pos < len); /* should always be true */ + while (pos < len); return GNUNET_OK; } /** - * Read the contents of a binary file into a buffer. + * Function used internally to read the content of a buffer into a buffer. * - * @param h handle to an open file - * @param file name of the source file - * @param line line number in the source file + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +read_from_buffer (struct GNUNET_BIO_ReadHandle *h, + const char *what, + char *result, + size_t len) +{ + if (h->size < len || h->size - h->pos < len) + { + GNUNET_asprintf (&h->emsg, + _ ("Error while reading `%s' from buffer: %s"), + what, + _ ("Not enough data left")); + return GNUNET_SYSERR; + } + GNUNET_memcpy (result, h->buffer + h->pos, len); + h->pos += len; + return GNUNET_OK; +} + + +/** + * Read some contents into a buffer. + * + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) * @param result the buffer to write the result to * @param len the number of bytes to read * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ int -GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, - const char *file, - int line, - void *result, - size_t len) +GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *result, + size_t len) { - char what[PATH_MAX + 1024]; + char *dst = result; - GNUNET_snprintf (what, sizeof(what), "%s:%d", file, line); - return GNUNET_BIO_read (h, what, result, len); + if (NULL != h->emsg) + return GNUNET_SYSERR; + + if (0 == len) + return GNUNET_OK; + + switch (h->type) + { + case IO_FILE: + return read_from_file (h, what, dst, len); + case IO_BUFFER: + return read_from_buffer (h, what, dst, len); + default: + GNUNET_asprintf (&h->emsg, + _ ("Invalid handle type while reading `%s'"), + what); + return GNUNET_SYSERR; + } } /** - * Read 0-terminated string from a file. + * Read 0-terminated string. * - * @param h handle to an open file + * @param h the IO handle to read from * @param what describes what is being read (for error message creation) - * @param result the buffer to store a pointer to the (allocated) string to + * @param result where to store the pointer to the (allocated) string * (note that *result could be set to NULL as well) * @param max_length maximum allowed length for the string * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure @@ -238,10 +331,21 @@ GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, char *buf; uint32_t big; - if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big)) + if (GNUNET_OK != GNUNET_BIO_read_int32 (h, + _ ("string length"), + (int32_t *) &big)) { - GNUNET_free_non_null (h->emsg); - GNUNET_asprintf (&h->emsg, _ ("Error reading length of string `%s'"), what); + char *tmp = h->emsg; + if (NULL != tmp) + GNUNET_asprintf (&h->emsg, + _ ("%s (while reading `%s')"), + tmp, + what); + else + GNUNET_asprintf (&h->emsg, + _ ("Error reading length of string `%s'"), + what); + GNUNET_free_non_null (tmp); return GNUNET_SYSERR; } if (0 == big) @@ -274,7 +378,7 @@ GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, /** - * Read metadata container from a file. + * Read a metadata container. * * @param h handle to an open file * @param what describes what is being read (for error message creation) @@ -290,20 +394,23 @@ GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, char *buf; struct GNUNET_CONTAINER_MetaData *meta; - if (GNUNET_OK != GNUNET_BIO_read_int32 (h, (int32_t *) &size)) + if (GNUNET_OK != GNUNET_BIO_read_int32 (h, + _ ("metadata length"), + (int32_t *) &size)) return GNUNET_SYSERR; - if (size == 0) + if (0 == size) { *result = NULL; return GNUNET_OK; } - if (size > MAX_META_DATA) + if (MAX_META_DATA < size) { - GNUNET_asprintf (&h->emsg, - _ ("Serialized metadata `%s' larger than allowed (%u>%u)"), - what, - size, - MAX_META_DATA); + GNUNET_asprintf ( + &h->emsg, + _ ("Serialized metadata `%s' larger than allowed (%u > %u)"), + what, + size, + MAX_META_DATA); return GNUNET_SYSERR; } buf = GNUNET_malloc (size); @@ -316,7 +423,7 @@ GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, if (NULL == meta) { GNUNET_free (buf); - GNUNET_asprintf (&h->emsg, _ ("Metadata `%s' failed to deserialize"), what); + GNUNET_asprintf (&h->emsg, _ ("Failed to deserialize metadata `%s'"), what); return GNUNET_SYSERR; } GNUNET_free (buf); @@ -324,25 +431,56 @@ GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, return GNUNET_OK; } +/** + * Read a float. + * + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) + * @param f address of float to read + */ +int +GNUNET_BIO_read_float(struct GNUNET_BIO_ReadHandle *h, + const char *what, + float *f) +{ + int32_t *i = (int32_t *) f; + return GNUNET_BIO_read_int32 (h, what, i); +} + + +/** + * Read a double. + * + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) + * @param f address of double to read + */ +int +GNUNET_BIO_read_double(struct GNUNET_BIO_ReadHandle *h, + const char *what, + double *f) +{ + int64_t *i = (int64_t *) f; + return GNUNET_BIO_read_int64 (h, what, i); +} + /** * Read an (u)int32_t. * - * @param h hande to open file - * @param file name of the source file - * @param line line number in the source file - * @param i address of 32-bit integer to read + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) + * @param i where to store the data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, - const char *file, - int line, - int32_t *i) +GNUNET_BIO_read_int32 (struct GNUNET_BIO_ReadHandle *h, + const char *what, + int32_t *i) { int32_t big; - if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof(int32_t))) + if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof(int32_t))) return GNUNET_SYSERR; *i = ntohl (big); return GNUNET_OK; @@ -352,21 +490,19 @@ GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, /** * Read an (u)int64_t. * - * @param h hande to open file - * @param file name of the source file - * @param line line number in the source file - * @param i address of 64-bit integer to read + * @param h the IO handle to read from + * @param what describes what is being read (for error message creation) + * @param i where to store the data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, - const char *file, - int line, - int64_t *i) +GNUNET_BIO_read_int64 (struct GNUNET_BIO_ReadHandle *h, + const char *what, + int64_t *i) { int64_t big; - if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof(int64_t))) + if (GNUNET_OK != GNUNET_BIO_read (h, what, &big, sizeof(int64_t))) return GNUNET_SYSERR; *i = GNUNET_ntohll (big); return GNUNET_OK; @@ -379,17 +515,29 @@ GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, struct GNUNET_BIO_WriteHandle { /** - * Underlying file handle. + * The "backend" type. + */ + enum IOType type; + + /** + * Handle to a file on disk, if @e type is #IO_FILE. */ struct GNUNET_DISK_FileHandle *fd; /** - * I/O buffer. Do not free, allocated at the end of the struct. + * Error message, NULL if there were no errors. */ - char *buffer; + char *emsg; + + /** + * I/O buffer. + * This field is a void * because it is used to hold pointers to allocated + * structures or arrays and will be casted to the appropriate type. + */ + void *buffer; /** - * Number of bytes already in @e buffer. + * Number of bytes available in @e buffer. */ size_t have; @@ -403,25 +551,26 @@ struct GNUNET_BIO_WriteHandle /** * Open a file for writing. * - * @param fn file name to be opened + * @param fn name of the file to be opened * @return IO handle on success, NULL on error */ struct GNUNET_BIO_WriteHandle * -GNUNET_BIO_write_open (const char *fn) +GNUNET_BIO_write_open_file (const char *fn) { struct GNUNET_DISK_FileHandle *fd; struct GNUNET_BIO_WriteHandle *h; fd = GNUNET_DISK_file_open (fn, - GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE + GNUNET_DISK_OPEN_WRITE + | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) return NULL; h = GNUNET_malloc (sizeof(struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE); - h->buffer = (char *) &h[1]; + h->buffer = &h[1]; h->size = BIO_BUFFER_SIZE; h->fd = fd; return h; @@ -429,42 +578,94 @@ GNUNET_BIO_write_open (const char *fn) /** - * Close an open file for writing. + * Create a handle backed by an in-memory buffer. + * + * @return IO handle on success, NULL on error + */ +struct GNUNET_BIO_WriteHandle * +GNUNET_BIO_write_open_buffer (void) +{ + struct GNUNET_BIO_WriteHandle *h; + + h = GNUNET_new (struct GNUNET_BIO_WriteHandle); + h->type = IO_BUFFER; + h->buffer = (void *) GNUNET_malloc (sizeof (struct GNUNET_Buffer)); + return h; +} + + +/** + * Close an IO handle. + * If the handle was using a file, the file will be closed. * * @param h file handle + * @param emsg set to the (allocated) error message + * if the handle has an error message, the return value is #GNUNET_SYSERR * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ int -GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h) +GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h, char **emsg) { - int ret; + int err; - ret = GNUNET_SYSERR; - if ((NULL != h->fd) && (GNUNET_OK == (ret = GNUNET_BIO_flush (h)))) - GNUNET_DISK_file_close (h->fd); + err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR; + if (NULL != emsg) + *emsg = h->emsg; + else + GNUNET_free_non_null (h->emsg); + switch (h->type) + { + case IO_FILE: + if (NULL == h->fd) + return GNUNET_SYSERR; + if (GNUNET_OK != GNUNET_BIO_flush (h)) + { + if (NULL != emsg) + *emsg = h->emsg; + else + GNUNET_free_non_null (h->emsg); + err = GNUNET_SYSERR; + } + else + { + GNUNET_DISK_file_close (h->fd); + } + break; + case IO_BUFFER: + GNUNET_buffer_clear ((struct GNUNET_Buffer *) h->buffer); + GNUNET_free (h->buffer); + break; + } GNUNET_free (h); - return ret; + return err; } /** - * Force a buffered writer to flush its buffer + * Force a file-based buffered writer to flush its buffer. + * If the handle does not use a file, this function returs #GNUNET_OK + * without doing anything. * - * @param h the writer handle - * @return #GNUNET_OK upon success. Upon failure #GNUNET_SYSERR is returned and - * the file is closed + * @param h the IO handle + * @return #GNUNET_OK upon success. Upon failure #GNUNET_SYSERR is returned + * and the file is closed */ int GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h) { ssize_t ret; + if (IO_FILE != h->type) + return GNUNET_OK; + ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->have); if (ret != (ssize_t) h->have) { GNUNET_DISK_file_close (h->fd); h->fd = NULL; - return GNUNET_SYSERR; /* error */ + GNUNET_free_non_null (h->emsg); + GNUNET_asprintf (&h->emsg, _ ("Unable to flush buffer to file")); + return GNUNET_SYSERR; } h->have = 0; return GNUNET_OK; @@ -472,96 +673,213 @@ GNUNET_BIO_flush (struct GNUNET_BIO_WriteHandle *h) /** - * Write a buffer to a file. + * Get the IO handle's contents. + * If the handle doesn't use an in-memory buffer, this function returns + * #GNUNET_SYSERR. * - * @param h handle to open file - * @param buffer the data to write - * @param n number of bytes to write - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + * @param h the IO handle + * @param emsg set to the (allocated) error message + * if the handle has an error message the return value is #GNUNET_SYSERR + * @param contents where to store the pointer to the handle's contents + * @param size where to store the size of @e contents + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ int -GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, - const void *buffer, - size_t n) +GNUNET_BIO_get_buffer_contents (struct GNUNET_BIO_WriteHandle *h, + char **emsg, + void **contents, + size_t *size) +{ + if (IO_BUFFER != h->type) + return GNUNET_SYSERR; + if (NULL == contents || NULL == size) + return GNUNET_SYSERR; + int ret = (NULL != h->emsg) ? GNUNET_SYSERR : GNUNET_OK; + if (NULL != emsg) + *emsg = h->emsg; + else + GNUNET_free_non_null (h->emsg); + *contents = GNUNET_buffer_reap ((struct GNUNET_Buffer *) h->buffer, size); + return ret; +} + + +/** + * Function used internally to write the contents of a buffer into a file. + * + * @param h the IO handle to write to + * @param what describes what is being written (for error message creation) + * @param source the buffer to write + * @param len the number of bytes to write + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_to_file (struct GNUNET_BIO_WriteHandle *h, + const char *what, + const char *source, + size_t len) { - const char *src = buffer; size_t min; - size_t pos; + size_t pos = 0; + char *buffer = (char *) h->buffer; if (NULL == h->fd) + { + GNUNET_asprintf (&h->emsg, + _ ("Error while writing `%s' to file: %s"), + what, + _ ("No associated file")); return GNUNET_SYSERR; - pos = 0; + } + do { - /* first, just use buffer */ min = h->size - h->have; - if (min > n - pos) - min = n - pos; - GNUNET_memcpy (&h->buffer[h->have], &src[pos], min); + if (len - pos < min) + min = len - pos; + GNUNET_memcpy (&buffer[h->have], &source[pos], min); pos += min; h->have += min; - if (pos == n) - return GNUNET_OK; /* done */ + if (len == pos) + return GNUNET_OK; GNUNET_assert (h->have == h->size); if (GNUNET_OK != GNUNET_BIO_flush (h)) - return GNUNET_SYSERR; /* error */ + { + char *tmp = h->emsg; + GNUNET_asprintf (&h->emsg, + _ ("Error while writing `%s' to file: %s"), + what, + tmp); + GNUNET_free_non_null (tmp); + return GNUNET_SYSERR; + } } - while (pos < n); /* should always be true */ + while (pos < len); GNUNET_break (0); return GNUNET_OK; } /** - * Write a string to a file. + * Function used internally to write the contents of a buffer to another buffer. + * + * @param h the IO handle to write to + * @param what describes what is being written (for error message creation) + * @param source the buffer to write + * @param len the number of bytes to write + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_to_buffer (struct GNUNET_BIO_WriteHandle *h, + const char *what, + const char *source, + size_t len) +{ + GNUNET_buffer_write ((struct GNUNET_Buffer *) h->buffer, source, len); + h->have += len; + return GNUNET_OK; +} + + +/** + * Write a buffer to a handle. + * + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param buffer the data to write + * @param n number of bytes to write + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, + const char *what, + const void *buffer, + size_t n) +{ + const char *src = buffer; + + if (NULL != h->emsg) + return GNUNET_SYSERR; + + if (0 == n) + return GNUNET_OK; + + switch (h->type) + { + case IO_FILE: + return write_to_file (h, what, src, n); + case IO_BUFFER: + return write_to_buffer (h, what, src, n); + default: + GNUNET_asprintf (&h->emsg, + _ ("Invalid handle type while writing `%s'"), + what); + return GNUNET_SYSERR; + } +} + + +/** + * Write a 0-terminated string. * - * @param h handle to open file + * @param h the IO handle to write to + * @param what what is being written (for error message creation) * @param s string to write (can be NULL) * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s) +GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, + const char *what, + const char *s) { uint32_t slen; slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1); - if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen)) + if (GNUNET_OK != GNUNET_BIO_write_int32 (h, _ ("string length"), slen)) return GNUNET_SYSERR; if (0 != slen) - return GNUNET_BIO_write (h, s, slen - 1); + return GNUNET_BIO_write (h, what, s, slen - 1); return GNUNET_OK; } /** - * Write metadata container to a file. + * Write a metadata container. * - * @param h handle to open file + * @param h the IO handle to write to + * @param what what is being written (for error message creation) * @param m metadata to write * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, + const char *what, const struct GNUNET_CONTAINER_MetaData *m) { ssize_t size; char *buf; if (m == NULL) - return GNUNET_BIO_write_int32 (h, 0); + return GNUNET_BIO_write_int32 (h, _ ("metadata length"), 0); buf = NULL; size = GNUNET_CONTAINER_meta_data_serialize ( m, &buf, MAX_META_DATA, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); - if (size == -1) + if (-1 == size) { GNUNET_free (buf); + GNUNET_free_non_null (h->emsg); + GNUNET_asprintf (&h->emsg, + _ ("Failed to serialize metadata `%s'"), + what); return GNUNET_SYSERR; } - if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) || - (GNUNET_OK != GNUNET_BIO_write (h, buf, size))) + if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, + _ ("metadata length"), + (uint32_t) size)) + || (GNUNET_OK != GNUNET_BIO_write (h, what, buf, size))) { GNUNET_free (buf); return GNUNET_SYSERR; @@ -571,37 +889,670 @@ GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, } +/** + * Write a float. + * + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param f float to write + */ +int +GNUNET_BIO_write_float(struct GNUNET_BIO_WriteHandle *h, + const char *what, + float f) +{ + int32_t i = f; + return GNUNET_BIO_write_int32 (h, what, i); +} + + +/** + * Write a double. + * + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param f double to write + */ +int +GNUNET_BIO_write_double(struct GNUNET_BIO_WriteHandle *h, + const char *what, + double f) +{ + int64_t i = f; + return GNUNET_BIO_write_int64 (h, what, i); +} + + /** * Write an (u)int32_t. * - * @param h hande to open file + * @param h the IO handle to write to + * @param what what is being written (for error message creation) * @param i 32-bit integer to write * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i) +GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, + const char *what, + int32_t i) { int32_t big; big = htonl (i); - return GNUNET_BIO_write (h, &big, sizeof(int32_t)); + return GNUNET_BIO_write (h, what, &big, sizeof(int32_t)); } /** * Write an (u)int64_t. * - * @param h hande to open file + * @param h the IO handle to write to + * @param what what is being written (for error message creation) * @param i 64-bit integer to write * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int -GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i) +GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, + const char *what, + int64_t i) { int64_t big; big = GNUNET_htonll (i); - return GNUNET_BIO_write (h, &big, sizeof(int64_t)); + return GNUNET_BIO_write (h, what, &big, sizeof(int64_t)); +} + + +/** + * Function used internally to read some bytes from within a read spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to read from + * @param what what is being read (for error message creation) + * @param target where to store the data + * @param target_size how many bytes to read + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +read_spec_handler_object (void *cls, + struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *target, + size_t target_size) +{ + return GNUNET_BIO_read (h, what, target, target_size); +} + + +/** + * Create the specification to read a certain amount of bytes. + * + * @param what describes what is being read (for error message creation) + * @param result the buffer to write the result to + * @param len the number of bytes to read + * @return the read spec + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_object (const char *what, + void *result, + size_t len) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_object, + .cls = NULL, + .what = what, + .target = result, + .size = len, + }; + + return rs; +} + + +/** + * Function used interally to read a string from within a read spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to read from + * @param what what is being read (for error message creation) + * @param target where to store the data + * @param target_size how many bytes to read + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +read_spec_handler_string (void *cls, + struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *target, + size_t target_size) +{ + char **result = target; + return GNUNET_BIO_read_string (h, what, result, target_size); +} + + +/** + * Create the specification to read a 0-terminated string. + * + * @param what describes what is being read (for error message creation) + * @param result where to store the pointer to the (allocated) string + * (note that *result could be set to NULL as well) + * @param max_length maximum allowed length for the string + * @return the read spec + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_string (const char *what, + char **result, + size_t max_length) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_string, + .cls = NULL, + .target = result, + .size = max_length, + }; + + return rs; +} + + +/** + * Function used internally to read a metadata container from within a read + * spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to read from + * @param what what is being read (for error message creation) + * @param target where to store the data + * @param target_size ignored + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +read_spec_handler_meta_data (void *cls, + struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *target, + size_t target_size) +{ + struct GNUNET_CONTAINER_MetaData **result = target; + return GNUNET_BIO_read_meta_data (h, what, result); +} + + +/** + * Create the specification to read a metadata container. + * + * @param what describes what is being read (for error message creation) + * @param result the buffer to store a pointer to the (allocated) metadata + * @return the read spec + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_meta_data (const char *what, + struct GNUNET_CONTAINER_MetaData **result) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_meta_data, + .cls = NULL, + .target = result, + .size = 0, + }; + + return rs; +} + + +/** + * Function used internally to read an (u)int32_t from within a read spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to read from + * @param what what is being read (for error message creation) + * @param target where to store the data + * @param target_size ignored + * @retun #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +read_spec_handler_int32 (void *cls, + struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *target, + size_t target_size) +{ + int32_t *result = target; + return GNUNET_BIO_read_int32 (h, what, result); +} + + +/** + * Create the specification to read an (u)int32_t. + * + * @param what describes what is being read (for error message creation) + * @param i where to store the data + * @return the read spec + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_int32 (const char *what, + int32_t *i) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_int32, + .cls = NULL, + .target = i, + .size = 0, + }; + + return rs; +} + + +/** + * Function used internally to read an (u)int64_t from within a read spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to read from + * @param what what is being read (for error message creation) + * @param target where to store the data + * @param target_size ignored + * @retun #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +read_spec_handler_int64 (void *cls, + struct GNUNET_BIO_ReadHandle *h, + const char *what, + void *target, + size_t target_size) +{ + int64_t *result = target; + return GNUNET_BIO_read_int64 (h, what, result); +} + + +/** + * Create the specification to read an (u)int64_t. + * + * @param what describes what is being read (for error message creation) + * @param i where to store the data + * @return the read spec + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_int64 (const char *what, + int64_t *i) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_int64, + .cls = NULL, + .target = i, + .size = 0, + }; + + return rs; +} + + +/** + * Create the specification to read a float. + * + * @param what describes what is being read (for error message creation) + * @param f address of float to read + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_float(const char *what, float *f) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_int32, + .cls = NULL, + .target = (int32_t *) f, + .size = 0, + }; + + return rs; +} + + +/** + * Create the specification to read a double. + * + * @param what describes what is being read (for error message creation) + * @param f address of double to read + */ +struct GNUNET_BIO_ReadSpec +GNUNET_BIO_read_spec_double(const char *what, double *f) +{ + struct GNUNET_BIO_ReadSpec rs = { + .rh = &read_spec_handler_int64, + .cls = NULL, + .target = (int64_t *) f, + .size = 0, + }; + + return rs; +} + + +/** + * Execute the read specifications in order. + * + * @param h the IO handle to read from + * @param rs array of read specs + * the last element must be #GNUNET_BIO_read_spec_end + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_read_spec_commit (struct GNUNET_BIO_ReadHandle *h, + struct GNUNET_BIO_ReadSpec *rs) +{ + int ret = GNUNET_OK; + + for (size_t i=0; NULL!=rs[i].rh; ++i) + { + ret = rs[i].rh (rs[i].cls, h, rs[i].what, rs[i].target, rs[i].size); + if (GNUNET_OK != ret) + return ret; + } + + return ret; +} + + +/** + * Function used internally to write some bytes from within a write spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param source the data to write + * @param source_size how many bytes to write + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_spec_handler_object (void *cls, + struct GNUNET_BIO_WriteHandle *h, + const char *what, + void *source, + size_t source_size) +{ + return GNUNET_BIO_write (h, what, source, source_size); +} + + +/** + * Create the specification to read some bytes. + * + * @param what describes what is being written (for error message creation) + * @param source the data to write + * @param size how many bytes should be written + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_object (const char *what, + void *source, + size_t size) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_object, + .cls = NULL, + .what = what, + .source = source, + .source_size = size, + }; + + return ws; +} + + +/** + * Function used internally to write a 0-terminated string from within a write + * spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param source the data to write + * @param source_size ignored + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_spec_handler_string (void *cls, + struct GNUNET_BIO_WriteHandle *h, + const char *what, + void *source, + size_t source_size) +{ + const char *s = source; + return GNUNET_BIO_write_string (h, what, s); +} + + +/** + * Create the specification to write a 0-terminated string. + * + * @param what describes what is being read (for error message creation) + * @param s string to write (can be NULL) + * @return the read spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_string (const char *what, + const char *s) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_string, + .cls = NULL, + .what = what, + .source = (void *) s, + .source_size = 0, + }; + + return ws; +} + + +/** + * Function used internally to write a metadata container from within a write + * spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param source the data to write + * @param source_size ignored + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_spec_handler_meta_data (void *cls, + struct GNUNET_BIO_WriteHandle *h, + const char *what, + void *source, + size_t source_size) +{ + const struct GNUNET_CONTAINER_MetaData *m = source; + return GNUNET_BIO_write_meta_data (h, what, m); +} + + +/** + * Create the specification to write a metadata container. + * + * @param what what is being written (for error message creation) + * @param m metadata to write + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_meta_data (const char *what, + const struct GNUNET_CONTAINER_MetaData *m) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_meta_data, + .cls = NULL, + .what = what, + .source = (void *) m, + .source_size = 0, + }; + + return ws; +} + + +/** + * Function used internally to write an (u)int32_t from within a write spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param source the data to write + * @param source_size ignored + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_spec_handler_int32 (void *cls, + struct GNUNET_BIO_WriteHandle *h, + const char *what, + void *source, + size_t source_size) +{ + int32_t i = *(int32_t *) source; + return GNUNET_BIO_write_int32 (h, what, i); +} + + +/** + * Create the specification to write an (u)int32_t. + * + * @param what describes what is being written (for error message creation) + * @param i pointer to a 32-bit integer + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_int32 (const char *what, + int32_t *i) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_int32, + .cls = NULL, + .what = what, + .source = i, + .source_size = 0, + }; + + return ws; +} + + +/** + * Function used internally to write an (u)int64_t from within a write spec. + * + * @param cls ignored, always NULL + * @param h the IO handle to write to + * @param what what is being written (for error message creation) + * @param source the data to write + * @param source_size ignored + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +static int +write_spec_handler_int64 (void *cls, + struct GNUNET_BIO_WriteHandle *h, + const char *what, + void *source, + size_t source_size) +{ + int64_t i = *(int64_t *) source; + return GNUNET_BIO_write_int64 (h, what, i); +} + + +/** + * Create the specification to write an (u)int64_t. + * + * @param what describes what is being written (for error message creation) + * @param i pointer to a 64-bit integer + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_int64 (const char *what, + int64_t *i) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_int64, + .cls = NULL, + .what = what, + .source = i, + .source_size = 0, + }; + + return ws; +} + + +/** + * Create the specification to write a float. + * + * @param what describes what is being written (for error message creation) + * @param f pointer to a float + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_float(const char *what, float *f) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_int32, + .cls = NULL, + .what = what, + .source = (int32_t *) f, + .source_size = 0, + }; + + return ws; +} + + +/** + * Create the specification to write an double. + * + * @param what describes what is being written (for error message creation) + * @param f pointer to a double + * @return the write spec + */ +struct GNUNET_BIO_WriteSpec +GNUNET_BIO_write_spec_double(const char *what, double *f) +{ + struct GNUNET_BIO_WriteSpec ws = { + .wh = &write_spec_handler_int64, + .cls = NULL, + .what = what, + .source = (int64_t *) f, + .source_size = 0, + }; + + return ws; +} + + +/** + * Execute the write specifications in order. + * + * @param h the IO handle to write to + * @param ws array of write specs + * the last element must be #GNUNET_BIO_write_spec_end + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise + */ +int +GNUNET_BIO_write_spec_commit (struct GNUNET_BIO_WriteHandle *h, + struct GNUNET_BIO_WriteSpec *ws) +{ + int ret = GNUNET_OK; + + for (size_t i=0; NULL!=ws[i].wh; ++i) + { + ret = ws[i].wh (ws[i].cls, h, ws[i].what, ws[i].source, ws[i].source_size); + if (GNUNET_OK != ret) + return ret; + } + + /* If it's a file-based handle, the flush makes sure that the data in the + buffer is actualy written to the disk. */ + if (IO_FILE == h->type) + ret = GNUNET_BIO_flush (h); + + return ret; } diff --git a/src/util/buffer.c b/src/util/buffer.c index dabf630c7..c865f6307 100644 --- a/src/util/buffer.c +++ b/src/util/buffer.c @@ -130,7 +130,26 @@ GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf) buf->mem[buf->position++] = '\0'; } res = buf->mem; - *buf = (struct GNUNET_Buffer) { 0 }; + memset (buf, 0, sizeof (struct GNUNET_Buffer)); + return res; +} + + +/** + * Clear the buffer and return its contents. + * The caller is responsible to eventually #GNUNET_free + * the returned data. + * + * @param buf the buffer to reap the contents from + * @param size where to store the size of the returned data + * @returns the data contained in the string + */ +void * +GNUNET_buffer_reap (struct GNUNET_Buffer *buf, size_t *size) +{ + *size = buf->position; + void *res = buf->mem; + memset (buf, 0, sizeof (struct GNUNET_Buffer)); return res; } @@ -144,7 +163,7 @@ void GNUNET_buffer_clear (struct GNUNET_Buffer *buf) { GNUNET_free_non_null (buf->mem); - *buf = (struct GNUNET_Buffer) { 0 }; + memset (buf, 0, sizeof (struct GNUNET_Buffer)); } diff --git a/src/util/test_bio.c b/src/util/test_bio.c index 53b45c23a..0c8453121 100644 --- a/src/util/test_bio.c +++ b/src/util/test_bio.c @@ -30,363 +30,406 @@ #define TESTSTRING "testString" #define TESTNUMBER64 ((int64_t) 100000L) + static int -test_normal_rw () +test_normal_rw (void) { - char *msg; - int64_t testNum; - char *readResultString; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - struct GNUNET_CONTAINER_MetaData *metaDataW; - struct GNUNET_CONTAINER_MetaData *metaDataR; - - metaDataW = GNUNET_CONTAINER_meta_data_create (); - metaDataR = NULL; - GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_meta_data (fileW, metaDataW)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int64 (fileW, TESTNUMBER64)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - readResultString = NULL; - GNUNET_assert (GNUNET_OK == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResultString, 200)); - GNUNET_assert (NULL != readResultString); - GNUNET_assert (0 == strcmp (TESTSTRING, readResultString)); - GNUNET_free (readResultString); + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + void *buffer; + size_t buffer_size = 0; + char *filename = GNUNET_DISK_mktemp ("gnunet-bio"); + struct GNUNET_CONTAINER_MetaData *mdW; + struct GNUNET_CONTAINER_MetaData *mdR = NULL; + char *rString = NULL; + int64_t wNum = TESTNUMBER64; + int64_t rNum = 0; + + mdW = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_add_publication_date (mdW); + + struct GNUNET_BIO_WriteSpec ws[] = { + GNUNET_BIO_write_spec_string ("test-normal-rw-string", TESTSTRING), + GNUNET_BIO_write_spec_meta_data ("test-normal-rw-metadata", mdW), + GNUNET_BIO_write_spec_int64 ("test-normal-rw-int64", &wNum), + GNUNET_BIO_write_spec_end(), + }; + + struct GNUNET_BIO_ReadSpec rs[] = { + GNUNET_BIO_read_spec_string ("test-normal-rw-string", &rString, 200), + GNUNET_BIO_read_spec_meta_data ("test-normal-rw-metadata", &mdR), + GNUNET_BIO_read_spec_int64 ("test-normal-rw-int64", &rNum), + GNUNET_BIO_read_spec_end(), + }; + + /* I/O on file */ + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_spec_commit (wh, ws)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_spec_commit (rh, rs)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); + GNUNET_assert (0 == strcmp (TESTSTRING, rString)); + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_meta_data_test_equal (mdR, mdW)); + GNUNET_assert (wNum == rNum); + + GNUNET_CONTAINER_meta_data_destroy (mdR); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free(filename); + + /* I/O on buffer */ + wh = GNUNET_BIO_write_open_buffer (); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_spec_commit (wh, ws)); GNUNET_assert (GNUNET_OK == - GNUNET_BIO_read_meta_data (fileR, "Read meta error", - &metaDataR)); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_meta_data_test_equal (metaDataR, metaDataW)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_int64 (fileR, &testNum)); - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_CONTAINER_meta_data_destroy (metaDataW); - GNUNET_CONTAINER_meta_data_destroy (metaDataR); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); + GNUNET_BIO_get_buffer_contents (wh, + NULL, + &buffer, + &buffer_size)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_buffer (buffer, buffer_size); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_spec_commit (rh, rs)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); + GNUNET_assert (0 == strcmp (TESTSTRING, rString)); + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_meta_data_test_equal (mdR, mdW)); + GNUNET_assert (wNum == rNum); + + GNUNET_free (buffer); + + GNUNET_CONTAINER_meta_data_destroy (mdW); + GNUNET_CONTAINER_meta_data_destroy (mdR); return 0; } static int -test_nullstring_rw () +test_nullstring_rw (void) { - char *msg; - char *readResultString = (char *) "not null"; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, NULL)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - GNUNET_assert (GNUNET_OK == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResultString, 200)); - GNUNET_assert (NULL == readResultString); - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); - + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + char *rString = "not null"; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh, + "test-nullstring-rw", + NULL)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (rh, + "test-nullstring-rw", + &rString, 200)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == rString); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_emptystring_rw () +test_emptystring_rw (void) { - char *msg; - char *readResultString; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, "")); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - readResultString = NULL; - GNUNET_assert (GNUNET_OK == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResultString, 200)); - GNUNET_free (readResultString); - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + char *rString = NULL; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh, + "test-emptystring-rw", + "")); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (rh, + "test-emptystring-rw", + &rString, 200)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_free (rString); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_bigstring_rw () +test_bigstring_rw (void) { - char *msg; - char *readResultString; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - readResultString = NULL; - GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResultString, 1)); - GNUNET_assert (NULL == readResultString); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + char *rString = NULL; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (wh, + "test-bigstring-rw", + TESTSTRING)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_string (rh, + "test-bigstring-rw", + &rString, 1)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == rString); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_bigmeta_rw () +test_bigmeta_rw (void) { - char *msg; static char meta[1024 * 1024 * 10]; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - struct GNUNET_CONTAINER_MetaData *metaDataR; - - memset (meta, 'b', sizeof(meta)); - meta[sizeof(meta) - 1] = '\0'; - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, sizeof(meta))); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write (fileW, meta, sizeof(meta))); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - metaDataR = NULL; + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *mdR = NULL; + + memset (meta, 'b', sizeof (meta)); + meta[sizeof (meta) - 1] = '\0'; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh, + "test-bigmeta-rw-int32", + sizeof (meta))); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write (wh, + "test-bigmeta-rw-bytes", + meta, + sizeof (meta))); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_meta_data (fileR, "Read meta error", - &metaDataR)); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_assert (NULL == metaDataR); - GNUNET_free (fileName); + GNUNET_BIO_read_meta_data (rh, + "test-bigmeta-rw-metadata", + &mdR)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == mdR); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_directory_r () +test_directory_r (void) { -#ifdef __linux__ - char *msg; - char readResult[200]; - struct GNUNET_BIO_ReadHandle *fileR; - - fileR = GNUNET_BIO_read_open ("/dev"); - GNUNET_assert (NULL != fileR); - GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read (fileR, "Read error", readResult, - sizeof(readResult))); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); +#ifdef LINUX + struct GNUNET_BIO_ReadHandle *rh; + char rString[200]; + + rh = GNUNET_BIO_read_open_file ("/dev"); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read (rh, + "test-directory-r", + rString, + sizeof (rString))); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); #endif return 0; } static int -test_nullfile_rw () +test_nullfile_rw (void) { - static char fileNameNO[102401]; - struct GNUNET_BIO_WriteHandle *fileWNO; - struct GNUNET_BIO_ReadHandle *fileRNO; + static char filename[102401]; + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; - memset (fileNameNO, 'a', sizeof(fileNameNO)); - fileNameNO[sizeof(fileNameNO) - 1] = '\0'; + memset (filename, 'a', sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; - GNUNET_log_skip (1, GNUNET_NO); - fileWNO = GNUNET_BIO_write_open (fileNameNO); + GNUNET_log_skip (2, GNUNET_NO); + wh = GNUNET_BIO_write_open_file (filename); GNUNET_log_skip (0, GNUNET_YES); - GNUNET_assert (NULL == fileWNO); + GNUNET_assert (NULL == wh); - GNUNET_log_skip (1, GNUNET_NO); - fileRNO = GNUNET_BIO_read_open (fileNameNO); + GNUNET_log_skip (2, GNUNET_NO); + rh = GNUNET_BIO_read_open_file (filename); GNUNET_log_skip (0, GNUNET_YES); - GNUNET_assert (NULL == fileRNO); + GNUNET_assert (NULL == rh); + return 0; } static int -test_fullfile_rw () +test_fullfile_rw (void) { -#ifdef __linux__ - /* /dev/full only seems to exist on Linux */ - char *msg; - int64_t testNum; - char *readResultString; - char readResult[200]; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - struct GNUNET_CONTAINER_MetaData *metaDataW; - struct GNUNET_CONTAINER_MetaData *metaDataR; - - metaDataW = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); - - fileW = GNUNET_BIO_write_open ("/dev/full"); - GNUNET_assert (NULL != fileW); - (void) GNUNET_BIO_write (fileW, TESTSTRING, strlen (TESTSTRING)); - (void) GNUNET_BIO_write_string (fileW, TESTSTRING); - (void) GNUNET_BIO_write_meta_data (fileW, metaDataW); - GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); - GNUNET_CONTAINER_meta_data_destroy (metaDataW); - - fileW = GNUNET_BIO_write_open ("/dev/full"); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open ("/dev/null"); - GNUNET_assert (NULL != fileR); - GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read (fileR, "Read error", readResult, - sizeof(readResult))); - readResultString = NULL; - GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResultString, 200)); - GNUNET_assert (NULL == readResultString); - GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_int64 (fileR, &testNum)); - metaDataR = NULL; - GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_meta_data (fileR, "Read meta error", - &metaDataR)); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (NULL == metaDataR); +#ifdef LINUX + /* /dev/full doesn't exist on every platform */ + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *rString = NULL; + char rResult[200]; + struct GNUNET_CONTAINER_MetaData *mdW; + struct GNUNET_CONTAINER_MetaData *mdR = NULL; + + mdW = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_add_publication_date (mdW); + + struct GNUNET_BIO_WriteSpec ws[] = { + GNUNET_BIO_write_spec_object ("test-fullfile-rw-bytes", + TESTSTRING, + strlen (TESTSTRING)), + GNUNET_BIO_write_spec_string ("test-fullfile-rw-string", + TESTSTRING), + GNUNET_BIO_write_spec_meta_data ("test-fullfile-rw-metadata", + mdW), + GNUNET_BIO_write_spec_end (), + }; + + struct GNUNET_BIO_ReadSpec rs[] = { + GNUNET_BIO_read_spec_object ("test-fullfile-rw-bytes", + rResult, + sizeof (rResult)), + GNUNET_BIO_read_spec_string ("test-fullfile-rw-string", + &rString, + 200), + GNUNET_BIO_read_spec_meta_data ("test-fullfile-rw-metadata", + &mdR), + GNUNET_BIO_read_spec_end(), + }; + + wh = GNUNET_BIO_write_open_file ("/dev/full"); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_spec_commit (wh, ws)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file ("/dev/null"); + GNUNET_assert (NULL != rh); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_spec_commit (rh, rs)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == rString); + GNUNET_assert (NULL == mdR); #endif return 0; } static int -test_fakestring_rw () +test_fakestring_rw (void) { - char *msg; - int32_t tmpInt = 2; - char *readResult; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + char *rString = NULL; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh, + "test-fakestring-rw-int32", + 2)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_string (fileR, "Read string error", - &readResult, 200)); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); + GNUNET_BIO_read_string (rh, + "test-fakestring-rw-string", + &rString, 200)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == rString); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_fakemeta_rw () +test_fakemeta_rw (void) { - char *msg; - int32_t tmpInt = 2; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - struct GNUNET_CONTAINER_MetaData *metaDataR; - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - metaDataR = NULL; + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *mdR = NULL; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh, + "test-fakestring-rw-int32", + 2)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_meta_data (fileR, "Read meta error", - &metaDataR)); - GNUNET_assert (NULL == metaDataR); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_free (fileName); + GNUNET_BIO_read_meta_data (rh, + "test-fakestring-rw-metadata", + &mdR)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == mdR); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -test_fakebigmeta_rw () +test_fakebigmeta_rw (void) { - char *msg; - int32_t tmpInt = 1024 * 1024 * 10; - struct GNUNET_BIO_WriteHandle *fileW; - struct GNUNET_BIO_ReadHandle *fileR; - char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); - struct GNUNET_CONTAINER_MetaData *metaDataR; - - fileW = GNUNET_BIO_write_open (fileName); - GNUNET_assert (NULL != fileW); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); - GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); - - fileR = GNUNET_BIO_read_open (fileName); - GNUNET_assert (NULL != fileR); - metaDataR = NULL; + struct GNUNET_BIO_WriteHandle *wh; + struct GNUNET_BIO_ReadHandle *rh; + char *filename = GNUNET_DISK_mktemp ("gnunet_bio"); + struct GNUNET_CONTAINER_MetaData *mdR = NULL; + int32_t wNum = 1024 * 1024 * 10; + + wh = GNUNET_BIO_write_open_file (filename); + GNUNET_assert (NULL != wh); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (wh, + "test-fakebigmeta-rw-int32", + wNum)); + GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (wh, NULL)); + + rh = GNUNET_BIO_read_open_file (filename); + GNUNET_assert (NULL != rh); GNUNET_assert (GNUNET_SYSERR == - GNUNET_BIO_read_meta_data (fileR, "Read meta error", - &metaDataR)); - msg = NULL; - GNUNET_BIO_read_close (fileR, &msg); - GNUNET_free (msg); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); - GNUNET_assert (NULL == metaDataR); - GNUNET_free (fileName); + GNUNET_BIO_read_meta_data (rh, + "test-fakebigmeta-rw-metadata", + &mdR)); + GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_close (rh, NULL)); + + GNUNET_assert (NULL == mdR); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (filename)); + GNUNET_free (filename); return 0; } static int -check_string_rw () +check_string_rw (void) { GNUNET_assert (0 == test_nullstring_rw ()); GNUNET_assert (0 == test_emptystring_rw ()); @@ -397,7 +440,7 @@ check_string_rw () static int -check_metadata_rw () +check_metadata_rw (void) { GNUNET_assert (0 == test_fakebigmeta_rw ()); GNUNET_assert (0 == test_fakemeta_rw ()); @@ -407,7 +450,7 @@ check_metadata_rw () static int -check_file_rw () +check_file_rw (void) { GNUNET_assert (0 == test_normal_rw ()); GNUNET_assert (0 == test_nullfile_rw ()); -- cgit v1.2.3