THRIFT-5237 Implement MAX_MESSAGE_SIZE and consolidate limits into a TConfiguration class
Client: c_glib
Patch: Zezeng Wang

This closes #2208
diff --git a/lib/c_glib/test/testthriftfdreadcheck.c b/lib/c_glib/test/testthriftfdreadcheck.c
new file mode 100755
index 0000000..986b70d
--- /dev/null
+++ b/lib/c_glib/test/testthriftfdreadcheck.c
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_fd_transport.h>
+
+#define MAX_MESSAGE_SIZE 2
+
+static const gchar TEST_DATA[12] = "abcde01234!";
+
+static void
+test_open_and_close (void)
+{
+  ThriftConfiguration *configuration;
+  ThriftTransport *transport;
+  ThriftTransportClass *klass;
+  GError *error;
+  gint fd;
+  gchar *filename;
+
+  error = NULL;
+  filename = NULL;
+
+  fd = g_file_open_tmp (NULL, &filename, &error);
+  g_assert (fd >= 0);
+
+  configuration = g_object_new (THRIFT_TYPE_CONFIGURATION, "max_message_size", MAX_MESSAGE_SIZE,
+                                "max_frame_size", MAX_MESSAGE_SIZE, NULL);
+
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "configuration", configuration, "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  /* open is no-op */
+  g_assert (klass->is_open (transport));
+  g_assert (klass->peek (transport, &error));
+  g_assert (klass->open (transport, &error));
+  g_assert (klass->is_open (transport));
+  g_assert (klass->peek (transport, &error));
+
+  g_assert (klass->close (transport, &error));
+  g_assert (! klass->open (transport, &error));
+  g_assert (! klass->is_open (transport));
+  g_assert (! klass->peek (transport, &error));
+
+  /* already closed */
+  g_assert (close (fd) != 0);
+  g_assert (errno == EBADF);
+
+  g_object_unref (transport);
+  g_object_unref (configuration);
+
+  g_remove (filename);
+  g_free (filename);
+
+  /* test bad fd */
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "fd", -1,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  g_assert (! klass->is_open (transport));
+  error = NULL;
+  g_assert (! klass->peek (transport, &error));
+  error = NULL;
+  g_assert (! klass->open (transport, &error));
+  error = NULL;
+  g_assert (! klass->close (transport, &error));
+
+  g_object_unref (transport);
+}
+
+static void
+test_read_and_write (void)
+{
+  gchar out_buf[8];
+  gchar *b;
+  gint want, got;
+  ThriftConfiguration *configuration;
+  ThriftTransport *transport;
+  ThriftTransportClass *klass;
+  GError *error;
+  gint fd;
+  gchar *filename;
+
+  error = NULL;
+  filename = NULL;
+
+  fd = g_file_open_tmp (NULL, &filename, &error);
+  g_assert (fd >= 0);
+
+  configuration = g_object_new (THRIFT_TYPE_CONFIGURATION, "max_message_size", MAX_MESSAGE_SIZE,
+                                "max_frame_size", MAX_MESSAGE_SIZE, NULL);
+  /* write */
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                             "configuration", configuration, "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+  g_assert (klass->is_open (transport));
+  g_assert (klass->write (transport, (gpointer) TEST_DATA, 11, &error));
+  g_assert (klass->flush (transport, &error));
+  g_assert (klass->close (transport, &error));
+  g_object_unref (transport);
+
+  /* read */
+  fd = open(filename, O_RDONLY, S_IRUSR | S_IWUSR);
+  g_assert (fd >= 0);
+
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "configuration", configuration, 
+                                              "remainingmessagesize", MAX_MESSAGE_SIZE, 
+                                              "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  memset(out_buf, 0, 8);
+  b = out_buf;
+  want = 2;
+  while (want > 0) {
+    got = klass->read (transport, (gpointer) b, want, &error);
+    g_assert (got > 0 && got <= want);
+    b += got;
+    want -= got;
+  }
+  g_assert (memcmp (out_buf, TEST_DATA, 2) == 0);
+
+  memset(out_buf, 0, 8);
+  b = out_buf;
+  want = 4;
+  got = klass->read (transport, (gpointer) b, want, &error);
+  g_assert (got < 0);
+
+  g_assert (klass->close (transport, &error));
+  g_object_unref (transport);
+  g_object_unref (configuration);
+
+  /* clean up */
+
+  g_remove (filename);
+  g_free (filename);
+}
+
+int
+main (int argc, char *argv[])
+{
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/testfdtransport/OpenAndClose", test_open_and_close);
+  g_test_add_func ("/testfdtransport/ReadAndWrite", test_read_and_write);
+
+  return g_test_run ();
+}