diff options
author | Yorhel <git@yorhel.nl> | 2014-08-17 19:09:19 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2014-08-17 19:11:04 +0200 |
commit | e2566325af7c77f7621639a6d5fca8b2a3bb914e (patch) | |
tree | 744a4d80a314e58b66c003365946ea054e3757ec | |
parent | 93946b6ec565077367cedb2a70fc640aa8fa6953 (diff) |
Add functions to construct YPC values
This code is mostly untested.
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | lib/internal.h | 1 | ||||
-rw-r--r-- | lib/util/byteswap.h | 48 | ||||
-rw-r--r-- | lib/val/ypc_add_bin.c | 16 | ||||
-rw-r--r-- | lib/val/ypc_add_float.c | 15 | ||||
-rw-r--r-- | lib/val/ypc_add_int.c | 27 | ||||
-rw-r--r-- | lib/val/ypc_add_raw.c | 10 | ||||
-rw-r--r-- | lib/val/ypc_add_textn.c | 12 | ||||
-rw-r--r-- | lib/val/ypc_val_resize.c | 16 | ||||
-rw-r--r-- | lib/ypc.h | 22 |
10 files changed, 173 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 9d2e6f3..b870456 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,13 +28,20 @@ libypc_la_SOURCES=\ lib/util/str2sockaddr_port.c\ lib/util/tweetnacl.c\ lib/util/utf8.c\ + lib/val/ypc_add_bin.c\ + lib/val/ypc_add_float.c\ + lib/val/ypc_add_int.c\ + lib/val/ypc_add_raw.c\ + lib/val/ypc_add_textn.c\ lib/val/ypc_val_parse.c\ + lib/val/ypc_val_resize.c\ lib/ypc_init.c\ lib/ypc_msg_free.c\ lib/ypc_msg_new.c EXTRA_DIST=\ lib/internal.h\ + lib/util/byteswap.h\ lib/util/str2sockaddr.h\ lib/util/tweetnacl.h\ lib/util/utf8.h diff --git a/lib/internal.h b/lib/internal.h index e0a2d9f..2db57ec 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -80,7 +80,6 @@ typedef enum { } ypc_state; -typedef struct ypc_msg ypc_msg; struct ypc_msg { /* Interior pointers, used in either the send or receive queue. */ ypc_msg *next, *prev; diff --git a/lib/util/byteswap.h b/lib/util/byteswap.h new file mode 100644 index 0000000..99981a6 --- /dev/null +++ b/lib/util/byteswap.h @@ -0,0 +1,48 @@ +#include "../internal.h" + +/* Run-time endianness detection is easier and more reliable than trying to + * figure it out from preprocessor defines. A sane compiler should optimize the + * run-time code away when inlined, so there should be no overhead from + * checking endianness. */ +static inline bool ypc__bigendian() { + union { uint16_t l; char c[2]; } u; + u.l = 1; + return u.c[0] == 0; +} + + +static inline uint16_t ypc__swap16(uint16_t v) { +#if defined(_MSC_VER) + return _byteswap_short(v); +#else + return (v>>8) | (v<<8); +#endif +} + + +static inline uint32_t ypc__swap32(uint32_t v) { +#if defined(_MSC_VER) + return _byteswap_ulong(v); +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + return __builtin_bswap32(v); +#else + return ypc__swap16(v >> 16) | ((uint32_t)ypc__swap16(v) << 16); +#endif +} + + +static inline uint32_t ypc__swap64(uint64_t v) { +#if defined(_MSC_VER) + return _byteswap_uint64(v); +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + return __builtin_bswap64(v); +#else + return ypc__swap32(v >> 32) | ((uint64_t)ypc__swap32(v) << 32); +#endif +} + + +/* Conversion between host<->network byte order */ +static inline uint16_t ypc__hn16(uint16_t v) { return ypc__bigendian() ? v : ypc__swap16(v); } +static inline uint32_t ypc__hn32(uint32_t v) { return ypc__bigendian() ? v : ypc__swap32(v); } +static inline uint64_t ypc__hn64(uint64_t v) { return ypc__bigendian() ? v : ypc__swap64(v); } diff --git a/lib/val/ypc_add_bin.c b/lib/val/ypc_add_bin.c new file mode 100644 index 0000000..14bcd84 --- /dev/null +++ b/lib/val/ypc_add_bin.c @@ -0,0 +1,16 @@ +#include "../internal.h" + +YPC_EXPORT int ypc_add_bin(ypc_val *v, const uint8_t *buf, size_t len) { + if(len >= 1<<24) + return -1; + size_t want = v->len + len + 4; + if(v->size < want && ypc_val_resize(v, want) != 0) + return -1; + v->buf[v->len++] = 8; + v->buf[v->len++] = len >> 16; + v->buf[v->len++] = len >> 8; + v->buf[v->len++] = len; + memcpy(v->buf+v->len, buf, len); + v->len += len; + return 0; +} diff --git a/lib/val/ypc_add_float.c b/lib/val/ypc_add_float.c new file mode 100644 index 0000000..5fbf740 --- /dev/null +++ b/lib/val/ypc_add_float.c @@ -0,0 +1,15 @@ +#include "../internal.h" +#include "../util/byteswap.h" + +YPC_EXPORT int ypc_add_float(ypc_val *v, double d) { + if(v->size < v->len+9 && ypc_val_resize(v, v->len+9)) + return -1; + v->buf[v->len++] = 7; + + uint64_t n; + memcpy(&n, &d, 8); + n = ypc__hn64(n); + memcpy(v->buf+v->len, &n, 8); + v->len += 8; + return 0; +} diff --git a/lib/val/ypc_add_int.c b/lib/val/ypc_add_int.c new file mode 100644 index 0000000..bb31983 --- /dev/null +++ b/lib/val/ypc_add_int.c @@ -0,0 +1,27 @@ +#include "../internal.h" +#include "../util/byteswap.h" + +YPC_EXPORT int ypc_add_int(ypc_val *v, int64_t i) { + if(v->size < v->len + 9 && ypc_val_resize(v, v->len+9) != 0) + return -1; + if(i >= INT8_MIN && i <= INT8_MAX) { + v->buf[v->len++] = 3; + v->buf[v->len++] = i; + } else if(i >= INT16_MIN && i <= INT16_MAX) { + v->buf[v->len++] = 4; + uint16_t n = ypc__hn16(i); + memcpy(v->buf+v->len, &n, 2); + v->len += 2; + } else if(i >= INT32_MIN && i <= INT32_MAX) { + v->buf[v->len++] = 5; + uint32_t n = ypc__hn32(i); + memcpy(v->buf+v->len, &n, 4); + v->len += 4; + } else { + v->buf[v->len++] = 6; + uint64_t n = ypc__hn64(i); + memcpy(v->buf+v->len, &n, 8); + v->len += 8; + } + return 0; +} diff --git a/lib/val/ypc_add_raw.c b/lib/val/ypc_add_raw.c new file mode 100644 index 0000000..b6beb39 --- /dev/null +++ b/lib/val/ypc_add_raw.c @@ -0,0 +1,10 @@ +#include "../internal.h" + +YPC_EXPORT int ypc_add_raw(ypc_val *v, const uint8_t *buf, size_t len) { + size_t want = v->len + len; + if(v->size < want && ypc_val_resize(v, want) != 0) + return -1; + memcpy(v->buf+v->len, buf, len); + v->len += len; + return 0; +} diff --git a/lib/val/ypc_add_textn.c b/lib/val/ypc_add_textn.c new file mode 100644 index 0000000..72e57ae --- /dev/null +++ b/lib/val/ypc_add_textn.c @@ -0,0 +1,12 @@ +#include "../internal.h" + +YPC_EXPORT int ypc_add_textn(ypc_val *v, const char *s, size_t len) { + size_t want = v->len+len+2; + if(v->size < want && ypc_val_resize(v, want) != 0) + return -1; + v->buf[v->len++] = 9; + memcpy(v->buf+v->len, s, len); + v->len += len; + v->buf[v->len++] = 0; + return 0; +} diff --git a/lib/val/ypc_val_resize.c b/lib/val/ypc_val_resize.c new file mode 100644 index 0000000..d135285 --- /dev/null +++ b/lib/val/ypc_val_resize.c @@ -0,0 +1,16 @@ +#include "../internal.h" + +#define roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) + +YPC_EXPORT int ypc_val_resize(ypc_val *v, size_t s) { + if(s >= UINT32_MAX/2) + return -1; + v->size = s; + roundup32(v->size); + uint8_t *buf = realloc(v->buf, v->size); + if(!buf) + return -1; + v->buf = buf; + return 0; +} + @@ -12,12 +12,19 @@ #include <stdint.h> #include <stdlib.h> #include <stdbool.h> +#include <string.h> typedef struct ypc ypc; typedef struct ypc_msg ypc_msg; typedef struct ypc_serv ypc_serv; +typedef struct { + uint8_t *buf; + uint32_t size, len; +} ypc_val; + + #define YPC_NONBLOCK 0x01 #define YPC_RECV 0x02 #define YPC_CANREAD 0x04 @@ -59,6 +66,12 @@ YPC_IMPORT int ypc_init(); YPC_IMPORT void ypc_val_parse_init(ypc_val_parser *); YPC_IMPORT int ypc_val_parse(ypc_val_parser *, const uint8_t *, size_t *); +YPC_IMPORT int ypc_val_resize(ypc_val *, size_t); +YPC_IMPORT int ypc_add_raw(ypc_val *, const uint8_t *, size_t); +YPC_IMPORT int ypc_add_int(ypc_val *, int64_t); +YPC_IMPORT int ypc_add_float(ypc_val *, double); +YPC_IMPORT int ypc_add_bin(ypc_val *, const uint8_t *, size_t); +YPC_IMPORT int ypc_add_textn(ypc_val *, const char *, size_t); YPC_IMPORT ypc_msg *ypc_msg_new(const char *, size_t); YPC_IMPORT void ypc_msg_free(ypc_msg *); @@ -84,4 +97,13 @@ YPC_IMPORT void ypc_serv_free(ypc_serv *); #endif +/* Smallish stuff that is better suited for inlining */ +static inline int ypc_val_init(ypc_val *v, size_t size) { v->buf = NULL; v->len = 0; return ypc_val_resize(v, size ? size : 512); } +static inline int ypc_add_null(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\0", 1); } +static inline int ypc_add_bool(ypc_val *v, bool b) { return ypc_add_raw(v, (uint8_t *)(b ? "\2" : "\1"), 1); } +static inline int ypc_add_text(ypc_val *v, const char *t) { return ypc_add_textn(v, t, strlen(t)); } +static inline int ypc_add_array(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\12", 1); } +static inline int ypc_add_map(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\13", 1); } +static inline int ypc_add_close(ypc_val *v) { return ypc_add_raw(v, (uint8_t *)"\14", 1); } + #endif |