diff options
author | Gonzalo Aguilar Delgado <gaguilar@level2crm.com> | 2017-09-15 12:26:02 +0200 |
---|---|---|
committer | James E. King, III <jking@apache.org> | 2017-11-18 21:10:18 -0500 |
commit | 87ad2bcaaa5a9fe224ad7a9826b676ca9721ddd1 (patch) | |
tree | b8aca3ee0e996f76f9881e1306d6e5bb8ed3b371 | |
parent | 95d5fb3a1e38125b9eabcbe9cda1a6c7bbe3e93d (diff) | |
download | thrift-87ad2bcaaa5a9fe224ad7a9826b676ca9721ddd1.tar.gz |
THRIFT-4329: multiplexed processor, client and server for c_glib
Client: c_glib
This closes #1361
24 files changed, 1896 insertions, 797 deletions
diff --git a/lib/c_glib/CMakeLists.txt b/lib/c_glib/CMakeLists.txt index 5e277f05b..3743a68dd 100644 --- a/lib/c_glib/CMakeLists.txt +++ b/lib/c_glib/CMakeLists.txt @@ -33,9 +33,12 @@ set(thrift_c_glib_SOURCES src/thrift/c_glib/thrift_application_exception.c src/thrift/c_glib/processor/thrift_processor.c src/thrift/c_glib/processor/thrift_dispatch_processor.c + src/thrift/c_glib/processor/thrift_multiplexed_processor.c src/thrift/c_glib/protocol/thrift_protocol.c src/thrift/c_glib/protocol/thrift_protocol_factory.c + src/thrift/c_glib/protocol/thrift_protocol_decorator.c src/thrift/c_glib/protocol/thrift_binary_protocol.c + src/thrift/c_glib/protocol/thrift_stored_message_protocol.c src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c src/thrift/c_glib/protocol/thrift_compact_protocol.c src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am index 871766bdf..49b5b238c 100755 --- a/lib/c_glib/Makefile.am +++ b/lib/c_glib/Makefile.am @@ -34,10 +34,12 @@ libthrift_c_glib_la_SOURCES = src/thrift/c_glib/thrift.c \ src/thrift/c_glib/thrift_application_exception.c \ src/thrift/c_glib/processor/thrift_processor.c \ src/thrift/c_glib/processor/thrift_dispatch_processor.c \ + src/thrift/c_glib/processor/thrift_multiplexed_processor.c \ src/thrift/c_glib/protocol/thrift_protocol.c \ src/thrift/c_glib/protocol/thrift_protocol_decorator.c \ src/thrift/c_glib/protocol/thrift_protocol_factory.c \ src/thrift/c_glib/protocol/thrift_binary_protocol.c \ + src/thrift/c_glib/protocol/thrift_stored_message_protocol.c \ src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c \ src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c \ src/thrift/c_glib/protocol/thrift_compact_protocol.c \ @@ -75,7 +77,9 @@ include_protocol_HEADERS = src/thrift/c_glib/protocol/thrift_protocol.h \ src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h \ src/thrift/c_glib/protocol/thrift_compact_protocol.h \ src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h \ - src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h + src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h \ + src/thrift/c_glib/protocol/thrift_stored_message_protocol.h + include_transportdir = $(include_thriftdir)/transport include_transport_HEADERS = src/thrift/c_glib/transport/thrift_buffered_transport.h \ @@ -98,7 +102,8 @@ include_server_HEADERS = src/thrift/c_glib/server/thrift_server.h \ include_processordir = $(include_thriftdir)/processor include_processor_HEADERS = src/thrift/c_glib/processor/thrift_processor.h \ - src/thrift/c_glib/processor/thrift_dispatch_processor.h + src/thrift/c_glib/processor/thrift_dispatch_processor.h \ + src/thrift/c_glib/processor/thrift_multiplexed_processor.h EXTRA_DIST = \ diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c new file mode 100644 index 000000000..68a0f4d46 --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c @@ -0,0 +1,346 @@ +/* + * 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 <stdio.h> + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/processor/thrift_processor.h> +#include <thrift/c_glib/processor/thrift_multiplexed_processor.h> +#include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h> +#include <thrift/c_glib/protocol/thrift_stored_message_protocol.h> +#include <thrift/c_glib/thrift_application_exception.h> + +G_DEFINE_TYPE(ThriftMultiplexedProcessor, thrift_multiplexed_processor, THRIFT_TYPE_PROCESSOR) + + +enum +{ + PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME = 1, + PROP_THRIFT_MULTIPLEXED_PROCESSOR_END +}; + +static GParamSpec *thrift_multiplexed_processor_obj_properties[PROP_THRIFT_MULTIPLEXED_PROCESSOR_END] = { NULL, }; + + +static gboolean +thrift_multiplexed_processor_register_processor_impl(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error) +{ + ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(processor); + g_hash_table_replace(self->multiplexed_services, + g_strdup(multiplexed_processor_name), + g_object_ref (multiplexed_processor)); + + /* Make first registered become default */ + if(!self->default_processor_name){ + self->default_processor_name = g_strdup(multiplexed_processor_name); + } + return TRUE; +} + + +static gboolean +thrift_multiplexed_processor_process_impl (ThriftProcessor *processor, ThriftProtocol *in, + ThriftProtocol *out, GError **error) +{ + gboolean retval = FALSE; + gboolean token_error = FALSE; + ThriftApplicationException *xception; + ThriftStoredMessageProtocol *stored_message_protocol = NULL; + ThriftMessageType message_type; + ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(processor); + ThriftProcessor *multiplexed_processor = NULL; + ThriftTransport *transport; + char *token=NULL; + int token_index=0; + char *state=NULL; + gchar *fname=NULL; + gint32 seqid, result; + + /* FIXME It seems that previous processor is not managing error correctly */ + if(*error!=NULL) { + g_debug ("thrift_multiplexed_processor: last error not removed: %s", + *error != NULL ? (*error)->message : "(null)"); + g_clear_error (error); + } + + + THRIFT_PROTOCOL_GET_CLASS(in)->read_message_begin(in, &fname, &message_type, &seqid, error); + + if(!(message_type == T_CALL || message_type == T_ONEWAY)) { + g_set_error (error, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_TYPE, + "message type invalid for this processor"); + }else{ + /* Split by the token */ + for (token = strtok_r(fname, THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR, &state), + token_index=0; + token != NULL && !token_error; + token = strtok_r(NULL, THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR, &state), + token_index++) + { + switch(token_index){ + case 0: + /* It should be the service name */ + multiplexed_processor = g_hash_table_lookup(self->multiplexed_services, token); + if(multiplexed_processor==NULL){ + token_error=TRUE; + } + break; + case 1: + /* It should be the function name */ + stored_message_protocol = g_object_new (THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, + "protocol", in, + "name", token, + "type", message_type, + "seqid", seqid, + NULL); + break; + default: + g_set_error (error, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_WRONGLY_MULTIPLEXED, + "the message has more tokens than expected!"); + token_error=TRUE; + break; + } + } + /* Set default */ + if(!stored_message_protocol && + !multiplexed_processor && + token_index==1 && self->default_processor_name){ + /* It should be the service name */ + multiplexed_processor = g_hash_table_lookup(self->multiplexed_services, self->default_processor_name); + if(multiplexed_processor==NULL){ + g_set_error (error, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE, + "service %s not available on this processor", + self->default_processor_name); + }else{ + /* Set the message name to the original name */ + stored_message_protocol = g_object_new (THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, + "protocol", in, + "name", fname, + "type", message_type, + "seqid", seqid, + NULL); + } + + } + + if(stored_message_protocol!=NULL && multiplexed_processor!=NULL){ + retval = THRIFT_PROCESSOR_GET_CLASS (multiplexed_processor)->process (multiplexed_processor, (ThriftProtocol *) stored_message_protocol, out, error) ; + }else{ + if(!error) + g_set_error (error, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE, + "service %s is not multiplexed in this processor", + fname); + } + + + } + + if(!retval){ + /* By default, return an application exception to the client indicating the + method name is not recognized. */ + /* Copied from dispach processor */ + + if ((thrift_protocol_skip (in, T_STRUCT, error) < 0) || + (thrift_protocol_read_message_end (in, error) < 0)) + return retval; + + g_object_get (in, "transport", &transport, NULL); + result = thrift_transport_read_end (transport, error); + g_object_unref (transport); + if (result < 0) { + /* We must free fname */ + g_free(fname); + return retval; + } + + if (thrift_protocol_write_message_begin (out, + fname, + T_EXCEPTION, + seqid, + error) < 0){ + /* We must free fname */ + g_free(fname); + + return retval; + } + + + xception = + g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, + "type", THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD, + "message", (*error)->message, + NULL); + result = thrift_struct_write (THRIFT_STRUCT (xception), + out, + error); + g_object_unref (xception); + if ((result < 0) || + (thrift_protocol_write_message_end (out, error) < 0)) + return retval; + + g_object_get (out, "transport", &transport, NULL); + retval = + ((thrift_transport_write_end (transport, error) >= 0) && + (thrift_transport_flush (transport, error) >= 0)); + g_object_unref (transport); + }else{ + /* The protocol now has a copy we can free it */ + g_free(fname); + + } + + /* + FIXME This makes everything fail, I don't know why. + if(stored_message_protocol!=NULL){ + // After its use we must free it + g_object_unref(stored_message_protocol); + } + */ + return retval; +} + +/* define the GError domain for Thrift transports */ +GQuark +thrift_multiplexed_processor_error_quark (void) +{ + return g_quark_from_static_string (THRIFT_MULTIPLEXED_PROCESSOR_ERROR_DOMAIN); +} + + +static void +thrift_multiplexed_processor_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR (object); + + switch (property_id) + { + case PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME: + self->default_processor_name = g_value_dup_string (value); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +thrift_multiplexed_processor_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR (object); + + switch (property_id) + { + case PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME: + g_value_set_string (value, self->default_processor_name); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/* destructor */ +static void +thrift_multiplexed_processor_finalize (GObject *object) +{ + ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(object); + + /* Free our multiplexed hash table */ + g_hash_table_unref (self->multiplexed_services); + self->multiplexed_services = NULL; + + if(self->default_processor_name){ + g_free(self->default_processor_name); + self->default_processor_name=NULL; + } + + /* Chain up to parent */ + if (G_OBJECT_CLASS (thrift_multiplexed_processor_parent_class)->finalize) + (*G_OBJECT_CLASS (thrift_multiplexed_processor_parent_class)->finalize) (object); +} + +/* class initializer for ThriftMultiplexedProcessor */ +static void +thrift_multiplexed_processor_class_init (ThriftMultiplexedProcessorClass *cls) +{ + /* Override */ + THRIFT_PROCESSOR_CLASS(cls)->process = thrift_multiplexed_processor_process_impl; + GObjectClass *gobject_class = G_OBJECT_CLASS (cls); + + /* Object methods */ + gobject_class->set_property = thrift_multiplexed_processor_set_property; + gobject_class->get_property = thrift_multiplexed_processor_get_property; + gobject_class->finalize = thrift_multiplexed_processor_finalize; + + /* Class methods */ + cls->register_processor = thrift_multiplexed_processor_register_processor_impl; + + + thrift_multiplexed_processor_obj_properties[PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME] = + g_param_spec_string ("default", + "Default service name the protocol points to where no multiplexed client used", + "Set the default service name", + NULL, + (G_PARAM_READWRITE)); + + g_object_class_install_properties (gobject_class, + PROP_THRIFT_MULTIPLEXED_PROCESSOR_END, + thrift_multiplexed_processor_obj_properties); + +} + +static void +thrift_multiplexed_processor_init (ThriftMultiplexedProcessor *self) +{ + + /* Create our multiplexed services hash table */ + self->multiplexed_services = g_hash_table_new_full ( + g_str_hash, + g_str_equal, + g_free, + g_object_unref); + self->default_processor_name = NULL; +} + + +gboolean +thrift_multiplexed_processor_register_processor(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error) +{ + return THRIFT_MULTIPLEXED_PROCESSOR_GET_CLASS(processor)->register_processor(processor, multiplexed_processor_name, multiplexed_processor, error); +} + + diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h new file mode 100644 index 000000000..6406616c2 --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h @@ -0,0 +1,114 @@ +/* + * thrift_multiplexed_processor.h + * + * Created on: 14 sept. 2017 + * Author: gaguilar + */ + +#ifndef _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_ +#define _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_ + + +#include <glib-object.h> + +#include <thrift/c_glib/processor/thrift_processor.h> + + +G_BEGIN_DECLS + +/*! \file thrift_multiplexed_processor.h + * \brief The multiplexed processor for c_glib. + */ + +/* type macros */ +#define THRIFT_TYPE_MULTIPLEXED_PROCESSOR (thrift_multiplexed_processor_get_type ()) +#define THRIFT_MULTIPLEXED_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessor)) +#define THRIFT_IS_MULTIPLEXED_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR)) +#define THRIFT_MULTIPLEXED_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessorClass)) +#define THRIFT_IS_MULTIPLEXED_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_MULTIPLEXED_PROCESSOR)) +#define THRIFT_MULTIPLEXED_PROCESSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessorClass)) + +/* define the GError domain string */ +#define THRIFT_MULTIPLEXED_PROCESSOR_ERROR_DOMAIN "thrift-multiplexed-processor-error-quark" + + +/*! + * Thrift MultiplexedProcessor object + */ +struct _ThriftMultiplexedProcessor +{ + ThriftProcessor parent; + + /* private */ + gchar * default_processor_name; + GHashTable *multiplexed_services; +}; +typedef struct _ThriftMultiplexedProcessor ThriftMultiplexedProcessor; + +/*! + * Thrift MultiplexedProcessor class + */ +struct _ThriftMultiplexedProcessorClass +{ + ThriftProcessorClass parent; + + gboolean (* register_processor) (ThriftProcessor *self, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error); + +}; +typedef struct _ThriftMultiplexedProcessorClass ThriftMultiplexedProcessorClass; + +/* used by THRIFT_TYPE_MULTIPLEXED_PROCESSOR */ +GType thrift_multiplexed_processor_get_type (void); + +/*! + * Processes the request. + * \public \memberof ThriftMultiplexedProcessorClass + */ +gboolean thrift_multiplexed_processor_process (ThriftMultiplexedProcessor *processor, + ThriftProtocol *in, ThriftProtocol *out, + GError **error); + + +/* Public API */ + +/** + * @brief Registers a processor in the multiplexed processor under its name. It + * will take a reference to the processor so refcount will be incremented. + * It will also be decremented on object destruction. + * + * The first registered processor becomes default. But you can override it with + * "default" property. + * + * It returns a compliant error if it cannot be registered. + * + * @param processor Pointer to the multiplexed processor. + * @param multiplexed_processor_name Name of the processor you want to register + * @param multiplexed_processor Pointer to implemented processor you want multiplex. + * @param error Error object where we should store errors. + * + * @see https://developer.gnome.org/glib/stable/glib-Error-Reporting.html#g-set-error + */ +gboolean thrift_multiplexed_processor_register_processor(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error); + + +/* define error/exception types */ +typedef enum +{ + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_UNKNOWN, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_TYPE, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_WRONGLY_MULTIPLEXED, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SEND, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_RECEIVE, + THRIFT_MULTIPLEXED_PROCESSOR_ERROR_CLOSE +} ThriftMultiplexedProcessorError; + + +GQuark thrift_multiplexed_processor_error_quark (void); +#define THRIFT_MULTIPLEXED_PROCESSOR_ERROR (thrift_multiplexed_processor_error_quark ()) + + +G_END_DECLS + + +#endif /* _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_ */ diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c index c74f048c9..727f4a87c 100644 --- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c +++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c @@ -57,7 +57,7 @@ thrift_multiplexed_protocol_write_message_begin (ThriftMultiplexedProtocol *prot service_name = g_strdup(name); } - // relay to the protocol_decorator + /* relay to the protocol_decorator */ ret = thrift_protocol_decorator_write_message_begin(protocol, service_name, message_type, seqid, error); g_free(service_name); diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c index 1feec3474..03f9420f7 100644 --- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c +++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c @@ -486,13 +486,11 @@ thrift_protocol_decorator_set_property (GObject *object, GParamSpec *pspec) { ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (object); - g_debug("Is protocol decorator %i", THRIFT_IS_PROTOCOL_DECORATOR(object)); switch (property_id) { case PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_CONCRETE_PROTOCOL: self->concrete_protocol = g_value_dup_object (value); - g_debug("Setting concrete protocol %p to %p in %s", (void *)self, (void *)self->concrete_protocol, g_type_name(G_TYPE_FROM_INSTANCE(object))); break; default: @@ -509,7 +507,6 @@ thrift_protocol_decorator_get_property (GObject *object, GParamSpec *pspec) { ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (object); - g_debug("Is protocol decorator %i", THRIFT_IS_PROTOCOL_DECORATOR(object)); switch (property_id) { diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c new file mode 100644 index 000000000..a0d560bfc --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c @@ -0,0 +1,192 @@ +/* + * 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 <stdio.h> +#include <glib.h> +#include <glib-object.h> + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/protocol/thrift_protocol.h> +#include <thrift/c_glib/protocol/thrift_protocol_decorator.h> +#include <thrift/c_glib/protocol/thrift_stored_message_protocol.h> + + +enum +{ + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME = 1, + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE, + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID, + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT, /* TODO ugly hack */ + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END +}; + +G_DEFINE_TYPE(ThriftStoredMessageProtocol, thrift_stored_message_protocol, THRIFT_TYPE_PROTOCOL_DECORATOR) + + +static GParamSpec *thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END] = { NULL, }; + +gint32 +thrift_stored_message_protocol_read_message_begin (ThriftProtocol *protocol, + gchar **name, + ThriftMessageType *message_type, + gint32 *seqid, GError **error) +{ + gint32 ret = 0; + g_return_val_if_fail (THRIFT_IS_STORED_MESSAGE_PROTOCOL (protocol), -1); + THRIFT_UNUSED_VAR (error); + + ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (protocol); + + /* We return the stored values on construction */ + *name = self->name; + *message_type = self->mtype; + *seqid = self->seqid; + + return ret; +} + + +static void +thrift_stored_message_protocol_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (object); + + switch (property_id) + { + case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME: + self->name = g_value_dup_string (value); + break; + case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE: + self->mtype = g_value_get_int (value); + break; + case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID: + self->seqid = g_value_get_int (value); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +thrift_stored_message_protocol_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (object); + ThriftProtocolDecorator *decorator = THRIFT_PROTOCOL_DECORATOR (object); + ThriftTransport *transport=NULL; + switch (property_id) + { + case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME: + g_value_set_string (value, self->name); + break; + case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT: + /* FIXME Since we don't override properties in the decorator as it should + we just override the properties that we know are used */ + g_object_get(decorator->concrete_protocol,pspec->name, &transport, NULL); + g_value_set_pointer (value, transport); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +thrift_stored_message_protocol_init (ThriftStoredMessageProtocol *protocol) +{ + protocol->name = NULL; +} + +static void +thrift_stored_message_protocol_finalize (GObject *gobject) +{ + ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (gobject); + + if (self->name) { + g_free(self->name); + self->name = NULL; + } + + /* Always chain up to the parent class; as with dispose(), finalize() + * is guaranteed to exist on the parent's class virtual function table + */ + G_OBJECT_CLASS (thrift_stored_message_protocol_parent_class)->finalize(gobject); +} + + +/* initialize the class */ +static void +thrift_stored_message_protocol_class_init (ThriftStoredMessageProtocolClass *klass) +{ + ThriftProtocolClass *cls = THRIFT_PROTOCOL_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + cls->read_message_begin = thrift_stored_message_protocol_read_message_begin; + + object_class->set_property = thrift_stored_message_protocol_set_property; + object_class->get_property = thrift_stored_message_protocol_get_property; + object_class->finalize = thrift_stored_message_protocol_finalize; + + thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME] = + g_param_spec_string ("name", + "Service name the protocol points to", + "Set the service name", + NULL, + (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE] = + g_param_spec_int ("type", + "Message type in the wire", + "Set the message type in the wire", + T_CALL, T_ONEWAY, + T_CALL, + (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID] = + g_param_spec_int ("seqid", + "Sequence id type in the wire", + "Set the Sequence id in the wire", + 0, G_MAXINT, + 0, + (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + /* TODO Ugly hack, in theory we must override all properties from underlaying + protocol */ + thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT] = + g_param_spec_pointer ("transport", + "Transport on the underlaying implementation", + "Transport of decorated protocol", + G_PARAM_READABLE); + + + + g_object_class_install_properties (object_class, + PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END, + thrift_stored_message_protocol_obj_properties); +} diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h new file mode 100644 index 000000000..88782ac36 --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h @@ -0,0 +1,78 @@ +/* + * 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_STORED_MESSAGE_PROTOCOL_H +#define _THRIFT_STORED_MESSAGE_PROTOCOL_H + +#include <glib-object.h> + +#include <thrift/c_glib/protocol/thrift_protocol.h> +#include <thrift/c_glib/protocol/thrift_protocol_decorator.h> +#include <thrift/c_glib/transport/thrift_transport.h> + +G_BEGIN_DECLS + +/*! \file thrift_stored_message_protocol.h + * \brief StoredMessage protocol implementation of a pre-stored message header + * on Thrift protocol. Implements the ThriftProtocol interface. + */ + +/* type macros */ +#define THRIFT_TYPE_STORED_MESSAGE_PROTOCOL (thrift_stored_message_protocol_get_type ()) +#define THRIFT_STORED_MESSAGE_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocol)) +#define THRIFT_IS_STORED_MESSAGE_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL)) +#define THRIFT_STORED_MESSAGE_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocolClass)) +#define THRIFT_IS_STORED_MESSAGE_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL)) +#define THRIFT_STORED_MESSAGE_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocolClass)) + +/* constant */ +#define THRIFT_STORED_MESSAGE_PROTOCOL_DEFAULT_SEPARATOR ":" + +typedef struct _ThriftStoredMessageProtocol ThriftStoredMessageProtocol; + + + +/*! + * Thrift StoredMessage Protocol instance. + */ +struct _ThriftStoredMessageProtocol +{ + ThriftProtocolDecorator parent; + + gchar *name; + ThriftMessageType mtype; + gint32 seqid; +}; + +typedef struct _ThriftStoredMessageProtocolClass ThriftStoredMessageProtocolClass; + +/*! + * Thrift StoredMessage Protocol class. + */ +struct _ThriftStoredMessageProtocolClass +{ + ThriftProtocolDecoratorClass parent; +}; + +/* used by THRIFT_TYPE_STORED_MESSAGE_PROTOCOL */ +GType thrift_stored_message_protocol_get_type (void); + +G_END_DECLS + +#endif /* _THRIFT_STORED_MESSAGE_PROTOCOL_H */ diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h index ef4f00d1e..ede60f172 100644 --- a/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h @@ -17,7 +17,7 @@ * under the License. */ -// clang-format off +/* clang-format off */ #ifndef _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ # define _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ @@ -63,17 +63,17 @@ # define THRIFT_TIMESPEC thrift_timespec # define THRIFT_CTIME_R thrift_ctime_r # define THRIFT_POLL thrift_poll -# if WINVER <= 0x0502 //XP, Server2003 +# if WINVER <= 0x0502 /* XP, Server2003 */ # define THRIFT_POLLFD thrift_pollfd # define THRIFT_POLLIN 0x0300 # define THRIFT_POLLOUT 0x0010 -# else //Vista, Win7... +# else /* Vista, Win7... */ # define THRIFT_POLLFD pollfd # define THRIFT_POLLIN POLLIN # define THRIFT_POLLOUT POLLOUT -# endif //WINVER +# endif /* WINVER */ # define THRIFT_SHUT_RDWR SD_BOTH -#else //not _WIN32 +#else /* not _WIN32 */ # include <errno.h> # define THRIFT_GET_SOCKET_ERROR errno # define THRIFT_ERRNO errno @@ -117,4 +117,4 @@ # define THRIFT_SHUT_RDWR SHUT_RDWR #endif -#endif // _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ +#endif /* _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ */ 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 ce6b344e7..6dd0f0d3a 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 @@ -95,6 +95,25 @@ thrift_socket_peek (ThriftTransport *transport, GError **error) return result; } + +/* 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 = THRIFT_INVALID_SOCKET; + return TRUE; +} + /* implements thrift_transport_open */ gboolean thrift_socket_open (ThriftTransport *transport, GError **error) @@ -128,7 +147,7 @@ thrift_socket_open (ThriftTransport *transport, GError **error) /* 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_addr.s_addr = ((struct in_addr *) (hp->h_addr_list[0]))->s_addr; pin.sin_port = htons (tsocket->port); /* create the socket */ @@ -144,7 +163,8 @@ thrift_socket_open (ThriftTransport *transport, GError **error) /* open a connection */ if (connect (tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1) { - g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CONNECT, + thrift_socket_close(tsocket, NULL); + 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; @@ -153,23 +173,6 @@ thrift_socket_open (ThriftTransport *transport, GError **error) 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 = THRIFT_INVALID_SOCKET; - return TRUE; -} /* implements thrift_transport_read */ gint32 diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c index 4abeb9341..ee5540685 100644 --- a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c @@ -140,6 +140,84 @@ static void thrift_ssl_socket_dyn_lock_destroy_callback(void* lock, const char* G_DEFINE_TYPE(ThriftSSLSocket, thrift_ssl_socket, THRIFT_TYPE_SOCKET) + +/** + * When there's a thread context attached, we pass the SSL socket context so it + * can check if the error is outside SSL, on I/O for example + * @param socket + * @param error_msg + * @param thrift_error_no + * @param ssl_error + * @param error + */ +static +void thrift_ssl_socket_get_ssl_error(ThriftSSLSocket *socket, const guchar *error_msg, guint thrift_error_no, int ssl_error, GError **error) +{ + unsigned long error_code; + char buffer[1024]; + int buffer_size=1024; + gboolean first_error = TRUE; + int ssl_error_type = SSL_get_error(socket->ssl, ssl_error); + if(ssl_error_type>0){ + switch(ssl_error_type){ + case SSL_ERROR_SSL: + buffer_size-=snprintf(buffer, buffer_size, "SSL %s: ", error_msg); + while ((error_code = ERR_get_error()) != 0 && buffer_size>1) { + const char* reason = ERR_reason_error_string(error_code); + if(reason!=NULL){ + if(!first_error) { + buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "\n\t"); + first_error=FALSE; + } + buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX(%s) -> %s", error_code, reason, SSL_state_string(socket->ssl)); + } + } + break; + case SSL_ERROR_SYSCALL: + buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg); + buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", errno, strerror(errno)); + break; + case SSL_ERROR_WANT_READ: + buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg); + buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while reading from underlaying layer"); + break; + case SSL_ERROR_WANT_WRITE: + buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg); + buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while writting to underlaying layer"); + break; + + } + g_set_error (error, THRIFT_TRANSPORT_ERROR, + thrift_error_no, "%s", buffer); + } +} + +/** + * For global SSL errors + * @param error_msg + * @param thrift_error_no + * @param error + */ +static +void thrift_ssl_socket_get_error(const guchar *error_msg, guint thrift_error_no, GError **error) +{ + unsigned long error_code; + while ((error_code = ERR_get_error()) != 0) { + const char* reason = ERR_reason_error_string(error_code); + if (reason == NULL) { + g_set_error (error, THRIFT_TRANSPORT_ERROR, + thrift_error_no, + "SSL error %lX: %s", error_code, error_msg); + }else{ + g_set_error (error, THRIFT_TRANSPORT_ERROR, + thrift_error_no, + "SSL error %lX %s: %s", error_code,reason, error_msg); + } + } +} + + + /* implements thrift_transport_is_open */ gboolean thrift_ssl_socket_is_open (ThriftTransport *transport) @@ -159,10 +237,8 @@ thrift_ssl_socket_peek (ThriftTransport *transport, GError **error) gchar byte; rc = SSL_peek(ssl_socket->ssl, &byte, 1); if (rc < 0) { - g_set_error (error, - THRIFT_TRANSPORT_ERROR, - THRIFT_SSL_SOCKET_ERROR_SSL, - "failed to peek at socket - id?"); + thrift_ssl_socket_get_ssl_error(ssl_socket, "Check socket data", + THRIFT_SSL_SOCKET_ERROR_SSL, rc, error); } if (rc == 0) { ERR_clear_error(); @@ -176,13 +252,14 @@ thrift_ssl_socket_peek (ThriftTransport *transport, GError **error) gboolean thrift_ssl_socket_open (ThriftTransport *transport, GError **error) { + ERR_clear_error(); + if (!thrift_socket_open(transport, error)) { return FALSE; } if (!THRIFT_SSL_SOCKET_GET_CLASS(transport)->handle_handshake(transport, error)) { - GError *tmperr; - thrift_socket_close(transport, &tmperr); + thrift_ssl_socket_close(transport, NULL); return FALSE; } @@ -194,13 +271,14 @@ gboolean thrift_ssl_socket_close (ThriftTransport *transport, GError **error) { gboolean retval = FALSE; - if(THRIFT_SSL_SOCKET(transport)->ssl) { - int rc = SSL_shutdown(THRIFT_SSL_SOCKET(transport)->ssl); - if (rc < 0) { + ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET(transport); + if(ssl_socket!=NULL && ssl_socket->ssl) { + int rc = SSL_shutdown(ssl_socket->ssl); +/* if (rc < 0) { int errno_copy = THRIFT_SSL_SOCKET_ERROR_SSL; - } - SSL_free(THRIFT_SSL_SOCKET(transport)->ssl); - THRIFT_SSL_SOCKET(transport)->ssl = NULL; + }*/ + SSL_free(ssl_socket->ssl); + ssl_socket->ssl = NULL; ERR_remove_state(0); } return thrift_socket_close(transport, error); @@ -216,9 +294,9 @@ thrift_ssl_socket_read (ThriftTransport *transport, gpointer buf, guint bytes = 0; guint retries = 0; ThriftSocket *socket = THRIFT_SOCKET (transport); - g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET, FALSE); + g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE); - for (retries=0; retries < maxRecvRetries_; retries++) { + for (retries=0; retries < maxRecvRetries_; retries++) { bytes = SSL_read(ssl_socket->ssl, buf, len); if (bytes >= 0) break; @@ -227,10 +305,11 @@ thrift_ssl_socket_read (ThriftTransport *transport, gpointer buf, if (ERR_get_error() == 0 && errno_copy == THRIFT_EINTR) { continue; } + }else{ + thrift_ssl_socket_get_ssl_error(ssl_socket, "Receive error", + THRIFT_SSL_SOCKET_ERROR_SSL, bytes, error); + } - g_set_error (error, THRIFT_TRANSPORT_ERROR, - THRIFT_TRANSPORT_ERROR_RECEIVE, - "failed to read %d bytes - %s", len, strerror(errno)); return -1; } return bytes; @@ -256,16 +335,15 @@ thrift_ssl_socket_write (ThriftTransport *transport, const gpointer buf, gint ret = 0; guint sent = 0; ThriftSocket *socket = THRIFT_SOCKET (transport); - g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET, FALSE); + g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE); while (sent < len) { ret = SSL_write (ssl_socket->ssl, (guint8 *)buf + sent, len - sent); if (ret < 0) { - g_set_error (error, THRIFT_TRANSPORT_ERROR, - THRIFT_TRANSPORT_ERROR_SEND, - "failed to send %d bytes - %s", len, strerror(errno)); + thrift_ssl_socket_get_ssl_error(ssl_socket, "Send error", + THRIFT_SSL_SOCKET_ERROR_SSL, ret, error); return FALSE; } sent += ret; @@ -295,7 +373,7 @@ thrift_ssl_socket_flush (ThriftTransport *transport, GError **error) guint sent = 0; ThriftSocket *socket = THRIFT_SOCKET (transport); - g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET, FALSE); + g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE); BIO* bio = SSL_get_wbio(ssl_socket->ssl); if (bio == NULL) { @@ -331,8 +409,7 @@ thrift_ssl_socket_handle_handshake(ThriftTransport * transport, GError **error) rc = SSL_connect(ssl_socket->ssl); } if (rc <= 0) { - fprintf(stderr,"The error returned was %d\n", SSL_get_error(ssl_socket->ssl, rc)); - thrift_ssl_socket_get_error(error, "Not possible to connect", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE); + thrift_ssl_socket_get_ssl_error(ssl_socket, "Error while connect/bind", THRIFT_SSL_SOCKET_ERROR_CONNECT_BIND, rc, error); return FALSE; } }else @@ -390,16 +467,16 @@ gboolean thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const cha X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_socket->ctx); if(cert_store!=NULL){ - int index = 0; - while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) { - if(cacert) { - X509_STORE_add_cert(cert_store, cacert); - X509_free(cacert); - cacert=NULL; - } /* Free immediately */ - index++; - } - retval=TRUE; + int index = 0; + while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) { + if(cacert) { + X509_STORE_add_cert(cert_store, cacert); + X509_free(cacert); + cacert=NULL; + } /* Free immediately */ + index++; + } + retval=TRUE; } BIO_free(mem); return retval; @@ -416,46 +493,46 @@ thrift_ssl_socket_authorize(ThriftTransport * transport, GError **error) if(cls!=NULL && ssl_socket->ssl!=NULL){ int rc = SSL_get_verify_result(ssl_socket->ssl); if (rc != X509_V_OK) { /* verify authentication result */ - if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && ssl_socket->allow_selfsigned) { - g_debug("The certificate is a self-signed certificate and configuration allows it"); - } else { - g_set_error (error, - THRIFT_TRANSPORT_ERROR, - THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED, - "The certificate verification failed: %s (%d)", X509_verify_cert_error_string(rc), rc); - return FALSE; - } + if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && ssl_socket->allow_selfsigned) { + g_debug("The certificate is a self-signed certificate and configuration allows it"); + } else { + g_set_error (error, + THRIFT_TRANSPORT_ERROR, + THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED, + "The certificate verification failed: %s (%d)", X509_verify_cert_error_string(rc), rc); + return FALSE; + } } X509* cert = SSL_get_peer_certificate(ssl_socket->ssl); if (cert == NULL) { - if (SSL_get_verify_mode(ssl_socket->ssl) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { - g_set_error (error, - THRIFT_TRANSPORT_ERROR, - THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED, - "No certificate present. Are you connecting SSL server?"); - return FALSE; - } - g_debug("No certificate required"); - return TRUE; + if (SSL_get_verify_mode(ssl_socket->ssl) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { + g_set_error (error, + THRIFT_TRANSPORT_ERROR, + THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED, + "No certificate present. Are you connecting SSL server?"); + return FALSE; + } + g_debug("No certificate required"); + return TRUE; } /* certificate is present, since we don't support access manager we are done */ if (cls->authorize_peer == NULL) { - X509_free(cert); - g_debug("Certificate presented but we're not checking it"); - return TRUE; + X509_free(cert); + g_debug("Certificate presented but we're not checking it"); + return TRUE; } else { - /* both certificate and access manager are present */ - struct sockaddr_storage sa; - socklen_t saLength = sizeof(struct sockaddr_storage); - if (getpeername(socket->sd, (struct sockaddr*)&sa, &saLength) != 0) { - sa.ss_family = AF_UNSPEC; - } - authorization_result = cls->authorize_peer(transport, cert, &sa, error); + /* both certificate and access manager are present */ + struct sockaddr_storage sa; + socklen_t saLength = sizeof(struct sockaddr_storage); + if (getpeername(socket->sd, (struct sockaddr*)&sa, &saLength) != 0) { + sa.ss_family = AF_UNSPEC; + } + authorization_result = cls->authorize_peer(transport, cert, &sa, error); } if(cert != NULL) { - X509_free(cert); + X509_free(cert); } } @@ -499,8 +576,8 @@ thrift_ssl_socket_finalize (GObject *object) if(socket->ctx!=NULL){ g_debug("Freeing the context for the instance"); SSL_CTX_free(socket->ctx); + socket->ctx=NULL; } - socket->ctx=NULL; } if (G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize) @@ -538,7 +615,7 @@ thrift_ssl_socket_set_property (GObject *object, guint property_id, g_debug("Freeing the context since we are setting a new one"); SSL_CTX_free(socket->ctx); } - socket->ctx = g_value_get_pointer(value); // We copy the context + socket->ctx = g_value_get_pointer(value); /* We copy the context */ break; case PROP_THRIFT_SSL_SELF_SIGNED: @@ -664,7 +741,7 @@ thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hos SSL_CTX *ssl_context = NULL; /* Create the context */ if((ssl_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){ - // FIXME Do error control + /* FIXME Do error control */ return thriftSSLSocket; } /* FIXME if the protocol is different? */ @@ -712,35 +789,18 @@ thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GErro } if (context == NULL) { - thrift_ssl_socket_get_error(error, "No cipher overlay", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE); + thrift_ssl_socket_get_error("No cipher overlay", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE, error); return NULL; } SSL_CTX_set_mode(context, SSL_MODE_AUTO_RETRY); - // Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake - // with older clients so they get a graceful denial. + /* Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake + with older clients so they get a graceful denial. */ if (ssl_protocol == SSLTLS) { SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); // THRIFT-3164 + SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); /* THRIFT-3164 */ } return context; } -void thrift_ssl_socket_get_error(GError **error, const guchar *error_msg, guint thrift_error_no) -{ - unsigned long error_code; - while ((error_code = ERR_get_error()) != 0) { - const char* reason = ERR_reason_error_string(error_code); - if (reason == NULL) { - g_set_error (error, THRIFT_TRANSPORT_ERROR, - thrift_error_no, - "SSL error %lX: %s", error_code, error_msg); - }else{ - g_set_error (error, THRIFT_TRANSPORT_ERROR, - thrift_error_no, - "SSL error %lX %s: %s", error_code,reason, error_msg); - } - } -} - diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h index 659c88dd9..0ca465a0f 100644 --- a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h @@ -53,6 +53,7 @@ G_BEGIN_DECLS typedef enum { THRIFT_SSL_SOCKET_ERROR_TRANSPORT=7, + THRIFT_SSL_SOCKET_ERROR_CONNECT_BIND, THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE, THRIFT_SSL_SOCKET_ERROR_SSL, THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED @@ -117,21 +118,6 @@ GType thrift_ssl_socket_get_type (void); /* Public API */ /** - * @brief Returns a error message for a defined error code. - * - * It uses gobject error functionality to get the error code of the last error - * produced by this API. - * - * @param error Pointer to the error message. - * @param error_msg Adds this message to the error that will be added to the - * code. - * @param thrift_error_no number of the error triggered. - * - * @see https://developer.gnome.org/glib/stable/glib-Error-Reporting.html#g-set-error - */ -void thrift_ssl_socket_get_error(GError **error, const guchar *error_msg, guint thrift_error_no); - -/** * @brief Set a pinning manager instead of the default one. * * The pinning manager will be used during the SSL handshake to check certificate diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt index 2c87dbcc9..fb3e41cec 100644 --- a/lib/c_glib/test/CMakeLists.txt +++ b/lib/c_glib/test/CMakeLists.txt @@ -111,6 +111,8 @@ include_directories("${PROJECT_SOURCE_DIR}/test/c_glib/src" "${CMAKE_CURRENT_BIN add_executable(testthrifttest testthrifttest.c ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_test_handler.c ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_test_handler.h + ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_second_service_handler.c + ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_second_service_handler.h gen-c_glib/t_test_thrift_test_types.h) target_link_libraries(testthrifttest testgenc) add_test(NAME testthrifttest COMMAND testthrifttest) diff --git a/lib/c_glib/test/testbufferedtransport.c b/lib/c_glib/test/testbufferedtransport.c index 1c15ef2ef..c6e6b581d 100755 --- a/lib/c_glib/test/testbufferedtransport.c +++ b/lib/c_glib/test/testbufferedtransport.c @@ -31,6 +31,7 @@ #include "../src/thrift/c_glib/transport/thrift_buffered_transport.c" static void thrift_server (const int port); +static void thrift_socket_server_open (const int port, int times); /* test object creation and destruction */ static void @@ -44,8 +45,8 @@ test_create_and_destroy(void) object = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, NULL); g_assert (object != NULL); g_object_get (G_OBJECT (object), "transport", &transport, - "r_buf_size", &r_buf_size, - "w_buf_size", &w_buf_size, NULL); + "r_buf_size", &r_buf_size, + "w_buf_size", &w_buf_size, NULL); g_object_unref (object); } @@ -55,35 +56,52 @@ test_open_and_close(void) ThriftSocket *tsocket = NULL; ThriftTransport *transport = NULL; GError *err = NULL; + pid_t pid; + int port = 51199; + int status; - /* 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 */ - g_assert (thrift_buffered_transport_open (transport, NULL) == FALSE); - g_assert (thrift_buffered_transport_is_open (transport) == TRUE); - g_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); + pid = fork (); + g_assert ( pid >= 0 ); - g_assert (thrift_buffered_transport_open (transport, &err) == FALSE); - g_object_unref (transport); - g_object_unref (tsocket); - g_error_free (err); - err = NULL; + if ( pid == 0 ) + { + /* child listens */ + thrift_socket_server_open (port,1); + exit (0); + } else { + /* parent connects, 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); + + /* create a BufferedTransport wrapper of the Socket */ + transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, + "transport", THRIFT_TRANSPORT (tsocket), NULL); + + /* this shouldn't work */ + g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE); + g_assert (thrift_buffered_transport_is_open (transport) == TRUE); + g_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); + + g_assert (thrift_buffered_transport_open (transport, &err) == FALSE); + g_object_unref (transport); + g_object_unref (tsocket); + g_error_free (err); + err = NULL; + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } static void @@ -100,57 +118,81 @@ test_read_and_write(void) g_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); - - g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE); - g_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); - - g_assert ( wait (&status) == pid ); - g_assert ( status == 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); + + g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE); + g_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); + + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } +} + + +static void +thrift_socket_server_open (const int port, int times) +{ + int bytes = 0; + ThriftServerTransport *transport = NULL; + ThriftTransport *client = NULL; + guchar buf[10]; /* a buffer */ + guchar match[10] = TEST_DATA; + int i; + ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, + "port", port, NULL); + + transport = THRIFT_SERVER_TRANSPORT (tsocket); + thrift_server_transport_listen (transport, NULL); + for(i=0;i<times;i++){ + client = thrift_server_transport_accept (transport, NULL); + g_assert (client != NULL); + thrift_socket_close (client, NULL); + g_object_unref (client); } + g_object_unref (tsocket); } static void @@ -163,15 +205,15 @@ thrift_server (const int port) guchar match[10] = TEST_DATA; ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, - "port", port, NULL); + "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); + thrift_server_transport_accept (transport, NULL), + "r_buf_size", 5, NULL); g_assert (client != NULL); /* read 10 bytes */ @@ -209,62 +251,62 @@ test_write_fail(void) g_assert ( pid >= 0 ); if ( pid == 0 ) - { - /* child listens */ - ThriftServerTransport *transport = NULL; - ThriftTransport *client = NULL; - - 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); - g_assert (client != NULL); - - /* just close socket */ - thrift_buffered_transport_close (client, NULL); - g_object_unref (client); - g_object_unref (tsocket); - 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); - - - g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE); - g_assert (thrift_buffered_transport_is_open (transport)); - - /* recognize disconnection */ - sleep(1); - g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == TRUE); - g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE); - - /* write and overflow buffer */ - g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE); - - /* write 1 and flush */ - g_assert (thrift_buffered_transport_write (transport, buf, 1, NULL) == TRUE); - g_assert (thrift_buffered_transport_flush (transport, NULL) == FALSE); - - thrift_buffered_transport_close (transport, NULL); - - g_object_unref (transport); - g_object_unref (tsocket); - - g_assert ( wait (&status) == pid ); - g_assert ( status == 0 ); - } + { + /* child listens */ + ThriftServerTransport *transport = NULL; + ThriftTransport *client = NULL; + + 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); + g_assert (client != NULL); + + /* just close socket */ + thrift_buffered_transport_close (client, NULL); + g_object_unref (client); + g_object_unref (tsocket); + 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); + + + g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE); + g_assert (thrift_buffered_transport_is_open (transport)); + + /* recognize disconnection */ + sleep(1); + g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == TRUE); + g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE); + + /* write and overflow buffer */ + g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE); + + /* write 1 and flush */ + g_assert (thrift_buffered_transport_write (transport, buf, 1, NULL) == TRUE); + g_assert (thrift_buffered_transport_flush (transport, NULL) == FALSE); + + thrift_buffered_transport_close (transport, NULL); + + g_object_unref (transport); + g_object_unref (tsocket); + + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } int diff --git a/lib/c_glib/test/testframedtransport.c b/lib/c_glib/test/testframedtransport.c index 032873789..45397cef4 100755 --- a/lib/c_glib/test/testframedtransport.c +++ b/lib/c_glib/test/testframedtransport.c @@ -30,6 +30,7 @@ #include "../src/thrift/c_glib/transport/thrift_framed_transport.c" static void thrift_server (const int port); +static void thrift_socket_server_open (const int port, int times); /* test object creation and destruction */ static void @@ -43,8 +44,8 @@ test_create_and_destroy(void) object = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, NULL); g_assert (object != NULL); g_object_get (G_OBJECT (object), "transport", &transport, - "r_buf_size", &r_buf_size, - "w_buf_size", &w_buf_size, NULL); + "r_buf_size", &r_buf_size, + "w_buf_size", &w_buf_size, NULL); g_object_unref (object); } @@ -54,35 +55,53 @@ test_open_and_close(void) ThriftSocket *tsocket = NULL; ThriftTransport *transport = NULL; GError *err = NULL; + pid_t pid; + int port = 51199; + int status; - /* 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 */ - g_assert (thrift_framed_transport_open (transport, NULL) == FALSE); - g_assert (thrift_framed_transport_is_open (transport) == TRUE); - g_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); + pid = fork (); + g_assert ( pid >= 0 ); - g_assert (thrift_framed_transport_open (transport, &err) == FALSE); - g_object_unref (transport); - g_object_unref (tsocket); - g_error_free (err); - err = NULL; + if ( pid == 0 ) + { + /* child listens */ + thrift_socket_server_open (port,1); + exit (0); + } else { + /* parent connects, 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); + + /* create a BufferedTransport wrapper of the Socket */ + transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, + "transport", THRIFT_TRANSPORT (tsocket), NULL); + + /* this shouldn't work */ + g_assert (thrift_framed_transport_open (transport, NULL) == TRUE); + g_assert (thrift_framed_transport_is_open (transport) == TRUE); + g_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); + + g_assert (thrift_framed_transport_open (transport, &err) == FALSE); + g_object_unref (transport); + g_object_unref (tsocket); + g_error_free (err); + err = NULL; + + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } static void @@ -99,46 +118,46 @@ test_read_and_write(void) g_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); - - g_assert (thrift_framed_transport_open (transport, NULL) == TRUE); - g_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); - - g_assert ( wait (&status) == pid ); - g_assert ( status == 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); + + g_assert (thrift_framed_transport_open (transport, NULL) == TRUE); + g_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); + + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } /* test reading from the transport after the peer has unexpectedly @@ -155,76 +174,100 @@ test_read_after_peer_close(void) 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 + { + 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); + thrift_transport_read (transport, buf, 10, &err); + g_assert (err != NULL); + + g_error_free (err); + err = NULL; - g_error_free (err); - err = NULL; + thrift_transport_read_end (transport, &err); + g_assert (err == NULL); - thrift_transport_read_end (transport, &err); - g_assert (err == NULL); + thrift_transport_close (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_socket_server_open (const int port, int times) +{ + int bytes = 0; + ThriftServerTransport *transport = NULL; + ThriftTransport *client = NULL; + guchar buf[10]; /* a buffer */ + guchar match[10] = TEST_DATA; + int i; - g_object_unref (transport); - g_object_unref (tsocket); + ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, + "port", port, NULL); - g_assert (wait (&status) == pid); - g_assert (status == 0); + transport = THRIFT_SERVER_TRANSPORT (tsocket); + thrift_server_transport_listen (transport, NULL); + for(i=0;i<times;i++){ + client = thrift_server_transport_accept (transport, NULL); + g_assert (client != NULL); + thrift_socket_close (client, NULL); + g_object_unref (client); } + g_object_unref (tsocket); } static void @@ -237,15 +280,15 @@ thrift_server (const int port) guchar match[10] = TEST_DATA; ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, - "port", port, NULL); + "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); + thrift_server_transport_accept (transport, NULL), + "r_buf_size", 5, NULL); g_assert (client != NULL); /* read 10 bytes */ diff --git a/lib/c_glib/test/testtransportsocket.c b/lib/c_glib/test/testtransportsocket.c index 8e963754e..fedbad6b6 100755 --- a/lib/c_glib/test/testtransportsocket.c +++ b/lib/c_glib/test/testtransportsocket.c @@ -33,9 +33,9 @@ int my_socket(int domain, int type, int protocol) { if (socket_error == 0) - { - return socket (domain, type, protocol); - } + { + return socket (domain, type, protocol); + } return -1; } @@ -44,9 +44,9 @@ ssize_t my_recv(int socket, void *buffer, size_t length, int flags) { if (recv_error == 0) - { - return recv (socket, buffer, length, flags); - } + { + return recv (socket, buffer, length, flags); + } return -1; } @@ -55,9 +55,9 @@ 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 send (socket, buffer, length, flags); + } return -1; } @@ -70,7 +70,7 @@ my_send(int socket, const void *buffer, size_t length, int flags) #undef send static void thrift_socket_server (const int port); - +static void thrift_socket_server_open (const int port, int times); /* test object creation and destruction */ static void test_create_and_destroy(void) @@ -93,82 +93,100 @@ test_open_and_close(void) ThriftSocket *tsocket = NULL; ThriftTransport *transport = NULL; GError *err = NULL; + int port = 51199; + pid_t pid; + int status; - /* 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); - g_assert (thrift_socket_is_open (transport) == TRUE); - thrift_socket_close (transport, NULL); - g_assert (thrift_socket_is_open (transport) == FALSE); - - /* test close failure */ - tsocket->sd = -1; - thrift_socket_close (transport, NULL); - g_object_unref (tsocket); + pid = fork (); + g_assert ( pid >= 0 ); - /* try a hostname lookup failure */ - tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken", - NULL); - transport = THRIFT_TRANSPORT (tsocket); - g_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; - g_assert (thrift_socket_open (transport, &err) == FALSE); - socket_error = 0; - g_object_unref (tsocket); - g_error_free (err); + if ( pid == 0 ) + { + /* child listens */ + thrift_socket_server_open (port, 1); + exit (0); + } else { + /* parent connects, wait a bit for the socket to be created */ + sleep (1); + + /* open a connection and close it */ + tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", + "port", port, NULL); + transport = THRIFT_TRANSPORT (tsocket); + thrift_socket_open (transport, NULL); + g_assert (thrift_socket_is_open (transport) == TRUE); + thrift_socket_close (transport, NULL); + g_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); + g_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; + g_assert (thrift_socket_open (transport, &err) == FALSE); + socket_error = 0; + g_object_unref (tsocket); + g_error_free (err); + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } static void test_read_and_write(void) { - int status; - pid_t pid; ThriftSocket *tsocket = NULL; ThriftTransport *transport = NULL; + pid_t pid; int port = 51199; + int status; guchar buf[10] = TEST_DATA; /* a buffer */ pid = fork (); g_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); - g_assert (thrift_socket_open (transport, NULL) == TRUE); - g_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); - - g_assert ( wait (&status) == pid ); - g_assert ( status == 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); + g_assert (thrift_socket_open (transport, NULL) == TRUE); + g_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); + + g_assert ( wait (&status) == pid ); + g_assert ( status == 0 ); + } } /* test ThriftSocket's peek() implementation */ @@ -183,9 +201,9 @@ test_peek(void) GError *error = NULL; client_transport = g_object_new (THRIFT_TYPE_SOCKET, - "hostname", "localhost", - "port", port, - NULL); + "hostname", "localhost", + "port", port, + NULL); /* thrift_transport_peek returns FALSE when the socket is closed */ g_assert (thrift_transport_is_open (client_transport) == FALSE); @@ -196,81 +214,105 @@ test_peek(void) 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); - } + { + 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); + /* 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); + /* 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 + /* 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); + 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); + /* 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 + /* 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); + 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); + thrift_transport_read_end (client_transport, &error); + thrift_transport_close (client_transport, &error); - g_object_unref (client_transport); + g_object_unref (client_transport); - g_assert (wait (&status) == pid); - g_assert (status == 0); + g_assert (wait (&status) == pid); + g_assert (status == 0); } } static void +thrift_socket_server_open (const int port, int times) +{ + int bytes = 0; + ThriftServerTransport *transport = NULL; + ThriftTransport *client = NULL; + guchar buf[10]; /* a buffer */ + guchar match[10] = TEST_DATA; + int i; + ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, + "port", port, NULL); + + transport = THRIFT_SERVER_TRANSPORT (tsocket); + thrift_server_transport_listen (transport, NULL); + for(i=0;i<times;i++){ + client = thrift_server_transport_accept (transport, NULL); + g_assert (client != NULL); + thrift_socket_close (client, NULL); + g_object_unref (client); + } + g_object_unref (tsocket); +} + + +static void thrift_socket_server (const int port) { int bytes = 0; @@ -280,7 +322,7 @@ thrift_socket_server (const int port) guchar match[10] = TEST_DATA; ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, - "port", port, NULL); + "port", port, NULL); transport = THRIFT_SERVER_TRANSPORT (tsocket); thrift_server_transport_listen (transport, NULL); diff --git a/lib/c_glib/test/testtransportsslsocket.c b/lib/c_glib/test/testtransportsslsocket.c index f2f56f835..3c2644d8d 100644 --- a/lib/c_glib/test/testtransportsslsocket.c +++ b/lib/c_glib/test/testtransportsslsocket.c @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +#define _POSIX_C_SOURCE 200112L /* https://stackoverflow.com/questions/37541985/storage-size-of-addrinfo-isnt-known */ + -#include <netdb.h> #include <sys/wait.h> +#include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> -#include <arpa/inet.h> #include <thrift/c_glib/transport/thrift_transport.h> #include <thrift/c_glib/transport/thrift_buffered_transport.h> @@ -30,7 +31,7 @@ #include <thrift/c_glib/transport/thrift_server_socket.h> #include <thrift/c_glib/transport/thrift_ssl_socket.h> -//#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' } +/* #define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' } */ #define TEST_DATA { "GET / HTTP/1.1\n\n" } @@ -40,9 +41,9 @@ int my_socket(int domain, int type, int protocol) { if (socket_error == 0) - { - return socket (domain, type, protocol); - } + { + return socket (domain, type, protocol); + } return -1; } @@ -51,9 +52,9 @@ ssize_t my_recv(int socket, void *buffer, size_t length, int flags) { if (recv_error == 0) - { - return recv (socket, buffer, length, flags); - } + { + return recv (socket, buffer, length, flags); + } return -1; } @@ -62,9 +63,9 @@ 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 send (socket, buffer, length, flags); + } return -1; } @@ -76,7 +77,7 @@ my_send(int socket, const void *buffer, size_t length, int flags) #undef recv #undef send -static void thrift_ssl_socket_server (const int port); +static void thrift_socket_server (const int port); /* test object creation and destruction */ static void @@ -111,18 +112,90 @@ test_ssl_create_and_set_properties(void) } static void -test_ssl_open_and_close(void) +test_ssl_open_and_close_non_ssl_server(void) { ThriftSSLSocket *tSSLSocket = NULL; ThriftTransport *transport = NULL; GError *error=NULL; + pid_t pid; + int non_ssl_port = 51198; + char errormsg[255]; + + + pid = fork (); + g_assert ( pid >= 0 ); + + if ( pid == 0 ) + { + /* child listens */ + /* This is a non SSL server */ + thrift_socket_server (non_ssl_port); + exit (0); + } else { + /* parent connects, wait a bit for the socket to be created */ + sleep (1); + + /* open a connection and close it */ + tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", non_ssl_port, &error); + + transport = THRIFT_TRANSPORT (tSSLSocket); + g_assert (thrift_ssl_socket_open (transport, &error) == FALSE); + g_assert_cmpstr(error->message, == ,"Error while connect/bind: 68 -> Connection reset by peer"); + g_clear_error (&error); + g_assert (thrift_ssl_socket_is_open (transport) == FALSE); + thrift_ssl_socket_close (transport, NULL); + g_assert (thrift_ssl_socket_is_open (transport) == FALSE); + + /* test close failure */ + THRIFT_SOCKET(tSSLSocket)->sd = -1; + thrift_ssl_socket_close (transport, NULL); + g_object_unref (tSSLSocket); + + /* try a hostname lookup failure */ + tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost.broken", non_ssl_port, &error); + transport = THRIFT_TRANSPORT (tSSLSocket); + g_assert (thrift_ssl_socket_open (transport, &error) == FALSE); + snprintf(errormsg, 255, "host lookup failed for localhost.broken:%d - Unknown host", non_ssl_port); + g_assert_cmpstr(error->message, ==, errormsg); + g_clear_error (&error); + g_object_unref (tSSLSocket); + error = NULL; + + /* try an error call to socket() */ + /* + tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", port, &error); + transport = THRIFT_TRANSPORT (tSSLSocket); + socket_error = 1; + assert (thrift_ssl_socket_open (transport, &error) == FALSE); + socket_error = 0; + g_object_unref (tSSLSocket); + g_error_free (error); + */ + } +} + +static void +test_ssl_write_invalid_socket(void) +{ + ThriftSSLSocket *tSSLSocket = NULL; + ThriftTransport *transport = NULL; + GError *error=NULL; + char buffer[] = "this must not break"; /* open a connection and close it */ - tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188, &error); + tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188+1, &error); transport = THRIFT_TRANSPORT (tSSLSocket); - thrift_ssl_socket_open (transport, NULL); - g_assert (thrift_ssl_socket_is_open (transport) == TRUE); + g_assert (thrift_ssl_socket_open (transport, NULL) == FALSE); + g_assert (thrift_ssl_socket_is_open (transport) == FALSE); + + /* FIXME This must be tested but since the assertion inside thrift_ssl_socket_write breaks the test unit + it's disabled. They idea is to disable trap/coredump during this test + g_assert (thrift_ssl_socket_write(transport, buffer, sizeof(buffer), &error) == FALSE); + g_message ("write_failed_with_error: %s", + error != NULL ? error->message : "No"); + g_clear_error (&error); + */ thrift_ssl_socket_close (transport, NULL); g_assert (thrift_ssl_socket_is_open (transport) == FALSE); @@ -130,23 +203,6 @@ test_ssl_open_and_close(void) THRIFT_SOCKET(tSSLSocket)->sd = -1; thrift_ssl_socket_close (transport, NULL); g_object_unref (tSSLSocket); - - /* try a hostname lookup failure */ - tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost.broken", 51188, &error); - transport = THRIFT_TRANSPORT (tSSLSocket); - g_assert (thrift_ssl_socket_open (transport, &error) == FALSE); - g_object_unref (tSSLSocket); - g_error_free (error); - error = NULL; - - /* try an error call to socket() */ - tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188, &error); - transport = THRIFT_TRANSPORT (tSSLSocket); - socket_error = 1; - g_assert (thrift_ssl_socket_open (transport, &error) == FALSE); - socket_error = 0; - g_object_unref (tSSLSocket); - g_error_free (error); } @@ -160,22 +216,22 @@ unsigned char * get_cn_name(X509_NAME* const name) unsigned char *utf8 = NULL; do - { - if(!name) break; /* failed */ + { + if(!name) break; /* failed */ - idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1); - if(!(idx > -1)) break; /* failed */ + idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1); + if(!(idx > -1)) break; /* failed */ - X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx); - if(!entry) break; /* failed */ + X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx); + if(!entry) break; /* failed */ - ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry); - if(!data) break; /* failed */ + ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry); + if(!data) break; /* failed */ - int length = ASN1_STRING_to_UTF8(&utf8, data); - if(!utf8 || !(length > 0)) break; /* failed */ + int length = ASN1_STRING_to_UTF8(&utf8, data); + if(!utf8 || !(length > 0)) break; /* failed */ - } while (0); + } while (0); return utf8; } @@ -197,34 +253,34 @@ int verify_ip(char * hostname, struct sockaddr_storage *addr) int retval = 0; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6 + memset(&hints, 0, sizeof (struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* use AF_INET6 to force IPv6 */ hints.ai_socktype = SOCK_STREAM; if ( (res = getaddrinfo(hostname, NULL, &hints, &addr_info) ) != 0) - { - // get the host info - g_error("Cannot get the host address"); - return retval; - } - // loop through all the results and connect to the first we can - char dnshost[INET6_ADDRSTRLEN]; // bigger addr supported IPV6 + { + /* get the host info */ + g_error("Cannot get the host address"); + return retval; + } + /* loop through all the results and connect to the first we can */ + char dnshost[INET6_ADDRSTRLEN]; /* bigger addr supported IPV6 */ char socket_ip[INET6_ADDRSTRLEN]; if(inet_ntop(addr->ss_family, get_in_addr(addr), socket_ip, INET6_ADDRSTRLEN)==socket_ip){ - g_debug("We are connected to host %s checking against certificate...", socket_ip); - int sizeip = socket_ip!=NULL ? strlen(socket_ip) : 0; - for(p = addr_info; p != NULL; p = p->ai_next) { - if(inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), dnshost, INET6_ADDRSTRLEN)==dnshost){ - if(dnshost!=NULL){ - g_info("DNS address [%i -> %s]", p->ai_addr, dnshost); - if(!strncmp(dnshost, socket_ip, sizeip)){ - retval=1; - break; // if we get here, we must have connected successfully - } - } + g_debug("We are connected to host %s checking against certificate...", socket_ip); + int sizeip = socket_ip!=NULL ? strlen(socket_ip) : 0; + for(p = addr_info; p != NULL; p = p->ai_next) { + if(inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), dnshost, INET6_ADDRSTRLEN)==dnshost){ + if(dnshost!=NULL){ + g_info("DNS address [%i -> %s]", p->ai_addr, dnshost); + if(!strncmp(dnshost, socket_ip, sizeip)){ + retval=1; + break; /* if we get here, we must have connected successfully */ + } + } + } } - } } if(addr_info) @@ -236,25 +292,25 @@ int verify_ip(char * hostname, struct sockaddr_storage *addr) static void read_from_file(char *buffer, long size, const char *file_name) { - char ch; - long index=0; - FILE *fp; + char ch; + long index=0; + FILE *fp; - fp = fopen(file_name,"r"); // read mode + fp = fopen(file_name,"r"); /* read mode */ - if( fp == NULL ) - { - perror("Error while opening the file.\n"); - exit(EXIT_FAILURE); - } + if( fp == NULL ) + { + perror("Error while opening the file.\n"); + exit(EXIT_FAILURE); + } - printf("The contents of %s file are :\n", file_name); + printf("The contents of %s file are :\n", file_name); - while(index<size && ( ch = fgetc(fp) ) != EOF ){ - buffer[index++] = ch; - } + while(index<size && ( ch = fgetc(fp) ) != EOF ){ + buffer[index++] = ch; + } - fclose(fp); + fclose(fp); } #define ISSUER_CN_PINNING "The Apache Software Foundation" @@ -269,25 +325,27 @@ gboolean verify_certificate_sn(X509 *cert, const unsigned char *serial_number) BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); if (!bn) { - fprintf(stderr, "unable to convert ASN1INTEGER to BN\n"); - return EXIT_FAILURE; + fprintf(stderr, "unable to convert ASN1INTEGER to BN\n"); + return EXIT_FAILURE; } char *tmp = BN_bn2dec(bn); if (!tmp) { - g_warning(stderr, "unable to convert BN to decimal string.\n"); - BN_free(bn); - return EXIT_FAILURE; + g_warning(stderr, "unable to convert BN to decimal string.\n"); + BN_free(bn); + return EXIT_FAILURE; } -// if (strlen(tmp) >= len) { -// g_warn(stderr, "buffer length shorter than serial number\n"); -// BN_free(bn); -// OPENSSL_free(tmp); -// return EXIT_FAILURE; -// } + /* + if (strlen(tmp) >= len) { + g_warn(stderr, "buffer length shorter than serial number\n"); + BN_free(bn); + OPENSSL_free(tmp); + return EXIT_FAILURE; + } + */ if(!strncmp(serial_number, tmp, strlen(serial_number))){ - retval=TRUE; + retval=TRUE; }else{ - g_warning("Serial number is not valid"); + g_warning("Serial number is not valid"); } BN_free(bn); @@ -306,52 +364,52 @@ gboolean my_access_manager(ThriftTransport * transport, X509 *cert, struct socka /* Issuer is the authority we trust that warrants nothing useful */ const unsigned char * issuer = get_cn_name(iname); if(issuer){ - gboolean valid = TRUE; - g_info("Issuer (cn) %s", issuer); + gboolean valid = TRUE; + g_info("Issuer (cn) %s", issuer); - // Issuer pinning - if(strncmp(ISSUER_CN_PINNING, issuer, strlen(ISSUER_CN_PINNING))){ - g_warning("The Issuer of the certificate is not valid"); - valid=FALSE; - } - OPENSSL_free(issuer); - if(!valid) - return valid; + /* Issuer pinning */ + if(strncmp(ISSUER_CN_PINNING, issuer, strlen(ISSUER_CN_PINNING))){ + g_warning("The Issuer of the certificate is not valid"); + valid=FALSE; + } + OPENSSL_free(issuer); + if(!valid) + return valid; } /* Subject is who the certificate is issued to by the authority */ const unsigned char * subject = get_cn_name(sname); if(subject){ - g_info("Subject (cn) %s", subject); - gboolean valid = TRUE; + g_info("Subject (cn) %s", subject); + gboolean valid = TRUE; - // Subject pinning - if(strncmp(SUBJECT_CN_PINNING, subject, strlen(SUBJECT_CN_PINNING))){ - g_warning("The subject of the certificate is not valid"); - valid=FALSE; - } + /* Subject pinning */ + if(strncmp(SUBJECT_CN_PINNING, subject, strlen(SUBJECT_CN_PINNING))){ + g_warning("The subject of the certificate is not valid"); + valid=FALSE; + } - if(!valid) - return valid; + if(!valid) + return valid; - // Host pinning - if(verify_ip(subject, addr)){ - g_info("Verified subject"); - }else{ - g_info("Cannot verify subject"); - valid=FALSE; - } - OPENSSL_free(subject); + /* Host pinning */ + if(verify_ip(subject, addr)){ + g_info("Verified subject"); + }else{ + g_info("Cannot verify subject"); + valid=FALSE; + } + OPENSSL_free(subject); - if(!valid) - return valid; + if(!valid) + return valid; } if(!verify_certificate_sn(cert, CERT_SERIAL_NUMBER)){ - return FALSE; + return FALSE; }else{ - g_info("Verified serial number"); + g_info("Verified serial number"); } return TRUE; @@ -369,32 +427,33 @@ test_ssl_authorization_manager(void) pid_t pid; ThriftSSLSocket *tSSLsocket = NULL; ThriftTransport *transport = NULL; - // int port = 51199; + /* int port = 51199; */ int port = 443; GError *error=NULL; guchar buf[17] = TEST_DATA; /* a buffer */ - // pid = fork (); - // g_assert ( pid >= 0 ); - // - // if ( pid == 0 ) - // { - // /* child listens */ - // thrift_ssl_socket_server (port); - // exit (0); - // } else { +/* + pid = fork (); + g_assert ( pid >= 0 ); + + if ( pid == 0 ) + { + thrift_ssl_socket_server (port); + exit (0); + } else { + */ /* parent connects, wait a bit for the socket to be created */ sleep (1); - // Test against level2 owncloud certificate + /* Test against level2 owncloud certificate */ tSSLsocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", port, &error); - thrift_ssl_socket_set_manager(tSSLsocket, my_access_manager); // Install pinning manager - //thrift_ssl_load_cert_from_file(tSSLsocket, "./owncloud.level2crm.pem"); + thrift_ssl_socket_set_manager(tSSLsocket, my_access_manager); /* Install pinning manager */ + /* thrift_ssl_load_cert_from_file(tSSLsocket, "./owncloud.level2crm.pem"); */ unsigned char cert_buffer[65534]; read_from_file(cert_buffer, 65534, "../../keys/client.pem"); if(!thrift_ssl_load_cert_from_buffer(tSSLsocket, cert_buffer)){ - g_warning("Certificates cannot be loaded!"); + g_warning("Certificates cannot be loaded!"); } transport = THRIFT_TRANSPORT (tSSLsocket); @@ -405,122 +464,24 @@ test_ssl_authorization_manager(void) /* write fail */ send_error = 1; - // thrift_ssl_socket_write (transport, buf, 1, NULL); - // send_error = 0; - - // thrift_ssl_socket_write_end (transport, NULL); - // thrift_ssl_socket_flush (transport, NULL); + /* + thrift_ssl_socket_write (transport, buf, 1, NULL); + send_error = 0; + thrift_ssl_socket_write_end (transport, NULL); + thrift_ssl_socket_flush (transport, NULL); + */ thrift_ssl_socket_close (transport, NULL); g_object_unref (tSSLsocket); - // g_assert ( wait (&status) == pid ); + /* g_assert ( wait (&status) == pid ); */ g_assert ( status == 0 ); - // } + /* } */ } #endif -/* test ThriftSocket's peek() implementation */ -//static void -//test_ssl_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_SSL_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_ssl_socket_server (const int port) +thrift_socket_server (const int port) { int bytes = 0; ThriftServerTransport *transport = NULL; @@ -529,7 +490,7 @@ thrift_ssl_socket_server (const int port) guchar match[10] = TEST_DATA; ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, - "port", port, NULL); + "port", port, NULL); transport = THRIFT_SERVER_TRANSPORT (tsocket); thrift_server_transport_listen (transport, NULL); @@ -566,10 +527,11 @@ main(int argc, char *argv[]) g_test_add_func ("/testtransportsslsocket/CreateAndDestroy", test_ssl_create_and_destroy); g_test_add_func ("/testtransportsslsocket/CreateAndSetProperties", test_ssl_create_and_set_properties); - g_test_add_func ("/testtransportsslsocket/OpenAndClose", test_ssl_open_and_close); - // This test is disabled because server is not ready - // g_test_add_func ("/testtransportsslsocket/AuthorizationManagerPinning", test_ssl_authorization_manager); - // g_test_add_func ("/testtransportsslsocket/Peek", test_ssl_peek); + g_test_add_func ("/testtransportsslsocket/OpenAndCloseNonSSLServer", test_ssl_open_and_close_non_ssl_server); + g_test_add_func ("/testtransportsslsocket/OpenAndWriteInvalidSocket", test_ssl_write_invalid_socket); + + + retval = g_test_run (); diff --git a/test/c_glib/Makefile.am b/test/c_glib/Makefile.am index 0c478f947..4a03d29d7 100755 --- a/test/c_glib/Makefile.am +++ b/test/c_glib/Makefile.am @@ -45,6 +45,8 @@ test_client_LDADD = \ test_server_SOURCES = \ src/thrift_test_handler.c \ src/thrift_test_handler.h \ + src/thrift_second_service_handler.c \ + src/thrift_second_service_handler.h \ src/test_server.c test_server_LDADD = \ diff --git a/test/c_glib/src/test_client.c b/test/c_glib/src/test_client.c index deff4e16b..ef24ab76c 100644 --- a/test/c_glib/src/test_client.c +++ b/test/c_glib/src/test_client.c @@ -412,7 +412,7 @@ main (int argc, char **argv) "2nd", &error)) { printf (" = \"%s\"\n", string); - if (strncmp (string, "testString(\"2nd\")", 18) != 0) { + if (strcmp (string, "testString(\"2nd\")") != 0) { ++fail_count; } diff --git a/test/c_glib/src/test_server.c b/test/c_glib/src/test_server.c index 7f41d3f89..2d716ec2e 100644 --- a/test/c_glib/src/test_server.c +++ b/test/c_glib/src/test_server.c @@ -23,6 +23,7 @@ #include <string.h> #include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/processor/thrift_multiplexed_processor.h> #include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h> #include <thrift/c_glib/protocol/thrift_compact_protocol_factory.h> #include <thrift/c_glib/server/thrift_server.h> @@ -37,8 +38,10 @@ #include <thrift/c_glib/transport/thrift_transport_factory.h> #include "../gen-c_glib/t_test_thrift_test.h" +#include "../gen-c_glib/t_test_second_service.h" #include "thrift_test_handler.h" +#include "thrift_second_service_handler.h" /* Our server object, declared globally so it is accessible within the SIGINT signal handler */ @@ -96,7 +99,10 @@ main (int argc, char **argv) GType protocol_factory_type = THRIFT_TYPE_BINARY_PROTOCOL_FACTORY; TTestThriftTestHandler *handler; + TTestThriftTestHandler *handler_second_service = NULL; ThriftProcessor *processor; + ThriftProcessor *processor_test = NULL; + ThriftProcessor *processor_second_service = NULL; ThriftServerTransport *server_transport; ThriftTransportFactory *transport_factory; ThriftProtocolFactory *protocol_factory; @@ -138,6 +144,13 @@ main (int argc, char **argv) protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; protocol_name = "compact"; } + else if (strncmp (protocol_option, "multi", 6) == 0) { + protocol_name = "binary:multi"; + } + else if (strncmp (protocol_option, "multic", 7) == 0) { + protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY; + protocol_name = "compact:multic"; + } else if (strncmp (protocol_option, "binary", 7) != 0) { fprintf (stderr, "Unknown protocol type %s\n", protocol_option); options_valid = FALSE; @@ -161,16 +174,57 @@ main (int argc, char **argv) /* Establish all our connection objects */ handler = g_object_new (TYPE_THRIFT_TEST_HANDLER, NULL); - processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, - "handler", handler, - NULL); + + + + if(strstr(protocol_name, ":multi")){ + /* When a multiplexed processor is involved the handler is not + registered as usual. We create the processor and the real + processor is registered. Multiple processors can be registered + at once. This is why we don't have a constructor property */ + processor = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROCESSOR, + NULL); + + handler_second_service = g_object_new (TYPE_SECOND_SERVICE_HANDLER, + NULL); + + processor_test = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, + "handler", handler, + NULL); + processor_second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_PROCESSOR, + "handler", handler_second_service, + NULL); + + /* We register a test processor with Multiplexed name ThriftTest */ + if(!thrift_multiplexed_processor_register_processor(processor, + "ThriftTest", processor_test, + &error)){ + g_message ("thrift_server_serve: %s", + error != NULL ? error->message : "(null)"); + g_clear_error (&error); + } + /* We register a second test processor with Multiplexed name SecondService + * we are responsible of freeing the processor when it's not used anymore */ + if(!thrift_multiplexed_processor_register_processor(processor, + "SecondService", processor_second_service, + &error)){ + g_message ("thrift_server_serve: %s", + error != NULL ? error->message : "(null)"); + g_clear_error (&error); + } + + }else{ + processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR, + "handler", handler, + NULL); + } server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", port, NULL); transport_factory = g_object_new (transport_factory_type, NULL); - if (strncmp (protocol_name, "compact", 8) == 0) { + if (strstr (protocol_name, "compact") != NULL) { protocol_factory = g_object_new (protocol_factory_type, "string_limit", string_limit, "container_limit", container_limit, @@ -222,6 +276,15 @@ main (int argc, char **argv) g_object_unref (server_transport); g_object_unref (processor); g_object_unref (handler); + if(handler_second_service){ + g_object_unref (handler_second_service); + } + if(processor_test){ + g_object_unref (processor_test); + } + if(processor_second_service){ + g_object_unref (processor_second_service); + } return 0; } diff --git a/test/c_glib/src/thrift_second_service_handler.c b/test/c_glib/src/thrift_second_service_handler.c new file mode 100644 index 000000000..c46437211 --- /dev/null +++ b/test/c_glib/src/thrift_second_service_handler.c @@ -0,0 +1,82 @@ +/* + * 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 <inttypes.h> +#include <string.h> +#include <unistd.h> + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/thrift_application_exception.h> + +#include "thrift_second_service_handler.h" + +/* A handler that implements the TTestSecondServiceIf interface */ + +G_DEFINE_TYPE (SecondServiceHandler, + second_service_handler, + T_TEST_TYPE_SECOND_SERVICE_HANDLER); + + +gboolean +second_service_handler_secondtest_string (TTestSecondServiceIf *iface, + gchar **_return, + const gchar *thing, + GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + gchar buffer[256]; + + printf ("testSecondServiceMultiplexSecondTestString(\"%s\")\n", thing); + snprintf(buffer, 255, "testString(\"%s\")", thing); + *_return = g_strdup (buffer); + + return TRUE; +} + +gboolean +second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error) +{ + THRIFT_UNUSED_VAR (iface); + THRIFT_UNUSED_VAR (error); + + printf ("blahBlah()\n"); + + return TRUE; +} + +static void +second_service_handler_init (SecondServiceHandler *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +second_service_handler_class_init (SecondServiceHandlerClass *klass) +{ + TTestSecondServiceHandlerClass *base_class = + T_TEST_SECOND_SERVICE_HANDLER_CLASS (klass); + + + base_class->secondtest_string = + second_service_handler_secondtest_string; + base_class->blah_blah = + second_service_handler_blah_blah; + +} diff --git a/test/c_glib/src/thrift_second_service_handler.h b/test/c_glib/src/thrift_second_service_handler.h new file mode 100644 index 000000000..bbe048cec --- /dev/null +++ b/test/c_glib/src/thrift_second_service_handler.h @@ -0,0 +1,73 @@ +/* + * 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 _SECOND_SERVICE_HANDLER_H +#define _SECOND_SERVICE_HANDLER_H + +#include <glib-object.h> +#include <stdio.h> + +#include "../gen-c_glib/t_test_second_service.h" + +G_BEGIN_DECLS + +/* A handler that implements the TTestSecondServiceIf interface */ + +#define TYPE_SECOND_SERVICE_HANDLER (second_service_handler_get_type ()) + +#define SECOND_SERVICE_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandler)) +#define IS_SECOND_SERVICE_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + TYPE_SECOND_SERVICE_HANDLER)) +#define SECOND_SERVICE_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_CAST ((c), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandlerClass)) +#define IS_SECOND_SERVICE_HANDLER_CLASS(c) \ + (G_TYPE_CHECK_CLASS_TYPE ((c), \ + TYPE_SECOND_SERVICE_HANDLER)) +#define SECOND_SERVICE_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + TYPE_SECOND_SERVICE_HANDLER, \ + SecondServiceHandlerClass)) + +typedef struct _SecondServiceHandler SecondServiceHandler; +typedef struct _SecondServiceHandlerClass SecondServiceHandlerClass; + +struct _SecondServiceHandler { + TTestSecondServiceHandler parent; +}; + +struct _SecondServiceHandlerClass { + TTestSecondServiceHandlerClass parent; + +}; + +/* Used by SECOND_SERVICE_HANDLER_GET_TYPE */ +GType second_service_handler_get_type (void); + +gboolean second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error); +gboolean second_service_handler_secondtest_string (TTestSecondServiceIf *iface, gchar ** _return, const gchar * thing, GError **error); + +G_END_DECLS + +#endif /* _SECOND_SERVICE_HANDLER_H */ diff --git a/test/features/tests.json b/test/features/tests.json index 3ab3b68da..41e07d7f6 100644 --- a/test/features/tests.json +++ b/test/features/tests.json @@ -66,7 +66,6 @@ "--string-limit=50" ], "protocols": [ - "binary", "compact" ], "transports": ["buffered"], @@ -84,7 +83,6 @@ "--container-limit=50" ], "protocols": [ - "binary", "compact" ], "transports": ["buffered"], diff --git a/test/tests.json b/test/tests.json index e62af2485..c1c3155fd 100644 --- a/test/tests.json +++ b/test/tests.json @@ -8,6 +8,12 @@ "command": [ "test_server", "--lt-debug" + ], + "protocols": [ + "binary:multi", + "compact:multic", + "multi", + "multic" ] }, "client": { |