summaryrefslogtreecommitdiffstats
path: root/contrib/fmhash/fmhash.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/fmhash/fmhash.c')
-rw-r--r--contrib/fmhash/fmhash.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/contrib/fmhash/fmhash.c b/contrib/fmhash/fmhash.c
new file mode 100644
index 0000000..224b824
--- /dev/null
+++ b/contrib/fmhash/fmhash.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2018, Harshvardhan Shrivastava
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <stdint.h>
+#include <stddef.h>
+#ifndef _AIX
+#include <typedefs.h>
+#endif
+#include <sys/types.h>
+#include <string.h>
+#ifdef USE_HASH_XXHASH
+# include <xxhash.h>
+#endif
+
+#include "rsyslog.h"
+#include "parserif.h"
+#include "module-template.h"
+#include "rainerscript.h"
+
+
+
+MODULE_TYPE_FUNCTION
+MODULE_TYPE_NOKEEP
+DEF_FMOD_STATIC_DATA
+
+typedef uint64_t hash_t;
+typedef uint32_t seed_t;
+typedef struct hash_context_s hash_context_t;
+
+typedef hash_t (*hash_impl)(const void*, size_t, seed_t);
+
+typedef rsRetVal (*hash_wrapper_2)(struct svar *__restrict__ const
+ , struct svar *__restrict__ const, hash_context_t*, hash_t*);
+typedef rsRetVal (*hash_wrapper_3)(struct svar *__restrict__ const, struct svar *__restrict__ const
+ , struct svar *__restrict__ const, hash_context_t*, hash_t*);
+
+struct hash_context_s {
+ hash_impl hashXX;
+ hash_wrapper_2 hash_wrapper_1_2;
+ hash_wrapper_3 hash_wrapper_2_3;
+};
+
+/*
+ * Fowler–Noll–Vo hash 32 bit
+ * http://www.isthe.com/chongo/src/fnv/hash_32.c
+ */
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wunknown-attributes"
+#endif
+static hash_t
+#if defined(__clang__)
+__attribute__((no_sanitize("unsigned-integer-overflow")))
+#endif
+fnv_32(const void* input, size_t len, seed_t seed) {
+ unsigned char *bp = (unsigned char *)input; /* start of buffer */
+
+ /*
+ * FNV-1 hash each octet in the buffer
+ */
+ size_t i;
+ for (i = 0; i < len; i++) {
+ /* multiply by the 32 bit FNV magic prime mod 2^32 */
+ seed += (seed<<1) + (seed<<4) + (seed<<7) + (seed<<8) + (seed<<24);
+
+ /* xor the bottom with the current octet */
+ seed ^= (seed_t)*bp++;
+ }
+
+ /* return our new hash value */
+ return seed;
+}
+
+
+/*
+ * Modified Bernstein
+ * http://www.eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
+ */
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wunknown-attributes"
+#endif
+static hash_t
+#if defined(__clang__)
+__attribute__((no_sanitize("unsigned-integer-overflow")))
+#endif
+djb_hash(const void* input, size_t len, seed_t seed) {
+ const char *p = input;
+ hash_t hash = 5381;
+ size_t i;
+ for (i = 0; i < len; i++) {
+ hash = 33 * hash ^ p[i];
+ }
+
+ return hash + seed;
+}
+
+/*Get 32 bit hash for input*/
+static hash_t
+hash32(const void* input, size_t len, seed_t seed) {
+ hash_t xhash = 0;
+#ifdef USE_HASH_XXHASH
+ xhash = XXH32(input, len, seed);
+#else
+ xhash = fnv_32(input, len, seed);
+#endif
+ return xhash;
+}
+
+/*Get 64 bit hash for input*/
+static hash_t
+hash64(const void* input, size_t len, seed_t seed) {
+ hash_t xhash = 0;
+#ifdef USE_HASH_XXHASH
+ xhash = XXH64(input, len, seed);
+#else
+ xhash = djb_hash(input, len, seed);
+#endif
+ return xhash;
+}
+
+static rsRetVal
+hash_wrapper2(struct svar *__restrict__ const sourceVal
+ , struct svar *__restrict__ const seedVal, hash_context_t* hcontext, hash_t* xhash) {
+ DEFiRet;
+ int freeHashStr = 0, success = 0;
+ char *hashStr = NULL;
+ seed_t seed = 0;
+ if(seedVal) {
+ seed = var2Number(seedVal, &success);
+ if (!success) {
+ parser_warnmsg("fmhash: hashXX(string, seed) didn't get a valid 'seed' limit"
+ ", defaulting hash value to 0");
+ ABORT_FINALIZE(RS_RET_PARAM_ERROR);
+ }
+ }
+
+ hashStr = (char*)var2CString(sourceVal, &freeHashStr);
+ size_t len = strlen(hashStr);
+ (*xhash) = hcontext->hashXX(hashStr, len, seed);
+ DBGPRINTF("fmhash: hashXX generated hash %" PRIu64 " for string(%.*s)"
+ , (*xhash), (int)len, hashStr);
+finalize_it:
+ if (freeHashStr) {
+ free(hashStr);
+ }
+ RETiRet;
+}
+
+static rsRetVal
+hash_wrapper3(struct svar *__restrict__ const sourceVal, struct svar *__restrict__ const modVal
+ , struct svar *__restrict__ const seedVal, hash_context_t* hcontext, hash_t* xhash) {
+
+ DEFiRet;
+ int success = 0;
+ hash_t mod = var2Number(modVal, &success);
+ if (! success) {
+ parser_warnmsg("fmhash: hashXXmod(string, mod)/hash64mod(string, mod, seed) didn't"
+ " get a valid 'mod' limit, defaulting hash value to 0");
+ ABORT_FINALIZE(RS_RET_PARAM_ERROR);
+ }
+ if(mod == 0) {
+ parser_warnmsg("fmhash: hashXXmod(string, mod)/hash64mod(string, mod, seed) invalid"
+ ", 'mod' is zero, , defaulting hash value to 0");
+ ABORT_FINALIZE(RS_RET_PARAM_ERROR);
+ }
+
+ CHKiRet((hcontext->hash_wrapper_1_2(sourceVal, seedVal, hcontext, xhash)));
+ if(mod != 0) {
+ (*xhash) = (*xhash) % mod;
+ }
+ DBGPRINTF("fmhash: hashXXmod generated hash-mod %" PRIu64 ".", (*xhash));
+finalize_it:
+ RETiRet;
+}
+
+static void
+init_hash32_context(hash_context_t* hash32_context) {
+ hash32_context->hashXX = hash32;
+ hash32_context->hash_wrapper_1_2 = hash_wrapper2;
+ hash32_context->hash_wrapper_2_3 = hash_wrapper3;
+};
+
+static void
+init_hash64_context(hash_context_t* hash64_context) {
+ hash64_context->hashXX = hash64;
+ hash64_context->hash_wrapper_1_2 = hash_wrapper2;
+ hash64_context->hash_wrapper_2_3 = hash_wrapper3;
+};
+
+static void ATTR_NONNULL()
+fmHashXX(struct cnffunc *__restrict__ const func, struct svar *__restrict__ const ret,
+ void *__restrict__ const usrptr, wti_t *__restrict__ const pWti) {
+ DEFiRet;
+ struct svar hashStrVal;
+ struct svar seedVal;
+ hash_context_t* hcontext = NULL;
+ hash_t xhash = 0;
+ cnfexprEval(func->expr[0], &hashStrVal, usrptr, pWti);
+ if(func->nParams == 2) cnfexprEval(func->expr[1], &seedVal, usrptr, pWti);
+ ret->d.n = 0;
+ ret->datatype = 'N';
+ hcontext = (hash_context_t*) func->funcdata;
+ CHKiRet((hcontext->hash_wrapper_1_2(&hashStrVal
+ , (func->nParams == 2 ? &seedVal : NULL)
+ , hcontext, &xhash)));
+ ret->d.n = xhash;
+finalize_it:
+ varFreeMembers(&hashStrVal);
+ if(func->nParams == 2) varFreeMembers(&seedVal);
+}
+
+static void ATTR_NONNULL()
+fmHashXXmod(struct cnffunc *__restrict__ const func, struct svar *__restrict__ const ret,
+ void *__restrict__ const usrptr, wti_t *__restrict__ const pWti) {
+
+ DEFiRet;
+ struct svar hashStrVal;
+ struct svar modVal;
+ struct svar seedVal;
+ hash_context_t* hcontext = NULL;
+ hash_t xhash = 0;
+ cnfexprEval(func->expr[0], &hashStrVal, usrptr, pWti);
+ cnfexprEval(func->expr[1], &modVal, usrptr, pWti);
+ if(func->nParams == 3) cnfexprEval(func->expr[2], &seedVal, usrptr, pWti);
+ ret->d.n = 0;
+ ret->datatype = 'N';
+ hcontext = (hash_context_t*) func->funcdata;
+ CHKiRet((hcontext->hash_wrapper_2_3(&hashStrVal
+ , &modVal, func->nParams > 2 ? &seedVal : NULL
+ , hcontext, &xhash)));
+ ret->d.n = xhash;
+finalize_it:
+ varFreeMembers(&hashStrVal);
+ varFreeMembers(&modVal);
+ if(func->nParams == 3) varFreeMembers(&seedVal);
+}
+
+static inline sbool check_param_count_hash(unsigned short nParams) {
+ return (nParams != 1 && nParams != 2);
+}
+
+static inline sbool check_param_count_hashmod(unsigned short nParams) {
+ return (nParams != 2 && nParams != 3);
+}
+
+static rsRetVal ATTR_NONNULL(1)
+init_fmHash64(struct cnffunc *const func)
+{
+ DEFiRet;
+ hash_context_t *hash_context = NULL;
+ if(check_param_count_hash(func->nParams)) {
+ parser_errmsg("fmhash: hash64(string) / hash64(string, seed)"
+ " insufficient params.\n");
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+ }
+ func->destructable_funcdata = 1;
+ CHKmalloc(hash_context = calloc(1, sizeof(hash_context_t)));
+ init_hash64_context(hash_context);
+ func->funcdata = (void*)hash_context;
+
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal ATTR_NONNULL(1)
+init_fmHash64mod(struct cnffunc *const func)
+{
+ DEFiRet;
+ hash_context_t *hash_context = NULL;
+ if(check_param_count_hashmod(func->nParams)) {
+ parser_errmsg("fmhash: hash64mod(string, mod)/hash64mod(string, mod, seed)"
+ " insufficient params.\n");
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+ }
+ func->destructable_funcdata = 1;
+ CHKmalloc(hash_context = calloc(1, sizeof(hash_context_t)));
+ init_hash64_context(hash_context);
+ func->funcdata = (void*)hash_context;
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal ATTR_NONNULL(1)
+init_fmHash32(struct cnffunc *const func)
+{
+ DEFiRet;
+ hash_context_t *hash_context = NULL;
+ if(check_param_count_hash(func->nParams)) {
+ parser_errmsg("fmhash: hash32(string) / hash32(string, seed)"
+ " insufficient params.\n");
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+ }
+ func->destructable_funcdata = 1;
+ CHKmalloc(hash_context = calloc(1, sizeof(hash_context_t)));
+ init_hash32_context(hash_context);
+ func->funcdata = (void*)hash_context;
+
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal ATTR_NONNULL(1)
+init_fmHash32mod(struct cnffunc *const func)
+{
+ DEFiRet;
+ hash_context_t *hash_context = NULL;
+ if(check_param_count_hashmod(func->nParams)) {
+ parser_errmsg("fmhash: hash32mod(string, mod)/hash32mod(string, mod, seed)"
+ " insufficient params.\n");
+ ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS);
+ }
+ func->destructable_funcdata = 1;
+ CHKmalloc(hash_context = calloc(1, sizeof(hash_context_t)));
+ init_hash32_context(hash_context);
+ func->funcdata = (void*)hash_context;
+finalize_it:
+ RETiRet;
+}
+
+
+static struct scriptFunct functions[] = {
+ {"hash64", 1, 2, fmHashXX, init_fmHash64, NULL},
+ {"hash64mod", 2, 3, fmHashXXmod, init_fmHash64mod, NULL},
+ {"hash32", 1, 2, fmHashXX, init_fmHash32, NULL},
+ {"hash32mod", 2, 3, fmHashXXmod, init_fmHash32mod, NULL},
+ {NULL, 0, 0, NULL, NULL, NULL} //last element to check end of array
+};
+
+
+BEGINgetFunctArray
+CODESTARTgetFunctArray
+ dbgprintf("Hash: fmhhash\n");
+ *version = 1;
+ *functArray = functions;
+ENDgetFunctArray
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_FMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ dbgprintf("rsyslog fmhash init called, compiled with version %s\n", VERSION);
+ENDmodInit