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 (); }
