From 712b073f95f694f23a070bd43cd0c9e7479142b7 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 7 Jul 2010 05:24:31 +0200 Subject: Implemented most types, sending & receiving --- CMakeLists.txt | 6 +- src/CMakeLists.txt | 6 ++ src/PacketHandler.vala | 77 ++++++++++++++++++++ src/Term.vala | 192 +++++++++++++++++++++++++++++++++++++++++++++++-- test/CMakeLists.txt | 6 ++ test/Test.vala | 8 ++- 6 files changed, 286 insertions(+), 9 deletions(-) create mode 100644 src/PacketHandler.vala diff --git a/CMakeLists.txt b/CMakeLists.txt index 9dddf9a..844570d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,11 +11,9 @@ ensure_vala_version("0.8" MINIMUM) find_package(PkgConfig) pkg_check_modules(GEE REQUIRED gee-1.0) +pkg_check_modules(GIO REQUIRED gio-2.0) +pkg_check_modules(GIO_UNIX REQUIRED gio-unix-2.0) pkg_check_modules(ERL REQUIRED erl_interface) -add_definitions(${GEE_CFLAGS} ${GEE_CFLAGS_OTHER} ${ERL_CFLAGS} ${ERL_CFLAGS_OTHER}) -link_libraries(${GEE_LIBRARIES} ${ERL_LIBRARIES}) -link_directories(${GEE_LIBRARY_DIRS} ${ERL_LIBRARY_DIRS}) - add_subdirectory(src) add_subdirectory(test) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a725dd3..af9fafe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,13 @@ +add_definitions(${GEE_CFLAGS} ${GEE_CFLAGS_OTHER} ${GIO_CFLAGS} ${GIO_CFLAGS_OTHER} ${ERL_CFLAGS} ${ERL_CFLAGS_OTHER}) +link_libraries(${GEE_LIBRARIES} ${GIO_LIBRARIES} ${ERL_LIBRARIES}) +link_directories(${GEE_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${ERL_LIBRARY_DIRS}) + vala_precompile(EVA_C + PacketHandler.vala Term.vala PACKAGES gee-1.0 + gio-2.0 erl_interface GENERATE_VAPI eva diff --git a/src/PacketHandler.vala b/src/PacketHandler.vala new file mode 100644 index 0000000..0f5cd3c --- /dev/null +++ b/src/PacketHandler.vala @@ -0,0 +1,77 @@ +namespace Eva { + public class PacketHandler { + private DataInputStream istream; + private DataOutputStream ostream; + private int sizeLength; + + public signal void received_term(Term term); + + public PacketHandler(InputStream input, OutputStream output, int length) { + assert(length == 1 || length == 2 || length == 4); + + istream = new DataInputStream(input); + ostream = new DataOutputStream(output); + sizeLength = length; + + istream.byte_order = DataStreamByteOrder.BIG_ENDIAN; + ostream.byte_order = DataStreamByteOrder.BIG_ENDIAN; + } + + public void send(Term term) throws Error { + Erl.Buffer buffer = Erl.Buffer.with_version(); + term.encode(buffer); + + switch(sizeLength) { + case 1: + ostream.put_byte((uchar)buffer.buff.length, null); + break; + case 2: + ostream.put_uint16((uint16)buffer.buff.length, null); + break; + case 4: + ostream.put_uint32((uint32)buffer.buff.length, null); + break; + } + + ostream.write(buffer.buff, buffer.buff.length, null); + } + + private async void receive() throws Error { + while(true) { + while(istream.get_available() < sizeLength) { + yield istream.fill_async((ssize_t)(sizeLength - istream.get_available()), 0, null); + } + + int length = 0; + switch(sizeLength) { + case 1: + length = istream.read_byte(null); + break; + case 2: + length = istream.read_uint16(null); + break; + case 4: + length = (int)istream.read_uint32(null); + break; + } + + uint8[] buffer = new uint8[length]; + size_t received = 0; + + while(received < length) { + size_t ret = yield istream.read_async(&(buffer[received]), length-received, 0, null); + assert(ret > 0); + + received += ret; + } + + Term term = Term.decode(buffer); + Idle.add(() => {received_term(term); return false;}); + } + } + + public void start() { + receive.begin(); + } + } +} diff --git a/src/Term.vala b/src/Term.vala index 2a9cca8..3a75931 100644 --- a/src/Term.vala +++ b/src/Term.vala @@ -3,12 +3,90 @@ namespace Eva { public abstract string to_string(); public abstract void encode(Erl.Buffer buffer); + + public static Term decode(void *buffer) { + int index = 0; + int version; + + Erl.decode_version(buffer, ref index, out version); + + return do_decode(buffer, ref index); + } + + private static Term do_decode(void *buffer, ref int index) { + int type, size; + assert(Erl.get_type(buffer, ref index, out type, out size) == 0); + + switch(type) { + case Erl.TermType.SMALL_INTEGER: + char value; + assert(Erl.decode_char(buffer, ref index, out value) == 0); + return new Int((uchar)value); + + case Erl.TermType.INTEGER: + long value; + assert(Erl.decode_long(buffer, ref index, out value) == 0); + return new Int(value); + + case Erl.TermType.FLOAT: + double value; + assert(Erl.decode_double(buffer, ref index, out value) == 0); + return new Double(value); + + case Erl.TermType.ATOM: + char[] value = new char[size+1]; + assert(Erl.decode_atom(buffer, ref index, value) == 0); + return new Atom(((string)value).ndup(size)); + + case Erl.TermType.SMALL_TUPLE: + case Erl.TermType.LARGE_TUPLE: + assert(Erl.decode_tuple_header(buffer, ref index, out size) == 0); + Tuple term = new Tuple(); + + for(int i = 0; i < size; ++i) { + term.value.add(do_decode(buffer, ref index)); + } + + return term; + + case Erl.TermType.NIL: + case Erl.TermType.LIST: + List term = new List(); + + while(true) { + assert(Erl.decode_list_header(buffer, ref index, out size) == 0); + if(size == 0) + break; + + for(int i = 0; i < size; ++i) { + term.value.add(do_decode(buffer, ref index)); + } + } + + return term; + + case Erl.TermType.STRING: + char[] value = new char[size+1]; + assert(Erl.decode_string(buffer, ref index, value) == 0); + return new String(((string)value).ndup(size)); + + case Erl.TermType.BINARY: + char[] value = new char[size]; + stdout.printf("Size: %i\n", size); + long l; + assert(Erl.decode_binary(buffer, ref index, value, out l) == 0); + return new Binary(value); + + default: + assert_not_reached(); + } + } } - public class Long : Object, Term { + public class Int : Object, Term { public long value {get; construct;} - public Long(long v) { + public Int(long v) { Object(value: v); } @@ -21,10 +99,10 @@ namespace Eva { } } - public class ULong : Object, Term { + public class UInt : Object, Term { public ulong value {get; construct;} - public ULong(ulong v) { + public UInt(ulong v) { Object(value: v); } @@ -68,4 +146,110 @@ namespace Eva { buffer.encode_atom(value.to_utf8()); } } + + public class Tuple : Object, Term { + public Gee.List value {get; construct;} + + public Tuple() { + Gee.List list = new Gee.ArrayList(); + Object(value: list); + } + + public string to_string() { + string ret = "{"; + bool first = true; + + foreach(Term term in value) { + if(first) { + first = false; + ret += term.to_string(); + } + else { + ret += "," + term.to_string(); + } + } + + return ret + "}"; + } + + public void encode(Erl.Buffer buffer) { + buffer.encode_tuple_header(value.size); + + foreach(Term term in value) { + term.encode(buffer); + } + } + } + + public class List : Object, Term { + public Gee.List value {get; construct;} + + public List() { + Gee.List list = new Gee.LinkedList(); + Object(value: list); + } + + public string to_string() { + string ret = "["; + bool first = true; + + foreach(Term term in value) { + if(first) { + first = false; + ret += term.to_string(); + } + else { + ret += "," + term.to_string(); + } + } + + return ret + "]"; + } + + public void encode(Erl.Buffer buffer) { + if(!value.is_empty) { + buffer.encode_list_header(value.size); + + foreach(Term term in value) { + term.encode(buffer); + } + } + + buffer.encode_empty_list(); + } + } + + public class String : Object, Term { + public string value {get; construct;} + + public String(string v) { + Object(value: v); + } + + public string to_string() { + return value.to_string(); + } + + public void encode(Erl.Buffer buffer) { + buffer.encode_string(value.to_utf8()); + } + } + + public class Binary : Object, Term { + public void* value {get; private set;} + public long len {get; private set;} + + public Binary(char[] v) { + value = Memory.dup(v, (uint)(sizeof(char)*v.length)); + len = v.length; + } + + public string to_string() { + return "[[Binary]]"; + } + + public void encode(Erl.Buffer buffer) { + buffer.encode_binary((char*)value, len); + } + } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2c11d3b..bad2b58 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,13 @@ +add_definitions(${GEE_CFLAGS} ${GEE_CFLAGS_OTHER} ${GIO_CFLAGS} ${GIO_CFLAGS_OTHER} ${GIO_UNIX_CFLAGS} ${GIO_UNIX_CFLAGS_OTHER} ${ERL_CFLAGS} ${ERL_CFLAGS_OTHER}) +link_libraries(${GEE_LIBRARIES} ${GIO_LIBRARIES} ${GIO_UNIX_LIBRARIES} ${ERL_LIBRARIES}) +link_directories(${GEE_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIO_UNIX_LIBRARY_DIRS} ${ERL_LIBRARY_DIRS}) + vala_precompile(TEST_C Test.vala PACKAGES gee-1.0 + gio-2.0 + gio-unix-2.0 erl_interface CUSTOM_VAPIS ${eva_BINARY_DIR}/src/eva.vapi diff --git a/test/Test.vala b/test/Test.vala index ce5da6d..5d71095 100644 --- a/test/Test.vala +++ b/test/Test.vala @@ -1,7 +1,13 @@ namespace Eva { class Test { public static int main(string[] args) { - Eva.Long term = new Eva.Long(42); + MainLoop main = new MainLoop(); + + Eva.PacketHandler handler = new Eva.PacketHandler(new UnixInputStream(3, true), new UnixOutputStream(4, true), 4); + handler.received_term.connect((term) => {stdout.printf("%s\n", term.to_string()); handler.send(term); main.quit();}); + handler.start(); + + main.run(); return 0; } -- cgit v1.2.3