You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by ro...@apache.org on 2014/09/29 20:31:52 UTC

[2/3] THRIFT-2709 c_glib: Support server implementation

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h
----------------------------------------------------------------------
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h
new file mode 100644
index 0000000..c3e9496
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_FRAMED_TRANSPORT_FACTORY_H
+#define _THRIFT_FRAMED_TRANSPORT_FACTORY_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_transport_factory.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_framed_transport_factory.h
+ *  \brief Wraps a transport with a ThriftFramedTransport.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY    \
+  (thrift_framed_transport_factory_get_type ())
+#define THRIFT_FRAMED_TRANSPORT_FACTORY(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,    \
+                               ThriftFramedTransportFactory))
+#define THRIFT_IS_FRAMED_TRANSPORT_FACTORY(obj)                         \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY))
+#define THRIFT_FRAMED_TRANSPORT_FACTORY_CLASS(c)                        \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                        \
+                            THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,       \
+                            ThriftFramedTransportFactoryClass))
+#define THRIFT_IS_FRAMED_TRANSPORT_FACTORY_CLASS(c)                     \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                        \
+                            THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY))
+#define THRIFT_FRAMED_TRANSPORT_FACTORY_GET_CLASS(obj)                  \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,     \
+                              ThriftFramedTransportFactoryClass))
+
+typedef struct _ThriftFramedTransportFactory ThriftFramedTransportFactory;
+
+/* Thrift Framed-Transport Factory instance */
+struct _ThriftFramedTransportFactory
+{
+  ThriftTransportFactory parent;
+};
+
+typedef struct _ThriftFramedTransportFactoryClass ThriftFramedTransportFactoryClass;
+
+/* Thrift Framed-Transport Factory class */
+struct _ThriftFramedTransportFactoryClass
+{
+  ThriftTransportFactoryClass parent;
+
+  /* vtable */
+  ThriftTransport *(*get_transport) (ThriftTransportFactory *factory,
+                                     ThriftTransport *transport);
+};
+
+/* used by THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY */
+GType thrift_framed_transport_factory_get_type (void);
+
+/* virtual public methods */
+ThriftTransport *
+thrift_framed_transport_factory_get_transport (ThriftTransportFactory *factory,
+                                               ThriftTransport *transport);
+
+G_END_DECLS
+
+#endif /* _THRIFT_FRAMED_TRANSPORT_FACTORY_H */

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
----------------------------------------------------------------------
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
index 1313577..6bc9af3 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
@@ -50,6 +50,54 @@ thrift_socket_is_open (ThriftTransport *transport)
   return socket->sd != THRIFT_INVALID_SOCKET;
 }
 
+/* overrides thrift_transport_peek */
+gboolean
+thrift_socket_peek (ThriftTransport *transport, GError **error)
+{
+  gboolean result = FALSE;
+  guint8 buf;
+  int r;
+  int errno_copy;
+
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+
+  if (thrift_socket_is_open (transport))
+  {
+    r = recv (socket->sd, &buf, 1, MSG_PEEK);
+    if (r == -1)
+    {
+      errno_copy = errno;
+
+      #if defined __FreeBSD__ || defined __MACH__
+      /* FreeBSD returns -1 and ECONNRESET if the socket was closed by the other
+         side */
+      if (errno_copy == ECONNRESET)
+      {
+        thrift_socket_close (transport, error);
+      }
+      else
+      {
+      #endif
+
+      g_set_error (error,
+                   THRIFT_TRANSPORT_ERROR,
+                   THRIFT_TRANSPORT_ERROR_SOCKET,
+                   "failed to peek at socket - %s",
+                   strerror (errno_copy));
+
+      #if defined __FreeBSD__ || defined __MACH__
+      }
+      #endif
+    }
+    else if (r > 0)
+    {
+      result = TRUE;
+    }
+  }
+
+  return result;
+}
+
 /* implements thrift_transport_open */
 gboolean
 thrift_socket_open (ThriftTransport *transport, GError **error)
@@ -311,6 +359,7 @@ thrift_socket_class_init (ThriftSocketClass *cls)
 
   gobject_class->finalize = thrift_socket_finalize;
   ttc->is_open = thrift_socket_is_open;
+  ttc->peek = thrift_socket_peek;
   ttc->open = thrift_socket_open;
   ttc->close = thrift_socket_close;
   ttc->read = thrift_socket_read;

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
----------------------------------------------------------------------
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
index 59d464c..5533437 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
@@ -32,6 +32,12 @@ thrift_transport_is_open (ThriftTransport *transport)
 }
 
 gboolean
+thrift_transport_peek (ThriftTransport *transport, GError **error)
+{
+  return THRIFT_TRANSPORT_GET_CLASS (transport)->peek (transport, error);
+}
+
+gboolean
 thrift_transport_open (ThriftTransport *transport, GError **error)
 {
   return THRIFT_TRANSPORT_GET_CLASS (transport)->open (transport, error);
@@ -79,6 +85,15 @@ thrift_transport_flush (ThriftTransport *transport, GError **error)
   return THRIFT_TRANSPORT_GET_CLASS (transport)->flush (transport, error);
 }
 
+/* by default, peek returns true if and only if the transport is open */
+static gboolean
+thrift_transport_real_peek (ThriftTransport *transport, GError **error)
+{
+  THRIFT_UNUSED_VAR (error);
+
+  return THRIFT_TRANSPORT_GET_CLASS (transport)->is_open (transport);
+}
+
 /* define the GError domain for Thrift transports */
 GQuark
 thrift_transport_error_quark (void)
@@ -99,6 +114,9 @@ thrift_transport_class_init (ThriftTransportClass *cls)
   cls->write = thrift_transport_write;
   cls->write_end = thrift_transport_write_end;
   cls->flush = thrift_transport_flush;
+
+  /* provide a default implementation for the peek method */
+  cls->peek = thrift_transport_real_peek;
 }
 
 static void

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
----------------------------------------------------------------------
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
index 65b5763..5555a5e 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
@@ -63,6 +63,7 @@ struct _ThriftTransportClass
 
   /* vtable */
   gboolean (*is_open) (ThriftTransport *transport);
+  gboolean (*peek) (ThriftTransport *transport, GError **error);
   gboolean (*open) (ThriftTransport *transport, GError **error);
   gboolean (*close) (ThriftTransport *transport, GError **error);
   gint32 (*read) (ThriftTransport *transport, gpointer buf,
@@ -92,6 +93,17 @@ gboolean thrift_transport_is_open (ThriftTransport *transport);
 gboolean thrift_transport_open (ThriftTransport *transport, GError **error);
 
 /*!
+ * Tests whether there is more data to read or if the remote side is still
+ * open. By default this is true whenever the transport is open, but
+ * implementations should add logic to test for this condition where possible
+ * (i.e. on a socket).
+ *
+ * This is used by a server to check if it should listen for another request.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_peek (ThriftTransport *transport, GError **error);
+
+/*!
  * Close the transport.
  * \public \memberof ThriftTransportInterface
  */

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/test/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 25f474a..72d0f64 100755
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -52,6 +52,7 @@ testapplicationexception_LDADD = \
 testtransportsocket_SOURCES = testtransportsocket.c
 testtransportsocket_LDADD = \
     ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_buffered_transport.o \
     ../libthrift_c_glib_la-thrift_server_transport.o \
     ../libthrift_c_glib_la-thrift_server_socket.o
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/test/testsimpleserver.c
----------------------------------------------------------------------
diff --git a/lib/c_glib/test/testsimpleserver.c b/lib/c_glib/test/testsimpleserver.c
index fca2dcd..92629b4 100755
--- a/lib/c_glib/test/testsimpleserver.c
+++ b/lib/c_glib/test/testsimpleserver.c
@@ -51,7 +51,7 @@ G_DEFINE_TYPE(TestProcessor, test_processor, THRIFT_TYPE_PROCESSOR)
 
 gboolean
 test_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
-                        ThriftProtocol *out)
+                        ThriftProtocol *out, GError **error)
 {
   return FALSE;
 }
@@ -88,7 +88,8 @@ test_server (void)
 
   if (pid == 0)
   {
-    THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss));
+    THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss),
+                                                         NULL);
     exit (0);
   } else {
     sleep (5);

http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/test/testtransportsocket.c
----------------------------------------------------------------------
diff --git a/lib/c_glib/test/testtransportsocket.c b/lib/c_glib/test/testtransportsocket.c
index 836ddd0..08cad1c 100755
--- a/lib/c_glib/test/testtransportsocket.c
+++ b/lib/c_glib/test/testtransportsocket.c
@@ -19,8 +19,10 @@
 
 #include <assert.h>
 #include <netdb.h>
+#include <sys/wait.h>
 
 #include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
 #include <thrift/c_glib/transport/thrift_server_transport.h>
 #include <thrift/c_glib/transport/thrift_server_socket.h>
 
@@ -173,6 +175,105 @@ test_read_and_write(void)
   }
 }
 
+/* test ThriftSocket's peek() implementation */
+static void
+test_peek(void)
+{
+  gint status;
+  pid_t pid;
+  guint port = 51199;
+  gchar data = 'A';
+  ThriftTransport *client_transport;
+  GError *error = NULL;
+
+  client_transport = g_object_new (THRIFT_TYPE_SOCKET,
+                                   "hostname", "localhost",
+                                   "port",     port,
+                                   NULL);
+
+  /* thrift_transport_peek returns FALSE when the socket is closed */
+  g_assert (thrift_transport_is_open (client_transport) == FALSE);
+  g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+  g_assert (error == NULL);
+
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    ThriftServerTransport *server_transport = NULL;
+
+    g_object_unref (client_transport);
+
+    /* child listens */
+    server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                     "port", port,
+                                     NULL);
+    g_assert (server_transport != NULL);
+
+    thrift_server_transport_listen (server_transport, &error);
+    g_assert (error == NULL);
+
+    client_transport = g_object_new
+      (THRIFT_TYPE_BUFFERED_TRANSPORT,
+       "transport",  thrift_server_transport_accept (server_transport, &error),
+       "r_buf_size", 0,
+       "w_buf_size", sizeof data,
+       NULL);
+    g_assert (error == NULL);
+    g_assert (client_transport != NULL);
+
+    /* write exactly one character to the client */
+    g_assert (thrift_transport_write (client_transport,
+                                      &data,
+                                      sizeof data,
+                                      &error) == TRUE);
+
+    thrift_transport_flush (client_transport, &error);
+    thrift_transport_write_end (client_transport, &error);
+    thrift_transport_close (client_transport, &error);
+
+    g_object_unref (client_transport);
+    g_object_unref (server_transport);
+
+    exit (0);
+  }
+  else {
+    /* parent connects, wait a bit for the socket to be created */
+    sleep (1);
+
+    /* connect to the child */
+    thrift_transport_open (client_transport, &error);
+    g_assert (error == NULL);
+    g_assert (thrift_transport_is_open (client_transport) == TRUE);
+
+    /* thrift_transport_peek returns TRUE when the socket is open and there is
+       data available to be read */
+    g_assert (thrift_transport_peek (client_transport, &error) == TRUE);
+    g_assert (error == NULL);
+
+    /* read exactly one character from the server */
+    g_assert_cmpint (thrift_transport_read (client_transport,
+                                            &data,
+                                            sizeof data,
+                                            &error), ==, sizeof data);
+
+    /* thrift_transport_peek returns FALSE when the socket is open but there is
+       no (more) data available to be read */
+    g_assert (thrift_transport_is_open (client_transport) == TRUE);
+    g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+    g_assert (error == NULL);
+
+    thrift_transport_read_end (client_transport, &error);
+    thrift_transport_close (client_transport, &error);
+
+    g_object_unref (client_transport);
+
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
 static void
 thrift_socket_server (const int port)
 {
@@ -215,6 +316,7 @@ main(int argc, char *argv[])
   g_test_add_func ("/testtransportsocket/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testtransportsocket/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testtransportsocket/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testtransportsocket/Peek", test_peek);
 
   return g_test_run ();
 }