Skip to content
Permalink
Browse files

Add macros to create constant Buffer objects.

These are more efficient than creating buffers in place when needed.

After replacement discovered that bufNewStr() and BufNewZ() were not being used in the core code so removed them.  This required using the macros in tests which is not the usual pattern.
  • Loading branch information...
dwsteele committed Apr 20, 2019
1 parent c916802 commit e513c52c0973772465a81a5db2ba18d0f956d686
@@ -21,6 +21,10 @@
</release-improvement-list>

<release-development-list>
<release-item>
<p>Add macros to create constant <code>Buffer</code> objects.</p>
</release-item>

<release-item>
<p>Add <code>unsigned int</code> <code>Variant</code> type and update code to use it.</p>
</release-item>
@@ -172,7 +172,7 @@ archiveAsyncStatusErrorWrite(ArchiveMode archiveMode, const String *walSegment,
storageNewWriteNP(
storageSpoolWrite(),
strNewFmt("%s/%s" STATUS_EXT_ERROR, strPtr(archiveAsyncSpoolQueue(archiveMode)), strPtr(errorFile))),
bufNewStr(strNewFmt("%d\n%s", code, strPtr(message))));
BUFSTR(strNewFmt("%d\n%s", code, strPtr(message))));
}
MEM_CONTEXT_TEMP_END();

@@ -200,7 +200,7 @@ archiveAsyncStatusOkWrite(ArchiveMode archiveMode, const String *walSegment, con
storageNewWriteNP(
storageSpoolWrite(),
strNewFmt("%s/%s" STATUS_EXT_OK, strPtr(archiveAsyncSpoolQueue(archiveMode)), strPtr(walSegment))),
warning == NULL ? NULL : bufNewStr(strNewFmt("0\n%s", strPtr(warning))));
warning == NULL ? NULL : BUFSTR(strNewFmt("0\n%s", strPtr(warning))));
}
MEM_CONTEXT_TEMP_END();

@@ -153,7 +153,7 @@ archiveGetFile(
ioFilterGroupAdd(
filterGroup,
cipherBlockFilter(
cipherBlockNew(cipherModeDecrypt, cipherType, bufNewStr(archiveGetCheckResult.cipherPass), NULL)));
cipherBlockNew(cipherModeDecrypt, cipherType, BUFSTR(archiveGetCheckResult.cipherPass), NULL)));
}

// If file is compressed then add the decompression filter
@@ -131,9 +131,7 @@ archivePushFile(
if (cipherType != cipherTypeNone)
{
ioFilterGroupAdd(
filterGroup,
cipherBlockFilter(
cipherBlockNew(cipherModeEncrypt, cipherType, bufNewStr(cipherPass), NULL)));
filterGroup, cipherBlockFilter(cipherBlockNew(cipherModeEncrypt, cipherType, BUFSTR(cipherPass), NULL)));
}

ioReadFilterGroupSet(storageFileReadIo(source), filterGroup);
@@ -133,18 +133,8 @@ ioWriteLine(IoWrite *this, const String *string)
ASSERT(string != NULL);
ASSERT(this->opened && !this->closed);

MEM_CONTEXT_TEMP_BEGIN()
{
// Load a buffer with the linefeed-terminated string
Buffer *buffer = bufNew(strSize(string) + 1);
memcpy(bufPtr(buffer), strPtr(string), strSize(string));
bufPtr(buffer)[strSize(string)] = '\n';
bufUsedSet(buffer, bufSize(buffer));

// Write the string
ioWrite(this, buffer);
}
MEM_CONTEXT_TEMP_END()
ioWrite(this, BUFSTR(string));
ioWrite(this, LF_BUF);

FUNCTION_LOG_RETURN_VOID();
}
@@ -7,17 +7,21 @@ Buffer Handler
#include "common/debug.h"
#include "common/type/buffer.h"

/***********************************************************************************************************************************
Constant buffers that are generally useful
***********************************************************************************************************************************/
BUFFER_STRDEF_EXTERN(BRACKETL_BUF, "[");
BUFFER_STRDEF_EXTERN(BRACKETR_BUF, "]");
BUFFER_STRDEF_EXTERN(EQ_BUF, "=");
BUFFER_STRDEF_EXTERN(LF_BUF, "\n");

/***********************************************************************************************************************************
Contains information about the buffer
***********************************************************************************************************************************/
struct Buffer
{
MemContext *memContext;
size_t size; // Actual size of buffer
bool limitSet; // Has a limit been set?
size_t limit; // Limited reported size of the buffer to make it appear smaller
size_t used; // Amount of buffer used
unsigned char *buffer; // Buffer allocation
BUFFER_COMMON // Variables that are common to static and dynamic buffers
MemContext *memContext; // Mem context for dynamic buffers
};

/***********************************************************************************************************************************
@@ -70,46 +74,6 @@ bufNewC(size_t size, const void *buffer)
FUNCTION_TEST_RETURN(this);
}

/***********************************************************************************************************************************
Create a new buffer from a string
***********************************************************************************************************************************/
Buffer *
bufNewStr(const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_END();

ASSERT(string != NULL);

// Create object and copy string
Buffer *this = bufNew(strSize(string));
memcpy(this->buffer, strPtr(string), bufSize(this));
this->used = bufSize(this);

FUNCTION_TEST_RETURN(this);
}

/***********************************************************************************************************************************
Create a new buffer from a zero-terminated string
***********************************************************************************************************************************/
Buffer *
bufNewZ(const char *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, string);
FUNCTION_TEST_END();

ASSERT(string != NULL);

// Create a new buffer and then copy the string into it.
Buffer *this = bufNew(strlen(string));
memcpy(this->buffer, string, bufSize(this));
this->used = bufSize(this);

FUNCTION_TEST_RETURN(this);
}

/***********************************************************************************************************************************
Append the contents of another buffer
***********************************************************************************************************************************/
@@ -17,8 +17,6 @@ Functions
***********************************************************************************************************************************/
Buffer *bufNew(size_t size);
Buffer *bufNewC(size_t size, const void *buffer);
Buffer *bufNewStr(const String *string);
Buffer *bufNewZ(const char *string);

Buffer *bufCat(Buffer *this, const Buffer *cat);
Buffer *bufCatC(Buffer *this, const unsigned char *cat, size_t catOffset, size_t catSize);
@@ -42,6 +40,70 @@ void bufUsedZero(Buffer *this);

void bufFree(Buffer *this);

/***********************************************************************************************************************************
Fields that are common between dynamically allocated and constant buffers
There is nothing user-accessible here but this construct allows constant buffers to be created and then handled by the same
functions that process dynamically allocated buffers.
***********************************************************************************************************************************/
#define BUFFER_COMMON \
size_t size; /* Actual size of buffer */ \
bool limitSet; /* Has a limit been set? */ \
size_t limit; /* Make the buffer appear smaller */ \
size_t used; /* Amount of buffer used */ \
unsigned char *buffer; /* Buffer allocation */

typedef struct BufferConst
{
BUFFER_COMMON
} BufferConst;

/***********************************************************************************************************************************
Macros for constant buffers
Frequently used constant buffers can be declared with these macros at compile time rather than dynamically at run time.
Note that buffers created in this way are declared as const so can't be modified or freed by the buf*() methods. Casting to
Buffer * will result in a segfault.
By convention all buffer constant identifiers are appended with _BUF.
***********************************************************************************************************************************/
// Create a buffer constant inline from an unsigned char[]
#define BUF(bufferParam, sizeParam) \
((const Buffer *)&(const BufferConst){.size = sizeParam, .used = sizeParam, .buffer = bufferParam})

// Create a buffer constant inline from a non-constant zero-terminated string
#define BUFSTRZ(stringz) \
BUF((unsigned char *)stringz, strlen(stringz))

// Create a buffer constant inline from a String
#define BUFSTR(string) \
BUF((unsigned char *)strPtr(string), strSize(string))

// Create a buffer constant inline from a constant zero-terminated string
#define BUFSTRDEF(stringdef) \
BUF((unsigned char *)stringdef, (sizeof(stringdef) - 1))

// Used to declare buffer constants that will be externed using BUFFER_DECLARE(). Must be used in a .c file.
#define BUFFER_STRDEF_EXTERN(name, string) \
const Buffer *name = BUFSTRDEF(string)

// Used to declare buffer constants that will be local to the .c file. Must be used in a .c file.
#define BUFFER_STRDEF_STATIC(name, string) \
static BUFFER_STRDEF_EXTERN(name, string)

// Used to extern buffer constants declared with BUFFER_STRDEF_EXTERN(. Must be used in a .h file.
#define BUFFER_DECLARE(name) \
extern const Buffer *name

/***********************************************************************************************************************************
Constant buffers that are generally useful
***********************************************************************************************************************************/
BUFFER_DECLARE(BRACKETL_BUF);
BUFFER_DECLARE(BRACKETR_BUF);
BUFFER_DECLARE(EQ_BUF);
BUFFER_DECLARE(LF_BUF);

/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
@@ -137,7 +137,7 @@ infoLoad(Info *this, const Storage *storage, bool copyFile, CipherType cipherTyp
ioReadFilterGroupSet(
storageFileReadIo(infoRead),
ioFilterGroupAdd(
ioFilterGroupNew(), cipherBlockFilter(cipherBlockNew(cipherModeDecrypt, cipherType, bufNewStr(cipherPass),
ioFilterGroupNew(), cipherBlockFilter(cipherBlockNew(cipherModeDecrypt, cipherType, BUFSTR(cipherPass),
NULL))));
}

@@ -53,8 +53,10 @@ STRING_STATIC(S3_XML_TAG_PREFIX_STR, "Prefix");
AWS authentication v4 constants
***********************************************************************************************************************************/
#define S3 "s3"
BUFFER_STRDEF_STATIC(S3_BUF, S3);
#define AWS4 "AWS4"
#define AWS4_REQUEST "aws4_request"
BUFFER_STRDEF_STATIC(AWS4_REQUEST_BUF, AWS4_REQUEST);
#define AWS4_HMAC_SHA256 "AWS4-HMAC-SHA256"

/***********************************************************************************************************************************
@@ -186,14 +188,14 @@ storageDriverS3Auth(
if (!strEq(date, this->signingKeyDate))
{
const Buffer *dateKey = cryptoHmacOne(
HASH_TYPE_SHA256_STR, bufNewStr(strNewFmt(AWS4 "%s", strPtr(this->secretAccessKey))), bufNewStr(date));
const Buffer *regionKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, dateKey, bufNewStr(this->region));
const Buffer *serviceKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, regionKey, bufNewZ(S3));
HASH_TYPE_SHA256_STR, BUFSTR(strNewFmt(AWS4 "%s", strPtr(this->secretAccessKey))), BUFSTR(date));
const Buffer *regionKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, dateKey, BUFSTR(this->region));
const Buffer *serviceKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, regionKey, S3_BUF);

// Switch to the object context so signing key and date are not lost
MEM_CONTEXT_BEGIN(this->memContext)
{
this->signingKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, serviceKey, bufNewZ(AWS4_REQUEST));
this->signingKey = cryptoHmacOne(HASH_TYPE_SHA256_STR, serviceKey, AWS4_REQUEST_BUF);
this->signingKeyDate = strDup(date);
}
MEM_CONTEXT_END();
@@ -203,7 +205,7 @@ storageDriverS3Auth(
const String *authorization = strNewFmt(
AWS4_HMAC_SHA256 " Credential=%s/%s/%s/" S3 "/" AWS4_REQUEST ",SignedHeaders=%s,Signature=%s",
strPtr(this->accessKey), strPtr(date), strPtr(this->region), strPtr(signedHeaders),
strPtr(bufHex(cryptoHmacOne(HASH_TYPE_SHA256_STR, this->signingKey, bufNewStr(stringToSign)))));
strPtr(bufHex(cryptoHmacOne(HASH_TYPE_SHA256_STR, this->signingKey, BUFSTR(stringToSign)))));

httpHeaderPut(httpHeader, S3_HEADER_AUTHORIZATION_STR, authorization);
}
@@ -48,20 +48,20 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewZ(BOGUS_STR));
BUFSTRDEF(BOGUS_STR));
TEST_ERROR(
archiveAsyncStatus(archiveModePush, segment, false), FormatError,
"000000010000000100000001.ok content must have at least two lines");

storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewZ(BOGUS_STR "\n"));
BUFSTRDEF(BOGUS_STR "\n"));
TEST_ERROR(
archiveAsyncStatus(archiveModePush, segment, false), FormatError, "000000010000000100000001.ok message must be > 0");

storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewZ(BOGUS_STR "\nmessage"));
BUFSTRDEF(BOGUS_STR "\nmessage"));
TEST_ERROR(
archiveAsyncStatus(archiveModePush, segment, false), FormatError, "unable to convert base 10 string 'BOGUS' to int");

@@ -70,13 +70,13 @@ testRun(void)

storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewZ("0\nwarning"));
BUFSTRDEF("0\nwarning"));
TEST_RESULT_BOOL(archiveAsyncStatus(archiveModePush, segment, false), true, "ok file with warning");
harnessLogResult("P00 WARN: warning");

storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.ok", strPtr(segment))),
bufNewZ("25\nerror"));
BUFSTRDEF("25\nerror"));
TEST_RESULT_BOOL(archiveAsyncStatus(archiveModePush, segment, false), true, "error status renamed to ok");
harnessLogResult(
"P00 WARN: WAL segment '000000010000000100000001' was not pushed due to error [25] and was manually skipped: error");
@@ -94,15 +94,15 @@ testRun(void)

storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.error", strPtr(segment))),
bufNewZ("25\nmessage"));
BUFSTRDEF("25\nmessage"));
TEST_ERROR(archiveAsyncStatus(archiveModePush, segment, true), AssertError, "message");

TEST_RESULT_BOOL(archiveAsyncStatus(archiveModePush, segment, false), false, "suppress error");

// -------------------------------------------------------------------------------------------------------------------------
storagePutNP(
storageNewWriteNP(storageSpoolWrite(), strNew(STORAGE_SPOOL_ARCHIVE_OUT "/global.error")),
bufNewZ("102\nexecute error"));
BUFSTRDEF("102\nexecute error"));

TEST_ERROR(archiveAsyncStatus(archiveModePush, strNew("anyfile"), true), ExecuteError, "execute error");
}
Oops, something went wrong.

0 comments on commit e513c52

Please sign in to comment.
You can’t perform that action at this time.