diff options
author | Tony Garnock-Jones <tonyg@kcbbs.gen.nz> | 2009-04-25 19:41:56 +0100 |
---|---|---|
committer | Tony Garnock-Jones <tonyg@kcbbs.gen.nz> | 2009-04-25 19:41:56 +0100 |
commit | 67970c9c56ebd49b57e61d50255b04fa1ac7d27d (patch) | |
tree | ec02d63a0a7b8f31b7a0c0426eeaab25f5884e1f | |
parent | 8bf174bc0a3d682ff9c8c11435008f1adf3c288f (diff) | |
download | rabbitmq-c-github-ask-67970c9c56ebd49b57e61d50255b04fa1ac7d27d.tar.gz |
Codegen, codec
-rw-r--r-- | .hgignore | 7 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | examples/Makefile.am | 4 | ||||
-rw-r--r-- | examples/amqp_sendstring.c | 12 | ||||
-rw-r--r-- | librabbitmq/Makefile.am | 5 | ||||
-rw-r--r-- | librabbitmq/amqp.h | 109 | ||||
-rw-r--r-- | librabbitmq/amqp_mem.c | 102 | ||||
-rw-r--r-- | librabbitmq/amqp_private.h | 48 | ||||
-rw-r--r-- | librabbitmq/amqp_table.c | 143 | ||||
-rw-r--r-- | librabbitmq/codegen.py | 409 | ||||
-rw-r--r-- | librabbitmq/f.c | 13 |
12 files changed, 678 insertions, 179 deletions
@@ -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; -} |