1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <errno.h>
21 #include <glib.h>
22 #include <thrift/c_glib/thrift.h>
23 #include <thrift/c_glib/transport/thrift_transport.h>
24 #include <thrift/c_glib/thrift_configuration.h>
25
26 /* object properties */
27 enum _ThriftTransportProperties
28 {
29 PROP_0,
30 PROP_THRIFT_TRANSPORT_CONFIGURATION,
31 PROP_THRIFT_TRANSPORT_REMAINING_MESSAGE_SIZE,
32 PROP_THRIFT_TRANSPORT_KNOW_MESSAGE_SIZE
33 };
34
35 /* define the GError domain string */
36 #define THRIFT_TRANSPORT_ERROR_DOMAIN "thrift-transport-error-quark"
37
G_DEFINE_ABSTRACT_TYPE(ThriftTransport,thrift_transport,G_TYPE_OBJECT)38 G_DEFINE_ABSTRACT_TYPE(ThriftTransport, thrift_transport, G_TYPE_OBJECT)
39
40 gboolean
41 thrift_transport_is_open (ThriftTransport *transport)
42 {
43 return THRIFT_TRANSPORT_GET_CLASS (transport)->is_open (transport);
44 }
45
46 gboolean
thrift_transport_peek(ThriftTransport * transport,GError ** error)47 thrift_transport_peek (ThriftTransport *transport, GError **error)
48 {
49 return THRIFT_TRANSPORT_GET_CLASS (transport)->peek (transport, error);
50 }
51
52 gboolean
thrift_transport_open(ThriftTransport * transport,GError ** error)53 thrift_transport_open (ThriftTransport *transport, GError **error)
54 {
55 return THRIFT_TRANSPORT_GET_CLASS (transport)->open (transport, error);
56 }
57
58 gboolean
thrift_transport_close(ThriftTransport * transport,GError ** error)59 thrift_transport_close (ThriftTransport *transport, GError **error)
60 {
61 return THRIFT_TRANSPORT_GET_CLASS (transport)->close (transport, error);
62 }
63
64 gint32
thrift_transport_read(ThriftTransport * transport,gpointer buf,guint32 len,GError ** error)65 thrift_transport_read (ThriftTransport *transport, gpointer buf,
66 guint32 len, GError **error)
67 {
68 return THRIFT_TRANSPORT_GET_CLASS (transport)->read (transport, buf,
69 len, error);
70 }
71
72 gboolean
thrift_transport_read_end(ThriftTransport * transport,GError ** error)73 thrift_transport_read_end (ThriftTransport *transport, GError **error)
74 {
75 return THRIFT_TRANSPORT_GET_CLASS (transport)->read_end (transport,
76 error);
77 }
78
79 gboolean
thrift_transport_write(ThriftTransport * transport,const gpointer buf,const guint32 len,GError ** error)80 thrift_transport_write (ThriftTransport *transport, const gpointer buf,
81 const guint32 len, GError **error)
82 {
83 return THRIFT_TRANSPORT_GET_CLASS (transport)->write (transport, buf,
84 len, error);
85 }
86
87 gboolean
thrift_transport_write_end(ThriftTransport * transport,GError ** error)88 thrift_transport_write_end (ThriftTransport *transport, GError **error)
89 {
90 return THRIFT_TRANSPORT_GET_CLASS (transport)->write_end (transport,
91 error);
92 }
93
94 gboolean
thrift_transport_flush(ThriftTransport * transport,GError ** error)95 thrift_transport_flush (ThriftTransport *transport, GError **error)
96 {
97 return THRIFT_TRANSPORT_GET_CLASS (transport)->flush (transport, error);
98 }
99
100 gint32
thrift_transport_read_all(ThriftTransport * transport,gpointer buf,guint32 len,GError ** error)101 thrift_transport_read_all (ThriftTransport *transport, gpointer buf,
102 guint32 len, GError **error)
103 {
104 return THRIFT_TRANSPORT_GET_CLASS (transport)->read_all (transport, buf,
105 len, error);
106 }
107
108 /* by default, peek returns true if and only if the transport is open */
109 static gboolean
thrift_transport_real_peek(ThriftTransport * transport,GError ** error)110 thrift_transport_real_peek (ThriftTransport *transport, GError **error)
111 {
112 THRIFT_UNUSED_VAR (error);
113
114 return THRIFT_TRANSPORT_GET_CLASS (transport)->is_open (transport);
115 }
116
117 static gint32
thrift_transport_real_read_all(ThriftTransport * transport,gpointer buf,guint32 len,GError ** error)118 thrift_transport_real_read_all (ThriftTransport *transport, gpointer buf,
119 guint32 len, GError **error)
120 {
121 ThriftTransportClass *ttc;
122 guint32 have;
123 gint32 ret;
124 gint8 *bytes;
125
126 THRIFT_UNUSED_VAR (error);
127
128 ttc = THRIFT_TRANSPORT_GET_CLASS (transport);
129 have = 0;
130 ret = 0;
131 bytes = (gint8*) buf;
132
133 while (have < len) {
134 if ((ret = ttc->read (transport, (gpointer) (bytes + have), len - have,
135 error)) < 0) {
136 return ret;
137 }
138 have += ret;
139 }
140
141 return have;
142 }
143
144 gboolean
thrift_transport_updateKnownMessageSize(ThriftTransport * transport,glong size,GError ** error)145 thrift_transport_updateKnownMessageSize(ThriftTransport *transport, glong size, GError **error)
146 {
147 gboolean boolean = TRUE;
148 ThriftTransport *tt = THRIFT_TRANSPORT (transport);
149 ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (transport);
150 glong consumed = tt->knowMessageSize_ - tt->remainingMessageSize_;
151 if(!ttc->resetConsumedMessageSize (transport, size, error))
152 {
153 boolean = FALSE;
154 }
155 if(!ttc->countConsumedMessageBytes (transport, consumed, error))
156 {
157 boolean = FALSE;
158 }
159 return boolean;
160 }
161
162 gboolean
thrift_transport_checkReadBytesAvailable(ThriftTransport * transport,glong numBytes,GError ** error)163 thrift_transport_checkReadBytesAvailable(ThriftTransport *transport, glong numBytes, GError **error)
164 {
165 gboolean boolean = TRUE;
166 ThriftTransport *tt = THRIFT_TRANSPORT (transport);
167 if(tt->remainingMessageSize_ < numBytes)
168 {
169 g_set_error(error,
170 THRIFT_TRANSPORT_ERROR,
171 THRIFT_TRANSPORT_ERROR_MAX_MESSAGE_SIZE_REACHED,
172 "MaxMessageSize reached");
173 boolean = FALSE;
174 }
175
176 return boolean;
177 }
178
179 gboolean
thrift_transport_resetConsumedMessageSize(ThriftTransport * transport,glong newSize,GError ** error)180 thrift_transport_resetConsumedMessageSize(ThriftTransport *transport, glong newSize, GError **error)
181 {
182 ThriftTransport *tt = THRIFT_TRANSPORT (transport);
183 if(newSize < 0)
184 {
185 if(tt->configuration != NULL)
186 {
187 tt->knowMessageSize_ = tt->configuration->maxMessageSize_;
188 tt->remainingMessageSize_ = tt->configuration->maxMessageSize_;
189 }
190 else
191 {
192 tt->knowMessageSize_ = DEFAULT_MAX_MESSAGE_SIZE;
193 tt->remainingMessageSize_ = DEFAULT_MAX_MESSAGE_SIZE;
194 }
195 return TRUE;
196 }
197 /* update only: message size can shrink, but not grow */
198 if(newSize > tt->knowMessageSize_)
199 {
200 g_set_error(error,
201 THRIFT_TRANSPORT_ERROR,
202 THRIFT_TRANSPORT_ERROR_MAX_MESSAGE_SIZE_REACHED,
203 "MaxMessageSize reached");
204 return FALSE;
205 }
206
207 tt->knowMessageSize_ = newSize;
208 tt->remainingMessageSize_ = newSize;
209
210 return TRUE;
211 }
212
213 gboolean
thrift_transport_countConsumedMessageBytes(ThriftTransport * transport,glong numBytes,GError ** error)214 thrift_transport_countConsumedMessageBytes(ThriftTransport *transport, glong numBytes, GError **error)
215 {
216 ThriftTransport *tt = THRIFT_TRANSPORT (transport);
217 if(tt->remainingMessageSize_ > numBytes)
218 {
219 tt->remainingMessageSize_ -= numBytes;
220 }
221 else
222 {
223 tt->remainingMessageSize_ = 0;
224 g_set_error(error,
225 THRIFT_TRANSPORT_ERROR,
226 THRIFT_TRANSPORT_ERROR_MAX_MESSAGE_SIZE_REACHED,
227 "MaxMessageSize reached");
228 return FALSE;
229 }
230
231 return TRUE;
232 }
233
234 /* property accesor */
235 void
thrift_transport_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)236 thrift_transport_get_property(GObject *object, guint property_id,
237 GValue *value, GParamSpec *pspec)
238 {
239 ThriftTransport *transport = THRIFT_TRANSPORT (object);
240
241 THRIFT_UNUSED_VAR (pspec);
242
243 switch (property_id)
244 {
245 case PROP_THRIFT_TRANSPORT_CONFIGURATION:
246 g_value_set_object (value, transport->configuration);
247 break;
248 case PROP_THRIFT_TRANSPORT_REMAINING_MESSAGE_SIZE:
249 g_value_set_long (value, transport->remainingMessageSize_);
250 break;
251 case PROP_THRIFT_TRANSPORT_KNOW_MESSAGE_SIZE:
252 g_value_set_long (value, transport->knowMessageSize_);
253 break;
254 }
255 }
256
257 /* property mutator */
258 void
thrift_transport_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)259 thrift_transport_set_property (GObject *object, guint property_id,
260 const GValue *value, GParamSpec *pspec)
261 {
262 ThriftTransport *transport = THRIFT_TRANSPORT (object);
263
264 THRIFT_UNUSED_VAR (pspec);
265
266 switch (property_id)
267 {
268 case PROP_THRIFT_TRANSPORT_CONFIGURATION:
269 transport->configuration = g_value_get_object (value);
270 break;
271 case PROP_THRIFT_TRANSPORT_REMAINING_MESSAGE_SIZE:
272 transport->remainingMessageSize_ = g_value_get_long (value);
273 break;
274 case PROP_THRIFT_TRANSPORT_KNOW_MESSAGE_SIZE:
275 transport->knowMessageSize_ = g_value_get_long (value);
276 break;
277 }
278 }
279
280 /* define the GError domain for Thrift transports */
281 GQuark
thrift_transport_error_quark(void)282 thrift_transport_error_quark (void)
283 {
284 return g_quark_from_static_string (THRIFT_TRANSPORT_ERROR_DOMAIN);
285 }
286
287 static void
thrift_transport_dispose(GObject * gobject)288 thrift_transport_dispose (GObject *gobject)
289 {
290 ThriftTransport *self = THRIFT_TRANSPORT (gobject);
291
292 if(self->configuration != NULL)
293 g_clear_object (&self->configuration);
294
295 /* Always chain up to the parent class; there is no need to check if
296 * the parent class implements the dispose() virtual function: it is
297 * always guaranteed to do so
298 */
299 G_OBJECT_CLASS (thrift_transport_parent_class)->dispose (gobject);
300 }
301
302 /* class initializer for ThriftTransport */
303 static void
thrift_transport_class_init(ThriftTransportClass * cls)304 thrift_transport_class_init (ThriftTransportClass *cls)
305 {
306 GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
307 GParamSpec *param_spec = NULL;
308
309 /* setup accessors and mutators */
310 gobject_class->get_property = thrift_transport_get_property;
311 gobject_class->set_property = thrift_transport_set_property;
312 gobject_class->dispose = thrift_transport_dispose;
313
314 param_spec = g_param_spec_object ("configuration",
315 "configuration (construct)",
316 "Thrift Configuration",
317 THRIFT_TYPE_CONFIGURATION,
318 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
319 g_object_class_install_property (gobject_class,
320 PROP_THRIFT_TRANSPORT_CONFIGURATION,
321 param_spec);
322
323 param_spec = g_param_spec_long ("remainingmessagesize",
324 "remainingmessagesize (construct)",
325 "Set the remaining message size",
326 0, /* min */
327 G_MAXINT32, /* max */
328 DEFAULT_MAX_MESSAGE_SIZE, /* default by construct */
329 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
330 g_object_class_install_property (gobject_class,
331 PROP_THRIFT_TRANSPORT_REMAINING_MESSAGE_SIZE,
332 param_spec);
333
334 param_spec = g_param_spec_long ("knowmessagesize",
335 "knowmessagesize (construct)",
336 "Set the known size of the message",
337 0, /* min */
338 G_MAXINT32, /* max */
339 DEFAULT_MAX_MESSAGE_SIZE, /* default by construct */
340 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
341 g_object_class_install_property (gobject_class,
342 PROP_THRIFT_TRANSPORT_KNOW_MESSAGE_SIZE,
343 param_spec);
344
345
346 /* set these as virtual methods to be implemented by a subclass */
347 cls->is_open = thrift_transport_is_open;
348 cls->open = thrift_transport_open;
349 cls->close = thrift_transport_close;
350 cls->read = thrift_transport_read;
351 cls->read_end = thrift_transport_read_end;
352 cls->write = thrift_transport_write;
353 cls->write_end = thrift_transport_write_end;
354 cls->flush = thrift_transport_flush;
355
356 /* provide a default implementation for the peek and read_all methods */
357 cls->peek = thrift_transport_real_peek;
358 cls->read_all = thrift_transport_real_read_all;
359
360 cls->updateKnownMessageSize = thrift_transport_updateKnownMessageSize;
361 cls->checkReadBytesAvailable = thrift_transport_checkReadBytesAvailable;
362 cls->resetConsumedMessageSize = thrift_transport_resetConsumedMessageSize;
363 cls->countConsumedMessageBytes = thrift_transport_countConsumedMessageBytes;
364 }
365
366 static void
thrift_transport_init(ThriftTransport * transport)367 thrift_transport_init (ThriftTransport *transport)
368 {
369 THRIFT_UNUSED_VAR (transport);
370 }
371