summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Garnock-Jones <tonyg@kcbbs.gen.nz>2009-04-25 19:41:56 +0100
committerTony Garnock-Jones <tonyg@kcbbs.gen.nz>2009-04-25 19:41:56 +0100
commit67970c9c56ebd49b57e61d50255b04fa1ac7d27d (patch)
treeec02d63a0a7b8f31b7a0c0426eeaab25f5884e1f
parent8bf174bc0a3d682ff9c8c11435008f1adf3c288f (diff)
downloadrabbitmq-c-github-ask-67970c9c56ebd49b57e61d50255b04fa1ac7d27d.tar.gz
Codegen, codec
-rw-r--r--.hgignore7
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac3
-rw-r--r--examples/Makefile.am4
-rw-r--r--examples/amqp_sendstring.c12
-rw-r--r--librabbitmq/Makefile.am5
-rw-r--r--librabbitmq/amqp.h109
-rw-r--r--librabbitmq/amqp_mem.c102
-rw-r--r--librabbitmq/amqp_private.h48
-rw-r--r--librabbitmq/amqp_table.c143
-rw-r--r--librabbitmq/codegen.py409
-rw-r--r--librabbitmq/f.c13
12 files changed, 678 insertions, 179 deletions
diff --git a/.hgignore b/.hgignore
index 1863fe8..98bc7e3 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,9 +8,10 @@
^missing$
(^|/)\.libs$
(^|/)\.deps$
-\.(o|lo)$
+\.(o|lo|la)$
^librabbitmq/amqp_framing\.[ch]$
-^Makefile(\.in)?$
-^librabbitmq/Makefile(\.in)?$
^config\.h$
+^stamp-h1$
^libtool$
+
+^(|librabbitmq/|examples/)Makefile(\.in)?$
diff --git a/Makefile.am b/Makefile.am
index 7362d88..fc4323c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=librabbitmq
+SUBDIRS=librabbitmq examples
squeakyclean: maintainer-clean
rm -f Makefile.in librabbitmq/Makefile.in
diff --git a/configure.ac b/configure.ac
index 9e27ae0..d158c6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_INIT([librabbitmq],[0.0.1],[tonyg@rabbitmq.com])
-AC_CONFIG_SRCDIR(librabbitmq/f.c)
+AC_CONFIG_SRCDIR(librabbitmq/codegen.py)
AM_INIT_AUTOMAKE
AC_CONFIG_HEADER([config.h])
@@ -30,4 +30,5 @@ AC_SUBST(AMQP_SPEC_JSON_PATH)
AC_OUTPUT(
Makefile
librabbitmq/Makefile
+examples/Makefile
)
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..226294f
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,4 @@
+bin_PROGRAMS = amqp_sendstring
+
+AM_CFLAGS = -I../librabbitmq
+AM_LDFLAGS = ../librabbitmq/librabbitmq.la
diff --git a/examples/amqp_sendstring.c b/examples/amqp_sendstring.c
new file mode 100644
index 0000000..9258f7f
--- /dev/null
+++ b/examples/amqp_sendstring.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <stdint.h>
+#include "amqp.h"
+
+int main(int argc, char const * const *argv) {
+ amqp_connection_state_t conn = amqp_new_connection();
+ amqp_destroy_connection(conn);
+ return 0;
+}
diff --git a/librabbitmq/Makefile.am b/librabbitmq/Makefile.am
index bfbd233..5fec206 100644
--- a/librabbitmq/Makefile.am
+++ b/librabbitmq/Makefile.am
@@ -1,8 +1,9 @@
lib_LTLIBRARIES = librabbitmq.la
-librabbitmq_la_SOURCES = f.c
+librabbitmq_la_SOURCES = amqp_mem.c amqp_table.c
nodist_librabbitmq_la_SOURCES = amqp_framing.c
-librabbitmq_la_INCLUDES = amqp_framing.h
+librabbitmq_la_INCLUDES = amqp_framing.h amqp.h
+noinst_librabbitmq_la_INCLUDES = amqp_private.h
BUILT_SOURCES = amqp_framing.h amqp_framing.c
CLEANFILES = amqp_framing.h amqp_framing.c
diff --git a/librabbitmq/amqp.h b/librabbitmq/amqp.h
new file mode 100644
index 0000000..2554cf8
--- /dev/null
+++ b/librabbitmq/amqp.h
@@ -0,0 +1,109 @@
+#ifndef librabbitmq_amqp_h
+#define librabbitmq_amqp_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int amqp_boolean_t;
+typedef uint32_t amqp_method_number_t;
+typedef uint32_t amqp_flags_t;
+typedef uint16_t amqp_channel_t;
+
+typedef struct amqp_bytes_t_ {
+ size_t len;
+ void *bytes;
+} amqp_bytes_t;
+
+typedef struct amqp_decimal_t_ {
+ int decimals;
+ uint32_t value;
+} amqp_decimal_t;
+
+typedef struct amqp_table_t_ {
+ int num_entries;
+ struct amqp_table_entry_t_ *entries;
+} amqp_table_t;
+
+typedef struct amqp_table_entry_t_ {
+ amqp_bytes_t key;
+ char kind;
+ union {
+ amqp_bytes_t bytes;
+ int32_t i32;
+ amqp_decimal_t decimal;
+ uint64_t u64;
+ amqp_table_t table;
+ } value;
+} amqp_table_entry_t;
+
+typedef struct amqp_pool_blocklist_t_ {
+ int num_blocks;
+ void **blocklist;
+} amqp_pool_blocklist_t;
+
+typedef struct amqp_pool_t_ {
+ size_t pagesize;
+
+ amqp_pool_blocklist_t pages;
+ amqp_pool_blocklist_t large_blocks;
+
+ int next_page;
+ char *alloc_block;
+ size_t alloc_used;
+} amqp_pool_t;
+
+typedef struct amqp_frame_t_ {
+ uint8_t frame_type; /* 0 means no event */
+ amqp_channel_t channel;
+ union {
+ struct {
+ amqp_method_number_t id;
+ void *decoded;
+ } method;
+ struct {
+ uint16_t class_id;
+ void *decoded;
+ } properties;
+ amqp_bytes_t body_fragment;
+ } payload;
+} amqp_frame_t;
+
+#define AMQP_EXCEPTION_CATEGORY_UNKNOWN 0
+#define AMQP_EXCEPTION_CATEGORY_CONNECTION 1
+#define AMQP_EXCEPTION_CATEGORY_CHANNEL 2
+
+/* Opaque struct. */
+typedef struct amqp_connection_state_t_ *amqp_connection_state_t;
+
+extern char const *amqp_version(void);
+
+extern void init_amqp_pool(amqp_pool_t *pool, size_t pagesize);
+extern void recycle_amqp_pool(amqp_pool_t *pool);
+extern void empty_amqp_pool(amqp_pool_t *pool);
+
+extern void *amqp_pool_alloc(amqp_pool_t *pool, size_t amount);
+
+extern amqp_connection_state_t amqp_new_connection(void);
+extern int amqp_tune_connection(amqp_connection_state_t state,
+ int frame_max);
+extern int amqp_destroy_connection(amqp_connection_state_t state);
+
+extern int amqp_handle_input(amqp_connection_state_t state,
+ amqp_pool_t *pool,
+ amqp_bytes_t received_data,
+ amqp_frame_t *decoded_frame);
+
+extern int amqp_send_frame(amqp_connection_state_t state,
+ amqp_pool_t *pool,
+ int (*writer)(int context, void const *buf, size_t len),
+ int context,
+ amqp_frame_t const *frame);
+
+extern int amqp_table_entry_cmp(void const *entry1, void const *entry2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/librabbitmq/amqp_mem.c b/librabbitmq/amqp_mem.c
new file mode 100644
index 0000000..64d06de
--- /dev/null
+++ b/librabbitmq/amqp_mem.c
@@ -0,0 +1,102 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "amqp.h"
+#include "../config.h"
+
+char const *amqp_version(void) {
+ return VERSION; /* defined in config.h */
+}
+
+void init_amqp_pool(amqp_pool_t *pool, size_t pagesize) {
+ pool->pagesize = pagesize ? pagesize : 4096;
+
+ pool->pages.num_blocks = 0;
+ pool->pages.blocklist = NULL;
+
+ pool->large_blocks.num_blocks = 0;
+ pool->large_blocks.blocklist = NULL;
+
+ pool->next_page = 0;
+ pool->alloc_block = NULL;
+ pool->alloc_used = 0;
+}
+
+static void empty_blocklist(amqp_pool_blocklist_t *x) {
+ int i;
+
+ for (i = 0; i < x->num_blocks; i++) {
+ free(x->blocklist[i]);
+ }
+ if (x->blocklist != NULL) {
+ free(x->blocklist);
+ }
+ x->num_blocks = 0;
+ x->blocklist = NULL;
+}
+
+void recycle_amqp_pool(amqp_pool_t *pool) {
+ empty_blocklist(&pool->large_blocks);
+ pool->next_page = 0;
+ pool->alloc_block = NULL;
+ pool->alloc_used = 0;
+}
+
+void empty_amqp_pool(amqp_pool_t *pool) {
+ recycle_amqp_pool(pool);
+ empty_blocklist(&pool->pages);
+}
+
+static void record_pool_block(amqp_pool_blocklist_t *x, void *block) {
+ size_t blocklistlength = sizeof(void *) * (x->num_blocks + 1);
+
+ if (x->blocklist == NULL) {
+ x->blocklist = malloc(blocklistlength);
+ } else {
+ x->blocklist = realloc(x->blocklist, blocklistlength);
+ }
+
+ x->blocklist[x->num_blocks] = block;
+ x->num_blocks++;
+}
+
+void *amqp_pool_alloc(amqp_pool_t *pool, size_t amount) {
+ if (amount == 0) {
+ return NULL;
+ }
+
+ amount = (amount + 7) & (~7); /* round up to nearest 8-byte boundary */
+
+ if (amount > pool->pagesize) {
+ void *result = calloc(1, amount);
+ record_pool_block(&pool->large_blocks, result);
+ return result;
+ }
+
+ if (pool->alloc_block != NULL) {
+ assert(pool->alloc_used <= pool->pagesize);
+
+ if (pool->alloc_used + amount <= pool->pagesize) {
+ void *result = pool->alloc_block + pool->alloc_used;
+ pool->alloc_used += amount;
+ return result;
+ }
+ }
+
+ if (pool->next_page >= pool->pages.num_blocks) {
+ pool->alloc_block = calloc(1, pool->pagesize);
+ record_pool_block(&pool->pages, pool->alloc_block);
+ pool->next_page = pool->pages.num_blocks;
+ } else {
+ pool->alloc_block = pool->pages.blocklist[pool->next_page];
+ pool->next_page++;
+ }
+
+ pool->alloc_used = amount;
+
+ return pool->alloc_block;
+}
diff --git a/librabbitmq/amqp_private.h b/librabbitmq/amqp_private.h
new file mode 100644
index 0000000..4f6628d
--- /dev/null
+++ b/librabbitmq/amqp_private.h
@@ -0,0 +1,48 @@
+#ifndef librabbitmq_amqp_private_h
+#define librabbitmq_amqp_private_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct amqp_connection_state_t_ {
+};
+
+#define CHECK_LIMIT(b, o, l, v) ({ if ((o + l) > (b).len) { return -EFAULT; } (v); })
+#define BUF_AT(b, o) (&(((uint8_t *) (b).bytes)[o]))
+
+#define D_8(b, o) CHECK_LIMIT(b, o, 1, * (uint8_t *) BUF_AT(b, o))
+#define D_16(b, o) CHECK_LIMIT(b, o, 2, ({uint16_t v; memcpy(&v, BUF_AT(b, o), 2); ntohs(v);}))
+#define D_32(b, o) CHECK_LIMIT(b, o, 4, ({uint32_t v; memcpy(&v, BUF_AT(b, o), 4); ntohl(v);}))
+#define D_64(b, o) ({ \
+ uint64_t hi = D_32(b, o); \
+ uint64_t lo = D_32(b, o + 4); \
+ hi << 32 | lo; \
+})
+
+#define D_BYTES(b, o, l) CHECK_LIMIT(b, o, l, BUF_AT(b, o))
+
+#define E_8(b, o, v) CHECK_LIMIT(b, o, 1, * (uint8_t *) BUF_AT(b, o) = (v))
+#define E_16(b, o, v) CHECK_LIMIT(b, o, 2, ({uint16_t vv = htons(v); memcpy(BUF_AT(b, o), &vv, 2);}))
+#define E_32(b, o, v) CHECK_LIMIT(b, o, 4, ({uint32_t vv = htonl(v); memcpy(BUF_AT(b, o), &vv, 4);}))
+#define E_64(b, o, v) ({ \
+ E_32(b, o, (uint32_t) (v >> 32)); \
+ E_32(b, o, (uint32_t) (v & 0xFFFFFFFF)); \
+})
+
+#define E_BYTES(b, o, l, v) CHECK_LIMIT(b, o, l, memcpy(BUF_AT(b, o), (v), (l)))
+
+extern int amqp_decode_table(amqp_bytes_t encoded,
+ amqp_pool_t *pool,
+ amqp_table_t *output,
+ int *offsetptr);
+
+extern int amqp_encode_table(amqp_bytes_t encoded,
+ amqp_table_t *input,
+ int *offsetptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/librabbitmq/amqp_table.c b/librabbitmq/amqp_table.c
new file mode 100644
index 0000000..fac42d9
--- /dev/null
+++ b/librabbitmq/amqp_table.c
@@ -0,0 +1,143 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "amqp.h"
+#include "../config.h"
+#include "amqp_private.h"
+
+#define INITIAL_TABLE_SIZE 16
+
+int amqp_decode_table(amqp_bytes_t encoded,
+ amqp_pool_t *pool,
+ amqp_table_t *output,
+ int *offsetptr)
+{
+ int offset = *offsetptr;
+ uint32_t tablesize = D_32(encoded, offset);
+ int num_entries = 0;
+ amqp_table_entry_t *entries = malloc(INITIAL_TABLE_SIZE * sizeof(amqp_table_entry_t));
+ int allocated_entries = INITIAL_TABLE_SIZE;
+ int limit;
+
+ offset += 4;
+ limit = offset + tablesize;
+
+ while (offset < limit) {
+ size_t keylen;
+ amqp_table_entry_t *entry;
+
+ keylen = D_8(encoded, offset);
+ offset++;
+
+ if (num_entries >= allocated_entries) {
+ allocated_entries = allocated_entries * 2;
+ entries = realloc(entries, allocated_entries * sizeof(amqp_table_entry_t));
+ }
+ entry = &entries[num_entries];
+
+ entry->key.len = keylen;
+ entry->key.bytes = D_BYTES(encoded, offset, keylen);
+ offset += keylen;
+
+ entry->kind = D_8(encoded, offset);
+ offset++;
+
+ switch (entry->kind) {
+ case 'S':
+ entry->value.bytes.len = D_32(encoded, offset);
+ offset += 4;
+ entry->value.bytes.bytes = D_BYTES(encoded, offset, entry->value.bytes.len);
+ offset += entry->value.bytes.len;
+ break;
+ case 'I':
+ entry->value.i32 = (int32_t) D_32(encoded, offset);
+ offset += 4;
+ break;
+ case 'D':
+ entry->value.decimal.decimals = D_8(encoded, offset);
+ offset++;
+ entry->value.decimal.value = D_32(encoded, offset);
+ offset += 4;
+ break;
+ case 'T':
+ entry->value.u64 = D_64(encoded, offset);
+ offset += 8;
+ break;
+ case 'F': {
+ int table_result = amqp_decode_table(encoded, pool, &(entry->value.table), &offset);
+ if (table_result != 0) return table_result;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ num_entries++;
+ }
+
+ output->num_entries = num_entries;
+ output->entries = amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t));
+ memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t));
+
+ *offsetptr = offset;
+ return 0;
+}
+
+int amqp_encode_table(amqp_bytes_t encoded,
+ amqp_table_t *input,
+ int *offsetptr)
+{
+ int offset = *offsetptr;
+ int tablesize_offset = offset;
+ int i;
+
+ offset += 4; /* skip space for the size of the table to be filled in later */
+
+ for (i = 0; i < input->num_entries; i++) {
+ amqp_table_entry_t *entry = &(input->entries[i]);
+
+ E_8(encoded, offset, entry->key.len);
+ offset++;
+
+ E_BYTES(encoded, offset, entry->key.len, entry->key.bytes);
+ offset += entry->key.len;
+
+ E_8(encoded, offset, entry->kind);
+ offset++;
+
+ switch (entry->kind) {
+ case 'S':
+ E_32(encoded, offset, entry->value.bytes.len);
+ offset += 4;
+ E_BYTES(encoded, offset, entry->value.bytes.len, entry->value.bytes.bytes);
+ offset += entry->value.bytes.len;
+ break;
+ case 'I':
+ E_32(encoded, offset, (uint32_t) entry->value.i32);
+ offset += 4;
+ break;
+ case 'D':
+ E_8(encoded, offset, entry->value.decimal.decimals);
+ offset++;
+ E_32(encoded, offset, entry->value.decimal.value);
+ offset += 4;
+ break;
+ case 'T':
+ E_64(encoded, offset, entry->value.u64);
+ offset += 8;
+ break;
+ case 'F': {
+ int table_result = amqp_encode_table(encoded, &(entry->value.table), &offset);
+ if (table_result != 0) return table_result;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+
+ E_32(encoded, tablesize_offset, (offset - *offsetptr - 4));
+ *offsetptr = offset;
+ return 0;
+}
diff --git a/librabbitmq/codegen.py b/librabbitmq/codegen.py
index d73db73..00159ae 100644
--- a/librabbitmq/codegen.py
+++ b/librabbitmq/codegen.py
@@ -47,23 +47,6 @@ cTypeMap = {
'timestamp': 'uint64_t',
}
-def convertTable(d):
- if len(d) == 0:
- return "[]"
- else: raise 'Non-empty table defaults not supported', d
-
-def convertBytes(x):
- return "(amqp_bytes_t) { .length = %d, .bytes = \"%s\" }" % (len(x), x)
-
-defaultValueTypeConvMap = {
- bool : lambda x: x and "1" or "0",
- str : convertBytes,
- int : lambda x: str(x),
- float : lambda x: str(x),
- dict: convertTable,
- unicode: lambda x: convertBytes(x.encode("utf-8"))
-}
-
def c_ize(s):
s = s.replace('-', '_')
s = s.replace(' ', '_')
@@ -72,34 +55,18 @@ def c_ize(s):
AmqpMethod.defName = lambda m: cConstantName(c_ize(m.klass.name) + '_' + c_ize(m.name) + "_method")
AmqpMethod.structName = lambda m: "amqp_" + c_ize(m.klass.name) + '_' + c_ize(m.name) + "_t"
+AmqpClass.structName = lambda c: "amqp_" + c_ize(c.name) + "_properties_t"
+
def cConstantName(s):
return 'AMQP_' + '_'.join(re.split('[- ]', s.upper()))
-class PackedMethodBitField:
- def __init__(self, index):
- self.index = index
- self.domain = 'bit'
- self.contents = []
-
- def extend(self, f):
- self.contents.append(f)
+def cFlagName(c, f):
+ return cConstantName(c.name + '_' + f.name) + '_FLAG'
- def count(self):
- return len(self.contents)
-
- def full(self):
- return self.count() == 8
-
def genErl(spec):
def cType(domain):
return cTypeMap[spec.resolveDomain(domain)]
- def fieldTypeList(fields):
- return '[' + ', '.join([cType(f.domain) for f in fields]) + ']'
-
- def fieldNameList(fields):
- return '[' + ', '.join([c_ize(f.name) for f in fields]) + ']'
-
def fieldTempList(fields):
return '[' + ', '.join(['F' + str(f.index) for f in fields]) + ']'
@@ -109,171 +76,297 @@ def genErl(spec):
def genLookupMethodName(m):
print ' case %s: return "%s";' % (m.defName(), m.defName())
- def packMethodFields(fields):
- packed = []
- bitfield = None
- for f in fields:
- if cType(f.domain) == 'bit':
- if not(bitfield) or bitfield.full():
- bitfield = PackedMethodBitField(f.index)
- packed.append(bitfield)
- bitfield.extend(f)
- else:
- bitfield = None
- packed.append(f)
- return packed
+ def genSingleDecode(prefix, cLvalue, unresolved_domain):
+ type = spec.resolveDomain(unresolved_domain)
+ if type == 'shortstr':
+ print prefix + "%s.len = D_8(encoded, offset);" % (cLvalue,)
+ print prefix + "offset++;"
+ print prefix + "%s.bytes = D_BYTES(encoded, offset, %s.len);" % (cLvalue, cLvalue)
+ print prefix + "offset += %s.len;" % (cLvalue,)
+ elif type == 'longstr':
+ print prefix + "%s.len = D_32(encoded, offset);" % (cLvalue,)
+ print prefix + "offset += 4;"
+ print prefix + "%s.bytes = D_BYTES(encoded, offset, %s.len);" % (cLvalue, cLvalue)
+ print prefix + "offset += %s.len;" % (cLvalue,)
+ elif type == 'octet':
+ print prefix + "%s = D_8(encoded, offset);" % (cLvalue,)
+ print prefix + "offset++;"
+ elif type == 'short':
+ print prefix + "%s = D_16(encoded, offset);" % (cLvalue,)
+ print prefix + "offset += 2;"
+ elif type == 'long':
+ print prefix + "%s = D_32(encoded, offset);" % (cLvalue,)
+ print prefix + "offset += 4;"
+ elif type == 'longlong':
+ print prefix + "%s = D_64(encoded, offset);" % (cLvalue,)
+ print prefix + "offset += 8;"
+ elif type == 'timestamp':
+ print prefix + "%s = D_64(encoded, offset);" % (cLvalue,)
+ print prefix + "offset += 8;"
+ elif type == 'bit':
+ raise "Can't decode bit in genSingleDecode"
+ elif type == 'table':
+ print prefix + "table_result = amqp_decode_table(encoded, pool, &(%s), &offset);" % \
+ (cLvalue,)
+ print prefix + "if (table_result != 0) return table_result;"
+ else:
+ raise "Illegal domain in genSingleDecode", type
- def methodFieldFragment(f):
- type = cType(f.domain)
- p = 'F' + str(f.index)
+ def genSingleEncode(prefix, cValue, unresolved_domain):
+ type = spec.resolveDomain(unresolved_domain)
if type == 'shortstr':
- return p+'Len:8/unsigned, '+p+':'+p+'Len/binary'
+ print prefix + "E_8(encoded, offset, %s.len);" % (cValue,)
+ print prefix + "offset++;"
+ print prefix + "E_BYTES(encoded, offset, %s.len, %s.bytes);" % (cValue, cValue)
+ print prefix + "offset += %s.len;" % (cValue,)
elif type == 'longstr':
- return p+'Len:32/unsigned, '+p+':'+p+'Len/binary'
+ print prefix + "E_32(encoded, offset, %s.len);" % (cValue,)
+ print prefix + "offset += 4;"
+ print prefix + "E_BYTES(encoded, offset, %s.len, %s.bytes);" % (cValue, cValue)
+ print prefix + "offset += %s.len;" % (cValue,)
elif type == 'octet':
- return p+':8/unsigned'
- elif type == 'shortint':
- return p+':16/unsigned'
- elif type == 'longint':
- return p+':32/unsigned'
- elif type == 'longlongint':
- return p+':64/unsigned'
+ print prefix + "E_8(encoded, offset, %s);" % (cValue,)
+ print prefix + "offset++;"
+ elif type == 'short':
+ print prefix + "E_16(encoded, offset, %s);" % (cValue,)
+ print prefix + "offset += 2;"
+ elif type == 'long':
+ print prefix + "E_32(encoded, offset, %s);" % (cValue,)
+ print prefix + "offset += 4;"
+ elif type == 'longlong':
+ print prefix + "E_64(encoded, offset, %s);" % (cValue,)
+ print prefix + "offset += 8;"
elif type == 'timestamp':
- return p+':64/unsigned'
+ print prefix + "E_64(encoded, offset, %s);" % (cValue,)
+ print prefix + "offset += 8;"
elif type == 'bit':
- return p+'Bits:8'
+ raise "Can't encode bit in genSingleDecode"
elif type == 'table':
- return p+'Len:32/unsigned, '+p+'Tab:'+p+'Len/binary'
+ print prefix + "table_result = amqp_encode_table(encoded, &(%s), &offset);" % \
+ (cValue,)
+ print prefix + "if (table_result != 0) return table_result;"
else:
- return 'UNIMPLEMENTED'
-
- def genFieldPostprocessing(packed):
- for f in packed:
- type = cType(f.domain)
- if type == 'bit':
- for index in range(f.count()):
- print " F%d = ((F%dBits band %d) /= 0)," % \
- (f.index + index,
- f.index,
- 1 << index)
- elif type == 'table':
- print " F%d = rabbit_binary_parser:parse_table(F%dTab)," % \
- (f.index, f.index)
- else:
- pass
+ raise "Illegal domain in genSingleEncode", type
def genDecodeMethodFields(m):
- packedFields = packMethodFields(m.arguments)
- binaryPattern = ', '.join([methodFieldFragment(f) for f in packedFields])
- if binaryPattern:
- restSeparator = ', '
- else:
- restSeparator = ''
- recordConstructorExpr = '#%s{%s}' % (m.structName(), fieldMapList(m.arguments))
- print "decode_method_fields(%s, <<%s>>) ->" % (m.defName(), binaryPattern)
- genFieldPostprocessing(packedFields)
- print " %s;" % (recordConstructorExpr,)
+ print " case %s: {" % (m.defName(),)
+ print " %s *m = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
+ (m.structName(), m.structName(), m.structName())
+ bitindex = None
+ for f in m.arguments:
+ if spec.resolveDomain(f.domain) == 'bit':
+ if bitindex is None:
+ bitindex = 0
+ if bitindex >= 8:
+ bitindex = 0
+ if bitindex == 0:
+ print " bit_buffer = D_8(encoded, offset);"
+ print " offset++;"
+ print " m->%s = (bit_buffer & (1 << %d)) ? 1 : 0;" % \
+ (c_ize(f.name), bitindex)
+ bitindex = bitindex + 1
+ else:
+ bitindex = None
+ genSingleDecode(" ", "m->%s" % (c_ize(f.name),), f.domain)
+ print " *decoded = m;"
+ print " return 0;"
+ print " }"
def genDecodeProperties(c):
- print "decode_properties(%d, PropBin) ->" % (c.index)
- print " %s = rabbit_binary_parser:parse_properties(%s, PropBin)," % \
- (fieldTempList(c.fields), fieldTypeList(c.fields))
- print " #'P_%s'{%s};" % (c_ize(c.name), fieldMapList(c.fields))
-
- def genFieldPreprocessing(packed):
- for f in packed:
- type = cType(f.domain)
- if type == 'bit':
- print " F%dBits = (%s)," % \
- (f.index,
- ' bor '.join(['(bitvalue(F%d) bsl %d)' % (x.index, x.index - f.index)
- for x in f.contents]))
- elif type == 'table':
- print " F%dTab = rabbit_binary_generator:generate_table(F%d)," % (f.index, f.index)
- print " F%dLen = size(F%dTab)," % (f.index, f.index)
- elif type in ['shortstr', 'longstr']:
- print " F%dLen = size(F%d)," % (f.index, f.index)
- else:
+ print " case %d: {" % (c.index,)
+ print " %s *p = (%s *) amqp_pool_alloc(pool, sizeof(%s));" % \
+ (c.structName(), c.structName(), c.structName())
+ print " p->_flags = flags;"
+ for f in c.fields:
+ if spec.resolveDomain(f.domain) == 'bit':
pass
+ else:
+ print " if (flags & %s) {" % (cFlagName(c, f),)
+ genSingleDecode(" ", "p->%s" % (c_ize(f.name),), f.domain)
+ print " }"
+ print " *decoded = p;"
+ print " return 0;"
+ print " }"
def genEncodeMethodFields(m):
- packedFields = packMethodFields(m.arguments)
- print "encode_method_fields(#%s{%s}) ->" % (m.structName(), fieldMapList(m.arguments))
- genFieldPreprocessing(packedFields)
- print " <<%s>>;" % (', '.join([methodFieldFragment(f) for f in packedFields]))
+ print " case %s: {" % (m.defName(),)
+ if m.arguments:
+ print " %s *m = (%s *) decoded;" % (m.structName(), m.structName())
+ bitindex = None
+ def finishBits():
+ if bitindex is not None:
+ print " E_8(encoded, offset, bit_buffer);"
+ print " offset++;"
+ for f in m.arguments:
+ if spec.resolveDomain(f.domain) == 'bit':
+ if bitindex is None:
+ bitindex = 0
+ print " bit_buffer = 0;"
+ if bitindex >= 8:
+ finishBits()
+ print " bit_buffer = 0;"
+ bitindex = 0
+ print " if (m->%s) { bit_buffer |= (1 << %d); }" % \
+ (c_ize(f.name), bitindex)
+ bitindex = bitindex + 1
+ else:
+ finishBits()
+ bitindex = None
+ genSingleEncode(" ", "m->%s" % (c_ize(f.name),), f.domain)
+ finishBits()
+ print " return offset;"
+ print " }"
def genEncodeProperties(c):
- print "encode_properties(#'P_%s'{%s}) ->" % (c_ize(c.name), fieldMapList(c.fields))
- print " rabbit_binary_generator:encode_properties(%s, %s);" % \
- (fieldTypeList(c.fields), fieldTempList(c.fields))
+ print " case %d: {" % (c.index,)
+ if c.fields:
+ print " %s *p = (%s *) decoded;" % (c.structName(), c.structName())
+ for f in c.fields:
+ if spec.resolveDomain(f.domain) == 'bit':
+ pass
+ else:
+ print " if (flags & %s) {" % (cFlagName(c, f),)
+ genSingleEncode(" ", "p->%s" % (c_ize(f.name),), f.domain)
+ print " }"
+ print " return offset;"
+ print " }"
def genLookupException(c,v,cls):
# We do this because 0.8 uses "soft error" and 8.1 uses "soft-error".
mCls = c_ize(cls).upper()
- if mCls == 'SOFT_ERROR': genLookupException1(c,'false')
- elif mCls == 'HARD_ERROR': genLookupException1(c, 'true')
+ if mCls == 'SOFT_ERROR': genLookupException1(c,'AMQP_EXCEPTION_CATEGORY_CHANNEL')
+ elif mCls == 'HARD_ERROR': genLookupException1(c, 'AMQP_EXCEPTION_CATEGORY_CONNECTION')
elif mCls == '': pass
else: raise 'Unknown constant class', cls
- def genLookupException1(c,hardErrorBoolStr):
- n = cConstantName(c)
- print 'lookup_amqp_exception(%s) -> {%s, ?%s, <<"%s">>};' % \
- (n.lower(), hardErrorBoolStr, n, n)
+ def genLookupException1(c, cCategory):
+ print ' case %s: return %s;' % (cConstantName(c), cCategory)
methods = spec.allMethods()
print '#include <stdlib.h>'
print '#include <string.h>'
print '#include <stdio.h>'
+ print '#include <errno.h>'
+ print '#include <arpa/inet.h> /* ntohl, htonl, ntohs, htons */'
print
+ print '#include "amqp.h"'
print '#include "amqp_framing.h"'
+ print '#include "amqp_private.h"'
print """
-char const *amqp_method_name(uint32_t methodNumber) {
+char const *amqp_method_name(amqp_method_number_t methodNumber) {
switch (methodNumber) {"""
for m in methods: genLookupMethodName(m)
print """ default: return NULL;
}
-}
-"""
+}"""
print """
-amqp_boolean_t amqp_method_has_content(uint32_t methodNumber) {
+amqp_boolean_t amqp_method_has_content(amqp_method_number_t methodNumber) {
switch (methodNumber) {"""
for m in methods:
if m.hasContent:
print ' case %s: return 1;' % (m.defName())
print """ default: return 0;
}
-}
-"""
+}"""
+ print """
+int amqp_decode_method(amqp_method_number_t methodNumber,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded)
+{
+ int offset = 0;
+ int table_result;
+ uint8_t bit_buffer;
+
+ switch (methodNumber) {"""
for m in methods: genDecodeMethodFields(m)
- print "decode_method_fields(Name, BinaryFields) ->"
- print " rabbit_misc:frame_error(Name, BinaryFields)."
+ print """ default: return -ENOENT;
+ }
+}"""
+ print """
+int amqp_decode_properties(uint16_t class_id,
+ amqp_pool_t *pool,
+ amqp_bytes_t encoded,
+ void **decoded)
+{
+ int offset = 0;
+ int table_result;
+
+ amqp_flags_t flags = 0;
+ int flagword_index = 0;
+ amqp_flags_t partial_flags;
+
+ do {
+ partial_flags = D_16(encoded, offset);
+ offset += 2;
+ flags |= (partial_flags << (flagword_index * 16));
+ } while (partial_flags & 1);
+
+ switch (class_id) {"""
for c in spec.allClasses(): genDecodeProperties(c)
- print "decode_properties(ClassId, _BinaryFields) -> exit({unknown_class_id, ClassId})."
+ print """ default: return -ENOENT;
+ }
+}"""
+
+ print """
+int amqp_encode_method(amqp_method_number_t methodNumber,
+ void *decoded,
+ amqp_bytes_t encoded)
+{
+ int offset = 0;
+ int table_result;
+ uint8_t bit_buffer;
+ switch (methodNumber) {"""
for m in methods: genEncodeMethodFields(m)
- print "encode_method_fields(Record) -> exit({unknown_method_name, element(1, Record)})."
+ print """ default: return -ENOENT;
+ }
+}"""
+
+ print """
+int amqp_encode_properties(uint16_t class_id,
+ void *decoded,
+ amqp_bytes_t encoded)
+{
+ int offset = 0;
+ int table_result;
+
+ /* Cheat, and get the flags out generically, relying on the
+ similarity of structure between classes */
+ amqp_flags_t flags = * (amqp_flags_t *) decoded; /* cheating! */
+
+ while (flags != 0) {
+ amqp_flags_t remainder = flags >> 16;
+ uint16_t partial_flags = flags & 0xFFFE;
+ if (remainder != 0) { partial_flags |= 1; }
+ E_16(encoded, offset, partial_flags);
+ offset += 2;
+ flags = remainder;
+ }
+ switch (class_id) {"""
for c in spec.allClasses(): genEncodeProperties(c)
- print "encode_properties(Record) -> exit({unknown_properties_record, Record})."
+ print """ default: return -ENOENT;
+ }
+}"""
+ print """
+int amqp_exception_category(uint16_t code) {
+ switch (code) {"""
for (c,v,cls) in spec.constants: genLookupException(c,v,cls)
- print "lookup_amqp_exception(Code) ->"
- print " rabbit_log:warning(\"Unknown AMQP error code '~p'~n\", [Code]),"
- print " {true, ?INTERNAL_ERROR, <<\"INTERNAL_ERROR\">>}."
-
+ print """ default: return 0;
+ }
+}"""
def genHrl(spec):
def cType(domain):
return cTypeMap[spec.resolveDomain(domain)]
- def fieldNameList(fields):
- return ', '.join([c_ize(f.name) for f in fields])
-
def fieldDeclList(fields):
return ''.join([" %s %s;\n" % (cType(f.domain), c_ize(f.name)) for f in fields])
@@ -282,20 +375,15 @@ def genHrl(spec):
for f in fields
if spec.resolveDomain(f.domain) != 'bit'])
- def fieldNameListDefaults(fields):
- def fillField(field):
- result = c_ize(f.name)
- if field.defaultvalue != None:
- conv_fn = defaultValueTypeConvMap[type(field.defaultvalue)]
- result += ' = ' + conv_fn(field.defaultvalue)
- return result
- return ', '.join([fillField(f) for f in fields])
-
methods = spec.allMethods()
- print "#ifndef LIBRABBITMQ_AMQP_FRAMING_H"
- print "#define LIBRABBITMQ_AMQP_FRAMING_H"
- print
+ print """#ifndef librabbitmq_amqp_framing_h
+#define librabbitmq_amqp_framing_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+"""
print "#define AMQP_PROTOCOL_VERSION_MAJOR %d" % (spec.major)
print "#define AMQP_PROTOCOL_VERSION_MINOR %d" % (spec.minor)
print "#define AMQP_PROTOCOL_PORT %d" % (spec.port)
@@ -307,7 +395,7 @@ def genHrl(spec):
print "/* Method field records. */"
for m in methods:
methodid = m.klass.index << 16 | m.index
- print "#define %s ((uint32_t) 0x%.08X) /* %d, %d; %d */" % \
+ print "#define %s ((amqp_method_number_t) 0x%.08X) /* %d, %d; %d */" % \
(m.defName(),
methodid,
m.klass.index,
@@ -324,13 +412,16 @@ def genHrl(spec):
shortnum = index / 16
partialindex = 15 - (index % 16)
bitindex = shortnum * 16 + partialindex
- print '#define %s_FLAG (1 << %d)' % (cConstantName(c.name + '_' + f.name), bitindex)
+ print '#define %s (1 << %d)' % (cFlagName(c, f), bitindex)
index = index + 1
- print "typedef struct {\n uint32_t _flags;\n%s} %s;\n" % \
- (fieldDeclList(c.fields), \
- 'amqp_%s_properties_t' % (c_ize(c.name),))
+ print "typedef struct {\n amqp_flags_t _flags;\n%s} %s;\n" % \
+ (fieldDeclList(c.fields), c.structName())
+
+ print """#ifdef __cplusplus
+}
+#endif
- print "#endif"
+#endif"""
def generateErl(specPath):
genErl(AmqpSpec(specPath))
diff --git a/librabbitmq/f.c b/librabbitmq/f.c
deleted file mode 100644
index e4bcf4d..0000000
--- a/librabbitmq/f.c
+++ /dev/null
@@ -1,13 +0,0 @@
-struct x {
- int l;
- char *b;
-};
-
-int bar(struct x v) {
- return 0;
-}
-
-int foo(void) {
- bar((struct x) { .l = 123, .b = "hi"});
- return 123;
-}