blob: c23679716bae61630281a821e14f88be025a97db [file] [log] [blame]
Roger Meierc1010922010-11-26 10:17:48 +00001/*
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
Roger Meier213a6642010-10-27 12:30:11 +000020#include <netdb.h>
Pengpeng Hou27b72082026-03-22 07:48:17 +080021#include <sys/un.h>
Roger Meier63243c62014-09-29 20:29:58 +020022#include <sys/wait.h>
Roger Meier213a6642010-10-27 12:30:11 +000023
Roger Meiere3da7682013-01-11 11:41:53 +010024#include <thrift/c_glib/transport/thrift_transport.h>
Roger Meier63243c62014-09-29 20:29:58 +020025#include <thrift/c_glib/transport/thrift_buffered_transport.h>
Roger Meiere3da7682013-01-11 11:41:53 +010026#include <thrift/c_glib/transport/thrift_server_transport.h>
27#include <thrift/c_glib/transport/thrift_server_socket.h>
Roger Meier213a6642010-10-27 12:30:11 +000028
29#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
30
31/* substituted functions to test failures of system and library calls */
32static int socket_error = 0;
33int
34my_socket(int domain, int type, int protocol)
35{
36 if (socket_error == 0)
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +020037 {
38 return socket (domain, type, protocol);
39 }
Roger Meier213a6642010-10-27 12:30:11 +000040 return -1;
41}
42
43static int recv_error = 0;
44ssize_t
45my_recv(int socket, void *buffer, size_t length, int flags)
46{
47 if (recv_error == 0)
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +020048 {
49 return recv (socket, buffer, length, flags);
50 }
Roger Meier213a6642010-10-27 12:30:11 +000051 return -1;
52}
53
54static int send_error = 0;
55ssize_t
56my_send(int socket, const void *buffer, size_t length, int flags)
57{
58 if (send_error == 0)
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +020059 {
60 return send (socket, buffer, length, flags);
61 }
Roger Meier213a6642010-10-27 12:30:11 +000062 return -1;
63}
64
65#define socket my_socket
66#define recv my_recv
67#define send my_send
Roger Meiere3da7682013-01-11 11:41:53 +010068#include "../src/thrift/c_glib/transport/thrift_socket.c"
Roger Meier213a6642010-10-27 12:30:11 +000069#undef socket
70#undef recv
71#undef send
72
Roger Meier213a6642010-10-27 12:30:11 +000073static void thrift_socket_server (const int port);
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +020074static void thrift_socket_server_open (const int port, int times);
Pengpeng Hou27b72082026-03-22 07:48:17 +080075
76static gchar *
77make_too_long_unix_socket_path (void)
78{
79 struct sockaddr_un addr;
80 const size_t path_len = sizeof (addr.sun_path) + 1;
81 gchar *path = g_malloc (path_len + 1);
82
83 memset (path, 'a', path_len);
84 path[path_len] = '\0';
85 return path;
86}
Roger Meier213a6642010-10-27 12:30:11 +000087/* test object creation and destruction */
88static void
89test_create_and_destroy(void)
90{
91 gchar *hostname = NULL;
92 guint port = 0;
93
94 GObject *object = NULL;
95 object = g_object_new (THRIFT_TYPE_SOCKET, NULL);
James E. King, III43f4bf22017-10-28 12:54:02 -040096 g_assert (object != NULL);
Roger Meier213a6642010-10-27 12:30:11 +000097 g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
98 g_free (hostname);
99
100 g_object_unref (object);
101}
102
103static void
104test_open_and_close(void)
105{
106 ThriftSocket *tsocket = NULL;
107 ThriftTransport *transport = NULL;
108 GError *err = NULL;
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200109 int port = 51199;
110 pid_t pid;
111 int status;
Roger Meier213a6642010-10-27 12:30:11 +0000112
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200113 pid = fork ();
114 g_assert ( pid >= 0 );
Roger Meier213a6642010-10-27 12:30:11 +0000115
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200116 if ( pid == 0 )
117 {
118 /* child listens */
119 thrift_socket_server_open (port, 1);
120 exit (0);
121 } else {
122 /* parent connects, wait a bit for the socket to be created */
123 sleep (1);
Roger Meier213a6642010-10-27 12:30:11 +0000124
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200125 /* open a connection and close it */
126 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
127 "port", port, NULL);
128 transport = THRIFT_TRANSPORT (tsocket);
129 thrift_socket_open (transport, NULL);
130 g_assert (thrift_socket_is_open (transport) == TRUE);
131 thrift_socket_close (transport, NULL);
132 g_assert (thrift_socket_is_open (transport) == FALSE);
Roger Meier213a6642010-10-27 12:30:11 +0000133
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200134 /* test close failure */
135 tsocket->sd = -1;
136 thrift_socket_close (transport, NULL);
137 g_object_unref (tsocket);
138
139 /* try a hostname lookup failure */
140 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
141 NULL);
142 transport = THRIFT_TRANSPORT (tsocket);
143 g_assert (thrift_socket_open (transport, &err) == FALSE);
144 g_object_unref (tsocket);
145 g_error_free (err);
146 err = NULL;
147
148 /* try an error call to socket() */
149 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
150 transport = THRIFT_TRANSPORT (tsocket);
151 socket_error = 1;
152 g_assert (thrift_socket_open (transport, &err) == FALSE);
153 socket_error = 0;
154 g_object_unref (tsocket);
155 g_error_free (err);
156 g_assert ( wait (&status) == pid );
157 g_assert ( status == 0 );
158 }
Roger Meier213a6642010-10-27 12:30:11 +0000159}
160
161static void
162test_read_and_write(void)
163{
Roger Meier213a6642010-10-27 12:30:11 +0000164 ThriftSocket *tsocket = NULL;
165 ThriftTransport *transport = NULL;
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200166 pid_t pid;
Roger Meier213a6642010-10-27 12:30:11 +0000167 int port = 51199;
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200168 int status;
Roger Meier213a6642010-10-27 12:30:11 +0000169 guchar buf[10] = TEST_DATA; /* a buffer */
170
171 pid = fork ();
James E. King, III43f4bf22017-10-28 12:54:02 -0400172 g_assert ( pid >= 0 );
Roger Meier213a6642010-10-27 12:30:11 +0000173
174 if ( pid == 0 )
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200175 {
176 /* child listens */
177 thrift_socket_server (port);
178 exit (0);
179 } else {
180 /* parent connects, wait a bit for the socket to be created */
181 sleep (1);
Roger Meier213a6642010-10-27 12:30:11 +0000182
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200183 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
184 "port", port, NULL);
185 transport = THRIFT_TRANSPORT (tsocket);
186 g_assert (thrift_socket_open (transport, NULL) == TRUE);
187 g_assert (thrift_socket_is_open (transport));
188 thrift_socket_write (transport, buf, 10, NULL);
Roger Meier213a6642010-10-27 12:30:11 +0000189
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200190 /* write fail */
191 send_error = 1;
192 thrift_socket_write (transport, buf, 1, NULL);
193 send_error = 0;
Roger Meier213a6642010-10-27 12:30:11 +0000194
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200195 thrift_socket_write_end (transport, NULL);
196 thrift_socket_flush (transport, NULL);
197 thrift_socket_close (transport, NULL);
198 g_object_unref (tsocket);
Roger Meier213a6642010-10-27 12:30:11 +0000199
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200200 g_assert ( wait (&status) == pid );
201 g_assert ( status == 0 );
202 }
Roger Meier213a6642010-10-27 12:30:11 +0000203}
204
Roger Meier63243c62014-09-29 20:29:58 +0200205/* test ThriftSocket's peek() implementation */
206static void
207test_peek(void)
208{
209 gint status;
210 pid_t pid;
211 guint port = 51199;
212 gchar data = 'A';
213 ThriftTransport *client_transport;
214 GError *error = NULL;
215
216 client_transport = g_object_new (THRIFT_TYPE_SOCKET,
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200217 "hostname", "localhost",
218 "port", port,
219 NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200220
221 /* thrift_transport_peek returns FALSE when the socket is closed */
222 g_assert (thrift_transport_is_open (client_transport) == FALSE);
223 g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
224 g_assert (error == NULL);
225
226 pid = fork ();
227 g_assert (pid >= 0);
228
229 if (pid == 0)
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200230 {
231 ThriftServerTransport *server_transport = NULL;
Roger Meier63243c62014-09-29 20:29:58 +0200232
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200233 g_object_unref (client_transport);
Roger Meier63243c62014-09-29 20:29:58 +0200234
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200235 /* child listens */
236 server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
237 "port", port,
238 NULL);
239 g_assert (server_transport != NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200240
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200241 thrift_server_transport_listen (server_transport, &error);
242 g_assert (error == NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200243
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200244 client_transport = g_object_new
245 (THRIFT_TYPE_BUFFERED_TRANSPORT,
246 "transport", thrift_server_transport_accept (server_transport, &error),
247 "r_buf_size", 0,
248 "w_buf_size", sizeof data,
249 NULL);
250 g_assert (error == NULL);
251 g_assert (client_transport != NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200252
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200253 /* write exactly one character to the client */
254 g_assert (thrift_transport_write (client_transport,
255 &data,
256 sizeof data,
257 &error) == TRUE);
Roger Meier63243c62014-09-29 20:29:58 +0200258
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200259 thrift_transport_flush (client_transport, &error);
260 thrift_transport_write_end (client_transport, &error);
261 thrift_transport_close (client_transport, &error);
Roger Meier63243c62014-09-29 20:29:58 +0200262
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200263 g_object_unref (client_transport);
264 g_object_unref (server_transport);
Roger Meier63243c62014-09-29 20:29:58 +0200265
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200266 exit (0);
267 }
Roger Meier63243c62014-09-29 20:29:58 +0200268 else {
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200269 /* parent connects, wait a bit for the socket to be created */
270 sleep (1);
Roger Meier63243c62014-09-29 20:29:58 +0200271
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200272 /* connect to the child */
273 thrift_transport_open (client_transport, &error);
274 g_assert (error == NULL);
275 g_assert (thrift_transport_is_open (client_transport) == TRUE);
Roger Meier63243c62014-09-29 20:29:58 +0200276
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200277 /* thrift_transport_peek returns TRUE when the socket is open and there is
Roger Meier63243c62014-09-29 20:29:58 +0200278 data available to be read */
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200279 g_assert (thrift_transport_peek (client_transport, &error) == TRUE);
280 g_assert (error == NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200281
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200282 /* read exactly one character from the server */
283 g_assert_cmpint (thrift_transport_read (client_transport,
284 &data,
285 sizeof data,
286 &error), ==, sizeof data);
Roger Meier63243c62014-09-29 20:29:58 +0200287
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200288 /* thrift_transport_peek returns FALSE when the socket is open but there is
Roger Meier63243c62014-09-29 20:29:58 +0200289 no (more) data available to be read */
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200290 g_assert (thrift_transport_is_open (client_transport) == TRUE);
291 g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
292 g_assert (error == NULL);
Roger Meier63243c62014-09-29 20:29:58 +0200293
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200294 thrift_transport_read_end (client_transport, &error);
295 thrift_transport_close (client_transport, &error);
Roger Meier63243c62014-09-29 20:29:58 +0200296
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200297 g_object_unref (client_transport);
Roger Meier63243c62014-09-29 20:29:58 +0200298
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200299 g_assert (wait (&status) == pid);
300 g_assert (status == 0);
Roger Meier63243c62014-09-29 20:29:58 +0200301 }
302}
303
Roger Meier213a6642010-10-27 12:30:11 +0000304static void
Pengpeng Hou27b72082026-03-22 07:48:17 +0800305test_open_rejects_too_long_unix_path (void)
306{
307 ThriftSocket *tsocket = NULL;
308 ThriftTransport *transport = NULL;
309 GError *error = NULL;
310 gchar *path = make_too_long_unix_socket_path ();
311
312 tsocket = g_object_new (THRIFT_TYPE_SOCKET,
313 "path", path,
314 NULL);
315 transport = THRIFT_TRANSPORT (tsocket);
316
317 g_assert (thrift_socket_open (transport, &error) == FALSE);
318 g_assert_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SOCKET);
319 g_clear_error (&error);
320 g_assert (thrift_socket_is_open (transport) == FALSE);
321
322 g_object_unref (tsocket);
323 g_free (path);
324}
325
326static void
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200327thrift_socket_server_open (const int port, int times)
328{
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200329 ThriftServerTransport *transport = NULL;
330 ThriftTransport *client = NULL;
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200331 int i;
332 ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
333 "port", port, NULL);
334
335 transport = THRIFT_SERVER_TRANSPORT (tsocket);
336 thrift_server_transport_listen (transport, NULL);
337 for(i=0;i<times;i++){
338 client = thrift_server_transport_accept (transport, NULL);
339 g_assert (client != NULL);
340 thrift_socket_close (client, NULL);
341 g_object_unref (client);
342 }
343 g_object_unref (tsocket);
344}
345
346
347static void
Roger Meier213a6642010-10-27 12:30:11 +0000348thrift_socket_server (const int port)
349{
350 int bytes = 0;
351 ThriftServerTransport *transport = NULL;
352 ThriftTransport *client = NULL;
353 guchar buf[10]; /* a buffer */
354 guchar match[10] = TEST_DATA;
355
356 ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
Gonzalo Aguilar Delgado87ad2bc2017-09-15 12:26:02 +0200357 "port", port, NULL);
Roger Meier213a6642010-10-27 12:30:11 +0000358
359 transport = THRIFT_SERVER_TRANSPORT (tsocket);
360 thrift_server_transport_listen (transport, NULL);
361 client = thrift_server_transport_accept (transport, NULL);
James E. King, III43f4bf22017-10-28 12:54:02 -0400362 g_assert (client != NULL);
Roger Meier213a6642010-10-27 12:30:11 +0000363
364 /* read 10 bytes */
365 bytes = thrift_socket_read (client, buf, 10, NULL);
James E. King, III43f4bf22017-10-28 12:54:02 -0400366 g_assert (bytes == 10); /* make sure we've read 10 bytes */
367 g_assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
Roger Meier213a6642010-10-27 12:30:11 +0000368
369 /* failed read */
370 recv_error = 1;
371 thrift_socket_read (client, buf, 1, NULL);
372 recv_error = 0;
373
374 thrift_socket_read_end (client, NULL);
375 thrift_socket_close (client, NULL);
376 g_object_unref (tsocket);
377 g_object_unref (client);
378}
379
380int
Roger Meierc1010922010-11-26 10:17:48 +0000381main(int argc, char *argv[])
Roger Meier213a6642010-10-27 12:30:11 +0000382{
Jens Geyer1c190272015-07-28 23:15:18 +0200383#if (!GLIB_CHECK_VERSION (2, 36, 0))
Roger Meier213a6642010-10-27 12:30:11 +0000384 g_type_init();
Jens Geyer1c190272015-07-28 23:15:18 +0200385#endif
386
Roger Meierc1010922010-11-26 10:17:48 +0000387 g_test_init (&argc, &argv, NULL);
Roger Meier213a6642010-10-27 12:30:11 +0000388
Roger Meierc1010922010-11-26 10:17:48 +0000389 g_test_add_func ("/testtransportsocket/CreateAndDestroy", test_create_and_destroy);
390 g_test_add_func ("/testtransportsocket/OpenAndClose", test_open_and_close);
391 g_test_add_func ("/testtransportsocket/ReadAndWrite", test_read_and_write);
Roger Meier63243c62014-09-29 20:29:58 +0200392 g_test_add_func ("/testtransportsocket/Peek", test_peek);
Pengpeng Hou27b72082026-03-22 07:48:17 +0800393 g_test_add_func ("/testtransportsocket/OpenRejectsTooLongUnixPath", test_open_rejects_too_long_unix_path);
Roger Meierc1010922010-11-26 10:17:48 +0000394
395 return g_test_run ();
Roger Meier213a6642010-10-27 12:30:11 +0000396}