summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2014-08-17 19:09:19 +0200
committerYorhel <git@yorhel.nl>2014-08-17 19:11:04 +0200
commite2566325af7c77f7621639a6d5fca8b2a3bb914e (patch)
tree744a4d80a314e58b66c003365946ea054e3757ec
parent93946b6ec565077367cedb2a70fc640aa8fa6953 (diff)
Add functions to construct YPC values
This code is mostly untested.
-rw-r--r--Makefile.am7
-rw-r--r--lib/internal.h1
-rw-r--r--lib/util/byteswap.h48
-rw-r--r--lib/val/ypc_add_bin.c16
-rw-r--r--lib/val/ypc_add_float.c15
-rw-r--r--lib/val/ypc_add_int.c27
-rw-r--r--lib/val/ypc_add_raw.c10
-rw-r--r--lib/val/ypc_add_textn.c12
-rw-r--r--lib/val/ypc_val_resize.c16
-rw-r--r--lib/ypc.h22
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;
+}
+
diff --git a/lib/ypc.h b/lib/ypc.h
index de2b7be..17bc5a2 100644
--- a/lib/ypc.h
+++ b/lib/ypc.h
@@ -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