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 <netdb.h>
21 #include <sys/wait.h>
22
23 #include <thrift/c_glib/transport/thrift_transport.h>
24 #include <thrift/c_glib/transport/thrift_socket.h>
25 #include <thrift/c_glib/transport/thrift_server_transport.h>
26 #include <thrift/c_glib/transport/thrift_server_socket.h>
27
28 #define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
29
30 #include "../src/thrift/c_glib/transport/thrift_framed_transport.c"
31
32 static void thrift_server (const int port);
33 static void thrift_socket_server_open (const int port, int times);
34
35 /* test object creation and destruction */
36 static void
test_create_and_destroy(void)37 test_create_and_destroy(void)
38 {
39 ThriftTransport *transport = NULL;
40 guint r_buf_size = 0;
41 guint w_buf_size = 0;
42
43 GObject *object = NULL;
44 object = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, NULL);
45 g_assert (object != NULL);
46 g_object_get (G_OBJECT (object), "transport", &transport,
47 "r_buf_size", &r_buf_size,
48 "w_buf_size", &w_buf_size, NULL);
49 g_object_unref (object);
50 }
51
52 static void
test_open_and_close(void)53 test_open_and_close(void)
54 {
55 ThriftSocket *tsocket = NULL;
56 ThriftTransport *transport = NULL;
57 GError *err = NULL;
58 pid_t pid;
59 int port = 51199;
60 int status;
61
62 pid = fork ();
63 g_assert ( pid >= 0 );
64
65 if ( pid == 0 )
66 {
67 /* child listens */
68 thrift_socket_server_open (port,1);
69 exit (0);
70 } else {
71 /* parent connects, wait a bit for the socket to be created */
72 sleep (1);
73 /* create a ThriftSocket */
74 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
75 "port", port, NULL);
76
77 /* create a BufferedTransport wrapper of the Socket */
78 transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
79 "transport", THRIFT_TRANSPORT (tsocket), NULL);
80
81 /* this shouldn't work */
82 g_assert (thrift_framed_transport_open (transport, NULL) == TRUE);
83 g_assert (thrift_framed_transport_is_open (transport) == TRUE);
84 g_assert (thrift_framed_transport_close (transport, NULL) == TRUE);
85 g_object_unref (transport);
86 g_object_unref (tsocket);
87
88 /* try and underlying socket failure */
89 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
90 NULL);
91
92 /* create a BufferedTransport wrapper of the Socket */
93 transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
94 "transport", THRIFT_TRANSPORT (tsocket), NULL);
95
96 g_assert (thrift_framed_transport_open (transport, &err) == FALSE);
97 g_object_unref (transport);
98 g_object_unref (tsocket);
99 g_error_free (err);
100 err = NULL;
101
102 g_assert ( wait (&status) == pid );
103 g_assert ( status == 0 );
104 }
105 }
106
107 static void
test_read_and_write(void)108 test_read_and_write(void)
109 {
110 int status;
111 pid_t pid;
112 ThriftSocket *tsocket = NULL;
113 ThriftTransport *transport = NULL;
114 int port = 51199;
115 guchar buf[10] = TEST_DATA; /* a buffer */
116
117 pid = fork ();
118 g_assert ( pid >= 0 );
119
120 if ( pid == 0 )
121 {
122 /* child listens */
123 thrift_server (port);
124 exit (0);
125 } else {
126 /* parent connects, wait a bit for the socket to be created */
127 sleep (1);
128
129 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
130 "port", port, NULL);
131 transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
132 "transport", THRIFT_TRANSPORT (tsocket),
133 "w_buf_size", 4, NULL);
134
135 g_assert (thrift_framed_transport_open (transport, NULL) == TRUE);
136 g_assert (thrift_framed_transport_is_open (transport));
137
138 /* write 10 bytes */
139 thrift_framed_transport_write (transport, buf, 10, NULL);
140 thrift_framed_transport_flush (transport, NULL);
141
142 thrift_framed_transport_write (transport, buf, 1, NULL);
143 thrift_framed_transport_flush (transport, NULL);
144
145 thrift_framed_transport_write (transport, buf, 10, NULL);
146 thrift_framed_transport_flush (transport, NULL);
147
148 thrift_framed_transport_write (transport, buf, 10, NULL);
149 thrift_framed_transport_flush (transport, NULL);
150
151 thrift_framed_transport_write_end (transport, NULL);
152 thrift_framed_transport_flush (transport, NULL);
153 thrift_framed_transport_close (transport, NULL);
154
155 g_object_unref (transport);
156 g_object_unref (tsocket);
157
158 g_assert ( wait (&status) == pid );
159 g_assert ( status == 0 );
160 }
161 }
162
163 /* test reading from the transport after the peer has unexpectedly
164 closed the connection */
165 static void
test_read_after_peer_close(void)166 test_read_after_peer_close(void)
167 {
168 int status;
169 pid_t pid;
170 int port = 51199;
171 GError *err = NULL;
172
173 pid = fork ();
174 g_assert (pid >= 0);
175
176 if (pid == 0)
177 {
178 ThriftServerTransport *server_transport = NULL;
179 ThriftTransport *client_transport = NULL;
180
181 /* child listens */
182 server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
183 "port", port,
184 NULL);
185 g_assert (server_transport != NULL);
186
187 thrift_server_transport_listen (server_transport, &err);
188 g_assert (err == NULL);
189
190 /* wrap the client transport in a ThriftFramedTransport */
191 client_transport = g_object_new
192 (THRIFT_TYPE_FRAMED_TRANSPORT,
193 "transport", thrift_server_transport_accept (server_transport, &err),
194 "r_buf_size", 0,
195 NULL);
196 g_assert (err == NULL);
197 g_assert (client_transport != NULL);
198
199 /* close the connection immediately after the client connects */
200 thrift_transport_close (client_transport, NULL);
201
202 g_object_unref (client_transport);
203 g_object_unref (server_transport);
204
205 exit (0);
206 } else {
207 ThriftSocket *tsocket = NULL;
208 ThriftTransport *transport = NULL;
209 guchar buf[10]; /* a buffer */
210
211 /* parent connects, wait a bit for the socket to be created */
212 sleep (1);
213
214 tsocket = g_object_new (THRIFT_TYPE_SOCKET,
215 "hostname", "localhost",
216 "port", port,
217 NULL);
218 transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
219 "transport", THRIFT_TRANSPORT (tsocket),
220 "w_buf_size", 0,
221 NULL);
222
223 g_assert (thrift_transport_open (transport, NULL) == TRUE);
224 g_assert (thrift_transport_is_open (transport));
225
226 /* attempting to read from the transport after the peer has closed
227 the connection fails gracefully without generating a critical
228 warning or segmentation fault */
229 thrift_transport_read (transport, buf, 10, &err);
230 g_assert (err != NULL);
231
232 g_error_free (err);
233 err = NULL;
234
235 thrift_transport_read_end (transport, &err);
236 g_assert (err == NULL);
237
238 thrift_transport_close (transport, &err);
239 g_assert (err == NULL);
240
241 g_object_unref (transport);
242 g_object_unref (tsocket);
243
244 g_assert (wait (&status) == pid);
245 g_assert (status == 0);
246 }
247 }
248
249 static void
thrift_socket_server_open(const int port,int times)250 thrift_socket_server_open (const int port, int times)
251 {
252 ThriftServerTransport *transport = NULL;
253 ThriftTransport *client = NULL;
254 int i;
255
256 ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
257 "port", port, NULL);
258
259 transport = THRIFT_SERVER_TRANSPORT (tsocket);
260 thrift_server_transport_listen (transport, NULL);
261 for(i=0;i<times;i++){
262 client = thrift_server_transport_accept (transport, NULL);
263 g_assert (client != NULL);
264 thrift_socket_close (client, NULL);
265 g_object_unref (client);
266 }
267 g_object_unref (tsocket);
268 }
269
270 static void
thrift_server(const int port)271 thrift_server (const int port)
272 {
273 int bytes = 0;
274 ThriftServerTransport *transport = NULL;
275 ThriftTransport *client = NULL;
276 guchar buf[12]; /* a buffer */
277 guchar match[10] = TEST_DATA;
278
279 ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
280 "port", port, NULL);
281
282 transport = THRIFT_SERVER_TRANSPORT (tsocket);
283 thrift_server_transport_listen (transport, NULL);
284
285 /* wrap the client in a BufferedTransport */
286 client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
287 thrift_server_transport_accept (transport, NULL),
288 "r_buf_size", 5, NULL);
289 g_assert (client != NULL);
290
291 /* read 10 bytes */
292 bytes = thrift_framed_transport_read (client, buf, 10, NULL);
293 g_assert (bytes == 10); /* make sure we've read 10 bytes */
294 g_assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
295
296 bytes = thrift_framed_transport_read (client, buf, 6, NULL);
297 bytes = thrift_framed_transport_read (client, buf, 5, NULL);
298 bytes = thrift_framed_transport_read (client, buf, 1, NULL);
299
300 bytes = thrift_framed_transport_read (client, buf, 12, NULL);
301
302 thrift_framed_transport_read_end (client, NULL);
303 thrift_framed_transport_close (client, NULL);
304 g_object_unref (client);
305 g_object_unref (tsocket);
306 }
307
308 int
main(int argc,char * argv[])309 main(int argc, char *argv[])
310 {
311 #if (!GLIB_CHECK_VERSION (2, 36, 0))
312 g_type_init();
313 #endif
314
315 g_test_init (&argc, &argv, NULL);
316
317 g_test_add_func ("/testframedtransport/CreateAndDestroy", test_create_and_destroy);
318 g_test_add_func ("/testframedtransport/OpenAndClose", test_open_and_close);
319 g_test_add_func ("/testframedtransport/ReadAndWrite", test_read_and_write);
320 g_test_add_func ("/testframedtransport/ReadAfterPeerClose", test_read_after_peer_close);
321
322 return g_test_run ();
323 }
324