THRIFT-2680 c_glib: ThriftFramedTransport fails when peer unexpectedly closes connection

Patch: Simon South
diff --git a/lib/c_glib/test/testframedtransport.c b/lib/c_glib/test/testframedtransport.c
index 03c9f9b..843ad93 100755
--- a/lib/c_glib/test/testframedtransport.c
+++ b/lib/c_glib/test/testframedtransport.c
@@ -144,6 +144,92 @@
   }
 }
 
+/* test reading from the transport after the peer has unexpectedly
+   closed the connection */
+static void
+test_read_after_peer_close(void)
+{
+  int status;
+  pid_t pid;
+  int port = 51199;
+  GError *err = NULL;
+
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    ThriftServerTransport *server_transport = NULL;
+    ThriftTransport *client_transport = NULL;
+
+    /* 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, &err);
+    g_assert (err == NULL);
+
+    /* wrap the client transport in a ThriftFramedTransport */
+    client_transport = g_object_new
+      (THRIFT_TYPE_FRAMED_TRANSPORT,
+       "transport",  thrift_server_transport_accept (server_transport, &err),
+       "r_buf_size", 0,
+       NULL);
+    g_assert (err == NULL);
+    g_assert (client_transport != NULL);
+
+    /* close the connection immediately after the client connects */
+    thrift_transport_close (client_transport, NULL);
+
+    g_object_unref (client_transport);
+    g_object_unref (server_transport);
+
+    exit (0);
+  } else {
+    ThriftSocket *tsocket = NULL;
+    ThriftTransport *transport = NULL;
+    guchar buf[10]; /* a buffer */
+
+    /* 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", 0,
+                              NULL);
+
+    g_assert (thrift_transport_open (transport, NULL) == TRUE);
+    g_assert (thrift_transport_is_open (transport));
+
+    /* attempting to read from the transport after the peer has closed
+       the connection fails gracefully without generating a critical
+       warning or segmentation fault */
+    thrift_transport_read (transport, buf, 10, &err);
+    g_assert (err != NULL);
+
+    g_error_free (err);
+    err = NULL;
+
+    thrift_transport_read_end (transport, &err);
+    g_assert (err == NULL);
+
+    thrift_transport_close (transport, &err);
+    g_assert (err == NULL);
+
+    g_object_unref (transport);
+    g_object_unref (tsocket);
+
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
 static void
 thrift_server (const int port)
 {
@@ -191,6 +277,7 @@
   g_test_add_func ("/testframedtransport/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testframedtransport/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testframedtransport/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testframedtransport/ReadAfterPeerClose", test_read_after_peer_close);
 
   return g_test_run ();
 }