New upstream version 8.1.0
This commit is contained in:
351
client_module/source/common/toolkit/HashTk.c
Normal file
351
client_module/source/common/toolkit/HashTk.c
Normal file
@@ -0,0 +1,351 @@
|
||||
#include <common/toolkit/HashTk.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
|
||||
#define HashTkDefaultHash HASHTK_HALFMD4
|
||||
//#define HashTkDefaultHash HASHTK_HSIEHHASH32
|
||||
|
||||
#define Hashtk_HALFMD4_IN_BUF_SIZE 8
|
||||
#define HashTk_HALFMD4_OUT_BUF_SIZE 4
|
||||
#define HashTk_INT_BYTES 4
|
||||
|
||||
#define HashTk_HALFMD4_MAJOR_BUFPOS 1 // as in ext4
|
||||
#define HashTk_HALFMD4_MINOR_BUFPOS 2
|
||||
|
||||
|
||||
#ifdef KERNEL_HAS_HALF_MD4_TRANSFORM
|
||||
#include <linux/types.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#else
|
||||
/* half_md4_transform and macros taken from lib/halfmd4.c */
|
||||
/* F, G and H are basic MD4 functions: selection, majority, parity */
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
/*
|
||||
* The generic round function. The application is so specific that
|
||||
* we don't bother protecting all the arguments with parens, as is generally
|
||||
* good macro practice, in favor of extra legibility.
|
||||
* Rotation is separate from addition to prevent recomputation
|
||||
*/
|
||||
#define ROUND(f, a, b, c, d, x, s) \
|
||||
(a += f(b, c, d) + x, a = rol32(a, s))
|
||||
#define K1 0
|
||||
#define K2 013240474631UL
|
||||
#define K3 015666365641UL
|
||||
|
||||
/*
|
||||
* Basic cut-down MD4 transform. Returns only 32 bits of result.
|
||||
*/
|
||||
static __u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
|
||||
{
|
||||
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
/* Round 1 */
|
||||
ROUND(F, a, b, c, d, in[0] + K1, 3);
|
||||
ROUND(F, d, a, b, c, in[1] + K1, 7);
|
||||
ROUND(F, c, d, a, b, in[2] + K1, 11);
|
||||
ROUND(F, b, c, d, a, in[3] + K1, 19);
|
||||
ROUND(F, a, b, c, d, in[4] + K1, 3);
|
||||
ROUND(F, d, a, b, c, in[5] + K1, 7);
|
||||
ROUND(F, c, d, a, b, in[6] + K1, 11);
|
||||
ROUND(F, b, c, d, a, in[7] + K1, 19);
|
||||
|
||||
/* Round 2 */
|
||||
ROUND(G, a, b, c, d, in[1] + K2, 3);
|
||||
ROUND(G, d, a, b, c, in[3] + K2, 5);
|
||||
ROUND(G, c, d, a, b, in[5] + K2, 9);
|
||||
ROUND(G, b, c, d, a, in[7] + K2, 13);
|
||||
ROUND(G, a, b, c, d, in[0] + K2, 3);
|
||||
ROUND(G, d, a, b, c, in[2] + K2, 5);
|
||||
ROUND(G, c, d, a, b, in[4] + K2, 9);
|
||||
ROUND(G, b, c, d, a, in[6] + K2, 13);
|
||||
|
||||
/* Round 3 */
|
||||
ROUND(H, a, b, c, d, in[3] + K3, 3);
|
||||
ROUND(H, d, a, b, c, in[7] + K3, 9);
|
||||
ROUND(H, c, d, a, b, in[2] + K3, 11);
|
||||
ROUND(H, b, c, d, a, in[6] + K3, 15);
|
||||
ROUND(H, a, b, c, d, in[1] + K3, 3);
|
||||
ROUND(H, d, a, b, c, in[5] + K3, 9);
|
||||
ROUND(H, c, d, a, b, in[0] + K3, 11);
|
||||
ROUND(H, b, c, d, a, in[4] + K3, 15);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
|
||||
return buf[1]; /* "most hashed" word */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static uint32_t HashTk_HsiehHash32(const char* data, int len);
|
||||
|
||||
static void HashTk_string2HashBufSigned(const char *msg, int len, __u32 *buf, int num);
|
||||
|
||||
/**
|
||||
* Copied from ext4 hash.c (str2hashbuf_signed() )
|
||||
*/
|
||||
static void HashTk_string2HashBufSigned(const char *msg, int len, __u32 *buf, int num)
|
||||
{
|
||||
__u32 pad, val;
|
||||
int i;
|
||||
const signed char *scp = (const signed char *) msg;
|
||||
|
||||
pad = (__u32)len | ((__u32)len << 8);
|
||||
pad |= pad << 16;
|
||||
|
||||
val = pad;
|
||||
if (len > num*4)
|
||||
len = num * 4;
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i % 4) == 0)
|
||||
val = pad;
|
||||
val = ((int) scp[i]) + (val << 8);
|
||||
if ((i % 4) == 3) {
|
||||
*buf++ = val;
|
||||
val = pad;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
if (--num >= 0)
|
||||
*buf++ = val;
|
||||
while (--num >= 0)
|
||||
*buf++ = pad;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note: This is the Hsieh hash function, which is available under old BSD-style license.
|
||||
* (It performs very well on x86 and PowerPC archs compared to other famous hash functions.)
|
||||
*
|
||||
* @data the buffer for which you want the hash value to be computed (arbitraty length)
|
||||
* @len length of the data buffer
|
||||
*/
|
||||
uint32_t HashTk_HsiehHash32(const char* data, int len)
|
||||
{
|
||||
uint32_t hash = len, tmp;
|
||||
int rem;
|
||||
|
||||
if(unlikely(len <= 0 || data == NULL) )
|
||||
return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for(; len > 0; len--)
|
||||
{
|
||||
hash += get16bits(data);
|
||||
tmp = (get16bits(data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2 * sizeof(uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch(rem)
|
||||
{
|
||||
case 3:
|
||||
hash += get16bits(data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof(uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2:
|
||||
hash += get16bits(data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1:
|
||||
hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the halfMD4 hash computation.
|
||||
* Note: OutBuf must be an array of size HashTk_HALFMD4_OUT_BUF_SIZE
|
||||
*/
|
||||
static void HashTk_halfMD4(const char* data, int len, uint32_t* outBuf)
|
||||
{
|
||||
uint32_t inBuf[Hashtk_HALFMD4_IN_BUF_SIZE];
|
||||
int maxMD4StrLen = Hashtk_HALFMD4_IN_BUF_SIZE * HashTk_INT_BYTES; // 32
|
||||
const char* dataPtr = data;
|
||||
int remainingLen = len;
|
||||
|
||||
/* Initialize the default seed for the hash checksum functions, magic numbers taken from
|
||||
* ext4fs_dirhash() */
|
||||
outBuf[0] = 0x67452301;
|
||||
outBuf[1] = 0xefcdab89;
|
||||
outBuf[2] = 0x98badcfe;
|
||||
outBuf[3] = 0x10325476;
|
||||
|
||||
while (remainingLen > 0) {
|
||||
HashTk_string2HashBufSigned(dataPtr, len, inBuf, Hashtk_HALFMD4_IN_BUF_SIZE);
|
||||
half_md4_transform(outBuf, inBuf);
|
||||
|
||||
remainingLen -= maxMD4StrLen;
|
||||
dataPtr += maxMD4StrLen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t HashTk_hash32(HashTkHashTypes hashType, const char* data, int len)
|
||||
{
|
||||
switch (hashType)
|
||||
{
|
||||
default:
|
||||
{
|
||||
printk_fhgfs(KERN_INFO, "Unknown hashtype: %d\n", hashType);
|
||||
hashType = HashTkDefaultHash;
|
||||
}
|
||||
BEEGFS_FALLTHROUGH;
|
||||
|
||||
case HASHTK_HSIEHHASH32:
|
||||
{
|
||||
return HashTk_HsiehHash32(data, len);
|
||||
} break;
|
||||
|
||||
case HASHTK_HALFMD4:
|
||||
{
|
||||
uint32_t buf[HashTk_HALFMD4_OUT_BUF_SIZE];
|
||||
uint32_t majHash;
|
||||
|
||||
HashTk_halfMD4(data, len, buf);
|
||||
|
||||
majHash = buf[HashTk_HALFMD4_MAJOR_BUFPOS];
|
||||
|
||||
return majHash;
|
||||
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This generates the 64bit hash by computing two 32bit hashes for the first and second half
|
||||
* of the data buf.
|
||||
*
|
||||
* @data the buffer for which you want the hash value to be computed (arbitraty length)
|
||||
* @len length of the data buffer
|
||||
*/
|
||||
uint64_t HashTk_hash64(HashTkHashTypes hashType, const char* data, int len)
|
||||
{
|
||||
uint64_t hash64;
|
||||
|
||||
switch (hashType)
|
||||
{
|
||||
default:
|
||||
{
|
||||
printk_fhgfs(KERN_INFO, "Unknown hashtype: %d\n", hashType);
|
||||
hashType = HashTkDefaultHash;
|
||||
}
|
||||
BEEGFS_FALLTHROUGH;
|
||||
|
||||
case HASHTK_HSIEHHASH32:
|
||||
{
|
||||
int len1stHalf = len / 2;
|
||||
int len2ndHalf = len - len1stHalf;
|
||||
|
||||
uint64_t high = HashTk_HsiehHash32(data, len1stHalf);
|
||||
uint64_t low = HashTk_HsiehHash32(&data[len1stHalf], len2ndHalf);
|
||||
|
||||
hash64 = (high << 32) | low;
|
||||
} break;
|
||||
|
||||
case HASHTK_HALFMD4:
|
||||
{
|
||||
uint32_t buf[HashTk_HALFMD4_OUT_BUF_SIZE];
|
||||
uint32_t majHash;
|
||||
uint32_t minHash;
|
||||
|
||||
HashTk_halfMD4(data, len, buf);
|
||||
|
||||
majHash = buf[HashTk_HALFMD4_MAJOR_BUFPOS];
|
||||
minHash = buf[HashTk_HALFMD4_MINOR_BUFPOS];
|
||||
|
||||
hash64 = (uint64_t) majHash << 32 | (uint64_t) minHash;
|
||||
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return hash64;
|
||||
}
|
||||
|
||||
|
||||
// Generates sha256 hash using the kernel crypto interface.
|
||||
int HashTk_sha256(const unsigned char* data, unsigned int dataLen, unsigned char* outHash)
|
||||
{
|
||||
const char* hashAlgName = "sha256";
|
||||
struct crypto_shash *alg;
|
||||
struct shash_desc *sdesc;
|
||||
int res = 0;
|
||||
|
||||
alg = crypto_alloc_shash(hashAlgName, 0, 0);
|
||||
if(IS_ERR(alg))
|
||||
{
|
||||
printk_fhgfs(KERN_ERR, "Allocating shash failed: %ld\n", PTR_ERR(alg));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdesc = kmalloc(crypto_shash_descsize(alg), GFP_KERNEL);
|
||||
if (sdesc == NULL)
|
||||
{
|
||||
printk_fhgfs(KERN_ERR, "Allocating hash memory failed\n");
|
||||
crypto_free_shash(alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdesc->tfm = alg;
|
||||
|
||||
res = crypto_shash_digest(sdesc, data, dataLen, outHash);
|
||||
if (res != 0)
|
||||
{
|
||||
printk_fhgfs(KERN_ERR, "Calculating hash failed: %d\n", res);
|
||||
}
|
||||
|
||||
kfree(sdesc);
|
||||
crypto_free_shash(alg);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Generates sha256 hash from the input byte slice and returns the auth secret containing the
|
||||
// 8 most significant bytes of the hash in little endian order. Matches the behavior of other
|
||||
// implementations.
|
||||
int HashTk_authHash(const unsigned char* data, unsigned int dataLen, uint64_t* outHash)
|
||||
{
|
||||
int res;
|
||||
unsigned char buf[32];
|
||||
|
||||
res = HashTk_sha256(data, dataLen, buf);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
*outHash = 0;
|
||||
for(int i = 7; i >= 0; --i)
|
||||
{
|
||||
*outHash <<= 8;
|
||||
*outHash += buf[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
client_module/source/common/toolkit/HashTk.h
Normal file
36
client_module/source/common/toolkit/HashTk.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BUFFERTK_H_
|
||||
#define BUFFERTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
enum HashTkHashTypes;
|
||||
typedef enum HashTkHashTypes HashTkHashTypes;
|
||||
|
||||
|
||||
extern uint32_t HashTk_hash32(HashTkHashTypes hashType, const char* data, int len);
|
||||
extern uint64_t HashTk_hash64(HashTkHashTypes hashType, const char* data, int len);
|
||||
static inline uint64_t HashTk_hash(HashTkHashTypes hashType, size_t hashSize,
|
||||
const char* data, int len);
|
||||
|
||||
int HashTk_sha256(const unsigned char* data, unsigned dataLen, unsigned char* outHash);
|
||||
int HashTk_authHash(const unsigned char* data, unsigned dataLen, uint64_t* outHash);
|
||||
|
||||
enum HashTkHashTypes
|
||||
{
|
||||
HASHTK_HSIEHHASH32 = 0,
|
||||
HASHTK_HALFMD4, // as used by ext4
|
||||
};
|
||||
|
||||
/**
|
||||
* Caller decides if it wants a 32- or 64-bit hash
|
||||
*/
|
||||
uint64_t HashTk_hash(HashTkHashTypes hashType, size_t hashSize, const char* data, int len)
|
||||
{
|
||||
if (hashSize == 64)
|
||||
return HashTk_hash64(hashType, data, len);
|
||||
else
|
||||
return HashTk_hash32(hashType, data, len);
|
||||
}
|
||||
|
||||
|
||||
#endif /* BUFFERTK_H_ */
|
||||
185
client_module/source/common/toolkit/ListTk.c
Normal file
185
client_module/source/common/toolkit/ListTk.c
Normal file
@@ -0,0 +1,185 @@
|
||||
#include <common/nodes/ConnectionListIter.h>
|
||||
#include <common/net/sock/NicAddressListIter.h>
|
||||
#include <common/net/sock/NicAddressStatsListIter.h>
|
||||
#include <common/toolkit/list/StrCpyListIter.h>
|
||||
#include <common/toolkit/list/UInt16ListIter.h>
|
||||
#include <common/toolkit/tree/PointerRBTree.h>
|
||||
#include <common/toolkit/tree/PointerRBTreeIter.h>
|
||||
#include "ListTk.h"
|
||||
|
||||
#include <linux/sort.h>
|
||||
|
||||
struct nicaddr_sort_entry {
|
||||
StrCpyList* preferences;
|
||||
NicAddress* addr;
|
||||
};
|
||||
|
||||
static int nicaddr_sort_comp(const void* l, const void* r)
|
||||
{
|
||||
const struct nicaddr_sort_entry* lhs = l;
|
||||
const struct nicaddr_sort_entry* rhs = r;
|
||||
|
||||
StrCpyListIter it;
|
||||
|
||||
StrCpyListIter_init(&it, lhs->preferences);
|
||||
while (!StrCpyListIter_end(&it)) {
|
||||
const char* value = StrCpyListIter_value(&it);
|
||||
|
||||
if (strcmp(value, lhs->addr->name) == 0)
|
||||
return -1;
|
||||
if (strcmp(value, rhs->addr->name) == 0)
|
||||
return 1;
|
||||
|
||||
StrCpyListIter_next(&it);
|
||||
}
|
||||
|
||||
if (NicAddress_preferenceComp(lhs->addr, rhs->addr))
|
||||
return -1;
|
||||
if (NicAddress_preferenceComp(rhs->addr, lhs->addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ListTk_cloneNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone, bool includeTcp)
|
||||
{
|
||||
NicAddressListIter iter;
|
||||
|
||||
NicAddressList_init(nicListClone);
|
||||
|
||||
NicAddressListIter_init(&iter, nicList);
|
||||
|
||||
for( ; !NicAddressListIter_end(&iter); NicAddressListIter_next(&iter) )
|
||||
{
|
||||
NicAddress* nicAddr = NicAddressListIter_value(&iter);
|
||||
if (includeTcp || nicAddr->nicType != NICADDRTYPE_STANDARD)
|
||||
{
|
||||
NicAddress* nicAddrClone;
|
||||
|
||||
// clone element
|
||||
|
||||
nicAddrClone = (NicAddress*)os_kmalloc(sizeof(NicAddress) );
|
||||
|
||||
memcpy(nicAddrClone, nicAddr, sizeof(NicAddress) );
|
||||
|
||||
// append to the clone list
|
||||
NicAddressList_append(nicListClone, nicAddrClone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sorted clone of a nicList.
|
||||
*
|
||||
* Note: the comparison implemented here is a valid only if preferences contains
|
||||
* all possible names ever encountered, or none at all.
|
||||
*/
|
||||
void ListTk_cloneSortNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone,
|
||||
StrCpyList* preferences)
|
||||
{
|
||||
NicAddressListIter listIter;
|
||||
|
||||
struct nicaddr_sort_entry* list, *p;
|
||||
|
||||
/* i'm so sorry. we can't indicate failure here without a lot of work in App, and the
|
||||
* lists are usually tiny anyway. */
|
||||
list = kcalloc(NicAddressList_length(nicList), sizeof(*list), GFP_NOFS | __GFP_NOFAIL);
|
||||
p = list;
|
||||
|
||||
NicAddressListIter_init(&listIter, nicList);
|
||||
|
||||
while (!NicAddressListIter_end(&listIter)) {
|
||||
p->preferences = preferences;
|
||||
p->addr = NicAddressListIter_value(&listIter);
|
||||
|
||||
NicAddressListIter_next(&listIter);
|
||||
p++;
|
||||
}
|
||||
|
||||
sort(list, NicAddressList_length(nicList), sizeof(*list), nicaddr_sort_comp, NULL);
|
||||
|
||||
/* *maybe* the clone already contains elements, don't rely on its size */
|
||||
p = list;
|
||||
NicAddressList_init(nicListClone);
|
||||
while (NicAddressList_length(nicList) != NicAddressList_length(nicListClone)) {
|
||||
NicAddress* clone = os_kmalloc(sizeof(*clone));
|
||||
memcpy(clone, p->addr, sizeof(*clone));
|
||||
NicAddressList_append(nicListClone, clone);
|
||||
p++;
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
}
|
||||
|
||||
void ListTk_kfreeNicAddressListElems(NicAddressList* nicList)
|
||||
{
|
||||
NicAddressListIter nicIter;
|
||||
|
||||
NicAddressListIter_init(&nicIter, nicList);
|
||||
|
||||
for( ; !NicAddressListIter_end(&nicIter); NicAddressListIter_next(&nicIter) )
|
||||
{
|
||||
NicAddress* nicAddr = NicAddressListIter_value(&nicIter);
|
||||
kfree(nicAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void ListTk_kfreeNicAddressStatsListElems(NicAddressStatsList* nicStatsList)
|
||||
{
|
||||
NicAddressStatsListIter nicStatsIter;
|
||||
|
||||
NicAddressStatsListIter_init(&nicStatsIter, nicStatsList);
|
||||
|
||||
for( ; !NicAddressStatsListIter_end(&nicStatsIter); NicAddressStatsListIter_next(&nicStatsIter) )
|
||||
{
|
||||
NicAddressStats* nicStats = NicAddressStatsListIter_value(&nicStatsIter);
|
||||
NicAddressStats_uninit(nicStats);
|
||||
kfree(nicStats);
|
||||
}
|
||||
}
|
||||
|
||||
void ListTk_copyUInt16ListToVec(UInt16List* srcList, UInt16Vec* destVec)
|
||||
{
|
||||
UInt16ListIter listIter;
|
||||
|
||||
UInt16ListIter_init(&listIter, srcList);
|
||||
|
||||
for( ; !UInt16ListIter_end(&listIter); UInt16ListIter_next(&listIter) )
|
||||
{
|
||||
int currentElem = UInt16ListIter_value(&listIter);
|
||||
|
||||
UInt16Vec_append(destVec, currentElem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param outPos zero-based list position of the searchStr if found, undefined otherwise
|
||||
*/
|
||||
bool ListTk_listContains(char* searchStr, StrCpyList* list, ssize_t* outPos)
|
||||
{
|
||||
StrCpyListIter iter;
|
||||
|
||||
(*outPos) = 0;
|
||||
|
||||
StrCpyListIter_init(&iter, list);
|
||||
|
||||
for( ; !StrCpyListIter_end(&iter); StrCpyListIter_next(&iter) )
|
||||
{
|
||||
char* currentElem = StrCpyListIter_value(&iter);
|
||||
|
||||
if(!strcmp(searchStr, currentElem) )
|
||||
return true;
|
||||
|
||||
(*outPos)++;
|
||||
}
|
||||
|
||||
(*outPos) = -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
26
client_module/source/common/toolkit/ListTk.h
Normal file
26
client_module/source/common/toolkit/ListTk.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef LISTTK_H_
|
||||
#define LISTTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/net/sock/NicAddressList.h>
|
||||
#include <common/net/sock/NicAddressStatsList.h>
|
||||
#include <common/nodes/ConnectionList.h>
|
||||
#include <common/toolkit/list/StrCpyList.h>
|
||||
#include <common/toolkit/vector/StrCpyVec.h>
|
||||
#include <common/toolkit/vector/UInt16Vec.h>
|
||||
|
||||
|
||||
/* includeTcp indicates whether or not to include TCP NICs in the cloned list */
|
||||
extern void ListTk_cloneNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone, bool includeTcp);
|
||||
extern void ListTk_cloneSortNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone,
|
||||
StrCpyList* preferences);
|
||||
extern void ListTk_copyUInt16ListToVec(UInt16List* srcList, UInt16Vec* destVec);
|
||||
|
||||
extern void ListTk_kfreeNicAddressListElems(NicAddressList* nicList);
|
||||
|
||||
extern void ListTk_kfreeNicAddressStatsListElems(NicAddressStatsList* nicStatsList);
|
||||
|
||||
extern bool ListTk_listContains(char* searchStr, StrCpyList* list, ssize_t* outPos);
|
||||
|
||||
|
||||
#endif /*LISTTK_H_*/
|
||||
46
client_module/source/common/toolkit/LockingTk.h
Normal file
46
client_module/source/common/toolkit/LockingTk.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef LOCKINGTK_H_
|
||||
#define LOCKINGTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/storage/StorageDefinitions.h>
|
||||
|
||||
|
||||
static inline const char* LockingTk_lockTypeToStr(int entryLockType);
|
||||
|
||||
|
||||
/**
|
||||
* @param entryLockType ENTRYLOCKTYPE_...
|
||||
* @return pointer to static string (no freeing by caller required)
|
||||
*/
|
||||
const char* LockingTk_lockTypeToStr(int entryLockType)
|
||||
{
|
||||
if(entryLockType & ENTRYLOCKTYPE_NOWAIT)
|
||||
{
|
||||
if(entryLockType & ENTRYLOCKTYPE_UNLOCK)
|
||||
return "unlock|nowait";
|
||||
else
|
||||
if(entryLockType & ENTRYLOCKTYPE_EXCLUSIVE)
|
||||
return "exclusive|nowait";
|
||||
else
|
||||
if(entryLockType & ENTRYLOCKTYPE_SHARED)
|
||||
return "shared|nowait";
|
||||
else
|
||||
return "unknown|nowait";
|
||||
}
|
||||
else
|
||||
{ // waiting allowed
|
||||
if(entryLockType & ENTRYLOCKTYPE_UNLOCK)
|
||||
return "unlock|wait";
|
||||
else
|
||||
if(entryLockType & ENTRYLOCKTYPE_EXCLUSIVE)
|
||||
return "exclusive|wait";
|
||||
else
|
||||
if(entryLockType & ENTRYLOCKTYPE_SHARED)
|
||||
return "shared|wait";
|
||||
else
|
||||
return "unknown|wait";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* LOCKINGTK_H_ */
|
||||
164
client_module/source/common/toolkit/LookupIntentInfoOut.h
Normal file
164
client_module/source/common/toolkit/LookupIntentInfoOut.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef LOOKUPINTENTINFO_H_
|
||||
#define LOOKUPINTENTINFO_H_
|
||||
|
||||
#include <app/App.h>
|
||||
#include <common/Common.h>
|
||||
#include <common/net/message/storage/lookup/LookupIntentRespMsg.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/storage/Path.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/storage/EntryInfo.h>
|
||||
#include <common/storage/PathInfo.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/storage/StorageDefinitions.h>
|
||||
#include <common/storage/striping/StripePattern.h>
|
||||
#include <common/toolkit/list/UInt16List.h>
|
||||
|
||||
|
||||
struct LookupIntentInfoOut;
|
||||
typedef struct LookupIntentInfoOut LookupIntentInfoOut;
|
||||
|
||||
static inline void LookupIntentInfoOut_initFromRespMsg(LookupIntentInfoOut* this,
|
||||
LookupIntentRespMsg* respMsg);
|
||||
static inline void LookupIntentInfoOut_setEntryInfoPtr(LookupIntentInfoOut* this,
|
||||
EntryInfo* entryInfo);
|
||||
static inline void LookupIntentInfoOut_setStripePattern(LookupIntentInfoOut* this,
|
||||
StripePattern *pattern);
|
||||
|
||||
static inline void LookupIntentInfoOut_uninit(LookupIntentInfoOut* this);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Out-Args for _lookupCreateStat operations. Init only with LookupIntentInfoOut_prepare().
|
||||
*
|
||||
* Note: This needs preparation by the same caller that does init of LookupIntentInfoIn
|
||||
* (to assign some out-pointers before the actual method is called).
|
||||
*/
|
||||
struct LookupIntentInfoOut
|
||||
{
|
||||
int responseFlags; // combination of LOOKUPINTENTRESPMSG_FLAG_...
|
||||
|
||||
int lookupRes;
|
||||
int statRes;
|
||||
int createRes; // FhgfsOpsErr_...
|
||||
int revalidateRes; // FhgfsOpsErr_SUCCESS if still valid, any other value otherwise
|
||||
int openRes;
|
||||
|
||||
fhgfs_stat* fhgfsStat;
|
||||
|
||||
|
||||
EntryInfo* entryInfoPtr; // Note: Not owned by this object.
|
||||
// Only deserialized if either lookup or create was successful.
|
||||
int revalidateUpdatedFlags;
|
||||
|
||||
|
||||
unsigned fileHandleIDLen;
|
||||
const char* fileHandleID;
|
||||
|
||||
// only set if open was successful
|
||||
PathInfo pathInfo;
|
||||
|
||||
StripePattern* stripePattern;
|
||||
};
|
||||
|
||||
|
||||
static inline void LookupIntentInfoOut_prepare(LookupIntentInfoOut* this,
|
||||
EntryInfo* outEntryInfo, fhgfs_stat* outFhgfsStat)
|
||||
{
|
||||
// note: we only assign the pointers to the out-structs here
|
||||
this->entryInfoPtr = outEntryInfo;
|
||||
this->fhgfsStat = outFhgfsStat;
|
||||
|
||||
this->responseFlags = 0;
|
||||
|
||||
this->lookupRes = FhgfsOpsErr_INTERNAL;
|
||||
this->statRes = FhgfsOpsErr_INTERNAL;
|
||||
this->createRes = FhgfsOpsErr_INTERNAL;
|
||||
this->revalidateRes = FhgfsOpsErr_INTERNAL;
|
||||
this->openRes = FhgfsOpsErr_INTERNAL;
|
||||
|
||||
this->stripePattern = NULL;
|
||||
}
|
||||
|
||||
void LookupIntentInfoOut_initFromRespMsg(LookupIntentInfoOut* this,
|
||||
LookupIntentRespMsg* respMsg)
|
||||
{
|
||||
this->responseFlags = respMsg->responseFlags;
|
||||
|
||||
this->lookupRes = respMsg->lookupResult;
|
||||
|
||||
if (this->responseFlags & LOOKUPINTENTRESPMSG_FLAG_CREATE)
|
||||
this->createRes = respMsg->createResult;
|
||||
|
||||
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_STAT)
|
||||
{
|
||||
this->statRes = respMsg->statResult;
|
||||
|
||||
if (this->statRes == FhgfsOpsErr_SUCCESS)
|
||||
StatData_getOsStat(&respMsg->statData, this->fhgfsStat);
|
||||
}
|
||||
|
||||
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_REVALIDATE)
|
||||
{
|
||||
this->revalidateRes = respMsg->revalidateResult;
|
||||
|
||||
/* no need to fill in EntryInfo on revalidate, we (the client) already have it. Only flags
|
||||
* might need to be updated. */
|
||||
this->revalidateUpdatedFlags = respMsg->entryInfo.featureFlags;
|
||||
}
|
||||
else
|
||||
if (respMsg->lookupResult == FhgfsOpsErr_SUCCESS || respMsg->createResult == FhgfsOpsErr_SUCCESS)
|
||||
EntryInfo_dup(&respMsg->entryInfo, this->entryInfoPtr);
|
||||
|
||||
|
||||
// only provided by the server on open
|
||||
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_OPEN)
|
||||
{
|
||||
this->openRes = respMsg->openResult;
|
||||
|
||||
if (respMsg->openResult == FhgfsOpsErr_SUCCESS)
|
||||
{
|
||||
this->fileHandleIDLen = respMsg->fileHandleIDLen;
|
||||
this->fileHandleID = kstrndup(respMsg->fileHandleID, respMsg->fileHandleIDLen, GFP_NOFS);
|
||||
|
||||
PathInfo_dup(&respMsg->pathInfo, &this->pathInfo);
|
||||
|
||||
this->stripePattern =
|
||||
StripePattern_createFromBuf(respMsg->patternStart, respMsg->patternLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LookupIntentInfoOut_setEntryInfoPtr(LookupIntentInfoOut* this, EntryInfo* entryInfo)
|
||||
{
|
||||
this->entryInfoPtr = entryInfo;
|
||||
}
|
||||
|
||||
void LookupIntentInfoOut_setStripePattern(LookupIntentInfoOut* this, StripePattern *pattern)
|
||||
{
|
||||
this->stripePattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitialize (free) LookupIntentInfoOut values
|
||||
*/
|
||||
void LookupIntentInfoOut_uninit(LookupIntentInfoOut* this)
|
||||
{
|
||||
// Free EntryInfo values
|
||||
if ( (this->entryInfoPtr) &&
|
||||
(this->createRes == FhgfsOpsErr_SUCCESS || this->lookupRes == FhgfsOpsErr_SUCCESS) )
|
||||
EntryInfo_uninit(this->entryInfoPtr);
|
||||
|
||||
// Destruct PathInfo
|
||||
if (this->openRes == FhgfsOpsErr_SUCCESS)
|
||||
{ // unitialize values only set on open success and if there was an open at all
|
||||
PathInfo_uninit(&this->pathInfo);
|
||||
|
||||
if (this->stripePattern)
|
||||
StripePattern_virtualDestruct(this->stripePattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /*LOOKUPINTENTINFO_H_*/
|
||||
40
client_module/source/common/toolkit/MathTk.h
Normal file
40
client_module/source/common/toolkit/MathTk.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef OPEN_MATHTK_H_
|
||||
#define OPEN_MATHTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
|
||||
static inline unsigned MathTk_log2Int32(unsigned value);
|
||||
static inline bool MathTk_isPowerOfTwo(unsigned value);
|
||||
|
||||
/**
|
||||
* Base 2 logarithm.
|
||||
*
|
||||
* See log2Int64() for details.
|
||||
*/
|
||||
unsigned MathTk_log2Int32(unsigned value)
|
||||
{
|
||||
/* __builtin_clz: Count leading zeros - returns the number of leading 0-bits in x, starting
|
||||
* at the most significant bit position. If x is 0, the result is undefined. */
|
||||
// (note: 8 is bits_per_byte)
|
||||
unsigned result = (sizeof(value) * 8) - 1 - __builtin_clz(value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there is only a single bit set in value, in which case value is a power of
|
||||
* two.
|
||||
*
|
||||
* @param value may not be 0 (result is undefined in that case).
|
||||
* @return true if only a single bit is set (=> value is a power of two), false otherwise
|
||||
*/
|
||||
bool MathTk_isPowerOfTwo(unsigned value)
|
||||
{
|
||||
//return ( (x != 0) && !(x & (x - 1) ) ); // this version is compatible with value==0
|
||||
|
||||
return !(value & (value - 1) );
|
||||
}
|
||||
|
||||
|
||||
#endif /* OPEN_MATHTK_H_ */
|
||||
826
client_module/source/common/toolkit/MessagingTk.c
Normal file
826
client_module/source/common/toolkit/MessagingTk.c
Normal file
@@ -0,0 +1,826 @@
|
||||
#include <app/App.h>
|
||||
#include <common/net/message/control/GenericResponseMsg.h>
|
||||
#include <common/nodes/MirrorBuddyGroupMapper.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/nodes/NodeConnPool.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/nodes/TargetStateStore.h>
|
||||
#include <nodes/NodeStoreEx.h>
|
||||
#include <toolkit/NoAllocBufferStore.h>
|
||||
#include "MessagingTk.h"
|
||||
|
||||
|
||||
#define MSGTK_KMALLOC_RECV_BUF_LEN (4*1024) /* kmalloc-style recv is only ok for small replies */
|
||||
#define MSGTK_STATE_SLEEP_MS 5000 /* how long to sleep if target state not good/offline */
|
||||
#define MSGTK_INFINITE_RETRY_WAIT_MS 5000 // how long to wait if peer asks for retry
|
||||
|
||||
/**
|
||||
* Note: rrArgs->outRespBuf must be returned/freed by the caller (depending on respBufType)
|
||||
* @param sock socket to use. If null, one will be pulled from Node's pool
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseWithRRArgsSock(App* app,
|
||||
RequestResponseArgs* rrArgs, Socket* sock)
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
const char* logContext = "Messaging (RPC)";
|
||||
|
||||
bool infiniteRetries = rrArgs->numRetries ? false : true;
|
||||
|
||||
unsigned currentRetryNum = 0;
|
||||
FhgfsOpsErr commRes;
|
||||
bool wasIndirectCommErr = false;
|
||||
|
||||
for( ; ; ) // retry loop
|
||||
{
|
||||
App_incNumRPCs(app);
|
||||
|
||||
commRes = __MessagingTk_requestResponseWithRRArgsComm(app, rrArgs, NULL, &wasIndirectCommErr, sock);
|
||||
if(likely(commRes == FhgfsOpsErr_SUCCESS) )
|
||||
return FhgfsOpsErr_SUCCESS;
|
||||
else
|
||||
if (fatal_signal_pending(current))
|
||||
{ // no retry allowed in this situation
|
||||
return FhgfsOpsErr_INTERRUPTED;
|
||||
}
|
||||
else
|
||||
if(!Node_getIsActive(rrArgs->node) )
|
||||
{ // no retry allowed in this situation
|
||||
return FhgfsOpsErr_UNKNOWNNODE;
|
||||
}
|
||||
else
|
||||
if(commRes == FhgfsOpsErr_WOULDBLOCK)
|
||||
return FhgfsOpsErr_COMMUNICATION; // no retries in this case
|
||||
else
|
||||
if( (commRes == FhgfsOpsErr_AGAIN) && App_getConnRetriesEnabled(app) )
|
||||
{ // retry infinitely
|
||||
currentRetryNum = 0;
|
||||
|
||||
Thread_sleep(MSGTK_INFINITE_RETRY_WAIT_MS);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if(commRes != FhgfsOpsErr_COMMUNICATION)
|
||||
{ // no retry allowed in this situation
|
||||
return commRes;
|
||||
}
|
||||
|
||||
if(App_getConnRetriesEnabled(app) &&
|
||||
(infiniteRetries || (currentRetryNum < rrArgs->numRetries) ) )
|
||||
{ // we have a retry left
|
||||
MessagingTk_waitBeforeRetry(currentRetryNum);
|
||||
currentRetryNum++;
|
||||
|
||||
if(currentRetryNum == 1 // log retry message only on first retry (to not spam the log)
|
||||
&& !(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_RETRY) )
|
||||
{
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Retrying communication with node: %s", nodeAndType.buf);
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // no more retries left
|
||||
return FhgfsOpsErr_COMMUNICATION;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: You probably rather want to call the alternative method, which gets buffers from the
|
||||
* store (unless you are the logger and want to avoid a deadlock wrt depleted msg buffers from the
|
||||
* store).
|
||||
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
|
||||
* broken connection from the conn pool.)
|
||||
*
|
||||
* @param outRespBuf will be kmalloced and needs to be kfreed by the caller
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseKMalloc(App* app, Node* node, NetMessage* requestMsg,
|
||||
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
|
||||
{
|
||||
RequestResponseArgs rrArgs;
|
||||
FhgfsOpsErr rrRes;
|
||||
|
||||
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
|
||||
|
||||
rrArgs.respBufType = MessagingTkBufType_kmalloc;
|
||||
|
||||
rrRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
|
||||
|
||||
*outRespBuf = rrArgs.outRespBuf;
|
||||
*outRespMsg = rrArgs.outRespMsg;
|
||||
|
||||
return rrRes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
|
||||
* broken connection from the conn pool.)
|
||||
*
|
||||
* @param outRespBuf must be returned to the store - not freed!
|
||||
* @param sock socket to use. If null, one will be pulled from Node's pool
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseSock(App* app, Node* node, NetMessage* requestMsg,
|
||||
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg, Socket* sock)
|
||||
{
|
||||
RequestResponseArgs rrArgs;
|
||||
FhgfsOpsErr rrRes;
|
||||
|
||||
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
|
||||
|
||||
rrRes = MessagingTk_requestResponseWithRRArgsSock(app, &rrArgs, sock);
|
||||
|
||||
*outRespBuf = rrArgs.outRespBuf;
|
||||
*outRespMsg = rrArgs.outRespMsg;
|
||||
|
||||
return rrRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Uses the number of retries that has been defined in the app config.
|
||||
*
|
||||
* @param outRespBuf must be returned to the store - not freed!
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseRetry(App* app, Node* node, NetMessage* requestMsg,
|
||||
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
|
||||
{
|
||||
Config* cfg = App_getConfig(app);
|
||||
|
||||
RequestResponseArgs rrArgs;
|
||||
FhgfsOpsErr rrRes;
|
||||
|
||||
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
|
||||
|
||||
rrArgs.numRetries = Config_getConnNumCommRetries(cfg);
|
||||
|
||||
rrRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
|
||||
|
||||
*outRespBuf = rrArgs.outRespBuf;
|
||||
*outRespMsg = rrArgs.outRespMsg;
|
||||
|
||||
return rrRes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sends a message to a node and receives a response.
|
||||
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
|
||||
*
|
||||
* If target states are provided, communication might be skipped for certain states.
|
||||
*
|
||||
* This version allows only a single retry. (One retry allowed because we might have gotten an
|
||||
* already broken connection from the conn pool.)
|
||||
*
|
||||
* note: uses the number of retries that has been defined in the app config.
|
||||
*
|
||||
* @param rrArgs outRespBuf must be returned to the store - not freed; rrArgs->nodeID may optionally
|
||||
* be provided when calling this.
|
||||
* @return received message and buffer are available through rrArgs in case of success.
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseNode(App* app,
|
||||
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs)
|
||||
{
|
||||
FhgfsOpsErr rrRes;
|
||||
|
||||
rrArgs->numRetries = 1;
|
||||
rrArgs->rrFlags = 0;
|
||||
rrArgs->respBufType = MessagingTkBufType_BufStore;
|
||||
|
||||
rrRes = __MessagingTk_requestResponseNodeRetry(app, rrNode, rrArgs);
|
||||
|
||||
return rrRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to a node and receives a response.
|
||||
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
|
||||
*
|
||||
* If target states are provided, communication might be skipped for certain states.
|
||||
*
|
||||
* note: uses the number of retries that has been defined in the app config.
|
||||
*
|
||||
* @param rrArgs outRespBuf must be returned to the store - not freed; rrArgs->nodeID may optionally
|
||||
* be provided when calling this.
|
||||
* @return received message and buffer are available through rrArgs in case of success.
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseNodeRetryAutoIntr(App* app, RequestResponseNode* rrNode,
|
||||
RequestResponseArgs* rrArgs)
|
||||
{
|
||||
Config* cfg = App_getConfig(app);
|
||||
|
||||
rrArgs->numRetries = Config_getConnNumCommRetries(cfg);
|
||||
rrArgs->rrFlags = REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP;
|
||||
rrArgs->respBufType = MessagingTkBufType_BufStore;
|
||||
|
||||
return __MessagingTk_requestResponseNodeRetry(app, rrNode, rrArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a message to a node and receives a response.
|
||||
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
|
||||
*
|
||||
* If target states are provided, communication might be skipped for certain states.
|
||||
*
|
||||
* @param rrArgs rrArgs->nodeID may optionally be provided when calling this.
|
||||
* @return received message and buffer are available through rrArgs in case of success.
|
||||
*/
|
||||
FhgfsOpsErr __MessagingTk_requestResponseNodeRetry(App* app, RequestResponseNode* rrNode,
|
||||
RequestResponseArgs* rrArgs)
|
||||
{
|
||||
const char* logContext = "Messaging (RPC node)";
|
||||
|
||||
unsigned currentRetryNum = 0; // used number of retries so far
|
||||
FhgfsOpsErr commRes;
|
||||
struct BuddySequenceNumber* handle = NULL;
|
||||
struct MirrorBuddyGroup* group = NULL;
|
||||
bool wasIndirectCommErr = false;
|
||||
|
||||
BEEGFS_BUG_ON_DEBUG(rrNode->targetStates == NULL, "targetStates missing");
|
||||
BEEGFS_BUG_ON_DEBUG(rrNode->mirrorBuddies == NULL, "mirrorBuddies missing");
|
||||
|
||||
for( ; ; ) // retry loop
|
||||
{
|
||||
bool nodeNeedsRelease = false;
|
||||
int acquireSeqRes = 0;
|
||||
bool seqAckIsSelective = false;
|
||||
|
||||
// select the right targetID
|
||||
|
||||
NumNodeID nodeID; // don't modify caller's nodeID
|
||||
|
||||
if (rrNode->peer.isMirrorGroup)
|
||||
{ // given targetID refers to a buddy mirror group
|
||||
nodeID = (NumNodeID){MirrorBuddyGroupMapper_getPrimaryTargetID(rrNode->mirrorBuddies,
|
||||
rrNode->peer.address.group)};
|
||||
|
||||
if (unlikely(NumNodeID_isZero(&nodeID)))
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
Logger_logErrFormatted(log, logContext, "Invalid mirror buddy group ID: %u",
|
||||
rrNode->peer.address.group);
|
||||
|
||||
commRes = FhgfsOpsErr_UNKNOWNNODE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (rrArgs->requestMsg->ops->supportsSequenceNumbers)
|
||||
{
|
||||
rrArgs->requestMsg->msgHeader.msgFlags |= MSGHDRFLAG_HAS_SEQUENCE_NO;
|
||||
|
||||
if (rrArgs->requestMsg->msgHeader.msgSequence == 0)
|
||||
acquireSeqRes = MirrorBuddyGroupMapper_acquireSequenceNumber(rrNode->mirrorBuddies,
|
||||
rrNode->peer.address.group, &rrArgs->requestMsg->msgHeader.msgSequence,
|
||||
&rrArgs->requestMsg->msgHeader.msgSequenceDone, &seqAckIsSelective, &handle,
|
||||
&group);
|
||||
|
||||
if (!acquireSeqRes)
|
||||
{
|
||||
if (seqAckIsSelective)
|
||||
rrArgs->requestMsg->msgHeader.msgFlags |= MSGHDRFLAG_IS_SELECTIVE_ACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
NodeType storeType = NodeStoreEx_getStoreType(rrNode->nodeStore);
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Could not generate seq#. Group IP: %u; type: %s", rrNode->peer.address.group,
|
||||
Node_nodeTypeToStr(storeType));
|
||||
|
||||
commRes = acquireSeqRes == EINTR ? FhgfsOpsErr_INTERRUPTED : FhgfsOpsErr_UNKNOWNNODE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
nodeID = rrNode->peer.address.target;
|
||||
|
||||
// check target state
|
||||
|
||||
if (rrNode->targetStates)
|
||||
{
|
||||
CombinedTargetState state;
|
||||
bool getStateRes = TargetStateStore_getState(rrNode->targetStates, nodeID.value,
|
||||
&state);
|
||||
|
||||
if (!getStateRes ||
|
||||
state.reachabilityState != TargetReachabilityState_ONLINE ||
|
||||
(rrNode->peer.isMirrorGroup &&
|
||||
state.consistencyState != TargetConsistencyState_GOOD))
|
||||
{
|
||||
if(state.reachabilityState == TargetReachabilityState_OFFLINE)
|
||||
{ // no need to wait for offline servers
|
||||
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_SPAM, logContext,
|
||||
"Skipping communication with offline nodeID: %u", nodeID.value);
|
||||
|
||||
commRes = FhgfsOpsErr_COMMUNICATION;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(!(rrArgs->rrFlags & REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP) )
|
||||
{ // caller did not allow sleeping if target state is not {good, offline}
|
||||
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_SPAM, logContext,
|
||||
"Skipping communication with nodeID: %u; "
|
||||
"target state: %s / %s",
|
||||
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
|
||||
TargetStateStore_consistencyStateToStr(state.consistencyState) );
|
||||
|
||||
commRes = FhgfsOpsErr_COMMUNICATION;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// sleep on states other than "good" and "offline" with mirroring
|
||||
if(rrNode->mirrorBuddies)
|
||||
{
|
||||
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_DEBUG, logContext,
|
||||
"Waiting before communication because of node state. "
|
||||
"nodeID: %u; node state: %s / %s",
|
||||
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
|
||||
TargetStateStore_consistencyStateToStr(state.consistencyState) );
|
||||
|
||||
Thread_sleep(MSGTK_STATE_SLEEP_MS);
|
||||
if (fatal_signal_pending(current))
|
||||
{ // make sure we don't loop endless if signal pending
|
||||
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_DEBUG, logContext,
|
||||
"Waiting before communication was interrupted by signal. "
|
||||
"nodeID: %u; node state: %s / %s",
|
||||
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
|
||||
TargetStateStore_consistencyStateToStr(state.consistencyState) );
|
||||
|
||||
commRes = FhgfsOpsErr_INTERRUPTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
currentRetryNum = 0; // reset retries in case of unusable target state
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reference node (if not provided by caller already)
|
||||
|
||||
if(!rrArgs->node)
|
||||
{
|
||||
rrArgs->node = NodeStoreEx_referenceNode(rrNode->nodeStore, nodeID);
|
||||
|
||||
if(!rrArgs->node)
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
NodeType storeType = NodeStoreEx_getStoreType(rrNode->nodeStore);
|
||||
Logger_logFormatted(log, Log_WARNING, logContext, "Unknown nodeID: %u; type: %s",
|
||||
nodeID.value, Node_nodeTypeToStr(storeType));
|
||||
|
||||
commRes = FhgfsOpsErr_UNKNOWNNODE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
nodeNeedsRelease = true;
|
||||
}
|
||||
else
|
||||
BEEGFS_BUG_ON_DEBUG(Node_getNumID(rrArgs->node).value != nodeID.value,
|
||||
"Mismatch between given rrArgs->node ID and nodeID");
|
||||
|
||||
// communicate
|
||||
|
||||
commRes = __MessagingTk_requestResponseWithRRArgsComm(app, rrArgs, group,
|
||||
&wasIndirectCommErr, NULL);
|
||||
|
||||
if(likely(commRes == FhgfsOpsErr_SUCCESS) )
|
||||
goto release_node_and_break;
|
||||
else
|
||||
if (fatal_signal_pending(current))
|
||||
{ // no retry allowed in this situation
|
||||
commRes = FhgfsOpsErr_INTERRUPTED;
|
||||
goto release_node_and_break;
|
||||
}
|
||||
else
|
||||
if(!Node_getIsActive(rrArgs->node) )
|
||||
{ // no retry allowed in this situation
|
||||
commRes = FhgfsOpsErr_UNKNOWNNODE;
|
||||
goto release_node_and_break;
|
||||
}
|
||||
else
|
||||
if(commRes == FhgfsOpsErr_WOULDBLOCK)
|
||||
{ // no retries in this case
|
||||
commRes = FhgfsOpsErr_COMMUNICATION;
|
||||
goto release_node_and_break;
|
||||
}
|
||||
else
|
||||
if( (commRes == FhgfsOpsErr_AGAIN) && App_getConnRetriesEnabled(app) )
|
||||
{ // retry infinitely
|
||||
currentRetryNum = 0;
|
||||
|
||||
Thread_sleep(MSGTK_INFINITE_RETRY_WAIT_MS);
|
||||
|
||||
goto release_node_and_continue;
|
||||
}
|
||||
else
|
||||
if(commRes != FhgfsOpsErr_COMMUNICATION)
|
||||
{ // no retry allowed in this situation
|
||||
goto release_node_and_break;
|
||||
}
|
||||
|
||||
if(App_getConnRetriesEnabled(app) &&
|
||||
(!rrArgs->numRetries || (currentRetryNum < rrArgs->numRetries) ) )
|
||||
{ // we have a retry left
|
||||
MessagingTk_waitBeforeRetry(currentRetryNum);
|
||||
currentRetryNum++;
|
||||
|
||||
/* if the metadata server reports an indirect communication error, we must retry the
|
||||
* communication with a new sequence number. if we reuse the current sequence number, the
|
||||
* meta server will continue to reply "indirect communication error", sending us into a
|
||||
* very long loop of pointless retries, followed by -EIO to userspace. */
|
||||
if (wasIndirectCommErr && handle)
|
||||
{
|
||||
MirrorBuddyGroup_releaseSequenceNumber(group, &handle);
|
||||
rrArgs->requestMsg->msgHeader.msgSequence = 0;
|
||||
wasIndirectCommErr = false;
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
if(currentRetryNum == 1 // log retry message only on first retry (to not spam the log)
|
||||
&& !(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_RETRY) )
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Retrying communication with node: %s", nodeAndType.buf);
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // no more retries left
|
||||
commRes = FhgfsOpsErr_COMMUNICATION;
|
||||
goto release_node_and_break;
|
||||
}
|
||||
|
||||
release_node_and_continue:
|
||||
if(nodeNeedsRelease)
|
||||
{
|
||||
Node_put(rrArgs->node);
|
||||
rrArgs->node = NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
// cleanup before early loop exit
|
||||
release_node_and_break:
|
||||
if(nodeNeedsRelease)
|
||||
{
|
||||
Node_put(rrArgs->node);
|
||||
rrArgs->node = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (handle)
|
||||
MirrorBuddyGroup_releaseSequenceNumber(group, &handle);
|
||||
|
||||
return commRes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send a request message to a node and receive the response.
|
||||
*
|
||||
* @param rrArgs:
|
||||
* .node receiver of msg;
|
||||
* .requestMsg the message that should be sent to the receiver;
|
||||
* .respMsgType expected response message type;
|
||||
* .outRespBuf response buffer if successful (must be returned to store by the caller);
|
||||
* .outRespMsg response message if successful (must be deleted by the caller);
|
||||
* @param sock socket to use. If NULL, one will be pulled from Node's pool
|
||||
* @return FhgfsOpsErr_COMMUNICATION on comm error, FhgfsOpsErr_WOULDBLOCK if remote side
|
||||
* encountered an indirect comm error and suggests not to try again, FhgfsOpsErr_AGAIN if other
|
||||
* side is suggesting infinite retries.
|
||||
*/
|
||||
FhgfsOpsErr __MessagingTk_requestResponseWithRRArgsComm(App* app,
|
||||
RequestResponseArgs* rrArgs, MirrorBuddyGroup* group, bool* wasIndirectCommErr,
|
||||
Socket* sock)
|
||||
{
|
||||
/* note: keep in mind that there are multiple alternative response buf alloc types avilable,
|
||||
e.g. "kmalloc" or "get from store". */
|
||||
|
||||
Logger* log = App_getLogger(app);
|
||||
const char* logContext = "Messaging (RPC)";
|
||||
|
||||
NodeConnPool* connPool = Node_getConnPool(rrArgs->node);
|
||||
|
||||
FhgfsOpsErr retVal = FhgfsOpsErr_COMMUNICATION;
|
||||
|
||||
unsigned bufLen; // length of shared send/recv buffer
|
||||
unsigned sendBufLen; // serialization length for sending
|
||||
ssize_t respRes = 0;
|
||||
ssize_t sendRes;
|
||||
|
||||
// cleanup init
|
||||
bool releaseSock = sock == NULL;
|
||||
rrArgs->outRespBuf = NULL;
|
||||
rrArgs->outRespMsg = NULL;
|
||||
|
||||
// connect
|
||||
// note: acquireStreamSocket() will fail immediately if a signal is pending
|
||||
|
||||
if (sock == NULL)
|
||||
sock = NodeConnPool_acquireStreamSocket(connPool);
|
||||
if(unlikely(!sock) )
|
||||
{ // not connected
|
||||
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED) &&
|
||||
!fatal_signal_pending(current))
|
||||
{ // only log once and only if user didn't manually interrupt with signal (to avoid log spam)
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Unable to connect to: %s", nodeAndType.buf);
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
|
||||
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED;
|
||||
}
|
||||
|
||||
return FhgfsOpsErr_COMMUNICATION;
|
||||
}
|
||||
|
||||
// prepare send buffer
|
||||
|
||||
sendBufLen = NetMessage_getMsgLength(rrArgs->requestMsg);
|
||||
|
||||
if(rrArgs->respBufType == MessagingTkBufType_BufStore)
|
||||
{ // pre-alloc'ed buffer from store
|
||||
|
||||
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
|
||||
bufLen = NoAllocBufferStore_getBufSize(bufStore);
|
||||
|
||||
if(unlikely(bufLen < sendBufLen) )
|
||||
{ // should never happen: trying to send a msg that is larger than pre-alloc'ed buf size
|
||||
Logger_logFormatted(log, Log_CRITICAL, logContext,
|
||||
"BufferStore buf size (%u) too small for msg length (%u). Message type: %hu",
|
||||
bufLen, sendBufLen, NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
|
||||
retVal = FhgfsOpsErr_INTERNAL;
|
||||
goto socket_invalidate;
|
||||
}
|
||||
|
||||
rrArgs->outRespBuf = NoAllocBufferStore_waitForBuf(bufStore);
|
||||
}
|
||||
else
|
||||
{ // alloc'ed buffer
|
||||
|
||||
bufLen = MAX(MSGTK_KMALLOC_RECV_BUF_LEN, sendBufLen);
|
||||
|
||||
rrArgs->outRespBuf = (char*)os_kmalloc(bufLen);
|
||||
if(unlikely(!rrArgs->outRespBuf) )
|
||||
{
|
||||
Logger_logFormatted(log, Log_CRITICAL, logContext,
|
||||
"Buffer allocation failed. Message type: %hu; Alloc size: %u",
|
||||
NetMessage_getMsgType(rrArgs->requestMsg), bufLen);
|
||||
|
||||
retVal = FhgfsOpsErr_OUTOFMEM;
|
||||
goto socket_invalidate;
|
||||
}
|
||||
}
|
||||
|
||||
NetMessage_serialize(rrArgs->requestMsg, rrArgs->outRespBuf, sendBufLen);
|
||||
|
||||
// send request
|
||||
|
||||
sendRes = Socket_send_kernel(sock, rrArgs->outRespBuf, sendBufLen, 0);
|
||||
|
||||
if(unlikely(sendRes != (ssize_t)sendBufLen) )
|
||||
goto socket_exception;
|
||||
|
||||
// receive response
|
||||
|
||||
respRes = MessagingTk_recvMsgBuf(app, sock, rrArgs->outRespBuf, bufLen);
|
||||
|
||||
if(unlikely(respRes <= 0) )
|
||||
{ // error
|
||||
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_COMMERR) )
|
||||
{
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
if (fatal_signal_pending(current)){
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Receive interrupted by signal. Node: %s @ %s",
|
||||
nodeAndType.buf, Socket_getPeername(sock) );
|
||||
}
|
||||
else
|
||||
if(respRes == -ETIMEDOUT) {
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Receive timed out from %s @ %s",
|
||||
nodeAndType.buf, Socket_getPeername(sock) );
|
||||
}
|
||||
else {
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Receive failed from %s @ %s (recv result: %zi)",
|
||||
nodeAndType.buf, Socket_getPeername(sock), respRes);
|
||||
}
|
||||
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Expected response type: %u", rrArgs->respMsgType);
|
||||
}
|
||||
|
||||
goto socket_invalidate;
|
||||
}
|
||||
|
||||
// got response => deserialize it
|
||||
rrArgs->outRespMsg = NetMessageFactory_createFromBuf(app, rrArgs->outRespBuf, respRes);
|
||||
|
||||
if (unlikely(rrArgs->outRespMsg->msgHeader.msgType == NETMSGTYPE_AckNotifyResp))
|
||||
{
|
||||
/* a failover happened before the primary could send a negative response to us, and the
|
||||
* secondary has already received word about the failed operation. treat this case like a
|
||||
* communication error and retry the message with a new sequence number. */
|
||||
*wasIndirectCommErr = true;
|
||||
goto socket_invalidate;
|
||||
}
|
||||
|
||||
if(unlikely(NetMessage_getMsgType(rrArgs->outRespMsg) == NETMSGTYPE_GenericResponse) )
|
||||
{ // special control msg received
|
||||
retVal = __MessagingTk_handleGenericResponse(app, rrArgs, group, wasIndirectCommErr);
|
||||
if(retVal != FhgfsOpsErr_INTERNAL)
|
||||
{ // we can re-use the connection
|
||||
if (releaseSock)
|
||||
NodeConnPool_releaseStreamSocket(connPool, sock);
|
||||
goto cleanup_no_socket;
|
||||
}
|
||||
|
||||
goto socket_invalidate;
|
||||
}
|
||||
|
||||
if(unlikely(NetMessage_getMsgType(rrArgs->outRespMsg) != rrArgs->respMsgType) )
|
||||
{ // response invalid (wrong msgType)
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
Logger_logErrFormatted(log, logContext,
|
||||
"Received invalid response type: %hu; expected: %d. Disconnecting: %s (%s)",
|
||||
NetMessage_getMsgType(rrArgs->outRespMsg), rrArgs->respMsgType,
|
||||
nodeAndType.buf, Socket_getPeername(sock) );
|
||||
|
||||
retVal = FhgfsOpsErr_INTERNAL;
|
||||
goto socket_invalidate;
|
||||
}
|
||||
|
||||
// correct response => return it (through rrArgs)
|
||||
|
||||
if (releaseSock)
|
||||
NodeConnPool_releaseStreamSocket(connPool, sock);
|
||||
|
||||
return FhgfsOpsErr_SUCCESS;
|
||||
|
||||
|
||||
// error handling (something went wrong)...
|
||||
|
||||
socket_exception:
|
||||
{
|
||||
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_COMMERR) )
|
||||
{
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
Logger_logErrFormatted(log, logContext,
|
||||
"Communication error: Node: %s (comm result: %lld; message type: %hu)",
|
||||
nodeAndType.buf,
|
||||
(long long)( (sendRes <= 0) ? sendRes : respRes),
|
||||
NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
|
||||
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_COMMERR;
|
||||
}
|
||||
}
|
||||
|
||||
socket_invalidate:
|
||||
if (releaseSock)
|
||||
{
|
||||
NodeConnPool_invalidateStreamSocket(connPool, sock);
|
||||
}
|
||||
|
||||
// clean up
|
||||
cleanup_no_socket:
|
||||
|
||||
if(rrArgs->outRespMsg)
|
||||
{
|
||||
NETMESSAGE_FREE(rrArgs->outRespMsg);
|
||||
rrArgs->outRespMsg = NULL;
|
||||
}
|
||||
|
||||
if(rrArgs->outRespBuf)
|
||||
{
|
||||
if(rrArgs->respBufType == MessagingTkBufType_BufStore)
|
||||
{
|
||||
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
|
||||
NoAllocBufferStore_addBuf(bufStore, rrArgs->outRespBuf);
|
||||
}
|
||||
else
|
||||
kfree(rrArgs->outRespBuf);
|
||||
|
||||
rrArgs->outRespBuf = NULL;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print log message and determine appropriate return code for requestResponseComm.
|
||||
*
|
||||
* If FhgfsOpsErr_INTERNAL is returned, the connection should be invalidated.
|
||||
*
|
||||
* @return FhgfsOpsErr_COMMUNICATION on indirect comm error (retry suggested),
|
||||
* FhgfsOpsErr_WOULDBLOCK if remote side encountered an indirect comm error and suggests not to
|
||||
* try again, FhgfsOpsErr_AGAIN if other side is suggesting infinite retries.
|
||||
*/
|
||||
FhgfsOpsErr __MessagingTk_handleGenericResponse(App* app, RequestResponseArgs* rrArgs,
|
||||
MirrorBuddyGroup* group, bool* wasIndirectCommErr)
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
const char* logContext = "Messaging (RPC)";
|
||||
|
||||
FhgfsOpsErr retVal;
|
||||
|
||||
GenericResponseMsg* genericResp = (GenericResponseMsg*)rrArgs->outRespMsg;
|
||||
NodeString nodeAndType;
|
||||
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
|
||||
|
||||
*wasIndirectCommErr = false;
|
||||
|
||||
switch(GenericResponseMsg_getControlCode(genericResp) )
|
||||
{
|
||||
case GenericRespMsgCode_TRYAGAIN:
|
||||
{
|
||||
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN) )
|
||||
{
|
||||
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN;
|
||||
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Peer is asking for a retry: %s; Reason: %s",
|
||||
nodeAndType.buf,
|
||||
GenericResponseMsg_getLogStr(genericResp) );
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
}
|
||||
|
||||
retVal = FhgfsOpsErr_AGAIN;
|
||||
} break;
|
||||
|
||||
case GenericRespMsgCode_INDIRECTCOMMERR:
|
||||
{
|
||||
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM) )
|
||||
{
|
||||
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM;
|
||||
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Peer reported indirect communication error: %s; Reason: %s",
|
||||
nodeAndType.buf,
|
||||
GenericResponseMsg_getLogStr(genericResp) );
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
}
|
||||
|
||||
retVal = FhgfsOpsErr_COMMUNICATION;
|
||||
*wasIndirectCommErr = true;
|
||||
} break;
|
||||
|
||||
case GenericRespMsgCode_NEWSEQNOBASE:
|
||||
{
|
||||
if (group)
|
||||
{
|
||||
MirrorBuddyGroup_setSeqNoBase(group,
|
||||
genericResp->simpleIntStringMsg.netMessage.msgHeader.msgSequence);
|
||||
retVal = FhgfsOpsErr_COMMUNICATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Received invalid seqNoBase update");
|
||||
retVal = FhgfsOpsErr_INTERNAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Logger_logFormatted(log, Log_NOTICE, logContext,
|
||||
"Peer replied with unknown control code: %s; Code: %u; Reason: %s",
|
||||
nodeAndType.buf,
|
||||
(unsigned)GenericResponseMsg_getControlCode(genericResp),
|
||||
GenericResponseMsg_getLogStr(genericResp) );
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
|
||||
|
||||
retVal = FhgfsOpsErr_INTERNAL;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
208
client_module/source/common/toolkit/MessagingTk.h
Normal file
208
client_module/source/common/toolkit/MessagingTk.h
Normal file
@@ -0,0 +1,208 @@
|
||||
#ifndef MESSAGINGTK_H_
|
||||
#define MESSAGINGTK_H_
|
||||
|
||||
#include <app/log/Logger.h>
|
||||
#include <app/App.h>
|
||||
#include <app/config/Config.h>
|
||||
#include <common/net/message/NetMessage.h>
|
||||
#include <common/net/sock/Socket.h>
|
||||
#include <common/nodes/MirrorBuddyGroup.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/threading/Thread.h>
|
||||
#include <common/toolkit/MessagingTkArgs.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/Common.h>
|
||||
#include <net/message/NetMessageFactory.h>
|
||||
|
||||
struct Socket;
|
||||
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseWithRRArgsSock(App* app,
|
||||
RequestResponseArgs* rrArgs, Socket* sock);
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseKMalloc(App* app, Node* node,
|
||||
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseSock(App* app, Node* node,
|
||||
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg,
|
||||
Socket* sock);
|
||||
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseRetry(App* app, Node* node,
|
||||
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
||||
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseNode(App* app,
|
||||
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
||||
extern FhgfsOpsErr MessagingTk_requestResponseNodeRetryAutoIntr(App* app,
|
||||
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
||||
|
||||
// private
|
||||
|
||||
extern FhgfsOpsErr __MessagingTk_requestResponseWithRRArgsComm(App* app,
|
||||
RequestResponseArgs* rrArgs, MirrorBuddyGroup* group, bool* wasIndirectCommErr, Socket* sock);
|
||||
extern FhgfsOpsErr __MessagingTk_handleGenericResponse(App* app, RequestResponseArgs* rrArgs,
|
||||
MirrorBuddyGroup* group, bool* wasIndirectCommErr);
|
||||
|
||||
extern FhgfsOpsErr __MessagingTk_requestResponseNodeRetry(App* app,
|
||||
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
||||
|
||||
// inliners
|
||||
|
||||
static inline char* MessagingTk_createMsgBuf(NetMessage* msg);
|
||||
static inline ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen);
|
||||
|
||||
static inline void MessagingTk_waitBeforeRetry(unsigned currentNumRetry);
|
||||
static inline int MessagingTk_getRetryWaitMS(unsigned currentNumRetry);
|
||||
static inline FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app,
|
||||
RequestResponseArgs* rrArgs);
|
||||
static inline FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node,
|
||||
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a message buffer of the required size and serializes the message to it.
|
||||
* Note: Uses kmalloc, so this is only safe for messages < 128kB
|
||||
*
|
||||
* @return buffer must be kfreed by the caller
|
||||
*/
|
||||
char* MessagingTk_createMsgBuf(NetMessage* msg)
|
||||
{
|
||||
size_t bufLen = NetMessage_getMsgLength(msg);
|
||||
char* buf = (char*)os_kmalloc(bufLen);
|
||||
|
||||
NetMessage_serialize(msg, buf, buf ? bufLen : 0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a complete message into given buffer, extended version.
|
||||
*
|
||||
* Note: This is the version for pre-allocated buffers.
|
||||
*
|
||||
* @param bufIn incoming message buffer.
|
||||
* @return positive message length on success, <=0 on error (e.g. -ETIMEDOUT on recv timeout,
|
||||
* -EMSGSIZE if msg too large for buffer).
|
||||
*/
|
||||
ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen)
|
||||
{
|
||||
const char* logContext = "MessagingTk (recv msg)";
|
||||
|
||||
size_t numReceived = 0;
|
||||
ssize_t recvRes;
|
||||
size_t msgLength;
|
||||
Config* cfg = App_getConfig(app);
|
||||
|
||||
// receive at least the message header
|
||||
|
||||
recvRes = Socket_recvExactTEx_kernel(sock, bufIn, NETMSG_MIN_LENGTH, 0, cfg->connMsgLongTimeout,
|
||||
&numReceived);
|
||||
|
||||
if(unlikely(recvRes <= 0) )
|
||||
{ // socket error
|
||||
Logger* log = App_getLogger(app);
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext, "Failed to receive message header from: %s",
|
||||
Socket_getPeername(sock) );
|
||||
|
||||
goto socket_exception;
|
||||
}
|
||||
|
||||
msgLength = NetMessage_extractMsgLengthFromBuf(bufIn);
|
||||
|
||||
if(msgLength <= numReceived)
|
||||
return msgLength; // success (msg had no additional payload)
|
||||
|
||||
|
||||
// receive the message payload part
|
||||
|
||||
if(unlikely(msgLength > bufInLen) )
|
||||
{ // message too big to be accepted
|
||||
Logger* log = App_getLogger(app);
|
||||
Logger_logFormatted(log, Log_WARNING, logContext,
|
||||
"Received a message that is too large from: %s (bufLen: %lld, msgLen: %lld)",
|
||||
Socket_getPeername(sock), (long long)bufInLen, (long long)msgLength);
|
||||
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
recvRes = Socket_recvExactTEx_kernel(sock, &bufIn[numReceived], msgLength-numReceived, 0,
|
||||
cfg->connMsgLongTimeout, &numReceived);
|
||||
|
||||
if(unlikely(recvRes <= 0) )
|
||||
goto socket_exception;
|
||||
|
||||
// success
|
||||
return msgLength;
|
||||
|
||||
|
||||
socket_exception:
|
||||
{
|
||||
Logger* log = App_getLogger(app);
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Receive interrupted by signal");
|
||||
else
|
||||
Logger_logFormatted(log, Log_DEBUG, logContext,
|
||||
"Receive failed from: %s (ErrCode: %lld)",
|
||||
Socket_getPeername(sock), (long long)recvRes);
|
||||
}
|
||||
|
||||
return recvRes;
|
||||
}
|
||||
|
||||
void MessagingTk_waitBeforeRetry(unsigned currentNumRetry)
|
||||
{
|
||||
int retryWaitMS = MessagingTk_getRetryWaitMS(currentNumRetry);
|
||||
|
||||
if(retryWaitMS)
|
||||
Thread_sleep(retryWaitMS);
|
||||
}
|
||||
|
||||
int MessagingTk_getRetryWaitMS(unsigned currentNumRetry)
|
||||
{
|
||||
// note: keep in sync with __Config_initConnNumCommRetries()
|
||||
|
||||
int retryWaitMS ;
|
||||
|
||||
if(!currentNumRetry)
|
||||
{
|
||||
retryWaitMS = 0;
|
||||
}
|
||||
else
|
||||
if(currentNumRetry <= 12) // 1st minute
|
||||
{
|
||||
retryWaitMS = 5000;
|
||||
}
|
||||
else
|
||||
if(currentNumRetry <= 24) // 2nd to 5th minute
|
||||
{
|
||||
retryWaitMS = 20000;
|
||||
}
|
||||
else // after 5th minute
|
||||
{
|
||||
retryWaitMS = 60000;
|
||||
}
|
||||
|
||||
return retryWaitMS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: rrArgs->outRespBuf must be returned/freed by the caller (depending on respBufType)
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app, RequestResponseArgs* rrArgs)
|
||||
{
|
||||
return MessagingTk_requestResponseWithRRArgsSock(app, rrArgs, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
|
||||
* broken connection from the conn pool.)
|
||||
*
|
||||
* @param outRespBuf must be returned to the store - not freed!
|
||||
*/
|
||||
FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node, NetMessage* requestMsg,
|
||||
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
|
||||
{
|
||||
return MessagingTk_requestResponseSock(app, node, requestMsg, respMsgType,
|
||||
outRespBuf, outRespMsg, NULL);
|
||||
}
|
||||
|
||||
#endif /*MESSAGINGTK_H_*/
|
||||
157
client_module/source/common/toolkit/MessagingTkArgs.h
Normal file
157
client_module/source/common/toolkit/MessagingTkArgs.h
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifndef MESSAGINGTKARGS_H_
|
||||
#define MESSAGINGTKARGS_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/Types.h>
|
||||
#include <toolkit/NoAllocBufferStore.h>
|
||||
|
||||
|
||||
#define REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP 2 // sleep on non-{good,offline} state
|
||||
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN 1 // peer asked for retry
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM 2 /* peer encountered indirect comm
|
||||
error, suggests retry */
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM_NOTAGAIN 4 /* peer encountered indirect comm
|
||||
error, suggests no retry */
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED 8 // unable to establish connection
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_COMMERR 16 // communication error
|
||||
#define REQUESTRESPONSEARGS_LOGFLAG_RETRY 32 // communication retry
|
||||
|
||||
|
||||
struct TargetMapper; // forward declaration
|
||||
struct TargetStateStore; // forward declaration
|
||||
struct NodeStoreEx; // forward declaration
|
||||
struct MirrorBuddyGroupMapper; // forward declaration
|
||||
|
||||
|
||||
struct RequestResponseNode;
|
||||
typedef struct RequestResponseNode RequestResponseNode;
|
||||
|
||||
enum MessagingTkBufType;
|
||||
typedef enum MessagingTkBufType MessagingTkBufType;
|
||||
|
||||
struct RequestResponseArgs;
|
||||
typedef struct RequestResponseArgs RequestResponseArgs;
|
||||
|
||||
|
||||
static inline void RequestResponseArgs_prepare(RequestResponseArgs* this, Node* node,
|
||||
NetMessage* requestMsg, unsigned respMsgType);
|
||||
static inline void RequestResponseArgs_freeRespBuffers(RequestResponseArgs* this, App* app);
|
||||
|
||||
|
||||
struct RRPeer
|
||||
{
|
||||
union {
|
||||
NumNodeID target;
|
||||
uint32_t group;
|
||||
} address;
|
||||
bool isMirrorGroup;
|
||||
};
|
||||
|
||||
static inline struct RRPeer RRPeer_target(NumNodeID target)
|
||||
{
|
||||
struct RRPeer result = {
|
||||
.address = {
|
||||
.target = target,
|
||||
},
|
||||
.isMirrorGroup = false,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline struct RRPeer RRPeer_group(uint32_t group)
|
||||
{
|
||||
struct RRPeer result = {
|
||||
.address = {
|
||||
.group = group,
|
||||
},
|
||||
.isMirrorGroup = true,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This value container contains arguments for requestResponse() with a certain node.
|
||||
*/
|
||||
struct RequestResponseNode
|
||||
{
|
||||
struct RRPeer peer;
|
||||
struct NodeStoreEx* nodeStore; // for nodeID lookup
|
||||
|
||||
struct TargetStateStore* targetStates; /* if !NULL, check for state "good" or fail immediately if
|
||||
offline (other states handling depend on mirrorBuddies) */
|
||||
struct MirrorBuddyGroupMapper* mirrorBuddies; // if !NULL, the given targetID is a mirror groupID
|
||||
};
|
||||
|
||||
enum MessagingTkBufType
|
||||
{
|
||||
MessagingTkBufType_BufStore = 0,
|
||||
MessagingTkBufType_kmalloc = 1, // only for small response messages (<4KiB)
|
||||
};
|
||||
|
||||
/**
|
||||
* Arguments for request-response communication.
|
||||
*/
|
||||
struct RequestResponseArgs
|
||||
{
|
||||
Node* node; // receiver
|
||||
|
||||
NetMessage* requestMsg;
|
||||
unsigned respMsgType; // expected type of response message
|
||||
|
||||
unsigned numRetries; // 0 means infinite retries
|
||||
unsigned rrFlags; // combination of REQUESTRESPONSEARGS_FLAG_... flags
|
||||
MessagingTkBufType respBufType; // defines how to get/alloc outRespBuf
|
||||
|
||||
char* outRespBuf;
|
||||
NetMessage* outRespMsg;
|
||||
|
||||
// internal (initialized by MessagingTk_requestResponseWithRRArgs() )
|
||||
unsigned char logFlags; // REQUESTRESPONSEARGS_LOGFLAG_... combination to avoid double-logging
|
||||
};
|
||||
|
||||
/**
|
||||
* Default initializer.
|
||||
* Some of the default values will overridden by the corresponding MessagingTk methods.
|
||||
*
|
||||
* @param node may be NULL, depending on which requestResponse...() method is used.
|
||||
* @param respMsgType expected type of response message (NETMSGTYPE_...)
|
||||
*/
|
||||
void RequestResponseArgs_prepare(RequestResponseArgs* this, Node* node, NetMessage* requestMsg,
|
||||
unsigned respMsgType)
|
||||
{
|
||||
this->node = node;
|
||||
|
||||
this->requestMsg = requestMsg;
|
||||
this->respMsgType = respMsgType;
|
||||
|
||||
this->numRetries = 1;
|
||||
this->rrFlags = 0;
|
||||
this->respBufType = MessagingTkBufType_BufStore;
|
||||
|
||||
this->outRespBuf = NULL;
|
||||
this->outRespMsg = NULL;
|
||||
|
||||
this->logFlags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free/release outRespBuf and desctruct outRespMsg if they are not NULL.
|
||||
*/
|
||||
void RequestResponseArgs_freeRespBuffers(RequestResponseArgs* this, App* app)
|
||||
{
|
||||
NETMESSAGE_FREE(this->outRespMsg);
|
||||
|
||||
if(this->outRespBuf)
|
||||
{
|
||||
if(this->respBufType == MessagingTkBufType_BufStore)
|
||||
{
|
||||
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
|
||||
NoAllocBufferStore_addBuf(bufStore, this->outRespBuf);
|
||||
}
|
||||
else
|
||||
SAFE_KFREE(this->outRespBuf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MESSAGINGTKARGS_H_ */
|
||||
71
client_module/source/common/toolkit/MetadataTk.c
Normal file
71
client_module/source/common/toolkit/MetadataTk.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <app/App.h>
|
||||
#include <app/log/Logger.h>
|
||||
#include <common/net/message/NetMessage.h>
|
||||
#include <common/storage/Metadata.h>
|
||||
#include <common/storage/StorageDefinitions.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <nodes/NodeStoreEx.h>
|
||||
#include <toolkit/NoAllocBufferStore.h>
|
||||
|
||||
#include "MetadataTk.h"
|
||||
|
||||
/**
|
||||
* Used to initialize struct CreateInfo. This function always should be used, to make sure,
|
||||
* values are not forgotten.
|
||||
*
|
||||
* Note: preferred meta/storage targets are automatically set to app's preferred meta/storage
|
||||
* targets; keep that in mind when you're cleaning up.
|
||||
*/
|
||||
void CreateInfo_init(App* app, struct inode* parentDirInode, const char* entryName,
|
||||
int mode, int umask, bool isExclusiveCreate, const struct FileEvent* fileEvent,
|
||||
CreateInfo* outCreateInfo)
|
||||
{
|
||||
MountConfig *mountConfig = app->mountConfig;
|
||||
|
||||
outCreateInfo->userID = FhgfsCommon_getCurrentUserID();
|
||||
|
||||
// groupID and mode logic taken from inode_init_owner()
|
||||
if (parentDirInode && ((parentDirInode->i_mode & S_ISGID) || mountConfig->grpid))
|
||||
{
|
||||
outCreateInfo->groupID = i_gid_read(parentDirInode);
|
||||
if (S_ISDIR(mode) && (parentDirInode->i_mode & S_ISGID))
|
||||
mode |= S_ISGID;
|
||||
}
|
||||
else
|
||||
outCreateInfo->groupID = FhgfsCommon_getCurrentGroupID();
|
||||
|
||||
outCreateInfo->entryName = entryName;
|
||||
outCreateInfo->mode = mode;
|
||||
outCreateInfo->umask = umask;
|
||||
outCreateInfo->isExclusiveCreate = isExclusiveCreate;
|
||||
|
||||
outCreateInfo->preferredStorageTargets = App_getPreferredStorageTargets(app);
|
||||
outCreateInfo->preferredMetaTargets = App_getPreferredMetaNodes(app);
|
||||
outCreateInfo->fileEvent = fileEvent;
|
||||
|
||||
StoragePoolId_set(&(outCreateInfo->storagePoolId), STORAGEPOOLID_INVALIDPOOLID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param outEntryInfo contained values will be kalloced (on success) and need to be kfreed with
|
||||
* FhgfsInode_freeEntryMinInfoVals() later.
|
||||
*/
|
||||
bool MetadataTk_getRootEntryInfoCopy(App* app, EntryInfo* outEntryInfo)
|
||||
{
|
||||
NodeStoreEx* nodes = App_getMetaNodes(app);
|
||||
|
||||
NodeOrGroup rootOwner = NodeStoreEx_getRootOwner(nodes);
|
||||
const char* parentEntryID = StringTk_strDup("");
|
||||
const char* entryID = StringTk_strDup(META_ROOTDIR_ID_STR);
|
||||
const char* dirName = StringTk_strDup("");
|
||||
DirEntryType entryType = (DirEntryType) DirEntryType_DIRECTORY;
|
||||
|
||||
/* Even if rootOwner is invalid, we still init outEntryInfo and malloc as FhGFS
|
||||
* policy says that kfree(NULL) is not allowed (the kernel allows it). */
|
||||
|
||||
EntryInfo_init(outEntryInfo, rootOwner, parentEntryID, entryID, dirName, entryType, 0);
|
||||
|
||||
return NodeOrGroup_valid(rootOwner);
|
||||
}
|
||||
149
client_module/source/common/toolkit/MetadataTk.h
Normal file
149
client_module/source/common/toolkit/MetadataTk.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#ifndef METADATATK_H_
|
||||
#define METADATATK_H_
|
||||
|
||||
#include <app/App.h>
|
||||
#include <common/Common.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/storage/Path.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/storage/EntryInfo.h>
|
||||
#include <common/storage/StorageErrors.h>
|
||||
#include <common/storage/StorageDefinitions.h>
|
||||
#include <common/toolkit/list/UInt16List.h>
|
||||
#include <common/toolkit/MetadataTk.h>
|
||||
#include <os/OsTypeConversion.h>
|
||||
|
||||
#include "LookupIntentInfoOut.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#define METADATATK_OWNERSEARCH_MAX_STEPS 128 /* to avoid infinite searching */
|
||||
|
||||
|
||||
struct CreateInfo;
|
||||
typedef struct CreateInfo CreateInfo;
|
||||
|
||||
struct OpenInfo;
|
||||
typedef struct OpenInfo OpenInfo;
|
||||
|
||||
struct LookupIntentInfoIn;
|
||||
typedef struct LookupIntentInfoIn LookupIntentInfoIn;
|
||||
|
||||
struct FileEvent;
|
||||
|
||||
|
||||
extern bool MetadataTk_getRootEntryInfoCopy(App* app, EntryInfo* outEntryInfo);
|
||||
|
||||
// inliners
|
||||
|
||||
void CreateInfo_init(App* app, struct inode* parentDirInode, const char* entryName,
|
||||
int mode, int umask, bool isExclusiveCreate, const struct FileEvent* fileEvent,
|
||||
struct CreateInfo* outCreateInfo);
|
||||
static inline void CreateInfo_setStoragePoolId(CreateInfo* this, StoragePoolId storagePoolId);
|
||||
static inline void LookupIntentInfoIn_init(LookupIntentInfoIn* this,
|
||||
const EntryInfo* parentEntryInfo, const char* entryName);
|
||||
static inline void LookupIntentInfoIn_addEntryInfo(LookupIntentInfoIn* this,
|
||||
const EntryInfo* entryInfo);
|
||||
static inline void LookupIntentInfoIn_addMetaVersion(LookupIntentInfoIn* this,
|
||||
uint32_t metaVersion);
|
||||
static inline void LookupIntentInfoIn_addOpenInfo(LookupIntentInfoIn* this,
|
||||
const OpenInfo* openInfo);
|
||||
static inline void LookupIntentInfoIn_addCreateInfo(LookupIntentInfoIn* this,
|
||||
const CreateInfo* createInfo);
|
||||
static inline void OpenInfo_init(OpenInfo* this, int accessFlags, bool isPagedMode);
|
||||
static inline void LookupIntentInfoOut_prepare(LookupIntentInfoOut* this,
|
||||
EntryInfo* outEntryInfo, fhgfs_stat* outFhgfsStat);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* File/Dir create information. Should be initialized using CreateInfo_init().
|
||||
*/
|
||||
struct CreateInfo
|
||||
{
|
||||
const char* entryName; // file name
|
||||
unsigned userID;
|
||||
unsigned groupID;
|
||||
int mode;
|
||||
int umask;
|
||||
UInt16List* preferredMetaTargets;
|
||||
UInt16List* preferredStorageTargets;
|
||||
bool isExclusiveCreate; // only for open() and creat(), is O_CREAT set?
|
||||
StoragePoolId storagePoolId; // can be set to override storage pool information of parent
|
||||
// directory
|
||||
const struct FileEvent* fileEvent;
|
||||
};
|
||||
|
||||
struct OpenInfo
|
||||
{
|
||||
int accessFlags; // fhgfs flags, not in-kernel open/access flags
|
||||
// const char* sessionID; // set at lower level on initializing LookupIntentMsg
|
||||
};
|
||||
|
||||
/**
|
||||
* In-Args for _lookupCreateStat operations. Init only with LookupIntentInfoIn_init().
|
||||
*/
|
||||
struct LookupIntentInfoIn
|
||||
{
|
||||
const EntryInfo* parentEntryInfo;
|
||||
const EntryInfo* entryInfoPtr; // only set on revalidate
|
||||
const char* entryName; // file name
|
||||
|
||||
const CreateInfo* createInfo; // only set on file create
|
||||
bool isExclusiveCreate; // true iff O_EXCL is set
|
||||
|
||||
const OpenInfo* openInfo; // only set on file open
|
||||
uint32_t metaVersion; //only set on revalidate
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param accessFlags is the same as openFlags
|
||||
*/
|
||||
void OpenInfo_init(OpenInfo* this, int accessFlags, bool isPagedMode)
|
||||
{
|
||||
this->accessFlags = OsTypeConv_openFlagsOsToFhgfs(accessFlags, isPagedMode);
|
||||
|
||||
// this->sessionID = sessionID; // see OpenInfo definition
|
||||
}
|
||||
|
||||
static inline void LookupIntentInfoIn_init(LookupIntentInfoIn* this,
|
||||
const EntryInfo* parentEntryInfo, const char* entryName)
|
||||
{
|
||||
this->parentEntryInfo = parentEntryInfo;
|
||||
this->entryName = entryName;
|
||||
this->entryInfoPtr = NULL;
|
||||
this->openInfo = NULL;
|
||||
this->createInfo = NULL;
|
||||
}
|
||||
|
||||
void LookupIntentInfoIn_addEntryInfo(LookupIntentInfoIn* this, const EntryInfo* entryInfo)
|
||||
{
|
||||
this->entryInfoPtr = entryInfo;
|
||||
}
|
||||
|
||||
|
||||
void LookupIntentInfoIn_addMetaVersion(LookupIntentInfoIn* this, uint32_t version)
|
||||
{
|
||||
this->metaVersion = version;
|
||||
}
|
||||
|
||||
void LookupIntentInfoIn_addOpenInfo(LookupIntentInfoIn* this, const OpenInfo* openInfo)
|
||||
{
|
||||
this->openInfo = openInfo;
|
||||
}
|
||||
|
||||
void LookupIntentInfoIn_addCreateInfo(LookupIntentInfoIn* this, const CreateInfo* createInfo)
|
||||
{
|
||||
this->createInfo = createInfo;
|
||||
|
||||
if (likely(createInfo) )
|
||||
this->isExclusiveCreate = createInfo->isExclusiveCreate;
|
||||
}
|
||||
|
||||
static inline void CreateInfo_setStoragePoolId(CreateInfo* this, StoragePoolId storagePoolId)
|
||||
{
|
||||
this->storagePoolId = storagePoolId;
|
||||
}
|
||||
|
||||
#endif /*METADATATK_H_*/
|
||||
198
client_module/source/common/toolkit/NetFilter.h
Normal file
198
client_module/source/common/toolkit/NetFilter.h
Normal file
@@ -0,0 +1,198 @@
|
||||
#ifndef NETFILTER_H_
|
||||
#define NETFILTER_H_
|
||||
|
||||
#include <app/config/Config.h>
|
||||
#include <common/toolkit/Serialization.h>
|
||||
#include <common/toolkit/SocketTk.h>
|
||||
#include <common/Common.h>
|
||||
#include <linux/in.h>
|
||||
|
||||
|
||||
struct NetFilterEntry;
|
||||
typedef struct NetFilterEntry NetFilterEntry;
|
||||
|
||||
struct NetFilter;
|
||||
typedef struct NetFilter NetFilter;
|
||||
|
||||
|
||||
static inline __must_check bool NetFilter_init(NetFilter* this, const char* filename);
|
||||
static inline NetFilter* NetFilter_construct(const char* filename);
|
||||
static inline void NetFilter_uninit(NetFilter* this);
|
||||
static inline void NetFilter_destruct(NetFilter* this);
|
||||
|
||||
// inliners
|
||||
static inline bool NetFilter_isAllowed(NetFilter* this, struct in_addr ipAddr);
|
||||
static inline bool NetFilter_isContained(NetFilter* this, struct in_addr ipAddr);
|
||||
static inline bool __NetFilter_prepareArray(NetFilter* this, const char* filename);
|
||||
|
||||
// getters & setters
|
||||
static inline size_t NetFilter_getNumFilterEntries(NetFilter* this);
|
||||
|
||||
|
||||
struct NetFilterEntry
|
||||
{
|
||||
uint32_t netAddressShifted; // shifted by number of significant bits
|
||||
// Note: this address is in host(!) byte order to enable correct shift operator usage
|
||||
int shiftBitsNum; // for right shift
|
||||
};
|
||||
|
||||
struct NetFilter
|
||||
{
|
||||
NetFilterEntry* filterArray;
|
||||
size_t filterArrayLen;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param filename path to filter file.
|
||||
*/
|
||||
bool NetFilter_init(NetFilter* this, const char* filename)
|
||||
{
|
||||
return __NetFilter_prepareArray(this, filename);
|
||||
}
|
||||
|
||||
NetFilter* NetFilter_construct(const char* filename)
|
||||
{
|
||||
NetFilter* this = kmalloc(sizeof(*this), GFP_NOFS);
|
||||
|
||||
if(!this ||
|
||||
!NetFilter_init(this, filename) )
|
||||
{
|
||||
kfree(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void NetFilter_uninit(NetFilter* this)
|
||||
{
|
||||
SAFE_KFREE(this->filterArray);
|
||||
}
|
||||
|
||||
void NetFilter_destruct(NetFilter* this)
|
||||
{
|
||||
NetFilter_uninit(this);
|
||||
|
||||
kfree(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Empty filter will always return allowed (i.e. "true").
|
||||
* Note: Will always allow the loopback address.
|
||||
*/
|
||||
bool NetFilter_isAllowed(NetFilter* this, struct in_addr ipAddr)
|
||||
{
|
||||
if(!this->filterArrayLen)
|
||||
return true;
|
||||
|
||||
return NetFilter_isContained(this, ipAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Always implicitly contains the loopback address.
|
||||
*/
|
||||
bool NetFilter_isContained(NetFilter* this, struct in_addr ipAddr)
|
||||
{
|
||||
uint32_t ipHostOrder;
|
||||
size_t i;
|
||||
|
||||
// note: stored addresses are in host byte order to enable correct shift operator usage
|
||||
ipHostOrder = ntohl(ipAddr.s_addr);
|
||||
|
||||
if(ipHostOrder == INADDR_LOOPBACK) // (inaddr_loopback is in host byte order)
|
||||
return true;
|
||||
|
||||
for(i = 0; i < this->filterArrayLen; i++)
|
||||
{
|
||||
const uint32_t ipHostOrderShifted = ipHostOrder >> this->filterArray[i].shiftBitsNum;
|
||||
|
||||
if(this->filterArray[i].netAddressShifted == ipHostOrderShifted)
|
||||
{ // address match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no match found
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filename path to filter file.
|
||||
* @return false if a specified file could not be opened.
|
||||
*/
|
||||
bool __NetFilter_prepareArray(NetFilter* this, const char* filename)
|
||||
{
|
||||
bool loadRes = true;
|
||||
StrCpyList filterList;
|
||||
|
||||
this->filterArray = NULL;
|
||||
this->filterArrayLen = 0;
|
||||
|
||||
if(!StringTk_hasLength(filename) )
|
||||
{ // no file specified => no filter entries
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
StrCpyList_init(&filterList);
|
||||
|
||||
loadRes = Config_loadStringListFile(filename, &filterList);
|
||||
if(!loadRes)
|
||||
{ // file error
|
||||
printk_fhgfs(KERN_WARNING,
|
||||
"Unable to load configured net filter file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(StrCpyList_length(&filterList) )
|
||||
{ // file did contain some lines
|
||||
StrCpyListIter iter;
|
||||
size_t i;
|
||||
|
||||
this->filterArrayLen = StrCpyList_length(&filterList);
|
||||
this->filterArray = kmalloc(this->filterArrayLen * sizeof(NetFilterEntry), GFP_NOFS);
|
||||
if(!this->filterArray)
|
||||
goto err_alloc;
|
||||
|
||||
StrCpyListIter_init(&iter, &filterList);
|
||||
i = 0;
|
||||
|
||||
for( ; !StrCpyListIter_end(&iter); StrCpyListIter_next(&iter) )
|
||||
{
|
||||
char* line = StrCpyListIter_value(&iter);
|
||||
uint32_t entryAddr;
|
||||
|
||||
char* findRes = strchr(line, '/');
|
||||
if(!findRes)
|
||||
{ // slash character missing => ignore this faulty line (and reduce filter length)
|
||||
this->filterArrayLen--;
|
||||
continue;
|
||||
}
|
||||
|
||||
*findRes = 0;
|
||||
|
||||
// note: we store addresses in host byte order to enable correct shift operator usage
|
||||
entryAddr = ntohl(SocketTk_in_aton(line).s_addr);
|
||||
this->filterArray[i].shiftBitsNum = 32 - StringTk_strToUInt(findRes + 1);
|
||||
this->filterArray[i].netAddressShifted = entryAddr >> this->filterArray[i].shiftBitsNum;
|
||||
|
||||
i++; // must be increased here because of the faulty line handling
|
||||
}
|
||||
}
|
||||
|
||||
StrCpyList_uninit(&filterList);
|
||||
return true;
|
||||
|
||||
err_alloc:
|
||||
StrCpyList_uninit(&filterList);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t NetFilter_getNumFilterEntries(NetFilter* this)
|
||||
{
|
||||
return this->filterArrayLen;
|
||||
}
|
||||
|
||||
|
||||
#endif /* NETFILTER_H_ */
|
||||
188
client_module/source/common/toolkit/NodesTk.c
Normal file
188
client_module/source/common/toolkit/NodesTk.c
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <toolkit/NoAllocBufferStore.h>
|
||||
#include <common/net/message/nodes/GetMirrorBuddyGroupsMsg.h>
|
||||
#include <common/net/message/nodes/GetNodesMsg.h>
|
||||
#include <common/net/message/nodes/GetNodesRespMsg.h>
|
||||
#include <common/net/message/nodes/GetStatesAndBuddyGroupsMsg.h>
|
||||
#include <common/net/message/nodes/GetStatesAndBuddyGroupsRespMsg.h>
|
||||
#include <common/net/message/nodes/GetTargetMappingsMsg.h>
|
||||
#include <common/net/message/nodes/GetTargetMappingsRespMsg.h>
|
||||
#include <common/threading/Thread.h>
|
||||
#include <common/toolkit/MessagingTk.h>
|
||||
#include <common/toolkit/Random.h>
|
||||
#include "NodesTk.h"
|
||||
|
||||
/**
|
||||
* Download node list from given source node.
|
||||
*
|
||||
* @param sourceNode the node from which node you want to download
|
||||
* @param nodeType which type of node list you want to download
|
||||
* @param outNodeList caller is responsible for the deletion of the received nodes
|
||||
* @param outRootID may be NULL if caller is not interested
|
||||
* @param outRootIsBuddyMirrored may be NULL if caller is not interested
|
||||
* @return true if download successful
|
||||
*/
|
||||
bool NodesTk_downloadNodes(App* app, Node* sourceNode, NodeType nodeType, NodeList* outNodeList,
|
||||
NumNodeID* outRootNodeID, bool* outRootIsBuddyMirrored)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
GetNodesMsg msg;
|
||||
|
||||
FhgfsOpsErr commRes;
|
||||
GetNodesRespMsg* respMsgCast;
|
||||
RequestResponseArgs rrArgs;
|
||||
|
||||
// prepare request
|
||||
GetNodesMsg_initFromValue(&msg, nodeType);
|
||||
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg, NETMSGTYPE_GetNodesResp);
|
||||
|
||||
#ifndef BEEGFS_DEBUG
|
||||
// Silence log message unless built in debug mode.
|
||||
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
|
||||
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
// connect & communicate
|
||||
|
||||
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
|
||||
|
||||
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
|
||||
goto cleanup_request;
|
||||
|
||||
// handle result
|
||||
respMsgCast = (GetNodesRespMsg*)rrArgs.outRespMsg;
|
||||
|
||||
GetNodesRespMsg_parseNodeList(app, respMsgCast, outNodeList);
|
||||
|
||||
if(outRootNodeID)
|
||||
*outRootNodeID = GetNodesRespMsg_getRootNumID(respMsgCast);
|
||||
|
||||
if (outRootIsBuddyMirrored)
|
||||
*outRootIsBuddyMirrored = GetNodesRespMsg_getRootIsBuddyMirrored(respMsgCast);
|
||||
|
||||
retVal = true;
|
||||
|
||||
// cleanup
|
||||
|
||||
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
|
||||
|
||||
cleanup_request:
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads target mappings from given source node.
|
||||
*
|
||||
* @return true if download successful
|
||||
*/
|
||||
bool NodesTk_downloadTargetMappings(App* app, Node* sourceNode, struct list_head* mappings)
|
||||
{
|
||||
GetTargetMappingsMsg msg;
|
||||
|
||||
FhgfsOpsErr commRes;
|
||||
GetTargetMappingsRespMsg* respMsgCast;
|
||||
RequestResponseArgs rrArgs;
|
||||
|
||||
// prepare request
|
||||
GetTargetMappingsMsg_init(&msg);
|
||||
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg,
|
||||
NETMSGTYPE_GetTargetMappingsResp);
|
||||
|
||||
#ifndef BEEGFS_DEBUG
|
||||
// Silence log message unless built in debug mode.
|
||||
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
|
||||
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
// communicate
|
||||
|
||||
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
|
||||
|
||||
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
|
||||
return false;
|
||||
|
||||
// handle result
|
||||
|
||||
respMsgCast = (GetTargetMappingsRespMsg*)rrArgs.outRespMsg;
|
||||
|
||||
list_splice_tail_init(&respMsgCast->mappings, mappings);
|
||||
|
||||
// cleanup
|
||||
|
||||
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download target states and buddy groups combined in a single message.
|
||||
*/
|
||||
bool NodesTk_downloadStatesAndBuddyGroups(App* app, Node* sourceNode, NodeType nodeType,
|
||||
struct list_head* groups, struct list_head* states)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
GetStatesAndBuddyGroupsMsg msg;
|
||||
|
||||
FhgfsOpsErr commRes;
|
||||
GetStatesAndBuddyGroupsRespMsg* respMsgCast;
|
||||
RequestResponseArgs rrArgs;
|
||||
|
||||
Node* localNode = App_getLocalNode(app);
|
||||
NumNodeID localNodeNumID = Node_getNumID(localNode);
|
||||
|
||||
// prepare request
|
||||
GetStatesAndBuddyGroupsMsg_init(&msg, nodeType, localNodeNumID);
|
||||
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg,
|
||||
NETMSGTYPE_GetStatesAndBuddyGroupsResp);
|
||||
|
||||
#ifndef BEEGFS_DEBUG
|
||||
// Silence log message unless built in debug mode.
|
||||
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
|
||||
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
|
||||
#endif // BEEGFS_DEBUG
|
||||
|
||||
// communicate
|
||||
|
||||
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
|
||||
|
||||
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
|
||||
goto cleanup_request;
|
||||
|
||||
// handle result
|
||||
|
||||
respMsgCast = (GetStatesAndBuddyGroupsRespMsg*)rrArgs.outRespMsg;
|
||||
|
||||
list_splice_tail_init(&respMsgCast->groups, groups);
|
||||
list_splice_tail_init(&respMsgCast->states, states);
|
||||
retVal = true;
|
||||
|
||||
// cleanup
|
||||
|
||||
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
|
||||
|
||||
cleanup_request:
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Walk over all nodes in the given store and drop established (available) connections.
|
||||
*
|
||||
* @return number of dropped connections
|
||||
*/
|
||||
unsigned NodesTk_dropAllConnsByStore(NodeStoreEx* nodes)
|
||||
{
|
||||
unsigned numDroppedConns = 0;
|
||||
|
||||
Node* node = NodeStoreEx_referenceFirstNode(nodes);
|
||||
while(node)
|
||||
{
|
||||
NodeConnPool* connPool = Node_getConnPool(node);
|
||||
|
||||
numDroppedConns += NodeConnPool_disconnectAvailableStreams(connPool);
|
||||
|
||||
node = NodeStoreEx_referenceNextNodeAndReleaseOld(nodes, node); // iterate to next node
|
||||
}
|
||||
|
||||
return numDroppedConns;
|
||||
}
|
||||
18
client_module/source/common/toolkit/NodesTk.h
Normal file
18
client_module/source/common/toolkit/NodesTk.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef NODESTK_H_
|
||||
#define NODESTK_H_
|
||||
|
||||
#include <nodes/NodeStoreEx.h>
|
||||
#include <common/Common.h>
|
||||
#include <common/toolkit/list/StrCpyListIter.h>
|
||||
#include <common/toolkit/list/UInt8List.h>
|
||||
|
||||
|
||||
extern bool NodesTk_downloadNodes(App* app, Node* sourceNode, NodeType nodeType,
|
||||
NodeList* outNodeList, NumNodeID* outRootNodeID, bool* outRootIsBuddyMirrored);
|
||||
extern bool NodesTk_downloadTargetMappings(App* app, Node* sourceNode, struct list_head* mappings);
|
||||
extern bool NodesTk_downloadStatesAndBuddyGroups(App* app, Node* sourceNode,
|
||||
NodeType nodeType, struct list_head* groups, struct list_head* states);
|
||||
extern unsigned NodesTk_dropAllConnsByStore(NodeStoreEx* nodes);
|
||||
|
||||
|
||||
#endif /* NODESTK_H_ */
|
||||
31
client_module/source/common/toolkit/Random.c
Normal file
31
client_module/source/common/toolkit/Random.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <common/toolkit/Random.h>
|
||||
#include <common/Common.h>
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
|
||||
/**
|
||||
* @return positive (incl. zero) random number
|
||||
*/
|
||||
int Random_getNextInt(void)
|
||||
{
|
||||
int randVal;
|
||||
|
||||
get_random_bytes(&randVal, sizeof(randVal) );
|
||||
|
||||
// Note: -randVal (instead of ~randVal) wouldn't work for INT_MIN
|
||||
|
||||
return (randVal < 0) ? (~randVal) : randVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param min inclusive min value
|
||||
* @param max inclusive max value
|
||||
*/
|
||||
int Random_getNextInRange(int min, int max)
|
||||
{
|
||||
int randVal = Random_getNextInt() % (max - min + 1);
|
||||
|
||||
return(min + randVal);
|
||||
}
|
||||
|
||||
10
client_module/source/common/toolkit/Random.h
Normal file
10
client_module/source/common/toolkit/Random.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef OPEN_RANDOM_H_
|
||||
#define OPEN_RANDOM_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
|
||||
extern int Random_getNextInt(void);
|
||||
extern int Random_getNextInRange(int min, int max);
|
||||
|
||||
#endif /* OPEN_RANDOM_H_ */
|
||||
919
client_module/source/common/toolkit/Serialization.c
Normal file
919
client_module/source/common/toolkit/Serialization.c
Normal file
@@ -0,0 +1,919 @@
|
||||
#include "Serialization.h"
|
||||
#include "common/Common.h"
|
||||
#include <os/OsDeps.h>
|
||||
|
||||
bool __Serialization_deserializeNestedField(DeserializeCtx* ctx, DeserializeCtx* outCtx)
|
||||
{
|
||||
unsigned length;
|
||||
|
||||
if(!Serialization_deserializeUInt(ctx, &length) )
|
||||
return false;
|
||||
|
||||
length -= Serialization_serialLenUInt();
|
||||
|
||||
if (ctx->length < length)
|
||||
return false;
|
||||
|
||||
outCtx->data = ctx->data;
|
||||
outCtx->length = length;
|
||||
|
||||
ctx->data += length;
|
||||
ctx->length -= length;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 on error (e.g. strLen is greater than bufLen), used buffer size otherwise
|
||||
*/
|
||||
void Serialization_serializeStr(SerializeCtx* ctx, unsigned strLen, const char* strStart)
|
||||
{
|
||||
// write length field
|
||||
Serialization_serializeUInt(ctx, strLen);
|
||||
|
||||
// write raw string
|
||||
Serialization_serializeBlock(ctx, strStart, strLen);
|
||||
|
||||
// write termination char
|
||||
Serialization_serializeChar(ctx, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false on error (e.g. strLen is greater than bufLen)
|
||||
*/
|
||||
bool Serialization_deserializeStr(DeserializeCtx* ctx,
|
||||
unsigned* outStrLen, const char** outStrStart)
|
||||
{
|
||||
// length field
|
||||
if(unlikely(!Serialization_deserializeUInt(ctx, outStrLen) ) )
|
||||
return false;
|
||||
|
||||
// check length and terminating zero
|
||||
if(unlikely( (ctx->length < *outStrLen + 1) || ( (ctx->data)[*outStrLen] != 0) ) )
|
||||
return false;
|
||||
|
||||
// string start
|
||||
*outStrStart = ctx->data;
|
||||
ctx->data += *outStrLen + 1;
|
||||
ctx->length -= *outStrLen + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 on error (e.g. arrLen is greater than bufLen), used buffer size otherwise
|
||||
*/
|
||||
void Serialization_serializeCharArray(SerializeCtx* ctx, unsigned arrLen, const char* arrStart)
|
||||
{
|
||||
// elem count info field
|
||||
Serialization_serializeUInt(ctx, arrLen);
|
||||
|
||||
// copy raw array data
|
||||
Serialization_serializeBlock(ctx, arrStart, arrLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false on error (e.g. arrLen is greater than bufLen)
|
||||
*/
|
||||
bool Serialization_deserializeCharArray(DeserializeCtx* ctx,
|
||||
unsigned* outElemNum, const char** outArrStart, unsigned* outLen)
|
||||
{
|
||||
if(unlikely(!Serialization_deserializeUInt(ctx, outElemNum) ) )
|
||||
return false;
|
||||
|
||||
if(ctx->length < *outElemNum)
|
||||
return false;
|
||||
|
||||
// array start
|
||||
*outArrStart = ctx->data;
|
||||
|
||||
ctx->data += *outElemNum;
|
||||
ctx->length -= *outElemNum;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: adds padding to achieve 4 byte alignment
|
||||
*
|
||||
* @return 0 on error (e.g. strLen is greater than bufLen), used buffer size otherwise
|
||||
*/
|
||||
void Serialization_serializeStrAlign4(SerializeCtx* ctx, unsigned strLen, const char* strStart)
|
||||
{
|
||||
// write length field
|
||||
Serialization_serializeUInt(ctx, strLen);
|
||||
|
||||
// write raw string
|
||||
Serialization_serializeBlock(ctx, strStart, strLen);
|
||||
|
||||
// write termination char
|
||||
Serialization_serializeChar(ctx, 0);
|
||||
|
||||
// align to 4b length
|
||||
if( (strLen + 1) % 4)
|
||||
Serialization_serializeBlock(ctx, "\0\0\0", 4 - (strLen + 1) % 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false on error (e.g. strLen is greater than bufLen)
|
||||
*/
|
||||
bool Serialization_deserializeStrAlign4(DeserializeCtx* ctx,
|
||||
unsigned* outStrLen, const char** outStrStart)
|
||||
{
|
||||
const char* const bufAtStart = ctx->data;
|
||||
unsigned padding;
|
||||
|
||||
// length field
|
||||
if(unlikely(!Serialization_deserializeUInt(ctx, outStrLen) ) )
|
||||
return false;
|
||||
|
||||
// check length and terminating zero
|
||||
if(unlikely( (ctx->length < *outStrLen + 1) || ( (ctx->data)[*outStrLen] != 0) ) )
|
||||
return false;
|
||||
|
||||
// string start
|
||||
*outStrStart = ctx->data;
|
||||
ctx->data += *outStrLen + 1;
|
||||
ctx->length -= *outStrLen + 1;
|
||||
|
||||
padding = (ctx->data - bufAtStart) % 4;
|
||||
if(padding != 0)
|
||||
{
|
||||
if(unlikely(ctx->length < padding) )
|
||||
return false;
|
||||
|
||||
ctx->data += 4 - padding;
|
||||
ctx->length -= 4 - padding;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization of a NicList.
|
||||
*
|
||||
* note: 4 byte aligned.
|
||||
*
|
||||
* @return 0 on error, used buffer size otherwise
|
||||
*/
|
||||
void Serialization_serializeNicList(SerializeCtx* ctx, NicAddressList* nicList)
|
||||
{
|
||||
unsigned nicListSize = NicAddressList_length(nicList);
|
||||
NicAddressListIter iter;
|
||||
unsigned startOffset = ctx->length;
|
||||
|
||||
// length field placeholder
|
||||
Serialization_serializeUInt(ctx, 0xFFFFFFFF);
|
||||
|
||||
// elem count info field
|
||||
Serialization_serializeUInt(ctx, nicListSize);
|
||||
|
||||
// serialize each element of the nicList
|
||||
NicAddressListIter_init(&iter, nicList);
|
||||
|
||||
for(unsigned i = 0; i < nicListSize; i++, NicAddressListIter_next(&iter) )
|
||||
{
|
||||
NicAddress* nicAddr = NicAddressListIter_value(&iter);
|
||||
const size_t minNameSize = MIN(sizeof(nicAddr->name), SERIALIZATION_NICLISTELEM_NAME_SIZE);
|
||||
|
||||
// We currently only support and store ipv4 addresses internally, so we always set the
|
||||
// protocol field to 4.
|
||||
Serialization_serializeUInt8(ctx, 4);
|
||||
|
||||
{ // ipAddress
|
||||
Serialization_serializeBlock(ctx, &nicAddr->ipAddr.s_addr, sizeof(nicAddr->ipAddr.s_addr) );
|
||||
}
|
||||
|
||||
{ // name
|
||||
Serialization_serializeBlock(ctx, nicAddr->name, minNameSize);
|
||||
}
|
||||
|
||||
{ // nicType
|
||||
Serialization_serializeBlock(ctx, &nicAddr->nicType, sizeof(uint8_t) );
|
||||
}
|
||||
|
||||
{ // 2 bytes padding (for 4 byte alignment)
|
||||
Serialization_serializeBlock(ctx, "\0\0", 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite placeholder with length
|
||||
if (ctx->data)
|
||||
put_unaligned_le32(ctx->length - startOffset, ctx->data + startOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized NicList for deserialization via deserializeNicList().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeNicListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
if(!Serialization_deserializeUInt(ctx, &outList->length) )
|
||||
return false;
|
||||
|
||||
if(!Serialization_deserializeUInt(ctx, &outList->elemCount) )
|
||||
return false;
|
||||
|
||||
outList->data = ctx->data;
|
||||
// We need the length of the actual list without the two header fields above (which are included
|
||||
// in the sequence length field)
|
||||
outList->length -= 8;
|
||||
|
||||
if(unlikely(ctx->length < outList->length) )
|
||||
return false;
|
||||
|
||||
ctx->data += outList->length;
|
||||
ctx->length -= outList->length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a NicList.
|
||||
* (requires pre-processing via nicListBufToMsg() )
|
||||
*/
|
||||
void Serialization_deserializeNicList(const RawList* inList, NicAddressList* outNicList)
|
||||
{
|
||||
const char* currentNicListPos = inList->data;
|
||||
unsigned skipped = 0;
|
||||
|
||||
for(unsigned i = 0; i < inList->elemCount; i++)
|
||||
{
|
||||
uint8_t protocol;
|
||||
NicAddress* nicAddr = os_kmalloc(sizeof(NicAddress) );
|
||||
const size_t minNameSize = MIN(sizeof(nicAddr->name), SERIALIZATION_NICLISTELEM_NAME_SIZE);
|
||||
memset(nicAddr, 0, sizeof(NicAddress) ); // clear unused fields
|
||||
|
||||
{ // protocol
|
||||
protocol = (uint8_t) get_unaligned((char*)currentNicListPos);
|
||||
currentNicListPos += 1;
|
||||
}
|
||||
|
||||
if (protocol == 4)
|
||||
{ // ipAddress
|
||||
// Ipv4 address
|
||||
nicAddr->ipAddr.s_addr = get_unaligned((unsigned*)currentNicListPos);
|
||||
currentNicListPos += 4;
|
||||
} else {
|
||||
// If this is an ipv6 address, skip it as it is not supported yet.
|
||||
// 16 bytes ipv6 address + name + nicType + padding
|
||||
currentNicListPos += 16 + SERIALIZATION_NICLISTELEM_NAME_SIZE + 1 + 2;
|
||||
skipped += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
{ // name
|
||||
memcpy(&nicAddr->name, currentNicListPos, minNameSize);
|
||||
(nicAddr->name)[minNameSize-1] = 0; // make sure the string is zero-terminated
|
||||
|
||||
currentNicListPos += SERIALIZATION_NICLISTELEM_NAME_SIZE;
|
||||
}
|
||||
|
||||
{ // nicType
|
||||
nicAddr->nicType = (NicAddrType_t) get_unaligned((char*)currentNicListPos);
|
||||
currentNicListPos += 1;
|
||||
}
|
||||
|
||||
{ // 2 bytes padding (for 4 byte alignment)
|
||||
currentNicListPos += 2;
|
||||
}
|
||||
|
||||
NicAddressList_append(outNicList, nicAddr);
|
||||
}
|
||||
|
||||
if (skipped > 0) {
|
||||
printk_fhgfs(KERN_INFO, "Skipped deserializing %d unsupported IPv6 Nics", skipped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized NodeList for deserialization via deserializeNodeList().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeNodeListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if(!Serialization_deserializeUInt(ctx, &outList->elemCount) )
|
||||
return false;
|
||||
|
||||
// store start pos for later deserialize()
|
||||
|
||||
outList->data = ctx->data;
|
||||
|
||||
for(i=0; i < outList->elemCount; i++)
|
||||
{
|
||||
{// nodeID
|
||||
unsigned nodeIDLen = 0;
|
||||
const char* nodeID = NULL;
|
||||
|
||||
if(unlikely(!Serialization_deserializeStr(ctx, &nodeIDLen, &nodeID) ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
{// nicList (4b aligned)
|
||||
RawList nicList;
|
||||
|
||||
if(unlikely(!Serialization_deserializeNicListPreprocess(ctx, &nicList) ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
{// nodeNumID
|
||||
NumNodeID nodeNumID = {0};
|
||||
|
||||
if(unlikely(!NumNodeID_deserialize(ctx, &nodeNumID) ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
{// portUDP
|
||||
uint16_t portUDP = 0;
|
||||
|
||||
if(unlikely(!Serialization_deserializeUShort(ctx, &portUDP) ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
{// portTCP
|
||||
uint16_t portTCP = 0;
|
||||
|
||||
if(unlikely(!Serialization_deserializeUShort(ctx, &portTCP) ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
{// nodeType
|
||||
char nodeType = 0;
|
||||
|
||||
if(unlikely(!Serialization_deserializeChar(ctx, &nodeType) ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a NodeList.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* Note: Nodes will be constructed and need to be deleted later
|
||||
*/
|
||||
void Serialization_deserializeNodeList(App* app, const RawList* inList, NodeList* outNodeList)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
DeserializeCtx ctx = {
|
||||
.data = inList->data,
|
||||
.length = -1,
|
||||
};
|
||||
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
NicAddressList nicList;
|
||||
|
||||
const char* nodeID = NULL;
|
||||
NumNodeID nodeNumID = (NumNodeID){0};
|
||||
uint16_t portUDP = 0;
|
||||
uint16_t portTCP = 0;
|
||||
char nodeType = 0;
|
||||
|
||||
|
||||
NicAddressList_init(&nicList);
|
||||
|
||||
|
||||
{// nodeID
|
||||
unsigned nodeIDLen = 0;
|
||||
|
||||
Serialization_deserializeStr(&ctx, &nodeIDLen, &nodeID);
|
||||
}
|
||||
|
||||
{// nicList (4b aligned)
|
||||
RawList rawNicList;
|
||||
|
||||
Serialization_deserializeNicListPreprocess(&ctx, &rawNicList);
|
||||
Serialization_deserializeNicList(&rawNicList, &nicList);
|
||||
}
|
||||
|
||||
// nodeNumID
|
||||
NumNodeID_deserialize(&ctx, &nodeNumID);
|
||||
|
||||
// portUDP
|
||||
Serialization_deserializeUShort(&ctx, &portUDP);
|
||||
|
||||
// portTCP
|
||||
Serialization_deserializeUShort(&ctx, &portTCP);
|
||||
|
||||
// nodeType
|
||||
Serialization_deserializeChar(&ctx, &nodeType);
|
||||
|
||||
{// construct node
|
||||
Node* node;
|
||||
App_lockNicList(app);
|
||||
node = Node_construct(app, nodeID, nodeNumID, portUDP, portTCP, &nicList,
|
||||
nodeType == NODETYPE_Meta || nodeType == NODETYPE_Storage? App_getLocalRDMANicListLocked(app) : NULL);
|
||||
App_unlockNicList(app);
|
||||
|
||||
Node_setNodeAliasAndType(node, NULL, (NodeType)nodeType);
|
||||
|
||||
// append node to outList
|
||||
NodeList_append(outNodeList, node);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
ListTk_kfreeNicAddressListElems(&nicList);
|
||||
NicAddressList_uninit(&nicList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization of a StrCpyList.
|
||||
*
|
||||
* Note: We keep the serialiazation format compatible with string vec serialization
|
||||
*/
|
||||
void Serialization_serializeStrCpyList(SerializeCtx* ctx, StrCpyList* list)
|
||||
{
|
||||
SerializeCtx startCtx = *ctx;
|
||||
StrCpyListIter iter;
|
||||
|
||||
size_t listSize = StrCpyList_length(list);
|
||||
size_t i;
|
||||
|
||||
// totalBufLen info field
|
||||
Serialization_serializeUInt(ctx, 0);
|
||||
|
||||
// elem count info field
|
||||
Serialization_serializeUInt(ctx, listSize);
|
||||
|
||||
// store each element of the list as a raw zero-terminated string
|
||||
StrCpyListIter_init(&iter, list);
|
||||
|
||||
for(i=0; i < listSize; i++, StrCpyListIter_next(&iter) )
|
||||
{
|
||||
char* currentElem = StrCpyListIter_value(&iter);
|
||||
size_t serialElemLen = strlen(currentElem) + 1; // +1 for the terminating zero
|
||||
|
||||
Serialization_serializeBlock(ctx, currentElem, serialElemLen);
|
||||
}
|
||||
|
||||
// fix totalBufLen info field
|
||||
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized StrCpyList.
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeStrCpyListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
DeserializeCtx outCtx;
|
||||
|
||||
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
|
||||
return false;
|
||||
|
||||
// elem count field
|
||||
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
|
||||
return false;
|
||||
|
||||
if(unlikely(outList->elemCount && ( outCtx.data[outCtx.length - 1] != 0) ) )
|
||||
return false;
|
||||
|
||||
outList->data = outCtx.data;
|
||||
outList->length = outCtx.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a StrCpyList.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeStrCpyList(const RawList* inList, StrCpyList* outList)
|
||||
{
|
||||
const char* listStart = inList->data;
|
||||
unsigned listBufLen = inList->length;
|
||||
unsigned i;
|
||||
|
||||
// read each list element as a raw zero-terminated string
|
||||
// and make sure that we do not read beyond the specified end position
|
||||
|
||||
for(i = 0; (i < inList->elemCount) && (listBufLen > 0); i++)
|
||||
{
|
||||
size_t elemLen = strlen(listStart);
|
||||
|
||||
StrCpyList_append(outList, listStart);
|
||||
|
||||
listStart += elemLen + 1; // +1 for the terminating zero
|
||||
listBufLen -= elemLen + 1; // +1 for the terminating zero
|
||||
}
|
||||
|
||||
return i == inList->elemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization of a StrCpyVec.
|
||||
*
|
||||
* Note: We keep the serialiazation format compatible with string list serialization
|
||||
*/
|
||||
void Serialization_serializeStrCpyVec(SerializeCtx* ctx, StrCpyVec* vec)
|
||||
{
|
||||
Serialization_serializeStrCpyList(ctx, &vec->strCpyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized StrCpyVec.
|
||||
*
|
||||
* Note: We keep the serialization format compatible to the string list format.
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeStrCpyVecPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
// serialization format is 100% compatible to the list version, so we can just use the list
|
||||
// version code here...
|
||||
|
||||
return Serialization_deserializeStrCpyListPreprocess(ctx, outList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a StrCpyVec.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeStrCpyVec(const RawList* inList, StrCpyVec* outVec)
|
||||
{
|
||||
const char* listStart = inList->data;
|
||||
unsigned listBufLen = inList->length;
|
||||
unsigned i;
|
||||
|
||||
// read each list element as a raw zero-terminated string
|
||||
// and make sure that we do not read beyond the specified end position
|
||||
|
||||
for(i = 0; (i < inList->elemCount) && (listBufLen > 0); i++)
|
||||
{
|
||||
size_t elemLen = strlen(listStart);
|
||||
|
||||
StrCpyVec_append(outVec, listStart);
|
||||
|
||||
listStart += elemLen + 1; // +1 for the terminating zero
|
||||
listBufLen -= elemLen + 1; // +1 for the terminating zero
|
||||
}
|
||||
|
||||
return i == inList->elemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized UInt8List().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt8ListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
DeserializeCtx outCtx;
|
||||
|
||||
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
|
||||
return false;
|
||||
|
||||
// elem count field
|
||||
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
|
||||
return false;
|
||||
|
||||
if(outCtx.length != outList->elemCount * Serialization_serialLenUInt8() )
|
||||
return false;
|
||||
|
||||
outList->data = outCtx.data;
|
||||
outList->length = outCtx.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a UInt8List.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt8List(const RawList* inList, UInt8List* outList)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
if(!Serialization_deserializeUInt8(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
UInt8List_append(outList, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized UInt8Vec().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt8VecPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
// serialization format is 100% compatible to the list version, so we can just use the list
|
||||
// version code here...
|
||||
|
||||
return Serialization_deserializeUInt8ListPreprocess(ctx, outList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a UInt8Vec.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt8Vec(const RawList* inList, UInt8Vec* outVec)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
if(!Serialization_deserializeUInt8(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
UInt8Vec_append(outVec, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serialization of a UInt16List.
|
||||
*
|
||||
* Note: We keep the serialization format compatible with int vec serialization
|
||||
*/
|
||||
void Serialization_serializeUInt16List(SerializeCtx* ctx, UInt16List* list)
|
||||
{
|
||||
SerializeCtx startCtx = *ctx;
|
||||
UInt16ListIter iter;
|
||||
unsigned i;
|
||||
|
||||
unsigned listSize = UInt16List_length(list);
|
||||
|
||||
// totalBufLen info field
|
||||
Serialization_serializeUInt(ctx, 0);
|
||||
|
||||
// elem count info field
|
||||
Serialization_serializeUInt(ctx, listSize);
|
||||
|
||||
// store each element of the list
|
||||
UInt16ListIter_init(&iter, list);
|
||||
|
||||
for(i=0; i < listSize; i++, UInt16ListIter_next(&iter) )
|
||||
{
|
||||
uint16_t currentValue = UInt16ListIter_value(&iter);
|
||||
|
||||
Serialization_serializeUShort(ctx, currentValue);
|
||||
}
|
||||
|
||||
// fix totalBufLen info field
|
||||
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized UInt16List().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt16ListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
DeserializeCtx outCtx;
|
||||
|
||||
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
|
||||
return false;
|
||||
|
||||
// elem count field
|
||||
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
|
||||
return false;
|
||||
|
||||
if(outCtx.length != outList->elemCount * Serialization_serialLenUShort() )
|
||||
return false;
|
||||
|
||||
outList->data = outCtx.data;
|
||||
outList->length = outCtx.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a UInt16List.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt16List(const RawList* inList, UInt16List* outList)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
if(!Serialization_deserializeUShort(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
UInt16List_append(outList, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: We keep the serialiazation format compatible with string list serialization
|
||||
*/
|
||||
void Serialization_serializeUInt16Vec(SerializeCtx* ctx, UInt16Vec* vec)
|
||||
{
|
||||
// UInt16Vecs are derived from UInt16Lists, so we can just do a cast here and use the list
|
||||
// version code...
|
||||
|
||||
Serialization_serializeUInt16List(ctx, (UInt16List*)vec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized UInt16Vec().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt16VecPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
// serialization format is 100% compatible to the list version, so we can just use the list
|
||||
// version code here...
|
||||
|
||||
return Serialization_deserializeUInt16ListPreprocess(ctx, outList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a UInt16Vec.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeUInt16Vec(const RawList* inList, UInt16Vec* outVec)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
if(!Serialization_deserializeUShort(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
UInt16Vec_append(outVec, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialization of a Int64CpyList.
|
||||
*
|
||||
* Note: We keep the serialization format compatible with int vec serialization
|
||||
*/
|
||||
void Serialization_serializeInt64CpyList(SerializeCtx* ctx, Int64CpyList* list)
|
||||
{
|
||||
SerializeCtx startCtx = *ctx;
|
||||
Int64CpyListIter iter;
|
||||
unsigned i;
|
||||
|
||||
unsigned listSize = Int64CpyList_length(list);
|
||||
|
||||
// totalBufLen info field
|
||||
Serialization_serializeUInt(ctx, 0);
|
||||
|
||||
// elem count info field
|
||||
Serialization_serializeUInt(ctx, listSize);
|
||||
|
||||
// store each element of the list
|
||||
Int64CpyListIter_init(&iter, list);
|
||||
|
||||
for(i=0; i < listSize; i++, Int64CpyListIter_next(&iter) )
|
||||
{
|
||||
int64_t currentValue = Int64CpyListIter_value(&iter);
|
||||
|
||||
Serialization_serializeInt64(ctx, currentValue);
|
||||
}
|
||||
|
||||
// fix totalBufLen info field
|
||||
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized Int64CpyList().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeInt64CpyListPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
DeserializeCtx outCtx;
|
||||
|
||||
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
|
||||
return false;
|
||||
|
||||
// elem count field
|
||||
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
|
||||
return false;
|
||||
|
||||
if(outCtx.length != (outList->elemCount * Serialization_serialLenInt64() ) )
|
||||
return false;
|
||||
|
||||
outList->data = outCtx.data;
|
||||
outList->length = outCtx.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a Int64CpyList.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeInt64CpyList(const RawList* inList, Int64CpyList* outList)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
int64_t value;
|
||||
|
||||
if(!Serialization_deserializeInt64(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
Int64CpyList_append(outList, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: We keep the serialiazation format compatible with string list serialization
|
||||
*/
|
||||
void Serialization_serializeInt64CpyVec(SerializeCtx* ctx, Int64CpyVec* vec)
|
||||
{
|
||||
// Int64CpyVecs are derived from Int64CpyLists, so we can just do a cast here and use the list
|
||||
// version code...
|
||||
|
||||
Serialization_serializeInt64CpyList(ctx, (Int64CpyList*)vec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes a serialized Int64CpyVec().
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeInt64CpyVecPreprocess(DeserializeCtx* ctx, RawList* outList)
|
||||
{
|
||||
// serialization format is 100% compatible to the list version, so we can just use the list
|
||||
// version code here...
|
||||
|
||||
return Serialization_deserializeInt64CpyListPreprocess(ctx, outList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a Int64CpyVec.
|
||||
* (requires pre-processing)
|
||||
*
|
||||
* @return false on error or inconsistency
|
||||
*/
|
||||
bool Serialization_deserializeInt64CpyVec(const RawList* inList, Int64CpyVec* outVec)
|
||||
{
|
||||
DeserializeCtx ctx = { inList->data, inList->length };
|
||||
unsigned i;
|
||||
|
||||
// read each list element
|
||||
for(i=0; i < inList->elemCount; i++)
|
||||
{
|
||||
int64_t value;
|
||||
|
||||
if(!Serialization_deserializeInt64(&ctx, &value) )
|
||||
return false;
|
||||
|
||||
Int64CpyVec_append(outVec, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
617
client_module/source/common/toolkit/Serialization.h
Normal file
617
client_module/source/common/toolkit/Serialization.h
Normal file
@@ -0,0 +1,617 @@
|
||||
#ifndef SERIALIZATION_H_
|
||||
#define SERIALIZATION_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/net/sock/NetworkInterfaceCard.h>
|
||||
#include <common/net/sock/NicAddressList.h>
|
||||
#include <common/toolkit/list/Int64CpyList.h>
|
||||
#include <common/toolkit/list/Int64CpyListIter.h>
|
||||
#include <common/toolkit/list/NumNodeIDList.h>
|
||||
#include <common/toolkit/list/NumNodeIDListIter.h>
|
||||
#include <common/toolkit/list/StrCpyList.h>
|
||||
#include <common/toolkit/list/StrCpyListIter.h>
|
||||
#include <common/toolkit/list/UInt8List.h>
|
||||
#include <common/toolkit/list/UInt8ListIter.h>
|
||||
#include <common/toolkit/list/UInt16List.h>
|
||||
#include <common/toolkit/list/UInt16ListIter.h>
|
||||
#include <common/toolkit/vector/Int64CpyVec.h>
|
||||
#include <common/toolkit/vector/StrCpyVec.h>
|
||||
#include <common/toolkit/vector/UInt16Vec.h>
|
||||
#include <common/toolkit/vector/UInt8Vec.h>
|
||||
#include <common/toolkit/ListTk.h>
|
||||
#include <common/toolkit/Serialization.h>
|
||||
#include <common/storage/Path.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/nodes/NodeList.h>
|
||||
#include <common/nodes/NodeListIter.h>
|
||||
#include <os/OsCompat.h>
|
||||
|
||||
#ifdef KERNEL_HAS_LINUX_UNALIGNED_H
|
||||
#include <linux/unaligned.h>
|
||||
#else
|
||||
#include <asm/unaligned.h>
|
||||
#endif
|
||||
|
||||
#define SERIALIZATION_NICLISTELEM_NAME_SIZE (16)
|
||||
|
||||
bool __Serialization_deserializeNestedField(DeserializeCtx* ctx, DeserializeCtx* outCtx);
|
||||
|
||||
// string (de)serialization
|
||||
void Serialization_serializeStr(SerializeCtx* ctx, unsigned strLen, const char* strStart);
|
||||
bool Serialization_deserializeStr(DeserializeCtx* ctx,
|
||||
unsigned* outStrLen, const char** outStrStart);
|
||||
|
||||
// string aligned (de)serialization
|
||||
void Serialization_serializeStrAlign4(SerializeCtx* ctx, unsigned strLen, const char* strStart);
|
||||
bool Serialization_deserializeStrAlign4(DeserializeCtx* ctx,
|
||||
unsigned* outStrLen, const char** outStrStart);
|
||||
|
||||
// char array (arbitrary binary data) (de)serialization
|
||||
void Serialization_serializeCharArray(SerializeCtx* ctx, unsigned arrLen, const char* arrStart);
|
||||
bool Serialization_deserializeCharArray(DeserializeCtx* ctx,
|
||||
unsigned* outArrLen, const char** outArrStart, unsigned* outLen);
|
||||
|
||||
// nicList (de)serialization
|
||||
void Serialization_serializeNicList(SerializeCtx* ctx, NicAddressList* nicList);
|
||||
bool Serialization_deserializeNicListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
void Serialization_deserializeNicList(const RawList* inList, NicAddressList* outNicList);
|
||||
|
||||
// nodeList (de)serialization
|
||||
bool Serialization_deserializeNodeListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
void Serialization_deserializeNodeList(App* app, const RawList* inList, NodeList* outNodeList);
|
||||
|
||||
// strCpyList (de)serialization
|
||||
void Serialization_serializeStrCpyList(SerializeCtx* ctx, StrCpyList* list);
|
||||
bool Serialization_deserializeStrCpyListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeStrCpyList(const RawList* inList, StrCpyList* outList);
|
||||
|
||||
// strCpyVec (de)serialization
|
||||
void Serialization_serializeStrCpyVec(SerializeCtx* ctx, StrCpyVec* vec);
|
||||
bool Serialization_deserializeStrCpyVecPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeStrCpyVec(const RawList* inList, StrCpyVec* outVec);
|
||||
|
||||
// uint8List (de)serialization
|
||||
bool Serialization_deserializeUInt8ListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeUInt8List(const RawList* inList, UInt8List* outList);
|
||||
|
||||
// uint8Vec (de)serialization
|
||||
bool Serialization_deserializeUInt8VecPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeUInt8Vec(const RawList* inList, UInt8Vec* outList);
|
||||
|
||||
// uint16List (de)serialization
|
||||
void Serialization_serializeUInt16List(SerializeCtx* ctx, UInt16List* list);
|
||||
bool Serialization_deserializeUInt16ListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeUInt16List(const RawList* inList, UInt16List* outList);
|
||||
|
||||
// uint16Vec (de)serialization
|
||||
void Serialization_serializeUInt16Vec(SerializeCtx* ctx, UInt16Vec* vec);
|
||||
bool Serialization_deserializeUInt16VecPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeUInt16Vec(const RawList* inList, UInt16Vec* outVec);
|
||||
|
||||
// int64CpyList (de)serialization
|
||||
void Serialization_serializeInt64CpyList(SerializeCtx* ctx, Int64CpyList* list);
|
||||
bool Serialization_deserializeInt64CpyListPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeInt64CpyList(const RawList* inList, Int64CpyList* outList);
|
||||
|
||||
// uint64Vec (de)serialization
|
||||
void Serialization_serializeInt64CpyVec(SerializeCtx* ctx, Int64CpyVec* vec);
|
||||
bool Serialization_deserializeInt64CpyVecPreprocess(DeserializeCtx* ctx, RawList* outList);
|
||||
bool Serialization_deserializeInt64CpyVec(const RawList* inList, Int64CpyVec* outVec);
|
||||
|
||||
// inliners
|
||||
static inline void Serialization_serializeBlock(SerializeCtx* ctx, const void* value,
|
||||
unsigned length);
|
||||
|
||||
static inline unsigned Serialization_serialLenChar(void);
|
||||
static inline void Serialization_serializeChar(SerializeCtx* ctx, char value);
|
||||
static inline bool Serialization_deserializeChar(DeserializeCtx* ctx, char* outValue);
|
||||
static inline unsigned Serialization_serialLenBool(void);
|
||||
static inline void Serialization_serializeBool(SerializeCtx* ctx, bool value);
|
||||
static inline bool Serialization_deserializeBool(DeserializeCtx* ctx, bool* outValue);
|
||||
static inline unsigned Serialization_serialLenUInt8(void);
|
||||
static inline bool Serialization_deserializeUInt8(DeserializeCtx* ctx, uint8_t* outValue);
|
||||
static inline unsigned Serialization_serialLenShort(void);
|
||||
static inline void Serialization_serializeShort(SerializeCtx* ctx, short value);
|
||||
static inline bool Serialization_deserializeShort(DeserializeCtx* ctx, short* outValue);
|
||||
static inline unsigned Serialization_serialLenUShort(void);
|
||||
static inline void Serialization_serializeUShort(SerializeCtx* ctx, unsigned short value);
|
||||
static inline bool Serialization_deserializeUShort(DeserializeCtx* ctx, unsigned short* outValue);
|
||||
static inline void Serialization_serializeInt(SerializeCtx* ctx, int value);
|
||||
static inline bool Serialization_deserializeInt(DeserializeCtx* ctx, int* outValue);
|
||||
static inline unsigned Serialization_serialLenInt(void);
|
||||
static inline void Serialization_serializeUInt(SerializeCtx* ctx, unsigned value);
|
||||
static inline bool Serialization_deserializeUInt(DeserializeCtx* ctx, unsigned* outValue);
|
||||
static inline unsigned Serialization_serialLenUInt(void);
|
||||
static inline void Serialization_serializeInt64(SerializeCtx* ctx, int64_t value);
|
||||
static inline bool Serialization_deserializeInt64(DeserializeCtx* ctx, int64_t* outValue);
|
||||
static inline unsigned Serialization_serialLenInt64(void);
|
||||
static inline void Serialization_serializeUInt64(SerializeCtx* ctx, uint64_t value);
|
||||
static inline bool Serialization_deserializeUInt64(DeserializeCtx* ctx, uint64_t* outValue);
|
||||
static inline unsigned Serialization_serialLenUInt64(void);
|
||||
|
||||
|
||||
void Serialization_serializeBlock(SerializeCtx* ctx, const void* value, unsigned length)
|
||||
{
|
||||
if(ctx->data)
|
||||
memcpy(ctx->data + ctx->length, value, length);
|
||||
|
||||
ctx->length += length;
|
||||
}
|
||||
|
||||
#define __Serialization_deserializeRaw(ctx, convert, outValue) \
|
||||
({ \
|
||||
DeserializeCtx* ctx__ = (ctx); \
|
||||
bool result = false; \
|
||||
(void) (outValue == (__typeof__(convert(ctx__->data) )*) 0); \
|
||||
if(likely(ctx__->length >= sizeof(*(outValue) ) ) ) \
|
||||
{ \
|
||||
*(outValue) = convert(ctx__->data); \
|
||||
ctx__->data += sizeof(*(outValue) ); \
|
||||
ctx__->length -= sizeof(*(outValue) ); \
|
||||
result = true; \
|
||||
} \
|
||||
result; \
|
||||
})
|
||||
|
||||
|
||||
// char (de)serialization
|
||||
static inline unsigned Serialization_serialLenChar(void)
|
||||
{
|
||||
return sizeof(char);
|
||||
}
|
||||
|
||||
static inline void Serialization_serializeChar(SerializeCtx* ctx, char value)
|
||||
{
|
||||
if(ctx->data)
|
||||
ctx->data[ctx->length] = value;
|
||||
|
||||
ctx->length += sizeof(value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeChar(DeserializeCtx* ctx, char* outValue)
|
||||
{
|
||||
return __Serialization_deserializeRaw(ctx, *, outValue);
|
||||
}
|
||||
|
||||
|
||||
// bool (de)serialization
|
||||
static inline unsigned Serialization_serialLenBool(void)
|
||||
{
|
||||
return Serialization_serialLenChar();
|
||||
}
|
||||
|
||||
static inline void Serialization_serializeBool(SerializeCtx* ctx, bool value)
|
||||
{
|
||||
Serialization_serializeChar(ctx, value ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeBool(DeserializeCtx* ctx, bool* outValue)
|
||||
{
|
||||
char charVal = 0;
|
||||
bool deserRes = Serialization_deserializeChar(ctx, &charVal);
|
||||
|
||||
*outValue = (charVal != 0);
|
||||
return deserRes;
|
||||
}
|
||||
|
||||
// uint8_t (de)serialization
|
||||
static inline void Serialization_serializeUInt8(SerializeCtx* ctx, uint8_t value)
|
||||
{
|
||||
Serialization_serializeChar(ctx, (char) value);
|
||||
}
|
||||
|
||||
static inline unsigned Serialization_serialLenUInt8(void)
|
||||
{
|
||||
return Serialization_serialLenChar();
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeUInt8(DeserializeCtx* ctx,
|
||||
uint8_t* outValue)
|
||||
{
|
||||
return Serialization_deserializeChar(ctx, (char*)outValue);
|
||||
}
|
||||
|
||||
// short (de)serialization
|
||||
static inline unsigned Serialization_serialLenShort(void)
|
||||
{
|
||||
return Serialization_serialLenUShort();
|
||||
}
|
||||
|
||||
static inline void Serialization_serializeShort(SerializeCtx* ctx, short value)
|
||||
{
|
||||
Serialization_serializeUShort(ctx, value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeShort(DeserializeCtx* ctx,
|
||||
short* outValue)
|
||||
{
|
||||
return Serialization_deserializeUShort(ctx, (unsigned short*)outValue);
|
||||
}
|
||||
|
||||
// ushort (de)serialization
|
||||
static inline unsigned Serialization_serialLenUShort(void)
|
||||
{
|
||||
return sizeof(unsigned short);
|
||||
}
|
||||
|
||||
static inline void Serialization_serializeUShort(SerializeCtx* ctx, unsigned short value)
|
||||
{
|
||||
if(ctx->data)
|
||||
put_unaligned_le16(value, ctx->data + ctx->length);
|
||||
|
||||
ctx->length += sizeof(value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeUShort(DeserializeCtx* ctx, unsigned short* outValue)
|
||||
{
|
||||
return __Serialization_deserializeRaw(ctx, get_unaligned_le16, outValue);
|
||||
}
|
||||
|
||||
// int (de)serialization
|
||||
static inline unsigned Serialization_serialLenInt(void)
|
||||
{
|
||||
return Serialization_serialLenUInt();
|
||||
}
|
||||
|
||||
static inline void Serialization_serializeInt(SerializeCtx* ctx, int value)
|
||||
{
|
||||
Serialization_serializeUInt(ctx, value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeInt(DeserializeCtx* ctx, int* outValue)
|
||||
{
|
||||
return Serialization_deserializeUInt(ctx, (unsigned*)outValue);
|
||||
}
|
||||
|
||||
|
||||
// uint (de)serialization
|
||||
static inline void Serialization_serializeUInt(SerializeCtx* ctx, unsigned value)
|
||||
{
|
||||
if(ctx->data)
|
||||
put_unaligned_le32(value, ctx->data + ctx->length);
|
||||
|
||||
ctx->length += sizeof(value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeUInt(DeserializeCtx* ctx, unsigned* outValue)
|
||||
{
|
||||
return __Serialization_deserializeRaw(ctx, get_unaligned_le32, outValue);
|
||||
}
|
||||
|
||||
static inline unsigned Serialization_serialLenUInt(void)
|
||||
{
|
||||
return sizeof(unsigned);
|
||||
}
|
||||
|
||||
// int64 (de)serialization
|
||||
static inline void Serialization_serializeInt64(SerializeCtx* ctx, int64_t value)
|
||||
{
|
||||
Serialization_serializeUInt64(ctx, value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeInt64(DeserializeCtx* ctx,
|
||||
int64_t* outValue)
|
||||
{
|
||||
return Serialization_deserializeUInt64(ctx, (uint64_t*)outValue);
|
||||
}
|
||||
|
||||
static inline unsigned Serialization_serialLenInt64(void)
|
||||
{
|
||||
return Serialization_serialLenUInt64();
|
||||
}
|
||||
|
||||
// uint64 (de)serialization
|
||||
static inline void Serialization_serializeUInt64(SerializeCtx* ctx, uint64_t value)
|
||||
{
|
||||
if(ctx->data)
|
||||
put_unaligned_le64(value, ctx->data + ctx->length);
|
||||
|
||||
ctx->length += sizeof(value);
|
||||
}
|
||||
|
||||
static inline bool Serialization_deserializeUInt64(DeserializeCtx* ctx,
|
||||
uint64_t* outValue)
|
||||
{
|
||||
return __Serialization_deserializeRaw(ctx, get_unaligned_le64, outValue);
|
||||
}
|
||||
|
||||
static inline unsigned Serialization_serialLenUInt64(void)
|
||||
{
|
||||
return sizeof(uint64_t);
|
||||
}
|
||||
|
||||
#define __SERDES_CONCAT_I(a, b) a ## b
|
||||
#define __SERDES_CONCAT(a, b) __SERDES_CONCAT_I(a, b)
|
||||
|
||||
#define __SERDES_COUNT_I(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, count, ...) count
|
||||
#define __SERDES_COUNT(...) __SERDES_COUNT_I(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define __SERDES_CALL(Base, ...) __SERDES_CONCAT(Base, __SERDES_COUNT(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#define __SERDES_FIELD_NAME(Name, SerMod, NS, Suffix) Name
|
||||
#define __SERDES_FIELD_SER(Name, SerMod, NS, Suffix) NS##_serialize##Suffix
|
||||
#define __SERDES_FIELD_SER_MOD(Name, SerMod, NS, Suffix) SerMod
|
||||
#define __SERDES_FIELD_DES(Name, SerMod, NS, Suffix) NS##_deserialize##Suffix
|
||||
|
||||
#define __SERDES_DEFINE_SER_1(Field) \
|
||||
__SERDES_FIELD_SER Field(ctx, __SERDES_FIELD_SER_MOD Field(value->__SERDES_FIELD_NAME Field));
|
||||
#define __SERDES_DEFINE_SER_2(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_1(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_3(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_2(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_4(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_3(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_5(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_4(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_6(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_5(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_7(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_6(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_8(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_7(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_9(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_8(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_SER_10(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_9(__VA_ARGS__)
|
||||
|
||||
#define __SERDES_DEFINE_SER(NS, Type, ...) \
|
||||
__attribute__((unused)) \
|
||||
void NS##_serialize(SerializeCtx* ctx, const Type* value) \
|
||||
{ \
|
||||
__SERDES_CALL(__SERDES_DEFINE_SER_, __VA_ARGS__) \
|
||||
}
|
||||
|
||||
|
||||
#define __SERDES_DEFINE_DES_1(Field) \
|
||||
if (!__SERDES_FIELD_DES Field(ctx, &value->__SERDES_FIELD_NAME Field)) \
|
||||
goto err;
|
||||
#define __SERDES_DEFINE_DES_2(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_1(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_3(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_2(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_4(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_3(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_5(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_4(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_6(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_5(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_7(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_6(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_8(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_7(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_9(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_8(__VA_ARGS__)
|
||||
#define __SERDES_DEFINE_DES_10(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_9(__VA_ARGS__)
|
||||
|
||||
#define __SERDES_DEFINE_DES(NS, Type, Init, ErrFini, ...) \
|
||||
__attribute__((unused)) \
|
||||
bool NS##_deserialize(DeserializeCtx* ctx, Type* value) \
|
||||
{ \
|
||||
Init; \
|
||||
__SERDES_CALL(__SERDES_DEFINE_DES_, __VA_ARGS__) \
|
||||
return true; \
|
||||
err: \
|
||||
ErrFini; \
|
||||
return false; \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SERDES_DECLARE_SERIALIZERS() - declares serialize and deserialize functions for a given type.
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type the type to be made serializable/deserializable
|
||||
*
|
||||
* creates ``extern`` declarations for serializer functions as generated by
|
||||
* ``SERDES_DEFINE_SERIALIZERS`` or ``SERDES_DEFINE_SERIALIZERS_SIMPLE``.
|
||||
*/
|
||||
#define SERDES_DECLARE_SERIALIZERS(NS, Type) \
|
||||
extern void NS##_serialize(SerializeCtx* ctx, const Type* value); \
|
||||
extern bool NS##_deserialize(DeserializeCtx* ctx, Type* value);
|
||||
/**
|
||||
* SERDES_DEFINE_SERIALIZERS() - defines serialize and deserialize functions for a given type.
|
||||
* @Access access modifiers for the generated functions
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type the type to be made serializable/deserializable
|
||||
* @DesInit initialization code to be run before an instance is deserialized
|
||||
* @DesErrFini finalization code to be run when deserialization fails
|
||||
* @... description of @Type
|
||||
*
|
||||
* Declares a function ``NS##_serialize(SerializeCtx* ctx, const Type* value)`` and a function
|
||||
* ``NS##_deserialize(DeserializeCtx* ctx, Type* value)`` that follow the
|
||||
* serializer and deserializer conventions.
|
||||
*
|
||||
* During deserialization, ``DesInit`` is evaluated as an expression in the scope of the
|
||||
* deserializer function (ie, ``ctx`` and ``value`` are available). @DesInit may be called on
|
||||
* objects that have been initialized previously, via @DesInit or some other method. The invoker
|
||||
* must be careful to not introduce memory leaks via this expression. @DesInit and @DesErrFini
|
||||
* should always call the usual initialization and release functions for the type.
|
||||
*
|
||||
* If deserialization fails for any reason, ``DesErrFini`` is evaluated in the context of the
|
||||
* deserializer function just like ``DesInit``. All resources allocated during initialization or
|
||||
* deserialization must be released by ``DesErrFini``.
|
||||
*
|
||||
* @Type is exposed to the serializer as a list if one to 10 comma-separated tuples of the form
|
||||
* ``(FieldName, SerMod, SerNS, Suffix)``.
|
||||
*
|
||||
* * ``FieldName`` is the name of the serialized field. Fields are serialized and deserialized in
|
||||
* the order they appear in the description list.
|
||||
* * ``SerMod`` is a modifier applied to the serialized value before passing it on to the
|
||||
* serializer (see example).
|
||||
* * ``SerNS`` is the namespace of the serializer and deserializer functions for this field.
|
||||
* * ``Suffix`` is appended to the canonical name of the serializer and deserializer functions for
|
||||
* the field.
|
||||
*
|
||||
* For the generated serializer, each field expands into a single call to a serializer.
|
||||
* ``SerNS##_serialize##Suffix(ctx, SerMod (value->FieldName);``
|
||||
*
|
||||
* For the generated deserializer, each field expands into a single call to a deserializer. For
|
||||
* deserializers the ``SerMod`` field of the description is ignored and a pointer is always passed.
|
||||
* ``SerNS##_deserialize##Suffix(ctx, &(value->FieldName));``
|
||||
*
|
||||
* Example:
|
||||
* ``
|
||||
* struct S
|
||||
* {
|
||||
* const char* str;
|
||||
* };
|
||||
* SERDES_DEFINE_SERIALIZERS(static inline, _S, struct S,
|
||||
* value->str = NULL,
|
||||
* kfree(value->str),
|
||||
* (str, &, Serdes, CStr))
|
||||
* ``
|
||||
* will expand to this serializer and deserializer code:
|
||||
* ``
|
||||
* static inline void _S_serialize(SerializeCtx* ctx, const struct S* value)
|
||||
* {
|
||||
* Serdes_serializeCStr(ctx, &(value->str));
|
||||
* }
|
||||
* static inline bool _S_deserialize(DeserializeCtx* ctx, struct S* value)
|
||||
* {
|
||||
* value->str = NULL;
|
||||
* if (!Serdes_deserializeCStr(ctx, &value->str))
|
||||
* goto err;
|
||||
* return true;
|
||||
* err:
|
||||
* kfree(value->str);
|
||||
* return false;
|
||||
* }
|
||||
* ``
|
||||
*/
|
||||
#define SERDES_DEFINE_SERIALIZERS(Access, NS, Type, DesInit, DesErrFini, ...) \
|
||||
Access __SERDES_DEFINE_SER(NS, Type, __VA_ARGS__) \
|
||||
Access __SERDES_DEFINE_DES(NS, Type, DesInit, DesErrFini, __VA_ARGS__)
|
||||
/**
|
||||
* SERDES_DEFINE_SERIALIZERS_SIMPLE() - defines serialize and deserialize functions for a given type
|
||||
* @Access access modifiers for the generated functions
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type the type to be made serializable/deserializable
|
||||
* @... description of @Type
|
||||
*
|
||||
* expands to ``SERDES_DEFINE_SERIALIZERS(Access, NS, Type, ({}), ({}), __VA_ARGS__)``, ie no
|
||||
* special intialization or cleanup is done for deserialization.
|
||||
*/
|
||||
#define SERDES_DEFINE_SERIALIZERS_SIMPLE(Access, NS, Type, ...) \
|
||||
SERDES_DEFINE_SERIALIZERS(Access, NS, Type, ({}), ({}), __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* SERDES_SERIALIZE_AS - defines enum serializers based on underlying type
|
||||
* @Access access modifiers for the generated functions
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type the type to be made serializable/deserializable
|
||||
* @As underlying type to used for serialized data
|
||||
* @AsSuffix suffix for de/serializer in ``Serialization``
|
||||
*
|
||||
* enum types that go over the wire must be serialized with a consistent type at both end. this
|
||||
* macro defines serializers for a given enum @Type which use @As for the binary representation.
|
||||
* since this is about underlying types this macro can only call ``Serialization_*`` functions.
|
||||
*/
|
||||
#define SERDES_SERIALIZE_AS(Access, NS, Type, As, AsSuffix) \
|
||||
__attribute__((unused)) \
|
||||
Access void NS##_serialize(SerializeCtx* ctx, Type value) \
|
||||
{ \
|
||||
Serialization_serialize##AsSuffix(ctx, (As) value); \
|
||||
} \
|
||||
__attribute__((unused)) \
|
||||
Access bool NS##_deserialize(DeserializeCtx* ctx, Type* value) \
|
||||
{ \
|
||||
As tmp; \
|
||||
if (!Serialization_deserialize##AsSuffix(ctx, &tmp)) \
|
||||
return false; \
|
||||
*value = (Type) tmp; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
/**
|
||||
* SERDES_DECLARE_LIST_SERIALIZERS() - declare list serializers for a given type
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type type of list entry
|
||||
*
|
||||
* Declares ``extern`` prototypes of the functions as generated by
|
||||
* ``SERDES_DEFINE_LIST_SERIALIZERS``
|
||||
*/
|
||||
#define SERDES_DECLARE_LIST_SERIALIZERS(NS, Type) \
|
||||
extern void NS##_serialize(SerializeCtx* ctx, const struct list_head* list); \
|
||||
extern bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list); \
|
||||
/**
|
||||
* SERDES_DEFINE_LIST_SERIALIZERS() - defines list serializers for a given type
|
||||
* @Access access modifiers for the generated functions
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @Type type of list entry
|
||||
* @TypeNS namespace of serializer/deserializer functions for @Type
|
||||
* @TypeFini cleanup expression for a @Type
|
||||
* @ListMember name of the &struct list_head for this list in @Type
|
||||
* @HasLength %true if the binary representation of the list required a length field, %false if it
|
||||
* must not have a length field
|
||||
*
|
||||
* Defines two functions ``void NS##_serialize(SerializeCtx* ctx, const struct list_head* list)``
|
||||
* and ``bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list)`` for serialization and
|
||||
* deserialization of lists.
|
||||
*
|
||||
* For serialization, each field is serialized in order by calling ``TypeNS##_serialize``.
|
||||
*
|
||||
* For deserialization, each field is deserialized into a newly kmalloc()ed element by calling
|
||||
* ``TypeNS##_deserialize``. Correctly deserialized elements are appended to the provided
|
||||
* &struct list_head. If deserialization fails the expression ``TypeFini(entry)`` is evaluated for
|
||||
* each successfully deserialized element, ``list`` is left unchanged.
|
||||
*/
|
||||
#define SERDES_DEFINE_LIST_SERIALIZERS(Access, NS, Type, TypeNS, TypeFini, ListMember, HasLength) \
|
||||
__attribute__((unused)) \
|
||||
Access void NS##_serialize(SerializeCtx* ctx, const struct list_head* list) \
|
||||
{ \
|
||||
unsigned items = 0; \
|
||||
Type* item; \
|
||||
SerializeCtx ctxAtStart = *ctx; \
|
||||
if (HasLength) \
|
||||
Serialization_serializeUInt(ctx, 0); /* total field size */ \
|
||||
Serialization_serializeUInt(ctx, 0); /* number of elements */ \
|
||||
list_for_each_entry(item, list, ListMember) \
|
||||
{ \
|
||||
TypeNS##_serialize(ctx, item); \
|
||||
items += 1; \
|
||||
} \
|
||||
if (HasLength) \
|
||||
Serialization_serializeUInt(&ctxAtStart, ctx->length - ctxAtStart.length); \
|
||||
Serialization_serializeUInt(&ctxAtStart, items); \
|
||||
} \
|
||||
__attribute__((unused)) \
|
||||
Access bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list) \
|
||||
{ \
|
||||
DeserializeCtx innerCtx = {0, 0}; \
|
||||
DeserializeCtx* usedCtx = NULL; \
|
||||
unsigned items = 0; \
|
||||
LIST_HEAD(desItems); \
|
||||
\
|
||||
if (HasLength) { \
|
||||
if (!__Serialization_deserializeNestedField(ctx, &innerCtx)) \
|
||||
return false; \
|
||||
usedCtx = &innerCtx; \
|
||||
} else { \
|
||||
usedCtx = ctx; \
|
||||
} \
|
||||
if (!Serialization_deserializeUInt(usedCtx, &items)) \
|
||||
return false; \
|
||||
while (items-- > 0) \
|
||||
{ \
|
||||
Type* entry = kmalloc(sizeof(*entry), GFP_NOFS); \
|
||||
if (!entry) \
|
||||
goto err; \
|
||||
if (!TypeNS##_deserialize(usedCtx, entry)) \
|
||||
{ \
|
||||
kfree(entry); \
|
||||
goto err; \
|
||||
} \
|
||||
list_add_tail(&entry->ListMember, &desItems); \
|
||||
} \
|
||||
list_splice_tail(&desItems, list); \
|
||||
return true; \
|
||||
err: \
|
||||
BEEGFS_KFREE_LIST_DTOR(&desItems, Type, ListMember, TypeFini); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SERDES_DEFINE_ENUM_SERIALIZERS() - defines static inline serializers for an enum type with a
|
||||
* given underlying type.
|
||||
* @NS namespace prefix for the generated functions
|
||||
* @EnumTy full enum type
|
||||
* @Underlying underlying integer type of the enum
|
||||
* @SerdesSuffix suffix for the ``Serialization_`` functions that serialize the underlying type
|
||||
*/
|
||||
#define SERDES_DEFINE_ENUM_SERIALIZERS(NS, EnumTy, Underlying, SerdesSuffix) \
|
||||
static inline void NS##_serialize(SerializeCtx* ctx, EnumTy value) \
|
||||
{ \
|
||||
Serialization_serialize##SerdesSuffix(ctx, (Underlying) value); \
|
||||
} \
|
||||
static inline bool NS##_deserialize(DeserializeCtx* ctx, EnumTy* value) \
|
||||
{ \
|
||||
Underlying raw; \
|
||||
if (!Serialization_deserialize##SerdesSuffix(ctx, &raw)) \
|
||||
return false; \
|
||||
*value = (EnumTy) raw; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#endif /*SERIALIZATION_H_*/
|
||||
22
client_module/source/common/toolkit/SerializationTypes.h
Normal file
22
client_module/source/common/toolkit/SerializationTypes.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef common_toolkit_SerializationTypes_h_uxGn0NqFVyO6ma2TYHAEI
|
||||
#define common_toolkit_SerializationTypes_h_uxGn0NqFVyO6ma2TYHAEI
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
typedef struct SerializeCtx {
|
||||
char* const data;
|
||||
unsigned length;
|
||||
} SerializeCtx;
|
||||
|
||||
typedef struct DeserializeCtx {
|
||||
const char* data;
|
||||
size_t length;
|
||||
} DeserializeCtx;
|
||||
|
||||
typedef struct RawList {
|
||||
const char* data;
|
||||
unsigned length;
|
||||
unsigned elemCount;
|
||||
} RawList;
|
||||
|
||||
#endif
|
||||
235
client_module/source/common/toolkit/SocketTk.c
Normal file
235
client_module/source/common/toolkit/SocketTk.c
Normal file
@@ -0,0 +1,235 @@
|
||||
#include <common/toolkit/SocketTk.h>
|
||||
#include <common/net/sock/StandardSocket.h>
|
||||
#include <common/net/sock/RDMASocket.h>
|
||||
#include <common/Common.h>
|
||||
#include <common/toolkit/TimeTk.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
|
||||
struct file* SocketTkDummyFilp = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* One-time initialization of a dummy file pointer (required for polling)
|
||||
* Note: remember to call the corresponding uninit routine
|
||||
*/
|
||||
bool SocketTk_initOnce(void)
|
||||
{
|
||||
SocketTkDummyFilp = filp_open("/dev/null", O_RDONLY, 0);
|
||||
if(IS_ERR(SocketTkDummyFilp) )
|
||||
{
|
||||
printk_fhgfs(KERN_WARNING, "Failed to open the dummy filp for polling\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SocketTk_uninitOnce(void)
|
||||
{
|
||||
if(SocketTkDummyFilp && !IS_ERR(SocketTkDummyFilp) )
|
||||
filp_close(SocketTkDummyFilp, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Synchronous I/O multiplexing for standard and RDMA sockets.
|
||||
* Note: comparable to userspace poll()
|
||||
*
|
||||
* @param pollState list of sockets and event wishes
|
||||
* @return number of socks for which interesting events are available or negative linux error code.
|
||||
* (tvp is being set to time remaining)
|
||||
*/
|
||||
int SocketTk_poll(PollState* state, int timeoutMS)
|
||||
{
|
||||
struct poll_wqueues stdTable;
|
||||
poll_table* stdWait = NULL; // value NULL means "don't register for waiting"
|
||||
int table_err = 0;
|
||||
int numSocksWithREvents = 0; // the return value
|
||||
Socket* socket;
|
||||
|
||||
long __timeout = TimeTk_msToJiffiesSchedulable(timeoutMS);
|
||||
|
||||
/* 4.19 (vanilla, not stable) had a bug in the sock_poll_wait signature. rhel 4.18 backports
|
||||
* this bug. 4.19.1 fixes it again. */
|
||||
BUILD_BUG_ON(__builtin_types_compatible_p(
|
||||
__typeof__(&sock_poll_wait),
|
||||
void (*)(struct file*, poll_table*)));
|
||||
|
||||
poll_initwait(&stdTable);
|
||||
|
||||
if(__timeout)
|
||||
stdWait = &stdTable.pt;
|
||||
|
||||
// 1st loop: register the socks that we're waiting for and wait blocking
|
||||
// if no data is available yet
|
||||
// 2nd loop (after event or timeout): check all socks for available data
|
||||
// note: std socks return all events, even those we haven't been waiting for
|
||||
// 3rd and futher loops: in case an uninteresting event occurred
|
||||
for( ; ; )
|
||||
{
|
||||
numSocksWithREvents = 0; // (must be inside the loop to be consistent)
|
||||
|
||||
/* wait INTERRUPTIBLE if no signal is pending, otherwise the wait contributes to load.
|
||||
* users of this function should be migrated to use socket callbacks instead. */
|
||||
set_current_state(signal_pending(current) ? TASK_KILLABLE : TASK_INTERRUPTIBLE);
|
||||
|
||||
// for each sock: ask for available data and register waitqueue
|
||||
list_for_each_entry(socket, &state->list, poll._list)
|
||||
{
|
||||
if(Socket_getSockType(socket) == NICADDRTYPE_RDMA)
|
||||
{ // RDMA socket
|
||||
struct RDMASocket* currentRDMASock = (RDMASocket*)socket;
|
||||
bool finishPoll = (numSocksWithREvents || !__timeout);
|
||||
|
||||
unsigned long mask = RDMASocket_poll(
|
||||
currentRDMASock, socket->poll._events, finishPoll);
|
||||
|
||||
if(mask)
|
||||
{ // interesting event occurred
|
||||
socket->poll.revents = mask; // save event mask as revents
|
||||
numSocksWithREvents++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Standard socket
|
||||
struct socket* currentRawSock =
|
||||
StandardSocket_getRawSock( (StandardSocket*)socket);
|
||||
poll_table* currentStdWait = numSocksWithREvents ? NULL : stdWait;
|
||||
|
||||
unsigned long mask = (*currentRawSock->ops->poll)(
|
||||
SocketTkDummyFilp, currentRawSock, currentStdWait);
|
||||
|
||||
if(mask & (socket->poll._events | POLLERR | POLLHUP | POLLNVAL) )
|
||||
{ // interesting event occurred
|
||||
socket->poll.revents = mask; // save event mask as revents
|
||||
numSocksWithREvents++;
|
||||
}
|
||||
|
||||
//cond_resched(); // (commented out for latency reasons)
|
||||
}
|
||||
} // end of for_each_socket loop
|
||||
|
||||
stdWait = NULL; // don't register standard socks for waiting in following loops
|
||||
|
||||
// skip the waiting if we already found something
|
||||
if (numSocksWithREvents || !__timeout || fatal_signal_pending(current))
|
||||
break;
|
||||
|
||||
// skip the waiting if we have an error
|
||||
if(unlikely(stdTable.error) )
|
||||
{
|
||||
table_err = stdTable.error;
|
||||
break;
|
||||
}
|
||||
|
||||
// wait (and reduce remaining timeout)
|
||||
__timeout = schedule_timeout(__timeout);
|
||||
|
||||
} // end of sleep loop
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
// cleanup loop for RDMA socks
|
||||
list_for_each_entry(socket, &state->list, poll._list)
|
||||
{
|
||||
if(Socket_getSockType(socket) == NICADDRTYPE_RDMA)
|
||||
{
|
||||
struct RDMASocket* currentRDMASock = (RDMASocket*)socket;
|
||||
RDMASocket_poll(currentRDMASock, socket->poll._events, true);
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup for standard socks
|
||||
poll_freewait(&stdTable);
|
||||
|
||||
//printk_fhgfs(KERN_INFO, "%s:%d: return %d\n", __func__, __LINE__,
|
||||
// table_err ? table_err : numSocksWithREvents); // debug in
|
||||
|
||||
return table_err ? table_err : numSocksWithREvents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note: Old kernel versions do not support validation of the IP string.
|
||||
*
|
||||
* @param outIPAddr set to INADDR_NONE if an error was detected
|
||||
* @return false for wrong input on modern kernels (>= 2.6.20), old kernels always return
|
||||
* true
|
||||
*/
|
||||
bool SocketTk_getHostByAddrStr(const char* hostAddr, struct in_addr* outIPAddr)
|
||||
{
|
||||
if(unlikely(!in4_pton(hostAddr, strlen(hostAddr), (u8 *)outIPAddr, -1, NULL) ) )
|
||||
{ // not a valid address string
|
||||
outIPAddr->s_addr = INADDR_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Better use SocketTk_getHostByAddrStr(), which can also check for errors on recent kernels.
|
||||
*
|
||||
* @return INADDR_NONE if an error was detected (recent kernels only)
|
||||
*/
|
||||
struct in_addr SocketTk_in_aton(const char* hostAddr)
|
||||
{
|
||||
struct in_addr retVal;
|
||||
|
||||
// Note: retVal INADDR_NONE will be set by getHostByAddrStr()
|
||||
|
||||
SocketTk_getHostByAddrStr(hostAddr, &retVal);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buf the buffer to which <IP> should be written.
|
||||
*/
|
||||
void SocketTk_ipaddrToStrNoAlloc(struct in_addr ipaddress, char* ipStr, size_t ipStrLen)
|
||||
{
|
||||
int printRes = snprintf(ipStr, ipStrLen, "%pI4", &ipaddress);
|
||||
if(unlikely( (size_t)printRes >= ipStrLen) )
|
||||
ipStr[ipStrLen-1] = 0; // ipStrLen exceeded => zero-terminate result
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string is kalloced and needs to be kfreed
|
||||
*/
|
||||
char* SocketTk_ipaddrToStr(struct in_addr ipaddress)
|
||||
{
|
||||
char* ipStr = os_kmalloc(SOCKETTK_IPADDRSTR_LEN);
|
||||
if (likely(ipStr != NULL))
|
||||
SocketTk_ipaddrToStrNoAlloc(ipaddress, ipStr, SOCKETTK_IPADDRSTR_LEN);
|
||||
return ipStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buf the buffer to which <IP>:<port> should be written.
|
||||
*/
|
||||
void SocketTk_endpointAddrToStrNoAlloc(char* buf, size_t bufLen, struct in_addr ipaddress,
|
||||
unsigned short port)
|
||||
{
|
||||
int printRes = snprintf(buf, bufLen, "%pI4:%u", &ipaddress, port);
|
||||
if(unlikely( (unsigned)printRes >= bufLen) )
|
||||
buf[bufLen-1] = 0; // bufLen exceeded => zero-terminate result
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string is kalloced and needs to be kfreed
|
||||
*/
|
||||
char* SocketTk_endpointAddrToStr(struct in_addr ipaddress, unsigned short port)
|
||||
{
|
||||
char* endpointStr = os_kmalloc(SOCKETTK_ENDPOINTSTR_LEN);
|
||||
if (likely(endpointStr != NULL))
|
||||
SocketTk_endpointAddrToStrNoAlloc(endpointStr, SOCKETTK_ENDPOINTSTR_LEN, ipaddress, port);
|
||||
return endpointStr;
|
||||
}
|
||||
|
||||
|
||||
49
client_module/source/common/toolkit/SocketTk.h
Normal file
49
client_module/source/common/toolkit/SocketTk.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef OPEN_SOCKETTK_H_
|
||||
#define OPEN_SOCKETTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/net/sock/Socket.h>
|
||||
#include <common/toolkit/Time.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#define SOCKETTK_ENDPOINTSTR_LEN SOCKET_PEERNAME_LEN // size for _endpointAddrToStrNoAlloc()
|
||||
#define SOCKETTK_IPADDRSTR_LEN (4*4)
|
||||
|
||||
// forward declarations
|
||||
struct PollState;
|
||||
typedef struct PollState PollState;
|
||||
|
||||
|
||||
extern bool SocketTk_initOnce(void);
|
||||
extern void SocketTk_uninitOnce(void);
|
||||
|
||||
extern int SocketTk_poll(PollState* state, int timeoutMS);
|
||||
|
||||
extern bool SocketTk_getHostByAddrStr(const char* hostAddr, struct in_addr* outIPAddr);
|
||||
extern struct in_addr SocketTk_in_aton(const char* hostAddr);
|
||||
|
||||
extern char* SocketTk_ipaddrToStr(struct in_addr ipaddress);
|
||||
extern void SocketTk_ipaddrToStrNoAlloc(struct in_addr ipaddress, char* ipStr, size_t ipStrLen);
|
||||
extern char* SocketTk_endpointAddrToStr(struct in_addr ipaddress, unsigned short port);
|
||||
extern void SocketTk_endpointAddrToStrNoAlloc(char* buf, size_t bufLen,
|
||||
struct in_addr ipaddress, unsigned short port);
|
||||
|
||||
|
||||
struct PollState
|
||||
{
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static inline void PollState_init(PollState* state)
|
||||
{
|
||||
INIT_LIST_HEAD(&state->list);
|
||||
}
|
||||
|
||||
static inline void PollState_addSocket(PollState* state, Socket* socket, short events)
|
||||
{
|
||||
list_add_tail(&socket->poll._list, &state->list);
|
||||
socket->poll._events = events;
|
||||
socket->poll.revents = 0;
|
||||
}
|
||||
|
||||
#endif /*OPEN_SOCKETTK_H_*/
|
||||
125
client_module/source/common/toolkit/StringTk.c
Normal file
125
client_module/source/common/toolkit/StringTk.c
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <common/toolkit/StringTk.h>
|
||||
#include <common/Common.h>
|
||||
|
||||
|
||||
void StringTk_explode(const char* s, char delimiter, StrCpyList* outList)
|
||||
{
|
||||
ssize_t sLen = strlen(s);
|
||||
ssize_t lastPos = (strlen(s) && (s[0] == delimiter) ) ? 0 : -1;
|
||||
ssize_t currentPos;
|
||||
char* findRes;
|
||||
ssize_t newElemLen;
|
||||
|
||||
// note: starts at pos 1 because an occurence at pos 0 would lead to an empty string,
|
||||
// which would be ignored anyways
|
||||
// note: i think the initialization of currentPos here is useless
|
||||
for(currentPos = 1; ; )
|
||||
{
|
||||
findRes = strchr(&s[lastPos+1], delimiter);
|
||||
|
||||
if(!findRes)
|
||||
{
|
||||
ssize_t restLen = sLen - (lastPos+1);
|
||||
|
||||
if(restLen)
|
||||
{ // add rest
|
||||
char* newElem = StringTk_subStr(&s[lastPos+1], restLen);
|
||||
|
||||
StrCpyList_append(outList, newElem);
|
||||
kfree(newElem);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
currentPos = findRes - s;
|
||||
|
||||
// add substring to outList (leave the delimiter positions out)
|
||||
newElemLen = currentPos-lastPos-1; // -1=last delimiter
|
||||
if(newElemLen)
|
||||
{
|
||||
char* newElem = StringTk_subStr(&s[lastPos+1], newElemLen);
|
||||
|
||||
StrCpyList_append(outList, newElem);
|
||||
kfree(newElem);
|
||||
}
|
||||
|
||||
lastPos = currentPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool StringTk_strToBool(const char* s)
|
||||
{
|
||||
if( !StringTk_hasLength(s) ||
|
||||
!strcmp(s, "1") ||
|
||||
!strcasecmp(s, "y") ||
|
||||
!strcasecmp(s, "on") ||
|
||||
!strcasecmp(s, "yes") ||
|
||||
!strcasecmp(s, "true") )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string is kmalloc'ed and has to be kfree'd by the caller
|
||||
*/
|
||||
char* StringTk_trimCopy(const char* s)
|
||||
{
|
||||
int lastRight;
|
||||
int firstLeft;
|
||||
int sLen;
|
||||
|
||||
sLen = strlen(s);
|
||||
|
||||
firstLeft = 0;
|
||||
while( (firstLeft < sLen) &&
|
||||
(s[firstLeft]==' ' || s[firstLeft]=='\n' || s[firstLeft]=='\r' || s[firstLeft]=='\t') )
|
||||
firstLeft++;
|
||||
|
||||
if(firstLeft == sLen)
|
||||
return StringTk_strDup(""); // the string is empty or contains only space chars
|
||||
|
||||
// the string contains at least one non-space char
|
||||
|
||||
lastRight = sLen - 1;
|
||||
while(s[lastRight]==' ' || s[lastRight]=='\n' || s[lastRight]=='\r' || s[lastRight]=='\t')
|
||||
lastRight--;
|
||||
|
||||
return StringTk_subStr(&s[firstLeft], lastRight - firstLeft + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Provided, because old kernels don't provide kasprintf().
|
||||
*
|
||||
* @return will be kalloced and needs to be kfree'd by the caller
|
||||
*/
|
||||
char* StringTk_kasprintf(const char *fmt, ...)
|
||||
{
|
||||
char* printStr;
|
||||
int printLen;
|
||||
char tmpChar; // (old kernels don't seem to be able to handle vsnprintf(NULL, 0, ...) )
|
||||
va_list ap;
|
||||
va_list apCopy; // kasprintf uses this
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
va_copy(apCopy, ap);
|
||||
|
||||
printLen = vsnprintf(&tmpChar, 1, fmt, apCopy);
|
||||
|
||||
va_end(apCopy);
|
||||
|
||||
printStr = os_kmalloc(printLen + 1);
|
||||
if(likely(printStr) )
|
||||
{
|
||||
vsnprintf(printStr, printLen + 1, fmt, ap);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return printStr;
|
||||
}
|
||||
|
||||
101
client_module/source/common/toolkit/StringTk.h
Normal file
101
client_module/source/common/toolkit/StringTk.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef OPEN_STRINGTK_H_
|
||||
#define OPEN_STRINGTK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/toolkit/list/StrCpyList.h>
|
||||
|
||||
|
||||
// manipulation
|
||||
extern void StringTk_explode(const char* s, char delimiter, StrCpyList* outList);
|
||||
static inline char* StringTk_strncpyTerminated(char* dest, const char* src, size_t count);
|
||||
|
||||
// numerical
|
||||
static inline int StringTk_strToInt(const char* s);
|
||||
static inline unsigned StringTk_strToUInt(const char* s);
|
||||
static inline uint64_t StringTk_strToUInt64(const char* s);
|
||||
extern bool StringTk_strToBool(const char* s);
|
||||
|
||||
// construction
|
||||
static inline char* StringTk_strDup(const char* s);
|
||||
|
||||
static inline char* StringTk_subStr(const char* start, unsigned numChars);
|
||||
extern char* StringTk_trimCopy(const char* s);
|
||||
extern char* StringTk_kasprintf(const char *fmt, ...);
|
||||
|
||||
static inline char* StringTk_intToStr(int a);
|
||||
static inline char* StringTk_uintToStr(unsigned a);
|
||||
|
||||
// inliners
|
||||
static inline bool StringTk_hasLength(const char* s);
|
||||
|
||||
|
||||
|
||||
bool StringTk_hasLength(const char* s)
|
||||
{
|
||||
return s[0] ? true : false;
|
||||
}
|
||||
|
||||
|
||||
char* StringTk_strncpyTerminated(char* dest, const char* src, size_t count)
|
||||
{
|
||||
// Note: The problem with strncpy() is that dest is not guaranteed to be zero-terminated.
|
||||
// strlcpy() does guarantee that.
|
||||
// strlcpy() was removed in commit d26270061ae6 (string: Remove strlcpy()), use strscpy() instead.
|
||||
|
||||
strscpy(dest, src, count);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int StringTk_strToInt(const char* s)
|
||||
{
|
||||
return (int)simple_strtol(s, NULL, 10);
|
||||
}
|
||||
|
||||
unsigned StringTk_strToUInt(const char* s)
|
||||
{
|
||||
return (unsigned)simple_strtoul(s, NULL, 10);
|
||||
}
|
||||
|
||||
uint64_t StringTk_strToUInt64(const char* s)
|
||||
{
|
||||
return simple_strtoull(s, NULL, 10);
|
||||
}
|
||||
|
||||
char* StringTk_strDup(const char* s)
|
||||
{
|
||||
return kstrdup(s, GFP_NOFS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string is kmalloc'ed and has to be kfree'd by the caller
|
||||
*/
|
||||
char* StringTk_subStr(const char* start, unsigned numChars)
|
||||
{
|
||||
char* subStr = (char*)os_kmalloc(numChars+1);
|
||||
|
||||
if(numChars)
|
||||
memcpy(subStr, start, numChars);
|
||||
|
||||
subStr[numChars] = 0;
|
||||
|
||||
return subStr;
|
||||
}
|
||||
|
||||
char* StringTk_intToStr(int a)
|
||||
{
|
||||
char aStr[24];
|
||||
sprintf(aStr, "%d", a);
|
||||
|
||||
return StringTk_strDup(aStr);
|
||||
}
|
||||
|
||||
char* StringTk_uintToStr(unsigned a)
|
||||
{
|
||||
char aStr[24];
|
||||
sprintf(aStr, "%u", a);
|
||||
|
||||
return StringTk_strDup(aStr);
|
||||
}
|
||||
|
||||
#endif /*OPEN_STRINGTK_H_*/
|
||||
52
client_module/source/common/toolkit/SynchronizedCounter.h
Normal file
52
client_module/source/common/toolkit/SynchronizedCounter.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef SYNCHRONIZEDCOUNTER_H_
|
||||
#define SYNCHRONIZEDCOUNTER_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/threading/Mutex.h>
|
||||
#include <common/threading/Condition.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
struct SynchronizedCounter;
|
||||
typedef struct SynchronizedCounter SynchronizedCounter;
|
||||
|
||||
static inline void SynchronizedCounter_init(SynchronizedCounter* this);
|
||||
|
||||
// inliners
|
||||
static inline void SynchronizedCounter_waitForCount(SynchronizedCounter* this, int waitCount);
|
||||
static inline void SynchronizedCounter_incCount(SynchronizedCounter* this);
|
||||
static inline void SynchronizedCounter_incCountBy(SynchronizedCounter* this, int count);
|
||||
|
||||
|
||||
struct SynchronizedCounter
|
||||
{
|
||||
atomic_t count;
|
||||
|
||||
struct completion barrier;
|
||||
};
|
||||
|
||||
|
||||
void SynchronizedCounter_init(SynchronizedCounter* this)
|
||||
{
|
||||
atomic_set(&this->count, 0);
|
||||
init_completion(&this->barrier);
|
||||
}
|
||||
|
||||
void SynchronizedCounter_waitForCount(SynchronizedCounter* this, int waitCount)
|
||||
{
|
||||
SynchronizedCounter_incCountBy(this, -waitCount);
|
||||
wait_for_completion(&this->barrier);
|
||||
}
|
||||
|
||||
void SynchronizedCounter_incCount(SynchronizedCounter* this)
|
||||
{
|
||||
SynchronizedCounter_incCountBy(this, 1);
|
||||
}
|
||||
|
||||
void SynchronizedCounter_incCountBy(SynchronizedCounter* this, int count)
|
||||
{
|
||||
if (atomic_add_return(count, &this->count) == 0)
|
||||
complete(&this->barrier);
|
||||
}
|
||||
|
||||
#endif /*SYNCHRONIZEDCOUNTER_H_*/
|
||||
122
client_module/source/common/toolkit/Time.h
Normal file
122
client_module/source/common/toolkit/Time.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef OPEN_TIME_H_
|
||||
#define OPEN_TIME_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The basis for this Time class is a monotonic clock.
|
||||
*/
|
||||
#ifdef KERNEL_HAS_64BIT_TIMESTAMPS
|
||||
typedef struct timespec64 Time;
|
||||
#else
|
||||
typedef struct timespec Time;
|
||||
#endif
|
||||
|
||||
|
||||
static inline unsigned Time_elapsedSinceMS(Time* this, Time* earlierT);
|
||||
static inline unsigned long long Time_elapsedSinceNS(Time* this, Time* earlierT);
|
||||
static inline unsigned Time_elapsedMS(Time* this);
|
||||
static inline int Time_compare(Time* this, Time* o);
|
||||
static inline unsigned long long Time_toNS(Time* this);
|
||||
|
||||
static inline void Time_setToNow(Time* this)
|
||||
{
|
||||
#ifdef KERNEL_HAS_KTIME_GET_TS64
|
||||
ktime_get_ts64(this);
|
||||
#else
|
||||
ktime_get_ts(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time to to "real" time, i.e. get the time from a non-monotonic clock.
|
||||
*/
|
||||
static inline void Time_setToNowReal(Time *this)
|
||||
{
|
||||
#ifdef KERNEL_HAS_KTIME_GET_REAL_TS64
|
||||
ktime_get_real_ts64(this);
|
||||
#else
|
||||
ktime_get_real_ts(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void Time_setZero(Time *this)
|
||||
{
|
||||
this->tv_sec = 0;
|
||||
this->tv_nsec = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set to current time.
|
||||
*/
|
||||
static inline void Time_init(Time* this)
|
||||
{
|
||||
Time_setToNow(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time values to zero, e.g. to mark this time as unitialized or far back in the past.
|
||||
*/
|
||||
static inline void Time_initZero(Time* this)
|
||||
{
|
||||
Time_setZero(this);
|
||||
}
|
||||
|
||||
static inline bool Time_getIsZero(Time* this)
|
||||
{
|
||||
return (!this->tv_sec && !this->tv_sec);
|
||||
}
|
||||
|
||||
static inline unsigned Time_elapsedSinceMS(Time* this, Time* earlierT)
|
||||
{
|
||||
unsigned secs = (this->tv_sec - earlierT->tv_sec) * 1000;
|
||||
int micros = (this->tv_nsec - earlierT->tv_nsec) / 1000000; /* can also be negative,
|
||||
so this must be signed */
|
||||
|
||||
return secs + micros;
|
||||
}
|
||||
|
||||
unsigned long long Time_elapsedSinceNS(Time* this, Time* earlierT)
|
||||
{
|
||||
unsigned long long secs = (this->tv_sec - earlierT->tv_sec) * 1000000000ull;
|
||||
long nanos = (this->tv_nsec - earlierT->tv_nsec); /* can also be negative,
|
||||
so this must be signed */
|
||||
|
||||
return secs + nanos;
|
||||
}
|
||||
|
||||
unsigned long long Time_toNS(Time* this)
|
||||
{
|
||||
return this->tv_sec * 1000000000ull + this->tv_nsec;
|
||||
}
|
||||
|
||||
int Time_compare(Time* this, Time* o)
|
||||
{
|
||||
long long diff = Time_toNS(this) - Time_toNS(o);
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
else if (diff > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Time_elapsedMS(Time* this)
|
||||
{
|
||||
unsigned elapsedMS;
|
||||
|
||||
Time currentT;
|
||||
Time_init(¤tT);
|
||||
|
||||
elapsedMS = Time_elapsedSinceMS(¤tT, this);
|
||||
|
||||
return elapsedMS;
|
||||
}
|
||||
|
||||
#endif /* OPEN_TIME_H_ */
|
||||
21
client_module/source/common/toolkit/TimeTk.h
Normal file
21
client_module/source/common/toolkit/TimeTk.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef TIMETK_H_
|
||||
#define TIMETK_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
|
||||
static inline long TimeTk_msToJiffiesSchedulable(unsigned ms);
|
||||
|
||||
|
||||
|
||||
long TimeTk_msToJiffiesSchedulable(unsigned ms)
|
||||
{
|
||||
unsigned long resultJiffies = msecs_to_jiffies(ms);
|
||||
|
||||
return (resultJiffies >= MAX_SCHEDULE_TIMEOUT) ? (MAX_SCHEDULE_TIMEOUT-1) : resultJiffies;
|
||||
}
|
||||
|
||||
|
||||
#endif /*TIMETK_H_*/
|
||||
20
client_module/source/common/toolkit/ackstore/AckStoreMap.c
Normal file
20
client_module/source/common/toolkit/ackstore/AckStoreMap.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "AckStoreMap.h"
|
||||
#include "AckStoreMapIter.h"
|
||||
|
||||
AckStoreMapIter AckStoreMap_find(AckStoreMap* this, const char* searchKey)
|
||||
{
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
|
||||
|
||||
AckStoreMapIter iter;
|
||||
AckStoreMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
int compareAckStoreMapElems(const void* key1, const void* key2)
|
||||
{
|
||||
return strcmp(key1, key2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
117
client_module/source/common/toolkit/ackstore/AckStoreMap.h
Normal file
117
client_module/source/common/toolkit/ackstore/AckStoreMap.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifndef ACKSTOREMAP_H_
|
||||
#define ACKSTOREMAP_H_
|
||||
|
||||
#include <common/toolkit/tree/PointerRBTree.h>
|
||||
#include <common/toolkit/tree/PointerRBTreeIter.h>
|
||||
#include "WaitAckMap.h"
|
||||
|
||||
|
||||
struct AckStoreEntry;
|
||||
typedef struct AckStoreEntry AckStoreEntry;
|
||||
|
||||
|
||||
struct AckStoreMapElem;
|
||||
typedef struct AckStoreMapElem AckStoreMapElem;
|
||||
struct AckStoreMap;
|
||||
typedef struct AckStoreMap AckStoreMap;
|
||||
|
||||
struct AckStoreMapIter; // forward declaration of the iterator
|
||||
|
||||
|
||||
static inline void AckStoreEntry_init(AckStoreEntry* this, char* ackID,
|
||||
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier);
|
||||
static inline AckStoreEntry* AckStoreEntry_construct(char* ackID,
|
||||
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier);
|
||||
static inline void AckStoreEntry_destruct(AckStoreEntry* this);
|
||||
|
||||
|
||||
static inline void AckStoreMap_init(AckStoreMap* this);
|
||||
static inline void AckStoreMap_uninit(AckStoreMap* this);
|
||||
|
||||
static inline bool AckStoreMap_insert(AckStoreMap* this, char* newKey,
|
||||
AckStoreEntry* newValue);
|
||||
static inline bool AckStoreMap_erase(AckStoreMap* this, const char* eraseKey);
|
||||
|
||||
extern struct AckStoreMapIter AckStoreMap_find(AckStoreMap* this, const char* searchKey);
|
||||
|
||||
extern int compareAckStoreMapElems(const void* key1, const void* key2);
|
||||
|
||||
|
||||
struct AckStoreEntry
|
||||
{
|
||||
char* ackID;
|
||||
|
||||
WaitAckMap* waitMap; // ack will be removed from this map if it is received
|
||||
WaitAckMap* receivedMap; // ack will be added to this map if it is received
|
||||
|
||||
WaitAckNotification* notifier;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct AckStoreMapElem
|
||||
{
|
||||
RBTreeElem rbTreeElem;
|
||||
};
|
||||
|
||||
struct AckStoreMap
|
||||
{
|
||||
RBTree rbTree;
|
||||
};
|
||||
|
||||
|
||||
void AckStoreEntry_init(AckStoreEntry* this, char* ackID,
|
||||
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier)
|
||||
{
|
||||
this->ackID = ackID;
|
||||
this->waitMap = waitMap;
|
||||
this->receivedMap = receivedMap;
|
||||
this->notifier = notifier;
|
||||
}
|
||||
|
||||
AckStoreEntry* AckStoreEntry_construct(char* ackID,
|
||||
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier)
|
||||
{
|
||||
AckStoreEntry* this = (AckStoreEntry*)os_kmalloc(sizeof(*this) );
|
||||
|
||||
AckStoreEntry_init(this, ackID, waitMap, receivedMap, notifier);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void AckStoreEntry_destruct(AckStoreEntry* this)
|
||||
{
|
||||
kfree(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AckStoreMap_init(AckStoreMap* this)
|
||||
{
|
||||
PointerRBTree_init( (RBTree*)this, compareAckStoreMapElems);
|
||||
}
|
||||
|
||||
void AckStoreMap_uninit(AckStoreMap* this)
|
||||
{
|
||||
PointerRBTree_uninit( (RBTree*)this);
|
||||
}
|
||||
|
||||
bool AckStoreMap_insert(AckStoreMap* this, char* newKey, AckStoreEntry* newValue)
|
||||
{
|
||||
bool insRes;
|
||||
|
||||
insRes = PointerRBTree_insert( (RBTree*)this, newKey, newValue);
|
||||
if(!insRes)
|
||||
{
|
||||
// not inserted because the key already existed
|
||||
}
|
||||
|
||||
return insRes;
|
||||
}
|
||||
|
||||
bool AckStoreMap_erase(AckStoreMap* this, const char* eraseKey)
|
||||
{
|
||||
return PointerRBTree_erase( (RBTree*)this, eraseKey);
|
||||
}
|
||||
|
||||
#endif /* ACKSTOREMAP_H_ */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef ACKSTOREMAPITER_H_
|
||||
#define ACKSTOREMAPITER_H_
|
||||
|
||||
#include "AckStoreMap.h"
|
||||
|
||||
struct AckStoreMapIter;
|
||||
typedef struct AckStoreMapIter AckStoreMapIter;
|
||||
|
||||
static inline void AckStoreMapIter_init(AckStoreMapIter* this, AckStoreMap* map, RBTreeElem* treeElem);
|
||||
static inline AckStoreEntry* AckStoreMapIter_value(AckStoreMapIter* this);
|
||||
static inline bool AckStoreMapIter_end(AckStoreMapIter* this);
|
||||
|
||||
struct AckStoreMapIter
|
||||
{
|
||||
RBTreeIter rbTreeIter;
|
||||
};
|
||||
|
||||
void AckStoreMapIter_init(AckStoreMapIter* this, AckStoreMap* map, RBTreeElem* treeElem)
|
||||
{
|
||||
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
|
||||
}
|
||||
|
||||
AckStoreEntry* AckStoreMapIter_value(AckStoreMapIter* this)
|
||||
{
|
||||
return (AckStoreEntry*)PointerRBTreeIter_value( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
bool AckStoreMapIter_end(AckStoreMapIter* this)
|
||||
{
|
||||
return PointerRBTreeIter_end( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* ACKSTOREMAPITER_H_ */
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "AcknowledgmentStore.h"
|
||||
|
||||
/**
|
||||
* Note: This method does not lock the notifier->waitAcksMutex, because this is typically
|
||||
* called from a context that does not yet require syncing.
|
||||
*
|
||||
* @param waitAcks do not access this map until you called unregister (for thread-safety)
|
||||
* @param receivedAcks do not access this map until you called unregister (for thread-safety)
|
||||
* @param notifier used to wake up the thread waiting for acks
|
||||
*/
|
||||
void AcknowledgmentStore_registerWaitAcks(AcknowledgmentStore* this,
|
||||
WaitAckMap* waitAcks, WaitAckMap* receivedAcks, WaitAckNotification* notifier)
|
||||
{
|
||||
WaitAckMapIter iter;
|
||||
|
||||
Mutex_lock(&this->mutex);
|
||||
|
||||
for(iter = WaitAckMap_begin(waitAcks); !WaitAckMapIter_end(&iter); WaitAckMapIter_next(&iter) )
|
||||
{
|
||||
WaitAck* currentWaitAck = WaitAckMapIter_value(&iter);
|
||||
|
||||
AckStoreEntry* newStoreEntry = AckStoreEntry_construct(
|
||||
currentWaitAck->ackID, waitAcks, receivedAcks, notifier);
|
||||
|
||||
AckStoreMap_insert(&this->storeMap, currentWaitAck->ackID, newStoreEntry);
|
||||
}
|
||||
|
||||
Mutex_unlock(&this->mutex);
|
||||
}
|
||||
|
||||
void AcknowledgmentStore_unregisterWaitAcks(AcknowledgmentStore* this, WaitAckMap* waitAcks)
|
||||
{
|
||||
WaitAckMapIter iter;
|
||||
|
||||
Mutex_lock(&this->mutex);
|
||||
|
||||
for(iter = WaitAckMap_begin(waitAcks); !WaitAckMapIter_end(&iter); WaitAckMapIter_next(&iter) )
|
||||
{
|
||||
char* currentKey = WaitAckMapIter_key(&iter);
|
||||
AckStoreMapIter storeIter = AckStoreMap_find(&this->storeMap, currentKey);
|
||||
|
||||
// free allocated entry and remove it from store map
|
||||
|
||||
AckStoreEntry_destruct(AckStoreMapIter_value(&storeIter) );
|
||||
AckStoreMap_erase(&this->storeMap, currentKey);
|
||||
}
|
||||
|
||||
Mutex_unlock(&this->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if someone was waiting for this ackID, false otherwise
|
||||
*/
|
||||
bool AcknowledgmentStore_receivedAck(AcknowledgmentStore* this, const char* ackID)
|
||||
{
|
||||
bool retVal = false;
|
||||
AckStoreMapIter storeIter;
|
||||
|
||||
Mutex_lock(&this->mutex); // L O C K (store)
|
||||
|
||||
storeIter = AckStoreMap_find(&this->storeMap, ackID);
|
||||
if(!AckStoreMapIter_end(&storeIter) )
|
||||
{ // ack entry exists in store
|
||||
WaitAckMapIter waitIter;
|
||||
AckStoreEntry* storeEntry = AckStoreMapIter_value(&storeIter);
|
||||
|
||||
Mutex_lock(&storeEntry->notifier->waitAcksMutex); // L O C K (notifier)
|
||||
|
||||
waitIter = WaitAckMap_find(storeEntry->waitMap, ackID);
|
||||
if(!WaitAckMapIter_end(&waitIter) )
|
||||
{ // entry exists in waitMap => move to receivedMap
|
||||
char* waitAckID = WaitAckMapIter_key(&waitIter);
|
||||
WaitAck* waitAck = WaitAckMapIter_value(&waitIter);
|
||||
|
||||
WaitAckMap_insert(storeEntry->receivedMap, waitAckID, waitAck);
|
||||
WaitAckMap_erase(storeEntry->waitMap, ackID);
|
||||
|
||||
if(!WaitAckMap_length(storeEntry->waitMap) )
|
||||
{ // all acks received => notify
|
||||
WaitAckNotification* notifier = storeEntry->notifier;
|
||||
|
||||
Condition_broadcast(¬ifier->waitAcksCompleteCond);
|
||||
}
|
||||
|
||||
retVal = true;
|
||||
}
|
||||
|
||||
Mutex_unlock(&storeEntry->notifier->waitAcksMutex); // U N L O C K (notifier)
|
||||
|
||||
|
||||
AckStoreEntry_destruct(storeEntry);
|
||||
AckStoreMap_erase(&this->storeMap, ackID);
|
||||
}
|
||||
|
||||
Mutex_unlock(&this->mutex); // U N L O C K (store)
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
bool AcknowledgmentStore_waitForAckCompletion(AcknowledgmentStore* this,
|
||||
WaitAckMap* waitAcks, WaitAckNotification* notifier, int timeoutMS)
|
||||
{
|
||||
bool retVal;
|
||||
|
||||
Mutex_lock(¬ifier->waitAcksMutex);
|
||||
|
||||
if(WaitAckMap_length(waitAcks) )
|
||||
Condition_timedwait(¬ifier->waitAcksCompleteCond, ¬ifier->waitAcksMutex, timeoutMS);
|
||||
|
||||
retVal = WaitAckMap_length(waitAcks) ? false : true;
|
||||
|
||||
Mutex_unlock(¬ifier->waitAcksMutex);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef ACKNOWLEDGMENTSTORE_H_
|
||||
#define ACKNOWLEDGMENTSTORE_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/threading/Mutex.h>
|
||||
#include <common/threading/Condition.h>
|
||||
#include "AckStoreMap.h"
|
||||
#include "AckStoreMapIter.h"
|
||||
#include "WaitAckMap.h"
|
||||
#include "WaitAckMapIter.h"
|
||||
|
||||
|
||||
struct AcknowledgmentStore;
|
||||
typedef struct AcknowledgmentStore AcknowledgmentStore;
|
||||
|
||||
static inline void AcknowledgmentStore_init(AcknowledgmentStore* this);
|
||||
static inline AcknowledgmentStore* AcknowledgmentStore_construct(void);
|
||||
static inline void AcknowledgmentStore_uninit(AcknowledgmentStore* this);
|
||||
static inline void AcknowledgmentStore_destruct(AcknowledgmentStore* this);
|
||||
|
||||
extern void AcknowledgmentStore_registerWaitAcks(AcknowledgmentStore* this,
|
||||
WaitAckMap* waitAcks, WaitAckMap* receivedAcks, WaitAckNotification* notifier);
|
||||
extern void AcknowledgmentStore_unregisterWaitAcks(AcknowledgmentStore* this, WaitAckMap* waitAcks);
|
||||
extern bool AcknowledgmentStore_receivedAck(AcknowledgmentStore* this, const char* ackID);
|
||||
extern bool AcknowledgmentStore_waitForAckCompletion(AcknowledgmentStore* this,
|
||||
WaitAckMap* waitAcks, WaitAckNotification* notifier, int timeoutMS);
|
||||
|
||||
|
||||
|
||||
struct AcknowledgmentStore
|
||||
{
|
||||
AckStoreMap storeMap;
|
||||
Mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
void AcknowledgmentStore_init(AcknowledgmentStore* this)
|
||||
{
|
||||
AckStoreMap_init(&this->storeMap);
|
||||
Mutex_init(&this->mutex);
|
||||
}
|
||||
|
||||
AcknowledgmentStore* AcknowledgmentStore_construct(void)
|
||||
{
|
||||
AcknowledgmentStore* this = (AcknowledgmentStore*)os_kmalloc(sizeof(*this) );
|
||||
|
||||
AcknowledgmentStore_init(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void AcknowledgmentStore_uninit(AcknowledgmentStore* this)
|
||||
{
|
||||
Mutex_uninit(&this->mutex);
|
||||
AckStoreMap_uninit(&this->storeMap);
|
||||
}
|
||||
|
||||
void AcknowledgmentStore_destruct(AcknowledgmentStore* this)
|
||||
{
|
||||
AcknowledgmentStore_uninit(this);
|
||||
|
||||
kfree(this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* ACKNOWLEDGMENTSTORE_H_ */
|
||||
32
client_module/source/common/toolkit/ackstore/WaitAckMap.c
Normal file
32
client_module/source/common/toolkit/ackstore/WaitAckMap.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "WaitAckMap.h"
|
||||
#include "WaitAckMapIter.h"
|
||||
|
||||
WaitAckMapIter WaitAckMap_find(WaitAckMap* this, const char* searchKey)
|
||||
{
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
|
||||
|
||||
WaitAckMapIter iter;
|
||||
WaitAckMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
WaitAckMapIter WaitAckMap_begin(WaitAckMap* this)
|
||||
{
|
||||
struct rb_node* node = rb_first(&this->rbTree.treeroot);
|
||||
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
|
||||
|
||||
WaitAckMapIter iter;
|
||||
WaitAckMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
int compareWaitAckMapElems(const void* key1, const void* key2)
|
||||
{
|
||||
return strcmp(key1, key2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
136
client_module/source/common/toolkit/ackstore/WaitAckMap.h
Normal file
136
client_module/source/common/toolkit/ackstore/WaitAckMap.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef WAITACKMAP_H_
|
||||
#define WAITACKMAP_H_
|
||||
|
||||
#include <common/nodes/Node.h>
|
||||
#include <common/toolkit/tree/PointerRBTree.h>
|
||||
#include <common/toolkit/tree/PointerRBTreeIter.h>
|
||||
#include <common/threading/Mutex.h>
|
||||
#include <common/threading/Condition.h>
|
||||
|
||||
|
||||
struct WaitAckNotification;
|
||||
typedef struct WaitAckNotification WaitAckNotification;
|
||||
|
||||
struct WaitAck;
|
||||
typedef struct WaitAck WaitAck;
|
||||
|
||||
|
||||
struct WaitAckMapElem;
|
||||
typedef struct WaitAckMapElem WaitAckMapElem;
|
||||
struct WaitAckMap;
|
||||
typedef struct WaitAckMap WaitAckMap;
|
||||
|
||||
struct WaitAckMapIter; // forward declaration of the iterator
|
||||
|
||||
|
||||
static inline void WaitAckNotification_init(WaitAckNotification* this);
|
||||
static inline void WaitAckNotification_uninit(WaitAckNotification* this);
|
||||
|
||||
static inline void WaitAck_init(WaitAck* this, char* ackID, void* privateData);
|
||||
|
||||
|
||||
static inline void WaitAckMap_init(WaitAckMap* this);
|
||||
static inline void WaitAckMap_uninit(WaitAckMap* this);
|
||||
|
||||
static inline bool WaitAckMap_insert(WaitAckMap* this, char* newKey,
|
||||
WaitAck* newValue);
|
||||
static inline bool WaitAckMap_erase(WaitAckMap* this, const char* eraseKey);
|
||||
static inline size_t WaitAckMap_length(WaitAckMap* this);
|
||||
|
||||
static inline void WaitAckMap_clear(WaitAckMap* this);
|
||||
|
||||
extern struct WaitAckMapIter WaitAckMap_find(WaitAckMap* this, const char* searchKey);
|
||||
extern struct WaitAckMapIter WaitAckMap_begin(WaitAckMap* this);
|
||||
|
||||
extern int compareWaitAckMapElems(const void* key1, const void* key2);
|
||||
|
||||
|
||||
struct WaitAckNotification
|
||||
{
|
||||
Mutex waitAcksMutex; // this mutex also syncs access to the waitMap/receivedMap during the
|
||||
// wait phase (which is between registration and deregistration)
|
||||
Condition waitAcksCompleteCond; // in case all WaitAcks have been received
|
||||
};
|
||||
|
||||
struct WaitAck
|
||||
{
|
||||
char* ackID;
|
||||
void* privateData; // caller's private data
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct WaitAckMapElem
|
||||
{
|
||||
RBTreeElem rbTreeElem;
|
||||
};
|
||||
|
||||
struct WaitAckMap
|
||||
{
|
||||
RBTree rbTree;
|
||||
};
|
||||
|
||||
|
||||
void WaitAckNotification_init(WaitAckNotification* this)
|
||||
{
|
||||
Mutex_init(&this->waitAcksMutex);
|
||||
Condition_init(&this->waitAcksCompleteCond);
|
||||
}
|
||||
|
||||
void WaitAckNotification_uninit(WaitAckNotification* this)
|
||||
{
|
||||
Mutex_uninit(&this->waitAcksMutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ackID is not copied, so don't free or touch it while you use this object
|
||||
* @param privateData any private data that helps the caller to identify to ack later
|
||||
*/
|
||||
void WaitAck_init(WaitAck* this, char* ackID, void* privateData)
|
||||
{
|
||||
this->ackID = ackID;
|
||||
this->privateData = privateData;
|
||||
}
|
||||
|
||||
void WaitAckMap_init(WaitAckMap* this)
|
||||
{
|
||||
PointerRBTree_init( (RBTree*)this, compareWaitAckMapElems);
|
||||
}
|
||||
|
||||
void WaitAckMap_uninit(WaitAckMap* this)
|
||||
{
|
||||
PointerRBTree_uninit( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
bool WaitAckMap_insert(WaitAckMap* this, char* newKey, WaitAck* newValue)
|
||||
{
|
||||
bool insRes;
|
||||
|
||||
insRes = PointerRBTree_insert( (RBTree*)this, newKey, newValue);
|
||||
if(!insRes)
|
||||
{
|
||||
// not inserted because the key already existed
|
||||
}
|
||||
|
||||
return insRes;
|
||||
}
|
||||
|
||||
bool WaitAckMap_erase(WaitAckMap* this, const char* eraseKey)
|
||||
{
|
||||
return PointerRBTree_erase( (RBTree*)this, eraseKey);
|
||||
}
|
||||
|
||||
size_t WaitAckMap_length(WaitAckMap* this)
|
||||
{
|
||||
return PointerRBTree_length( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
void WaitAckMap_clear(WaitAckMap* this)
|
||||
{
|
||||
PointerRBTree_clear(&this->rbTree);
|
||||
}
|
||||
|
||||
|
||||
#endif /* WAITACKMAP_H_ */
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef WAITACKMAPITER_H_
|
||||
#define WAITACKMAPITER_H_
|
||||
|
||||
#include "WaitAckMap.h"
|
||||
|
||||
struct WaitAckMapIter;
|
||||
typedef struct WaitAckMapIter WaitAckMapIter;
|
||||
|
||||
static inline void WaitAckMapIter_init(WaitAckMapIter* this, WaitAckMap* map, RBTreeElem* treeElem);
|
||||
static inline WaitAck* WaitAckMapIter_next(WaitAckMapIter* this);
|
||||
static inline char* WaitAckMapIter_key(WaitAckMapIter* this);
|
||||
static inline WaitAck* WaitAckMapIter_value(WaitAckMapIter* this);
|
||||
static inline bool WaitAckMapIter_end(WaitAckMapIter* this);
|
||||
|
||||
struct WaitAckMapIter
|
||||
{
|
||||
RBTreeIter rbTreeIter;
|
||||
};
|
||||
|
||||
void WaitAckMapIter_init(WaitAckMapIter* this, WaitAckMap* map, RBTreeElem* treeElem)
|
||||
{
|
||||
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
|
||||
}
|
||||
|
||||
WaitAck* WaitAckMapIter_next(WaitAckMapIter* this)
|
||||
{
|
||||
return (WaitAck*)PointerRBTreeIter_next( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
char* WaitAckMapIter_key(WaitAckMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_key( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
WaitAck* WaitAckMapIter_value(WaitAckMapIter* this)
|
||||
{
|
||||
return (WaitAck*)PointerRBTreeIter_value( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
bool WaitAckMapIter_end(WaitAckMapIter* this)
|
||||
{
|
||||
return PointerRBTreeIter_end( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* WAITACKMAPITER_H_ */
|
||||
73
client_module/source/common/toolkit/list/Int64CpyList.h
Normal file
73
client_module/source/common/toolkit/list/Int64CpyList.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef INT64CPYLIST_H_
|
||||
#define INT64CPYLIST_H_
|
||||
|
||||
#include <common/toolkit/list/PointerList.h>
|
||||
|
||||
/**
|
||||
* We need to copy int64 values (instead of just assigning them to just to the internal pointer)
|
||||
* because we might be running on 32bit archs.
|
||||
*/
|
||||
|
||||
struct Int64CpyList;
|
||||
typedef struct Int64CpyList Int64CpyList;
|
||||
|
||||
static inline void Int64CpyList_init(Int64CpyList* this);
|
||||
static inline void Int64CpyList_uninit(Int64CpyList* this);
|
||||
static inline void Int64CpyList_append(Int64CpyList* this, int64_t value);
|
||||
static inline size_t Int64CpyList_length(Int64CpyList* this);
|
||||
static inline void Int64CpyList_clear(Int64CpyList* this);
|
||||
|
||||
struct Int64CpyList
|
||||
{
|
||||
struct PointerList pointerList;
|
||||
};
|
||||
|
||||
|
||||
void Int64CpyList_init(Int64CpyList* this)
|
||||
{
|
||||
PointerList_init( (PointerList*)this);
|
||||
}
|
||||
|
||||
void Int64CpyList_uninit(Int64CpyList* this)
|
||||
{
|
||||
struct PointerListElem* elem = ( (PointerList*)this)->head;
|
||||
while(elem)
|
||||
{
|
||||
struct PointerListElem* next = elem->next;
|
||||
kfree(elem->valuePointer);
|
||||
elem = next;
|
||||
}
|
||||
|
||||
|
||||
PointerList_uninit( (PointerList*)this);
|
||||
}
|
||||
|
||||
void Int64CpyList_append(Int64CpyList* this, int64_t value)
|
||||
{
|
||||
int64_t* valueCopyPointer = (int64_t*)os_kmalloc(sizeof(int64_t) );
|
||||
|
||||
*valueCopyPointer = value;
|
||||
|
||||
PointerList_append( (PointerList*)this, valueCopyPointer);
|
||||
}
|
||||
|
||||
static inline size_t Int64CpyList_length(Int64CpyList* this)
|
||||
{
|
||||
return PointerList_length( (PointerList*)this);
|
||||
}
|
||||
|
||||
void Int64CpyList_clear(Int64CpyList* this)
|
||||
{
|
||||
struct PointerListElem* elem = ( (PointerList*)this)->head;
|
||||
while(elem)
|
||||
{
|
||||
struct PointerListElem* next = elem->next;
|
||||
kfree(elem->valuePointer);
|
||||
elem = next;
|
||||
}
|
||||
|
||||
PointerList_clear( (PointerList*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /*INT64CPYLIST_H_*/
|
||||
43
client_module/source/common/toolkit/list/Int64CpyListIter.h
Normal file
43
client_module/source/common/toolkit/list/Int64CpyListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef INT64CPYLISTITER_H_
|
||||
#define INT64CPYLISTITER_H_
|
||||
|
||||
#include "Int64CpyList.h"
|
||||
#include "PointerListIter.h"
|
||||
|
||||
struct Int64CpyListIter;
|
||||
typedef struct Int64CpyListIter Int64CpyListIter;
|
||||
|
||||
static inline void Int64CpyListIter_init(Int64CpyListIter* this, Int64CpyList* list);
|
||||
static inline void Int64CpyListIter_next(Int64CpyListIter* this);
|
||||
static inline int64_t Int64CpyListIter_value(Int64CpyListIter* this);
|
||||
static inline bool Int64CpyListIter_end(Int64CpyListIter* this);
|
||||
|
||||
|
||||
struct Int64CpyListIter
|
||||
{
|
||||
struct PointerListIter pointerListIter;
|
||||
};
|
||||
|
||||
|
||||
void Int64CpyListIter_init(Int64CpyListIter* this, Int64CpyList* list)
|
||||
{
|
||||
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
|
||||
}
|
||||
|
||||
void Int64CpyListIter_next(Int64CpyListIter* this)
|
||||
{
|
||||
PointerListIter_next( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
int64_t Int64CpyListIter_value(Int64CpyListIter* this)
|
||||
{
|
||||
return *(int64_t*)PointerListIter_value( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
bool Int64CpyListIter_end(Int64CpyListIter* this)
|
||||
{
|
||||
return PointerListIter_end( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /*INT64CPYLISTITER_H_*/
|
||||
54
client_module/source/common/toolkit/list/NumNodeIDList.h
Normal file
54
client_module/source/common/toolkit/list/NumNodeIDList.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef NUMNODEIDLIST_H_
|
||||
#define NUMNODEIDLIST_H_
|
||||
|
||||
#include <common/nodes/NumNodeID.h>
|
||||
#include <common/toolkit/list/PointerList.h>
|
||||
|
||||
/**
|
||||
* Derived from PointerList. Internally, we cast NumNodeID values directly to pointers here (instead
|
||||
* of allocating them and assigning the pointer to the allocated mem here).
|
||||
*/
|
||||
|
||||
struct NumNodeIDList;
|
||||
typedef struct NumNodeIDList NumNodeIDList;
|
||||
|
||||
static inline void NumNodeIDList_init(NumNodeIDList* this);
|
||||
static inline void NumNodeIDList_uninit(NumNodeIDList* this);
|
||||
static inline void NumNodeIDList_append(NumNodeIDList* this, NumNodeID value);
|
||||
static inline size_t NumNodeIDList_length(NumNodeIDList* this);
|
||||
static inline void NumNodeIDList_clear(NumNodeIDList* this);
|
||||
|
||||
struct NumNodeIDList
|
||||
{
|
||||
struct PointerList pointerList;
|
||||
};
|
||||
|
||||
|
||||
void NumNodeIDList_init(NumNodeIDList* this)
|
||||
{
|
||||
PointerList_init( (PointerList*)this);
|
||||
}
|
||||
|
||||
void NumNodeIDList_uninit(NumNodeIDList* this)
|
||||
{
|
||||
PointerList_uninit( (PointerList*)this);
|
||||
}
|
||||
|
||||
void NumNodeIDList_append(NumNodeIDList* this, NumNodeID value)
|
||||
{
|
||||
/* cast value directly to pointer type here to store value directly in the pointer variable
|
||||
without allocating extra mem */
|
||||
PointerList_append( (PointerList*)this, (void*)(size_t)value.value);
|
||||
}
|
||||
|
||||
static inline size_t NumNodeIDList_length(NumNodeIDList* this)
|
||||
{
|
||||
return PointerList_length( (PointerList*)this);
|
||||
}
|
||||
|
||||
void NumNodeIDList_clear(NumNodeIDList* this)
|
||||
{
|
||||
PointerList_clear( (PointerList*)this);
|
||||
}
|
||||
|
||||
#endif /* NUMNODEIDLIST_H_ */
|
||||
43
client_module/source/common/toolkit/list/NumNodeIDListIter.h
Normal file
43
client_module/source/common/toolkit/list/NumNodeIDListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef NUMNODEIDLISTITER_H_
|
||||
#define NUMNODEIDLISTITER_H_
|
||||
|
||||
#include <common/toolkit/list/PointerListIter.h>
|
||||
#include "NumNodeIDList.h"
|
||||
|
||||
struct NumNodeIDListIter;
|
||||
typedef struct NumNodeIDListIter NumNodeIDListIter;
|
||||
|
||||
static inline void NumNodeIDListIter_init(NumNodeIDListIter* this, NumNodeIDList* list);
|
||||
static inline void NumNodeIDListIter_next(NumNodeIDListIter* this);
|
||||
static inline NumNodeID NumNodeIDListIter_value(NumNodeIDListIter* this);
|
||||
static inline bool NumNodeIDListIter_end(NumNodeIDListIter* this);
|
||||
|
||||
|
||||
struct NumNodeIDListIter
|
||||
{
|
||||
struct PointerListIter pointerListIter;
|
||||
};
|
||||
|
||||
|
||||
void NumNodeIDListIter_init(NumNodeIDListIter* this, NumNodeIDList* list)
|
||||
{
|
||||
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
|
||||
}
|
||||
|
||||
void NumNodeIDListIter_next(NumNodeIDListIter* this)
|
||||
{
|
||||
PointerListIter_next( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
NumNodeID NumNodeIDListIter_value(NumNodeIDListIter* this)
|
||||
{
|
||||
return (NumNodeID){(size_t)PointerListIter_value( (PointerListIter*)this)};
|
||||
}
|
||||
|
||||
bool NumNodeIDListIter_end(NumNodeIDListIter* this)
|
||||
{
|
||||
return PointerListIter_end( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* NUMNODEIDLISTITER_H_ */
|
||||
267
client_module/source/common/toolkit/list/PointerList.h
Normal file
267
client_module/source/common/toolkit/list/PointerList.h
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef POINTERLIST_H_
|
||||
#define POINTERLIST_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
|
||||
struct PointerListElem;
|
||||
typedef struct PointerListElem PointerListElem;
|
||||
struct PointerList;
|
||||
typedef struct PointerList PointerList;
|
||||
|
||||
static inline void PointerList_init(PointerList* this);
|
||||
static inline void PointerList_uninit(PointerList* this);
|
||||
|
||||
static inline void PointerList_addHead(PointerList* this, void* valuePointer);
|
||||
static inline void PointerList_addTail(PointerList* this, void* valuePointer);
|
||||
static inline void PointerList_append(PointerList* this, void* valuePointer);
|
||||
static inline void PointerList_removeHead(PointerList* this);
|
||||
static inline void PointerList_removeTail(PointerList* this);
|
||||
static inline void PointerList_removeElem(PointerList* this, PointerListElem* elem);
|
||||
static inline void PointerList_moveToHead(PointerList* this, PointerListElem* elem);
|
||||
static inline void PointerList_moveToTail(PointerList* this, PointerListElem* elem);
|
||||
static inline size_t PointerList_length(const PointerList* this);
|
||||
static inline void PointerList_clear(PointerList* this);
|
||||
|
||||
static inline PointerListElem* PointerList_getTail(PointerList* this);
|
||||
static inline PointerListElem* PointerList_getHead(PointerList* this);
|
||||
|
||||
|
||||
struct PointerListElem
|
||||
{
|
||||
void* valuePointer;
|
||||
|
||||
struct PointerListElem* prev;
|
||||
struct PointerListElem* next;
|
||||
};
|
||||
|
||||
struct PointerList
|
||||
{
|
||||
struct PointerListElem* head;
|
||||
struct PointerListElem* tail;
|
||||
|
||||
size_t length;
|
||||
};
|
||||
|
||||
void PointerList_init(PointerList* this)
|
||||
{
|
||||
this->head = NULL;
|
||||
this->tail = NULL;
|
||||
|
||||
this->length = 0;
|
||||
}
|
||||
|
||||
void PointerList_uninit(PointerList* this)
|
||||
{
|
||||
PointerList_clear(this);
|
||||
}
|
||||
|
||||
static inline void __PointerList_addHead(PointerList* this, PointerListElem* elem)
|
||||
{
|
||||
if(this->length)
|
||||
{ // elements exist => replace head
|
||||
elem->next = this->head;
|
||||
this->head->prev = elem;
|
||||
this->head = elem;
|
||||
}
|
||||
else
|
||||
{ // no elements exist yet
|
||||
this->head = elem;
|
||||
this->tail = elem;
|
||||
|
||||
elem->next = NULL;
|
||||
}
|
||||
|
||||
elem->prev = NULL;
|
||||
this->length++;
|
||||
}
|
||||
|
||||
void PointerList_addHead(PointerList* this, void* valuePointer)
|
||||
{
|
||||
PointerListElem* elem = (PointerListElem*)os_kmalloc(
|
||||
sizeof(PointerListElem) );
|
||||
elem->valuePointer = valuePointer;
|
||||
__PointerList_addHead(this, elem);
|
||||
}
|
||||
|
||||
static inline void __PointerList_addTail(PointerList* this, PointerListElem* elem)
|
||||
{
|
||||
if(this->length)
|
||||
{ // elements exist => replace tail
|
||||
elem->prev = this->tail;
|
||||
this->tail->next = elem;
|
||||
this->tail = elem;
|
||||
}
|
||||
else
|
||||
{ // no elements exist yet
|
||||
this->head = elem;
|
||||
this->tail = elem;
|
||||
|
||||
elem->prev = NULL;
|
||||
}
|
||||
|
||||
elem->next = NULL;
|
||||
this->length++;
|
||||
}
|
||||
|
||||
void PointerList_addTail(PointerList* this, void* valuePointer)
|
||||
{
|
||||
PointerListElem* elem = (PointerListElem*)os_kmalloc(sizeof(PointerListElem) );
|
||||
elem->valuePointer = valuePointer;
|
||||
__PointerList_addTail(this, elem);
|
||||
}
|
||||
|
||||
void PointerList_append(PointerList* this, void* valuePointer)
|
||||
{
|
||||
PointerList_addTail(this, valuePointer);
|
||||
}
|
||||
|
||||
static inline void __PointerList_removeHead(PointerList* this, bool freeElem)
|
||||
{
|
||||
#ifdef BEEGFS_DEBUG
|
||||
if(!this->length)
|
||||
{
|
||||
BEEGFS_BUG_ON(true, "Attempt to remove head from empty list");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(this->length == 1)
|
||||
{ // removing the last element
|
||||
if (freeElem)
|
||||
kfree(this->head);
|
||||
this->head = NULL;
|
||||
this->tail = NULL;
|
||||
this->length = 0;
|
||||
}
|
||||
else
|
||||
{ // there are more elements in the list
|
||||
PointerListElem* newHead = this->head->next;
|
||||
|
||||
if (freeElem)
|
||||
kfree(this->head);
|
||||
|
||||
this->head = newHead;
|
||||
this->head->prev = NULL;
|
||||
|
||||
this->length--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PointerList_removeHead(PointerList* this)
|
||||
{
|
||||
__PointerList_removeHead(this, true);
|
||||
}
|
||||
|
||||
static inline void __PointerList_removeTail(PointerList* this, bool freeElem)
|
||||
{
|
||||
#ifdef BEEGFS_DEBUG
|
||||
if(!this->length)
|
||||
{
|
||||
BEEGFS_BUG_ON(true, "Attempt to remove tail from empty list");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(this->length == 1)
|
||||
{ // removing the last element
|
||||
if (freeElem)
|
||||
kfree(this->tail);
|
||||
this->head = NULL;
|
||||
this->tail = NULL;
|
||||
this->length = 0;
|
||||
}
|
||||
else
|
||||
{ // there are more elements in the list
|
||||
PointerListElem* newTail = this->tail->prev;
|
||||
|
||||
if (freeElem)
|
||||
kfree(this->tail);
|
||||
|
||||
this->tail = newTail;
|
||||
this->tail->next = NULL;
|
||||
|
||||
this->length--;
|
||||
}
|
||||
}
|
||||
|
||||
void PointerList_removeTail(PointerList* this)
|
||||
{
|
||||
__PointerList_removeTail(this, true);
|
||||
}
|
||||
|
||||
static inline void __PointerList_removeElem(PointerList* this, PointerListElem* elem, bool freeElem)
|
||||
{
|
||||
if(elem == this->head)
|
||||
__PointerList_removeHead(this, freeElem);
|
||||
else
|
||||
if(elem == this->tail)
|
||||
__PointerList_removeTail(this, freeElem);
|
||||
else
|
||||
{
|
||||
// not head and not tail, so this elem is somewhere in the middle
|
||||
|
||||
PointerListElem* prev = elem->prev;
|
||||
PointerListElem* next = elem->next;
|
||||
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
|
||||
if (freeElem)
|
||||
kfree(elem);
|
||||
|
||||
this->length--;
|
||||
}
|
||||
}
|
||||
|
||||
void PointerList_removeElem(PointerList* this, PointerListElem* elem)
|
||||
{
|
||||
__PointerList_removeElem(this, elem, true);
|
||||
}
|
||||
|
||||
size_t PointerList_length(const PointerList* this)
|
||||
{
|
||||
return this->length;
|
||||
}
|
||||
|
||||
void PointerList_clear(PointerList* this)
|
||||
{
|
||||
// free all elems
|
||||
PointerListElem* elem = this->head;
|
||||
while(elem)
|
||||
{
|
||||
PointerListElem* next = elem->next;
|
||||
kfree(elem);
|
||||
elem = next;
|
||||
}
|
||||
|
||||
// reset attributes
|
||||
this->head = NULL;
|
||||
this->tail = NULL;
|
||||
|
||||
this->length = 0;
|
||||
}
|
||||
|
||||
PointerListElem* PointerList_getTail(PointerList* this)
|
||||
{
|
||||
return this->tail;
|
||||
}
|
||||
|
||||
PointerListElem* PointerList_getHead(PointerList* this)
|
||||
{
|
||||
return this->head;
|
||||
}
|
||||
|
||||
void PointerList_moveToHead(PointerList* this, PointerListElem *elem)
|
||||
{
|
||||
__PointerList_removeElem(this, elem, false);
|
||||
__PointerList_addHead(this, elem);
|
||||
}
|
||||
|
||||
void PointerList_moveToTail(PointerList* this, PointerListElem *elem)
|
||||
{
|
||||
__PointerList_removeElem(this, elem, false);
|
||||
__PointerList_addTail(this, elem);
|
||||
}
|
||||
|
||||
#endif /*POINTERLIST_H_*/
|
||||
62
client_module/source/common/toolkit/list/PointerListIter.h
Normal file
62
client_module/source/common/toolkit/list/PointerListIter.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef POINTERLISTITER_H_
|
||||
#define POINTERLISTITER_H_
|
||||
|
||||
#include "PointerList.h"
|
||||
|
||||
struct PointerListIter;
|
||||
typedef struct PointerListIter PointerListIter;
|
||||
|
||||
static inline void PointerListIter_init(PointerListIter* this, PointerList* list);
|
||||
static inline void PointerListIter_next(PointerListIter* this);
|
||||
static inline void* PointerListIter_value(PointerListIter* this);
|
||||
static inline bool PointerListIter_end(PointerListIter* this);
|
||||
static inline PointerListIter PointerListIter_remove(PointerListIter* this);
|
||||
|
||||
struct PointerListIter
|
||||
{
|
||||
PointerList* list;
|
||||
PointerListElem* elem;
|
||||
};
|
||||
|
||||
void PointerListIter_init(PointerListIter* this, PointerList* list)
|
||||
{
|
||||
this->list = list;
|
||||
this->elem = list->head;
|
||||
}
|
||||
|
||||
void PointerListIter_next(PointerListIter* this)
|
||||
{
|
||||
// note: must not return the value because the current elem could be the end of the list
|
||||
|
||||
this->elem = this->elem->next;
|
||||
}
|
||||
|
||||
void* PointerListIter_value(PointerListIter* this)
|
||||
{
|
||||
return this->elem->valuePointer;
|
||||
}
|
||||
|
||||
bool PointerListIter_end(PointerListIter* this)
|
||||
{
|
||||
return (this->elem == NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* note: the current iterator becomes invalid after the call (use the returned iterator)
|
||||
* @return the new iterator that points to the element just behind the erased one
|
||||
*/
|
||||
PointerListIter PointerListIter_remove(PointerListIter* this)
|
||||
{
|
||||
PointerListIter newIter = *this;
|
||||
|
||||
PointerListElem* elem = this->elem;
|
||||
|
||||
PointerListIter_next(&newIter);
|
||||
|
||||
PointerList_removeElem(this->list, elem);
|
||||
|
||||
return newIter;
|
||||
}
|
||||
|
||||
|
||||
#endif /*POINTERLISTITER_H_*/
|
||||
77
client_module/source/common/toolkit/list/StrCpyList.h
Normal file
77
client_module/source/common/toolkit/list/StrCpyList.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef STRCPYLIST_H_
|
||||
#define STRCPYLIST_H_
|
||||
|
||||
#include "StringList.h"
|
||||
|
||||
struct StrCpyList;
|
||||
typedef struct StrCpyList StrCpyList;
|
||||
|
||||
static inline void StrCpyList_init(StrCpyList* this);
|
||||
static inline void StrCpyList_uninit(StrCpyList* this);
|
||||
static inline void StrCpyList_addHead(StrCpyList* this, const char* valuePointer);
|
||||
static inline void StrCpyList_append(StrCpyList* this, const char* valuePointer);
|
||||
static inline size_t StrCpyList_length(StrCpyList* this);
|
||||
static inline void StrCpyList_clear(StrCpyList* this);
|
||||
|
||||
struct StrCpyList
|
||||
{
|
||||
struct StringList stringList;
|
||||
};
|
||||
|
||||
|
||||
void StrCpyList_init(StrCpyList* this)
|
||||
{
|
||||
StringList_init( (StringList*)this);
|
||||
}
|
||||
|
||||
void StrCpyList_uninit(StrCpyList* this)
|
||||
{
|
||||
struct PointerListElem* elem = ( (PointerList*)this)->head;
|
||||
while(elem)
|
||||
{
|
||||
struct PointerListElem* next = elem->next;
|
||||
kfree(elem->valuePointer);
|
||||
elem = next;
|
||||
}
|
||||
|
||||
|
||||
StringList_uninit( (StringList*)this);
|
||||
}
|
||||
|
||||
void StrCpyList_addHead(StrCpyList* this, const char* valuePointer)
|
||||
{
|
||||
size_t valueLen = strlen(valuePointer)+1;
|
||||
char* valueCopy = (char*)os_kmalloc(valueLen);
|
||||
memcpy(valueCopy, valuePointer, valueLen);
|
||||
|
||||
StringList_addHead( (StringList*)this, valueCopy);
|
||||
}
|
||||
|
||||
void StrCpyList_append(StrCpyList* this, const char* valuePointer)
|
||||
{
|
||||
size_t valueLen = strlen(valuePointer)+1;
|
||||
char* valueCopy = (char*)os_kmalloc(valueLen);
|
||||
memcpy(valueCopy, valuePointer, valueLen);
|
||||
|
||||
StringList_append( (StringList*)this, valueCopy);
|
||||
}
|
||||
|
||||
size_t StrCpyList_length(StrCpyList* this)
|
||||
{
|
||||
return StringList_length( (StringList*)this);
|
||||
}
|
||||
|
||||
void StrCpyList_clear(StrCpyList* this)
|
||||
{
|
||||
struct PointerListElem* elem = ( (PointerList*)this)->head;
|
||||
while(elem)
|
||||
{
|
||||
struct PointerListElem* next = elem->next;
|
||||
kfree(elem->valuePointer);
|
||||
elem = next;
|
||||
}
|
||||
|
||||
StringList_clear( (StringList*)this);
|
||||
}
|
||||
|
||||
#endif /*STRCPYLIST_H_*/
|
||||
43
client_module/source/common/toolkit/list/StrCpyListIter.h
Normal file
43
client_module/source/common/toolkit/list/StrCpyListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef STRCPYLISTITER_H_
|
||||
#define STRCPYLISTITER_H_
|
||||
|
||||
#include "StrCpyList.h"
|
||||
#include "StringListIter.h"
|
||||
|
||||
struct StrCpyListIter;
|
||||
typedef struct StrCpyListIter StrCpyListIter;
|
||||
|
||||
static inline void StrCpyListIter_init(StrCpyListIter* this, StrCpyList* list);
|
||||
static inline void StrCpyListIter_next(StrCpyListIter* this);
|
||||
static inline char* StrCpyListIter_value(StrCpyListIter* this);
|
||||
static inline bool StrCpyListIter_end(StrCpyListIter* this);
|
||||
|
||||
|
||||
struct StrCpyListIter
|
||||
{
|
||||
struct StringListIter stringListIter;
|
||||
};
|
||||
|
||||
|
||||
void StrCpyListIter_init(StrCpyListIter* this, StrCpyList* list)
|
||||
{
|
||||
StringListIter_init( (StringListIter*)this, (StringList*)list);
|
||||
}
|
||||
|
||||
void StrCpyListIter_next(StrCpyListIter* this)
|
||||
{
|
||||
StringListIter_next( (StringListIter*)this);
|
||||
}
|
||||
|
||||
char* StrCpyListIter_value(StrCpyListIter* this)
|
||||
{
|
||||
return (char*)StringListIter_value( (StringListIter*)this);
|
||||
}
|
||||
|
||||
bool StrCpyListIter_end(StrCpyListIter* this)
|
||||
{
|
||||
return StringListIter_end( (StringListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /*STRCPYLISTITER_H_*/
|
||||
52
client_module/source/common/toolkit/list/StringList.h
Normal file
52
client_module/source/common/toolkit/list/StringList.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef STRINGLIST_H_
|
||||
#define STRINGLIST_H_
|
||||
|
||||
#include "PointerList.h"
|
||||
|
||||
struct StringList;
|
||||
typedef struct StringList StringList;
|
||||
|
||||
static inline void StringList_init(StringList* this);
|
||||
static inline void StringList_uninit(StringList* this);
|
||||
static inline void StringList_addHead(StringList* this, char* valuePointer);
|
||||
static inline void StringList_append(StringList* this, char* valuePointer);
|
||||
static inline size_t StringList_length(StringList* this);
|
||||
static inline void StringList_clear(StringList* this);
|
||||
|
||||
struct StringList
|
||||
{
|
||||
PointerList pointerList;
|
||||
};
|
||||
|
||||
|
||||
void StringList_init(StringList* this)
|
||||
{
|
||||
PointerList_init( (PointerList*)this);
|
||||
}
|
||||
|
||||
void StringList_uninit(StringList* this)
|
||||
{
|
||||
PointerList_uninit( (PointerList*)this);
|
||||
}
|
||||
|
||||
void StringList_addHead(StringList* this, char* valuePointer)
|
||||
{
|
||||
PointerList_addHead( (PointerList*)this, valuePointer);
|
||||
}
|
||||
|
||||
void StringList_append(StringList* this, char* valuePointer)
|
||||
{
|
||||
PointerList_append( (PointerList*)this, valuePointer);
|
||||
}
|
||||
|
||||
size_t StringList_length(StringList* this)
|
||||
{
|
||||
return PointerList_length( (PointerList*)this);
|
||||
}
|
||||
|
||||
void StringList_clear(StringList* this)
|
||||
{
|
||||
PointerList_clear( (PointerList*)this);
|
||||
}
|
||||
|
||||
#endif /*STRINGLIST_H_*/
|
||||
43
client_module/source/common/toolkit/list/StringListIter.h
Normal file
43
client_module/source/common/toolkit/list/StringListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef STRINGLISTITER_H_
|
||||
#define STRINGLISTITER_H_
|
||||
|
||||
#include "StringList.h"
|
||||
#include "PointerListIter.h"
|
||||
|
||||
struct StringListIter;
|
||||
typedef struct StringListIter StringListIter;
|
||||
|
||||
static inline void StringListIter_init(StringListIter* this, StringList* list);
|
||||
static inline void StringListIter_next(StringListIter* this);
|
||||
static inline char* StringListIter_value(StringListIter* this);
|
||||
static inline bool StringListIter_end(StringListIter* this);
|
||||
|
||||
|
||||
struct StringListIter
|
||||
{
|
||||
PointerListIter pointerListIter;
|
||||
};
|
||||
|
||||
|
||||
void StringListIter_init(StringListIter* this, StringList* list)
|
||||
{
|
||||
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
|
||||
}
|
||||
|
||||
void StringListIter_next(StringListIter* this)
|
||||
{
|
||||
PointerListIter_next( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
char* StringListIter_value(StringListIter* this)
|
||||
{
|
||||
return (char*)PointerListIter_value( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
bool StringListIter_end(StringListIter* this)
|
||||
{
|
||||
return PointerListIter_end( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /*STRINGLISTITER_H_*/
|
||||
53
client_module/source/common/toolkit/list/UInt16List.h
Normal file
53
client_module/source/common/toolkit/list/UInt16List.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef UINT16LIST_H_
|
||||
#define UINT16LIST_H_
|
||||
|
||||
#include <common/toolkit/list/PointerList.h>
|
||||
|
||||
/**
|
||||
* Derived from PointerList. Internally, we cast uint16_t values directly to pointers here (instead
|
||||
* of allocating them and assigning the pointer to the allocated mem here).
|
||||
*/
|
||||
|
||||
struct UInt16List;
|
||||
typedef struct UInt16List UInt16List;
|
||||
|
||||
static inline void UInt16List_init(UInt16List* this);
|
||||
static inline void UInt16List_uninit(UInt16List* this);
|
||||
static inline void UInt16List_append(UInt16List* this, uint16_t value);
|
||||
static inline size_t UInt16List_length(UInt16List* this);
|
||||
static inline void UInt16List_clear(UInt16List* this);
|
||||
|
||||
struct UInt16List
|
||||
{
|
||||
struct PointerList pointerList;
|
||||
};
|
||||
|
||||
|
||||
void UInt16List_init(UInt16List* this)
|
||||
{
|
||||
PointerList_init( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt16List_uninit(UInt16List* this)
|
||||
{
|
||||
PointerList_uninit( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt16List_append(UInt16List* this, uint16_t value)
|
||||
{
|
||||
/* cast value directly to pointer type here to store value directly in the pointer variable
|
||||
without allocating extra mem */
|
||||
PointerList_append( (PointerList*)this, (void*)(size_t)value);
|
||||
}
|
||||
|
||||
static inline size_t UInt16List_length(UInt16List* this)
|
||||
{
|
||||
return PointerList_length( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt16List_clear(UInt16List* this)
|
||||
{
|
||||
PointerList_clear( (PointerList*)this);
|
||||
}
|
||||
|
||||
#endif /* UINT16LIST_H_ */
|
||||
43
client_module/source/common/toolkit/list/UInt16ListIter.h
Normal file
43
client_module/source/common/toolkit/list/UInt16ListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef UINT16LISTITER_H_
|
||||
#define UINT16LISTITER_H_
|
||||
|
||||
#include <common/toolkit/list/PointerListIter.h>
|
||||
#include "UInt16List.h"
|
||||
|
||||
struct UInt16ListIter;
|
||||
typedef struct UInt16ListIter UInt16ListIter;
|
||||
|
||||
static inline void UInt16ListIter_init(UInt16ListIter* this, UInt16List* list);
|
||||
static inline void UInt16ListIter_next(UInt16ListIter* this);
|
||||
static inline uint16_t UInt16ListIter_value(UInt16ListIter* this);
|
||||
static inline bool UInt16ListIter_end(UInt16ListIter* this);
|
||||
|
||||
|
||||
struct UInt16ListIter
|
||||
{
|
||||
struct PointerListIter pointerListIter;
|
||||
};
|
||||
|
||||
|
||||
void UInt16ListIter_init(UInt16ListIter* this, UInt16List* list)
|
||||
{
|
||||
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
|
||||
}
|
||||
|
||||
void UInt16ListIter_next(UInt16ListIter* this)
|
||||
{
|
||||
PointerListIter_next( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
uint16_t UInt16ListIter_value(UInt16ListIter* this)
|
||||
{
|
||||
return (uint16_t)(size_t)PointerListIter_value( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
bool UInt16ListIter_end(UInt16ListIter* this)
|
||||
{
|
||||
return PointerListIter_end( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* UINT16LISTITER_H_ */
|
||||
53
client_module/source/common/toolkit/list/UInt8List.h
Normal file
53
client_module/source/common/toolkit/list/UInt8List.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef UINT8LIST_H_
|
||||
#define UINT8LIST_H_
|
||||
|
||||
#include <common/toolkit/list/PointerList.h>
|
||||
|
||||
/**
|
||||
* Derived from PointerList. Internally, we cast uint8_t values directly to pointers here (instead
|
||||
* of allocating them and assigning the pointer to the allocated mem here).
|
||||
*/
|
||||
|
||||
struct UInt8List;
|
||||
typedef struct UInt8List UInt8List;
|
||||
|
||||
static inline void UInt8List_init(UInt8List* this);
|
||||
static inline void UInt8List_uninit(UInt8List* this);
|
||||
static inline void UInt8List_append(UInt8List* this, uint8_t value);
|
||||
static inline size_t UInt8List_length(UInt8List* this);
|
||||
static inline void UInt8List_clear(UInt8List* this);
|
||||
|
||||
struct UInt8List
|
||||
{
|
||||
struct PointerList pointerList;
|
||||
};
|
||||
|
||||
|
||||
void UInt8List_init(UInt8List* this)
|
||||
{
|
||||
PointerList_init( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt8List_uninit(UInt8List* this)
|
||||
{
|
||||
PointerList_uninit( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt8List_append(UInt8List* this, uint8_t value)
|
||||
{
|
||||
/* cast value directly to pointer type here to store value directly in the pointer variable
|
||||
without allocating extra mem */
|
||||
PointerList_append( (PointerList*)this, (void*)(size_t)value);
|
||||
}
|
||||
|
||||
static inline size_t UInt8List_length(UInt8List* this)
|
||||
{
|
||||
return PointerList_length( (PointerList*)this);
|
||||
}
|
||||
|
||||
void UInt8List_clear(UInt8List* this)
|
||||
{
|
||||
PointerList_clear( (PointerList*)this);
|
||||
}
|
||||
|
||||
#endif /* UINT8LIST_H_ */
|
||||
43
client_module/source/common/toolkit/list/UInt8ListIter.h
Normal file
43
client_module/source/common/toolkit/list/UInt8ListIter.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef UINT8LISTITER_H_
|
||||
#define UINT8LISTITER_H_
|
||||
|
||||
#include <common/toolkit/list/PointerListIter.h>
|
||||
#include "UInt8List.h"
|
||||
|
||||
struct UInt8ListIter;
|
||||
typedef struct UInt8ListIter UInt8ListIter;
|
||||
|
||||
static inline void UInt8ListIter_init(UInt8ListIter* this, UInt8List* list);
|
||||
static inline void UInt8ListIter_next(UInt8ListIter* this);
|
||||
static inline uint8_t UInt8ListIter_value(UInt8ListIter* this);
|
||||
static inline bool UInt8ListIter_end(UInt8ListIter* this);
|
||||
|
||||
|
||||
struct UInt8ListIter
|
||||
{
|
||||
struct PointerListIter pointerListIter;
|
||||
};
|
||||
|
||||
|
||||
void UInt8ListIter_init(UInt8ListIter* this, UInt8List* list)
|
||||
{
|
||||
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
|
||||
}
|
||||
|
||||
void UInt8ListIter_next(UInt8ListIter* this)
|
||||
{
|
||||
PointerListIter_next( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
uint8_t UInt8ListIter_value(UInt8ListIter* this)
|
||||
{
|
||||
return (uint8_t)(size_t)PointerListIter_value( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
bool UInt8ListIter_end(UInt8ListIter* this)
|
||||
{
|
||||
return PointerListIter_end( (PointerListIter*)this);
|
||||
}
|
||||
|
||||
|
||||
#endif /* UINT8LISTITER_H_ */
|
||||
24
client_module/source/common/toolkit/tree/IntMap.c
Normal file
24
client_module/source/common/toolkit/tree/IntMap.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <common/toolkit/tree/IntMap.h>
|
||||
#include <common/toolkit/tree/IntMapIter.h>
|
||||
|
||||
IntMapIter IntMap_find(IntMap* this, const int searchKey)
|
||||
{
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem(
|
||||
(RBTree*)this, (const void*)(const size_t)searchKey);
|
||||
|
||||
IntMapIter iter;
|
||||
IntMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
IntMapIter IntMap_begin(IntMap* this)
|
||||
{
|
||||
struct rb_node* node = rb_first(&this->rbTree.treeroot);
|
||||
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
|
||||
|
||||
IntMapIter iter;
|
||||
IntMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
88
client_module/source/common/toolkit/tree/IntMap.h
Normal file
88
client_module/source/common/toolkit/tree/IntMap.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef INTMAP_H_
|
||||
#define INTMAP_H_
|
||||
|
||||
#include "PointerRBTree.h"
|
||||
#include "PointerRBTreeIter.h"
|
||||
|
||||
|
||||
/**
|
||||
* We assign the integer keys directly to the key pointers (i.e. no extra allocation involved,
|
||||
* but a lot of casting to convince gcc that we know what we're doing).
|
||||
* Values are just arbitrary pointers.
|
||||
*/
|
||||
|
||||
|
||||
struct IntMapElem;
|
||||
typedef struct IntMapElem IntMapElem;
|
||||
struct IntMap;
|
||||
typedef struct IntMap IntMap;
|
||||
|
||||
struct IntMapIter; // forward declaration of the iterator
|
||||
|
||||
static inline void IntMap_init(IntMap* this);
|
||||
static inline void IntMap_uninit(IntMap* this);
|
||||
|
||||
static inline bool IntMap_insert(IntMap* this, int newKey, char* newValue);
|
||||
static inline bool IntMap_erase(IntMap* this, const int eraseKey);
|
||||
static inline size_t IntMap_length(IntMap* this);
|
||||
|
||||
static inline void IntMap_clear(IntMap* this);
|
||||
|
||||
extern struct IntMapIter IntMap_find(IntMap* this, const int searchKey);
|
||||
extern struct IntMapIter IntMap_begin(IntMap* this);
|
||||
|
||||
|
||||
struct IntMapElem
|
||||
{
|
||||
RBTreeElem rbTreeElem;
|
||||
};
|
||||
|
||||
struct IntMap
|
||||
{
|
||||
RBTree rbTree;
|
||||
};
|
||||
|
||||
|
||||
void IntMap_init(IntMap* this)
|
||||
{
|
||||
PointerRBTree_init( (RBTree*)this, PointerRBTree_keyCompare);
|
||||
}
|
||||
|
||||
void IntMap_uninit(IntMap* this)
|
||||
{
|
||||
// (nothing alloc'ed by this sub map type => nothing special here to be free'd)
|
||||
|
||||
PointerRBTree_uninit( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param newValue just assigned, not copied.
|
||||
* @return true if element was inserted, false if key already existed (in which case
|
||||
* nothing is changed)
|
||||
*/
|
||||
bool IntMap_insert(IntMap* this, int newKey, char* newValue)
|
||||
{
|
||||
return PointerRBTree_insert( (RBTree*)this, (void*)(size_t)newKey, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if no element with the given key existed
|
||||
*/
|
||||
bool IntMap_erase(IntMap* this, const int eraseKey)
|
||||
{
|
||||
return PointerRBTree_erase( (RBTree*)this, (const void*)(const size_t)eraseKey);
|
||||
}
|
||||
|
||||
size_t IntMap_length(IntMap* this)
|
||||
{
|
||||
return PointerRBTree_length( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
void IntMap_clear(IntMap* this)
|
||||
{
|
||||
PointerRBTree_clear(&this->rbTree);
|
||||
}
|
||||
|
||||
#endif /* INTMAP_H_ */
|
||||
45
client_module/source/common/toolkit/tree/IntMapIter.h
Normal file
45
client_module/source/common/toolkit/tree/IntMapIter.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef INTMAPITER_H_
|
||||
#define INTMAPITER_H_
|
||||
|
||||
#include "IntMap.h"
|
||||
|
||||
struct IntMapIter;
|
||||
typedef struct IntMapIter IntMapIter;
|
||||
|
||||
static inline void IntMapIter_init(IntMapIter* this, IntMap* map, RBTreeElem* treeElem);
|
||||
static inline char* IntMapIter_next(IntMapIter* this);
|
||||
static inline int IntMapIter_key(IntMapIter* this);
|
||||
static inline char* IntMapIter_value(IntMapIter* this);
|
||||
static inline bool IntMapIter_end(IntMapIter* this);
|
||||
|
||||
struct IntMapIter
|
||||
{
|
||||
RBTreeIter rbTreeIter;
|
||||
};
|
||||
|
||||
void IntMapIter_init(IntMapIter* this, IntMap* map, RBTreeElem* treeElem)
|
||||
{
|
||||
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
|
||||
}
|
||||
|
||||
char* IntMapIter_next(IntMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_next( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
int IntMapIter_key(IntMapIter* this)
|
||||
{
|
||||
return (int)(size_t)PointerRBTreeIter_key( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
char* IntMapIter_value(IntMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_value( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
bool IntMapIter_end(IntMapIter* this)
|
||||
{
|
||||
return PointerRBTreeIter_end( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
#endif /* INTMAPITER_H_ */
|
||||
24
client_module/source/common/toolkit/tree/PointerRBTree.c
Normal file
24
client_module/source/common/toolkit/tree/PointerRBTree.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <common/toolkit/tree/PointerRBTree.h>
|
||||
#include <common/toolkit/tree/PointerRBTreeIter.h>
|
||||
|
||||
|
||||
RBTreeIter PointerRBTree_find(RBTree* this, const void* searchKey)
|
||||
{
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem(this, searchKey);
|
||||
|
||||
RBTreeIter iter;
|
||||
PointerRBTreeIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
RBTreeIter PointerRBTree_begin(RBTree* this)
|
||||
{
|
||||
struct rb_node* node = rb_first(&this->treeroot);
|
||||
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
|
||||
|
||||
RBTreeIter iter;
|
||||
PointerRBTreeIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
201
client_module/source/common/toolkit/tree/PointerRBTree.h
Normal file
201
client_module/source/common/toolkit/tree/PointerRBTree.h
Normal file
@@ -0,0 +1,201 @@
|
||||
#ifndef POINTERRBTREE_H_
|
||||
#define POINTERRBTREE_H_
|
||||
|
||||
#include <common/Common.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
|
||||
struct RBTreeElem;
|
||||
typedef struct RBTreeElem RBTreeElem;
|
||||
struct RBTree;
|
||||
typedef struct RBTree RBTree;
|
||||
|
||||
|
||||
/**
|
||||
* @return: <0 if key1<key2, 0 for equal keys, >0 otherwise
|
||||
*/
|
||||
typedef int (*TreeElemsComparator)(const void* key1, const void* key2);
|
||||
|
||||
|
||||
struct RBTreeIter; // forward declaration of the iterator
|
||||
|
||||
static inline void PointerRBTree_init(RBTree* this, TreeElemsComparator compareTreeElems);
|
||||
static inline void PointerRBTree_uninit(RBTree* this);
|
||||
|
||||
static inline RBTreeElem* _PointerRBTree_findElem(RBTree* this, const void* searchKey);
|
||||
|
||||
static inline bool PointerRBTree_insert(RBTree* this, void* newKey, void* newValue);
|
||||
static bool PointerRBTree_erase(RBTree* this, const void* eraseKey);
|
||||
static inline size_t PointerRBTree_length(RBTree* this);
|
||||
|
||||
static inline void PointerRBTree_clear(RBTree* this);
|
||||
|
||||
static inline int PointerRBTree_keyCompare(const void* a, const void* b);
|
||||
|
||||
extern struct RBTreeIter PointerRBTree_find(RBTree* this, const void* searchKey);
|
||||
extern struct RBTreeIter PointerRBTree_begin(RBTree* this);
|
||||
|
||||
struct RBTreeElem
|
||||
{
|
||||
struct rb_node treenode;
|
||||
|
||||
void* key;
|
||||
void* value;
|
||||
};
|
||||
|
||||
|
||||
struct RBTree
|
||||
{
|
||||
struct rb_root treeroot;
|
||||
|
||||
size_t length;
|
||||
|
||||
TreeElemsComparator compareTreeElems;
|
||||
};
|
||||
|
||||
|
||||
void PointerRBTree_init(RBTree* this, TreeElemsComparator compareTreeElems)
|
||||
{
|
||||
this->treeroot.rb_node = NULL;
|
||||
this->length = 0;
|
||||
|
||||
this->compareTreeElems = compareTreeElems;
|
||||
}
|
||||
|
||||
void PointerRBTree_uninit(RBTree* this)
|
||||
{
|
||||
PointerRBTree_clear(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return NULL if the element was not found
|
||||
*/
|
||||
RBTreeElem* _PointerRBTree_findElem(RBTree* this, const void* searchKey)
|
||||
{
|
||||
int compRes;
|
||||
|
||||
struct rb_node* node = this->treeroot.rb_node;
|
||||
|
||||
while(node)
|
||||
{
|
||||
RBTreeElem* treeElem = container_of(node, RBTreeElem, treenode);
|
||||
|
||||
compRes = this->compareTreeElems(searchKey, treeElem->key);
|
||||
|
||||
if(compRes < 0)
|
||||
node = node->rb_left;
|
||||
else
|
||||
if(compRes > 0)
|
||||
node = node->rb_right;
|
||||
else
|
||||
{ // element found => return it
|
||||
return treeElem;
|
||||
}
|
||||
}
|
||||
|
||||
// element not found
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if element was inserted, false if it already existed (in which case
|
||||
* nothing is changed) or if out of mem.
|
||||
*/
|
||||
bool PointerRBTree_insert(RBTree* this, void* newKey, void* newValue)
|
||||
{
|
||||
RBTreeElem* newElem;
|
||||
|
||||
// the parent's (left or right) link to which the child will be connected
|
||||
struct rb_node** link = &this->treeroot.rb_node;
|
||||
// the parent of the new node
|
||||
struct rb_node* parent = NULL;
|
||||
|
||||
while(*link)
|
||||
{
|
||||
int compRes;
|
||||
RBTreeElem* treeElem;
|
||||
|
||||
parent = *link;
|
||||
treeElem = container_of(parent, RBTreeElem, treenode);
|
||||
|
||||
compRes = this->compareTreeElems(newKey, treeElem->key);
|
||||
|
||||
if(compRes < 0)
|
||||
link = &(*link)->rb_left;
|
||||
else
|
||||
if(compRes > 0)
|
||||
link = &(*link)->rb_right;
|
||||
else
|
||||
{ // target already exists => do nothing (according to the behavior of c++ map::insert)
|
||||
//rbReplaceNode(parent, newElem, this);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// create new element
|
||||
|
||||
newElem = os_kmalloc(sizeof(*newElem) );
|
||||
newElem->key = newKey;
|
||||
newElem->value = newValue;
|
||||
|
||||
// link the new element
|
||||
rb_link_node(&newElem->treenode, parent, link);
|
||||
rb_insert_color(&newElem->treenode, &this->treeroot);
|
||||
|
||||
this->length++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if no element with the given key existed
|
||||
*/
|
||||
bool PointerRBTree_erase(RBTree* this, const void* eraseKey)
|
||||
{
|
||||
RBTreeElem* treeElem;
|
||||
|
||||
treeElem = _PointerRBTree_findElem(this, eraseKey);
|
||||
if(!treeElem)
|
||||
{ // element not found
|
||||
return false;
|
||||
}
|
||||
|
||||
// unlink the element
|
||||
rb_erase(&treeElem->treenode, &this->treeroot);
|
||||
|
||||
kfree(treeElem);
|
||||
|
||||
this->length--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t PointerRBTree_length(RBTree* this)
|
||||
{
|
||||
return this->length;
|
||||
}
|
||||
|
||||
void PointerRBTree_clear(RBTree* this)
|
||||
{
|
||||
while(this->length)
|
||||
{
|
||||
RBTreeElem* root = container_of(this->treeroot.rb_node, RBTreeElem, treenode);
|
||||
PointerRBTree_erase(this, root->key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int PointerRBTree_keyCompare(const void* a, const void* b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a == b)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /*POINTERRBTREE_H_*/
|
||||
57
client_module/source/common/toolkit/tree/PointerRBTreeIter.h
Normal file
57
client_module/source/common/toolkit/tree/PointerRBTreeIter.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef POINTERRBTREEITER_H_
|
||||
#define POINTERRBTREEITER_H_
|
||||
|
||||
#include "PointerRBTree.h"
|
||||
|
||||
struct RBTreeIter;
|
||||
typedef struct RBTreeIter RBTreeIter;
|
||||
|
||||
static inline void PointerRBTreeIter_init(
|
||||
RBTreeIter* this, RBTree* tree, RBTreeElem* treeElem);
|
||||
|
||||
static inline void* PointerRBTreeIter_next(RBTreeIter* this);
|
||||
static inline void* PointerRBTreeIter_key(RBTreeIter* this);
|
||||
static inline void* PointerRBTreeIter_value(RBTreeIter* this);
|
||||
static inline bool PointerRBTreeIter_end(RBTreeIter* this);
|
||||
|
||||
struct RBTreeIter
|
||||
{
|
||||
RBTree* tree;
|
||||
RBTreeElem* treeElem;
|
||||
};
|
||||
|
||||
|
||||
void PointerRBTreeIter_init(RBTreeIter* this, RBTree* tree, RBTreeElem* treeElem)
|
||||
{
|
||||
this->tree = tree;
|
||||
this->treeElem = treeElem;
|
||||
}
|
||||
|
||||
void* PointerRBTreeIter_next(RBTreeIter* this)
|
||||
{
|
||||
struct rb_node* next = rb_next(&this->treeElem->treenode);
|
||||
|
||||
this->treeElem = next ? container_of(next, RBTreeElem, treenode) : NULL;
|
||||
|
||||
return this->treeElem;
|
||||
}
|
||||
|
||||
void* PointerRBTreeIter_key(RBTreeIter* this)
|
||||
{
|
||||
return this->treeElem->key;
|
||||
}
|
||||
|
||||
void* PointerRBTreeIter_value(RBTreeIter* this)
|
||||
{
|
||||
return this->treeElem->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the end of the iterator was reached
|
||||
*/
|
||||
bool PointerRBTreeIter_end(RBTreeIter* this)
|
||||
{
|
||||
return (this->treeElem == NULL);
|
||||
}
|
||||
|
||||
#endif /*POINTERRBTREEITER_H_*/
|
||||
30
client_module/source/common/toolkit/tree/StrCpyMap.c
Normal file
30
client_module/source/common/toolkit/tree/StrCpyMap.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "StrCpyMap.h"
|
||||
#include "StrCpyMapIter.h"
|
||||
|
||||
StrCpyMapIter StrCpyMap_find(StrCpyMap* this, const char* searchKey)
|
||||
{
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
|
||||
|
||||
StrCpyMapIter iter;
|
||||
StrCpyMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
StrCpyMapIter StrCpyMap_begin(StrCpyMap* this)
|
||||
{
|
||||
struct rb_node* node = rb_first(&this->rbTree.treeroot);
|
||||
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
|
||||
|
||||
StrCpyMapIter iter;
|
||||
StrCpyMapIter_init(&iter, this, treeElem);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
int compareStrCpyMapElems(const void* key1, const void* key2)
|
||||
{
|
||||
return strcmp(key1, key2);
|
||||
}
|
||||
|
||||
131
client_module/source/common/toolkit/tree/StrCpyMap.h
Normal file
131
client_module/source/common/toolkit/tree/StrCpyMap.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef STRCPYMAP_H_
|
||||
#define STRCPYMAP_H_
|
||||
|
||||
#include <common/toolkit/tree/PointerRBTree.h>
|
||||
#include <common/toolkit/tree/PointerRBTreeIter.h>
|
||||
|
||||
struct StrCpyMapElem;
|
||||
typedef struct StrCpyMapElem StrCpyMapElem;
|
||||
struct StrCpyMap;
|
||||
typedef struct StrCpyMap StrCpyMap;
|
||||
|
||||
struct StrCpyMapIter; // forward declaration of the iterator
|
||||
|
||||
static inline void StrCpyMap_init(StrCpyMap* this);
|
||||
static inline void StrCpyMap_uninit(StrCpyMap* this);
|
||||
|
||||
static inline bool StrCpyMap_insert(StrCpyMap* this, const char* newKey,
|
||||
const char* newValue);
|
||||
static inline bool StrCpyMap_erase(StrCpyMap* this, const char* eraseKey);
|
||||
static inline size_t StrCpyMap_length(StrCpyMap* this);
|
||||
|
||||
static inline void StrCpyMap_clear(StrCpyMap* this);
|
||||
|
||||
extern struct StrCpyMapIter StrCpyMap_find(StrCpyMap* this, const char* searchKey);
|
||||
extern struct StrCpyMapIter StrCpyMap_begin(StrCpyMap* this);
|
||||
|
||||
extern int compareStrCpyMapElems(const void* key1, const void* key2);
|
||||
|
||||
|
||||
struct StrCpyMapElem
|
||||
{
|
||||
RBTreeElem rbTreeElem;
|
||||
};
|
||||
|
||||
struct StrCpyMap
|
||||
{
|
||||
RBTree rbTree;
|
||||
};
|
||||
|
||||
|
||||
void StrCpyMap_init(StrCpyMap* this)
|
||||
{
|
||||
PointerRBTree_init( (RBTree*)this, compareStrCpyMapElems);
|
||||
}
|
||||
|
||||
void StrCpyMap_uninit(StrCpyMap* this)
|
||||
{
|
||||
StrCpyMap_clear(this);
|
||||
|
||||
PointerRBTree_uninit( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return true if element was inserted, false if key already existed (in which case
|
||||
* nothing is changed)
|
||||
*/
|
||||
bool StrCpyMap_insert(StrCpyMap* this, const char* newKey, const char* newValue)
|
||||
{
|
||||
size_t keyLen;
|
||||
char* keyCopy;
|
||||
size_t valueLen;
|
||||
char* valueCopy;
|
||||
bool insRes;
|
||||
|
||||
// copy key
|
||||
keyLen = strlen(newKey)+1;
|
||||
keyCopy = (char*)os_kmalloc(keyLen);
|
||||
memcpy(keyCopy, newKey, keyLen);
|
||||
|
||||
// copy value
|
||||
valueLen = strlen(newValue)+1;
|
||||
valueCopy = (char*)os_kmalloc(valueLen);
|
||||
memcpy(valueCopy, newValue, valueLen);
|
||||
|
||||
insRes = PointerRBTree_insert( (RBTree*)this, keyCopy, valueCopy);
|
||||
if(!insRes)
|
||||
{
|
||||
// not inserted because the key already existed => free up the copies
|
||||
kfree(keyCopy);
|
||||
kfree(valueCopy);
|
||||
}
|
||||
|
||||
return insRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if no element with the given key existed
|
||||
*/
|
||||
bool StrCpyMap_erase(StrCpyMap* this, const char* eraseKey)
|
||||
{
|
||||
bool eraseRes;
|
||||
void* elemKey;
|
||||
void* elemValue;
|
||||
|
||||
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, eraseKey);
|
||||
if(!treeElem)
|
||||
{ // element not found
|
||||
return false;
|
||||
}
|
||||
|
||||
elemKey = treeElem->key;
|
||||
elemValue = treeElem->value;
|
||||
|
||||
eraseRes = PointerRBTree_erase( (RBTree*)this, eraseKey);
|
||||
if(eraseRes)
|
||||
{ // treeElem has been erased
|
||||
kfree(elemKey);
|
||||
kfree(elemValue);
|
||||
}
|
||||
|
||||
return eraseRes;
|
||||
}
|
||||
|
||||
size_t StrCpyMap_length(StrCpyMap* this)
|
||||
{
|
||||
return PointerRBTree_length( (RBTree*)this);
|
||||
}
|
||||
|
||||
|
||||
void StrCpyMap_clear(StrCpyMap* this)
|
||||
{
|
||||
while(this->rbTree.length)
|
||||
{
|
||||
RBTreeElem* root = container_of(this->rbTree.treeroot.rb_node, RBTreeElem, treenode);
|
||||
StrCpyMap_erase(this, root->key);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*STRCPYMAP_H_*/
|
||||
45
client_module/source/common/toolkit/tree/StrCpyMapIter.h
Normal file
45
client_module/source/common/toolkit/tree/StrCpyMapIter.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef STRCPYMAPITER_H_
|
||||
#define STRCPYMAPITER_H_
|
||||
|
||||
#include "StrCpyMap.h"
|
||||
|
||||
struct StrCpyMapIter;
|
||||
typedef struct StrCpyMapIter StrCpyMapIter;
|
||||
|
||||
static inline void StrCpyMapIter_init(StrCpyMapIter* this, StrCpyMap* map, RBTreeElem* treeElem);
|
||||
static inline char* StrCpyMapIter_next(StrCpyMapIter* this);
|
||||
static inline char* StrCpyMapIter_key(StrCpyMapIter* this);
|
||||
static inline char* StrCpyMapIter_value(StrCpyMapIter* this);
|
||||
static inline bool StrCpyMapIter_end(StrCpyMapIter* this);
|
||||
|
||||
struct StrCpyMapIter
|
||||
{
|
||||
RBTreeIter rbTreeIter;
|
||||
};
|
||||
|
||||
void StrCpyMapIter_init(StrCpyMapIter* this, StrCpyMap* map, RBTreeElem* treeElem)
|
||||
{
|
||||
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
|
||||
}
|
||||
|
||||
char* StrCpyMapIter_next(StrCpyMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_next( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
char* StrCpyMapIter_key(StrCpyMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_key( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
char* StrCpyMapIter_value(StrCpyMapIter* this)
|
||||
{
|
||||
return (char*)PointerRBTreeIter_value( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
bool StrCpyMapIter_end(StrCpyMapIter* this)
|
||||
{
|
||||
return PointerRBTreeIter_end( (RBTreeIter*)this);
|
||||
}
|
||||
|
||||
#endif /*STRCPYMAPITER_H_*/
|
||||
89
client_module/source/common/toolkit/vector/Int64CpyVec.h
Normal file
89
client_module/source/common/toolkit/vector/Int64CpyVec.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef INT64CPYVEC_H_
|
||||
#define INT64CPYVEC_H_
|
||||
|
||||
#include <common/toolkit/list/Int64CpyList.h>
|
||||
|
||||
/**
|
||||
* Note: Derived from the corresponding list. Use the list iterator for read-only access
|
||||
*/
|
||||
|
||||
struct Int64CpyVec;
|
||||
typedef struct Int64CpyVec Int64CpyVec;
|
||||
|
||||
static inline void Int64CpyVec_init(Int64CpyVec* this);
|
||||
static inline void Int64CpyVec_uninit(Int64CpyVec* this);
|
||||
static inline void Int64CpyVec_append(Int64CpyVec* this, int64_t value);
|
||||
static inline size_t Int64CpyVec_length(Int64CpyVec* this);
|
||||
static inline void Int64CpyVec_clear(Int64CpyVec* this);
|
||||
|
||||
// getters & setters
|
||||
static inline int64_t Int64CpyVec_at(Int64CpyVec* this, size_t index);
|
||||
|
||||
|
||||
struct Int64CpyVec
|
||||
{
|
||||
Int64CpyList Int64CpyList;
|
||||
|
||||
int64_t** vecArray;
|
||||
size_t vecArrayLen;
|
||||
};
|
||||
|
||||
|
||||
void Int64CpyVec_init(Int64CpyVec* this)
|
||||
{
|
||||
Int64CpyList_init( (Int64CpyList*)this);
|
||||
|
||||
this->vecArrayLen = 4;
|
||||
this->vecArray = (int64_t**)os_kmalloc(
|
||||
this->vecArrayLen * sizeof(int64_t*) );
|
||||
}
|
||||
|
||||
void Int64CpyVec_uninit(Int64CpyVec* this)
|
||||
{
|
||||
kfree(this->vecArray);
|
||||
|
||||
Int64CpyList_uninit( (Int64CpyList*)this);
|
||||
}
|
||||
|
||||
void Int64CpyVec_append(Int64CpyVec* this, int64_t value)
|
||||
{
|
||||
PointerListElem* lastElem;
|
||||
int64_t* lastElemValuePointer;
|
||||
|
||||
Int64CpyList_append( (Int64CpyList*)this, value);
|
||||
|
||||
// check if we have enough buffer space for new elem
|
||||
if(Int64CpyList_length( (Int64CpyList*)this) > this->vecArrayLen)
|
||||
{ // double vector array size (create new, copy, exchange, delete old)
|
||||
int64_t** newVecArray =
|
||||
(int64_t**)os_kmalloc(this->vecArrayLen*sizeof(int64_t*)*2);
|
||||
memcpy(newVecArray, this->vecArray, this->vecArrayLen*sizeof(int64_t*) );
|
||||
kfree(this->vecArray);
|
||||
this->vecArrayLen = this->vecArrayLen * 2;
|
||||
this->vecArray = newVecArray;
|
||||
}
|
||||
|
||||
// get last elem and add the valuePointer to the array
|
||||
lastElem = PointerList_getTail( (PointerList*)this);
|
||||
lastElemValuePointer = (int64_t*)lastElem->valuePointer;
|
||||
(this->vecArray)[Int64CpyList_length( (Int64CpyList*)this)-1] = lastElemValuePointer;
|
||||
}
|
||||
|
||||
size_t Int64CpyVec_length(Int64CpyVec* this)
|
||||
{
|
||||
return Int64CpyList_length( (Int64CpyList*)this);
|
||||
}
|
||||
|
||||
int64_t Int64CpyVec_at(Int64CpyVec* this, size_t index)
|
||||
{
|
||||
BEEGFS_BUG_ON_DEBUG(index >= Int64CpyVec_length(this), "Index out of bounds");
|
||||
|
||||
return *(this->vecArray[index]);
|
||||
}
|
||||
|
||||
void Int64CpyVec_clear(Int64CpyVec* this)
|
||||
{
|
||||
Int64CpyList_clear( (Int64CpyList*)this);
|
||||
}
|
||||
|
||||
#endif /*INT64CPYVEC_H_*/
|
||||
89
client_module/source/common/toolkit/vector/StrCpyVec.h
Normal file
89
client_module/source/common/toolkit/vector/StrCpyVec.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef STRCPYVEC_H_
|
||||
#define STRCPYVEC_H_
|
||||
|
||||
#include <common/toolkit/list/StrCpyList.h>
|
||||
|
||||
/**
|
||||
* Note: Derived from the corresponding list. Use the list iterator for read-only access
|
||||
*/
|
||||
|
||||
struct StrCpyVec;
|
||||
typedef struct StrCpyVec StrCpyVec;
|
||||
|
||||
static inline void StrCpyVec_init(StrCpyVec* this);
|
||||
static inline void StrCpyVec_uninit(StrCpyVec* this);
|
||||
static inline void StrCpyVec_append(StrCpyVec* this, const char* valuePointer);
|
||||
static inline size_t StrCpyVec_length(StrCpyVec* this);
|
||||
static inline void StrCpyVec_clear(StrCpyVec* this);
|
||||
|
||||
|
||||
// getters & setters
|
||||
static inline char* StrCpyVec_at(StrCpyVec* this, size_t index);
|
||||
|
||||
|
||||
struct StrCpyVec
|
||||
{
|
||||
StrCpyList strCpyList;
|
||||
|
||||
char** vecArray;
|
||||
size_t vecArrayLen;
|
||||
};
|
||||
|
||||
|
||||
void StrCpyVec_init(StrCpyVec* this)
|
||||
{
|
||||
StrCpyList_init( (StrCpyList*)this);
|
||||
|
||||
this->vecArrayLen = 4;
|
||||
this->vecArray = (char**)os_kmalloc(
|
||||
this->vecArrayLen * sizeof(char*) );
|
||||
}
|
||||
|
||||
void StrCpyVec_uninit(StrCpyVec* this)
|
||||
{
|
||||
kfree(this->vecArray);
|
||||
|
||||
StrCpyList_uninit( (StrCpyList*)this);
|
||||
}
|
||||
|
||||
void StrCpyVec_append(StrCpyVec* this, const char* valuePointer)
|
||||
{
|
||||
PointerListElem* lastElem;
|
||||
char* lastElemValuePointer;
|
||||
|
||||
StrCpyList_append( (StrCpyList*)this, valuePointer);
|
||||
|
||||
// check if we have enough buffer space for new elem
|
||||
if(StrCpyList_length( (StrCpyList*)this) > this->vecArrayLen)
|
||||
{ // double vector array size (create new, copy, exchange, delete old)
|
||||
char** newVecArray = (char**)os_kmalloc(this->vecArrayLen*sizeof(char*)*2);
|
||||
memcpy(newVecArray, this->vecArray, this->vecArrayLen*sizeof(char*) );
|
||||
kfree(this->vecArray);
|
||||
this->vecArrayLen = this->vecArrayLen * 2;
|
||||
this->vecArray = newVecArray;
|
||||
}
|
||||
|
||||
// get last elem and add the valuePointer to the array
|
||||
lastElem = PointerList_getTail( (PointerList*)this);
|
||||
lastElemValuePointer = (char*)lastElem->valuePointer;
|
||||
(this->vecArray)[StrCpyList_length( (StrCpyList*)this)-1] = lastElemValuePointer;
|
||||
}
|
||||
|
||||
size_t StrCpyVec_length(StrCpyVec* this)
|
||||
{
|
||||
return StrCpyList_length( (StrCpyList*)this);
|
||||
}
|
||||
|
||||
char* StrCpyVec_at(StrCpyVec* this, size_t index)
|
||||
{
|
||||
BEEGFS_BUG_ON_DEBUG(index >= StrCpyVec_length(this), "Index out of bounds");
|
||||
|
||||
return (this->vecArray)[index];
|
||||
}
|
||||
|
||||
void StrCpyVec_clear(StrCpyVec* this)
|
||||
{
|
||||
StrCpyList_clear( (StrCpyList*)this);
|
||||
}
|
||||
|
||||
#endif /*STRCPYVEC_H_*/
|
||||
90
client_module/source/common/toolkit/vector/UInt16Vec.h
Normal file
90
client_module/source/common/toolkit/vector/UInt16Vec.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef UINT16VEC_H_
|
||||
#define UINT16VEC_H_
|
||||
|
||||
#include <common/toolkit/list/UInt16List.h>
|
||||
|
||||
|
||||
struct UInt16Vec;
|
||||
typedef struct UInt16Vec UInt16Vec;
|
||||
|
||||
static inline void UInt16Vec_init(UInt16Vec* this);
|
||||
static inline void UInt16Vec_uninit(UInt16Vec* this);
|
||||
static inline void UInt16Vec_append(UInt16Vec* this, uint16_t value);
|
||||
static inline size_t UInt16Vec_length(UInt16Vec* this);
|
||||
static inline void UInt16Vec_clear(UInt16Vec* this);
|
||||
|
||||
// getters & setters
|
||||
static inline uint16_t UInt16Vec_at(UInt16Vec* this, size_t index);
|
||||
|
||||
|
||||
/**
|
||||
* Note: Derived from the corresponding list. Use the list iterator for read-only access
|
||||
*/
|
||||
struct UInt16Vec
|
||||
{
|
||||
UInt16List UInt16List;
|
||||
|
||||
uint16_t* vecArray;
|
||||
size_t vecArrayLen;
|
||||
};
|
||||
|
||||
|
||||
void UInt16Vec_init(UInt16Vec* this)
|
||||
{
|
||||
UInt16List_init( (UInt16List*)this);
|
||||
|
||||
this->vecArrayLen = 4;
|
||||
this->vecArray = (uint16_t*)os_kmalloc(this->vecArrayLen * sizeof(uint16_t) );
|
||||
}
|
||||
|
||||
void UInt16Vec_uninit(UInt16Vec* this)
|
||||
{
|
||||
kfree(this->vecArray);
|
||||
|
||||
UInt16List_uninit( (UInt16List*)this);
|
||||
}
|
||||
|
||||
void UInt16Vec_append(UInt16Vec* this, uint16_t value)
|
||||
{
|
||||
size_t newListLen;
|
||||
|
||||
UInt16List_append( (UInt16List*)this, value);
|
||||
|
||||
newListLen = UInt16List_length( (UInt16List*)this);
|
||||
|
||||
// check if we have enough buffer space for new elem
|
||||
|
||||
if(newListLen > this->vecArrayLen)
|
||||
{ // double vector array size: alloc new, copy values, delete old, switch to new
|
||||
uint16_t* newVecArray = (uint16_t*)os_kmalloc(this->vecArrayLen * sizeof(uint16_t) * 2);
|
||||
memcpy(newVecArray, this->vecArray, this->vecArrayLen * sizeof(uint16_t) );
|
||||
|
||||
kfree(this->vecArray);
|
||||
|
||||
this->vecArrayLen = this->vecArrayLen * 2;
|
||||
this->vecArray = newVecArray;
|
||||
}
|
||||
|
||||
// add value to last array elem (determine last used index based on list length)
|
||||
|
||||
(this->vecArray)[newListLen-1] = value;
|
||||
}
|
||||
|
||||
size_t UInt16Vec_length(UInt16Vec* this)
|
||||
{
|
||||
return UInt16List_length( (UInt16List*)this);
|
||||
}
|
||||
|
||||
uint16_t UInt16Vec_at(UInt16Vec* this, size_t index)
|
||||
{
|
||||
BEEGFS_BUG_ON_DEBUG(index >= UInt16Vec_length(this), "Index out of bounds");
|
||||
|
||||
return this->vecArray[index];
|
||||
}
|
||||
|
||||
void UInt16Vec_clear(UInt16Vec* this)
|
||||
{
|
||||
UInt16List_clear( (UInt16List*)this);
|
||||
}
|
||||
|
||||
#endif /* UINT16VEC_H_ */
|
||||
92
client_module/source/common/toolkit/vector/UInt8Vec.h
Normal file
92
client_module/source/common/toolkit/vector/UInt8Vec.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifndef UINT8VEC_H_
|
||||
#define UINT8VEC_H_
|
||||
|
||||
#include <common/toolkit/list/UInt8List.h>
|
||||
|
||||
|
||||
struct UInt8Vec;
|
||||
typedef struct UInt8Vec UInt8Vec;
|
||||
|
||||
static inline void UInt8Vec_init(UInt8Vec* this);
|
||||
static inline void UInt8Vec_uninit(UInt8Vec* this);
|
||||
static inline void UInt8Vec_append(UInt8Vec* this, uint8_t value);
|
||||
static inline size_t UInt8Vec_length(UInt8Vec* this);
|
||||
static inline void UInt8Vec_clear(UInt8Vec* this);
|
||||
|
||||
// getters & setters
|
||||
static inline uint8_t UInt8Vec_at(UInt8Vec* this, size_t index);
|
||||
|
||||
|
||||
/**
|
||||
* Note: Derived from the corresponding list. Use the list iterator for read-only access
|
||||
*/
|
||||
struct UInt8Vec
|
||||
{
|
||||
UInt8List UInt8List;
|
||||
|
||||
uint8_t* vecArray;
|
||||
size_t vecArrayLen;
|
||||
};
|
||||
|
||||
|
||||
void UInt8Vec_init(UInt8Vec* this)
|
||||
{
|
||||
UInt8List_init( (UInt8List*)this);
|
||||
|
||||
this->vecArrayLen = 4;
|
||||
this->vecArray = (uint8_t*)os_kmalloc(this->vecArrayLen * sizeof(uint8_t) );
|
||||
}
|
||||
|
||||
void UInt8Vec_uninit(UInt8Vec* this)
|
||||
{
|
||||
kfree(this->vecArray);
|
||||
|
||||
UInt8List_uninit( (UInt8List*)this);
|
||||
}
|
||||
|
||||
void UInt8Vec_append(UInt8Vec* this, uint8_t value)
|
||||
{
|
||||
size_t newListLen;
|
||||
|
||||
UInt8List_append( (UInt8List*)this, value);
|
||||
|
||||
newListLen = UInt8List_length( (UInt8List*)this);
|
||||
|
||||
// check if we have enough buffer space for new elem
|
||||
|
||||
if(newListLen > this->vecArrayLen)
|
||||
{ // double vector array size: alloc new, copy values, delete old, switch to new
|
||||
uint8_t* newVecArray = (uint8_t*)os_kmalloc(this->vecArrayLen * sizeof(uint8_t) * 2);
|
||||
memcpy(newVecArray, this->vecArray, this->vecArrayLen * sizeof(uint8_t) );
|
||||
|
||||
kfree(this->vecArray);
|
||||
|
||||
this->vecArrayLen = this->vecArrayLen * 2;
|
||||
this->vecArray = newVecArray;
|
||||
}
|
||||
|
||||
// add value to last array elem (determine last used index based on list length)
|
||||
|
||||
(this->vecArray)[newListLen-1] = value;
|
||||
}
|
||||
|
||||
size_t UInt8Vec_length(UInt8Vec* this)
|
||||
{
|
||||
return UInt8List_length( (UInt8List*)this);
|
||||
}
|
||||
|
||||
uint8_t UInt8Vec_at(UInt8Vec* this, size_t index)
|
||||
{
|
||||
BEEGFS_BUG_ON_DEBUG(index >= UInt8Vec_length(this), "Index out of bounds");
|
||||
|
||||
return this->vecArray[index];
|
||||
}
|
||||
|
||||
void UInt8Vec_clear(UInt8Vec* this)
|
||||
{
|
||||
UInt8List_clear( (UInt8List*)this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* UINT8VEC_H_ */
|
||||
Reference in New Issue
Block a user