THRIFT-582 C(c_glib) implementation of Thrift
Patch: Anatol Pomozov and Michael Lum
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@1027933 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 367621b..9dbc1c1 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -23,6 +23,10 @@
SUBDIRS += cpp
endif
+if WITH_C_GLIB
+SUBDIRS += c_glib
+endif
+
if WITH_MONO
SUBDIRS += csharp
endif
diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am
new file mode 100644
index 0000000..5b66818
--- /dev/null
+++ b/lib/c_glib/Makefile.am
@@ -0,0 +1,93 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+SUBDIRS = . test
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+lib_LTLIBRARIES = libthrift_c_glib.la
+pkgconfig_DATA = thrift_c_glib.pc
+
+common_cflags = -g -Wall -W -Werror -Isrc $(GLIB_CFLAGS)
+common_ldflags = -g -Wall -W $(GLIB_LDFLAGS) @GCOV_LDFLAGS@
+
+# this removes optimizations and adds coverage flags
+CFLAGS = @GCOV_CFLAGS@
+
+# Define the source files for the module
+
+libthrift_c_glib_la_SOURCES = src/thrift.c \
+ src/thrift_struct.c \
+ src/thrift_application_exception.c \
+ src/processor/thrift_processor.c \
+ src/protocol/thrift_protocol.c \
+ src/protocol/thrift_protocol_factory.c \
+ src/protocol/thrift_binary_protocol.c \
+ src/protocol/thrift_binary_protocol_factory.c \
+ src/transport/thrift_transport.c \
+ src/transport/thrift_transport_factory.c \
+ src/transport/thrift_socket.c \
+ src/transport/thrift_server_transport.c \
+ src/transport/thrift_server_socket.c \
+ src/transport/thrift_buffered_transport.c \
+ src/transport/thrift_framed_transport.c \
+ src/transport/thrift_memory_buffer.c \
+ src/server/thrift_server.c \
+ src/server/thrift_simple_server.c
+
+libthrift_c_glib_la_CFLAGS = $(common_cflags)
+
+include_thriftdir = $(includedir)/thrift
+include_thrift_HEADERS = \
+ $(top_builddir)/config.h \
+ src/thrift.h \
+ src/thrift_application_exception.h \
+ src/thrift_struct.h
+
+include_protocoldir = $(include_thriftdir)/protocol
+include_protocol_HEADERS = src/protocol/thrift_protocol.h \
+ src/protocol/thrift_protocol_factory.h \
+ src/protocol/thrift_binary_protocol.h \
+ src/protocol/thrift_binary_protocol_factory.h
+
+include_transportdir = $(include_thriftdir)/transport
+include_transport_HEADERS = src/transport/thrift_buffered_transport.h \
+ src/transport/thrift_framed_transport.h \
+ src/transport/thrift_memory_buffer.h \
+ src/transport/thrift_server_socket.h \
+ src/transport/thrift_server_transport.h \
+ src/transport/thrift_socket.h \
+ src/transport/thrift_transport.h \
+ src/transport/thrift_transport_factory.h
+
+include_serverdir = $(include_thriftdir)/server
+include_server_HEADERS = src/server/thrift_server.h \
+ src/server/thrift_simple_server.h
+
+include_processordir = $(include_thriftdir)/processor
+include_processor_HEADERS = src/processor/thrift_processor.h
+
+
+EXTRA_DIST = \
+ README \
+ thrift_c_glib.pc.in
+
+CLEANFILES = \
+ *.gcno \
+ *.gcda
diff --git a/lib/c_glib/src/processor/thrift_processor.c b/lib/c_glib/src/processor/thrift_processor.c
new file mode 100644
index 0000000..c5d4034
--- /dev/null
+++ b/lib/c_glib/src/processor/thrift_processor.c
@@ -0,0 +1,50 @@
+#include "thrift.h"
+#include "processor/thrift_processor.h"
+
+/* forward declarations */
+static void thrift_processor_class_init (ThriftProcessorClass *cls);
+
+/* define ThriftProcessorClass's type */
+GType
+thrift_processor_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftProcessorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_processor_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftProcessor),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftProcessor",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+/* class initializer for ThriftProcessor */
+static void
+thrift_processor_class_init (ThriftProcessorClass *cls)
+{
+ /* set these as virtual methods to be implemented by a subclass */
+ cls->process = thrift_processor_process;
+}
+
+gboolean
+thrift_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
+ ThriftProtocol *out)
+{
+ return THRIFT_PROCESSOR_GET_CLASS (processor)->process (processor, in, out);
+}
+
diff --git a/lib/c_glib/src/processor/thrift_processor.h b/lib/c_glib/src/processor/thrift_processor.h
new file mode 100644
index 0000000..cc0b006
--- /dev/null
+++ b/lib/c_glib/src/processor/thrift_processor.h
@@ -0,0 +1,59 @@
+#ifndef _THRIFT_PROCESSOR_H
+#define _THRIFT_PROCESSOR_H
+
+#include <glib-object.h>
+
+#include "protocol/thrift_protocol.h"
+
+/*! \file thrift_processor.h
+ * \brief Abstract class for Thrift processors.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_PROCESSOR (thrift_processor_get_type ())
+#define THRIFT_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_PROCESSOR, ThriftProcessor))
+#define THRIFT_IS_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_PROCESSOR))
+#define THRIFT_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_PROCESSOR, \
+ ThriftProcessorClass))
+#define THRIFT_IS_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_PROCESSOR))
+#define THRIFT_PROCESSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_PROCESSOR, \
+ ThriftProcessorClass))
+
+/*!
+ * Thrift Processorobject
+ */
+struct _ThriftProcessor
+{
+ GObject parent;
+};
+typedef struct _ThriftProcessor ThriftProcessor;
+
+/*!
+ * Thrift Processor class
+ */
+struct _ThriftProcessorClass
+{
+ GObjectClass parent;
+
+ /* vtable */
+ gboolean (*process) (ThriftProcessor *processor, ThriftProtocol *in,
+ ThriftProtocol *out);
+};
+typedef struct _ThriftProcessorClass ThriftProcessorClass;
+
+/* used by THRIFT_TYPE_PROCESSOR */
+GType thrift_processor_get_type (void);
+
+/*!
+ * Processes the request.
+ * \public \memberof ThriftProcessorClass
+ */
+gboolean thrift_processor_process (ThriftProcessor *processor,
+ ThriftProtocol *in, ThriftProtocol *out);
+
+#endif /* _THRIFT_PROCESSOR_H */
diff --git a/lib/c_glib/src/protocol/thrift_binary_protocol.c b/lib/c_glib/src/protocol/thrift_binary_protocol.c
new file mode 100644
index 0000000..afedc9e
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_binary_protocol.c
@@ -0,0 +1,983 @@
+#include <string.h>
+#include <stdio.h>
+
+#include "thrift.h"
+#include "protocol/thrift_protocol.h"
+#include "protocol/thrift_binary_protocol.h"
+
+/* forward declarations */
+static guint64 thrift_bitwise_cast_guint64 (gdouble v);
+static gdouble thrift_bitwise_cast_gdouble (guint64 v);
+static void thrift_binary_protocol_class_init (ThriftProtocolClass *cls);
+
+gint32 thrift_binary_protocol_write_message_begin (ThriftProtocol *protocol,
+ const gchar *name, const ThriftMessageType message_type,
+ const gint32 seqid, GError **error);
+gint32 thrift_binary_protocol_write_message_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_struct_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ GError **error);
+gint32 thrift_binary_protocol_write_struct_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_field_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ GError **error);
+gint32 thrift_binary_protocol_write_field_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_field_stop (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_map_begin (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size,
+ GError **error);
+gint32 thrift_binary_protocol_write_map_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_list_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error);
+gint32 thrift_binary_protocol_write_list_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_set_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error);
+gint32 thrift_binary_protocol_write_set_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_write_bool (ThriftProtocol *protocol,
+ const gboolean value, GError **error);
+gint32 thrift_binary_protocol_write_byte (ThriftProtocol *protocol,
+ const gint8 value, GError **error);
+gint32 thrift_binary_protocol_write_i16 (ThriftProtocol *protocol,
+ const gint16 value, GError **error);
+gint32 thrift_binary_protocol_write_i32 (ThriftProtocol *protocol,
+ const gint32 value, GError **error);
+gint32 thrift_binary_protocol_write_i64 (ThriftProtocol *protocol,
+ const gint64 value, GError **error);
+gint32 thrift_binary_protocol_write_double (ThriftProtocol *protocol,
+ const gdouble value,
+ GError **error);
+gint32 thrift_binary_protocol_write_string (ThriftProtocol *protocol,
+ const gchar *str, GError **error);
+gint32 thrift_binary_protocol_write_binary (ThriftProtocol *protocol,
+ const gpointer buf,
+ const guint32 len, GError **error);
+gint32 thrift_binary_protocol_read_message_begin (
+ ThriftProtocol *protocol, gchar **name,
+ ThriftMessageType *message_type, gint32 *seqid, GError **error);
+gint32 thrift_binary_protocol_read_message_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_struct_begin (ThriftProtocol *protocol,
+ gchar **name,
+ GError **error);
+gint32 thrift_binary_protocol_read_struct_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_field_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftType *field_type,
+ gint16 *field_id,
+ GError **error);
+gint32 thrift_binary_protocol_read_field_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_map_begin (ThriftProtocol *protocol,
+ ThriftType *key_type,
+ ThriftType *value_type,
+ guint32 *size,
+ GError **error);
+gint32 thrift_binary_protocol_read_map_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_list_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error);
+gint32 thrift_binary_protocol_read_list_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_set_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error);
+gint32 thrift_binary_protocol_read_set_end (ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_binary_protocol_read_bool (ThriftProtocol *protocol,
+ gboolean *value, GError **error);
+gint32 thrift_binary_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+ GError **error);
+gint32 thrift_binary_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+ GError **error);
+gint32 thrift_binary_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+ GError **error);
+gint32 thrift_binary_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+ GError **error);
+gint32 thrift_binary_protocol_read_double (ThriftProtocol *protocol,
+ gdouble *value, GError **error);
+gint32 thrift_binary_protocol_read_string (ThriftProtocol *protocol,
+ gchar **str, GError **error);
+gint32 thrift_binary_protocol_read_binary (ThriftProtocol *protocol,
+ gpointer *buf, guint32 *len,
+ GError **error);
+
+static guint64
+thrift_bitwise_cast_guint64 (gdouble v)
+{
+ union {
+ gdouble from;
+ guint64 to;
+ } u;
+ u.from = v;
+ return u.to;
+}
+
+static gdouble
+thrift_bitwise_cast_gdouble (guint64 v)
+{
+ union {
+ guint64 from;
+ gdouble to;
+ } u;
+ u.from = v;
+ return u.to;
+}
+
+GType
+thrift_binary_protocol_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftBinaryProtocolClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_binary_protocol_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftBinaryProtocol),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_PROTOCOL,
+ "ThriftBinaryProtocolType",
+ &info, 0);
+ }
+
+ return type;
+}
+
+/* initialize the class */
+static void
+thrift_binary_protocol_class_init (ThriftProtocolClass *cls)
+{
+ cls->write_message_begin = thrift_binary_protocol_write_message_begin;
+ cls->write_message_end = thrift_binary_protocol_write_message_end;
+ cls->write_struct_begin = thrift_binary_protocol_write_struct_begin;
+ cls->write_struct_end = thrift_binary_protocol_write_struct_end;
+ cls->write_field_begin = thrift_binary_protocol_write_field_begin;
+ cls->write_field_end = thrift_binary_protocol_write_field_end;
+ cls->write_field_stop = thrift_binary_protocol_write_field_stop;
+ cls->write_map_begin = thrift_binary_protocol_write_map_begin;
+ cls->write_map_end = thrift_binary_protocol_write_map_end;
+ cls->write_list_begin = thrift_binary_protocol_write_list_begin;
+ cls->write_list_end = thrift_binary_protocol_write_list_end;
+ cls->write_set_begin = thrift_binary_protocol_write_set_begin;
+ cls->write_set_end = thrift_binary_protocol_write_set_end;
+ cls->write_bool = thrift_binary_protocol_write_bool;
+ cls->write_byte = thrift_binary_protocol_write_byte;
+ cls->write_i16 = thrift_binary_protocol_write_i16;
+ cls->write_i32 = thrift_binary_protocol_write_i32;
+ cls->write_i64 = thrift_binary_protocol_write_i64;
+ cls->write_double = thrift_binary_protocol_write_double;
+ cls->write_string = thrift_binary_protocol_write_string;
+ cls->write_binary = thrift_binary_protocol_write_binary;
+ cls->read_message_begin = thrift_binary_protocol_read_message_begin;
+ cls->read_message_end = thrift_binary_protocol_read_message_end;
+ cls->read_struct_begin = thrift_binary_protocol_read_struct_begin;
+ cls->read_struct_end = thrift_binary_protocol_read_struct_end;
+ cls->read_field_begin = thrift_binary_protocol_read_field_begin;
+ cls->read_field_end = thrift_binary_protocol_read_field_end;
+ cls->read_map_begin = thrift_binary_protocol_read_map_begin;
+ cls->read_map_end = thrift_binary_protocol_read_map_end;
+ cls->read_list_begin = thrift_binary_protocol_read_list_begin;
+ cls->read_list_end = thrift_binary_protocol_read_list_end;
+ cls->read_set_begin = thrift_binary_protocol_read_set_begin;
+ cls->read_set_end = thrift_binary_protocol_read_set_end;
+ cls->read_bool = thrift_binary_protocol_read_bool;
+ cls->read_byte = thrift_binary_protocol_read_byte;
+ cls->read_i16 = thrift_binary_protocol_read_i16;
+ cls->read_i32 = thrift_binary_protocol_read_i32;
+ cls->read_i64 = thrift_binary_protocol_read_i64;
+ cls->read_double = thrift_binary_protocol_read_double;
+ cls->read_string = thrift_binary_protocol_read_string;
+ cls->read_binary = thrift_binary_protocol_read_binary;
+}
+
+gint32
+thrift_binary_protocol_write_message_begin (ThriftProtocol *protocol,
+ const gchar *name, const ThriftMessageType message_type,
+ const gint32 seqid, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 version = (THRIFT_BINARY_PROTOCOL_VERSION_1)
+ | ((gint32) message_type);
+ gint32 ret;
+ gint32 xfer = 0;
+
+ if ((ret = thrift_protocol_write_i32 (protocol, version, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ if ((ret = thrift_protocol_write_string (protocol, name, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ if ((ret = thrift_protocol_write_i32 (protocol, seqid, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_write_message_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_struct_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (name);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_struct_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_field_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (name);
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+
+ if ((ret = thrift_protocol_write_byte (protocol, (gint8) field_type,
+ error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ if ((ret = thrift_protocol_write_i16 (protocol, field_id, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_write_field_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_field_stop (ThriftProtocol *protocol,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ return thrift_protocol_write_byte (protocol, (gint8) T_STOP, error);
+}
+
+gint32
+thrift_binary_protocol_write_map_begin (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+
+ if ((ret = thrift_protocol_write_byte (protocol, (gint8) key_type,
+ error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ if ((ret = thrift_protocol_write_byte (protocol, (gint8) value_type,
+ error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ if ((ret = thrift_protocol_write_i32 (protocol, (gint32) size, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_write_map_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_list_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+
+ if ((ret = thrift_protocol_write_byte (protocol, (gint8) element_type,
+ error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_write_i32 (protocol, (gint32) size, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_write_list_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_set_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ return thrift_protocol_write_list_begin (protocol, element_type,
+ size, error);
+}
+
+gint32
+thrift_binary_protocol_write_set_end (ThriftProtocol *protocol, GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_write_bool (ThriftProtocol *protocol,
+ const gboolean value, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ guint8 tmp = value ? 1 : 0;
+ return thrift_protocol_write_byte (protocol, tmp, error);
+}
+
+gint32
+thrift_binary_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &value, 1, error))
+ {
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_binary_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint16 net = g_htons (value);
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &net, 2, error))
+ {
+ return 2;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_binary_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 net = g_htonl (value);
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &net, 4, error))
+ {
+ return 4;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_binary_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint64 net = GUINT64_TO_BE (value);
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &net, 8, error))
+ {
+ return 8;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_binary_protocol_write_double (ThriftProtocol *protocol,
+ const gdouble value, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ guint64 bits = GUINT64_FROM_BE (thrift_bitwise_cast_guint64 (value));
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &bits, 8, error))
+ {
+ return 8;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_binary_protocol_write_string (ThriftProtocol *protocol,
+ const gchar *str, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ guint32 len = str != NULL ? strlen (str) : 0;
+ /* write the string length + 1 which includes the null terminator */
+ return thrift_protocol_write_binary (protocol, (const gpointer) str,
+ len, error);
+}
+
+gint32
+thrift_binary_protocol_write_binary (ThriftProtocol *protocol,
+ const gpointer buf,
+ const guint32 len, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gint32 xfer = 0;
+
+ if ((ret = thrift_protocol_write_i32 (protocol, len, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (len > 0)
+ {
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) buf, len, error) == FALSE)
+ {
+ return -1;
+ }
+ xfer += len;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_message_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftMessageType *message_type,
+ gint32 *seqid, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+ gint32 sz;
+
+ if ((ret = thrift_protocol_read_i32 (protocol, &sz, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (sz < 0)
+ {
+ /* check for version */
+ guint32 version = sz & THRIFT_BINARY_PROTOCOL_VERSION_MASK;
+ if (version != THRIFT_BINARY_PROTOCOL_VERSION_1)
+ {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+ "expected version %d, got %d",
+ THRIFT_BINARY_PROTOCOL_VERSION_1, version);
+ return -1;
+ }
+
+ *message_type = (ThriftMessageType) (sz & 0x000000ff);
+
+ if ((ret = thrift_protocol_read_string (protocol, name, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_read_i32 (protocol, seqid, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ }
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_message_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_struct_begin (ThriftProtocol *protocol,
+ gchar **name,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ *name = NULL;
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_struct_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_field_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftType *field_type,
+ gint16 *field_id,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (name);
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+ gint8 type;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &type, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ *field_type = (ThriftType) type;
+ if (*field_type == T_STOP)
+ {
+ *field_id = 0;
+ return xfer;
+ }
+ if ((ret = thrift_protocol_read_i16 (protocol, field_id, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_field_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_map_begin (ThriftProtocol *protocol,
+ ThriftType *key_type,
+ ThriftType *value_type,
+ guint32 *size,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+ gint8 k, v;
+ gint32 sizei;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &k, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ *key_type = (ThriftType) k;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &v, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ *value_type = (ThriftType) v;
+
+ if ((ret = thrift_protocol_read_i32 (protocol, &sizei, error)) <0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (sizei < 0)
+ {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", sizei);
+ return -1;
+ }
+
+ *size = (guint32) sizei;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_map_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_list_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ gint32 ret;
+ gint32 xfer = 0;
+ gint8 e;
+ gint32 sizei;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &e, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+ *element_type = (ThriftType) e;
+
+ if ((ret = thrift_protocol_read_i32 (protocol, &sizei, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (sizei < 0)
+ {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", sizei);
+ return -1;
+ }
+
+ *size = (guint32) sizei;
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_list_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_set_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+ return thrift_protocol_read_list_begin (protocol, element_type, size, error);
+}
+
+gint32
+thrift_binary_protocol_read_set_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_binary_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[1];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 1, error)) < 0)
+ {
+ return -1;
+ }
+ *value = *(gint8 *) b != 0;
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[1];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 1, error)) < 0)
+ {
+ return -1;
+ }
+ *value = *(gint8 *) b;
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[2];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 2, error)) < 0)
+ {
+ return -1;
+ }
+ *value = *(gint16 *) b;
+ *value = g_ntohs (*value);
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[4];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 4, error)) < 0)
+ {
+ return -1;
+ }
+ *value = *(gint32 *) b;
+ *value = g_ntohl (*value);
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[8];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 8, error)) < 0)
+ {
+ return -1;
+ }
+ *value = *(gint64 *) b;
+ *value = GUINT64_FROM_BE (*value);
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_double (ThriftProtocol *protocol,
+ gdouble *value, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gpointer b[8];
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 8, error)) < 0)
+ {
+ return -1;
+ }
+ guint64 bits = *(guint64 *) b;
+ bits = GUINT64_FROM_BE (bits);
+ *value = thrift_bitwise_cast_gdouble (bits);
+ return ret;
+}
+
+gint32
+thrift_binary_protocol_read_string (ThriftProtocol *protocol,
+ gchar **str, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ guint32 len;
+ gint32 ret;
+ gint32 xfer = 0;
+ gint32 read_len = 0;
+
+ /* read the length into read_len */
+ if ((ret =
+ thrift_protocol_read_i32 (protocol, &read_len, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (read_len > 0)
+ {
+ /* allocate the memory for the string */
+ len = (guint32) read_len + 1; // space for null terminator
+ *str = g_new0 (gchar, len);
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ *str, read_len, error)) < 0)
+ {
+ g_free (*str);
+ *str = NULL;
+ len = 0;
+ return -1;
+ }
+ xfer += ret;
+ } else {
+ *str = NULL;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_binary_protocol_read_binary (ThriftProtocol *protocol,
+ gpointer *buf, guint32 *len,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+ gint32 ret;
+ gint32 xfer = 0;
+ gint32 read_len = 0;
+
+ /* read the length into read_len */
+ if ((ret =
+ thrift_protocol_read_i32 (protocol, &read_len, error)) < 0)
+ {
+ return -1;
+ }
+ xfer += ret;
+
+ if (read_len > 0)
+ {
+ /* allocate the memory as an array of unsigned char for binary data */
+ *len = (guint32) read_len;
+ *buf = g_new (guchar, *len);
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ *buf, *len, error)) < 0)
+ {
+ g_free (*buf);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+ xfer += ret;
+ } else {
+ *buf = NULL;
+ }
+
+ return xfer;
+}
+
+
diff --git a/lib/c_glib/src/protocol/thrift_binary_protocol.h b/lib/c_glib/src/protocol/thrift_binary_protocol.h
new file mode 100644
index 0000000..461c524
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_binary_protocol.h
@@ -0,0 +1,55 @@
+#ifndef _THRIFT_BINARY_PROTOCOL_H
+#define _THRIFT_BINARY_PROTOCOL_H
+
+#include <glib-object.h>
+
+#include "protocol/thrift_protocol.h"
+#include "transport/thrift_transport.h"
+
+/*! \file thrift_binary_protocol.h
+ * \brief Binary protocol implementation of a Thrift protocol. Implements the
+ * ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_BINARY_PROTOCOL (thrift_binary_protocol_get_type ())
+#define THRIFT_BINARY_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_BINARY_PROTOCOL, \
+ ThriftBinaryProtocol))
+#define THRIFT_IS_BINARY_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_BINARY_PROTOCOL))
+#define THRIFT_BINARY_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_BINARY_PROTOCOL, \
+ ThriftBinaryProtocolClass))
+#define THRIFT_IS_BINARY_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_BINARY_PROTOCOL))
+#define THRIFT_BINARY_PROTOCOL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_BINARY_PROTOCOL, \
+ ThriftBinaryProtocolClass))
+
+/* version numbers */
+#define THRIFT_BINARY_PROTOCOL_VERSION_1 0x80010000
+#define THRIFT_BINARY_PROTOCOL_VERSION_MASK 0xffff0000
+
+/*!
+ * Thrift Binary Protocol instance.
+ */
+struct _ThriftBinaryProtocol
+{
+ ThriftProtocol parent;
+};
+typedef struct _ThriftBinaryProtocol ThriftBinaryProtocol;
+
+/*!
+ * Thrift Binary Protocol class.
+ */
+struct _ThriftBinaryProtocolClass
+{
+ ThriftProtocolClass parent;
+};
+typedef struct _ThriftBinaryProtocolClass ThriftBinaryProtocolClass;
+
+/* used by THRIFT_TYPE_BINARY_PROTOCOL */
+GType thrift_binary_protocol_get_type (void);
+
+#endif /* _THRIFT_BINARY_PROTOCOL_H */
diff --git a/lib/c_glib/src/protocol/thrift_binary_protocol_factory.c b/lib/c_glib/src/protocol/thrift_binary_protocol_factory.c
new file mode 100644
index 0000000..a3b4373
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_binary_protocol_factory.c
@@ -0,0 +1,58 @@
+
+#include "thrift.h"
+#include "protocol/thrift_binary_protocol.h"
+#include "protocol/thrift_binary_protocol_factory.h"
+
+/* forward declarations */
+static void thrift_binary_protocol_factory_class_init (ThriftProtocolFactoryClass *cls);
+
+ThriftProtocol *thrift_binary_protocol_factory_get_protocol (ThriftProtocolFactory *factory, ThriftTransport *transport);
+
+GType
+thrift_binary_protocol_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftBinaryProtocolFactoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_binary_protocol_factory_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftBinaryProtocolFactory),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_PROTOCOL_FACTORY,
+ "ThriftBinaryProtocolFactoryType",
+ &info, 0);
+ }
+
+ return type;
+}
+
+static void
+thrift_binary_protocol_factory_class_init (ThriftProtocolFactoryClass *cls)
+{
+ cls->get_protocol = thrift_binary_protocol_factory_get_protocol;
+}
+
+ThriftProtocol *
+thrift_binary_protocol_factory_get_protocol (ThriftProtocolFactory *factory,
+ ThriftTransport *transport)
+{
+ THRIFT_UNUSED_VAR (factory);
+
+ ThriftBinaryProtocol *tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+ "transport", transport, NULL);
+
+ return THRIFT_PROTOCOL (tb);
+}
+
+
diff --git a/lib/c_glib/src/protocol/thrift_binary_protocol_factory.h b/lib/c_glib/src/protocol/thrift_binary_protocol_factory.h
new file mode 100644
index 0000000..ae4ae40
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_binary_protocol_factory.h
@@ -0,0 +1,46 @@
+#ifndef _THRIFT_BINARY_PROTOCOL_FACTORY_H
+#define _THRIFT_BINARY_PROTOCOL_FACTORY_H
+
+#include <glib-object.h>
+
+#include "protocol/thrift_protocol_factory.h"
+
+/* type macros */
+#define THRIFT_TYPE_BINARY_PROTOCOL_FACTORY \
+ (thrift_binary_protocol_factory_get_type ())
+#define THRIFT_BINARY_PROTOCOL_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_BINARY_PROTOCOL_FACTORY, \
+ ThriftBinaryProtocolFactory))
+#define THRIFT_IS_BINARY_PROTOCOL_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_BINARY_PROTOCOL_FACTORY))
+#define THRIFT_BINARY_PROTOCOL_FACTORY_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_BINARY_PROTOCOL_FACTORY, \
+ ThriftBinaryProtocolFactoryClass))
+#define THRIFT_IS_BINARY_PROTOCOL_FACTORY_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_BINARY_PROTOCOL_FACTORY))
+#define THRIFT_BINARY_PROTOCOL_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_BINARY_PROTOCOL_FACTORY, \
+ ThriftBinaryProtocolFactoryClass))
+
+struct _ThriftBinaryProtocolFactory
+{
+ ThriftProtocolFactory parent;
+};
+typedef struct _ThriftBinaryProtocolFactory ThriftBinaryProtocolFactory;
+
+struct _ThriftBinaryProtocolFactoryClass
+{
+ ThriftProtocolFactoryClass parent;
+};
+typedef struct _ThriftBinaryProtocolFactoryClass
+ ThriftBinaryProtocolFactoryClass;
+
+/* used by THRIFT_TYPE_BINARY_PROTOCOL_FACTORY */
+GType thrift_binary_protocol_factory_get_type (void);
+
+#endif /* _THRIFT_BINARY_PROTOCOL_FACTORY_H */
diff --git a/lib/c_glib/src/protocol/thrift_protocol.c b/lib/c_glib/src/protocol/thrift_protocol.c
new file mode 100644
index 0000000..8ea54b6
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_protocol.c
@@ -0,0 +1,604 @@
+#include "thrift.h"
+#include "protocol/thrift_protocol.h"
+#include "transport/thrift_transport.h"
+
+/* define the GError domain string */
+#define THRIFT_PROTOCOL_ERROR_DOMAIN "thrift-protocol-error-quark"
+
+/* object properties */
+enum _ThriftProtocolProperties
+{
+ PROP_0,
+ PROP_THRIFT_PROTOCOL_TRANSPORT
+};
+
+/* forward declarations */
+static void thrift_protocol_instance_init (ThriftProtocol *protocol);
+static void thrift_protocol_class_init (ThriftProtocolClass *cls);
+void thrift_protocol_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec);
+void thrift_protocol_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec);
+
+/* define ThriftProtocolInterface's type */
+GType
+thrift_protocol_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (ThriftProtocolClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_protocol_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftProtocol),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_protocol_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftProtocol",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+static void
+thrift_protocol_instance_init (ThriftProtocol *protocol)
+{
+ protocol->transport = NULL;
+}
+
+static void
+thrift_protocol_class_init (ThriftProtocolClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+
+ gobject_class->get_property = thrift_protocol_get_property;
+ gobject_class->set_property = thrift_protocol_set_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_PROTOCOL_TRANSPORT,
+ g_param_spec_object ("transport", "Transport", "Thrift Transport",
+ THRIFT_TYPE_TRANSPORT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ cls->write_message_begin = thrift_protocol_write_message_begin;
+ cls->write_message_end = thrift_protocol_write_message_end;
+ cls->write_struct_begin = thrift_protocol_write_struct_begin;
+ cls->write_struct_end = thrift_protocol_write_struct_end;
+ cls->write_field_begin = thrift_protocol_write_field_begin;
+ cls->write_field_end = thrift_protocol_write_field_end;
+ cls->write_field_stop = thrift_protocol_write_field_stop;
+ cls->write_map_begin = thrift_protocol_write_map_begin;
+ cls->write_map_end = thrift_protocol_write_map_end;
+ cls->write_list_begin = thrift_protocol_write_list_begin;
+ cls->write_list_end = thrift_protocol_write_list_end;
+ cls->write_set_begin = thrift_protocol_write_set_begin;
+ cls->write_set_end = thrift_protocol_write_set_end;
+ cls->write_bool = thrift_protocol_write_bool;
+ cls->write_byte = thrift_protocol_write_byte;
+ cls->write_i16 = thrift_protocol_write_i16;
+ cls->write_i32 = thrift_protocol_write_i32;
+ cls->write_i64 = thrift_protocol_write_i64;
+ cls->write_double = thrift_protocol_write_double;
+ cls->write_string = thrift_protocol_write_string;
+ cls->write_binary = thrift_protocol_write_binary;
+ cls->read_message_begin = thrift_protocol_read_message_begin;
+ cls->read_message_end = thrift_protocol_read_message_end;
+ cls->read_struct_begin = thrift_protocol_read_struct_begin;
+ cls->read_struct_end = thrift_protocol_read_struct_end;
+ cls->read_field_begin = thrift_protocol_read_field_begin;
+ cls->read_field_end = thrift_protocol_read_field_end;
+ cls->read_map_begin = thrift_protocol_read_map_begin;
+ cls->read_map_end = thrift_protocol_read_map_end;
+ cls->read_list_begin = thrift_protocol_read_list_begin;
+ cls->read_set_begin = thrift_protocol_read_set_begin;
+ cls->read_set_end = thrift_protocol_read_set_end;
+ cls->read_bool = thrift_protocol_read_bool;
+ cls->read_byte = thrift_protocol_read_byte;
+ cls->read_i16 = thrift_protocol_read_i16;
+ cls->read_i32 = thrift_protocol_read_i32;
+ cls->read_i64 = thrift_protocol_read_i64;
+ cls->read_double = thrift_protocol_read_double;
+ cls->read_string = thrift_protocol_read_string;
+ cls->read_binary = thrift_protocol_read_binary;
+}
+
+void
+thrift_protocol_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftProtocol *protocol = THRIFT_PROTOCOL (object);
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_PROTOCOL_TRANSPORT:
+ g_value_set_object (value, protocol->transport);
+ break;
+ }
+}
+
+void
+thrift_protocol_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+
+ ThriftProtocol *protocol = THRIFT_PROTOCOL (object);
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_PROTOCOL_TRANSPORT:
+ protocol->transport = g_value_get_object (value);
+ break;
+ }
+}
+
+
+gint32
+thrift_protocol_write_message_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftMessageType message_type,
+ const gint32 seqid, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_message_begin
+ (protocol, name,
+ message_type, seqid,
+ error);
+}
+
+gint32
+thrift_protocol_write_message_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_message_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_struct_begin (ThriftProtocol *protocol, const gchar *name,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_struct_begin (protocol,
+ name, error);
+}
+
+gint32
+thrift_protocol_write_struct_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_struct_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_field_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_field_begin (protocol,
+ name, field_type,
+ field_id, error);
+}
+
+gint32
+thrift_protocol_write_field_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_field_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_field_stop (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_field_stop (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_map_begin (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_map_begin (protocol,
+ key_type, value_type,
+ size, error);
+}
+
+gint32
+thrift_protocol_write_map_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_map_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_list_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_list_begin (protocol,
+ element_type, size,
+ error);
+}
+
+gint32
+thrift_protocol_write_list_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_list_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_set_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_set_begin (protocol,
+ element_type, size,
+ error);
+}
+
+gint32
+thrift_protocol_write_set_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_set_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_write_bool (ThriftProtocol *protocol,
+ const gboolean value, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_bool (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_byte (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_i16 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_i32 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_i64 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_write_double (ThriftProtocol *protocol,
+ const gdouble value, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_double (protocol,
+ value, error);
+}
+
+gint32
+thrift_protocol_write_string (ThriftProtocol *protocol,
+ const gchar *str, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_string (protocol, str,
+ error);
+}
+
+gint32
+thrift_protocol_write_binary (ThriftProtocol *protocol, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->write_binary (protocol, buf,
+ len, error);
+}
+
+gint32
+thrift_protocol_read_message_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftMessageType *message_type,
+ gint32 *seqid, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_message_begin (protocol,
+ name, message_type,
+ seqid, error);
+}
+
+gint32
+thrift_protocol_read_message_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_message_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_struct_begin (ThriftProtocol *protocol,
+ gchar **name,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_struct_begin (protocol,
+ name,
+ error);
+}
+
+gint32
+thrift_protocol_read_struct_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_struct_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_field_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftType *field_type,
+ gint16 *field_id,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_field_begin (protocol,
+ name,
+ field_type,
+ field_id,
+ error);
+}
+
+gint32
+thrift_protocol_read_field_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_field_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_map_begin (ThriftProtocol *protocol,
+ ThriftType *key_type,
+ ThriftType *value_type, guint32 *size,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_map_begin (protocol,
+ key_type,
+ value_type,
+ size,
+ error);
+}
+
+gint32
+thrift_protocol_read_map_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_map_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_list_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_list_begin (protocol,
+ element_type,
+ size, error);
+}
+
+gint32
+thrift_protocol_read_list_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_list_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_set_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_set_begin (protocol,
+ element_type,
+ size, error);
+}
+
+gint32
+thrift_protocol_read_set_end (ThriftProtocol *protocol, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_set_end (protocol,
+ error);
+}
+
+gint32
+thrift_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_bool (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_byte (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_i16 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_i32 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+ GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_i64 (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_double (ThriftProtocol *protocol,
+ gdouble *value, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_double (protocol, value,
+ error);
+}
+
+gint32
+thrift_protocol_read_string (ThriftProtocol *protocol,
+ gchar **str, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_string (protocol, str,
+ error);
+}
+
+gint32
+thrift_protocol_read_binary (ThriftProtocol *protocol, gpointer *buf,
+ guint32 *len, GError **error)
+{
+ return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_binary (protocol, buf,
+ len, error);
+}
+
+gint32
+thrift_protocol_skip (ThriftProtocol *protocol, ThriftType type, GError **error)
+{
+ switch (type)
+ {
+ case T_BOOL:
+ {
+ gboolean boolv;
+ return thrift_protocol_read_bool (protocol, &boolv, error);
+ }
+ case T_BYTE:
+ {
+ gint8 bytev;
+ return thrift_protocol_read_byte (protocol, &bytev, error);
+ }
+
+ case T_I16:
+ {
+ gint16 i16;
+ return thrift_protocol_read_i16 (protocol, &i16, error);
+ }
+ case T_I32:
+ {
+ gint32 i32;
+ return thrift_protocol_read_i32 (protocol, &i32, error);
+ }
+ case T_I64:
+ {
+ gint64 i64;
+ return thrift_protocol_read_i64 (protocol, &i64, error);
+ }
+ case T_DOUBLE:
+ {
+ gdouble dub;
+ return thrift_protocol_read_double (protocol, &dub, error);
+ }
+ case T_STRING:
+ {
+ gpointer data;
+ guint32 len;
+ gint32 ret = thrift_protocol_read_binary (protocol, &data, &len, error);
+ g_free (data);
+ return ret;
+ }
+ case T_STRUCT:
+ {
+ guint32 result = 0;
+ gchar *name;
+ gint16 fid;
+ ThriftType ftype;
+ result += thrift_protocol_read_struct_begin (protocol, &name, error);
+
+ while (1)
+ {
+ result += thrift_protocol_read_field_begin (protocol, &name, &ftype,
+ &fid, error);
+ if (ftype == T_STOP)
+ {
+ break;
+ }
+ result += thrift_protocol_skip (protocol, ftype, error);
+ result += thrift_protocol_read_field_end (protocol, error);
+ }
+ result += thrift_protocol_read_struct_end (protocol, error);
+ return result;
+ }
+ case T_MAP:
+ {
+ guint32 result = 0;
+ ThriftType elem_type;
+ guint32 i, size;
+ result += thrift_protocol_read_set_begin (protocol, &elem_type, &size,
+ error);
+ for (i = 0; i < size; i++)
+ {
+ result += thrift_protocol_skip (protocol, elem_type, error);
+ }
+ result += thrift_protocol_read_set_end (protocol, error);
+ return result;
+ }
+ case T_LIST:
+ {
+ guint32 result = 0;
+ ThriftType elem_type;
+ guint32 i, size;
+ result += thrift_protocol_read_list_begin (protocol, &elem_type, &size,
+ error);
+ for (i = 0; i < size; i++)
+ {
+ result += thrift_protocol_skip (protocol, elem_type, error);
+ }
+ result += thrift_protocol_read_list_end (protocol, error);
+ return result;
+ }
+ default:
+ return 0;
+ }
+}
+
+/* define the GError domain for Thrift protocols */
+GQuark
+thrift_protocol_error_quark (void)
+{
+ return g_quark_from_static_string (THRIFT_PROTOCOL_ERROR_DOMAIN);
+}
+
diff --git a/lib/c_glib/src/protocol/thrift_protocol.h b/lib/c_glib/src/protocol/thrift_protocol.h
new file mode 100644
index 0000000..0340a60
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_protocol.h
@@ -0,0 +1,324 @@
+#ifndef _THRIFT_PROTOCOL_H
+#define _THRIFT_PROTOCOL_H
+
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+
+/**
+ * Enumerated definition of the types that the Thrift protocol supports.
+ * Take special note of the T_END type which is used specifically to mark
+ * the end of a sequence of fields.
+ */
+enum _ThriftType {
+ T_STOP = 0,
+ T_VOID = 1,
+ T_BOOL = 2,
+ T_BYTE = 3,
+ T_I08 = 3,
+ T_I16 = 6,
+ T_I32 = 8,
+ T_U64 = 9,
+ T_I64 = 10,
+ T_DOUBLE = 4,
+ T_STRING = 11,
+ T_UTF7 = 11,
+ T_STRUCT = 12,
+ T_MAP = 13,
+ T_SET = 14,
+ T_LIST = 15,
+ T_UTF8 = 16,
+ T_UTF16 = 17
+};
+typedef enum _ThriftType ThriftType;
+
+/**
+ * Enumerated definition of the message types that the Thrift protocol
+ * supports.
+ */
+enum _ThriftMessageType {
+ T_CALL = 1,
+ T_REPLY = 2,
+ T_EXCEPTION = 3,
+ T_ONEWAY = 4
+};
+typedef enum _ThriftMessageType ThriftMessageType;
+
+/*! \file thrift_protocol.h
+ * \brief Abstract class for Thrift protocol implementations.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_PROTOCOL (thrift_protocol_get_type ())
+#define THRIFT_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_PROTOCOL, ThriftProtocol))
+#define THRIFT_IS_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_PROTOCOL))
+#define THRIFT_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_PROTOCOL, \
+ ThriftProtocolClass))
+#define THRIFT_IS_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_PROTOCOL))
+#define THRIFT_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_PROTOCOL, \
+ ThriftProtocolClass))
+
+/*!
+ * Thrift Protocol object
+ */
+struct _ThriftProtocol
+{
+ GObject parent;
+
+ /* protected */
+ ThriftTransport *transport;
+};
+typedef struct _ThriftProtocol ThriftProtocol;
+
+/*!
+ * Thrift Protocol class
+ */
+struct _ThriftProtocolClass
+{
+ GObjectClass parent;
+
+ gint32 (*write_message_begin) (ThriftProtocol *protocol, const gchar *name,
+ const ThriftMessageType message_type,
+ const gint32 seqid, GError **error);
+ gint32 (*write_message_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_struct_begin) (ThriftProtocol *protocol, const gchar *name,
+ GError **error);
+ gint32 (*write_struct_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_field_begin) (ThriftProtocol *protocol, const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id, GError **error);
+ gint32 (*write_field_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_field_stop) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_map_begin) (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size, GError **error);
+ gint32 (*write_map_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_list_begin) (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error);
+ gint32 (*write_list_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_set_begin) (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error);
+ gint32 (*write_set_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*write_bool) (ThriftProtocol *protocol, const gboolean value,
+ GError **error);
+ gint32 (*write_byte) (ThriftProtocol *protocol, const gint8 value,
+ GError **error);
+ gint32 (*write_i16) (ThriftProtocol *protocol, const gint16 value,
+ GError **error);
+ gint32 (*write_i32) (ThriftProtocol *protocol, const gint32 value,
+ GError **error);
+ gint32 (*write_i64) (ThriftProtocol *protocol, const gint64 value,
+ GError **error);
+ gint32 (*write_double) (ThriftProtocol *protocol, const gdouble value,
+ GError **error);
+ gint32 (*write_string) (ThriftProtocol *protocol, const gchar *str,
+ GError **error);
+ gint32 (*write_binary) (ThriftProtocol *protocol, const gpointer buf,
+ const guint32 len, GError **error);
+
+ gint32 (*read_message_begin) (ThriftProtocol *thrift_protocol, gchar **name,
+ ThriftMessageType *message_type,
+ gint32 *seqid, GError **error);
+ gint32 (*read_message_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_struct_begin) (ThriftProtocol *protocol, gchar **name,
+ GError **error);
+ gint32 (*read_struct_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_field_begin) (ThriftProtocol *protocol, gchar **name,
+ ThriftType *field_type, gint16 *field_id,
+ GError **error);
+ gint32 (*read_field_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_map_begin) (ThriftProtocol *protocol, ThriftType *key_type,
+ ThriftType *value_type, guint32 *size,
+ GError **error);
+ gint32 (*read_map_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_list_begin) (ThriftProtocol *protocol, ThriftType *element_type,
+ guint32 *size, GError **error);
+ gint32 (*read_list_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_set_begin) (ThriftProtocol *protocol, ThriftType *element_type,
+ guint32 *size, GError **error);
+ gint32 (*read_set_end) (ThriftProtocol *protocol, GError **error);
+ gint32 (*read_bool) (ThriftProtocol *protocol, gboolean *value,
+ GError **error);
+ gint32 (*read_byte) (ThriftProtocol *protocol, gint8 *value, GError **error);
+ gint32 (*read_i16) (ThriftProtocol *protocol, gint16 *value, GError **error);
+ gint32 (*read_i32) (ThriftProtocol *protocol, gint32 *value, GError **error);
+ gint32 (*read_i64) (ThriftProtocol *protocol, gint64 *value, GError **error);
+ gint32 (*read_double) (ThriftProtocol *protocol, gdouble *value,
+ GError **error);
+ gint32 (*read_string) (ThriftProtocol *protocol, gchar **str, GError **error);
+ gint32 (*read_binary) (ThriftProtocol *protocol, gpointer *buf,
+ guint32 *len, GError **error);
+};
+typedef struct _ThriftProtocolClass ThriftProtocolClass;
+
+/* used by THRIFT_TYPE_PROTOCOL */
+GType thrift_protocol_get_type (void);
+
+/* virtual public methods */
+gint32 thrift_protocol_write_message_begin (ThriftProtocol *protocol,
+ const gchar *name, const ThriftMessageType message_type,
+ const gint32 seqid, GError **error);
+
+gint32 thrift_protocol_write_message_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_struct_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ GError **error);
+
+gint32 thrift_protocol_write_struct_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_field_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ GError **error);
+
+gint32 thrift_protocol_write_field_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_field_stop (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_map_begin (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size, GError **error);
+
+gint32 thrift_protocol_write_map_end (ThriftProtocol *protocol, GError **error);
+
+gint32 thrift_protocol_write_list_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error);
+
+gint32 thrift_protocol_write_list_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_set_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size, GError **error);
+
+gint32 thrift_protocol_write_set_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_write_bool (ThriftProtocol *protocol,
+ const gboolean value, GError **error);
+
+gint32 thrift_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
+ GError **error);
+
+gint32 thrift_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
+ GError **error);
+
+gint32 thrift_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
+ GError **error);
+
+gint32 thrift_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
+ GError **error);
+
+gint32 thrift_protocol_write_double (ThriftProtocol *protocol,
+ const gdouble value, GError **error);
+
+gint32 thrift_protocol_write_string (ThriftProtocol *protocol,
+ const gchar *str, GError **error);
+
+gint32 thrift_protocol_write_binary (ThriftProtocol *protocol,
+ const gpointer buf,
+ const guint32 len, GError **error);
+
+gint32 thrift_protocol_read_message_begin (ThriftProtocol *thrift_protocol,
+ gchar **name,
+ ThriftMessageType *message_type,
+ gint32 *seqid, GError **error);
+
+gint32 thrift_protocol_read_message_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_read_struct_begin (ThriftProtocol *protocol,
+ gchar **name,
+ GError **error);
+
+gint32 thrift_protocol_read_struct_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_read_field_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftType *field_type,
+ gint16 *field_id,
+ GError **error);
+
+gint32 thrift_protocol_read_field_end (ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_protocol_read_map_begin (ThriftProtocol *protocol,
+ ThriftType *key_type,
+ ThriftType *value_type, guint32 *size,
+ GError **error);
+
+gint32 thrift_protocol_read_map_end (ThriftProtocol *protocol, GError **error);
+
+gint32 thrift_protocol_read_list_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error);
+
+gint32 thrift_protocol_read_list_end (ThriftProtocol *protocol, GError **error);
+
+gint32 thrift_protocol_read_set_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error);
+
+gint32 thrift_protocol_read_set_end (ThriftProtocol *protocol, GError **error);
+
+gint32 thrift_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
+ GError **error);
+
+gint32 thrift_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+ GError **error);
+
+gint32 thrift_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+ GError **error);
+
+gint32 thrift_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+ GError **error);
+
+gint32 thrift_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+ GError **error);
+
+gint32 thrift_protocol_read_double (ThriftProtocol *protocol,
+ gdouble *value, GError **error);
+
+gint32 thrift_protocol_read_string (ThriftProtocol *protocol,
+ gchar **str, GError **error);
+
+gint32 thrift_protocol_read_binary (ThriftProtocol *protocol,
+ gpointer *buf, guint32 *len,
+ GError **error);
+
+gint32 thrift_protocol_skip (ThriftProtocol *protocol, ThriftType type,
+ GError **error);
+
+/* define error types */
+typedef enum
+{
+ THRIFT_PROTOCOL_ERROR_UNKNOWN,
+ THRIFT_PROTOCOL_ERROR_INVALID_DATA,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+ THRIFT_PROTOCOL_ERROR_NOT_IMPLEMENTED
+} ThriftProtocolError;
+
+/* define an error domain for GError to use */
+GQuark thrift_protocol_error_quark (void);
+#define THRIFT_PROTOCOL_ERROR (thrift_protocol_error_quark ())
+
+#endif /* _THRIFT_PROTOCOL_H */
diff --git a/lib/c_glib/src/protocol/thrift_protocol_factory.c b/lib/c_glib/src/protocol/thrift_protocol_factory.c
new file mode 100644
index 0000000..53b468d
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_protocol_factory.c
@@ -0,0 +1,50 @@
+#include "thrift.h"
+#include "protocol/thrift_protocol_factory.h"
+
+/* forward declarations */
+static void thrift_protocol_factory_class_init (ThriftProtocolFactoryClass *cls);
+ThriftProtocol *thrift_protocol_factory_get_protocol(ThriftProtocolFactory *factory, ThriftTransport *transport);
+
+
+/* define ThriftProtocolFactoryInterface's type */
+GType
+thrift_protocol_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (ThriftProtocolFactoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_protocol_factory_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftProtocolFactory),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftProtocolFactory",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+static void
+thrift_protocol_factory_class_init (ThriftProtocolFactoryClass *cls)
+{
+ cls->get_protocol = thrift_protocol_factory_get_protocol;
+}
+
+ThriftProtocol *
+thrift_protocol_factory_get_protocol(ThriftProtocolFactory *factory,
+ ThriftTransport *transport)
+{
+ return THRIFT_PROTOCOL_FACTORY_GET_CLASS (factory)->get_protocol (factory,
+ transport);
+}
+
diff --git a/lib/c_glib/src/protocol/thrift_protocol_factory.h b/lib/c_glib/src/protocol/thrift_protocol_factory.h
new file mode 100644
index 0000000..d153255
--- /dev/null
+++ b/lib/c_glib/src/protocol/thrift_protocol_factory.h
@@ -0,0 +1,57 @@
+#ifndef _THRIFT_PROTOCOL_FACTORY_H
+#define _THRIFT_PROTOCOL_FACTORY_H
+
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+#include "protocol/thrift_protocol.h"
+
+/*! \file thrift_protocol_factory.h
+ * \brief Abstract class for Thrift protocol factory implementations.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_PROTOCOL_FACTORY (thrift_protocol_factory_get_type ())
+#define THRIFT_PROTOCOL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_PROTOCOL_FACTORY, \
+ ThriftProtocolFactory))
+#define THRIFT_IS_PROTOCOL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_PROTOCOL_FACTORY))
+#define THRIFT_PROTOCOL_FACTORY_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_PROTOCOL_FACTORY, \
+ ThriftProtocolFactoryClass))
+#define THRIFT_IS_PROTOCOL_FACTORY_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_PROTOCOL_FACTORY))
+#define THRIFT_PROTOCOL_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_PROTOCOL_FACTORY, \
+ ThriftProtocolFactoryClass))
+
+/*!
+ * Thrift Protocol Factory object
+ */
+struct _ThriftProtocolFactory
+{
+ GObject parent;
+};
+typedef struct _ThriftProtocolFactory ThriftProtocolFactory;
+
+/*!
+ * Thrift Protocol Factory class
+ */
+struct _ThriftProtocolFactoryClass
+{
+ GObjectClass parent;
+
+ ThriftProtocol *(*get_protocol) (ThriftProtocolFactory *factory,
+ ThriftTransport *transport);
+};
+typedef struct _ThriftProtocolFactoryClass ThriftProtocolFactoryClass;
+
+/* used by THRIFT_TYPE_PROTOCOL_FACTORY */
+GType thrift_protocol_factory_get_type (void);
+
+/* virtual public methods */
+ThriftProtocol *thrift_protocol_factory_get_protocol(ThriftProtocolFactory *factory, ThriftTransport *transport);
+
+#endif /* _THRIFT_PROTOCOL_FACTORY_H */
diff --git a/lib/c_glib/src/server/thrift_server.c b/lib/c_glib/src/server/thrift_server.c
new file mode 100644
index 0000000..c7e6c1f
--- /dev/null
+++ b/lib/c_glib/src/server/thrift_server.c
@@ -0,0 +1,192 @@
+#include "thrift.h"
+#include "thrift_server.h"
+
+/* object properties */
+enum _ThriftServerProperties
+{
+ PROP_0,
+ PROP_THRIFT_SERVER_PROCESSOR,
+ PROP_THRIFT_SERVER_SERVER_TRANSPORT,
+ PROP_THRIFT_SERVER_INPUT_TRANSPORT_FACTORY,
+ PROP_THRIFT_SERVER_OUTPUT_TRANSPORT_FACTORY,
+ PROP_THRIFT_SERVER_INPUT_PROTOCOL_FACTORY,
+ PROP_THRIFT_SERVER_OUTPUT_PROTOCOL_FACTORY
+};
+
+/* forward declarations */
+static void thrift_server_instance_init (ThriftServer *server);
+static void thrift_server_class_init (ThriftServerClass *cls);
+void thrift_server_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec);
+void thrift_server_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec);
+
+
+/* define ThriftServerClass's type */
+GType
+thrift_server_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftServerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_server_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftServer),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_server_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftServer",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+/* instance initializer for Thrift Server */
+static void
+thrift_server_instance_init (ThriftServer *server)
+{
+ server->processor = NULL;
+ server->server_transport = NULL;
+ server->input_transport_factory = NULL;
+ server->output_transport_factory = NULL;
+ server->input_protocol_factory = NULL;
+ server->output_protocol_factory = NULL;
+}
+
+/* class initializer for ThriftServer
+ * TODO: implement ServerEventHandler as a GClosure
+ */
+static void
+thrift_server_class_init (ThriftServerClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+
+ gobject_class->get_property = thrift_server_get_property;
+ gobject_class->set_property = thrift_server_set_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_PROCESSOR,
+ g_param_spec_object ("processor", "Processor", "Thrift Processor",
+ THRIFT_TYPE_PROCESSOR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_SERVER_TRANSPORT,
+ g_param_spec_object ("server_transport", "Server Transport",
+ "Thrift Server Transport",
+ THRIFT_TYPE_SERVER_TRANSPORT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_INPUT_TRANSPORT_FACTORY,
+ g_param_spec_object ("input_transport_factory", "Input Transport Factory",
+ "Thrift Server Input Transport Factory",
+ THRIFT_TYPE_TRANSPORT_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_OUTPUT_TRANSPORT_FACTORY,
+ g_param_spec_object ("output_transport_factory",
+ "Output Transport Factory",
+ "Thrift Server Output Transport Factory",
+ THRIFT_TYPE_TRANSPORT_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_INPUT_PROTOCOL_FACTORY,
+ g_param_spec_object ("input_protocol_factory", "Input Protocol Factory",
+ "Thrift Server Input Protocol Factory",
+ THRIFT_TYPE_PROTOCOL_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_OUTPUT_PROTOCOL_FACTORY,
+ g_param_spec_object ("output_protocol_factory", "Output Protocol Factory",
+ "Thrift Server Output Protocol Factory",
+ THRIFT_TYPE_PROTOCOL_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /* set these as virtual methods to be implemented by a subclass */
+ cls->serve = thrift_server_serve;
+ cls->stop = thrift_server_stop;
+}
+
+void
+thrift_server_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftServer *server = THRIFT_SERVER (object);
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SERVER_PROCESSOR:
+ g_value_set_object (value, server->processor);
+ break;
+ case PROP_THRIFT_SERVER_SERVER_TRANSPORT:
+ g_value_set_object (value, server->server_transport);
+ break;
+ case PROP_THRIFT_SERVER_INPUT_TRANSPORT_FACTORY:
+ g_value_set_object (value, server->input_transport_factory);
+ break;
+ case PROP_THRIFT_SERVER_OUTPUT_TRANSPORT_FACTORY:
+ g_value_set_object (value, server->output_transport_factory);
+ break;
+ case PROP_THRIFT_SERVER_INPUT_PROTOCOL_FACTORY:
+ g_value_set_object (value, server->input_protocol_factory);
+ break;
+ case PROP_THRIFT_SERVER_OUTPUT_PROTOCOL_FACTORY:
+ g_value_set_object (value, server->output_protocol_factory);
+ break;
+ }
+}
+
+void
+thrift_server_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ ThriftServer *server = THRIFT_SERVER (object);
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SERVER_PROCESSOR:
+ server->processor = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_SERVER_SERVER_TRANSPORT:
+ server->server_transport = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_SERVER_INPUT_TRANSPORT_FACTORY:
+ server->input_transport_factory = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_SERVER_OUTPUT_TRANSPORT_FACTORY:
+ server->output_transport_factory = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_SERVER_INPUT_PROTOCOL_FACTORY:
+ server->input_protocol_factory = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_SERVER_OUTPUT_PROTOCOL_FACTORY:
+ server->output_protocol_factory = g_value_get_object (value);
+ break;
+ }
+}
+
+void
+thrift_server_serve (ThriftServer *server)
+{
+ THRIFT_SERVER_GET_CLASS (server)->serve (server);
+}
+
+void
+thrift_server_stop (ThriftServer *server)
+{
+ THRIFT_SERVER_GET_CLASS (server)->stop (server);
+}
+
diff --git a/lib/c_glib/src/server/thrift_server.h b/lib/c_glib/src/server/thrift_server.h
new file mode 100644
index 0000000..2bbe95b
--- /dev/null
+++ b/lib/c_glib/src/server/thrift_server.h
@@ -0,0 +1,75 @@
+#ifndef _THRIFT_SERVER_H
+#define _THRIFT_SERVER_H
+
+#include <glib-object.h>
+
+#include "processor/thrift_processor.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_transport_factory.h"
+#include "protocol/thrift_protocol_factory.h"
+
+/*! \file thrift_server.h
+ * \brief Abstract class for Thrift servers.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SERVER (thrift_server_get_type ())
+#define THRIFT_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_SERVER, ThriftServer))
+#define THRIFT_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_SERVER))
+#define THRIFT_SERVER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_SERVER, \
+ ThriftServerClass))
+#define THRIFT_IS_SERVER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_SERVER))
+#define THRIFT_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_SERVER, \
+ ThriftServerClass))
+
+/*!
+ * Thrift Server object
+ */
+struct _ThriftServer
+{
+ GObject parent;
+
+ /* protected */
+ ThriftProcessor *processor;
+ ThriftServerTransport *server_transport;
+ ThriftTransportFactory *input_transport_factory;
+ ThriftTransportFactory *output_transport_factory;
+ ThriftProtocolFactory *input_protocol_factory;
+ ThriftProtocolFactory *output_protocol_factory;
+};
+typedef struct _ThriftServer ThriftServer;
+
+/*!
+ * Thrift Server class
+ */
+struct _ThriftServerClass
+{
+ GObjectClass parent;
+
+ /* vtable */
+ void (*serve) (ThriftServer *server);
+ void (*stop) (ThriftServer *server);
+};
+typedef struct _ThriftServerClass ThriftServerClass;
+
+/* used by THRIFT_TYPE_SERVER */
+GType thrift_server_get_type (void);
+
+/*!
+ * Processes the request.
+ * \public \memberof ThriftServerClass
+ */
+void thrift_server_serve (ThriftServer *server);
+
+/*!
+ * Stop handling requests.
+ */
+void thrift_server_stop (ThriftServer *server);
+
+#endif /* _THRIFT_SERVER_H */
+
diff --git a/lib/c_glib/src/server/thrift_simple_server.c b/lib/c_glib/src/server/thrift_simple_server.c
new file mode 100644
index 0000000..1957928
--- /dev/null
+++ b/lib/c_glib/src/server/thrift_simple_server.c
@@ -0,0 +1,133 @@
+
+#include "server/thrift_simple_server.h"
+#include "transport/thrift_transport_factory.h"
+#include "protocol/thrift_protocol_factory.h"
+#include "protocol/thrift_binary_protocol_factory.h"
+
+static void thrift_simple_server_instance_init (ThriftServer *server);
+static void thrift_simple_server_class_init (ThriftServerClass *cls);
+
+/* forward declarations */
+void thrift_simple_server_serve (ThriftServer *server);
+void thrift_simple_server_stop (ThriftServer *server);
+
+GType
+thrift_simple_server_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftSimpleServerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_simple_server_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftSimpleServer),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_simple_server_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_SERVER,
+ "ThriftSimpleServerType",
+ &info, 0);
+ }
+
+ return type;
+}
+
+static void
+thrift_simple_server_instance_init (ThriftServer *server)
+{
+ (THRIFT_SIMPLE_SERVER (server))->running = FALSE;
+
+ if (server->input_transport_factory == NULL)
+ {
+ server->input_transport_factory =
+ g_object_new (THRIFT_TYPE_TRANSPORT_FACTORY, NULL);
+ }
+ if (server->output_transport_factory == NULL)
+ {
+ server->output_transport_factory =
+ g_object_new (THRIFT_TYPE_TRANSPORT_FACTORY, NULL);
+ }
+ if (server->input_protocol_factory == NULL)
+ {
+ server->input_protocol_factory =
+ g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY, NULL);
+ }
+ if (server->output_protocol_factory == NULL)
+ {
+ server->output_protocol_factory =
+ g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY, NULL);
+ }
+}
+
+
+/* initialize the class */
+static void
+thrift_simple_server_class_init (ThriftServerClass *cls)
+{
+ cls->serve = thrift_simple_server_serve;
+ cls->stop = thrift_simple_server_stop;
+}
+
+void
+thrift_simple_server_serve (ThriftServer *server)
+{
+ g_return_if_fail (THRIFT_IS_SIMPLE_SERVER (server));
+
+ ThriftTransport *t = NULL;
+ ThriftTransport *input_transport = NULL, *output_transport = NULL;
+ ThriftProtocol *input_protocol = NULL, *output_protocol = NULL;
+ ThriftSimpleServer *tss = THRIFT_SIMPLE_SERVER (server);
+
+ THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport)
+ ->listen (server->server_transport, NULL);
+
+ tss->running = TRUE;
+ while (tss->running == TRUE)
+ {
+ t = thrift_server_transport_accept (server->server_transport, NULL);
+ input_transport =
+ THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->input_transport_factory)
+ ->get_transport (server->input_transport_factory, t);
+ output_transport =
+ THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->output_transport_factory)
+ ->get_transport (server->output_transport_factory, t);
+ input_protocol =
+ THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->input_protocol_factory)
+ ->get_protocol (server->input_protocol_factory, t);
+ output_protocol =
+ THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->output_protocol_factory)
+ ->get_protocol (server->output_protocol_factory, t);
+
+ while (THRIFT_PROCESSOR_GET_CLASS (server->processor)
+ ->process (server->processor, input_protocol, output_protocol))
+ {
+ // TODO: implement transport peek ()
+ }
+
+ // TODO: handle exceptions
+ THRIFT_TRANSPORT_GET_CLASS (input_transport)->close (input_transport, NULL);
+ THRIFT_TRANSPORT_GET_CLASS (output_transport)->close (output_transport,
+ NULL);
+ }
+
+ // attempt to shutdown
+ THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport)
+ ->close (server->server_transport, NULL);
+}
+
+void
+thrift_simple_server_stop (ThriftServer *server)
+{
+ g_return_if_fail (THRIFT_IS_SIMPLE_SERVER (server));
+ (THRIFT_SIMPLE_SERVER (server))->running = FALSE;
+}
+
+
diff --git a/lib/c_glib/src/server/thrift_simple_server.h b/lib/c_glib/src/server/thrift_simple_server.h
new file mode 100644
index 0000000..137f623
--- /dev/null
+++ b/lib/c_glib/src/server/thrift_simple_server.h
@@ -0,0 +1,53 @@
+#ifndef _THRIFT_SIMPLE_SERVER_H
+#define _THRIFT_SIMPLE_SERVER_H
+
+#include <glib-object.h>
+
+#include "server/thrift_server.h"
+
+/*! \file thrift_simple_server.h
+ * \brief A simple Thrift server, single-threaded.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SIMPLE_SERVER (thrift_simple_server_get_type ())
+#define THRIFT_SIMPLE_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_SIMPLE_SERVER, \
+ ThriftSimpleServer))
+#define THRIFT_IS_SIMPLE_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_SIMPLE_SERVER))
+#define THRIFT_SIMPLE_SERVER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c) \
+ THRIFT_TYPE_SIMPLE_SERVER, \
+ ThriftSimpleServerClass))
+#define THRIFT_IS_SIMPLE_SERVER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_SIMPLE_SERVER))
+#define THRIFT_SIMPLE_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_SIMPLE_SERVER, \
+ ThriftSimpleServerClass))
+
+/**
+ * Thrift Simple Server instance.
+ */
+struct _ThriftSimpleServer
+{
+ ThriftServer parent;
+
+ /* private */
+ volatile gboolean running;
+};
+typedef struct _ThriftSimpleServer ThriftSimpleServer;
+
+/**
+ * Thrift Simple Server class.
+ */
+struct _ThriftSimpleServerClass
+{
+ ThriftServerClass parent;
+};
+typedef struct _ThriftSimpleServerClass ThriftSimpleServerClass;
+
+/* used by THRIFT_TYPE_SIMPLE_SERVER */
+GType thrift_simple_server_get_type (void);
+
+#endif /* _THRIFT_SIMPLE_SERVER_H */
+
diff --git a/lib/c_glib/src/thrift.c b/lib/c_glib/src/thrift.c
new file mode 100644
index 0000000..18a36aa
--- /dev/null
+++ b/lib/c_glib/src/thrift.c
@@ -0,0 +1,13 @@
+#include "thrift.h"
+
+/**
+ * GHashTable callback to add keys to a GList.
+ */
+void
+thrift_hash_table_get_keys (gpointer key, gpointer value, gpointer user_data)
+{
+ THRIFT_UNUSED_VAR (value);
+ GList **list = (GList **) user_data;
+ *list = g_list_append (*list, key);
+}
+
diff --git a/lib/c_glib/src/thrift.h b/lib/c_glib/src/thrift.h
new file mode 100644
index 0000000..59db6fd
--- /dev/null
+++ b/lib/c_glib/src/thrift.h
@@ -0,0 +1,18 @@
+#ifndef _THRIFT_H
+#define _THRIFT_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+/* this macro is called to satisfy -Wall hardcore compilation */
+#ifndef THRIFT_UNUSED_VAR
+# define THRIFT_UNUSED_VAR(x) ((void) x)
+#endif
+
+void thrift_hash_table_get_keys (gpointer key, gpointer value,
+ gpointer user_data);
+
+#endif // #ifndef _THRIFT_THRIFT_H
diff --git a/lib/c_glib/src/thrift_application_exception.c b/lib/c_glib/src/thrift_application_exception.c
new file mode 100644
index 0000000..fa57a81
--- /dev/null
+++ b/lib/c_glib/src/thrift_application_exception.c
@@ -0,0 +1,192 @@
+#include "thrift_application_exception.h"
+#include "protocol/thrift_protocol.h"
+
+/* forward declarations */
+void thrift_application_exception_instance_init (ThriftApplicationException *object);
+void thrift_application_exception_class_init (ThriftStructClass *cls);
+gint32 thrift_application_exception_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error);
+gint32 thrift_application_exception_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error);
+
+GType
+thrift_application_exception_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo type_info =
+ {
+ sizeof (ThriftApplicationExceptionClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_application_exception_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftApplicationException),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_application_exception_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_STRUCT,
+ "ThriftApplicationExceptionType",
+ &type_info, 0);
+ }
+ return type;
+}
+
+void
+thrift_application_exception_instance_init (ThriftApplicationException *object)
+{
+ object->type = 0;
+ object->__isset_type = FALSE;
+ object->message = NULL;
+ object->__isset_message = FALSE;
+}
+
+void
+thrift_application_exception_class_init (ThriftStructClass *cls)
+{
+ cls->read = thrift_application_exception_read;
+ cls->write = thrift_application_exception_write;
+}
+
+gint32
+thrift_application_exception_read (ThriftStruct *object,
+ ThriftProtocol *protocol, GError **error)
+{
+ gint32 ret;
+ gint32 xfer = 0;
+ gchar *name;
+ ThriftType ftype;
+ gint16 fid;
+ ThriftApplicationException *this = THRIFT_APPLICATION_EXCEPTION (object);
+
+ /* read the struct begin marker */
+ if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)
+ {
+ if (name) g_free (name);
+ return -1;
+ }
+ xfer += ret;
+ if (name) g_free (name);
+
+ while (1)
+ {
+ if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype,
+ &fid, error)) < 0)
+ {
+ if (name) g_free (name);
+ return -1;
+ }
+ xfer += ret;
+ if (name) g_free (name);
+
+ /* break if we get a STOP field */
+ if (ftype == T_STOP)
+ {
+ break;
+ }
+
+ switch (fid)
+ {
+ case 1:
+ if (ftype == T_STRING)
+ {
+ if ((ret = thrift_protocol_read_string (protocol, &this->message,
+ error)) < 0)
+ return -1;
+ xfer += ret;
+ this->__isset_message = TRUE;
+ } else {
+ if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)
+ return -1;
+ xfer += ret;
+ }
+ break;
+ case 2:
+ if (ftype == T_I32)
+ {
+ if ((ret = thrift_protocol_read_i32 (protocol, &this->type,
+ error)) < 0)
+ return -1;
+ xfer += ret;
+ this->__isset_type = TRUE;
+ } else {
+ if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)
+ return -1;
+ xfer += ret;
+ }
+ break;
+ default:
+ if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)
+ return -1;
+ xfer += ret;
+ break;
+ }
+ if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+ }
+
+ if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+
+ return xfer;
+}
+
+gint32
+thrift_application_exception_write (ThriftStruct *object,
+ ThriftProtocol *protocol, GError **error)
+{
+ gint32 ret;
+ gint32 xfer = 0;
+
+ ThriftApplicationException *this = THRIFT_APPLICATION_EXCEPTION (object);
+
+ if ((ret = thrift_protocol_write_struct_begin (protocol,
+ "TApplicationException",
+ error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_field_begin (protocol, "message",
+ T_STRING, 1, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_string (protocol, this->message, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_field_begin (protocol, "type",
+ T_I32, 2, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_i32 (protocol, this->type, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+ if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)
+ return -1;
+ xfer += ret;
+
+ return xfer;
+}
+
+
+/* GError domain */
+#define THRIFT_APPLICATION_EXCEPTION_ERROR_DOMAIN "thrift-application-exception-error-quark"
+
+GQuark
+thrift_application_exception_error_quark (void)
+{
+ return g_quark_from_static_string (THRIFT_APPLICATION_EXCEPTION_ERROR_DOMAIN);
+}
+
diff --git a/lib/c_glib/src/thrift_application_exception.h b/lib/c_glib/src/thrift_application_exception.h
new file mode 100644
index 0000000..8639df2
--- /dev/null
+++ b/lib/c_glib/src/thrift_application_exception.h
@@ -0,0 +1,67 @@
+#ifndef _THRIFT_APPLICATION_EXCEPTION_H
+#define _THRIFT_APPLICATION_EXCEPTION_H
+
+#include <glib-object.h>
+#include "thrift_struct.h"
+
+/*! \file thrift_application_exception.h
+ * \brief C Implementation of a TApplicationException.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_APPLICATION_EXCEPTION \
+ (thrift_application_exception_get_type ())
+#define THRIFT_APPLICATION_EXCEPTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_APPLICATION_EXCEPTION, \
+ ThriftApplicationException))
+#define THRIFT_IS_APPLICATION_EXCEPTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_APPLICATION_EXCEPTION))
+#define THRIFT_APPLICATION_EXCEPTION_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_APPLICATION_EXCEPTION, \
+ ThriftApplicationExceptionClass))
+#define THRIFT_IS_APPLICATION_EXCEPTION_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_APPLICATION_EXCEPTION))
+#define THRIFT_APPLICATION_EXCEPTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_APPLICATION_EXCEPTION, \
+ ThriftApplicationExceptionClass))
+
+struct _ThriftApplicationException
+{
+ ThriftStruct parent;
+
+ /* public */
+ gint32 type;
+ gboolean __isset_type;
+ gchar *message;
+ gboolean __isset_message;
+};
+typedef struct _ThriftApplicationException ThriftApplicationException;
+
+struct _ThriftApplicationExceptionClass
+{
+ ThriftStructClass parent;
+};
+typedef struct _ThriftApplicationExceptionClass ThriftApplicationExceptionClass;
+
+GType thrift_application_exception_get_type (void);
+
+/* gerror codes */
+typedef enum
+{
+ THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,
+ THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD,
+ THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE,
+ THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME,
+ THRIFT_APPLICATION_EXCEPTION_ERROR_BAD_SEQUENCE_ID,
+ THRIFT_APPLICATION_EXCEPTION_ERROR_MISSING_RESULT
+} ThriftApplicationExceptionError;
+
+/* define error domain for GError */
+GQuark thrift_application_exception_error_quark (void);
+#define THRIFT_APPLICATION_EXCEPTION_ERROR (thrift_application_exception_error_quark ())
+
+#endif /* _THRIFT_APPLICATION_EXCEPTION_H */
diff --git a/lib/c_glib/src/thrift_struct.c b/lib/c_glib/src/thrift_struct.c
new file mode 100644
index 0000000..3f73c38
--- /dev/null
+++ b/lib/c_glib/src/thrift_struct.c
@@ -0,0 +1,55 @@
+#include "thrift_struct.h"
+
+static void
+thrift_struct_class_init (ThriftStructClass *cls)
+{
+ ThriftStructClass *c = THRIFT_STRUCT_CLASS (cls);
+ c->read = thrift_struct_read;
+ c->write = thrift_struct_write;
+}
+
+GType
+thrift_struct_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo type_info =
+ {
+ sizeof (ThriftStructClass),
+ NULL, /* base_init */
+ NULL, /* base finalize */
+ (GClassInitFunc) thrift_struct_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftStruct),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "ThriftStructType",
+ &type_info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+gint32
+thrift_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_STRUCT (object), -1);
+ return THRIFT_STRUCT_GET_CLASS (object)->read (object, protocol, error);
+}
+
+gint32
+thrift_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_STRUCT (object), -1);
+ return THRIFT_STRUCT_GET_CLASS (object)->write (object, protocol, error);
+}
+
diff --git a/lib/c_glib/src/thrift_struct.h b/lib/c_glib/src/thrift_struct.h
new file mode 100644
index 0000000..f3e6060
--- /dev/null
+++ b/lib/c_glib/src/thrift_struct.h
@@ -0,0 +1,50 @@
+#ifndef THRIFT_STRUCT_H
+#define THRIFT_STRUCT_H
+
+#include <glib-object.h>
+
+#include "protocol/thrift_protocol.h"
+
+#define THRIFT_TYPE_STRUCT (thrift_struct_get_type ())
+#define THRIFT_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_STRUCT, ThriftStruct))
+#define THRIFT_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_STRUCT, ThriftStructClass))
+#define THRIFT_IS_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_STRUCT))
+#define THRIFT_IS_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_STRUCT))
+#define THRIFT_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_STRUCT, \
+ ThriftStructClass))
+
+/* struct */
+struct _ThriftStruct
+{
+ GObject parent;
+
+ /* private */
+};
+typedef struct _ThriftStruct ThriftStruct;
+
+struct _ThriftStructClass
+{
+ GObjectClass parent;
+
+ /* public */
+ gint32 (*read) (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+ gint32 (*write) (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+};
+typedef struct _ThriftStructClass ThriftStructClass;
+
+GType thrift_struct_get_type (void);
+
+gint32 thrift_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+
+gint32 thrift_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_buffered_transport.c b/lib/c_glib/src/transport/thrift_buffered_transport.c
new file mode 100644
index 0000000..45ea31c
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_buffered_transport.c
@@ -0,0 +1,406 @@
+#include <assert.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_buffered_transport.h"
+
+/* object properties */
+enum _ThriftBufferedTransportProperties
+{
+ PROP_0,
+ PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT,
+ PROP_THRIFT_BUFFERED_TRANSPORT_READ_BUFFER_SIZE,
+ PROP_THRIFT_BUFFERED_TRANSPORT_WRITE_BUFFER_SIZE
+};
+
+/* forward declarations */
+static void thrift_buffered_transport_instance_init (ThriftBufferedTransport *self);
+static void thrift_buffered_transport_class_init (ThriftBufferedTransportClass *cls);
+
+
+gboolean thrift_buffered_transport_is_open (ThriftTransport *transport);
+gboolean thrift_buffered_transport_open (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_buffered_transport_close (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_buffered_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+gboolean thrift_buffered_transport_read_end (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_buffered_transport_read_slow (ThriftTransport *transport,
+ gpointer buf, guint32 len,
+ GError **error);
+gboolean thrift_buffered_transport_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error);
+gboolean thrift_buffered_transport_write_end (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_buffered_transport_write_slow (ThriftTransport *transport,
+ gpointer buf, guint32 len,
+ GError **error);
+gboolean thrift_buffered_transport_flush (ThriftTransport *transport,
+ GError **error);
+
+GType
+thrift_buffered_transport_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftBufferedTransportClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_buffered_transport_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftBufferedTransport),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_buffered_transport_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_TRANSPORT,
+ "ThriftBufferedTransport", &info, 0);
+ }
+
+ return type;
+}
+
+/* initializes the instance */
+static void
+thrift_buffered_transport_instance_init (ThriftBufferedTransport *transport)
+{
+ transport->transport = NULL;
+ transport->r_buf = g_byte_array_new ();
+ transport->w_buf = g_byte_array_new ();
+}
+
+/* destructor */
+static void
+thrift_buffered_transport_finalize (GObject *object)
+{
+ ThriftBufferedTransport *transport = THRIFT_BUFFERED_TRANSPORT (object);
+
+ if (transport->r_buf != NULL)
+ {
+ g_byte_array_free (transport->r_buf, TRUE);
+ }
+ transport->r_buf = NULL;
+
+ if (transport->w_buf != NULL)
+ {
+ g_byte_array_free (transport->w_buf, TRUE);
+ }
+ transport->w_buf = NULL;
+}
+
+/* property accessor */
+void
+thrift_buffered_transport_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftBufferedTransport *transport = THRIFT_BUFFERED_TRANSPORT (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT:
+ g_value_set_object (value, transport->transport);
+ break;
+ case PROP_THRIFT_BUFFERED_TRANSPORT_READ_BUFFER_SIZE:
+ g_value_set_uint (value, transport->r_buf_size);
+ break;
+ case PROP_THRIFT_BUFFERED_TRANSPORT_WRITE_BUFFER_SIZE:
+ g_value_set_uint (value, transport->w_buf_size);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_buffered_transport_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftBufferedTransport *transport = THRIFT_BUFFERED_TRANSPORT (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT:
+ transport->transport = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_BUFFERED_TRANSPORT_READ_BUFFER_SIZE:
+ transport->r_buf_size = g_value_get_uint (value);
+ break;
+ case PROP_THRIFT_BUFFERED_TRANSPORT_WRITE_BUFFER_SIZE:
+ transport->w_buf_size = g_value_get_uint (value);
+ break;
+ }
+}
+
+/* initializes the class */
+static void
+thrift_buffered_transport_class_init (ThriftBufferedTransportClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_buffered_transport_get_property;
+ gobject_class->set_property = thrift_buffered_transport_set_property;
+
+ param_spec = g_param_spec_object ("transport", "transport (construct)",
+ "Thrift transport",
+ THRIFT_TYPE_TRANSPORT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("r_buf_size",
+ "read buffer size (construct)",
+ "Set the read buffer size",
+ 0, /* min */
+ 1048576, /* max, 1024*1024 */
+ 512, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_BUFFERED_TRANSPORT_READ_BUFFER_SIZE,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("w_buf_size",
+ "write buffer size (construct)",
+ "Set the write buffer size",
+ 0, /* min */
+ 1048576, /* max, 1024*1024 */
+ 512, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_BUFFERED_TRANSPORT_WRITE_BUFFER_SIZE,
+ param_spec);
+
+
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+
+ gobject_class->finalize = thrift_buffered_transport_finalize;
+ ttc->is_open = thrift_buffered_transport_is_open;
+ ttc->open = thrift_buffered_transport_open;
+ ttc->close = thrift_buffered_transport_close;
+ ttc->read = thrift_buffered_transport_read;
+ ttc->read_end = thrift_buffered_transport_read_end;
+ ttc->write = thrift_buffered_transport_write;
+ ttc->write_end = thrift_buffered_transport_write_end;
+ ttc->flush = thrift_buffered_transport_flush;
+}
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_buffered_transport_is_open (ThriftTransport *transport)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport);
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_buffered_transport_open (ThriftTransport *transport, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->open (t->transport, error);
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_buffered_transport_close (ThriftTransport *transport, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->close (t->transport, error);
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_buffered_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+
+ /* if we have enough buffer data to fulfill the read, just use
+ * a memcpy */
+ if (len <= t->r_buf->len)
+ {
+ memcpy (buf, t->r_buf->data, len);
+ g_byte_array_remove_range (t->r_buf, 0, len);
+ return len;
+ }
+
+ return thrift_buffered_transport_read_slow (transport, buf, len, error);
+}
+
+/* implements thrift_transport_read_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_buffered_transport_read_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* the actual read is "slow" because it calls the underlying transport */
+gint32
+thrift_buffered_transport_read_slow (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+ guint32 want = len;
+ guint32 got = 0;
+ guchar tmpdata[t->r_buf_size];
+ guint32 have = t->r_buf->len;
+
+ // we shouldn't hit this unless the buffer doesn't have enough to read
+ assert (t->r_buf->len < want);
+
+ // first copy what we have in our buffer.
+ if (have > 0)
+ {
+ memcpy (buf, t->r_buf, t->r_buf->len);
+ want -= t->r_buf->len;
+ t->r_buf = g_byte_array_remove_range (t->r_buf, 0, t->r_buf->len);
+ }
+
+ // if the buffer is still smaller than what we want to read, then just
+ // read it directly. otherwise, fill the buffer and then give out
+ // enough to satisfy the read.
+ if (t->r_buf_size < want)
+ {
+ got += THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+ tmpdata,
+ want,
+ error);
+
+ // copy the data starting from where we left off
+ memcpy (buf + have, tmpdata, got);
+ return got + have;
+ } else {
+ got += THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+ tmpdata,
+ t->r_buf_size,
+ error);
+ t->r_buf = g_byte_array_append (t->r_buf, tmpdata, got);
+
+ // hand over what we have up to what the caller wants
+ guint32 give = want < t->r_buf->len ? want : t->r_buf->len;
+
+
+ memcpy (buf + len - want, t->r_buf->data, give);
+ t->r_buf = g_byte_array_remove_range (t->r_buf, 0, give);
+ want -= give;
+
+ return (len - want);
+ }
+}
+
+
+/* implements thrift_transport_write */
+gboolean
+thrift_buffered_transport_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+
+ /* the length of the current buffer plus the length of the data being read */
+ if (t->w_buf->len + len <= t->w_buf_size)
+ {
+ t->w_buf = g_byte_array_append (t->w_buf, buf, len);
+ return len;
+ }
+
+ return thrift_buffered_transport_write_slow (transport, buf, len, error);
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_buffered_transport_write_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+gboolean
+thrift_buffered_transport_write_slow (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+ guint32 have_bytes = t->w_buf->len;
+ guint32 space = t->w_buf_size - t->w_buf->len;
+
+ // we need two syscalls because the buffered data plus the buffer itself
+ // is too big.
+ if ((have_bytes + len >= 2*t->w_buf->len) || (have_bytes == 0))
+ {
+ if (have_bytes > 0)
+ {
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+ t->w_buf->data,
+ have_bytes,
+ error);
+ }
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+ buf, len, error);
+ if (t->w_buf->len > 0)
+ {
+ t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
+ }
+
+ return TRUE;
+ }
+
+ t->w_buf = g_byte_array_append (t->w_buf, buf, space);
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+ t->w_buf->data,
+ t->w_buf->len,
+ error);
+
+ t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
+ t->w_buf = g_byte_array_append (t->w_buf, buf+space, len-space);
+
+ return TRUE;
+}
+
+/* implements thrift_transport_flush */
+gboolean
+thrift_buffered_transport_flush (ThriftTransport *transport, GError **error)
+{
+ ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+
+ if (t->w_buf != NULL && t->w_buf->len > 0)
+ {
+ // write the buffer and then empty it
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+ t->w_buf->data,
+ t->w_buf->len,
+ error);
+ t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
+ }
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->flush (t->transport,
+ error);
+
+ return TRUE;
+}
+
+
diff --git a/lib/c_glib/src/transport/thrift_buffered_transport.h b/lib/c_glib/src/transport/thrift_buffered_transport.h
new file mode 100644
index 0000000..6b0b17e
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_buffered_transport.h
@@ -0,0 +1,61 @@
+#ifndef _THRIFT_BUFFERED_TRANSPORT_H
+#define _THRIFT_BUFFERED_TRANSPORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+
+/*! \file thrift_buffered_transport.h
+ * \brief Implementation of a Thrift buffered transport. Subclasses
+ * the ThriftTransport class.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_BUFFERED_TRANSPORT (thrift_buffered_transport_get_type ())
+#define THRIFT_BUFFERED_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_BUFFERED_TRANSPORT, \
+ ThriftBufferedTransport))
+#define THRIFT_IS_BUFFERED_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_BUFFERED_TRANSPORT))
+#define THRIFT_BUFFERED_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_BUFFERED_TRANSPORT, \
+ ThriftBufferedTransportClass))
+#define THRIFT_IS_BUFFERED_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_BUFFERED_TRANSPORT)
+#define THRIFT_BUFFERED_TRANSPORT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_BUFFERED_TRANSPORT, \
+ ThriftBufferedTransportClass))
+
+/*!
+ * ThriftBufferedTransport instance.
+ */
+struct _ThriftBufferedTransport
+{
+ ThriftTransport parent;
+
+ /* protected */
+ ThriftTransport *transport;
+
+ /* private */
+ GByteArray *r_buf;
+ GByteArray *w_buf;
+ guint32 r_buf_size;
+ guint32 w_buf_size;
+};
+typedef struct _ThriftBufferedTransport ThriftBufferedTransport;
+
+/*!
+ * ThriftBufferedTransport class.
+ */
+struct _ThriftBufferedTransportClass
+{
+ ThriftTransportClass parent;
+};
+typedef struct _ThriftBufferedTransportClass ThriftBufferedTransportClass;
+
+/* used by THRIFT_TYPE_BUFFERED_TRANSPORT */
+GType thrift_buffered_transport_get_type (void);
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_framed_transport.c b/lib/c_glib/src/transport/thrift_framed_transport.c
new file mode 100644
index 0000000..de9cb00
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_framed_transport.c
@@ -0,0 +1,397 @@
+#include <assert.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_framed_transport.h"
+
+/* object properties */
+enum _ThriftFramedTransportProperties
+{
+ PROP_0,
+ PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT,
+ PROP_THRIFT_FRAMED_TRANSPORT_READ_BUFFER_SIZE,
+ PROP_THRIFT_FRAMED_TRANSPORT_WRITE_BUFFER_SIZE
+};
+
+/* forward declarations */
+static void thrift_framed_transport_instance_init (ThriftFramedTransport *self);
+static void thrift_framed_transport_class_init (ThriftFramedTransportClass *cls);
+
+
+gboolean thrift_framed_transport_is_open (ThriftTransport *transport);
+gboolean thrift_framed_transport_open (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_framed_transport_close (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_framed_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+gboolean thrift_framed_transport_read_end (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_framed_transport_read_slow (ThriftTransport *transport,
+ gpointer buf, guint32 len,
+ GError **error);
+gboolean thrift_framed_transport_read_frame (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_framed_transport_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error);
+gboolean thrift_framed_transport_write_end (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_framed_transport_write_slow (ThriftTransport *transport,
+ gpointer buf, guint32 len,
+ GError **error);
+gboolean thrift_framed_transport_flush (ThriftTransport *transport,
+ GError **error);
+
+GType
+thrift_framed_transport_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftFramedTransportClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_framed_transport_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftFramedTransport),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_framed_transport_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_TRANSPORT,
+ "ThriftFramedTransport", &info, 0);
+ }
+
+ return type;
+}
+
+/* initializes the instance */
+static void
+thrift_framed_transport_instance_init (ThriftFramedTransport *transport)
+{
+ transport->transport = NULL;
+ transport->r_buf = g_byte_array_new ();
+ transport->w_buf = g_byte_array_new ();
+}
+
+/* destructor */
+static void
+thrift_framed_transport_finalize (GObject *object)
+{
+ ThriftFramedTransport *transport = THRIFT_FRAMED_TRANSPORT (object);
+
+ if (transport->r_buf != NULL)
+ {
+ g_byte_array_free (transport->r_buf, TRUE);
+ }
+ transport->r_buf = NULL;
+
+ if (transport->w_buf != NULL)
+ {
+ g_byte_array_free (transport->w_buf, TRUE);
+ }
+ transport->w_buf = NULL;
+}
+
+/* property accessor */
+void
+thrift_framed_transport_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftFramedTransport *transport = THRIFT_FRAMED_TRANSPORT (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT:
+ g_value_set_object (value, transport->transport);
+ break;
+ case PROP_THRIFT_FRAMED_TRANSPORT_READ_BUFFER_SIZE:
+ g_value_set_uint (value, transport->r_buf_size);
+ break;
+ case PROP_THRIFT_FRAMED_TRANSPORT_WRITE_BUFFER_SIZE:
+ g_value_set_uint (value, transport->w_buf_size);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_framed_transport_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftFramedTransport *transport = THRIFT_FRAMED_TRANSPORT (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT:
+ transport->transport = g_value_get_object (value);
+ break;
+ case PROP_THRIFT_FRAMED_TRANSPORT_READ_BUFFER_SIZE:
+ transport->r_buf_size = g_value_get_uint (value);
+ break;
+ case PROP_THRIFT_FRAMED_TRANSPORT_WRITE_BUFFER_SIZE:
+ transport->w_buf_size = g_value_get_uint (value);
+ break;
+ }
+}
+
+/* initializes the class */
+static void
+thrift_framed_transport_class_init (ThriftFramedTransportClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_framed_transport_get_property;
+ gobject_class->set_property = thrift_framed_transport_set_property;
+
+ param_spec = g_param_spec_object ("transport", "transport (construct)",
+ "Thrift transport",
+ THRIFT_TYPE_TRANSPORT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("r_buf_size",
+ "read buffer size (construct)",
+ "Set the read buffer size",
+ 0, /* min */
+ 1048576, /* max, 1024*1024 */
+ 512, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_FRAMED_TRANSPORT_READ_BUFFER_SIZE,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("w_buf_size",
+ "write buffer size (construct)",
+ "Set the write buffer size",
+ 0, /* min */
+ 1048576, /* max, 1024*1024 */
+ 512, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_FRAMED_TRANSPORT_WRITE_BUFFER_SIZE,
+ param_spec);
+
+
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+
+ gobject_class->finalize = thrift_framed_transport_finalize;
+ ttc->is_open = thrift_framed_transport_is_open;
+ ttc->open = thrift_framed_transport_open;
+ ttc->close = thrift_framed_transport_close;
+ ttc->read = thrift_framed_transport_read;
+ ttc->read_end = thrift_framed_transport_read_end;
+ ttc->write = thrift_framed_transport_write;
+ ttc->write_end = thrift_framed_transport_write_end;
+ ttc->flush = thrift_framed_transport_flush;
+}
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_framed_transport_is_open (ThriftTransport *transport)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport);
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_framed_transport_open (ThriftTransport *transport, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->open (t->transport, error);
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_framed_transport_close (ThriftTransport *transport, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ return THRIFT_TRANSPORT_GET_CLASS (t->transport)->close (t->transport, error);
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_framed_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+
+ /* if we have enough buffer data to fulfill the read, just use
+ * a memcpy from the buffer */
+ if (len <= t->r_buf->len)
+ {
+ memcpy (buf, t->r_buf->data, len);
+ g_byte_array_remove_range (t->r_buf, 0, len);
+ return len;
+ }
+
+ return thrift_framed_transport_read_slow (transport, buf, len, error);
+}
+
+/* implements thrift_transport_read_end
+ * called when read is complete. nothing to do on our end. */
+gboolean
+thrift_framed_transport_read_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* the actual read is "slow" because it calls the underlying transport */
+gint32
+thrift_framed_transport_read_slow (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ guint32 want = len;
+ guint32 have = t->r_buf->len;
+
+ // we shouldn't hit this unless the buffer doesn't have enough to read
+ assert (t->r_buf->len < want);
+
+ // first copy what we have in our buffer, if there is anything left
+ if (have > 0)
+ {
+ memcpy (buf, t->r_buf, t->r_buf->len);
+ want -= t->r_buf->len;
+ t->r_buf = g_byte_array_remove_range (t->r_buf, 0, t->r_buf->len);
+ }
+
+ // read a frame of input and buffer it
+ thrift_framed_transport_read_frame (transport, error);
+
+ // hand over what we have up to what the caller wants
+ guint32 give = want < t->r_buf->len ? want : t->r_buf->len;
+
+ // copy the data into the buffer
+ memcpy (buf + len - want, t->r_buf->data, give);
+ t->r_buf = g_byte_array_remove_range (t->r_buf, 0, give);
+ want -= give;
+
+ return (len - want);
+}
+
+/* reads a frame and puts it into the buffer */
+gboolean
+thrift_framed_transport_read_frame (ThriftTransport *transport,
+ GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ gint32 sz, bytes;
+
+ /* read the size */
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+ (guint32 *) &sz,
+ sizeof (sz), error);
+ sz = ntohl (sz);
+
+ /* create a buffer to hold the data and read that much data */
+ guchar tmpdata[sz];
+ bytes = THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+ tmpdata,
+ sz - sizeof (sz),
+ error);
+
+ /* add the data to the buffer */
+ g_byte_array_append (t->r_buf, tmpdata, bytes);
+
+ return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_framed_transport_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+
+ /* the length of the current buffer plus the length of the data being read */
+ if (t->w_buf->len + len <= t->w_buf_size)
+ {
+ t->w_buf = g_byte_array_append (t->w_buf, buf, len);
+ return TRUE;
+ }
+
+ return thrift_framed_transport_write_slow (transport, buf, len, error);
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_framed_transport_write_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+gboolean
+thrift_framed_transport_write_slow (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ THRIFT_UNUSED_VAR (error);
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+
+ // append the data to the buffer and we're done
+ g_byte_array_append (t->w_buf, buf, len);
+
+ return TRUE;
+}
+
+/* implements thrift_transport_flush */
+gboolean
+thrift_framed_transport_flush (ThriftTransport *transport, GError **error)
+{
+ ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+ gint32 sz_hbo, sz_nbo;
+
+ // get the size of the frame in host and network byte order
+ sz_hbo = t->w_buf->len + sizeof(sz_nbo);
+ sz_nbo = (gint32) htonl ((guint32) sz_hbo);
+
+ // copy the size of the frame and then the frame itself
+ guchar tmpdata[sz_hbo];
+ memcpy (tmpdata, (guint8 *) &sz_nbo, sizeof (sz_nbo));
+
+ if (t->w_buf->len > 0)
+ {
+ memcpy (tmpdata + sizeof (sz_nbo), t->w_buf->data, t->w_buf->len);
+ t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
+ }
+
+ // write the buffer and then empty it
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+ tmpdata, sz_hbo,
+ error);
+
+ THRIFT_TRANSPORT_GET_CLASS (t->transport)->flush (t->transport,
+ error);
+
+ return TRUE;
+}
+
+
diff --git a/lib/c_glib/src/transport/thrift_framed_transport.h b/lib/c_glib/src/transport/thrift_framed_transport.h
new file mode 100644
index 0000000..d859b97
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_framed_transport.h
@@ -0,0 +1,61 @@
+#ifndef _THRIFT_FRAMED_TRANSPORT_H
+#define _THRIFT_FRAMED_TRANSPORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+
+/*! \file thrift_framed_transport.h
+ * \brief Implementation of a Thrift framed transport. Subclasses
+ * the ThriftTransport class.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_FRAMED_TRANSPORT (thrift_framed_transport_get_type ())
+#define THRIFT_FRAMED_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_FRAMED_TRANSPORT, \
+ ThriftFramedTransport))
+#define THRIFT_IS_FRAMED_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_FRAMED_TRANSPORT))
+#define THRIFT_FRAMED_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_FRAMED_TRANSPORT, \
+ ThriftFramedTransportClass))
+#define THRIFT_IS_FRAMED_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_FRAMED_TRANSPORT)
+#define THRIFT_FRAMED_TRANSPORT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_FRAMED_TRANSPORT, \
+ ThriftFramedTransportClass))
+
+/*!
+ * ThriftFramedTransport instance.
+ */
+struct _ThriftFramedTransport
+{
+ ThriftTransport parent;
+
+ /* protected */
+ ThriftTransport *transport;
+
+ /* private */
+ GByteArray *r_buf;
+ GByteArray *w_buf;
+ guint32 r_buf_size;
+ guint32 w_buf_size;
+};
+typedef struct _ThriftFramedTransport ThriftFramedTransport;
+
+/*!
+ * ThriftFramedTransport class.
+ */
+struct _ThriftFramedTransportClass
+{
+ ThriftTransportClass parent;
+};
+typedef struct _ThriftFramedTransportClass ThriftFramedTransportClass;
+
+/* used by THRIFT_TYPE_FRAMED_TRANSPORT */
+GType thrift_framed_transport_get_type (void);
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_memory_buffer.c b/lib/c_glib/src/transport/thrift_memory_buffer.c
new file mode 100644
index 0000000..34a4dfa
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_memory_buffer.c
@@ -0,0 +1,260 @@
+#include <assert.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_memory_buffer.h"
+
+/* object properties */
+enum _ThriftMemoryBufferProperties
+{
+ PROP_0,
+ PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE,
+};
+
+/* forward declarations */
+static void thrift_memory_buffer_instance_init (ThriftMemoryBuffer *self);
+static void thrift_memory_buffer_class_init (ThriftMemoryBufferClass *cls);
+
+
+gboolean thrift_memory_buffer_is_open (ThriftTransport *transport);
+gboolean thrift_memory_buffer_open (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_memory_buffer_close (ThriftTransport *transport,
+ GError **error);
+gint32 thrift_memory_buffer_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+gboolean thrift_memory_buffer_read_end (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_memory_buffer_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error);
+gboolean thrift_memory_buffer_write_end (ThriftTransport *transport,
+ GError **error);
+gboolean thrift_memory_buffer_flush (ThriftTransport *transport,
+ GError **error);
+
+GType
+thrift_memory_buffer_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftMemoryBufferClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_memory_buffer_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftMemoryBuffer),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_memory_buffer_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_TRANSPORT,
+ "ThriftMemoryBuffer", &info, 0);
+ }
+
+ return type;
+}
+
+/* initializes the instance */
+static void
+thrift_memory_buffer_instance_init (ThriftMemoryBuffer *transport)
+{
+ transport->buf = g_byte_array_new ();
+}
+
+/* destructor */
+static void
+thrift_memory_buffer_finalize (GObject *object)
+{
+ ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
+
+ if (transport->buf != NULL)
+ {
+ g_byte_array_free (transport->buf, TRUE);
+ }
+ transport->buf = NULL;
+}
+
+/* property accessor */
+void
+thrift_memory_buffer_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE:
+ g_value_set_uint (value, transport->buf_size);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_memory_buffer_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE:
+ transport->buf_size = g_value_get_uint (value);
+ break;
+ }
+}
+
+/* initializes the class */
+static void
+thrift_memory_buffer_class_init (ThriftMemoryBufferClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_memory_buffer_get_property;
+ gobject_class->set_property = thrift_memory_buffer_set_property;
+
+ param_spec = g_param_spec_uint ("buf_size",
+ "buffer size (construct)",
+ "Set the read buffer size",
+ 0, /* min */
+ 1048576, /* max, 1024*1024 */
+ 512, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE,
+ param_spec);
+
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+
+ gobject_class->finalize = thrift_memory_buffer_finalize;
+ ttc->is_open = thrift_memory_buffer_is_open;
+ ttc->open = thrift_memory_buffer_open;
+ ttc->close = thrift_memory_buffer_close;
+ ttc->read = thrift_memory_buffer_read;
+ ttc->read_end = thrift_memory_buffer_read_end;
+ ttc->write = thrift_memory_buffer_write;
+ ttc->write_end = thrift_memory_buffer_write_end;
+ ttc->flush = thrift_memory_buffer_flush;
+}
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_memory_buffer_is_open (ThriftTransport *transport)
+{
+ THRIFT_UNUSED_VAR (transport);
+ return TRUE;
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_memory_buffer_open (ThriftTransport *transport, GError **error)
+{
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_memory_buffer_close (ThriftTransport *transport, GError **error)
+{
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_memory_buffer_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ THRIFT_UNUSED_VAR (error);
+ ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (transport);
+ guint32 give = len;
+
+ /* if the requested bytes are more than what we have available,
+ * just give all that we have the buffer */
+ if (t->buf->len < len)
+ {
+ give = t->buf->len;
+ }
+
+ memcpy (buf, t->buf->data, give);
+ g_byte_array_remove_range (t->buf, 0, give);
+
+ return give;
+}
+
+/* implements thrift_transport_read_end
+ * called when read is complete. nothing to do on our end. */
+gboolean
+thrift_memory_buffer_read_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_memory_buffer_write (ThriftTransport *transport,
+ const gpointer buf,
+ const guint32 len, GError **error)
+{
+ THRIFT_UNUSED_VAR (error);
+
+ ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (transport);
+
+ /* return an exception if the buffer doesn't have enough space. */
+ if (len > t->buf_size - t->buf->len)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SEND,
+ "unable to write %d bytes to buffer of length %d",
+ len, t->buf_size);
+ return FALSE;
+ } else {
+ t->buf = g_byte_array_append (t->buf, buf, len);
+ return TRUE;
+ }
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_memory_buffer_write_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_flush */
+gboolean
+thrift_memory_buffer_flush (ThriftTransport *transport, GError **error)
+{
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+
+ return TRUE;
+}
+
+
diff --git a/lib/c_glib/src/transport/thrift_memory_buffer.h b/lib/c_glib/src/transport/thrift_memory_buffer.h
new file mode 100644
index 0000000..7529d1f
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_memory_buffer.h
@@ -0,0 +1,55 @@
+#ifndef _THRIFT_MEMORY_BUFFER_H
+#define _THRIFT_MEMORY_BUFFER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+
+/*! \file thrift_memory_buffer.h
+ * \brief Implementation of a Thrift memory buffer transport.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_MEMORY_BUFFER (thrift_memory_buffer_get_type ())
+#define THRIFT_MEMORY_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_MEMORY_BUFFER, \
+ ThriftMemoryBuffer))
+#define THRIFT_IS_MEMORY_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_MEMORY_BUFFER))
+#define THRIFT_MEMORY_BUFFER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_MEMORY_BUFFER, \
+ ThriftMemoryBufferClass))
+#define THRIFT_IS_MEMORY_BUFFER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_MEMORY_BUFFER)
+#define THRIFT_MEMORY_BUFFER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_MEMORY_BUFFER, \
+ ThriftMemoryBufferClass))
+
+/*!
+ * ThriftMemoryBuffer instance.
+ */
+struct _ThriftMemoryBuffer
+{
+ ThriftTransport parent;
+
+ /* private */
+ GByteArray *buf;
+ guint32 buf_size;
+};
+typedef struct _ThriftMemoryBuffer ThriftMemoryBuffer;
+
+/*!
+ * ThriftMemoryBuffer class.
+ */
+struct _ThriftMemoryBufferClass
+{
+ ThriftTransportClass parent;
+};
+typedef struct _ThriftMemoryBufferClass ThriftMemoryBufferClass;
+
+/* used by THRIFT_TYPE_MEMORY_BUFFER */
+GType thrift_memory_buffer_get_type (void);
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_server_socket.c b/lib/c_glib/src/transport/thrift_server_socket.c
new file mode 100644
index 0000000..fe11648
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_server_socket.c
@@ -0,0 +1,272 @@
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "thrift.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+/* object properties */
+enum _ThriftServerSocketProperties
+{
+ PROP_0,
+ PROP_THRIFT_SERVER_SOCKET_PORT,
+ PROP_THRIFT_SERVER_SOCKET_BACKLOG
+};
+
+/* define the GError domain string */
+#define THRIFT_SERVER_SOCKET_ERROR_DOMAIN "thrift-server-socket-error-quark"
+
+/* for errors coming from socket() and connect() */
+extern int errno;
+
+/* forward declarations */
+static void thrift_server_socket_instance_init (ThriftServerSocket *self);
+static void thrift_server_socket_class_init (ThriftServerSocketClass *cls);
+
+gboolean thrift_server_socket_listen (ThriftServerTransport *transport,
+ GError **error);
+ThriftTransport *thrift_server_socket_accept (ThriftServerTransport *transport,
+ GError **error);
+gboolean thrift_server_socket_close (ThriftServerTransport *transport,
+ GError **error);
+
+GType
+thrift_server_socket_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftServerSocketClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_server_socket_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftServerSocket),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_server_socket_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_SERVER_TRANSPORT,
+ "ThriftServerSocket", &info, 0);
+ }
+
+ return type;
+}
+
+/* define the GError domain for this implementation */
+GQuark
+thrift_server_socket_error_quark (void)
+{
+ return g_quark_from_static_string(THRIFT_SERVER_SOCKET_ERROR_DOMAIN);
+}
+
+/* initializes the instance */
+static void
+thrift_server_socket_instance_init (ThriftServerSocket *socket)
+{
+ socket->sd = 0;
+}
+
+/* destructor */
+static void
+thrift_server_socket_finalize (GObject *object)
+{
+ ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
+
+ if (socket->sd != 0)
+ {
+ close (socket->sd);
+ }
+ socket->sd = 0;
+}
+
+/* property accessor */
+void
+thrift_server_socket_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SERVER_SOCKET_PORT:
+ g_value_set_uint (value, socket->port);
+ break;
+ case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
+ g_value_set_uint (value, socket->backlog);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_server_socket_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SERVER_SOCKET_PORT:
+ socket->port = g_value_get_uint (value);
+ break;
+ case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
+ socket->backlog = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/* initializes the class */
+static void
+thrift_server_socket_class_init (ThriftServerSocketClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_server_socket_get_property;
+ gobject_class->set_property = thrift_server_socket_set_property;
+
+ param_spec = g_param_spec_uint ("port",
+ "port (construct)",
+ "Set the port to listen to",
+ 0, /* min */
+ 65534, /* max */
+ 9090, /* default by convention */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_SOCKET_PORT,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("backlog",
+ "backlog (construct)",
+ "Set the accept backlog",
+ 0, /* max */
+ 65534, /* max */
+ 1024, /* default */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_SOCKET_BACKLOG,
+ param_spec);
+
+ gobject_class->finalize = thrift_server_socket_finalize;
+
+ ThriftServerTransportClass *tstc = THRIFT_SERVER_TRANSPORT_CLASS (cls);
+ tstc->listen = thrift_server_socket_listen;
+ tstc->accept = thrift_server_socket_accept;
+ tstc->close = thrift_server_socket_close;
+}
+
+gboolean
+thrift_server_socket_listen (ThriftServerTransport *transport, GError **error)
+{
+ int enabled = 1; /* for setsockopt() */
+ struct sockaddr_in pin;
+ ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
+
+ /* create a address structure */
+ memset (&pin, 0, sizeof(pin));
+ pin.sin_family = AF_INET;
+ pin.sin_addr.s_addr = INADDR_ANY;
+ pin.sin_port = htons(tsocket->port);
+
+ /* create a socket */
+ if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_SOCKET,
+ "failed to create socket - %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (setsockopt(tsocket->sd, SOL_SOCKET, SO_REUSEADDR, &enabled,
+ sizeof(enabled)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_SETSOCKOPT,
+ "unable to set SO_REUSEADDR - %s", strerror(errno));
+ return FALSE;
+ }
+
+ /* bind to the socket */
+ if (bind(tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_BIND,
+ "failed to bind to port %d - %s",
+ tsocket->port, strerror(errno));
+ return FALSE;
+ }
+
+ if (listen(tsocket->sd, tsocket->backlog) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_LISTEN,
+ "failed to listen to port %d - %s",
+ tsocket->port, strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ThriftTransport *
+thrift_server_socket_accept (ThriftServerTransport *transport, GError **error)
+{
+ int sd = 0;
+ guint addrlen = 0;
+ struct sockaddr_in address;
+ ThriftSocket *socket = NULL;
+
+ ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
+
+ if ((sd = accept(tsocket->sd, (struct sockaddr *) &address, &addrlen)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_ACCEPT,
+ "failed to accept connection - %s",
+ strerror(errno));
+ return FALSE;
+ }
+
+ socket = g_object_new (THRIFT_TYPE_SOCKET, NULL);
+ socket->sd = sd;
+
+ return THRIFT_TRANSPORT(socket);
+}
+
+gboolean
+thrift_server_socket_close (ThriftServerTransport *transport, GError **error)
+{
+ ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
+
+ if (close (tsocket->sd) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_CLOSE,
+ "unable to close socket - %s", strerror(errno));
+ return FALSE;
+ }
+ tsocket->sd = 0;
+
+ return TRUE;
+}
+
diff --git a/lib/c_glib/src/transport/thrift_server_socket.h b/lib/c_glib/src/transport/thrift_server_socket.h
new file mode 100644
index 0000000..c56bd84
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_server_socket.h
@@ -0,0 +1,73 @@
+#ifndef _THRIFT_SERVER_SOCKET_H
+#define _THRIFT_SERVER_SOCKET_H
+
+#include <glib-object.h>
+
+#include "thrift_server_transport.h"
+
+/*! \file thrift_server_socket.h
+ * \brief Socket implementation of a Thrift server transport. Implements the
+ * ThriftServerTransport class.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SERVER_SOCKET (thrift_server_socket_get_type ())
+#define THRIFT_SERVER_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_SERVER_SOCKET, \
+ ThriftServerSocket))
+#define THRIFT_IS_SERVER_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_SERVER_SOCKET))
+#define THRIFT_SERVER_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_SERVER_SOCKET, \
+ ThriftServerSocketClass))
+#define THRIFT_IS_SERVER_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_SERVER_SOCKET))
+#define THRIFT_SERVER_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_SERVER_SOCKET, \
+ ThriftServerSocketClass))
+
+/*!
+ * Thrift ServerSocket instance.
+ */
+struct _ThriftServerSocket
+{
+ ThriftServerTransport parent;
+
+ /* private */
+ gshort port;
+ gshort backlog;
+ int sd;
+ guint8 *buf;
+ guint32 buf_size;
+ guint32 buf_len;
+};
+typedef struct _ThriftServerSocket ThriftServerSocket;
+
+/*!
+ * Thrift ServerSocket class.
+ */
+struct _ThriftServerSocketClass
+{
+ ThriftServerTransportClass parent;
+};
+typedef struct _ThriftServerSocketClass ThriftServerSocketClass;
+
+/* used by THRIFT_TYPE_SERVER_SOCKET */
+GType thrift_server_socket_get_type (void);
+
+/* define error/exception types */
+typedef enum
+{
+ THRIFT_SERVER_SOCKET_ERROR_SOCKET,
+ THRIFT_SERVER_SOCKET_ERROR_SETSOCKOPT,
+ THRIFT_SERVER_SOCKET_ERROR_BIND,
+ THRIFT_SERVER_SOCKET_ERROR_LISTEN,
+ THRIFT_SERVER_SOCKET_ERROR_ACCEPT,
+ THRIFT_SERVER_SOCKET_ERROR_CLOSE
+} ThriftServerSocketError;
+
+/* define a error domain for GError to use */
+GQuark thrift_server_socket_error_quark (void);
+#define THRIFT_SERVER_SOCKET_ERROR (thrift_server_socket_error_quark ())
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_server_transport.c b/lib/c_glib/src/transport/thrift_server_transport.c
new file mode 100644
index 0000000..89cbaf3
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_server_transport.c
@@ -0,0 +1,70 @@
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_server_transport.h"
+
+/* forward declarations */
+static void thrift_server_transport_class_init (ThriftServerTransportClass *c);
+
+/* define ThriftTransportClass type */
+GType
+thrift_server_transport_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftServerTransportClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_server_transport_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftServerTransport),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "ThriftServerTransport",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+/* base initializer for the server transport interface */
+static void
+thrift_server_transport_class_init (ThriftServerTransportClass *c)
+{
+ c->listen = thrift_server_transport_listen;
+ c->accept = thrift_server_transport_accept;
+ c->close = thrift_server_transport_close;
+}
+
+gboolean
+thrift_server_transport_listen (ThriftServerTransport *transport,
+ GError **error)
+{
+ return THRIFT_SERVER_TRANSPORT_GET_CLASS (transport)->listen (transport,
+ error);
+}
+
+ThriftTransport *
+thrift_server_transport_accept (ThriftServerTransport *transport,
+ GError **error)
+{
+ return THRIFT_SERVER_TRANSPORT_GET_CLASS (transport)->accept (transport,
+ error);
+}
+
+gboolean
+thrift_server_transport_close (ThriftServerTransport *transport, GError **error)
+{
+ return THRIFT_SERVER_TRANSPORT_GET_CLASS (transport)->close (transport,
+ error);
+}
+
+
diff --git a/lib/c_glib/src/transport/thrift_server_transport.h b/lib/c_glib/src/transport/thrift_server_transport.h
new file mode 100644
index 0000000..a74fca0
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_server_transport.h
@@ -0,0 +1,72 @@
+#ifndef _THRIFT_SERVER_TRANSPORT_H
+#define _THRIFT_SERVER_TRANSPORT_H
+
+#include <glib-object.h>
+
+#include "thrift_transport.h"
+
+/*! \file thrift_server_transport.h
+ * \brief Abstract class for Thrift server transports.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SERVER_TRANSPORT (thrift_server_transport_get_type ())
+#define THRIFT_SERVER_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_SERVER_TRANSPORT, \
+ ThriftServerTransport))
+#define THRIFT_IS_SERVER_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_SERVER_TRANSPORT))
+#define THRIFT_SERVER_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_SERVER_TRANSPORT, \
+ ThriftServerTransportClass))
+#define THRIFT_IS_SERVER_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_SERVER_TRANSPORT))
+#define THRIFT_SERVER_TRANSPORT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_SERVER_TRANSPORT, \
+ ThriftServerTransportClass))
+
+struct _ThriftServerTransport
+{
+ GObject parent;
+};
+typedef struct _ThriftServerTransport ThriftServerTransport;
+
+/*!
+ * Thrift Transport class
+ */
+struct _ThriftServerTransportClass
+{
+ GObjectClass parent;
+
+ /* vtable */
+ gboolean (*listen) (ThriftServerTransport *transport, GError **error);
+ ThriftTransport *(*accept) (ThriftServerTransport *transport, GError **error);
+ gboolean (*close) (ThriftServerTransport *transport, GError **error);
+};
+typedef struct _ThriftServerTransportClass ThriftServerTransportClass;
+
+/* used by THRIFT_TYPE_SERVER_TRANSPORT */
+GType thrift_server_transport_get_type (void);
+
+/*!
+ * Listen for new connections.
+ * \public \memberof ThriftServerTransportClass
+ */
+gboolean thrift_server_transport_listen (ThriftServerTransport *transport,
+ GError **error);
+
+/*!
+ * Accept a connection.
+ * \public \memberof ThriftServerTransportClass
+ */
+ThriftTransport *thrift_server_transport_accept
+ (ThriftServerTransport *transport, GError **error);
+
+/*!
+ * Close the transport.
+ * \public \memberof ThriftServerTransportClass
+ */
+gboolean thrift_server_transport_close (ThriftServerTransport *transport,
+ GError **error);
+
+#endif /* _THRIFT_SERVER_TRANSPORT_H */
diff --git a/lib/c_glib/src/transport/thrift_socket.c b/lib/c_glib/src/transport/thrift_socket.c
new file mode 100644
index 0000000..951ae90
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_socket.c
@@ -0,0 +1,334 @@
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+
+/* object properties */
+enum _ThriftSocketProperties
+{
+ PROP_0,
+ PROP_THRIFT_SOCKET_HOSTNAME,
+ PROP_THRIFT_SOCKET_PORT
+};
+
+/* for errors coming from socket() and connect() */
+extern int errno;
+
+/* forward declarations */
+static void thrift_socket_instance_init (ThriftSocket *self);
+static void thrift_socket_class_init (ThriftSocketClass *cls);
+
+gboolean thrift_socket_is_open (ThriftTransport *transport);
+gboolean thrift_socket_open (ThriftTransport *transport, GError **error);
+gboolean thrift_socket_close (ThriftTransport *transport, GError **error);
+gint32 thrift_socket_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+gboolean thrift_socket_read_end (ThriftTransport *transport, GError **error);
+gboolean thrift_socket_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error);
+gboolean thrift_socket_write_end (ThriftTransport *transport, GError **error);
+gboolean thrift_socket_flush (ThriftTransport *transport, GError **error);
+
+GType
+thrift_socket_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftSocketClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_socket_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ThriftSocket),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) thrift_socket_instance_init,
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_TRANSPORT,
+ "ThriftSocket", &info, 0);
+ }
+
+ return type;
+}
+
+/* initializes the instance */
+static void
+thrift_socket_instance_init (ThriftSocket *socket)
+{
+ socket->sd = 0;
+}
+
+/* destructor */
+static void
+thrift_socket_finalize (GObject *object)
+{
+ ThriftSocket *socket = THRIFT_SOCKET (object);
+
+ if (socket->hostname != NULL)
+ {
+ g_free (socket->hostname);
+ }
+ socket->hostname = NULL;
+
+ if (socket->sd != 0)
+ {
+ close (socket->sd);
+ }
+ socket->sd = 0;
+}
+
+/* property accessor */
+void
+thrift_socket_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftSocket *socket = THRIFT_SOCKET (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SOCKET_HOSTNAME:
+ g_value_set_string (value, socket->hostname);
+ break;
+ case PROP_THRIFT_SOCKET_PORT:
+ g_value_set_uint (value, socket->port);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_socket_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ THRIFT_UNUSED_VAR (pspec);
+ ThriftSocket *socket = THRIFT_SOCKET (object);
+
+ switch (property_id)
+ {
+ case PROP_THRIFT_SOCKET_HOSTNAME:
+ socket->hostname = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_THRIFT_SOCKET_PORT:
+ socket->port = g_value_get_uint (value);
+ break;
+ }
+}
+
+/* initializes the class */
+static void
+thrift_socket_class_init (ThriftSocketClass *cls)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+ GParamSpec *param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_socket_get_property;
+ gobject_class->set_property = thrift_socket_set_property;
+
+ param_spec = g_param_spec_string ("hostname",
+ "hostname (construct)",
+ "Set the hostname of the remote host",
+ "localhost", /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_THRIFT_SOCKET_HOSTNAME,
+ param_spec);
+
+ param_spec = g_param_spec_uint ("port",
+ "port (construct)",
+ "Set the port of the remote host",
+ 0, /* min */
+ 65534, /* max */
+ 9090, /* default by convention */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_THRIFT_SOCKET_PORT,
+ param_spec);
+
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+
+ gobject_class->finalize = thrift_socket_finalize;
+ ttc->is_open = thrift_socket_is_open;
+ ttc->open = thrift_socket_open;
+ ttc->close = thrift_socket_close;
+ ttc->read = thrift_socket_read;
+ ttc->read_end = thrift_socket_read_end;
+ ttc->write = thrift_socket_write;
+ ttc->write_end = thrift_socket_write_end;
+ ttc->flush = thrift_socket_flush;
+}
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_socket_is_open (ThriftTransport *transport)
+{
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+ return socket->sd != 0;
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_socket_open (ThriftTransport *transport, GError **error)
+{
+ struct hostent *hp = NULL;
+ struct sockaddr_in pin;
+
+ ThriftSocket *tsocket = THRIFT_SOCKET (transport);
+ g_return_val_if_fail (tsocket->sd == 0, FALSE);
+
+ /* lookup the destination host */
+ if ((hp = gethostbyname (tsocket->hostname)) == NULL)
+ {
+ /* host lookup failed, bail out with an error */
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_HOST,
+ "host lookup failed for %s:%d - %s",
+ tsocket->hostname, tsocket->port,
+ hstrerror (h_errno));
+ return FALSE;
+ }
+
+ /* create a socket structure */
+ memset (&pin, 0, sizeof(pin));
+ pin.sin_family = AF_INET;
+ pin.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
+ pin.sin_port = htons (tsocket->port);
+
+ /* create the socket */
+ if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SOCKET,
+ "failed to create socket for host %s:%d - %s",
+ tsocket->hostname, tsocket->port,
+ strerror(errno));
+ return FALSE;
+ }
+
+ /* open a connection */
+ if (connect (tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CONNECT,
+ "failed to connect to host %s:%d - %s",
+ tsocket->hostname, tsocket->port, strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_socket_close (ThriftTransport *transport, GError **error)
+{
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+
+ if (close (socket->sd) == -1)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CLOSE,
+ "unable to close socket - %s",
+ strerror(errno));
+ return FALSE;
+ }
+
+ socket->sd = 0;
+ return TRUE;
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_socket_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ gint ret = 0;
+ guint got = 0;
+
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+
+ while (got < len)
+ {
+ ret = recv (socket->sd, buf, len, 0);
+ if (ret < 0)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_RECEIVE,
+ "failed to read %d bytes - %s", len, strerror(errno));
+ return -1;
+ }
+ got += ret;
+ }
+
+ return got;
+}
+
+/* implements thrift_transport_read_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_socket_read_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_socket_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ gint ret = 0;
+ guint sent = 0;
+
+ ThriftSocket *socket = THRIFT_SOCKET (transport);
+ g_return_val_if_fail (socket->sd != 0, FALSE);
+
+ while (sent < len)
+ {
+ ret = send (socket->sd, buf + sent, len - sent, 0);
+ if (ret < 0)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR,
+ THRIFT_TRANSPORT_ERROR_SEND,
+ "failed to send %d bytes - %s", len, strerror(errno));
+ return FALSE;
+ }
+ sent += ret;
+ }
+
+ return TRUE;
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete. nothing to do on our end. */
+gboolean
+thrift_socket_write_end (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+/* implements thrift_transport_flush
+ * flush pending data. since we are not buffered, this is a no-op */
+gboolean
+thrift_socket_flush (ThriftTransport *transport, GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (transport);
+ THRIFT_UNUSED_VAR (error);
+ return TRUE;
+}
+
+
diff --git a/lib/c_glib/src/transport/thrift_socket.h b/lib/c_glib/src/transport/thrift_socket.h
new file mode 100644
index 0000000..5fc2402
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_socket.h
@@ -0,0 +1,56 @@
+#ifndef _THRIFT_SOCKET_H
+#define _THRIFT_SOCKET_H
+
+#include <glib-object.h>
+
+#include "transport/thrift_transport.h"
+
+/*! \file thrift_socket.h
+ * \brief Socket implementation of a Thrift transport. Subclasses the
+ * ThriftTransport class.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SOCKET (thrift_socket_get_type ())
+#define THRIFT_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_SOCKET, ThriftSocket))
+#define THRIFT_IS_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_SOCKET))
+#define THRIFT_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_SOCKET, ThriftSocketClass))
+#define THRIFT_IS_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_SOCKET))
+#define THRIFT_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_SOCKET, \
+ ThriftSocketClass))
+
+/*!
+ * Thrift Socket instance.
+ */
+struct _ThriftSocket
+{
+ ThriftTransport parent;
+
+ /* private */
+ gchar *hostname;
+ gshort port;
+ int sd;
+ guint8 *buf;
+ guint32 buf_size;
+ guint32 buf_len;
+};
+typedef struct _ThriftSocket ThriftSocket;
+
+/*!
+ * Thrift Socket class.
+ */
+struct _ThriftSocketClass
+{
+ ThriftTransportClass parent;
+};
+typedef struct _ThriftSocketClass ThriftSocketClass;
+
+/* used by THRIFT_TYPE_SOCKET */
+GType thrift_socket_get_type (void);
+
+#endif
diff --git a/lib/c_glib/src/transport/thrift_transport.c b/lib/c_glib/src/transport/thrift_transport.c
new file mode 100644
index 0000000..9c57a75
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_transport.c
@@ -0,0 +1,114 @@
+#include "thrift.h"
+#include "transport/thrift_transport.h"
+
+/* define the GError domain string */
+#define THRIFT_TRANSPORT_ERROR_DOMAIN "thrift-transport-error-quark"
+
+/* forward declarations */
+static void thrift_transport_class_init (ThriftTransportClass *cls);
+
+/* define ThriftTransportInterface's type */
+GType
+thrift_transport_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (ThriftTransportClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_transport_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftTransport),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftTransport",
+ &info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+/* class initializer for ThriftTransport */
+static void
+thrift_transport_class_init (ThriftTransportClass *cls)
+{
+ /* set these as virtual methods to be implemented by a subclass */
+ cls->is_open = thrift_transport_is_open;
+ cls->open = thrift_transport_open;
+ cls->close = thrift_transport_close;
+ cls->read = thrift_transport_read;
+ cls->read_end = thrift_transport_read_end;
+ cls->write = thrift_transport_write;
+ cls->write_end = thrift_transport_write_end;
+ cls->flush = thrift_transport_flush;
+}
+
+gboolean
+thrift_transport_is_open (ThriftTransport *transport)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->is_open (transport);
+}
+
+gboolean
+thrift_transport_open (ThriftTransport *transport, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->open (transport, error);
+}
+
+gboolean
+thrift_transport_close (ThriftTransport *transport, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->close (transport, error);
+}
+
+gint32
+thrift_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->read (transport, buf,
+ len, error);
+}
+
+gboolean
+thrift_transport_read_end (ThriftTransport *transport, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->read_end (transport,
+ error);
+}
+
+gboolean
+thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->write (transport, buf,
+ len, error);
+}
+
+gboolean
+thrift_transport_write_end (ThriftTransport *transport, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->write_end (transport,
+ error);
+}
+
+gboolean
+thrift_transport_flush (ThriftTransport *transport, GError **error)
+{
+ return THRIFT_TRANSPORT_GET_CLASS (transport)->flush (transport, error);
+}
+
+/* define the GError domain for Thrift transports */
+GQuark
+thrift_transport_error_quark (void)
+{
+ return g_quark_from_static_string (THRIFT_TRANSPORT_ERROR_DOMAIN);
+}
+
diff --git a/lib/c_glib/src/transport/thrift_transport.h b/lib/c_glib/src/transport/thrift_transport.h
new file mode 100644
index 0000000..18edc4d
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_transport.h
@@ -0,0 +1,135 @@
+#ifndef _THRIFT_TRANSPORT_H
+#define _THRIFT_TRANSPORT_H
+
+#include <glib-object.h>
+
+/*! \file thrift_transport.h
+ * \brief Abstract class for Thrift transports.
+ *
+ * An abstract class is used instead of an interface because:
+ * - interfaces can't seem to be used as properties. ThriftProtocol has
+ * a ThriftTransport as an object property.
+ * - if a method needs to be added that all subclasses can use, a class
+ * is necessary.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_TRANSPORT (thrift_transport_get_type ())
+#define THRIFT_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_TRANSPORT, ThriftTransport))
+#define THRIFT_IS_TRANSPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_TRANSPORT))
+#define THRIFT_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_TRANSPORT, \
+ ThriftTransportClass))
+#define THRIFT_IS_TRANSPORT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_TRANSPORT))
+#define THRIFT_TRANSPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_TRANSPORT, \
+ ThriftTransportClass))
+
+/*!
+ * Thrift Protocol object
+ */
+struct _ThriftTransport
+{
+ GObject parent;
+};
+typedef struct _ThriftTransport ThriftTransport;
+
+/*!
+ * Thrift Transport class
+ */
+struct _ThriftTransportClass
+{
+ GObjectClass parent;
+
+ /* vtable */
+ gboolean (*is_open) (ThriftTransport *transport);
+ gboolean (*open) (ThriftTransport *transport, GError **error);
+ gboolean (*close) (ThriftTransport *transport, GError **error);
+ gint32 (*read) (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+ gboolean (*read_end) (ThriftTransport *transport, GError **error);
+ gboolean (*write) (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error);
+ gboolean (*write_end) (ThriftTransport *transport, GError **error);
+ gboolean (*flush) (ThriftTransport *transport, GError **error);
+};
+typedef struct _ThriftTransportClass ThriftTransportClass;
+
+/* used by THRIFT_TYPE_TRANSPORT */
+GType thrift_transport_get_type (void);
+
+/* virtual public methods */
+
+/*!
+ * Checks if this transport is opened.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_is_open (ThriftTransport *transport);
+
+/*!
+ * Open the transport for reading and writing.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_open (ThriftTransport *transport, GError **error);
+
+/*!
+ * Close the transport.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_close (ThriftTransport *transport, GError **error);
+
+/*!
+ * Read some data into the buffer buf.
+ * \public \memberof ThriftTransportInterface
+ */
+gint32 thrift_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error);
+
+/*!
+ * Called when read is completed.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_read_end (ThriftTransport *transport, GError **error);
+
+/*!
+ * Writes data from a buffer to the transport.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error);
+
+/*!
+ * Called when write is completed.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_write_end (ThriftTransport *transport,
+ GError **error);
+
+/*!
+ * Flushes any pending data to be written. Typically used with buffered
+ * transport mechanisms.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_flush (ThriftTransport *transport, GError **error);
+
+/* define error/exception types */
+typedef enum
+{
+ THRIFT_TRANSPORT_ERROR_UNKNOWN,
+ THRIFT_TRANSPORT_ERROR_HOST,
+ THRIFT_TRANSPORT_ERROR_SOCKET,
+ THRIFT_TRANSPORT_ERROR_CONNECT,
+ THRIFT_TRANSPORT_ERROR_SEND,
+ THRIFT_TRANSPORT_ERROR_RECEIVE,
+ THRIFT_TRANSPORT_ERROR_CLOSE
+} ThriftTransportError;
+
+/* define an error domain for GError to use */
+GQuark thrift_transport_error_quark (void);
+#define THRIFT_TRANSPORT_ERROR (thrift_transport_error_quark ())
+
+
+#endif /* _THRIFT_TRANSPORT_H */
diff --git a/lib/c_glib/src/transport/thrift_transport_factory.c b/lib/c_glib/src/transport/thrift_transport_factory.c
new file mode 100644
index 0000000..6f0199f
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_transport_factory.c
@@ -0,0 +1,51 @@
+#include "thrift.h"
+#include "transport/thrift_transport_factory.h"
+
+/* forward declaration s*/
+static void thrift_transport_factory_class_init (ThriftTransportFactoryClass *cls);
+ThriftTransport *thrift_transport_factory_get_transport (ThriftTransportFactory *factory, ThriftTransport *transport);
+
+GType
+thrift_transport_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (ThriftTransportFactoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) thrift_transport_factory_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ThriftTransportFactory),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "ThriftTransportFactory",
+ &info, 0);
+ }
+
+ return type;
+}
+
+static void
+thrift_transport_factory_class_init (ThriftTransportFactoryClass *cls)
+{
+ cls->get_transport = thrift_transport_factory_get_transport;
+}
+
+/* builds a transport from the base transport. */
+ThriftTransport *
+thrift_transport_factory_get_transport (ThriftTransportFactory *factory,
+ ThriftTransport *transport)
+{
+ THRIFT_UNUSED_VAR (factory);
+ return transport;
+}
+
+
+
diff --git a/lib/c_glib/src/transport/thrift_transport_factory.h b/lib/c_glib/src/transport/thrift_transport_factory.h
new file mode 100644
index 0000000..d987a80
--- /dev/null
+++ b/lib/c_glib/src/transport/thrift_transport_factory.h
@@ -0,0 +1,55 @@
+#ifndef _THRIFT_TRANSPORT_FACTORY_H
+#define _THRIFT_TRANSPORT_FACTORY_H
+
+#include <glib-object.h>
+
+#include "thrift_transport.h"
+
+/*! \file thrift_transport_factory.h
+ * \brief Base class for Thrift Transport Factories. Used by Thrift Servers
+ * to obtain a client transport from an existing transport. The default
+ * implementation simply clones the provided transport.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_TRANSPORT_FACTORY (thrift_transport_factory_get_type ())
+#define THRIFT_TRANSPORT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_TRANSPORT_FACTORY, \
+ ThriftTransportFactory))
+#define THRIFT_IS_TRANSPORT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_TRANSPORT_FACTORY))
+#define THRIFT_TRANSPORT_FACTORY_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_TRANSPORT_FACTORY, \
+ ThriftTransportFactoryClass))
+#define THRIFT_IS_TRANSPORT_FACTORY_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_TRANSPORT_FACTORY))
+#define THRIFT_TRANSPORT_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_TRANSPORT_FACTORY, \
+ ThriftTransportFactoryClass))
+
+/* Thrift Transport Factory instance */
+struct _ThriftTransportFactory
+{
+ GObject parent;
+};
+typedef struct _ThriftTransportFactory ThriftTransportFactory;
+
+/* Thrift Transport Factory class */
+struct _ThriftTransportFactoryClass
+{
+ GObjectClass parent;
+
+ /* vtable */
+ ThriftTransport *(*get_transport) (ThriftTransportFactory *factory,
+ ThriftTransport *transport);
+};
+typedef struct _ThriftTransportFactoryClass ThriftTransportFactoryClass;
+
+/* used by THRIFT_TYPE_TRANSPORT_FACTORY */
+GType thrift_transport_factory_get_type (void);
+
+/* virtual public methods */
+ThriftTransport *thrift_transport_factory_get_transport (ThriftTransportFactory *factory, ThriftTransport *transport);
+
+
+#endif /* _THRIFT_TRANSPORT_FACTORY_H */
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
new file mode 100644
index 0000000..a8889be
--- /dev/null
+++ b/lib/c_glib/test/Makefile.am
@@ -0,0 +1,229 @@
+SUBDIRS =
+
+AM_CPPFLAGS = -g -Wall -I../src $(GLIB_CFLAGS)
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+
+CFLAGS = @GCOV_CFLAGS@
+CXXFLAGS = -g
+
+check_SCRIPTS = \
+ testwrapper-testtransportsocket \
+ testwrapper-testprotocolbinary \
+ testwrapper-testbufferedtransport \
+ testwrapper-testframedtransport \
+ testwrapper-testmemorybuffer \
+ testwrapper-teststruct \
+ testwrapper-testsimpleserver \
+ testwrapper-testdebugproto \
+ testwrapper-testoptionalrequired \
+ testwrapper-testthrifttest
+
+if WITH_CPP
+ check_SCRIPTS += testwrapper-testthrifttestclient
+endif
+
+check_PROGRAMS = \
+ testtransportsocket \
+ testprotocolbinary \
+ testbufferedtransport \
+ testframedtransport \
+ testmemorybuffer \
+ teststruct \
+ testsimpleserver \
+ testdebugproto \
+ testoptionalrequired \
+ testthrifttest
+
+if WITH_CPP
+ check_PROGRAMS += testthrifttestclient
+endif
+
+testtransportsocket_SOURCES = testtransportsocket.c
+testtransportsocket_LDADD = \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ ../libthrift_c_glib_la-thrift_server_transport.o \
+ ../libthrift_c_glib_la-thrift_server_socket.o
+
+testprotocolbinary_SOURCES = testprotocolbinary.c
+testprotocolbinary_LDADD = \
+ ../libthrift_c_glib_la-thrift_protocol.o \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ ../libthrift_c_glib_la-thrift_socket.o \
+ ../libthrift_c_glib_la-thrift_server_transport.o \
+ ../libthrift_c_glib_la-thrift_server_socket.o
+
+testbufferedtransport_SOURCES = testbufferedtransport.c
+testbufferedtransport_LDADD = \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ ../libthrift_c_glib_la-thrift_socket.o \
+ ../libthrift_c_glib_la-thrift_server_transport.o \
+ ../libthrift_c_glib_la-thrift_server_socket.o
+
+testframedtransport_SOURCES = testframedtransport.c
+testframedtransport_LDADD = \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ ../libthrift_c_glib_la-thrift_socket.o \
+ ../libthrift_c_glib_la-thrift_server_transport.o \
+ ../libthrift_c_glib_la-thrift_server_socket.o
+
+testmemorybuffer_SOURCES = testmemorybuffer.c
+testmemorybuffer_LDADD = \
+ ../libthrift_c_glib_la-thrift_transport.o
+
+teststruct_SOURCES = teststruct.c
+teststruct_LDADD = \
+ ../libthrift_c_glib_la-thrift_protocol.o \
+ ../libthrift_c_glib_la-thrift_transport.o
+
+testsimpleserver_SOURCES = testsimpleserver.c
+testsimpleserver_LDADD = \
+ ../libthrift_c_glib_la-thrift_protocol.o \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ ../libthrift_c_glib_la-thrift_transport_factory.o \
+ ../libthrift_c_glib_la-thrift_processor.o \
+ ../libthrift_c_glib_la-thrift_protocol_factory.o \
+ ../libthrift_c_glib_la-thrift_binary_protocol.o \
+ ../libthrift_c_glib_la-thrift_binary_protocol_factory.o \
+ ../libthrift_c_glib_la-thrift_socket.o \
+ ../libthrift_c_glib_la-thrift_server_transport.o \
+ ../libthrift_c_glib_la-thrift_server_socket.o \
+ ../libthrift_c_glib_la-thrift_server.o
+
+testdebugproto_SOURCES = testdebugproto.c
+testdebugproto_LDADD = libtestgenc.la
+
+testoptionalrequired_SOURCES = testoptionalrequired.c
+testoptionalrequired_LDADD = \
+ ../libthrift_c_glib_la-thrift_protocol.o \
+ ../libthrift_c_glib_la-thrift_transport.o \
+ libtestgenc.la
+
+testthrifttest_SOURCES = testthrifttest.c
+testthrifttest_LDADD = libtestgenc.la
+
+testthrifttestclient_SOURCES = testthrifttestclient.cpp
+testthrifttestclient_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp -I../src -I./gen-c_glib $(GLIB_CFLAGS)
+testthrifttestclient_LDADD = ../../cpp/.libs/libthrift.la ../libthrift_c_glib.la libtestgenc.la libtestgencpp.la
+testthrifttestclient_LDFLAGS = -L../.libs -L../../cpp/.libs $(GLIB_LIBS) $(GOBJECT_LIBS)
+
+check_LTLIBRARIES = libtestgenc.la
+
+if WITH_CPP
+ check_LTLIBRARIES += libtestgencpp.la
+endif
+
+libtestgenc_la_SOURCES = \
+ gen-c_glib/t_test_debug_proto_test_types.c \
+ gen-c_glib/t_test_empty_service.c \
+ gen-c_glib/t_test_inherited.c \
+ gen-c_glib/t_test_optional_required_test_types.c \
+ gen-c_glib/t_test_reverse_order_service.c \
+ gen-c_glib/t_test_second_service.c \
+ gen-c_glib/t_test_service_for_exception_with_a_map.c \
+ gen-c_glib/t_test_srv.c \
+ gen-c_glib/t_test_thrift_test.c \
+ gen-c_glib/t_test_thrift_test_types.c \
+ gen-c_glib/t_test_debug_proto_test_types.h \
+ gen-c_glib/t_test_empty_service.h \
+ gen-c_glib/t_test_inherited.h \
+ gen-c_glib/t_test_optional_required_test_types.h \
+ gen-c_glib/t_test_reverse_order_service.h \
+ gen-c_glib/t_test_second_service.h \
+ gen-c_glib/t_test_service_for_exception_with_a_map.h \
+ gen-c_glib/t_test_srv.h \
+ gen-c_glib/t_test_thrift_test.h \
+ gen-c_glib/t_test_thrift_test_types.h
+libtestgenc_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+libtestgencpp_la_SOURCES = \
+ gen-cpp/ThriftTest.cpp \
+ gen-cpp/ThriftTest_constants.cpp \
+ gen-cpp/ThriftTest_types.cpp \
+ gen-cpp/ThriftTest.h \
+ gen-cpp/ThriftTest_constants.h \
+ gen-cpp/ThriftTest_types.h
+libtestgencpp_la_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift
+ $(THRIFT) --gen c_glib $<
+
+gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift
+ $(THRIFT) --gen c_glib $<
+
+gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test-.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/ThriftTest.thrift
+ $(THRIFT) --gen c_glib $<
+
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h: ../../../test/ThriftTest.thrift
+ $(THRIFT) --gen cpp $<
+
+
+TESTS = \
+ $(testwrapper-%) \
+ $(check_PROGRAMS) \
+ $(check_SCRIPTS)
+
+# globally added to all instances of valgrind calls
+# VALGRIND_OPTS = --suppressions=glib.suppress
+VALGRIND_OPTS =
+
+# globally added to all memcheck calls
+VALGRIND_MEM_OPTS = --tool=memcheck \
+ --num-callers=10 \
+ ${myextravalgrindmemopts}
+
+# globally added to all leakcheck calls
+VALGRIND_LEAK_OPTS = --tool=memcheck \
+ --num-callers=10 \
+ --leak-check=full \
+ --leak-resolution=high \
+ ${myextravalgrindleakopts}
+
+memcheck: $(check_PROGRAMS)
+ @for x in $(check_PROGRAMS); \
+ do \
+ $(MAKE) memcheck-$$x; \
+ done
+
+leakcheck: $(check_PROGRAMS)
+ @for x in $(check_PROGRAMS); \
+ do \
+ $(MAKE) leakcheck-$$x; \
+ done
+
+memcheck-%: %
+ @echo "*****************************************"; \
+ echo "MEMCHECK: $<"; \
+ echo "ARGS: ${VALGRIND_OPTS} ${VALGRIND_MEM_OPTS} ${$<_VALGRIND_MEM_OPTS}"; \
+ $(LIBTOOL) --mode=execute \
+ valgrind \
+ ${VALGRIND_OPTS} \
+ ${VALGRIND_MEM_OPTS} \
+ ${$<_VALGRIND_MEM_OPTS} ./$<
+
+leakcheck-%: %
+ @echo "*****************************************"; \
+ echo "LEAKCHECK: $<"; \
+ echo "ARGS: ${VALGRIND_OPTS} ${VALGRIND_LEAK_OPTS} ${$<_VALGRIND_LEAK_OPTS}"; \
+ G_SLICE=always-malloc $(LIBTOOL) --mode=execute \
+ valgrind \
+ ${VALGRIND_OPTS} \
+ ${VALGRIND_LEAK_OPTS} \
+ ${$<_VALGRIND_LEAK_OPTS} ./$<
+
+testwrapper-%: % test-wrapper.sh
+ @ln -sf test-wrapper.sh $@
+
+clean-local:
+ $(RM) -r gen-c_glib gen-cpp
+
+CLEANFILES = \
+ testwrapper-* \
+ *.bb \
+ *.bbg \
+ *.da \
+ *.gcno \
+ *.gcda \
+ *.gcov \
+ test-wrapper.sh
diff --git a/lib/c_glib/test/glib.suppress b/lib/c_glib/test/glib.suppress
new file mode 100644
index 0000000..0e0e9fe
--- /dev/null
+++ b/lib/c_glib/test/glib.suppress
@@ -0,0 +1,64 @@
+{
+ g_type_init_1
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:g_type_init_with_debug_flags
+}
+
+{
+ g_type_init_2
+ Memcheck:Leak
+ fun:calloc
+ ...
+ fun:g_type_init_with_debug_flags
+}
+
+{
+ g_type_init_3
+ Memcheck:Leak
+ fun:realloc
+ ...
+ fun:g_type_init_with_debug_flags
+}
+
+{
+ g_type_register_static_1
+ Memcheck:Leak
+ fun:realloc
+ ...
+ fun:g_type_register_static
+}
+
+{
+ g_type_register_statuc_2
+ Memcheck:Leak
+ fun:malloc
+ fun:realloc
+ fun:g_realloc
+ ...
+ fun:g_type_register_static
+}
+
+{
+ type_class_init_Wm1
+ Memcheck:Leak
+ fun:calloc
+ fun:g_malloc0
+ fun:type_class_init_Wm
+ fun:g_type_class_ref
+ ...
+ fun:g_object_newv
+}
+
+{
+ type_class_init_Wm2
+ Memcheck:Leak
+ fun:calloc
+ fun:g_malloc0
+ fun:type_class_init_Wm
+ fun:g_type_class_ref
+ ...
+ fun:type_class_init_Wm
+}
+
diff --git a/lib/c_glib/test/test-wrapper.sh.in b/lib/c_glib/test/test-wrapper.sh.in
new file mode 100644
index 0000000..956b2d1
--- /dev/null
+++ b/lib/c_glib/test/test-wrapper.sh.in
@@ -0,0 +1,58 @@
+# /bin/sh
+
+command="$0"
+
+stripcommand=`echo "$command" | sed 's/testwrapper-//'`
+
+"$stripcommand" "$@" || exit $?
+
+if test "x@ENABLE_COVERAGE@" = "x1"; then
+ # linux: 97.67% of 86 lines executed in file ../src/test123.h
+ # bsd: 100.00% of 196 source lines executed in file testbimap.c
+
+ extrastripcommand=`echo "$stripcommand" | sed 's/\.\///'`
+ ${GCOV:-gcov} "$extrastripcommand" 2>&1 \
+ | perl -ne 'BEGIN { $file = undef; }
+ next if m!^Creating!;
+ next if m!creating!;
+ next if m!^$!;
+ next if m!not exhausted!;
+ next if m!^Unexpected EOF!;
+ if (m!([\d\.]+)\% of \d+( source)? lines executed in file (.+)!)
+ {
+ do
+ {
+ if ( $3 !~ m#^/# )
+ {
+ $a = $3 =~ m%([\-\w\.]+)$%;
+ print STDERR $_;
+ print "$1.gcov\n";
+ }
+ } if $1 < 110.0;
+ }
+ elsif (m#^File .(.*?).$#)
+ {
+ $file = $1;
+ }
+ elsif (m#Lines executed:([\d\.]+)\% of (\d+)#)
+ {
+ $percent = $1;
+ $lines = $2;
+ do
+ {
+ if ( $file !~ m#^/# )
+ {
+ $a = $file =~ m%([\-\w\.]+)$%;
+ print STDERR "$percent% of $lines executed in file $file\n";
+ print "$1.gcov\n";
+ }
+ } if $percent < 110.0;
+ }
+ else
+ {
+ print
+ }' \
+ | xargs grep -n -A2 -B2 '#####.*\w'
+ exit 0
+fi
+
diff --git a/lib/c_glib/test/testbufferedtransport.c b/lib/c_glib/test/testbufferedtransport.c
new file mode 100644
index 0000000..6759509
--- /dev/null
+++ b/lib/c_glib/test/testbufferedtransport.c
@@ -0,0 +1,188 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_buffered_transport.c"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+ ThriftTransport *transport = NULL;
+ guint r_buf_size = 0;
+ guint w_buf_size = 0;
+
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, NULL);
+ assert (object != NULL);
+ g_object_get (G_OBJECT (object), "transport", &transport,
+ "r_buf_size", &r_buf_size,
+ "w_buf_size", &w_buf_size, NULL);
+ g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ GError *err = NULL;
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", 51188, NULL);
+
+ /* create a BufferedTransport wrapper of the Socket */
+ transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+ /* this shouldn't work */
+ assert (thrift_buffered_transport_open (transport, NULL) == FALSE);
+ assert (thrift_buffered_transport_is_open (transport) == TRUE);
+ assert (thrift_buffered_transport_close (transport, NULL) == TRUE);
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+
+ /* try and underlying socket failure */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+ NULL);
+
+ /* create a BufferedTransport wrapper of the Socket */
+ transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+ assert (thrift_buffered_transport_open (transport, &err) == FALSE);
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+ g_error_free (err);
+ err = NULL;
+}
+
+static void
+test_read_and_write(void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ int port = 51199;
+ guchar buf[10] = TEST_DATA; /* a buffer */
+
+ pid = fork ();
+ assert ( pid >= 0 );
+
+ if ( pid == 0 )
+ {
+ /* child listens */
+ thrift_server (port);
+ exit (0);
+ } else {
+ /* parent connects, wait a bit for the socket to be created */
+ sleep (1);
+
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket),
+ "w_buf_size", 4, NULL);
+
+ assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
+ assert (thrift_buffered_transport_is_open (transport));
+
+ /* write 10 bytes */
+ thrift_buffered_transport_write (transport, buf, 10, NULL);
+
+ /* write 1 byte at a time */
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+
+ /* overflow the buffer */
+ thrift_buffered_transport_write (transport, buf, 2, NULL);
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+ thrift_buffered_transport_flush (transport, NULL);
+
+ /* write 1 byte and flush */
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+ thrift_buffered_transport_flush (transport, NULL);
+
+ /* write and overflow buffer with 2 system calls */
+ thrift_buffered_transport_write (transport, buf, 1, NULL);
+ thrift_buffered_transport_write (transport, buf, 3, NULL);
+
+ /* write 10 bytes */
+ thrift_buffered_transport_write (transport, buf, 10, NULL);
+
+ thrift_buffered_transport_write_end (transport, NULL);
+ thrift_buffered_transport_flush (transport, NULL);
+ thrift_buffered_transport_close (transport, NULL);
+
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+
+ assert ( wait (&status) == pid );
+ assert ( status == 0 );
+ }
+}
+
+static void
+thrift_server (const int port)
+{
+ int bytes = 0;
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ guchar buf[10]; /* a buffer */
+ guchar match[10] = TEST_DATA;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+
+ /* wrap the client in a BufferedTransport */
+ client = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, "transport",
+ thrift_server_transport_accept (transport, NULL),
+ "r_buf_size", 5, NULL);
+ assert (client != NULL);
+
+ /* read 10 bytes */
+ bytes = thrift_buffered_transport_read (client, buf, 10, NULL);
+ assert (bytes == 10); /* make sure we've read 10 bytes */
+ assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+
+ /* read 1 byte */
+ bytes = thrift_buffered_transport_read (client, buf, 1, NULL);
+
+ bytes = thrift_buffered_transport_read (client, buf, 6, NULL);
+ bytes = thrift_buffered_transport_read (client, buf, 2, NULL);
+ bytes = thrift_buffered_transport_read (client, buf, 1, NULL);
+
+ thrift_buffered_transport_read_end (client, NULL);
+ thrift_buffered_transport_close (client, NULL);
+ g_object_unref (client);
+ g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+ g_type_init();
+ test_create_and_destroy();
+ test_open_and_close();
+ test_read_and_write();
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testdebugproto.c b/lib/c_glib/test/testdebugproto.c
new file mode 100644
index 0000000..b111e12
--- /dev/null
+++ b/lib/c_glib/test/testdebugproto.c
@@ -0,0 +1,64 @@
+#include <math.h>
+#include <glib-object.h>
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932385
+#endif
+
+#include "gen-c_glib/t_test_debug_proto_test_types.h"
+
+
+int
+main(void)
+{
+ g_type_init ();
+
+ TTestOneOfEach *ooe = NULL;
+ TTestNesting *n = NULL;
+ TTestHolyMoley *hm = NULL;
+
+ ooe = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+ ooe->im_true = TRUE;
+ ooe->im_false = FALSE;
+ ooe->a_bite = 0xd6;
+ ooe->integer16 = 27000;
+ ooe->integer32 = 1<<24;
+ ooe->integer64 = (guint64) 6000 * 1000 * 1000;
+ ooe->double_precision = M_PI;
+ ooe->some_characters = "Debug THIS!";
+ ooe->zomg_unicode = "\xd7\n\a\t";
+
+ n = g_object_new (T_TEST_TYPE_NESTING, NULL);
+ n->my_ooe = ooe;
+ n->my_ooe->integer16 = 16;
+ n->my_ooe->integer32 = 32;
+ n->my_ooe->integer64 = 64;
+ n->my_ooe->double_precision = (sqrt(5.0) + 1) / 2;
+ n->my_ooe->some_characters = ":R (me going \"rrrr\")";
+ n->my_ooe->zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20";
+ n->my_bonk->type = 31337;
+ n->my_bonk->message = "I am a bonk... xor!";
+
+ hm = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+ g_ptr_array_add (hm->big, ooe);
+ g_ptr_array_add (hm->big, n->my_ooe);
+ ((TTestOneOfEach *) g_ptr_array_index (hm->big, 0))->a_bite = 0x22;
+ ((TTestOneOfEach *) g_ptr_array_index (hm->big, 1))->a_bite = 0x33;
+
+ g_hash_table_insert (hm->contain, "random string", "random string");
+
+ TTestBonk *bonk = NULL;
+ bonk = g_object_new (T_TEST_TYPE_BONK, NULL);
+ GPtrArray *bonks = g_ptr_array_new ();
+ g_ptr_array_add (bonks, bonk);
+ g_hash_table_insert (hm->bonks, "nothing", bonks);
+
+ g_ptr_array_free (bonks, TRUE);
+ g_object_unref (bonk);
+ g_object_unref (ooe);
+ g_object_unref (n);
+ g_object_unref (hm);
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testframedtransport.c b/lib/c_glib/test/testframedtransport.c
new file mode 100644
index 0000000..23951f7
--- /dev/null
+++ b/lib/c_glib/test/testframedtransport.c
@@ -0,0 +1,176 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_framed_transport.c"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+ ThriftTransport *transport = NULL;
+ guint r_buf_size = 0;
+ guint w_buf_size = 0;
+
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, NULL);
+ assert (object != NULL);
+ g_object_get (G_OBJECT (object), "transport", &transport,
+ "r_buf_size", &r_buf_size,
+ "w_buf_size", &w_buf_size, NULL);
+ g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ GError *err = NULL;
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", 51188, NULL);
+
+ /* create a BufferedTransport wrapper of the Socket */
+ transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+ /* this shouldn't work */
+ assert (thrift_framed_transport_open (transport, NULL) == FALSE);
+ assert (thrift_framed_transport_is_open (transport) == TRUE);
+ assert (thrift_framed_transport_close (transport, NULL) == TRUE);
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+
+ /* try and underlying socket failure */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+ NULL);
+
+ /* create a BufferedTransport wrapper of the Socket */
+ transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+ assert (thrift_framed_transport_open (transport, &err) == FALSE);
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+ g_error_free (err);
+ err = NULL;
+}
+
+static void
+test_read_and_write(void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ int port = 51199;
+ guchar buf[10] = TEST_DATA; /* a buffer */
+
+ pid = fork ();
+ assert ( pid >= 0 );
+
+ if ( pid == 0 )
+ {
+ /* child listens */
+ thrift_server (port);
+ exit (0);
+ } else {
+ /* parent connects, wait a bit for the socket to be created */
+ sleep (1);
+
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+ "transport", THRIFT_TRANSPORT (tsocket),
+ "w_buf_size", 4, NULL);
+
+ assert (thrift_framed_transport_open (transport, NULL) == TRUE);
+ assert (thrift_framed_transport_is_open (transport));
+
+ /* write 10 bytes */
+ thrift_framed_transport_write (transport, buf, 10, NULL);
+ thrift_framed_transport_flush (transport, NULL);
+
+ thrift_framed_transport_write (transport, buf, 1, NULL);
+ thrift_framed_transport_flush (transport, NULL);
+
+ thrift_framed_transport_write (transport, buf, 10, NULL);
+ thrift_framed_transport_flush (transport, NULL);
+
+ thrift_framed_transport_write (transport, buf, 10, NULL);
+ thrift_framed_transport_flush (transport, NULL);
+
+ thrift_framed_transport_write_end (transport, NULL);
+ thrift_framed_transport_flush (transport, NULL);
+ thrift_framed_transport_close (transport, NULL);
+
+ g_object_unref (transport);
+ g_object_unref (tsocket);
+
+ assert ( wait (&status) == pid );
+ assert ( status == 0 );
+ }
+}
+
+static void
+thrift_server (const int port)
+{
+ int bytes = 0;
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ guchar buf[10]; /* a buffer */
+ guchar match[10] = TEST_DATA;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+
+ /* wrap the client in a BufferedTransport */
+ client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
+ thrift_server_transport_accept (transport, NULL),
+ "r_buf_size", 5, NULL);
+ assert (client != NULL);
+
+ /* read 10 bytes */
+ bytes = thrift_framed_transport_read (client, buf, 10, NULL);
+ assert (bytes == 10); /* make sure we've read 10 bytes */
+ assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+
+ bytes = thrift_framed_transport_read (client, buf, 6, NULL);
+ bytes = thrift_framed_transport_read (client, buf, 5, NULL);
+ bytes = thrift_framed_transport_read (client, buf, 1, NULL);
+
+ bytes = thrift_framed_transport_read (client, buf, 12, NULL);
+
+ thrift_framed_transport_read_end (client, NULL);
+ thrift_framed_transport_close (client, NULL);
+ g_object_unref (client);
+ g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+ g_type_init();
+ test_create_and_destroy();
+ test_open_and_close();
+ test_read_and_write();
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testmemorybuffer.c b/lib/c_glib/test/testmemorybuffer.c
new file mode 100644
index 0000000..52b18bf
--- /dev/null
+++ b/lib/c_glib/test/testmemorybuffer.c
@@ -0,0 +1,75 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_memory_buffer.c"
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+ assert (object != NULL);
+ g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+ ThriftMemoryBuffer *tbuffer = NULL;
+
+ /* create a ThriftMemoryBuffer */
+ tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+
+ /* this shouldn't work */
+ assert (thrift_memory_buffer_open (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+ assert (thrift_memory_buffer_is_open (THRIFT_TRANSPORT (tbuffer)) == TRUE);
+ assert (thrift_memory_buffer_close (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+ g_object_unref (tbuffer);
+}
+
+static void
+test_read_and_write(void)
+{
+ ThriftMemoryBuffer *tbuffer = NULL;
+ guchar buf[10] = TEST_DATA;
+ guchar read[10];
+ GError *error = NULL;
+
+ tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 5, NULL);
+ assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+ (gpointer) buf,
+ 10, &error) == FALSE);
+ assert (error != NULL);
+ g_error_free (error);
+ error = NULL;
+ g_object_unref (tbuffer);
+
+ tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 15, NULL);
+ assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+ (gpointer) buf, 10, &error) == TRUE);
+ assert (error == NULL);
+
+ assert (thrift_memory_buffer_read (THRIFT_TRANSPORT (tbuffer),
+ &read, 10, &error) > 0);
+ assert (error == NULL);
+}
+
+int
+main(void)
+{
+ g_type_init();
+ test_create_and_destroy();
+ test_open_and_close();
+ test_read_and_write();
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testoptionalrequired.c b/lib/c_glib/test/testoptionalrequired.c
new file mode 100644
index 0000000..cf44413
--- /dev/null
+++ b/lib/c_glib/test/testoptionalrequired.c
@@ -0,0 +1,182 @@
+#include <assert.h>
+#include <glib.h>
+
+#include "thrift_struct.h"
+#include "protocol/thrift_protocol.h"
+#include "protocol/thrift_binary_protocol.h"
+#include "transport/thrift_memory_buffer.h"
+#include "gen-c_glib/t_test_optional_required_test_types.h"
+
+#include "gen-c_glib/t_test_optional_required_test_types.c"
+
+static void
+write_to_read (ThriftStruct *w, ThriftStruct *r, GError **write_error,
+ GError **read_error)
+{
+ ThriftMemoryBuffer *tbuffer = NULL;
+ ThriftProtocol *protocol = NULL;
+
+ tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+ protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ tbuffer, NULL);
+
+ thrift_struct_write (w, protocol, write_error);
+ thrift_struct_read (r, protocol, read_error);
+
+ g_object_unref (protocol);
+ g_object_unref (tbuffer);
+}
+
+static void
+test_old_school1 (void)
+{
+ TTestOldSchool *o = NULL;
+
+ o = g_object_new (T_TEST_TYPE_OLD_SCHOOL, NULL);
+ o->im_int = 10;
+ o->im_str = g_strdup ("test");
+ o->im_big = g_ptr_array_new ();
+ g_ptr_array_free (o->im_big, FALSE);
+ g_free (o->im_str);
+ g_object_unref (o);
+}
+
+/**
+ * Write to read with optional fields
+ */
+static void
+test_simple (void)
+{
+ TTestSimple *s1 = NULL, *s2 = NULL, *s3 = NULL;
+
+ s1 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+ s2 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+ s3 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+
+ // write-to-read with optional fields
+ s1->im_optional = 10;
+ assert (s1->__isset_im_default == FALSE);
+ assert (s1->__isset_im_optional == FALSE);
+ write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s2), NULL, NULL);
+ assert (s2->__isset_im_default = TRUE);
+ assert (s2->__isset_im_optional == FALSE);
+ assert (s2->im_optional == 0);
+
+ s1->__isset_im_optional = TRUE;
+ write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s3), NULL, NULL);
+ assert (s3->__isset_im_default == TRUE);
+ assert (s3->__isset_im_optional == TRUE);
+ assert (s3->im_optional == 10);
+
+ g_object_unref (s1);
+ g_object_unref (s2);
+}
+
+/**
+ * Writing between optional and default
+ */
+static void
+test_tricky1 (void)
+{
+ TTestTricky1 *t1 = NULL;
+ TTestTricky2 *t2 = NULL;
+
+ t1 = g_object_new (T_TEST_TYPE_TRICKY1, NULL);
+ t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+
+ t2->im_optional = 10;
+ write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t1), NULL, NULL);
+ write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t2), NULL, NULL);
+
+ assert (t1->__isset_im_default == FALSE);
+ assert (t2->__isset_im_optional == TRUE);
+ assert (t1->im_default == t2->im_optional);
+ assert (t1->im_default == 0);
+
+ g_object_unref (t1);
+ g_object_unref (t2);
+}
+
+/**
+ * Writing between default and required.
+ */
+static void
+test_tricky2 (void)
+{
+ TTestTricky1 *t1 = NULL;
+ TTestTricky3 *t3 = NULL;
+
+ t1 = g_object_new (T_TEST_TYPE_TRICKY1, NULL);
+ t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+ write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t3), NULL, NULL);
+ write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t1), NULL, NULL);
+
+ assert (t1->__isset_im_default == TRUE);
+
+ g_object_unref (t1);
+ g_object_unref (t3);
+}
+
+/**
+ * Writing between optional and required.
+ */
+static void
+test_tricky3 (void)
+{
+ TTestTricky2 *t2 = NULL;
+ TTestTricky3 *t3 = NULL;
+
+ t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+ t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+ t2->__isset_im_optional = TRUE;
+
+ write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t3), NULL, NULL);
+ write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t2), NULL, NULL);
+
+ g_object_unref (t2);
+ g_object_unref (t3);
+}
+
+/**
+ * Catch an optional not set exception. To quote the
+ * C++ test, "Mu-hu-ha-ha-ha!"
+ */
+static void
+test_tricky4 (void)
+{
+ TTestTricky2 *t2 = NULL;
+ TTestTricky3 *t3 = NULL;
+ GError *read_error = NULL;
+
+ t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+ t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+ // throws protocol exception
+ write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t3), NULL, &read_error);
+ assert (read_error != NULL);
+ g_error_free (read_error);
+
+ write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t2), NULL, NULL);
+
+ assert (t2->__isset_im_optional);
+
+ g_object_unref (t2);
+ g_object_unref (t3);
+}
+
+int
+main(void)
+{
+ g_type_init ();
+ test_old_school1 ();
+ test_simple ();
+ test_tricky1 ();
+ test_tricky2 ();
+ test_tricky3 ();
+ test_tricky4 ();
+ return 0;
+}
+
+
diff --git a/lib/c_glib/test/testprotocolbinary.c b/lib/c_glib/test/testprotocolbinary.c
new file mode 100644
index 0000000..c8a54b9
--- /dev/null
+++ b/lib/c_glib/test/testprotocolbinary.c
@@ -0,0 +1,652 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "protocol/thrift_protocol.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_BOOL TRUE
+#define TEST_BYTE 123
+#define TEST_I16 12345
+#define TEST_I32 1234567890
+#define TEST_I64 123456789012345LL
+#define TEST_DOUBLE 1234567890.123
+#define TEST_STRING "this is a test string 1234567890!@#$%^&*()"
+#define TEST_PORT 51199
+
+static int transport_read_count = 0;
+static int transport_read_error = 0;
+static int transport_read_error_at = -1;
+gint32
+my_thrift_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ if (transport_read_count != transport_read_error_at
+ && transport_read_error == 0)
+ {
+ transport_read_count++;
+ return thrift_transport_read (transport, buf, len, error);
+ }
+ return -1;
+}
+
+static int transport_write_count = 0;
+static int transport_write_error = 0;
+static int transport_write_error_at = -1;
+gboolean
+my_thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ if (transport_write_count != transport_write_error_at
+ && transport_write_error == 0)
+ {
+ transport_write_count++;
+ return thrift_transport_write (transport, buf, len, error);
+ }
+ return FALSE;
+}
+
+#define thrift_transport_read my_thrift_transport_read
+#define thrift_transport_write my_thrift_transport_write
+#include "../src/protocol/thrift_binary_protocol.c"
+#undef thrift_transport_read
+#undef thrift_transport_write
+
+static void thrift_server_primitives (const int port);
+static void thrift_server_complex_types (const int port);
+
+static void
+test_create_and_destroy(void)
+{
+ GObject *object = NULL;
+
+ /* create an object and then destroy it */
+ object = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, NULL);
+ assert (object != NULL);
+ g_object_unref (object);
+}
+
+static void
+test_initialize(void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftBinaryProtocol *protocol = NULL;
+ ThriftSocket *temp = NULL;
+
+ /* create a ThriftTransport */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", 51188, NULL);
+ assert (tsocket != NULL);
+ /* create a ThriftBinaryProtocol using the Transport */
+ protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ tsocket, NULL);
+ assert (protocol != NULL);
+ /* fetch the properties */
+ g_object_get (G_OBJECT(protocol), "transport", &temp, NULL);
+ g_object_unref (temp);
+
+ /* clean up memory */
+ g_object_unref (protocol);
+ g_object_unref (tsocket);
+}
+
+static void
+test_read_and_write_primitives(void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ ThriftBinaryProtocol *tb = NULL;
+ ThriftProtocol *protocol = NULL;
+ gpointer binary = (gpointer *) TEST_STRING;
+ guint32 len = strlen (TEST_STRING);
+ int port = TEST_PORT;
+
+ /* fork a server from the client */
+ pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0)
+ {
+ /* child listens */
+ thrift_server_primitives (port);
+ exit (0);
+ } else {
+ /* parent. wait a bit for the socket to be created. */
+ sleep (1);
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ thrift_transport_open (transport, NULL);
+ assert (thrift_transport_is_open (transport));
+
+ /* create a ThriftBinaryTransport */
+ tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ tsocket, NULL);
+ protocol = THRIFT_PROTOCOL (tb);
+ assert (protocol != NULL);
+
+ /* write a bunch of primitives */
+ assert (thrift_binary_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+ assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+ assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+ assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+ assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+ assert (thrift_binary_protocol_write_double (protocol,
+ TEST_DOUBLE, NULL) > 0);
+ assert (thrift_binary_protocol_write_string (protocol,
+ TEST_STRING, NULL) > 0);
+ assert (thrift_binary_protocol_write_binary (protocol, binary,
+ len, NULL) > 0);
+ assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+ assert (thrift_binary_protocol_write_binary (protocol, binary,
+ len, NULL) > 0);
+
+ /* test write errors */
+ transport_write_error = 1;
+ assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE,
+ NULL) == -1);
+ assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
+ assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
+ assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
+ assert (thrift_binary_protocol_write_double (protocol, TEST_DOUBLE,
+ NULL) == -1);
+ assert (thrift_binary_protocol_write_binary (protocol, binary, len,
+ NULL) == -1);
+ transport_write_error = 0;
+
+ /* test binary partial failure */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_binary_protocol_write_binary (protocol, binary,
+ len, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* clean up */
+ thrift_transport_close (transport, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (protocol);
+ assert (wait (&status) == pid);
+ assert (status == 0);
+ }
+}
+
+static void
+test_read_and_write_complex_types (void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ ThriftBinaryProtocol *tb = NULL;
+ ThriftProtocol *protocol = NULL;
+ int port = TEST_PORT;
+
+ /* fork a server from the client */
+ pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0)
+ {
+ /* child listens */
+ thrift_server_complex_types (port);
+ exit (0);
+ } else {
+ /* parent. wait a bit for the socket to be created. */
+ sleep (1);
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ thrift_transport_open (transport, NULL);
+ assert (thrift_transport_is_open (transport));
+
+ /* create a ThriftBinaryTransport */
+ tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ tsocket, NULL);
+ protocol = THRIFT_PROTOCOL (tb);
+ assert (protocol != NULL);
+
+ /* test structures */
+ assert (thrift_binary_protocol_write_struct_begin (protocol,
+ NULL, NULL) == 0);
+ assert (thrift_binary_protocol_write_struct_end (protocol, NULL) == 0);
+
+ assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+ 1, NULL) > 0);
+ assert (thrift_binary_protocol_write_field_end (protocol, NULL) == 0);
+
+ /* test write error */
+ transport_write_error = 1;
+ assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+ 1, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write error */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test 2nd read failure on a field */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+ /* test write_field_stop */
+ assert (thrift_binary_protocol_write_field_stop (protocol, NULL) > 0);
+
+ /* write a map */
+ assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+ 1, NULL) > 0);
+ assert (thrift_binary_protocol_write_map_end (protocol, NULL) == 0);
+
+ /* test 2nd read failure on a map */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+ /* test 3rd read failure on a map */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+ /* test 1st write failure on a map */
+ transport_write_error = 1;
+ assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+ 1, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write failure on a map */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test 3rd write failure on a map */
+ transport_write_count = 0;
+ transport_write_error_at = 2;
+ assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test negative map size */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+ thrift_binary_protocol_write_i32 (protocol, -10, NULL);
+
+ /* test list operations */
+ assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+ 1, NULL) > 0);
+ assert (thrift_binary_protocol_write_list_end (protocol, NULL) == 0);
+
+ /* test 2nd read failure on a list */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+ /* test negative list size */
+ thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+ thrift_binary_protocol_write_i32 (protocol, -10, NULL);
+
+ /* test first write error on a list */
+ transport_write_error = 1;
+ assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+ 1, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write error on a list */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test set operation s*/
+ assert (thrift_binary_protocol_write_set_begin (protocol, T_VOID,
+ 1, NULL) > 0);
+ assert (thrift_binary_protocol_write_set_end (protocol, NULL) == 0);
+
+ /* invalid version */
+ assert (thrift_binary_protocol_write_i32 (protocol, -1, NULL) > 0);
+
+ /* sz > 0 for a message */
+ assert (thrift_binary_protocol_write_i32 (protocol, 1, NULL) > 0);
+
+ /* send a valid message */
+ thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+ thrift_binary_protocol_write_string (protocol, "test", NULL);
+ thrift_binary_protocol_write_i32 (protocol, 1, NULL);
+
+ /* broken 2nd read */
+ thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+
+ /* send a broken 3rd read */
+ thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+ thrift_binary_protocol_write_string (protocol, "test", NULL);
+
+ /* send a valid message */
+ assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) > 0);
+
+ assert (thrift_binary_protocol_write_message_end (protocol, NULL) == 0);
+
+ /* send broken writes */
+ transport_write_error = 1;
+ assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error = 0;
+
+ transport_write_count = 0;
+ transport_write_error_at = 2;
+ assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ transport_write_count = 0;
+ transport_write_error_at = 3;
+ assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* clean up */
+ thrift_transport_close (transport, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (protocol);
+ assert (wait (&status) == pid);
+ assert (status == 0);
+ }
+}
+
+
+static void
+thrift_server_primitives (const int port)
+{
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ ThriftBinaryProtocol *tbp = NULL;
+ ThriftProtocol *protocol = NULL;
+ gboolean value_boolean = FALSE;
+ gint8 value_byte = 0;
+ gint16 value_16 = 0;
+ gint32 value_32 = 0;
+ gint64 value_64 = 0;
+ gdouble value_double = 0;
+ gchar *string = NULL;
+ gpointer binary = NULL;
+ guint32 len = 0;
+ void *comparator = (void *) TEST_STRING;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ client, NULL);
+ protocol = THRIFT_PROTOCOL (tbp);
+
+ assert (thrift_binary_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (thrift_binary_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+ assert (thrift_binary_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+ assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+ assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+ assert (thrift_binary_protocol_read_double (protocol,
+ &value_double, NULL) > 0);
+ assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+ assert (thrift_binary_protocol_read_binary (protocol, &binary,
+ &len, NULL) > 0);
+
+ assert (value_boolean == TEST_BOOL);
+ assert (value_byte = TEST_BYTE);
+ assert (value_16 = TEST_I16);
+ assert (value_32 = TEST_I32);
+ assert (value_64 = TEST_I64);
+ assert (value_double = TEST_DOUBLE);
+ assert (strcmp (TEST_STRING, string) == 0);
+ assert (memcmp (comparator, binary, len) == 0);
+
+ g_free (string);
+ g_free (binary);
+
+ thrift_binary_protocol_read_binary (protocol, &binary, &len, NULL);
+ g_free (binary);
+
+ transport_read_count = 0;
+ transport_read_error_at = 0;
+ assert (thrift_binary_protocol_read_binary (protocol, &binary,
+ &len, NULL) == -1);
+ transport_read_error_at = -1;
+
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_binary_protocol_read_binary (protocol, &binary,
+ &len, NULL) == -1);
+ transport_read_error_at = -1;
+
+ transport_read_error = 1;
+ assert (thrift_binary_protocol_read_bool (protocol,
+ &value_boolean, NULL) == -1);
+ assert (thrift_binary_protocol_read_byte (protocol,
+ &value_byte, NULL) == -1);
+ assert (thrift_binary_protocol_read_i16 (protocol,
+ &value_16, NULL) == -1);
+ assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) == -1);
+ assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) == -1);
+ assert (thrift_binary_protocol_read_double (protocol,
+ &value_double, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test partial write failure */
+ thrift_protocol_read_i32 (protocol, &value_32, NULL);
+
+ thrift_transport_read_end (client, NULL);
+ thrift_transport_close (client, NULL);
+
+ g_object_unref (tbp);
+ g_object_unref (client);
+ g_object_unref (tsocket);
+}
+
+static void
+thrift_server_complex_types (const int port)
+{
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ ThriftBinaryProtocol *tbp = NULL;
+ ThriftProtocol *protocol = NULL;
+ gchar *struct_name = NULL;
+ gchar *field_name = NULL;
+ gchar *message_name = NULL;
+ ThriftType element_type, key_type, value_type, field_type;
+ ThriftMessageType message_type;
+ gint8 value = 0;
+ gint16 field_id = 0;
+ guint32 size = 0;
+ gint32 seqid = 0;
+ gint32 version = 0;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+ client, NULL);
+ protocol = THRIFT_PROTOCOL (tbp);
+
+ thrift_binary_protocol_read_struct_begin (protocol, &struct_name, NULL);
+ thrift_binary_protocol_read_struct_end (protocol, NULL);
+
+ thrift_binary_protocol_read_field_begin (protocol, &field_name, &field_type,
+ &field_id, NULL);
+ thrift_binary_protocol_read_field_end (protocol, NULL);
+
+ /* test first read error on a field */
+ transport_read_error = 1;
+ assert (thrift_binary_protocol_read_field_begin (protocol,
+ &field_name, &field_type,
+ &field_id, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test 2nd write failure */
+ thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+ /* test 2nd read failure on a field */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_binary_protocol_read_field_begin (protocol,
+ &field_name, &field_type,
+ &field_id, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test field stop */
+ thrift_binary_protocol_read_field_begin (protocol, &field_name, &field_type,
+ &field_id, NULL);
+
+ thrift_binary_protocol_read_map_begin (protocol, &key_type, &value_type,
+ &size, NULL);
+ thrift_binary_protocol_read_map_end (protocol, NULL);
+
+ /* test read failure on a map */
+ transport_read_count = 0;
+ transport_read_error_at = 0;
+ assert (thrift_binary_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test 2nd read failure on a map */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_binary_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test 3rd read failure on a map */
+ transport_read_count = 0;
+ transport_read_error_at = 2;
+ assert (thrift_binary_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test 2nd write failure */
+ thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+ /* test 3rd write failure */
+ thrift_binary_protocol_read_byte (protocol, &value, NULL);
+ thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+ /* test negative map size */
+ assert (thrift_binary_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+
+ /* test list operations */
+ thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+ thrift_binary_protocol_read_list_end (protocol, NULL);
+
+ /* test read failure */
+ transport_read_error = 1;
+ assert (thrift_binary_protocol_read_list_begin (protocol, &element_type,
+ &size, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test 2nd read failure */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+ transport_read_error_at = -1;
+
+ /* test negative list size failure */
+ thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+
+ /* test 2nd write failure */
+ thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+ /* test set operations */
+ thrift_binary_protocol_read_set_begin (protocol, &element_type, &size, NULL);
+ thrift_binary_protocol_read_set_end (protocol, NULL);
+
+ /* broken read */
+ transport_read_error = 1;
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error = 0;
+
+ /* invalid protocol version */
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+
+ /* sz > 0 */
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) > 0);
+
+ /* read a valid message */
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) > 0);
+ g_free (message_name);
+
+ /* broken 2nd read on a message */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* broken 3rd read on a message */
+ transport_read_count = 0;
+ transport_read_error_at = 3; /* read_string does two reads */
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ g_free (message_name);
+ transport_read_error_at = -1;
+
+ /* read a valid message */
+ assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) > 0);
+ g_free (message_name);
+
+ assert (thrift_binary_protocol_read_message_end (protocol, NULL) == 0);
+
+ /* handle 2nd write failure on a message */
+ thrift_binary_protocol_read_i32 (protocol, &version, NULL);
+
+ /* handle 2nd write failure on a message */
+ thrift_binary_protocol_read_i32 (protocol, &version, NULL);
+ thrift_binary_protocol_read_string (protocol, &message_name, NULL);
+
+ g_object_unref (client);
+ // TODO: investigate g_object_unref (tbp);
+ g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+ g_type_init ();
+ test_create_and_destroy ();
+ test_initialize ();
+ test_read_and_write_primitives ();
+ test_read_and_write_complex_types ();
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testsimpleserver.c b/lib/c_glib/test/testsimpleserver.c
new file mode 100644
index 0000000..182e9ef
--- /dev/null
+++ b/lib/c_glib/test/testsimpleserver.c
@@ -0,0 +1,113 @@
+#include <assert.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "processor/thrift_processor.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_PORT 51199
+
+#include "server/thrift_simple_server.c"
+
+/* create a rudimentary processor */
+#define TEST_PROCESSOR_TYPE (test_processor_get_type ())
+
+struct _TestProcessor
+{
+ ThriftProcessor parent;
+};
+typedef struct _TestProcessor TestProcessor;
+
+struct _TestProcessorClass
+{
+ ThriftProcessorClass parent;
+};
+typedef struct _TestProcessorClass TestProcessorClass;
+
+gboolean
+test_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
+ ThriftProtocol *out)
+{
+ return FALSE;
+}
+
+static void
+test_processor_class_init (ThriftProcessorClass *proc)
+{
+ proc->process = test_processor_process;
+}
+
+GType
+test_processor_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (TestProcessorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) test_processor_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (TestProcessor),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ NULL, /* value_table */
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_PROCESSOR,
+ "TestProcessorType",
+ &info, 0);
+ }
+
+ return type;
+}
+
+static void
+test_server (void)
+{
+ int status;
+ pid_t pid;
+ TestProcessor *p = NULL;
+ ThriftServerSocket *tss = NULL;
+ ThriftSimpleServer *ss = NULL;
+
+ p = g_object_new (TEST_PROCESSOR_TYPE, NULL);
+ tss = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", TEST_PORT, NULL);
+ ss = g_object_new (THRIFT_TYPE_SIMPLE_SERVER, "processor", p,
+ "server_transport", THRIFT_SERVER_TRANSPORT (tss), NULL);
+
+ /* run the server in a child process */
+ pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0)
+ {
+ THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss));
+ exit (0);
+ } else {
+ sleep (5);
+ kill (pid, SIGINT);
+
+ g_object_unref (ss);
+ g_object_unref (tss);
+ g_object_unref (p);
+ assert (wait (&status) == pid);
+ assert (status == SIGINT);
+ }
+}
+
+int
+main (void)
+{
+ g_type_init ();
+ test_server ();
+
+ return 0;
+}
diff --git a/lib/c_glib/test/teststruct.c b/lib/c_glib/test/teststruct.c
new file mode 100644
index 0000000..cb401e2
--- /dev/null
+++ b/lib/c_glib/test/teststruct.c
@@ -0,0 +1,121 @@
+#include <assert.h>
+#include <glib-object.h>
+
+#include "../src/thrift_struct.c"
+
+/* tests to ensure we can extend a ThriftStruct */
+
+struct _ThriftTestStruct
+{
+ ThriftStruct parent;
+};
+typedef struct _ThriftTestStruct ThriftTestStruct;
+
+struct _ThriftTestStructClass
+{
+ ThriftStructClass parent;
+};
+typedef struct _ThriftTestStructClass ThriftTestStructClass;
+
+GType thrift_test_struct_get_type (void);
+
+#define THRIFT_TYPE_TEST_STRUCT (thrift_test_struct_get_type ())
+#define THRIFT_TEST_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ THRIFT_TYPE_TEST_STRUCT, \
+ ThriftTestStruct))
+#define THRIFT_TEST_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ THRIFT_TYPE_TEST_STRUCT, \
+ ThriftTestStructClass))
+#define THRIFT_IS_TEST_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ THRIFT_TYPE_TEST_STRUCT))
+#define THRIFT_IS_TEST_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ THRIFT_TYPE_TEST_STRUCT))
+#define THRIFT_TEST_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ THRIFT_TYPE_TEST_STRUCT, \
+ ThriftTestStructClass))
+
+/* test declarations */
+gint32 thrift_test_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+gint32 thrift_test_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error);
+
+static void
+thrift_test_struct_class_init (ThriftTestStructClass *cls)
+{
+ ThriftStructClass *ts_cls = THRIFT_STRUCT_CLASS (cls);
+ ts_cls->read = thrift_test_struct_read;
+ ts_cls->write = thrift_test_struct_write;
+}
+
+static void
+thrift_test_struct_instance_init (ThriftTestStruct *s)
+{
+ (void) s;
+}
+
+GType
+thrift_test_struct_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo type_info =
+ {
+ sizeof (ThriftTestStructClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) thrift_test_struct_class_init,
+ NULL,
+ NULL,
+ sizeof (ThriftTestStruct),
+ 0,
+ (GInstanceInitFunc) thrift_test_struct_instance_init,
+ NULL,
+ };
+
+ type = g_type_register_static (THRIFT_TYPE_STRUCT,
+ "ThriftTestStructType", &type_info, 0);
+ }
+
+ return type;
+}
+
+gint32
+thrift_test_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error)
+{
+ return 0;
+}
+
+gint32
+thrift_test_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+ GError **error)
+{
+ return 0;
+}
+
+
+static void
+test_initialize_object (void)
+{
+ ThriftTestStruct *t = NULL;
+
+ t = g_object_new (THRIFT_TYPE_TEST_STRUCT, NULL);
+ assert ( THRIFT_IS_STRUCT (t));
+ thrift_struct_read (THRIFT_STRUCT (t), NULL, NULL);
+ thrift_struct_write (THRIFT_STRUCT (t), NULL, NULL);
+ thrift_test_struct_read (THRIFT_STRUCT (t), NULL, NULL);
+ thrift_test_struct_write (THRIFT_STRUCT (t), NULL, NULL);
+ g_object_unref (t);
+}
+
+int
+main(void)
+{
+ g_type_init ();
+ test_initialize_object ();
+
+ return 0;
+}
diff --git a/lib/c_glib/test/testthrifttest.c b/lib/c_glib/test/testthrifttest.c
new file mode 100644
index 0000000..6020f9c
--- /dev/null
+++ b/lib/c_glib/test/testthrifttest.c
@@ -0,0 +1,28 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const int TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+static void
+thrift_server (const int port)
+{
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+
+ g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+ g_type_init ();
+ thrift_server (TEST_PORT);
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testthrifttestclient.cpp b/lib/c_glib/test/testthrifttestclient.cpp
new file mode 100644
index 0000000..4b5b841
--- /dev/null
+++ b/lib/c_glib/test/testthrifttestclient.cpp
@@ -0,0 +1,551 @@
+
+/* test a C client with a C++ server */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <protocol/TBinaryProtocol.h>
+#include <protocol/TDebugProtocol.h>
+#include <server/TSimpleServer.h>
+#include <transport/TServerSocket.h>
+#include "ThriftTest.h"
+#include "ThriftTest_types.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace boost;
+
+using namespace apache::thrift;
+using namespace apache::thrift::concurrency;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+
+using namespace thrift::test;
+
+#define TEST_PORT 9980
+
+// Extra functions required for ThriftTest_types to work
+namespace thrift { namespace test {
+
+bool Insanity::operator<(thrift::test::Insanity const& other) const {
+ using apache::thrift::ThriftDebugString;
+ return ThriftDebugString(*this) < ThriftDebugString(other);
+}
+
+}}
+
+class TestHandler : public ThriftTestIf {
+ public:
+ TestHandler() {}
+
+ void testVoid() {
+ printf("[C -> C++] testVoid()\n");
+ }
+
+ void testString(string& out, const string &thing) {
+ printf("[C -> C++] testString(\"%s\")\n", thing.c_str());
+ out = thing;
+ }
+
+ int8_t testByte(const int8_t thing) {
+ printf("[C -> C++] testByte(%d)\n", (int)thing);
+ return thing;
+ }
+ int32_t testI32(const int32_t thing) {
+ printf("[C -> C++] testI32(%d)\n", thing);
+ return thing;
+ }
+
+ int64_t testI64(const int64_t thing) {
+ printf("[C -> C++] testI64(%lld)\n", thing);
+ return thing;
+ }
+
+ double testDouble(const double thing) {
+ printf("[C -> C++] testDouble(%lf)\n", thing);
+ return thing;
+ }
+
+ void testStruct(Xtruct& out, const Xtruct &thing) {
+ printf("[C -> C++] testStruct({\"%s\", %d, %d, %lld})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing);
+ out = thing;
+ }
+
+ void testNest(Xtruct2& out, const Xtruct2& nest) {
+ const Xtruct &thing = nest.struct_thing;
+ printf("[C -> C++] testNest({%d, {\"%s\", %d, %d, %lld}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing);
+ out = nest;
+ }
+
+ void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
+ printf("[C -> C++] testMap({");
+ map<int32_t, int32_t>::const_iterator m_iter;
+ bool first = true;
+ for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
+ if (first) {
+ first = false;
+ } else {
+ printf(", ");
+ }
+ printf("%d => %d", m_iter->first, m_iter->second);
+ }
+ printf("})\n");
+ out = thing;
+ }
+
+ void testSet(set<int32_t> &out, const set<int32_t> &thing) {
+ printf("[C -> C++] testSet({");
+ set<int32_t>::const_iterator s_iter;
+ bool first = true;
+ for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
+ if (first) {
+ first = false;
+ } else {
+ printf(", ");
+ }
+ printf("%d", *s_iter);
+ }
+ printf("})\n");
+ out = thing;
+ }
+
+ void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
+ printf("[C -> C++] testList({");
+ vector<int32_t>::const_iterator l_iter;
+ bool first = true;
+ for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
+ if (first) {
+ first = false;
+ } else { printf(", ");
+ }
+ printf("%d", *l_iter);
+ }
+ printf("})\n");
+ out = thing;
+ }
+
+ Numberz::type testEnum(const Numberz::type thing) {
+ printf("[C -> C++] testEnum(%d)\n", thing);
+ return thing;
+ }
+
+ UserId testTypedef(const UserId thing) {
+ printf("[C -> C++] testTypedef(%lld)\n", thing);
+ return thing; }
+
+ void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
+ printf("[C -> C++] testMapMap(%d)\n", hello);
+
+ map<int32_t,int32_t> pos;
+ map<int32_t,int32_t> neg;
+ for (int i = 1; i < 5; i++) {
+ pos.insert(make_pair(i,i));
+ neg.insert(make_pair(-i,-i));
+ }
+
+ mapmap.insert(make_pair(4, pos));
+ mapmap.insert(make_pair(-4, neg));
+
+ }
+
+ void testInsanity(map<UserId, map<Numberz::type,Insanity> > &insane, const Insanity &argument) {
+ printf("[C -> C++] testInsanity()\n");
+
+ Xtruct hello;
+ hello.string_thing = "Hello2";
+ hello.byte_thing = 2;
+ hello.i32_thing = 2;
+ hello.i64_thing = 2;
+
+ Xtruct goodbye;
+ goodbye.string_thing = "Goodbye4";
+ goodbye.byte_thing = 4;
+ goodbye.i32_thing = 4;
+ goodbye.i64_thing = 4;
+
+ Insanity crazy;
+ crazy.userMap.insert(make_pair(Numberz::EIGHT, 8));
+ crazy.xtructs.push_back(goodbye);
+
+ Insanity looney;
+ crazy.userMap.insert(make_pair(Numberz::FIVE, 5));
+ crazy.xtructs.push_back(hello);
+
+ map<Numberz::type, Insanity> first_map;
+ map<Numberz::type, Insanity> second_map;
+
+ first_map.insert(make_pair(Numberz::TWO, crazy));
+ first_map.insert(make_pair(Numberz::THREE, crazy));
+
+ second_map.insert(make_pair(Numberz::SIX, looney));
+
+ insane.insert(make_pair(1, first_map));
+ insane.insert(make_pair(2, second_map));
+
+ printf("return");
+ printf(" = {");
+ map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
+ for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
+ printf("%lld => {", i_iter->first);
+ map<Numberz::type,Insanity>::const_iterator i2_iter;
+ for (i2_iter = i_iter->second.begin();
+ i2_iter != i_iter->second.end();
+ ++i2_iter) {
+ printf("%d => {", i2_iter->first);
+ map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
+ map<Numberz::type, UserId>::const_iterator um;
+ printf("{");
+ for (um = userMap.begin(); um != userMap.end(); ++um) {
+ printf("%d => %lld, ", um->first, um->second);
+ }
+ printf("}, ");
+
+ vector<Xtruct> xtructs = i2_iter->second.xtructs;
+ vector<Xtruct>::const_iterator x;
+ printf("{");
+ for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+ printf("{\"%s\", %d, %d, %lld}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing);
+ }
+ printf("}");
+
+ printf("}, ");
+ }
+ printf("}, ");
+ }
+ printf("}\n");
+
+
+ }
+
+ void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string> &arg3, const Numberz::type arg4, const UserId arg5) {
+ printf("[C -> C++] testMulti()\n");
+
+ hello.string_thing = "Hello2";
+ hello.byte_thing = arg0;
+ hello.i32_thing = arg1;
+ hello.i64_thing = (int64_t)arg2;
+ }
+
+ void testException(const std::string &arg)
+ throw(Xception, apache::thrift::TException)
+ {
+ printf("[C -> C++] testException(%s)\n", arg.c_str());
+ if (arg.compare("Xception") == 0) {
+ Xception e;
+ e.errorCode = 1001;
+ e.message = arg;
+ throw e;
+ } else if (arg.compare("ApplicationException") == 0) {
+ apache::thrift::TException e;
+ throw e;
+ } else {
+ Xtruct result;
+ result.string_thing = arg;
+ return;
+ }
+ }
+
+ void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
+
+ printf("[C -> C++] testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str());
+
+ if (arg0.compare("Xception") == 0) {
+ Xception e;
+ e.errorCode = 1001;
+ e.message = "This is an Xception";
+ throw e;
+ } else if (arg0.compare("Xception2") == 0) {
+ Xception2 e;
+ e.errorCode = 2002;
+ e.struct_thing.string_thing = "This is an Xception2";
+ throw e;
+ } else {
+ result.string_thing = arg1;
+ return;
+ }
+ }
+
+ void testOneway(int sleepFor) {
+ printf("testOneway(%d): Sleeping...\n", sleepFor);
+ sleep(sleepFor);
+ printf("testOneway(%d): done sleeping!\n", sleepFor);
+ }
+};
+
+// C CLIENT
+extern "C" {
+
+#include "t_test_thrift_test.h"
+#include "t_test_thrift_test_types.h"
+#include "transport/thrift_socket.h"
+#include "protocol/thrift_protocol.h"
+#include "protocol/thrift_binary_protocol.h"
+
+static void
+test_thrift_client (void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftBinaryProtocol *protocol = NULL;
+ TTestThriftTestClient *client = NULL;
+ TTestThriftTestIf *iface = NULL;
+ GError *error = NULL;
+ gchar *string = NULL;
+ gint8 byte = 0;
+ gint16 i16 = 0;
+ gint32 i32 = 0, another_i32 = 56789;
+ gint64 i64 = 0;
+ double dbl = 0.0;
+ TTestXtruct *xtruct_in, *xtruct_out;
+ TTestXtruct2 *xtruct2_in, *xtruct2_out;
+ GHashTable *map_in = NULL, *map_out = NULL;
+ GHashTable *set_in = NULL, *set_out = NULL;
+ GArray *list_in = NULL, *list_out = NULL;
+ TTestNumberz enum_in, enum_out;
+ TTestUserId user_id_in, user_id_out;
+ GHashTable *insanity_in = NULL;
+ TTestXtruct *xtruct1, *xtruct2;
+ TTestInsanity *insanity_out = NULL;
+ TTestXtruct *multi_in = NULL;
+ GHashTable *multi_map_out = NULL;
+ TTestXception *xception = NULL;
+ TTestXception2 *xception2 = NULL;
+
+ // initialize gobject
+ g_type_init ();
+
+ // create a C client
+ tsocket = (ThriftSocket *) g_object_new (THRIFT_TYPE_SOCKET,
+ "hostname", "localhost",
+ "port", TEST_PORT, NULL);
+ protocol = (ThriftBinaryProtocol *) g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+ "transport",
+ tsocket, NULL);
+ client = (TTestThriftTestClient *) g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, "input_protocol", protocol, "output_protocol", protocol, NULL);
+ iface = T_TEST_THRIFT_TEST_IF (client);
+
+ // open and send
+ thrift_transport_open (THRIFT_TRANSPORT(tsocket), NULL);
+
+ assert (t_test_thrift_test_client_test_void (iface, &error) == TRUE);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_string (iface, &string, "test123", &error) == TRUE);
+ assert (strcmp (string, "test123") == 0);
+ g_free (string);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_byte (iface, &byte, (gint8) 5, &error) == TRUE);
+ assert (byte == 5);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_i32 (iface, &i32, 123, &error) == TRUE);
+ assert (i32 == 123);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_i64 (iface, &i64, 12345, &error) == TRUE);
+ assert (i64 == 12345);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_double (iface, &dbl, 5.6, &error) == TRUE);
+ assert (dbl == 5.6);
+ assert (error == NULL);
+
+ xtruct_out = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+ xtruct_out->byte_thing = 1;
+ xtruct_out->__isset_byte_thing = TRUE;
+ xtruct_out->i32_thing = 15;
+ xtruct_out->__isset_i32_thing = TRUE;
+ xtruct_out->i64_thing = 151;
+ xtruct_out->__isset_i64_thing = TRUE;
+ xtruct_out->string_thing = g_strdup ("abc123");
+ xtruct_out->__isset_string_thing = TRUE;
+ assert (t_test_thrift_test_client_test_struct (iface, &xtruct_in, xtruct_out, &error) == TRUE);
+ assert (error == NULL);
+
+ xtruct2_out = (TTestXtruct2 *) g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
+ xtruct2_out->byte_thing = 1;
+ xtruct2_out->__isset_byte_thing = TRUE;
+ xtruct2_out->struct_thing = xtruct_out;
+ xtruct2_out->__isset_struct_thing = TRUE;
+ xtruct2_out->i32_thing = 123;
+ xtruct2_out->__isset_i32_thing = TRUE;
+ assert (t_test_thrift_test_client_test_nest (iface, &xtruct2_in, xtruct2_out, &error) == TRUE);
+ assert (error == NULL);
+
+ g_object_unref (xtruct2_out);
+ g_object_unref (xtruct2_in);
+ g_free (xtruct_out->string_thing);
+ g_object_unref (xtruct_out);
+ g_object_unref (xtruct_in);
+
+ map_out = g_hash_table_new (NULL, NULL);
+ map_in = g_hash_table_new (NULL, NULL); g_hash_table_insert (map_out, &i32, &i32);
+ assert (t_test_thrift_test_client_test_map (iface, &map_in, map_out, &error) == TRUE);
+ assert (error == NULL);
+ g_hash_table_destroy (map_out);
+ g_hash_table_destroy (map_in);
+
+ set_out = g_hash_table_new (NULL, NULL);
+ set_in = g_hash_table_new (NULL, NULL);
+ g_hash_table_insert (set_out, &i32, &i32);
+ assert (t_test_thrift_test_client_test_set (iface, &set_in, set_out, &error) == TRUE);
+ assert (error == NULL);
+ g_hash_table_destroy (set_out);
+ g_hash_table_destroy (set_in);
+
+ list_out = g_array_new(TRUE, TRUE, sizeof(gint32));
+ list_in = g_array_new(TRUE, TRUE, sizeof(gint32));
+ another_i32 = 456;
+ g_array_append_val (list_out, i32);
+ g_array_append_val (list_out, another_i32);
+ assert (t_test_thrift_test_client_test_list (iface, &list_in, list_out, &error) == TRUE);
+ assert (error == NULL);
+ g_array_free (list_out, TRUE);
+ g_array_free (list_in, TRUE);
+
+ enum_out = T_TEST_NUMBERZ_ONE;
+ assert (t_test_thrift_test_client_test_enum (iface, &enum_in, enum_out, &error) == TRUE);
+ assert (enum_in == enum_out);
+ assert (error == NULL);
+
+ user_id_out = 12345;
+ assert (t_test_thrift_test_client_test_typedef (iface, &user_id_in, user_id_out, &error) == TRUE);
+ assert (user_id_in == user_id_out);
+ assert (error == NULL);
+
+ map_in = g_hash_table_new (NULL, NULL);
+ assert (t_test_thrift_test_client_test_map_map (iface, &map_in, i32, &error) == TRUE);
+ assert (error == NULL);
+ g_hash_table_destroy (map_in);
+
+ // insanity
+ insanity_out = (TTestInsanity *) g_object_new (T_TEST_TYPE_INSANITY, NULL);
+ insanity_out->userMap = g_hash_table_new (NULL, NULL);
+ g_hash_table_insert (insanity_out->userMap, &enum_out, &user_id_out);
+
+ xtruct1 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+ xtruct1->byte_thing = 1;
+ xtruct1->__isset_byte_thing = TRUE;
+ xtruct1->i32_thing = 15;
+ xtruct1->__isset_i32_thing = TRUE;
+ xtruct1->i64_thing = 151;
+ xtruct1->__isset_i64_thing = TRUE;
+ xtruct1->string_thing = g_strdup ("abc123");
+ xtruct1->__isset_string_thing = TRUE;
+ xtruct2 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+ xtruct2->byte_thing = 1;
+ xtruct2->__isset_byte_thing = TRUE;
+ xtruct2->i32_thing = 15;
+ xtruct2->__isset_i32_thing = TRUE;
+ xtruct2->i64_thing = 151;
+ xtruct2->__isset_i64_thing = TRUE;
+ xtruct2->string_thing = g_strdup ("abc123");
+ xtruct2->__isset_string_thing = TRUE;
+
+ insanity_out->xtructs = g_ptr_array_new ();
+ insanity_in = g_hash_table_new (NULL, NULL);
+ g_ptr_array_add (insanity_out->xtructs, xtruct1);
+ g_ptr_array_add (insanity_out->xtructs, xtruct2);
+ assert (t_test_thrift_test_client_test_insanity (iface, &insanity_in, insanity_out, &error) == TRUE);
+
+ g_hash_table_unref (insanity_in);
+ g_ptr_array_free (insanity_out->xtructs, TRUE);
+ g_free (xtruct1->string_thing);
+ g_free (xtruct2->string_thing);
+ g_object_unref (xtruct1);
+ g_object_unref (xtruct2);
+
+ multi_map_out = g_hash_table_new (NULL, NULL);
+ string = g_strdup ("abc123");
+ g_hash_table_insert (multi_map_out, &i16, string);
+ assert (t_test_thrift_test_client_test_multi (iface, &multi_in, byte, i32, i64, multi_map_out, enum_out, user_id_out, &error) == TRUE);
+ assert (multi_in->i32_thing == i32);
+ assert (multi_in->i64_thing == i64);
+ g_object_unref (multi_in);
+ g_hash_table_unref (multi_map_out);
+ g_free (string);
+
+ assert (t_test_thrift_test_client_test_exception (iface, "Xception", &xception, &error) == FALSE);
+ assert (xception->errorCode == 1001);
+ g_error_free (error);
+ error = NULL;
+
+ assert (t_test_thrift_test_client_test_exception (iface, "ApplicationException", &xception, &error) == FALSE);
+ g_error_free (error);
+ error = NULL;
+ g_object_unref (xception);
+ xception = NULL;
+
+ assert (t_test_thrift_test_client_test_exception (iface, "Test", &xception, &error) == TRUE);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception", NULL, &xception, &xception2, &error) == FALSE);
+ assert (xception->errorCode == 1001);
+ g_error_free (error);
+ error = NULL;
+ g_object_unref (xception);
+ xception = NULL;
+ xception2 = NULL;
+
+ assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception2", NULL, &xception, &xception2, &error) == FALSE);
+ assert (xception2->errorCode == 2002);
+ g_error_free (error);
+ error = NULL;
+ g_object_unref (xception2);
+ xception2 = NULL;
+
+ assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, NULL , NULL, &xception, &xception2, &error) == TRUE);
+ assert (error == NULL);
+
+ assert (t_test_thrift_test_client_test_oneway (iface, 1, &error) == TRUE);
+ assert (error == NULL);
+
+ /* sleep to let the oneway call go through */
+ sleep (5);
+
+ thrift_transport_close (THRIFT_TRANSPORT(tsocket), NULL);
+ g_object_unref (client);
+ g_object_unref (protocol);
+ g_object_unref (tsocket);
+}
+
+
+} /* extern "C" */
+
+
+static void
+bailout (int signum)
+{
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ int status;
+ int pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0) /* child */
+ {
+ shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+ shared_ptr<TestHandler> testHandler(new TestHandler());
+ shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+ shared_ptr<TServerSocket> serverSocket(new TServerSocket(TEST_PORT));
+ shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+ TSimpleServer simpleServer(testProcessor, serverSocket, transportFactory, protocolFactory);
+ signal (SIGALRM, bailout);
+ alarm (60);
+ simpleServer.serve();
+ } else {
+ sleep (1);
+ test_thrift_client ();
+ kill (pid, SIGINT);
+ wait (&status) == pid;
+ }
+
+ return 0;
+}
+
diff --git a/lib/c_glib/test/testtransportsocket.c b/lib/c_glib/test/testtransportsocket.c
new file mode 100644
index 0000000..14579c8
--- /dev/null
+++ b/lib/c_glib/test/testtransportsocket.c
@@ -0,0 +1,200 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+/* substituted functions to test failures of system and library calls */
+static int socket_error = 0;
+int
+my_socket(int domain, int type, int protocol)
+{
+ if (socket_error == 0)
+ {
+ return socket (domain, type, protocol);
+ }
+ return -1;
+}
+
+static int recv_error = 0;
+ssize_t
+my_recv(int socket, void *buffer, size_t length, int flags)
+{
+ if (recv_error == 0)
+ {
+ return recv (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+static int send_error = 0;
+ssize_t
+my_send(int socket, const void *buffer, size_t length, int flags)
+{
+ if (send_error == 0)
+ {
+ return send (socket, buffer, length, flags);
+ }
+ return -1;
+}
+
+#define socket my_socket
+#define recv my_recv
+#define send my_send
+#include "../src/transport/thrift_socket.c"
+#undef socket
+#undef recv
+#undef send
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_socket_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+ gchar *hostname = NULL;
+ guint port = 0;
+
+ GObject *object = NULL;
+ object = g_object_new (THRIFT_TYPE_SOCKET, NULL);
+ assert (object != NULL);
+ g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
+ g_free (hostname);
+
+ g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ GError *err = NULL;
+
+ /* open a connection and close it */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", 51188, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ thrift_socket_open (transport, NULL);
+ assert (thrift_socket_is_open (transport) == TRUE);
+ thrift_socket_close (transport, NULL);
+ assert (thrift_socket_is_open (transport) == FALSE);
+
+ /* test close failure */
+ tsocket->sd = -1;
+ thrift_socket_close (transport, NULL);
+ g_object_unref (tsocket);
+
+ /* try a hostname lookup failure */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+ NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ assert (thrift_socket_open (transport, &err) == FALSE);
+ g_object_unref (tsocket);
+ g_error_free (err);
+ err = NULL;
+
+ /* try an error call to socket() */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ socket_error = 1;
+ assert (thrift_socket_open (transport, &err) == FALSE);
+ socket_error = 0;
+ g_object_unref (tsocket);
+ g_error_free (err);
+}
+
+static void
+test_read_and_write(void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ int port = 51199;
+ guchar buf[10] = TEST_DATA; /* a buffer */
+
+ pid = fork ();
+ assert ( pid >= 0 );
+
+ if ( pid == 0 )
+ {
+ /* child listens */
+ thrift_socket_server (port);
+ exit (0);
+ } else {
+ /* parent connects, wait a bit for the socket to be created */
+ sleep (1);
+
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ assert (thrift_socket_open (transport, NULL) == TRUE);
+ assert (thrift_socket_is_open (transport));
+ thrift_socket_write (transport, buf, 10, NULL);
+
+ /* write fail */
+ send_error = 1;
+ thrift_socket_write (transport, buf, 1, NULL);
+ send_error = 0;
+
+ thrift_socket_write_end (transport, NULL);
+ thrift_socket_flush (transport, NULL);
+ thrift_socket_close (transport, NULL);
+ g_object_unref (tsocket);
+
+ assert ( wait (&status) == pid );
+ assert ( status == 0 );
+ }
+}
+
+static void
+thrift_socket_server (const int port)
+{
+ int bytes = 0;
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ guchar buf[10]; /* a buffer */
+ guchar match[10] = TEST_DATA;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ /* read 10 bytes */
+ bytes = thrift_socket_read (client, buf, 10, NULL);
+ assert (bytes == 10); /* make sure we've read 10 bytes */
+ assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
+
+ /* failed read */
+ recv_error = 1;
+ thrift_socket_read (client, buf, 1, NULL);
+ recv_error = 0;
+
+ thrift_socket_read_end (client, NULL);
+ thrift_socket_close (client, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (client);
+}
+
+int
+main(void)
+{
+ g_type_init();
+ test_create_and_destroy();
+ test_open_and_close();
+ test_read_and_write();
+
+ return 0;
+}
+
diff --git a/lib/c_glib/thrift_c_glib.pc.in b/lib/c_glib/thrift_c_glib.pc.in
new file mode 100644
index 0000000..44675df
--- /dev/null
+++ b/lib/c_glib/thrift_c_glib.pc.in
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Thrift
+Description: Thrift C API
+Version: @VERSION@
+Libs: -L${libdir} -lthriftc
+Cflags: -I${includedir}/thrift