X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=blobdiff_plain;f=src%2Futils%2Fproto.c;h=51c2ed8c45361f4625c4e7dc6d956594d7a96a7e;hp=404d2a30ec5d2dabd270ab393bd9e262ec429017;hb=57331451a2eb8cbcd812e7428ab1ded6d312365f;hpb=edba65afec8c547fb6c02346eda68595ce9a5839 diff --git a/src/utils/proto.c b/src/utils/proto.c index 404d2a3..51c2ed8 100644 --- a/src/utils/proto.c +++ b/src/utils/proto.c @@ -25,12 +25,19 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core/data.h" +#include "core/time.h" #include "utils/error.h" #include "utils/proto.h" -#include +#include #include +#include #include #include @@ -39,129 +46,229 @@ #include /* - * public API + * private helper functions */ -int -sdb_proto_select(int fd, int type) -{ - fd_set fds; - fd_set *readfds = NULL; - fd_set *writefds = NULL; - fd_set *exceptfds = NULL; +/* In case there's not enough buffer space, the marshal functions have to + * return the number of bytes that would have been written if enough space had + * been available. */ - if (fd < 0) { - errno = EBADF; - return -1; +static ssize_t +marshal_int(char *buf, size_t buf_len, int64_t v) +{ + if (buf_len >= sizeof(v)) { +#if __BYTE_ORDER != __BIG_ENDIAN + v = (((int64_t)ntohl((int32_t)v)) << 32) + + ((int64_t)ntohl((int32_t)(v >> 32))); +#endif + memcpy(buf, &v, sizeof(v)); } + return sizeof(v); +} /* marshal_int */ - FD_ZERO(&fds); - - switch (type) { - case SDB_PROTO_SELECTIN: - readfds = &fds; - break; - case SDB_PROTO_SELECTOUT: - writefds = &fds; - break; - case SDB_PROTO_SELECTERR: - exceptfds = &fds; - break; - default: - errno = EINVAL; - return -1; - } +static ssize_t +marshal_double(char *buf, size_t buf_len, double v) +{ + uint64_t t = 0; + assert(sizeof(v) == sizeof(t)); + memcpy(&t, &v, sizeof(v)); +#if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN + t = (((int64_t)ntohl((int32_t)t)) << 32) + + ((int64_t)ntohl((int32_t)(t >> 32))); +#endif + if (buf_len >= sizeof(t)) + memcpy(buf, &t, sizeof(t)); + return sizeof(t); +} /* marshal_double */ + +static ssize_t +marshal_datetime(char *buf, size_t buf_len, sdb_time_t v) +{ + return marshal_int(buf, buf_len, (int64_t)v); +} /* marshal_datetime */ - FD_SET(fd, &fds); +static ssize_t +marshal_binary(char *buf, size_t buf_len, size_t len, const unsigned char *v) +{ + uint32_t tmp = htonl((uint32_t)len); + if (buf_len >= len) { + memcpy(buf, &tmp, sizeof(tmp)); + memcpy(buf + sizeof(tmp), v, len); + } + return sizeof(tmp) + len; +} /* marshal_binary */ - while (42) { - int n; - errno = 0; - n = select(fd + 1, readfds, writefds, exceptfds, NULL); +static ssize_t +marshal_string(char *buf, size_t buf_len, const char *v) +{ + /* The actual string including the terminating null byte. */ + return marshal_binary(buf, buf_len, + strlen(v) + 1, (const unsigned char *)v); +} /* marshal_string */ - if ((n < 0) && (errno != EINTR)) - return (ssize_t)n; - if (n > 0) - break; - } - return 0; -} /* sdb_proto_select */ +/* + * public API + */ ssize_t -sdb_proto_send(int fd, size_t msg_len, const char *msg) +sdb_proto_marshal(char *buf, size_t buf_len, uint32_t code, + uint32_t msg_len, const char *msg) { - const char *buf; - size_t len; + size_t len = 2 * sizeof(uint32_t) + msg_len; + uint32_t tmp; - if ((fd < 0) || (msg_len && (! msg))) + if (buf_len < 2 * sizeof(uint32_t)) return -1; - if (! msg_len) - return 0; + if (buf_len < len) /* crop message */ + msg_len -= (uint32_t)(len - buf_len); - buf = msg; - len = msg_len; - while (len > 0) { - ssize_t status; + tmp = htonl(code); + memcpy(buf, &tmp, sizeof(tmp)); + tmp = htonl(msg_len); + memcpy(buf + sizeof(tmp), &tmp, sizeof(tmp)); - if (sdb_proto_select(fd, SDB_PROTO_SELECTOUT)) - return -1; + if (msg_len) + memcpy(buf + 2 * sizeof(tmp), msg, msg_len); + return len; +} /* sdb_proto_marshal */ - errno = 0; - status = write(fd, buf, len); - if (status < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) - continue; - if (errno == EINTR) - continue; +ssize_t +sdb_proto_marshal_data(char *buf, size_t buf_len, sdb_data_t *datum) +{ + ssize_t len = 0, n = 0; + uint32_t tmp; + size_t i; + int type; + + if (buf_len >= sizeof(tmp)) { + tmp = htonl((uint32_t)datum->type); + memcpy(buf, &tmp, sizeof(tmp)); + buf += sizeof(tmp); + buf_len -= sizeof(tmp); + } + else + buf_len = 0; + len += sizeof(tmp); + + if (datum->type == SDB_TYPE_NULL) + return len; + + if (datum->type == SDB_TYPE_INTEGER) + n = marshal_int(buf, buf_len, datum->data.integer); + else if (datum->type == SDB_TYPE_DECIMAL) + n = marshal_double(buf, buf_len, datum->data.decimal); + else if (datum->type == SDB_TYPE_STRING) + n = marshal_string(buf, buf_len, datum->data.string); + else if (datum->type == SDB_TYPE_DATETIME) + n = marshal_datetime(buf, buf_len, datum->data.datetime); + else if (datum->type == SDB_TYPE_BINARY) + n = marshal_binary(buf, buf_len, + datum->data.binary.length, datum->data.binary.datum); + else if (datum->type == SDB_TYPE_REGEX) + n = marshal_string(buf, buf_len, datum->data.re.raw); + + if (n < 0) + return n; + else if (n > 0) + return len + n; + + if (! (datum->type & SDB_TYPE_ARRAY)) { + errno = EINVAL; + return -1; + } - return status; + /* arrays */ + if (buf_len >= sizeof(tmp)) { + tmp = htonl((uint32_t)datum->data.array.length); + memcpy(buf, &tmp, sizeof(tmp)); + buf += sizeof(tmp); + buf_len -= sizeof(tmp); + } + else + buf_len = 0; + len += sizeof(tmp); + + type = datum->type & 0xff; + for (i = 0; i < datum->data.array.length; ++i) { + if (type == SDB_TYPE_INTEGER) { + int64_t *v = datum->data.array.values; + n = marshal_int(buf, buf_len, v[i]); + } + else if (type == SDB_TYPE_DECIMAL) { + double *v = datum->data.array.values; + n = marshal_double(buf, buf_len, v[i]); + } + else if (type == SDB_TYPE_STRING) { + char **v = datum->data.array.values; + n = marshal_string(buf, buf_len, v[i]); + } + else if (type == SDB_TYPE_DATETIME) { + sdb_time_t *v = datum->data.array.values; + n = marshal_datetime(buf, buf_len, v[i]); + } + else if (type == SDB_TYPE_BINARY) { + struct { + size_t length; + unsigned char *datum; + } *v = datum->data.array.values; + n = marshal_binary(buf, buf_len, v[i].length, v[i].datum); + } + else if (type == SDB_TYPE_REGEX) { + struct { + char *raw; + regex_t regex; + } *v = datum->data.array.values; + n = marshal_string(buf, buf_len, v[i].raw); + } + else { + errno = EINVAL; + return -1; } - len -= (size_t)status; - buf += status; + if (n < 0) + return -1; + if (buf_len >= (size_t)n) { + buf += n; + buf_len -= n; + } + else + buf_len = 0; + len += n; } + return len; +} /* sdb_proto_marshal_data */ - return (ssize_t)msg_len; -} /* sdb_proto_send */ - -ssize_t -sdb_proto_send_msg(int fd, uint32_t code, - uint32_t msg_len, const char *msg) +int +sdb_proto_unmarshal_header(const char *buf, size_t buf_len, + uint32_t *code, uint32_t *msg_len) { - size_t len = 2 * sizeof(uint32_t) + msg_len; - char buffer[len]; - uint32_t tmp; - tmp = htonl(code); - memcpy(buffer, &tmp, sizeof(tmp)); - tmp = htonl(msg_len); - memcpy(buffer + sizeof(tmp), &tmp, sizeof(tmp)); + if (buf_len < 2 * sizeof(uint32_t)) + return -1; + tmp = sdb_proto_unmarshal_int(buf, buf_len); + if (code) + *code = tmp; + tmp = sdb_proto_unmarshal_int(buf + sizeof(uint32_t), + buf_len - sizeof(uint32_t)); if (msg_len) - memcpy(buffer + 2 * sizeof(tmp), msg, msg_len); - - return sdb_proto_send(fd, len, buffer); -} /* sdb_proto_send_msg */ + *msg_len = tmp; + return 0; +} /* sdb_proto_unmarshal_header */ uint32_t -sdb_proto_get_int(sdb_strbuf_t *buf, size_t offset) +sdb_proto_unmarshal_int(const char *buf, size_t buf_len) { - const char *data; uint32_t n; - if (! buf) - return UINT32_MAX; - /* not enough data to read */ - if (offset + sizeof(uint32_t) > sdb_strbuf_len(buf)) + if (buf_len < sizeof(n)) return UINT32_MAX; - data = sdb_strbuf_string(buf); - data += offset; - memcpy(&n, data, sizeof(n)); + memcpy(&n, buf, sizeof(n)); return ntohl(n); -} /* sdb_proto_get_int */ +} /* sdb_proto_unmarshal_int */ /* vim: set tw=78 sw=4 ts=4 noexpandtab : */