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/.gitignore b/.gitignore
index 5aed523..7a39712 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,25 @@
 /lib/cpp/*.la
 /lib/cpp/*.lo
 /lib/cpp/*.pc
+/lib/c_glib/*.gcda
+/lib/c_glib/*.gcno
+/lib/c_glib/*.la
+/lib/c_glib/*.lo
+/lib/c_glib/*.loT
+/lib/c_glib/*.o
+/lib/c_glib/.deps
+/lib/c_glib/.libs
+/lib/c_glib/Makefile.in
+/lib/c_glib/Makefile
+/lib/c_glib/thriftc.pc
+/lib/c_glib/test/*.o
+/lib/c_glib/test/*.lo
+/lib/c_glib/test/testwrapper.sh
+/lib/c_glib/test/testwrapper-test*
+/lib/c_glib/test/.deps
+/lib/c_glib/test/.libs
+/lib/c_glib/test/gen-cpp/
+/lib/c_glib/test/gen-c_glib
 /lib/csharp/Makefile
 /lib/csharp/Makefile.in
 /lib/hs/dist
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 6902ba4..ac69b34 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -60,6 +60,9 @@
                  src/generate/t_generator.h \
                  src/generate/t_oop_generator.h
 
+if THRIFT_GEN_c_glib
+thrift_SOURCES += src/generate/t_c_glib_generator.cc
+endif
 if THRIFT_GEN_cpp
 thrift_SOURCES += src/generate/t_cpp_generator.cc
 endif
diff --git a/compiler/cpp/src/generate/t_c_glib_generator.cc b/compiler/cpp/src/generate/t_c_glib_generator.cc
new file mode 100644
index 0000000..223d489
--- /dev/null
+++ b/compiler/cpp/src/generate/t_c_glib_generator.cc
@@ -0,0 +1,2986 @@
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+
+using namespace std;
+
+/* forward declarations */
+string initial_caps_to_underscores (string name);
+string to_upper_case (string name);
+string to_lower_case (string name);
+
+/**
+ * C code generator, using glib for C typing.
+ */
+class t_c_glib_generator : public t_oop_generator
+{
+ public:
+
+  /* constructor */
+  t_c_glib_generator (t_program *program,
+                      const map<string, string> &parsed_options,
+                      const string &option_string) : t_oop_generator (program)
+  {
+    /* set the output directory */
+    this->out_dir_base_ = "gen-c_glib";
+
+    /* set the namespace */
+    this->nspace = program_->get_namespace ("c_glib");
+
+    if (this->nspace.empty())
+    {
+      this->nspace = "";
+      this->nspace_u = "";
+      this->nspace_uc = "";
+      this->nspace_lc = "";
+    } else {
+      /* replace dots with underscores */
+      char *tmp = strdup (this->nspace.c_str ());
+      for (unsigned int i = 0; i < strlen (tmp); i++)
+      {
+        if (tmp[i] == '.')
+        {
+          tmp[i] = '_';
+        }
+      }
+      this->nspace = string (tmp, strlen (tmp));
+      free (tmp);
+
+      /* clean up the namespace for C.
+       * An input of 'namespace foo' should result in:
+       *  - nspace = foo       - for thrift objects and typedefs
+       *  - nspace_u = Foo     - for internal GObject prefixes
+       *  - nspace_uc = FOO_   - for macro prefixes
+       *  - nspace_lc = foo_   - for filename and method prefixes
+       * The underscores are there since uc and lc strings are used as file and
+       * variable prefixes.
+       */
+      this->nspace_u = initial_caps_to_underscores (this->nspace);
+      this->nspace_uc = to_upper_case (this->nspace_u) + "_";
+      this->nspace_lc = to_lower_case (this->nspace_u) + "_";
+    }
+  }
+
+  /* initialization and destruction */
+  void init_generator ();
+  void close_generator ();
+
+  /* generation functions */
+  void generate_typedef (t_typedef *ttypedef);
+  void generate_enum (t_enum *tenum);
+  void generate_consts (vector<t_const *> consts);
+  void generate_struct (t_struct *tstruct);
+  void generate_service (t_service *tservice);
+  void generate_xception (t_struct *tstruct);
+
+ private:
+
+  /* file streams */
+  ofstream f_types_;
+  ofstream f_types_impl_;
+  ofstream f_header_;
+  ofstream f_service_;
+
+  /* namespace variables */
+  string nspace;
+  string nspace_u;
+  string nspace_uc;
+  string nspace_lc;
+
+  /* helper functions */
+  bool is_complex_type (t_type *ttype);
+  string type_name (t_type* ttype, bool in_typedef=false,
+                    bool is_const=false); 
+  string base_type_name (t_base_type *type);
+  string type_to_enum (t_type *type);
+  string constant_value (string name, t_type *type, t_const_value *value);
+  string function_signature (t_function *tfunction);
+  string argument_list (t_struct *tstruct);
+  string xception_list (t_struct *tstruct);
+  string declare_field (t_field *tfield, bool init=false, bool pointer=false,
+                        bool constant=false, bool reference=false);
+
+  /* generation functions */
+  void generate_const_initializer (string name, t_type *type,
+                                   t_const_value *value);
+  void generate_service_client (t_service *tservice);
+  void generate_service_server (t_service *tservice);
+  void generate_object (t_struct *tstruct);
+  void generate_struct_writer (ofstream &out, t_struct *tstruct,
+                               string this_name, string this_get="",
+                               bool is_function=true);
+  void generate_struct_reader (ofstream &out, t_struct *tstruct,
+                               string this_name, string this_get="",
+                               bool is_function=true);
+
+  void generate_serialize_field (ofstream &out, t_field *tfield,
+                                 string prefix, string suffix,
+                                 int error_ret);
+  void generate_serialize_struct (ofstream &out, t_struct *tstruct,
+                                  string prefix, int error_ret);
+  void generate_serialize_container (ofstream &out, t_type *ttype,
+                                     string prefix, int error_ret);
+  void generate_serialize_map_element (ofstream &out, t_map *tmap, string key,
+                                       string value, int error_ret);
+  void generate_serialize_set_element (ofstream &out, t_set *tset,
+                                       string element, int error_ret);
+  void generate_serialize_list_element (ofstream &out, t_list *tlist,
+                                        string list, string index,
+                                        int error_ret);
+
+  void generate_deserialize_field (ofstream &out, t_field *tfield,
+                                   string prefix, string suffix,
+                                   int error_ret);
+  void generate_deserialize_struct (ofstream &out, t_struct *tstruct,
+                                    string prefix, int error_ret);
+  void generate_deserialize_container (ofstream &out, t_type *ttype,
+                                       string prefix, int error_ret);
+  void generate_deserialize_map_element (ofstream &out, t_map *tmap,
+                                         string prefix, int error_ret);
+  void generate_deserialize_set_element (ofstream &out, t_set *tset,
+                                         string prefix, int error_ret);
+  void generate_deserialize_list_element (ofstream &out, t_list *tlist,
+                                          string prefix, string index,
+                                          int error_ret);
+
+  string generate_new_hash_from_type (t_type * ttype);
+  string generate_new_array_from_type(t_type * ttype); 
+};
+
+/**
+ * Prepare for file generation by opening up the necessary file
+ * output streams.
+ */
+void
+t_c_glib_generator::init_generator ()
+{
+  /* create output directory */
+  MKDIR (get_out_dir ().c_str ());
+
+  string program_name_u = initial_caps_to_underscores (program_name_);
+  string program_name_uc = to_upper_case (program_name_u);
+  string program_name_lc = to_lower_case (program_name_u);
+
+  /* create output files */
+  string f_types_name = get_out_dir () + this->nspace_lc 
+                        + program_name_lc + "_types.h";
+  f_types_.open (f_types_name.c_str ());
+  string f_types_impl_name = get_out_dir () + this->nspace_lc
+                             + program_name_lc + "_types.c";
+  f_types_impl_.open (f_types_impl_name.c_str ());
+
+  /* add thrift boilerplate headers */
+  f_types_ << autogen_comment ();
+  f_types_impl_ << autogen_comment ();
+
+  /* include inclusion guard */
+  f_types_ << 
+    "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl <<
+    "#define " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl <<
+    endl;
+
+  /* include base types */
+  f_types_ <<
+    "/* base includes */" << endl <<
+    "#include <glib-object.h>" << endl <<
+    "#include <thrift_struct.h>" << endl <<
+    "#include <protocol/thrift_protocol.h>" << endl;
+
+  /* include other thrift includes */
+  const vector<t_program *> &includes = program_->get_includes ();
+  for (size_t i = 0; i < includes.size (); ++i)
+  {
+    f_types_ <<
+      "/* other thrift includes */" << endl <<
+      "#include \"" << this->nspace_lc << includes[i]->get_name () << 
+          "_types.h\"" << endl;
+  }
+  f_types_ << endl;
+
+  /* include custom headers */
+  const vector<string> &c_includes = program_->get_c_includes ();
+  f_types_ << "/* custom thrift includes */" << endl;
+  for (size_t i = 0; i < c_includes.size (); ++i)
+  {
+    if (c_includes[i][0] == '<')
+    {
+      f_types_ <<
+        "#include " << c_includes[i] << endl;
+    } else {
+      f_types_ <<
+        "#include \"" << c_includes[i] << "\"" << endl;
+    }
+  }
+  f_types_ << endl;
+
+  // include the types file
+  f_types_impl_ <<
+    endl <<
+    "#include \"" << this->nspace_lc << program_name_u << 
+        "_types.h\"" << endl <<
+    "#include <thrift.h>" << endl <<
+    endl;
+
+  f_types_ <<
+    "/* begin types */" << endl << endl;
+}
+
+/**
+ *  Finish up generation and close all file streams.
+ */
+void
+t_c_glib_generator::close_generator ()
+{
+  string program_name_uc = to_upper_case 
+    (initial_caps_to_underscores (program_name_));
+
+  /* end the header inclusion guard */
+  f_types_ <<
+    "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl;
+
+  /* close output file */
+  f_types_.close ();
+  f_types_impl_.close ();
+}
+
+/**
+ * Generates a Thrift typedef in C code.  For example:
+ * 
+ * Thrift: 
+ * typedef map<i32,i32> SomeMap
+ * 
+ * C: 
+ * typedef GHashTable * ThriftSomeMap;
+ */
+void
+t_c_glib_generator::generate_typedef (t_typedef* ttypedef)
+{
+  f_types_ <<
+    indent() << "typedef " << type_name (ttypedef->get_type (), true) <<
+        " " << this->nspace << ttypedef->get_symbolic () << ";" << endl <<
+    endl;
+} 
+
+/**
+ * Generates a C enumeration.  For example:
+ *
+ * Thrift:
+ * enum MyEnum {
+ *   ONE = 1,
+ *   TWO
+ * }
+ *
+ * C:
+ * enum _ThriftMyEnum {
+ *   THRIFT_MY_ENUM_ONE = 1,
+ *   THRIFT_MY_ENUM_TWO
+ * };
+ * typedef enum _ThriftMyEnum ThriftMyEnum;
+ */
+void
+t_c_glib_generator::generate_enum (t_enum *tenum)
+{
+  string name = tenum->get_name ();
+  string name_uc = to_upper_case (initial_caps_to_underscores (name));
+
+  f_types_ <<
+    indent () << "enum _" << this->nspace << name << " {" << endl;
+
+  indent_up ();
+
+  vector<t_enum_value *> constants = tenum->get_constants ();
+  vector<t_enum_value *>::iterator c_iter;
+  bool first = true;
+
+  /* output each of the enumeration elements */
+  for (c_iter = constants.begin (); c_iter != constants.end (); ++c_iter)
+  {
+    if (first)
+    {
+      first = false;
+    } else {
+      f_types_ << "," << endl;
+    }
+
+    f_types_ <<
+      indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name ();
+    if ((*c_iter)->has_value ())
+    {
+      f_types_ <<
+        " = " << (*c_iter)->get_value ();
+    }
+  }
+
+  indent_down ();
+  f_types_ <<
+    endl <<
+    "};" << endl <<
+    "typedef enum _" << this->nspace << name << " " << this->nspace << name << ";" << endl <<
+    endl;
+}
+
+/**
+ * Generates Thrift constants in C code.
+ */
+void
+t_c_glib_generator::generate_consts (vector<t_const *> consts)
+{
+  f_types_ << "/* constants */" << endl;
+  f_types_impl_ << "/* constants */" << endl;
+
+  vector<t_const *>::iterator c_iter;
+  for (c_iter = consts.begin (); c_iter != consts.end (); ++c_iter)
+  {
+    string name = (*c_iter)->get_name ();
+    string name_uc = to_upper_case (name);
+    string name_lc = to_lower_case (name);
+    t_type *type = (*c_iter)->get_type ();
+    t_const_value *value = (*c_iter)->get_value ();
+
+    f_types_ <<
+      indent () << "#define " << this->nspace_uc << name_uc << " " <<
+          constant_value (name_lc, type, value) << endl;
+
+    generate_const_initializer (name_lc, type, value);
+  }
+
+  f_types_ << endl;
+  f_types_impl_ << endl;
+}
+
+/**
+ * Generate Thrift structs in C code, as GObjects.  Example:
+ *
+ * Thrift:
+ * struct Bonk
+ * {
+ *   1: string message,
+ *   2: i32 type
+ * }
+ *
+ * C GObject instance header:
+ * struct _ThriftBonk
+ * {
+ *   GObject parent;
+ *
+ *   gchar * message;
+ *   gint32 type;
+ * };
+ * typedef struct _ThriftBonk ThriftBonk
+ * // ... additional GObject boilerplate ...
+ */
+void
+t_c_glib_generator::generate_struct (t_struct *tstruct)
+{
+  f_types_ << "/* struct " << tstruct->get_name () << " */" << endl;
+  generate_object (tstruct);
+}
+
+/**
+ * Generate C code to represent Thrift services.  Creates a new GObject
+ * which can be used to access the service.
+ */
+void
+t_c_glib_generator::generate_service (t_service *tservice)
+{
+  string svcname_u = initial_caps_to_underscores (tservice->get_name ());
+  string svcname_uc = this->nspace_uc + to_upper_case (svcname_u);
+  string filename = this->nspace_lc + to_lower_case (svcname_u);
+
+  // make output files
+  string f_header_name = get_out_dir () + filename + ".h";
+  f_header_.open (f_header_name.c_str ());
+
+  string program_name_u = initial_caps_to_underscores (program_name_);
+  string program_name_lc = to_lower_case (program_name_u);
+
+  // add header file boilerplate
+  f_header_ <<
+    autogen_comment ();
+
+  // add an inclusion guard
+  f_header_ <<
+    "#ifndef " << svcname_uc << "_H" << endl <<
+    "#define " << svcname_uc << "_H" << endl <<
+    endl;
+
+  // add standard includes
+  f_header_ <<
+    "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl;
+
+  // if we are inheriting from another service, include its header
+  t_service *extends_service = tservice->get_extends ();
+  if (extends_service != NULL)
+  {
+    f_header_ <<
+      "#include \"" << this->nspace_lc << to_lower_case (initial_caps_to_underscores (extends_service->get_name ())) << ".h\"" << endl;
+  }
+  f_header_ << endl;
+
+  // create the service implementation
+  string f_service_name = get_out_dir () + filename + ".c";
+  f_service_.open (f_service_name.c_str ());
+
+  // add the boilerplace header
+  f_service_ <<
+    autogen_comment();
+
+  // include the headers
+  f_service_ <<
+    "#include <string.h>" << endl <<
+    "#include <thrift.h>" << endl <<
+    "#include <thrift_application_exception.h>" << endl <<
+    "#include \"" << filename << ".h\"" << endl <<
+    endl;
+
+  // generate the client objects
+  generate_service_client (tservice);
+
+  // generate the server objects
+  generate_service_server (tservice);
+
+  // end the header inclusion guard
+  f_header_ <<
+    "#endif /* " << svcname_uc << "_H */" << endl;
+
+  // close the files
+  f_service_.close ();
+  f_header_.close ();
+}
+
+/**
+ *
+ */
+void
+t_c_glib_generator::generate_xception (t_struct *tstruct)
+{
+  string name = tstruct->get_name ();
+  string name_u = initial_caps_to_underscores (name);
+  string name_lc = to_lower_case (name_u);
+  string name_uc = to_upper_case (name_u);
+
+  generate_object (tstruct);
+
+  f_types_ << "/* exception */" << endl <<
+    "typedef enum" << endl <<
+    "{" << endl <<
+    "  " << this->nspace_uc << name_uc << "_ERROR_CODE," << endl <<
+    "} " << this->nspace << name << "Error;" << endl <<
+    endl <<
+    "GQuark " << this->nspace_lc << name_lc << "_error_quark (void);" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_ERROR (" <<
+      this->nspace_lc << name_lc << "_error_quark ())" << endl <<
+    endl <<
+    endl;
+
+  f_types_impl_ <<
+    "/* define the GError domain for exceptions */" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" <<
+        this->nspace_lc << name_lc << "_error_quark\"" << endl <<
+    "GQuark" << endl <<
+    this->nspace_lc << name_lc << "_error_quark (void)" << endl <<
+    "{" << endl <<
+    "  return g_quark_from_static_string (" << this->nspace_uc << name_uc <<
+        "_ERROR_DOMAIN);" << endl <<
+    "}" << endl <<
+    endl;
+}
+
+/********************
+ * HELPER FUNCTIONS *
+ ********************/
+
+/**
+ * Returns true if ttype is not a primitive.
+ */
+bool
+t_c_glib_generator::is_complex_type (t_type *ttype)
+{
+  ttype = get_true_type (ttype);
+
+  return ttype->is_container ()
+         || ttype->is_struct ()
+         || ttype->is_xception ()
+         || (ttype->is_base_type ()
+             && (((t_base_type *) ttype)->get_base()
+                  == t_base_type::TYPE_STRING));
+}
+
+
+/**
+ * Maps a Thrift t_type to a C type.
+ */
+string
+t_c_glib_generator::type_name (t_type* ttype, bool in_typedef, bool is_const)
+{
+  if (ttype->is_base_type ())
+  {
+    string bname = base_type_name ((t_base_type *) ttype);
+
+    if (is_const)
+    {
+      return "const " + bname;
+    } else {
+      return bname;
+    }
+  }
+
+  if (ttype->is_container ())
+  {
+    string cname;
+
+    t_container *tcontainer = (t_container *) ttype;
+    if (tcontainer->has_cpp_name ())
+    {
+      cname = tcontainer->get_cpp_name ();
+    } else if (ttype->is_map ()) {
+      cname = "GHashTable *";
+    } else if (ttype->is_set ()) {
+      // since a set requires unique elements, use a GHashTable, and
+      // populate the keys and values with the same data, using keys for
+      // the actual writes and reads.
+      // TODO: discuss whether or not to implement TSet, THashSet or GHashSet
+      cname = "GHashTable *";
+    } else if (ttype->is_list ()) {
+      // TODO: investigate other implementations besides GPtrArray
+      cname = "GPtrArray *";
+      t_type *etype = ((t_list *) ttype)->get_elem_type ();
+      if (etype->is_base_type ())
+      {
+        t_base_type::t_base tbase = ((t_base_type *) etype)->get_base ();
+        switch (tbase)
+        {
+          case t_base_type::TYPE_VOID:
+            throw "compiler error: cannot determine array type";
+          case t_base_type::TYPE_BOOL:
+          case t_base_type::TYPE_BYTE:
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+          case t_base_type::TYPE_I64:
+          case t_base_type::TYPE_DOUBLE:
+            cname = "GArray *";
+            break;
+          case t_base_type::TYPE_STRING:
+            break;
+          default:
+            throw "compiler error: no array info for type";
+        }
+      }
+    }
+
+    if (is_const)
+    {
+      return "const " + cname;
+    } else {
+      return cname;
+    }
+  }
+
+  // check for a namespace
+  string pname = this->nspace + ttype->get_name ();
+
+  if (is_complex_type (ttype))
+  {
+    pname += " *";
+  }
+
+  if (is_const)
+  {
+    return "const " + pname;
+  } else {
+    return pname;
+  }
+}
+
+/**
+ * Maps a Thrift primitive to a C primitive.
+ */
+string
+t_c_glib_generator::base_type_name (t_base_type *type)
+{
+  t_base_type::t_base tbase = type->get_base ();
+
+  switch (tbase)
+  {
+    case t_base_type::TYPE_VOID:
+      return "void";
+    case t_base_type::TYPE_STRING:
+      if (type->is_binary ())
+      {
+        return "GByteArray *";
+      } else {
+        return "gchar *";
+      }
+    case t_base_type::TYPE_BOOL:
+      return "gboolean";
+    case t_base_type::TYPE_BYTE:
+      return "gint8";
+    case t_base_type::TYPE_I16:
+      return "gint16";
+    case t_base_type::TYPE_I32:
+      return "gint32";
+    case t_base_type::TYPE_I64:
+      return "gint64";
+    case t_base_type::TYPE_DOUBLE:
+      return "gdouble";
+    default:
+      throw "compiler error: no C base type name for base type "
+            + t_base_type::t_base_name (tbase);
+  }
+}
+
+/**
+ * Returns a member of the ThriftType C enumeration in thrift_protocol.h
+ * for a Thrift type.
+ */
+string
+t_c_glib_generator::type_to_enum (t_type *type)
+{
+  type = get_true_type (type);
+
+  if (type->is_base_type ())
+  {
+    t_base_type::t_base tbase = ((t_base_type *) type)->get_base ();
+
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        return "T_STRING";
+      case t_base_type::TYPE_BOOL:
+        return "T_BOOL";
+      case t_base_type::TYPE_BYTE:
+        return "T_BYTE";
+      case t_base_type::TYPE_I16:
+        return "T_I16";
+      case t_base_type::TYPE_I32:
+        return "T_I32";
+      case t_base_type::TYPE_I64:
+        return "T_I64";
+      case t_base_type::TYPE_DOUBLE:
+        return "T_DOUBLE";
+    }
+  } else if (type->is_enum ()) {
+    return "T_I32";
+  } else if (type->is_struct ()) {
+    return "T_STRUCT";
+  } else if (type->is_xception ()) {
+    return "T_STRUCT";
+  } else if (type->is_map ()) {
+    return "T_MAP";
+  } else if (type->is_set ()) {
+    return "T_SET";
+  } else if (type->is_list ()) {
+    return "T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name ();
+}
+
+
+/**
+ * Returns C code that represents a Thrift constant.
+ */
+string
+t_c_glib_generator::constant_value (string name, t_type *type, t_const_value *value)
+{
+  ostringstream render;
+
+  if (type->is_base_type ())
+  {
+    /* primitives */
+    t_base_type::t_base tbase = ((t_base_type *) type)->get_base ();
+    switch (tbase)
+    {
+      case t_base_type::TYPE_STRING:
+        render << "\"" + value->get_string () + "\"";
+        break;
+      case t_base_type::TYPE_BOOL:
+        render << ((value->get_integer () != 0) ? 1 : 0);
+        break;
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        render << value->get_integer ();
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        if (value->get_type () == t_const_value::CV_INTEGER)
+        {
+          render << value->get_integer ();
+        } else {
+          render << value->get_double ();
+        }
+        break;
+      default:
+        throw "compiler error: no const of base type "
+              + t_base_type::t_base_name (tbase);
+    }
+  } else if (type->is_enum ()) {
+    render << "(" << type_name (type) << ")" << value->get_integer ();
+  } else if (type->is_struct () || type->is_xception () || type->is_list ()
+             || type->is_set () || type->is_map ()) {
+    render << "(" << this->nspace_lc <<
+      to_lower_case (name) << "_constant ())";
+  } else {
+    render << "NULL /* not supported */";
+  }
+
+  return render.str ();
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string
+t_c_glib_generator::function_signature (t_function* tfunction)
+{
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* arglist = tfunction->get_arglist();
+  t_struct* xlist = tfunction->get_xceptions();
+  string fname = initial_caps_to_underscores(tfunction->get_name());
+
+  bool has_return = !ttype->is_void();
+  bool has_args = arglist->get_members().size() == 0;
+  bool has_xceptions = xlist->get_members().size() == 0;
+  return
+    "gboolean " + this->nspace_lc + fname + " (" + this->nspace
+    + service_name_ + "If * iface"
+    + (has_return ? ", " + type_name(ttype) + "* _return" : "")
+    + (has_args ? "" : (", " + argument_list (arglist))) 
+    + (has_xceptions ? "" : (", " + xception_list (xlist)))
+    + ", GError ** error)";
+}
+
+/**
+ * Renders a field list
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string
+t_c_glib_generator::argument_list (t_struct* tstruct) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type(), false, true) + " " +
+              (*f_iter)->get_name ();
+  }
+  return result;
+}
+
+/**
+ * Renders mutable exception lists
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string
+t_c_glib_generator::xception_list (t_struct* tstruct) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type(), false, false) + "* " +
+              (*f_iter)->get_name ();
+  }
+  return result;
+}
+
+
+/**
+ * Declares a field, including any necessary initialization.
+ */
+string
+t_c_glib_generator::declare_field (t_field *tfield, bool init, bool pointer,
+                              bool constant, bool reference)
+{
+  string result = "";
+  if (constant)
+  {
+    result += "const ";
+  }
+  result += type_name(tfield->get_type());
+  if (pointer)
+  {
+    result += "*";
+  }
+  if (reference)
+  {
+    result += "*";
+  }
+  result += " " + tfield->get_name();
+  if (init)
+  {
+    t_type* type = get_true_type(tfield->get_type());
+
+    if (type->is_base_type ())
+    {
+      t_base_type::t_base tbase = ((t_base_type *) type)->get_base();
+      switch (tbase)
+      {
+        case t_base_type::TYPE_VOID:
+          break;
+        case t_base_type::TYPE_BOOL:
+        case t_base_type::TYPE_BYTE:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+          result += " = 0";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          result += " = (gdouble) 0";
+          break;
+        case t_base_type::TYPE_STRING:
+          result += " = NULL";
+          break;
+        default:
+          throw "compiler error: no C intializer for base type "
+                + t_base_type::t_base_name (tbase);
+      }
+    } else if (type->is_enum ()) {
+      result += " = (" + type_name (type) + ") 0";
+    }
+  }
+
+  if (!reference)
+  {
+    result += ";";
+  }
+
+  return result;
+}
+
+/**
+ * Generates C code that initializes complex constants.
+ */
+void
+t_c_glib_generator::generate_const_initializer (string name, t_type *type,
+                                           t_const_value *value)
+{
+  string name_u = initial_caps_to_underscores (name);
+  string name_lc = to_lower_case (name_u);
+  string type_u = initial_caps_to_underscores (type->get_name ());
+  string type_uc = to_upper_case (type_u);
+
+  if (type->is_struct () || type->is_xception ()) {
+    const vector<t_field *> &fields = ((t_struct *) type)->get_members ();
+    vector<t_field *>::const_iterator f_iter;
+    const map<t_const_value *, t_const_value *> &val = value->get_map ();
+    map<t_const_value *, t_const_value *>::const_iterator v_iter;
+    ostringstream initializers;
+
+    // initialize any constants that may be referenced by this initializer
+    for (v_iter = val.begin (); v_iter != val.end (); ++v_iter)
+    {
+      t_type *field_type = NULL;
+      string field_name = "";
+
+      for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter)
+      {
+        if ((*f_iter)->get_name() == v_iter->first->get_string())
+        {
+          field_type = (*f_iter)->get_type ();
+          field_name = (*f_iter)->get_name ();
+        }
+      }
+      if (field_type == NULL)
+      {
+        throw "type error: " + type->get_name () + " has no field "
+              + v_iter->first->get_string();
+      }
+      field_name = tmp (field_name);
+
+      generate_const_initializer (name + "_constant_" + field_name,
+                                  field_type, v_iter->second);
+      initializers <<
+        "    constant->" << v_iter->first->get_string () << " = " <<
+        constant_value (name + "_constant_" + field_name,
+                        field_type, v_iter->second) << ";" << endl <<
+        "    constant->__isset_" << v_iter->first->get_string () <<
+        " = TRUE;" << endl;
+    }
+
+    // implement the initializer
+    f_types_impl_ <<
+      "static " << this->nspace << type->get_name () << " *" << endl <<
+      this->nspace_lc << name_lc << "_constant (void)" << endl <<
+      "{" << endl <<
+      "  static " << this->nspace << type->get_name () <<
+          " *constant = NULL;" << endl <<
+      "  if (constant == NULL)" << endl <<
+      "  {" << endl <<
+      "    constant = g_object_new (" << this->nspace_uc << "TYPE_" <<
+          type_uc << ", NULL);" << endl <<
+      initializers.str () << endl <<
+      "  }" << endl <<
+      "  return constant;" << endl <<
+      "}" << endl <<
+      endl;
+  } else if (type->is_list ()) {
+    string list_type = "GPtrArray *";
+    string list_initializer = "g_ptr_array_new ()";
+    string list_appender = "g_ptr_array_add";
+    bool list_variable = false;
+
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    ostringstream initializers;
+
+    if (etype->is_base_type ())
+    {
+      t_base_type::t_base tbase = ((t_base_type *) etype)->get_base ();
+      switch (tbase)
+      {
+        case t_base_type::TYPE_VOID:
+          throw "compiler error: cannot determine array type";
+        case t_base_type::TYPE_BOOL:
+        case t_base_type::TYPE_BYTE:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+        case t_base_type::TYPE_DOUBLE:
+          list_type = "GArray *";
+          list_initializer = generate_new_array_from_type (etype);
+          list_appender = "g_array_append_val";
+          list_variable = true;
+          break;
+        case t_base_type::TYPE_STRING:
+          break;
+        default:
+          throw "compiler error: no array info for type";
+      }
+    }
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
+    {
+      string fname = tmp (name);
+
+      generate_const_initializer (fname, etype, (*v_iter));
+      if (list_variable)
+      {
+        initializers <<
+          "    " << type_name (etype) << " " << fname << " = " <<
+            constant_value (fname, (t_type *) etype, (*v_iter)) << ";" <<
+                endl <<
+          "    " << list_appender << "(constant, " << fname << ");" << endl;
+      } else {
+        initializers <<
+          "    " << list_appender << "(constant, " <<
+          constant_value (fname, (t_type *) etype, (*v_iter)) << ");" << endl;
+      }
+    }
+
+    f_types_impl_ <<
+      "static " << list_type << endl <<
+      this->nspace_lc << name_lc << "_constant (void)" << endl <<
+      "{" << endl <<
+      "  static " << list_type << " constant = NULL;" << endl <<
+      "  if (constant == NULL)" << endl <<
+      "  {" << endl <<
+      "    constant = " << list_initializer << ";" << endl <<
+      initializers.str () << endl <<
+      "  }" << endl <<
+      "  return constant;" << endl <<
+      "}" << endl <<
+    endl;
+  } else if (type->is_set ()) {
+    t_type *etype = ((t_set *) type)->get_elem_type ();
+    const vector<t_const_value *>& val = value->get_list ();
+    vector<t_const_value*>::const_iterator v_iter;
+    ostringstream initializers;
+
+    for (v_iter = val.begin (); v_iter != val.end (); ++v_iter)
+    {
+      string fname = tmp (name);
+      generate_const_initializer (fname, etype, (*v_iter));
+      initializers <<
+        "    " << type_name (etype) << " " << fname << " = " <<
+          constant_value (fname, (t_type *) etype, (*v_iter)) << ";" << endl <<
+        "    g_hash_table_insert (constant, &" << fname << ", &" << fname <<
+        ");" << endl;
+    }
+
+    f_types_impl_ <<
+      "static GHashTable *" << endl <<
+      this->nspace_lc << name_lc << "_constant (void)" << endl <<
+      "{" << endl <<
+      "  static GHashTable *constant = NULL;" << endl <<
+      "  if (constant == NULL)" << endl <<
+      "  {" << endl <<
+      "    constant = g_hash_table_new (NULL, NULL);" << endl <<
+      initializers.str () << endl <<
+      "  }" << endl <<
+      "  return constant;" << endl <<
+      "}" << endl <<
+    endl; 
+  } else if (type->is_map ()) {
+    t_type *ktype = ((t_map *) type)->get_key_type ();
+    t_type *vtype = ((t_map *) type)->get_val_type ();
+    const vector<t_const_value *>& val = value->get_list ();
+    vector<t_const_value*>::const_iterator v_iter;
+    ostringstream initializers;
+
+    for (v_iter = val.begin (); v_iter != val.end (); ++v_iter)
+    {
+      string fname = tmp (name);
+      string kname = fname + "key";
+      string vname = fname + "val";
+      generate_const_initializer (kname, ktype, (*v_iter));
+      generate_const_initializer (vname, vtype, (*v_iter));
+
+      initializers <<
+        "    " << type_name (ktype) << " " << kname << " = " <<
+          constant_value (kname, (t_type *) ktype, (*v_iter)) << ";" << endl <<
+        "    " << type_name (vtype) << " " << vname << " = " <<
+          constant_value (vname, (t_type *) vtype, (*v_iter)) << ";" << endl <<
+        "    g_hash_table_insert (constant, &" << fname << ", &" << fname <<
+        ");" << endl;
+    }
+
+    f_types_impl_ <<
+      "static GHashTable *" << endl <<
+      this->nspace_lc << name_lc << "_constant (void)" << endl <<
+      "{" << endl <<
+      "  static GHashTable *constant = NULL;" << endl <<
+      "  if (constant == NULL)" << endl <<
+      "  {" << endl <<
+      "    constant = g_hash_table_new (NULL, NULL);" << endl <<
+      initializers.str () << endl <<
+      "  }" << endl <<
+      "  return constant;" << endl <<
+      "}" << endl <<
+    endl;
+  }
+}
+
+/**
+ * Generates C code that represents a Thrift service client.
+ */
+void
+t_c_glib_generator::generate_service_client (t_service *tservice)
+{
+  /* get some C friendly service names */
+  string service_name_lc = to_lower_case (initial_caps_to_underscores (service_name_));
+  string service_name_uc = to_upper_case (service_name_lc);
+
+  // Generate the client interface dummy object in the header.
+  f_header_ <<
+    "/* " << service_name_ << " service interface */" << endl <<
+    "typedef struct _" << this->nspace << service_name_ << "If " <<
+        this->nspace << service_name_ << "If; " <<
+        " /* dummy object */" << endl <<
+    endl;
+
+  // Generate the client interface object in the header.
+  f_header_ <<
+    "struct _" << this->nspace << service_name_ << "IfInterface" << endl <<
+    "{" << endl <<
+    "  GTypeInterface parent;" << endl <<
+  endl;
+
+  /* write out the functions for this interface */
+  indent_up ();
+  vector<t_function*> functions = tservice->get_functions ();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores ((*f_iter)->get_name ());
+    t_type *ttype = (*f_iter)->get_returntype ();
+    t_struct *arglist = (*f_iter)->get_arglist ();
+    t_struct *xlist = (*f_iter)->get_xceptions();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list (arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
+                    + ", GError **error)";
+                    
+    indent (f_header_) << "gboolean (*" << funname << ") " << params << ";" <<
+                          endl;
+  }
+  indent_down ();
+
+  f_header_ <<
+    "};" << endl <<
+    "typedef struct _" << this->nspace << service_name_ << "IfInterface " <<
+        this->nspace << service_name_ << "IfInterface;" << endl <<
+    endl;
+
+  // generate all the interface boilerplate
+  f_header_ <<
+    "GType " << this->nspace_lc << service_name_lc <<
+        "_if_get_type (void);" << endl <<
+    "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF " <<
+        "(" << this->nspace_lc << service_name_lc << "_if_get_type ())" <<
+        endl <<
+    "#define " << this->nspace_uc << service_name_uc << "_IF(obj) " <<
+        "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " <<
+        this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " <<
+        this->nspace << service_name_ << "If))" << endl <<
+    "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) " <<
+        "(G_TYPE_CHECK_INSTANCE_TYPE ((obj, " <<
+        this->nspace_uc << "TYPE_" << service_name_uc << "_IF))" << endl <<
+    "#define " << this->nspace_uc << service_name_uc <<
+        "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), " <<
+        this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " <<
+        this->nspace << service_name_ << "IfInterface))" << endl <<
+    endl;
+
+  // write out all the interface function prototypes
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores ((*f_iter)->get_name ());
+    t_type *ttype = (*f_iter)->get_returntype ();
+    t_struct *arglist = (*f_iter)->get_arglist ();
+    t_struct *xlist = (*f_iter)->get_xceptions ();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list (arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
+                    + ", GError **error)";
+
+    f_header_ << "gboolean " << this->nspace_lc << service_name_lc <<
+                 "_if_" << funname << " " << params << ";" << endl;
+  }
+  f_header_ << endl;
+
+  // Generate the client object instance definition in the header.
+  f_header_ <<
+    "/* " << service_name_ << " service client */" << endl <<
+    "struct _" << this->nspace << service_name_ << "Client" << endl <<
+    "{" << endl <<
+    "  GObject parent;" << endl <<
+    endl <<
+    "  ThriftProtocol *input_protocol;" << endl <<
+    "  ThriftProtocol *output_protocol;" << endl <<
+    "};" << endl <<
+    "typedef struct _" << this->nspace << service_name_ << "Client " <<
+      this->nspace << service_name_ << "Client;" << endl <<
+    endl;
+
+  // Generate the class definition in the header.
+  f_header_ <<
+    "struct _" << this->nspace << service_name_ << "ClientClass" << endl <<
+    "{" << endl <<
+    "  GObjectClass parent;" << endl <<
+    "};" << endl <<
+    "typedef struct _" << this->nspace << service_name_ << "ClientClass " <<
+      this->nspace << service_name_ << "ClientClass;" << endl <<
+    endl;
+
+  // Create all the GObject boilerplate
+  f_header_ <<
+    "GType " << this->nspace_lc << service_name_lc << 
+        "_client_get_type (void);" << endl <<
+    "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT " <<
+        "(" << this->nspace_lc << service_name_lc << "_client_get_type ())" <<
+        endl <<
+    "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) " <<
+        "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << 
+        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << 
+        this->nspace << service_name_ << "Client))" << endl <<
+    "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) " << 
+        "(G_TYPE_CHECK_CLASS_CAST ((c), " << 
+        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << 
+        this->nspace << service_name_ << "ClientClass))" << endl <<
+    "#define " << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) " <<
+        "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << 
+        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl << 
+    "#define " << this->nspace_uc << service_name_uc <<
+        "_IS_CLIENT_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << 
+        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl <<
+    "#define " << this->nspace_uc << service_name_uc <<
+        "_CLIENT_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << 
+        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " <<
+        this->nspace << service_name_ << "ClientClass))" << endl << 
+    endl;
+
+  /* write out the function prototypes */
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = to_lower_case (initial_caps_to_underscores ((*f_iter)->get_name ()));
+
+    t_function service_function ((*f_iter)->get_returntype (),
+                                 service_name_lc + string ("_client_")
+                                 + funname,
+                                 (*f_iter)->get_arglist (),
+                                 (*f_iter)->get_xceptions ());
+    indent (f_header_) << function_signature (&service_function) << ";" << endl;
+
+    t_function send_function (g_type_void,
+                              service_name_lc + string ("_client_send_")
+                              + funname,
+                              (*f_iter)->get_arglist ());
+    indent (f_header_) << function_signature (&send_function) << ";" << endl;
+
+    // implement recv if not a oneway service
+    if (!(*f_iter)->is_oneway ()) {
+      t_struct noargs (program_);
+      t_function recv_function ((*f_iter)->get_returntype (),
+                                service_name_lc + string ("_client_recv_") 
+                                + funname,
+                                &noargs,
+                                (*f_iter)->get_xceptions ());
+      indent (f_header_) << function_signature (&recv_function) << ";" << endl;
+    }
+  }
+
+  f_header_ << endl;
+  // end of header code
+
+  // Generate interface method implementations
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores ((*f_iter)->get_name ());
+    t_type *ttype = (*f_iter)->get_returntype ();
+    t_struct *arglist = (*f_iter)->get_arglist ();
+    t_struct *xlist = (*f_iter)->get_xceptions ();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list (arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
+                    + ", GError **error)";
+
+    string params_without_type = string("iface, ")
+                                 + (has_return ? "_return, " : "");
+
+    const vector<t_field *>& fields = arglist->get_members ();
+    vector<t_field *>::const_iterator f_iter_field;
+    for (f_iter_field = fields.begin(); f_iter_field != fields.end();
+         ++f_iter_field)
+    {
+      params_without_type += (*f_iter_field)->get_name (); 
+      params_without_type += ", ";
+    }
+
+    const vector<t_field *>& xceptions = xlist->get_members ();
+    vector<t_field *>::const_iterator x_iter;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
+    {
+      params_without_type += (*x_iter)->get_name ();
+      params_without_type += ", ";
+    }
+
+    f_service_ <<
+      "gboolean" << endl <<
+      this->nspace_lc << service_name_lc << "_if_" << funname << " " <<
+          params << endl <<
+      "{" << endl << 
+      "  return " << this->nspace_uc << service_name_uc <<
+          "_IF_GET_INTERFACE (iface)->" << funname << " (" <<
+          params_without_type << "error);" << endl <<
+      "}" << endl <<
+      endl;
+  }
+
+  // Generate interface boilerplate
+  f_service_ <<
+    "GType" << endl <<
+    this->nspace_lc << service_name_lc << "_if_get_type (void)" << endl <<
+    "{" << endl <<
+    "  static GType type = 0;" << endl <<
+    "  if (type == 0)" << endl <<
+    "  {" << endl <<
+    "    static const GTypeInfo type_info =" << endl <<
+    "    {" << endl <<
+    "      sizeof (" << this->nspace << service_name_ << "IfInterface)," <<
+        endl <<
+    "      NULL,  /* base_init */" << endl <<
+    "      NULL  /* base_finalize */" << endl <<
+    "    };" << endl <<
+    "    type = g_type_register_static (G_TYPE_INTERFACE," << endl <<
+    "                                   \"" << this->nspace << service_name_ <<
+        "If\"," << endl <<
+    "                                   &type_info, 0);" << endl <<
+    "  }" << endl <<
+    "  return type;" << endl <<
+    "}" << endl <<
+    endl;
+
+  // Generate client boilerplate
+  f_service_ <<
+    "static void " << endl <<
+    this->nspace_lc << service_name_lc <<
+        "_if_interface_init (" << this->nspace << service_name_ <<
+        "IfInterface *iface);" << endl <<
+    endl <<
+    "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_ <<
+      "Client, " << this->nspace_lc << service_name_lc << "_client," << endl <<
+      "                       G_TYPE_OBJECT, " << endl <<
+    "                         G_IMPLEMENT_INTERFACE (" <<
+        this->nspace_uc << "TYPE_" << service_name_uc << "_IF," << endl <<
+    "                                                " <<
+        this->nspace_lc << service_name_lc << "_if_interface_init));" << endl <<
+    endl;
+
+  // Generate client properties
+  f_service_ <<
+    "enum _" << this->nspace << service_name_ << "ClientProperties" << endl <<
+    "{" << endl <<
+    "  PROP_0," << endl <<
+    "  PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_INPUT_PROTOCOL," <<
+        endl <<
+    "  PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_OUTPUT_PROTOCOL" <<
+        endl <<
+    "};" << endl <<
+  endl;
+
+  // generate property setter
+  f_service_ <<
+    "void" << endl <<
+    this->nspace_lc << service_name_lc << "_client_set_property (" <<
+        "GObject *object, guint property_id, const GValue *value, " <<
+        "GParamSpec *pspec)" << endl <<
+    "{" << endl <<
+    "  " << this->nspace << service_name_ << "Client *client = " <<
+        this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl <<
+    endl <<
+    "  THRIFT_UNUSED_VAR (pspec);" << endl <<
+    endl <<
+    "  switch (property_id)" << endl <<
+    "  {" << endl <<
+    "    case PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_INPUT_PROTOCOL:" << endl <<
+    "      client->input_protocol = g_value_get_object (value);" << endl <<
+    "      break;" << endl <<
+    "    case PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_OUTPUT_PROTOCOL:" << endl <<
+    "      client->output_protocol = g_value_get_object (value);" << endl <<
+    "      break;" << endl <<
+    "  }" << endl <<
+    "}" << endl <<
+  endl;
+
+  // generate property getter
+  f_service_ <<
+    "void" << endl <<
+    this->nspace_lc << service_name_lc << "_client_get_property (" <<
+        "GObject *object, guint property_id, GValue *value, " <<
+        "GParamSpec *pspec)" << endl <<
+    "{" << endl <<
+    "  " << this->nspace << service_name_ << "Client *client = " <<
+        this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl <<
+    endl <<
+    "  THRIFT_UNUSED_VAR (pspec);" << endl <<
+    endl <<
+    "  switch (property_id)" << endl <<
+    "  {" << endl <<
+    "    case PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_INPUT_PROTOCOL:" << endl <<
+    "      g_value_set_object (value, client->input_protocol);" << endl <<
+    "      break;" << endl <<
+    "    case PROP_" << this->nspace_uc << service_name_uc <<
+        "_CLIENT_OUTPUT_PROTOCOL:" << endl <<
+    "      g_value_set_object (value, client->output_protocol);" << endl <<
+    "      break;" << endl <<
+    "  }" << endl <<
+    "}" << endl <<
+  endl;
+
+
+  // Generate client method implementations
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    string name = (*f_iter)->get_name ();
+    string funname = initial_caps_to_underscores (name);
+
+    // Get the struct of function call params and exceptions
+    t_struct* arg_struct = (*f_iter)->get_arglist ();
+
+    // Function for sending
+    t_function send_function (g_type_void,
+                              service_name_lc + string ("_client_send_")
+                              + funname,
+                              (*f_iter)->get_arglist ());
+
+    // Open the send function
+    indent (f_service_) <<
+      function_signature (&send_function) << endl;
+    scope_up(f_service_);
+
+    // Serialize the request
+    f_service_ <<
+      indent () << "gint32 cseqid = 0;" << endl <<
+      indent () << "ThriftProtocol * protocol = " << 
+        this->nspace_uc << service_name_uc << 
+        "_CLIENT (iface)->output_protocol;" << endl <<
+      endl <<
+      indent () << "if (thrift_protocol_write_message_begin (protocol, \"" <<
+        name << "\", T_CALL, cseqid, error) < 0)" << endl <<
+      indent () << "  return FALSE;" << endl <<
+      endl;
+
+    generate_struct_writer (f_service_, arg_struct, "", "", false);
+
+    f_service_ <<
+      indent () <<
+        "if (thrift_protocol_write_message_end (protocol, error) < 0)" <<
+        endl <<
+      indent () <<
+        "  return FALSE;" << endl <<
+      indent () <<
+        "if (!thrift_transport_flush (protocol->transport, error))" << endl <<
+      indent () <<
+        "  return FALSE;" << endl <<
+      indent () <<
+        "if (!thrift_transport_write_end (protocol->transport, error))" <<
+        endl <<
+      indent () <<
+        "  return FALSE;" << endl <<
+      endl <<
+      indent () << 
+        "return TRUE;" << endl;
+
+    scope_down (f_service_);
+    f_service_ << endl;
+
+    // Generate recv function only if not an async function
+    if (!(*f_iter)->is_oneway ()) {
+      t_struct noargs (program_);
+      t_function recv_function ((*f_iter)->get_returntype (),
+                                service_name_lc
+                                + string ("_client_recv_") + funname, &noargs,
+                                (*f_iter)->get_xceptions ());
+      // Open function
+      indent (f_service_) <<
+        function_signature (&recv_function) << endl;
+      scope_up (f_service_);
+
+      f_service_ << endl <<
+        indent() << "gint32 rseqid;" << endl <<
+        indent() << "gchar * fname;" << endl <<
+        indent() << "ThriftMessageType mtype;" << endl <<
+        indent() << "ThriftProtocol * protocol = " << 
+                      this->nspace_uc << service_name_uc <<
+                      "_CLIENT (iface)->input_protocol;" << endl <<
+        endl <<
+        indent() << "if (thrift_protocol_read_message_begin " << 
+                      "(protocol, &fname, &mtype, &rseqid, error) < 0)" <<
+                      endl <<
+        indent() << "{" << endl <<
+        indent() << "  if (fname) g_free (fname);" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        indent() << "}" << endl <<
+        endl <<
+        indent() << "if (mtype == T_EXCEPTION) {" << endl <<
+        indent() << "  if (fname) g_free (fname);" << endl <<
+        indent() << "  ThriftApplicationException *xception = g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl <<
+
+        indent() << "  thrift_struct_read (THRIFT_STRUCT (xception), protocol, NULL);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, NULL);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, NULL);" << endl <<
+        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, xception->type, \"application error: %s\", xception->message);" << endl <<
+        indent() << "  g_object_unref (xception);" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        indent() << "} else if (mtype != T_REPLY) {" << endl <<
+        indent() << "  if (fname) g_free (fname);" << endl <<
+        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, NULL);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, NULL);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, NULL);" << endl << 
+        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, \"invalid message type %d, expected T_REPLY\", mtype);" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        indent() << "} else if (strncmp (fname, \"" << name << "\", " << name.length () << ") != 0) {" << endl <<
+        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, NULL);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, error);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, error);" << endl <<
+        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, \"wrong method name %s, expected " << name << "\", fname);" << endl <<
+        indent() << "  if (fname) g_free (fname);" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if (fname) g_free (fname);" << endl << 
+        endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      {
+        t_struct result(program_, tservice->get_name() + "_" + 
+                        (*f_iter)->get_name() + "_result");
+        t_field success((*f_iter)->get_returntype(), "*_return", 0);
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          result.append(&success);
+        }
+
+        // add readers for exceptions, dereferencing the pointer.
+        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+          t_field *xception = new t_field((*x_iter)->get_type (),
+                                          "*" + (*x_iter)->get_name (),
+                                          (*x_iter)->get_key ());
+          result.append (xception);
+        }
+
+        generate_struct_reader (f_service_, &result, "", "", false);
+      }
+
+      f_service_ <<
+        indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        endl <<
+        indent() << "if (!thrift_transport_read_end (protocol->transport, error))" << endl <<
+        indent() << "  return FALSE;" << endl <<
+        endl;
+
+      // copy over any throw exceptions and return failure
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+        f_service_ << 
+          indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl <<
+          indent() << "{" << endl <<
+          indent() << "    g_set_error (error, " << this->nspace_uc <<
+              to_upper_case (initial_caps_to_underscores (
+                                 (*x_iter)->get_type ()->get_name ())) <<
+              "_ERROR, " <<
+              this->nspace_uc <<
+              to_upper_case (initial_caps_to_underscores (
+                                 (*x_iter)->get_type ()->get_name ())) <<
+              "_ERROR_CODE, \"" << (*x_iter)->get_type ()->get_name () << 
+              "\");" << endl <<
+          indent() << "    return FALSE;" << endl <<
+          indent() << "}" << endl;
+      }
+      // Close function
+      indent(f_service_) << "return TRUE;" << endl;
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+
+    // Open function
+    t_function service_function ((*f_iter)->get_returntype (),
+                                 service_name_lc
+                                 + string ("_client_") + funname,
+                                 (*f_iter)->get_arglist (),
+                                 (*f_iter)->get_xceptions ());
+    indent (f_service_) <<
+      function_signature (&service_function) << endl;
+    scope_up (f_service_);
+
+    // wrap each function
+    f_service_ <<
+      indent () << "if (!" << this->nspace_lc << service_name_lc <<
+                   "_client_send_" << funname <<
+      " (iface";
+
+    // Declare the function arguments
+    const vector<t_field *> &fields = arg_struct->get_members ();
+    vector<t_field *>::const_iterator fld_iter;
+    for (fld_iter = fields.begin (); fld_iter != fields.end (); ++fld_iter) {
+      f_service_ << ", " << (*fld_iter)->get_name ();
+    }
+    f_service_ << ", error))" << endl <<
+      indent () << "  return FALSE;" << endl;
+
+    // if not oneway, implement recv
+    if (!(*f_iter)->is_oneway ()) {
+      string ret = (*f_iter)->get_returntype ()->is_void () ? "" : "_return, ";
+
+      const vector<t_field *>& xceptions =
+          (*f_iter)->get_xceptions()->get_members ();
+      vector<t_field *>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
+      {
+        ret += (*x_iter)->get_name ();
+        ret += ", ";
+      }
+
+      f_service_ <<
+        indent () << "if (!" << this->nspace_lc << service_name_lc <<
+          "_client_recv_" << funname <<
+          " (iface, " << ret << "error))" << endl <<
+        indent () << "  return FALSE;" << endl;
+    }
+
+    // return TRUE which means all functions were called OK
+    indent (f_service_) << "return TRUE;" << endl;
+    scope_down (f_service_);
+    f_service_ << endl;
+  }
+
+  // create the interface initializer
+  f_service_ <<
+    "static void" << endl <<
+    this->nspace_lc << service_name_lc << "_if_interface_init (" <<
+        this->nspace << service_name_ << "IfInterface *iface)" << endl <<
+    "{" << endl;
+  for (f_iter = functions.begin (); f_iter != functions.end (); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores ((*f_iter)->get_name ());
+
+    f_service_ <<
+      "  iface->" << funname << " = " << this->nspace_lc << service_name_lc <<
+        "_client_" << funname << ";" << endl;
+  }
+  f_service_ <<
+    "}" << endl <<
+    endl;
+
+  // create the client instance initializer
+  f_service_ <<
+    "static void" << endl <<
+    this->nspace_lc << service_name_lc << "_client_init (" <<
+        this->nspace << service_name_ << "Client *client)" << endl <<
+    "{" << endl <<
+    "  client->input_protocol = NULL;" << endl <<
+    "  client->output_protocol = NULL;" << endl <<
+    "}" << endl <<
+    endl;
+
+  // create the client class initializer
+  f_service_ <<
+    "static void" << endl <<
+    this->nspace_lc << service_name_lc << "_client_class_init (" <<
+        this->nspace << service_name_ << "ClientClass *cls)" << endl <<
+    "{" << endl <<
+    "  GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl <<
+    "  GParamSpec *param_spec;" << endl <<
+    endl <<
+    "  gobject_class->set_property = " << this->nspace_lc <<
+        service_name_lc << "_client_set_property;" << endl <<
+    "  gobject_class->get_property = " << this->nspace_lc <<
+        service_name_lc << "_client_get_property;" << endl <<
+    endl <<
+    "  param_spec = g_param_spec_object (\"input_protocol\"," << endl <<
+    "                                    \"input protocol (construct)\"," <<
+        endl <<
+    "                                    \"Set the client input protocol\"," <<
+        endl <<
+    "                                    THRIFT_TYPE_PROTOCOL," << endl <<
+    "                                    G_PARAM_READWRITE);" << endl <<
+    "  g_object_class_install_property (gobject_class," << endl <<
+    "                                   PROP_" << this->nspace_uc <<
+        service_name_uc << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl <<
+    endl <<
+    "  param_spec = g_param_spec_object (\"output_protocol\"," << endl <<
+    "                                    \"output protocol (construct)\"," <<
+        endl <<
+    "                                    \"Set the client output protocol\"," <<
+        endl <<
+    "                                    THRIFT_TYPE_PROTOCOL," << endl <<
+    "                                    G_PARAM_READWRITE);" << endl <<
+    "  g_object_class_install_property (gobject_class," << endl <<
+    "                                   PROP_" << this->nspace_uc <<
+        service_name_uc << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates C code that represents a Thrift service server.
+ */
+void
+t_c_glib_generator::generate_service_server (t_service *tservice)
+{
+  /* get some C friendly service names */
+  string service_name_u = initial_caps_to_underscores (service_name_);
+  string service_name_uc = to_upper_case (service_name_u);
+
+  // write the server object instance definition in the header.
+  // TODO: implement after implement TServer and TProcessor
+}
+
+/**
+ * Generates C code to represent a THrift structure as a GObject.
+ */
+void
+t_c_glib_generator::generate_object (t_struct *tstruct)
+{
+  string name = tstruct->get_name ();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+
+  // write the instance definition
+  f_types_ <<
+    "struct _" << this->nspace << name << endl <<
+    "{ " << endl <<
+    "  ThriftStruct parent; " << endl <<
+    endl <<
+    "  /* public */" << endl;
+
+  // for each field, add a member variable
+  bool has_nonrequired_fields = false;
+  vector<t_field *>::const_iterator m_iter;
+  const vector<t_field *> &members = tstruct->get_members ();
+  for (m_iter = members.begin (); m_iter != members.end (); ++m_iter)
+  {
+    t_type *t = get_true_type ((*m_iter)->get_type ());
+    f_types_ <<
+      "  " << type_name (t) << " " << (*m_iter)->get_name () << ";" << endl;
+    if ((*m_iter)->get_req () != t_field::T_REQUIRED)
+    {
+      has_nonrequired_fields = true;
+      f_types_ <<
+        "  gboolean __isset_" << (*m_iter)->get_name () << ";" << endl;
+    }
+  }
+
+  // close the structure definition and create a typedef
+  f_types_ <<
+    "};" << endl <<
+    "typedef struct _" << this->nspace << name << " " << 
+        this->nspace << name << ";" << endl <<
+      endl;
+
+  // write the class definition
+  f_types_ <<
+    "struct _" << this->nspace << name << "Class" << endl <<
+    "{" << endl <<
+    "  ThriftStructClass parent;" << endl <<
+    "};" << endl <<
+    "typedef struct _" << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl <<
+    endl;
+
+  // write the standard GObject boilerplate
+  f_types_ <<
+    "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl <<
+    "#define " << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u << "_get_type ())" << endl <<
+    "#define " << this->nspace_uc << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "))" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl <<
+    "#define " << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl <<
+    "#define " << this->nspace_uc << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl <<
+    endl;
+
+  // start writing the object implementation .c file
+  // generate struct I/O methods
+  string this_get = this->nspace + name + " * this_object = " 
+                    + this->nspace_uc + name_uc + "(object);";
+  generate_struct_reader (f_types_impl_, tstruct, "this_object->", this_get);
+  generate_struct_writer (f_types_impl_, tstruct, "this_object->", this_get);
+
+  // generate the instance init function
+  f_types_impl_ <<
+    "void " << endl <<
+    this->nspace_lc << name_u << "_instance_init (" << this->nspace << name << " * object)" << endl <<
+    "{" << endl;
+
+  // satisfy compilers with -Wall turned on
+  indent_up ();
+  indent (f_types_impl_) << "/* satisfy -Wall */" << endl <<
+               indent () << "THRIFT_UNUSED_VAR (object);" << endl;
+
+  for (m_iter = members.begin (); m_iter != members.end (); ++m_iter)
+  {
+    t_type* t = get_true_type ((*m_iter)->get_type ());
+    if (t->is_base_type ()) {
+      // only have init's for base types
+      string dval = " = ";
+      if (t->is_enum ()) {
+        dval += "(" + type_name (t) + ")";
+      }
+      t_const_value* cv = (*m_iter)->get_value ();
+      if (cv != NULL) {
+        dval += constant_value ("", t, cv);
+      } else {
+        dval += t->is_string () ? "NULL" : "0";
+      }
+      indent(f_types_impl_) << "object->" << (*m_iter)->get_name () << dval << ";" << endl;
+    } else if (t->is_struct ()) {
+      string name = (*m_iter)->get_name ();
+      string type_name_uc = to_upper_case
+        (initial_caps_to_underscores ((*m_iter)->get_type ()->get_name ()));
+      indent (f_types_impl_) << "object->" << name << " = g_object_new (" << this->nspace_uc << "TYPE_" << type_name_uc << ", NULL);" << endl;
+    } else if (t->is_xception()) {
+      string name = (*m_iter)->get_name();
+      indent (f_types_impl_) << "object->" << name << " = NULL;" << endl;
+    } else if (t->is_container()) {
+      string name = (*m_iter)->get_name();
+
+      if (t->is_map () || t->is_set ())
+      {
+        indent (f_types_impl_) << "object->" << name << " = g_hash_table_new (NULL, NULL);" << endl;
+      } else if (t->is_list ()) {
+        t_type *etype = ((t_list *) t)->get_elem_type ();
+        string init_function = "g_ptr_array_new ()";
+
+        if (etype->is_base_type ())
+        {
+          t_base_type::t_base tbase = ((t_base_type *) etype)->get_base ();
+          switch (tbase)
+          {
+            case t_base_type::TYPE_VOID:
+              throw "compiler error: cannot determine array type";
+            case t_base_type::TYPE_BOOL:
+            case t_base_type::TYPE_BYTE:
+            case t_base_type::TYPE_I16:
+            case t_base_type::TYPE_I32:
+            case t_base_type::TYPE_I64:
+            case t_base_type::TYPE_DOUBLE:
+              init_function = generate_new_array_from_type (etype);
+              break;
+            case t_base_type::TYPE_STRING:
+              break;
+            default:
+              throw "compiler error: no array info for type";
+          }
+        }
+
+        indent (f_types_impl_) << "object->" << name << " = " <<
+                                  init_function << ";" << endl;
+      }
+
+    }
+
+    /* if not required, initialize the __isset variable */
+    if ((*m_iter)->get_req () != t_field::T_REQUIRED)
+    {
+      indent (f_types_impl_) << "object->__isset_" << (*m_iter)->get_name () << " = FALSE;" << endl;
+    }
+  }
+
+  indent_down ();
+  f_types_impl_ << "}" << endl <<
+  endl;
+
+  /* create the destructor */
+  f_types_impl_ <<
+    "void " << endl <<
+    this->nspace_lc << name_u << "_finalize (GObject *object)" << endl <<
+    "{" << endl;
+  indent_up ();
+
+  f_types_impl_ <<
+    indent () <<
+    this->nspace << name << " *tobject = " << this->nspace_uc <<
+    name_uc << " (object);" << endl << endl;
+
+  f_types_impl_ <<
+    indent () << "/* satisfy -Wall in case we don't use tobject */" << endl <<
+    indent () << "THRIFT_UNUSED_VAR (tobject);" << endl;
+
+  for (m_iter = members.begin (); m_iter != members.end (); ++m_iter)
+  {
+    t_type* t = get_true_type ((*m_iter)->get_type ());
+    if (t->is_container())
+    { 
+      string name = (*m_iter)->get_name();
+      if (t->is_map () || t->is_set ())
+      {
+        f_types_impl_ <<
+          indent () << "g_hash_table_unref (tobject->" << name << ");" << endl;
+      } else if (t->is_list ()) {
+        t_type *etype = ((t_list *) t)->get_elem_type ();
+        string destructor_function = "g_ptr_array_free";
+
+        if (etype->is_base_type ())
+        {
+          t_base_type::t_base tbase = ((t_base_type *) etype)->get_base ();
+          switch (tbase)
+          {
+            case t_base_type::TYPE_VOID:
+              throw "compiler error: cannot determine array type";
+            case t_base_type::TYPE_BOOL:
+            case t_base_type::TYPE_BYTE:
+            case t_base_type::TYPE_I16:
+            case t_base_type::TYPE_I32:           
+            case t_base_type::TYPE_I64:
+            case t_base_type::TYPE_DOUBLE:
+              destructor_function = "g_array_free";
+              break;
+            case t_base_type::TYPE_STRING:
+              break;
+            default:
+              throw "compiler error: no array info for type";
+          }
+        }
+
+        f_types_impl_ <<
+          indent () << destructor_function << " (tobject->" << name <<
+                       ", FALSE);" << endl;
+      }
+    }
+  }
+
+  indent_down ();
+  f_types_impl_ <<
+    "}" << endl <<
+    endl;
+
+
+  f_types_impl_ <<
+    "void " << endl <<
+    this->nspace_lc << name_u << "_class_init (ThriftStructClass * cls)" << endl <<
+    "{" << endl;
+  indent_up ();
+
+  f_types_impl_ <<   
+    indent () << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl <<
+    endl <<
+    indent () << "gobject_class->finalize = " << this->nspace_lc << name_u << "_finalize;" << endl <<
+    indent () << "cls->read = " << this->nspace_lc << name_u << "_read;" << endl <<
+    indent () << "cls->write = " << this->nspace_lc << name_u << "_write;" << endl;
+
+  indent_down ();
+  f_types_impl_ <<
+    "}" << endl <<
+    endl;
+
+
+  f_types_impl_ <<
+    "GType" << endl <<
+    this->nspace_lc << name_u << "_get_type (void)" << endl <<
+    "{" << endl <<
+    "  static GType type = 0;" << endl <<
+    endl <<
+    "  if (type == 0) " << endl <<
+    "  {" << endl <<
+    "    static const GTypeInfo type_info = " << endl <<
+    "    {" << endl <<
+    "      sizeof (" << this->nspace << name << "Class)," << endl <<
+    "      NULL, /* base_init */" << endl <<
+    "      NULL, /* base_finalize */" << endl <<
+    "      (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init," << endl <<
+    "      NULL, /* class_finalize */" << endl <<
+    "      NULL, /* class_data */" << endl <<
+    "      sizeof (" << this->nspace << name << ")," << endl <<
+    "      0, /* n_preallocs */" << endl <<
+    "      (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init," << endl <<
+    "      NULL, /* value_table */" << endl <<
+    "    };" << endl <<
+    endl <<
+    "    type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl <<
+    "                                   \"" << this->nspace << name << "Type\"," << endl <<
+    "                                   &type_info, 0);" << endl <<
+    "  }" << endl <<
+    endl <<
+    "  return type;" << endl <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates functions to write Thrift structures to a stream.
+ */
+void
+t_c_glib_generator::generate_struct_writer (ofstream &out, t_struct *tstruct,
+                                       string this_name, string this_get,
+                                       bool is_function)
+{
+  string name = tstruct->get_name ();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+
+  const vector<t_field *> &fields = tstruct->get_members ();
+  vector <t_field *>::const_iterator f_iter;
+  int error_ret = 0;
+
+  if (is_function)
+  {
+    error_ret = -1;
+    indent(out) <<
+      "gint32" << endl <<
+      this->nspace_lc << name_u <<
+      "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
+  }
+  indent (out) << "{" << endl;
+  indent_up ();
+
+  out <<
+    indent () << "gint32 ret;" << endl <<
+    indent () << "gint32 xfer = 0;" << endl <<
+    endl;
+
+  indent (out) << this_get << endl;
+  // satisfy -Wall in the case of an empty struct
+  if (!this_get.empty())
+  {
+    indent (out) << "THRIFT_UNUSED_VAR (this_object);" << endl;
+  }
+
+  out <<
+    indent () << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name << "\", error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl;
+
+  for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter)
+  {
+    if ((*f_iter)->get_req () == t_field::T_OPTIONAL)
+    {
+      indent (out) << "if (this_object->__isset_" << (*f_iter)->get_name () << " == TRUE) {" << endl;
+      indent_up ();
+    } 
+
+    out <<
+     indent () << "if ((ret = thrift_protocol_write_field_begin (protocol, " <<
+     "\"" << (*f_iter)->get_name () << "\", " <<
+     type_to_enum ((*f_iter)->get_type ()) << ", " <<
+     (*f_iter)->get_key () << ", error)) < 0)" << endl <<
+     indent () << "  return " << error_ret << ";" << endl <<
+     indent () << "xfer += ret;" << endl;
+    generate_serialize_field (out, *f_iter, this_name, "", error_ret);
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl;
+
+    if ((*f_iter)->get_req () == t_field::T_OPTIONAL)
+    {
+      indent_down ();
+      indent (out) << "}" << endl;
+    }
+  }
+
+  // write the struct map
+  out <<
+    indent () << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    indent () << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    endl;
+
+  if (is_function)
+  {
+    indent (out) << "return xfer;" << endl;
+  }
+
+  indent_down ();
+  indent (out) <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates code to read Thrift structures from a stream.
+ */
+void
+t_c_glib_generator::generate_struct_reader (ofstream &out, t_struct *tstruct,
+                                       string this_name, string this_get,
+                                       bool is_function)
+{
+  string name = tstruct->get_name ();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+  int error_ret = 0;
+  const vector<t_field *> &fields = tstruct->get_members ();
+  vector <t_field *>::const_iterator f_iter;
+
+  if (is_function)
+  {
+    error_ret = -1;
+    indent (out) <<
+      "/* reads a " << name_u << " object */" << endl <<
+      "gint32" << endl <<
+      this->nspace_lc << name_u <<
+          "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
+  }
+
+  indent (out) << "{" << endl;
+  indent_up ();
+
+  // declare stack temp variables
+  out <<
+    indent () << "gint32 ret;" << endl <<
+    indent () << "gint32 xfer = 0;" << endl <<
+    indent () << "gchar *name;" << endl <<
+    indent () << "ThriftType ftype;" << endl <<
+    indent () << "gint16 fid;" << endl <<
+    indent () << "guint32 len = 0;" << endl <<
+    indent () << "gpointer data = NULL;" << endl <<
+    indent () << this_get << endl;
+
+  for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter)
+  {
+    if ((*f_iter)->get_req () == t_field::T_REQUIRED)
+    {
+      indent (out) << "gboolean isset_" << (*f_iter)->get_name () << " = FALSE;" << endl;
+    }
+  }
+
+  out << endl;
+
+  // satisfy -Wall in case we don't use some variables
+  out <<
+    indent () << "/* satisfy -Wall in case these aren't used */" << endl <<
+    indent () << "THRIFT_UNUSED_VAR (len);" << endl <<
+    indent () << "THRIFT_UNUSED_VAR (data);" << endl;
+
+  if (!this_get.empty())
+  {
+    out << indent () << "THRIFT_UNUSED_VAR (this_object);" << endl;
+  }
+  out << endl;
+
+  // read the beginning of the structure marker
+  out <<
+    indent () << "/* read the struct begin marker */" << endl <<
+    indent () << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl <<
+    indent () << "{" << endl <<
+    indent () << "  if (name) g_free (name);" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "}" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    indent () << "if (name) g_free (name);" << endl <<
+    endl;
+
+  // read the struct fields
+  out <<
+    indent () << "/* read the struct fields */" << endl <<
+    indent () << "while (1)" << endl;
+  scope_up (out);
+
+  // read beginning field marker
+  out <<
+    indent () << "/* read the beginning of a field */" << endl <<
+    indent () << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" << endl <<
+    indent () << "{" << endl <<
+    indent () << "  if (name) g_free (name);" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "}" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    indent () << "if (name) g_free (name);" << endl <<
+    endl;
+
+  // check for field STOP marker
+  out <<
+    indent () << "/* break if we get a STOP field */" << endl <<
+    indent () << "if (ftype == T_STOP)" << endl <<
+    indent () << "{" << endl <<
+    indent () << "  break;" << endl <<
+    indent () << "}" << endl <<
+    endl;
+
+  // switch depending on the field type
+  indent (out) <<
+    "switch (fid)" << endl;
+
+  // start switch
+  scope_up (out);
+
+  // generate deserialization code for known types
+  for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter)
+  {
+    indent (out) <<
+      "case " << (*f_iter)->get_key () << ":" << endl;
+    indent_up ();
+    indent (out) <<
+      "if (ftype == " << type_to_enum ((*f_iter)->get_type ()) << ")" << endl;
+    indent (out) <<
+      "{" << endl;
+
+
+    indent_up ();
+    // generate deserialize field
+    generate_deserialize_field (out, *f_iter, this_name, "", error_ret);
+    indent_down ();
+
+    out <<
+      indent () << "} else {" << endl <<
+      indent () << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+      indent () << "    return " << error_ret << ";" << endl <<
+      indent () << "  xfer += ret;" << endl <<
+      indent () << "}" << endl <<
+      indent () << "break;" << endl;
+    indent_down();
+  }
+
+  // create the default case
+  out <<
+    indent () << "default:" << endl <<
+    indent () << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+    indent () << "    return " << error_ret << ";" << endl <<
+    indent () << "  xfer += ret;" << endl <<
+    indent () << "  break;" << endl;
+
+  // end switch
+  scope_down (out);
+
+  // read field end marker
+  out <<
+    indent () << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl;
+
+  // end while loop
+  scope_down (out);
+  out << endl;
+
+  // read the end of the structure
+  out <<
+    indent () << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    endl;
+
+  // if a required field is missing, throw an error
+  for (f_iter = fields.begin (); f_iter != fields.end (); ++f_iter)
+  {
+    if ((*f_iter)->get_req () == t_field::T_REQUIRED)
+    {
+      out <<
+        indent () << "if (!isset_" << (*f_iter)->get_name () << ")" << endl <<
+        indent () << "{" << endl <<
+        indent () << "  g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl <<
+        indent () << "               THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl <<
+        indent () << "               \"missing field\");" << endl <<
+        indent () << "  return -1;" << endl <<
+        indent () << "}" << endl <<
+        endl;
+    }
+  }
+
+  if (is_function)
+  {
+    indent (out) <<
+      "return xfer;" << endl;
+  }
+
+  // end the function/structure
+  indent_down ();
+  indent (out) <<
+    "}" << endl <<
+    endl;
+}
+
+void
+t_c_glib_generator::generate_serialize_field (ofstream &out, t_field *tfield,
+                                         string prefix, string suffix,
+                                         int error_ret)
+{
+  t_type *type = get_true_type (tfield->get_type ());
+  string name = prefix + tfield->get_name () + suffix;
+
+  if (type->is_void ())
+  {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+  }
+
+  if (type->is_struct () || type->is_xception ())
+  {
+    generate_serialize_struct (out, (t_struct *) type, name, error_ret);
+  } else if (type->is_container ()) {
+    generate_serialize_container (out, type, name, error_ret);
+  } else if (type->is_base_type () || type->is_enum ()) {
+    indent (out) <<
+      "if ((ret = thrift_protocol_write_";
+
+    if (type->is_base_type ())
+    {
+      t_base_type::t_base tbase = ((t_base_type *) type)->get_base ();
+      switch (tbase)
+      {
+        case t_base_type::TYPE_VOID:
+          throw "compiler error: cannot serialize void field in a struct: "
+                + name;
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "bool (protocol, " << name;
+          break;
+        case t_base_type::TYPE_BYTE:
+          out << "byte (protocol, " << name;
+          break;
+        case t_base_type::TYPE_I16:
+          out << "i16 (protocol, " << name;
+          break;
+        case t_base_type::TYPE_I32:
+          out << "i32 (protocol, " << name;
+          break;
+        case t_base_type::TYPE_I64:
+          out << "i64 (protocol, " << name;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out << "double (protocol, " << name;
+          break;
+        case t_base_type::TYPE_STRING:
+          if (((t_base_type *) type)->is_binary ())
+          {
+            out << "binary (protocol, ((GByteArray *) " << name <<
+                   ")->data, ((GByteArray *) " << name <<
+                   ")->len";
+          } else {
+            out << "string (protocol, " << name;
+          }
+          break;
+        default:
+          throw "compiler error: no C writer for base type "
+                + t_base_type::t_base_name (tbase) + name;
+      }
+    } else if (type->is_enum ()) {
+      out << "i32 (protocol, (gint32) " << name;
+    }
+    out << ", error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl;
+  } else {
+    printf ("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+            name.c_str(), type_name (type).c_str());
+  }
+}
+
+void
+t_c_glib_generator::generate_serialize_struct (ofstream &out, t_struct *tstruct,
+                                          string prefix, int error_ret)
+{
+  out <<
+    indent () << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl <<
+    endl;
+}
+
+void
+t_c_glib_generator::generate_serialize_container (ofstream &out, t_type *ttype,
+                                             string prefix, int error_ret)
+{
+  scope_up (out);
+
+  if (ttype->is_map ())
+  {
+    string length = "g_hash_table_size ((GHashTable *) " + prefix + ")";
+    t_type *tkey = ((t_map *) ttype)->get_key_type ();
+    t_type *tval = ((t_map *) ttype)->get_val_type ();
+    string tkey_name = type_name (tkey);
+    string tval_name = type_name (tval);
+    string tkey_ptr = tkey->is_string () || !tkey->is_base_type () ? "" : "*";
+    string tval_ptr = tval->is_string () || !tval->is_base_type () ? "" : "*";
+
+    /*
+     * Some ugliness here.  To maximize backwards compatibility, we
+     * avoid using GHashTableIter and instead get a GList of all keys,
+     * then copy it into a array on the stack, and free it.
+     * This is because we may exit early before we get a chance to free the
+     * GList.
+     */
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_map_begin (protocol, " <<
+                   type_to_enum (tkey) << ", " << type_to_enum (tval) <<
+                   ", (gint32) " << length << ", error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl <<
+      indent () << "GList *key_list = NULL, *iter = NULL;" << endl <<
+      indent () << tkey_name << tkey_ptr << " key;" << endl <<
+      indent () << tval_name << tval_ptr << " value;" << endl <<
+      indent () << "g_hash_table_foreach ((GHashTable *) " << prefix << 
+                   ", thrift_hash_table_get_keys, &key_list);" << endl <<
+      indent () << tkey_name << tkey_ptr <<
+                   " keys[g_list_length (key_list)];" << endl <<
+      indent () << "int i=0, key_count = g_list_length (key_list);" << endl <<
+      indent () <<
+        "for (iter = g_list_first (key_list); iter; iter = iter->next)" <<
+        endl <<
+      indent () << "{" << endl <<
+      indent () << "  keys[i++] = (" << tkey_name << tkey_ptr <<
+                   ") iter->data;" << endl <<
+      indent () << "}" << endl <<
+      indent () << "g_list_free (key_list);" << endl <<
+      endl <<
+      indent () << "for (i = 0; i < key_count; ++i)" << endl;
+
+    scope_up (out);
+    out <<
+      indent () << "key = keys[i];" << endl <<
+      indent () << "value = (" << tval_name << tval_ptr <<
+                   ") g_hash_table_lookup (((GHashTable *) " << prefix <<
+                   "), (gpointer) key);" << endl <<
+      endl;
+    generate_serialize_map_element (out, (t_map *) ttype, tkey_ptr + " key",
+                                    tval_ptr + " value", error_ret);
+    scope_down (out);
+
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_map_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl;
+  } else if (ttype->is_set ()) {
+    string length = "g_hash_table_size ((GHashTable *) " + prefix + ")";
+    t_type *telem = ((t_set *) ttype)->get_elem_type ();
+    string telem_name = type_name (telem);
+    string telem_ptr = telem->is_string () || !telem->is_base_type () ? "" : "*";
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_set_begin (protocol, " <<
+                   type_to_enum (telem) << ", (gint32) " << length <<
+                   ", error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      indent () << "GList *key_list = NULL, *iter = NULL;" << endl <<
+      indent () << telem_name << telem_ptr << " elem;" << endl <<
+      indent () << "gpointer value;" << endl <<
+      indent () << "g_hash_table_foreach ((GHashTable *) " << prefix <<
+                   ", thrift_hash_table_get_keys, &key_list);" << endl <<
+      indent () << telem_name << telem_ptr << "keys[g_list_length (key_list)];" << endl <<
+      indent () << "int i=0, key_count = g_list_length (key_list);" << endl <<
+      indent () << "for (iter = g_list_first (key_list); iter; iter = iter->next)" << endl <<
+      indent () << "{" << endl <<
+      indent () << "  keys[i++] = (" << telem_name << telem_ptr << ") iter->data;" << endl <<
+      indent () << "}" << endl <<
+      indent () << "g_list_free (key_list);" << endl <<
+      endl <<
+      indent () << "for (i=0; i<key_count; ++i)" << endl;
+
+    scope_up (out);
+    out <<
+      indent () << "elem = keys[i];" << endl <<
+      indent () << "value = (gpointer) g_hash_table_lookup (((GHashTable *) " <<
+                   prefix << "), (gpointer) elem);" << endl <<
+      endl;
+    generate_serialize_set_element (out, (t_set *) ttype, telem_ptr + "elem",
+                                    error_ret);
+    scope_down (out);
+
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_set_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl;
+  } else if (ttype->is_list ()) {
+    string length = prefix + "->len";
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_list_begin (protocol, " <<
+                   type_to_enum (((t_list *) ttype)->get_elem_type ()) <<
+                   ", (gint32) " << length << ", error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      indent () << "guint i;" << endl <<
+      indent () << "for (i=0; i<" << length << "; i++)" << endl;
+
+    scope_up (out);
+    generate_serialize_list_element (out, (t_list *) ttype, prefix, "i", error_ret);
+    scope_down (out);
+
+    out <<
+      indent () << "if ((ret = thrift_protocol_write_list_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl;
+  }
+
+  scope_down (out);
+}
+
+void
+t_c_glib_generator::generate_serialize_map_element (ofstream &out, t_map *tmap,
+                                               string key, string value,
+                                               int error_ret)
+{
+  t_field kfield (tmap->get_key_type (), key);
+  generate_serialize_field (out, &kfield, "", "", error_ret);
+
+  t_field vfield (tmap->get_val_type (), value);
+  generate_serialize_field (out, &vfield, "", "", error_ret);
+}
+
+void
+t_c_glib_generator::generate_serialize_set_element (ofstream &out, t_set *tset, 
+                                               string element, int error_ret)
+{
+  t_field efield (tset->get_elem_type (), element);
+  generate_serialize_field (out, &efield, "", "", error_ret);
+}
+
+void
+t_c_glib_generator::generate_serialize_list_element (ofstream &out, t_list *tlist,
+                                                string list, string index,
+                                                int error_ret)
+{
+  t_type *ttype = tlist->get_elem_type ();
+
+  // cast to non-const
+  string name = "g_ptr_array_index ((GPtrArray *) " + list + ", "
+                + index + ")";
+
+  if (ttype->is_base_type ())
+  {
+    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base (); 
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine array type";
+        break;
+      case t_base_type::TYPE_BOOL:
+        name = "g_array_index (" + list + ", gboolean, " + index + ")";
+        break;
+      case t_base_type::TYPE_BYTE:
+        name = "g_array_index (" + list + ", gint8, " + index + ")";
+        break;
+      case t_base_type::TYPE_I16:
+        name = "g_array_index (" + list + ", gint16, " + index + ")";
+        break;
+      case t_base_type::TYPE_I32:
+        name = "g_array_index (" + list + ", gint32, " + index + ")";
+        break;
+      case t_base_type::TYPE_I64:
+        name = "g_array_index (" + list + ", gint64, " + index + ")";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        name = "g_array_index (" + list + ", gdouble, " + index + ")";
+        break;
+      case t_base_type::TYPE_STRING:
+        break;
+      default:
+        throw "compiler error: no array info for type";
+    }
+  }
+
+  t_field efield (ttype, name);
+  generate_serialize_field (out, &efield, "", "", error_ret);
+}
+
+/* deserializes a field of any type. */
+void
+t_c_glib_generator::generate_deserialize_field (ofstream &out, t_field *tfield,
+                                           string prefix, string suffix,
+                                           int error_ret)
+{
+  t_type *type = get_true_type (tfield->get_type ());
+
+  if (type->is_void ())
+  {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name ();
+  }
+
+  string name = prefix + tfield->get_name () + suffix;
+
+  if (type->is_struct () || type->is_xception ())
+  {
+    generate_deserialize_struct (out, (t_struct *) type, name, error_ret);
+  } else if (type->is_container ()) {
+    generate_deserialize_container (out, type, name, error_ret);
+  } else if (type->is_base_type ()) {
+    t_base_type::t_base tbase = ((t_base_type *) type)->get_base ();
+
+    indent (out) << "if ((ret = thrift_protocol_read_";
+
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (((t_base_type *) type)->is_binary ())
+        {
+          out << "binary (protocol, &data, &len";
+        } else {
+          out << "string (protocol, &" << name;
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "bool (protocol, &" << name;
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "byte (protocol, &" << name;
+        break;
+      case t_base_type::TYPE_I16:
+        out << "i16 (protocol, &" << name;
+        break;
+      case t_base_type::TYPE_I32:
+        out << "i32 (protocol, &" << name;
+        break;
+      case t_base_type::TYPE_I64:
+        out << "i64 (protocol, &" << name;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "double (protocol, &" << name;
+        break;
+      default:
+        throw "compiler error: no C reader for base type "
+          + t_base_type::t_base_name (tbase) + name;
+    }
+    out << ", error)) < 0)" << endl;
+    out << indent () << "  return " << error_ret << ";" << endl <<
+           indent () << "xfer += ret;" << endl;
+
+    // load the byte array with the data
+    if (tbase == t_base_type::TYPE_STRING
+        && ((t_base_type *) type)->is_binary ())
+    {
+      indent (out) << name << " = g_byte_array_new ();" << endl;
+      indent (out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl;
+      indent (out) << "g_free (data);" << endl;
+    }
+  } else if (type->is_enum ()) {
+    string t = tmp ("ecast");
+    out <<
+      indent () << "gint32 " << t << ";" << endl <<
+      indent () << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      indent () << name << " = (" << type_name (type) << ")" << t << ";" << endl;
+  } else {
+    printf ("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+            tfield->get_name ().c_str (), type_name (type).c_str ());
+  }
+
+  // if the type is not required and this is a thrift struct (no prefix),
+  // set the isset variable.  if the type is required, then set the
+  // local variable indicating the value was set, so that we can do    // validation later.
+  if (tfield->get_req () != t_field::T_REQUIRED && prefix != "")
+  {
+    indent (out) << prefix << "__isset_" << tfield->get_name () << suffix << " = TRUE;" << endl;
+  } else if (tfield->get_req () == t_field::T_REQUIRED && prefix != "") {
+    indent (out) << "isset_" << tfield->get_name () << " = TRUE;" << endl;
+  }
+}
+
+void
+t_c_glib_generator::generate_deserialize_struct (ofstream &out, t_struct *tstruct,
+                                            string prefix, int error_ret)
+{
+  string name_uc = to_upper_case (initial_caps_to_underscores (tstruct->get_name ()));
+  out <<
+    indent () << prefix << " = g_object_new (" << this->nspace_uc << "TYPE_" << name_uc << ", NULL);" << endl <<
+    indent () << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
+    indent () << "  return " << error_ret << ";" << endl <<
+    indent () << "xfer += ret;" << endl;
+}
+
+void
+t_c_glib_generator::generate_deserialize_container (ofstream &out, t_type *ttype,
+                                               string prefix, int error_ret)
+{
+  scope_up (out);
+
+  if (ttype->is_map ())
+  {
+    out <<
+      indent () << "guint32 size;" << endl <<
+      indent () << "ThriftType key_type;" << endl <<
+      indent () << "ThriftType value_type;" << endl <<
+      endl <<
+      indent () << "/* read the map begin marker */" << endl <<
+      indent () << "if ((ret = thrift_protocol_read_map_begin (protocol, &key_type, &value_type, &size, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl;
+
+    // iterate over map elements
+    out <<
+      indent () << "/* iterate through each of the map's fields */" << endl <<
+      indent () << "guint32 i;" << endl <<
+      indent () << "for (i = 0; i < size; i++)" << endl;
+    scope_up (out);
+    generate_deserialize_map_element (out, (t_map *) ttype, prefix, error_ret);
+    scope_down (out);
+    out << endl;
+  
+    // read map end
+    out <<
+      indent () << "/* read the map end marker */" << endl <<
+      indent () << "if ((ret = thrift_protocol_read_map_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl;
+  } else if (ttype->is_set ()) {
+    out <<
+      indent () << "guint32 size;" << endl <<
+      indent () << "ThriftType element_type;" << endl <<
+      indent () << "if ((ret = thrift_protocol_read_set_begin (protocol, &element_type, &size, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl;
+
+    // iterate over the elements
+    out <<
+      indent () << "/* iterate through the set elements */" << endl <<
+      indent () << "guint32 i;" << endl <<
+      indent () << "for (i = 0; i < size; ++i)" << endl;
+
+    scope_up (out);
+    generate_deserialize_set_element (out, (t_set *) ttype, prefix, error_ret);
+    scope_down (out);
+
+    // read set end
+    out <<
+      indent () << "if ((ret = thrift_protocol_read_set_end (protocol, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl;
+  } else if (ttype->is_list ()) {
+    out <<
+      indent () << "guint32 size;" << endl <<
+      indent () << "ThriftType element_type;" << endl <<
+      indent () << "if ((ret = thrift_protocol_read_list_begin (protocol, &element_type, &size, error)) < 0)" << endl <<
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl;
+
+    out <<
+      indent () << "/* iterate through list elements */" << endl <<
+      indent () << "guint32 i;" << endl <<
+      indent () << "for (i = 0; i < size; i++)" << endl;
+
+    scope_up (out);
+    generate_deserialize_list_element (out, (t_list *) ttype, prefix, "i",
+                                       error_ret);
+    scope_down (out);
+
+    out <<
+      indent () << "if ((ret = thrift_protocol_read_list_end (protocol, error)) < 0)" << endl << 
+      indent () << "  return " << error_ret << ";" << endl <<
+      indent () << "xfer += ret;" << endl <<
+      endl;
+  }
+
+  scope_down (out);
+}
+
+void
+t_c_glib_generator::generate_deserialize_map_element (ofstream &out, t_map *tmap,
+                                                 string prefix, int error_ret)
+{
+  t_type *tkey = tmap->get_key_type ();
+  t_type *tval = tmap->get_val_type ();
+  string tkey_name = type_name (tkey);
+  string tval_name = type_name (tval);
+  string tkey_ptr = tkey->is_string () || !tkey->is_base_type () ? "" : "*";
+  string tval_ptr = tval->is_string () || !tval->is_base_type () ? "" : "*";
+
+  string keyname = tmp("key");
+  string valname = tmp("val");
+
+  if (tkey->is_map ())
+  {
+    out <<
+      indent () << tkey_name << tkey_ptr << " " << keyname << " = g_hash_table_new (NULL, NULL);" << endl;
+  } else {
+    out <<
+      indent () << tkey_name << tkey_ptr << " " << keyname << (tkey_ptr != "" ? " = g_new (" + tkey_name + ", 1)" : "") << ";" << endl;
+  }
+
+  if (tval->is_map ())
+  {
+    out <<
+      indent () << tval_name << tval_ptr << " " << valname << " = g_hash_table_new (NULL, NULL);" << endl;
+  } else {
+    out <<
+      indent () << tval_name << tval_ptr << " " << valname << (tval_ptr != "" ? " = g_new (" + tval_name + ", 1)" : "") << ";" << endl;
+  }
+
+  // deserialize the fields of the map element
+  t_field fkey (tkey, tkey_ptr + keyname);
+  generate_deserialize_field (out, &fkey, "", "", error_ret);
+  t_field fval (tval, tval_ptr + valname);
+  generate_deserialize_field (out, &fval, "", "", error_ret);
+
+  // insert into the hashtable.  if the field is not a pointer, then use
+  // the address of the object.
+  indent (out) <<
+    "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << (tkey_ptr != "" ? "" : "&") << keyname << ", (gpointer) " << (tval_ptr != "" ? "" : "&") << valname << ");" << endl;
+}
+
+void
+t_c_glib_generator::generate_deserialize_set_element (ofstream &out, t_set *tset,
+                                                 string prefix, int error_ret)
+{
+  t_type *telem = tset->get_elem_type ();
+  string telem_name = type_name (telem);
+  string telem_ptr = telem->is_string () || !telem->is_base_type () ? "" : "*";
+
+  if (telem->is_map())
+  {
+    out <<
+      indent () << telem_name << telem_ptr << " elem = g_hash_table_new (NULL, NULL);" << endl;
+  } else {
+    out <<
+      indent () << telem_name << telem_ptr << " elem" << (telem_ptr != "" ? " = g_new (" + telem_name + ", 1)" : "") << ";" << endl;
+  }
+
+  t_field felem (telem, telem_ptr + "elem");
+  generate_deserialize_field (out, &felem, "", "", error_ret);
+
+  indent (out) <<
+    "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) elem, (gpointer) 1);" << endl;
+}
+
+void
+t_c_glib_generator::generate_deserialize_list_element (ofstream &out, t_list *tlist,
+                                                  string prefix, string index,
+                                                  int error_ret)
+{
+  string elem = tmp ("_elem");
+  t_field felem (tlist->get_elem_type (), elem);
+
+  indent (out) << declare_field (&felem, true) << endl;
+  generate_deserialize_field (out, &felem, "", "", error_ret);
+
+  indent (out);
+
+  t_type *ttype = tlist->get_elem_type ();
+  if (ttype->is_base_type ())
+  {
+    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base ();
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine array type";
+      case t_base_type::TYPE_STRING:
+        out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
+        return;
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_DOUBLE:
+        out << "g_array_append_val (" << prefix << ", " << elem << ");" << endl;
+        return;
+      default:
+        throw "compiler error: no array info for type";
+    }
+  }
+  out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
+}
+
+string
+t_c_glib_generator::generate_new_hash_from_type (t_type * ttype)
+{
+  if (ttype->is_base_type ())
+  {
+    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base ();
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine hash type";
+        break;
+      case t_base_type::TYPE_BOOL:
+        return "g_hash_table_new (thrift_gboolean_hash, thrift_gboolean_equal);";
+      case t_base_type::TYPE_BYTE:
+        return "g_hash_table_new (thrift_gint8_hash, thrift_gint8_equal);";
+      case t_base_type::TYPE_I16:
+        return "g_hash_table_new (thrift_gint16_hash, thrift_gint16_equal);";
+      case t_base_type::TYPE_I32:
+        return "g_hash_table_new (thrift_gint32_hash, thrift_gint32_equal);";
+      case t_base_type::TYPE_I64:
+        return "g_hash_table_new (thrift_gint64_hash, thrift_gint64_equal);";
+      case t_base_type::TYPE_DOUBLE:
+        return "g_hash_table_new (thrift_gdouble_hash, thrift_gdouble_equal);";
+      case t_base_type::TYPE_STRING:
+        return "g_hash_table_new (g_str_hash, g_str_equal);";
+      default:
+        throw "compiler error: no hash table info for type";
+    }
+  }
+  return "g_hash_table_new (NULL, NULL);";
+}
+
+string
+t_c_glib_generator::generate_new_array_from_type(t_type * ttype)
+{
+  if (ttype->is_base_type ())
+  {
+    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base ();
+    switch (tbase)
+    {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine array type";
+        break;
+      case t_base_type::TYPE_BOOL:
+        return "g_array_new (0, 1, sizeof (gboolean));";
+      case t_base_type::TYPE_BYTE:
+        return "g_array_new (0, 1, sizeof (gint8));";
+      case t_base_type::TYPE_I16:
+        return "g_array_new (0, 1, sizeof (gint16));";
+      case t_base_type::TYPE_I32:
+        return "g_array_new (0, 1, sizeof (gint32));";
+      case t_base_type::TYPE_I64:
+        return "g_array_new (0, 1, sizeof (gint64));";
+      case t_base_type::TYPE_DOUBLE:
+        return "g_array_new (0, 1, sizeof (gdouble));";
+      case t_base_type::TYPE_STRING:
+        return "g_ptr_array_new ();";
+      default:
+        throw "compiler error: no array info for type";
+    }
+  }
+  return "g_ptr_array_new ();";
+}
+
+
+/***************************************
+ * UTILITY FUNCTIONS                   *
+ ***************************************/
+
+/**
+ * Upper case a string.  Wraps boost's string utility.
+ */
+string
+to_upper_case (string name)
+{
+  string s (name);
+  std::transform (s.begin(), s.end(), s.begin(), ::toupper);
+  return s;
+//  return boost::to_upper_copy (name);
+}
+
+/**
+ * Lower case a string.  Wraps boost's string utility.
+ */
+string
+to_lower_case (string name)
+{
+  string s (name);
+  std::transform (s.begin(), s.end(), s.begin(), ::tolower);
+  return s;
+//  return boost::to_lower_copy (name);
+}
+
+/**
+ * Makes a string friendly to C code standards by lowercasing and adding
+ * underscores, with the exception of the first character.  For example:
+ *
+ * Input: "ZomgCamelCase"
+ * Output: "zomg_camel_case"
+ */
+string
+initial_caps_to_underscores (string name)
+{
+  string ret;
+  const char *tmp = name.c_str ();
+  int pos = 0;
+
+  /* the first character isn't underscored if uppercase, just lowercased */
+  ret += tolower (tmp[pos]);
+  pos++;
+  for (unsigned int i = pos; i < name.length (); i++)
+  {
+    char lc = tolower (tmp[i]); 
+    if (lc != tmp[i])
+    {
+      ret += '_';
+    }
+    ret += lc;
+  }
+
+  return ret;
+}
+
+/* register this generator with the main program */
+THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "");
+
+
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 320d1f0..440d151 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -209,6 +209,14 @@
     return cpp_includes_;
   }
 
+  void add_c_include(std::string path) {
+    c_includes_.push_back(path);
+  }
+
+  const std::vector<std::string>& get_c_includes() {
+    return c_includes_;
+  }
+
  private:
 
   // File path
@@ -247,6 +255,9 @@
   // C++ extra includes
   std::vector<std::string> cpp_includes_;
 
+  // C extra includes
+  std::vector<std::string> c_includes_;
+
 };
 
 #endif
diff --git a/configure.ac b/configure.ac
index d843efb..82896ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,6 +99,16 @@
 AM_CONDITIONAL([AMX_HAVE_LIBEVENT], [test "$have_libevent" = "yes"])
 AM_CONDITIONAL([AMX_HAVE_ZLIB], [test "$have_zlib" = "yes"])
 
+AX_THRIFT_LIB(c_glib, [C (GLib)], no)
+if test "$with_c_glib" = "yes"; then
+  PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.0], have_glib2=yes, have_glib2=no)
+  PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.0], have_gobject2=yes, have_gobject2=no)
+  if test "$have_glib2" = "yes" -a "$have_gobject2" = "yes" ; then
+    have_c_glib="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_C_GLIB, [test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"])
+
 AX_THRIFT_LIB(csharp, [C#], yes)
 if test "$with_csharp" = "yes";  then
   PKG_CHECK_MODULES(MONO, mono >= 2.0.0, net_3_5=yes, net_3_5=no)
@@ -279,6 +289,7 @@
 ])
 
 AC_FUNC_ALLOCA
+AC_FUNC_FORK
 AC_FUNC_MALLOC
 AC_FUNC_MEMCMP
 AC_FUNC_REALLOC
@@ -305,6 +316,7 @@
 AC_CHECK_FUNCS([strtol])
 AC_CHECK_FUNCS([sqrt])
 dnl The following functions are optional.
+AC_CHECK_FUNCS([alarm])
 AC_CHECK_FUNCS([clock_gettime])
 AC_CHECK_FUNCS([sched_get_priority_min])
 AC_CHECK_FUNCS([sched_get_priority_max])
@@ -323,6 +335,8 @@
 
 AX_THRIFT_GEN(cpp, [C++], yes)
 AM_CONDITIONAL([THRIFT_GEN_cpp], [test "$ax_thrift_gen_cpp" = "yes"])
+AX_THRIFT_GEN(c_glib, [C (GLib)], yes)
+AM_CONDITIONAL([THRIFT_GEN_c_glib], [test "$ax_thrift_gen_c_glib" = "yes"])
 AX_THRIFT_GEN(java, [Java], yes)
 AM_CONDITIONAL([THRIFT_GEN_java], [test "$ax_thrift_gen_java" = "yes"])
 AX_THRIFT_GEN(as3, [AS3], yes)
@@ -356,6 +370,29 @@
 AX_THRIFT_GEN(javame, [JavaME], yes)
 AM_CONDITIONAL([THRIFT_GEN_javame], [test "$ax_thrift_gen_javame" = "yes"])
 
+# --- Coverage hooks ---
+
+AC_ARG_ENABLE(coverage,
+              [  --enable-coverage      turn on -fprofile-arcs -ftest-coverage],
+              [case "${enableval}" in
+                yes) ENABLE_COVERAGE=1 ;;
+                no) ENABLE_COVERAGE=0 ;;
+                *) AC_MSG_ERROR(bad value ${enableval} for --enable-cov) ;;
+              esac],
+              [ENABLE_COVERAGE=2])
+
+if test "x[$]ENABLE_COVERAGE" = "x1"; then
+  AC_MSG_WARN(enable coverage)
+  GCOV_CFLAGS="`echo \"[$]CFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage"
+  GCOV_CXXFLAGS="`echo \"[$]CXXFLAGS\" | perl -pe 's/-O\d+//g;'` -fprofile-arcs -ftest-coverage"
+  GCOV_LDFLAGS="-XCClinker -fprofile-arcs -XCClinker -ftest-coverage"
+fi
+
+AC_SUBST(ENABLE_COVERAGE)
+AC_SUBST(GCOV_CFLAGS)
+AC_SUBST(GCOV_CXXFLAGS)
+AC_SUBST(GCOV_LDFLAGS)
+
 AC_CONFIG_HEADERS(config.h:config.hin)
 
 AC_CONFIG_FILES([
@@ -368,6 +405,9 @@
   lib/cpp/thrift-nb.pc
   lib/cpp/thrift-z.pc
   lib/cpp/thrift.pc
+  lib/c_glib/Makefile
+  lib/c_glib/thrift_c_glib.pc
+  lib/c_glib/test/Makefile
   lib/csharp/Makefile
   lib/erl/Makefile
   lib/erl/src/Makefile
@@ -385,6 +425,9 @@
   test/rb/Makefile
 ])
 
+AC_CONFIG_FILES([lib/c_glib/test/test-wrapper.sh],
+                [chmod +x lib/c_glib/test/test-wrapper.sh])
+
 AC_OUTPUT
 
 
@@ -394,6 +437,7 @@
 echo "Building code generators ..... :$thrift_generators"
 echo
 echo "Building C++ Library ......... : $have_cpp"
+echo "Building C (GLib) Library .... : $have_c_glib"
 echo "Building Java Library ........ : $have_java"
 echo "Building C# Library .......... : $have_csharp"
 echo "Building Python Library ...... : $have_python"
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
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
index b01129a..7980047 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+namespace c_glib TTest
 namespace cpp thrift.test.debug
 namespace java thrift.test
 
diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift
index 67e6f58..8108a7f 100644
--- a/test/OptionalRequiredTest.thrift
+++ b/test/OptionalRequiredTest.thrift
@@ -21,6 +21,7 @@
  * details.
  */
 
+namespace c_glib TTest
 namespace cpp thrift.test
 namespace java thrift.test
 
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index ce324ef..237023b 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -21,6 +21,7 @@
  * details.
  */
 
+namespace c_glib TTest
 namespace java thrift.test
 namespace cpp thrift.test
 namespace rb Thrift.Test