tizen 2.3.1 release
[framework/connectivity/bluez.git] / android / test-ipc.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2013-2014  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33 #include <inttypes.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include <glib.h>
40 #include "src/shared/util.h"
41 #include "src/log.h"
42 #include "android/ipc-common.h"
43 #include "android/ipc.h"
44
45 static const char HAL_SK_PATH[] = "\0test_hal_socket";
46
47 #define SERVICE_ID_MAX 10
48
49 struct test_data {
50         bool disconnect;
51         const void *cmd;
52         uint16_t cmd_size;
53         uint8_t service;
54         const struct ipc_handler *handlers;
55         uint8_t handlers_size;
56 };
57
58 struct context {
59         GMainLoop *main_loop;
60
61         int sk;
62
63         guint source;
64         guint cmd_source;
65         guint notif_source;
66
67         GIOChannel *cmd_io;
68         GIOChannel *notif_io;
69
70         const struct test_data *data;
71 };
72
73
74 static struct ipc *ipc = NULL;
75
76 static void context_quit(struct context *context)
77 {
78         g_main_loop_quit(context->main_loop);
79 }
80
81 static gboolean cmd_watch(GIOChannel *io, GIOCondition cond,
82                                                 gpointer user_data)
83 {
84         struct context *context = user_data;
85         const struct test_data *test_data = context->data;
86         const struct ipc_hdr *sent_msg = test_data->cmd;
87         uint8_t buf[128];
88         int sk;
89
90         struct ipc_hdr success_resp = {
91                 .service_id = sent_msg->service_id,
92                 .opcode = sent_msg->opcode,
93                 .len = 0,
94         };
95
96         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
97                 g_assert(test_data->disconnect);
98                 return FALSE;
99         }
100
101         g_assert(!test_data->disconnect);
102
103         sk = g_io_channel_unix_get_fd(io);
104
105         g_assert(read(sk, buf, sizeof(buf)) == sizeof(struct ipc_hdr));
106         g_assert(!memcmp(&success_resp, buf, sizeof(struct ipc_hdr)));
107
108         context_quit(context);
109
110         return TRUE;
111 }
112
113 static gboolean notif_watch(GIOChannel *io, GIOCondition cond,
114                                                         gpointer user_data)
115 {
116         struct context *context = user_data;
117         const struct test_data *test_data = context->data;
118
119         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
120                 g_assert(test_data->disconnect);
121                 return FALSE;
122         }
123
124         g_assert(!test_data->disconnect);
125
126         return TRUE;
127 }
128
129 static gboolean connect_handler(GIOChannel *io, GIOCondition cond,
130                                                 gpointer user_data)
131 {
132         struct context *context = user_data;
133         const struct test_data *test_data = context->data;
134         GIOChannel *new_io;
135         GIOCondition watch_cond;
136         int sk;
137
138         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
139                 g_assert(FALSE);
140                 return FALSE;
141         }
142
143         g_assert(!context->cmd_source || !context->notif_source);
144
145         sk = accept(context->sk, NULL, NULL);
146         g_assert(sk >= 0);
147
148         new_io = g_io_channel_unix_new(sk);
149
150         watch_cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
151
152         if (context->cmd_source && !context->notif_source) {
153                 context->notif_source = g_io_add_watch(new_io, watch_cond,
154                                                         notif_watch, context);
155                 g_assert(context->notif_source > 0);
156                 context->notif_io = new_io;
157         }
158
159         if (!context->cmd_source) {
160                 context->cmd_source = g_io_add_watch(new_io, watch_cond,
161                                                         cmd_watch, context);
162                 context->cmd_io = new_io;
163         }
164
165         if (context->cmd_source && context->notif_source && !test_data->cmd)
166                 context_quit(context);
167
168         return TRUE;
169 }
170
171 static struct context *create_context(gconstpointer data)
172 {
173         struct context *context = g_new0(struct context, 1);
174         struct sockaddr_un addr;
175         GIOChannel *io;
176         int ret, sk;
177
178         context->main_loop = g_main_loop_new(NULL, FALSE);
179         g_assert(context->main_loop);
180
181         sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
182         g_assert(sk >= 0);
183
184         memset(&addr, 0, sizeof(addr));
185         addr.sun_family = AF_UNIX;
186
187         memcpy(addr.sun_path, HAL_SK_PATH, sizeof(HAL_SK_PATH));
188
189         ret = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
190         g_assert(ret == 0);
191
192         ret = listen(sk, 5);
193         g_assert(ret == 0);
194
195         io = g_io_channel_unix_new(sk);
196
197         g_io_channel_set_close_on_unref(io, TRUE);
198
199         context->source = g_io_add_watch(io,
200                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
201                                 connect_handler, context);
202         g_assert(context->source > 0);
203
204         g_io_channel_unref(io);
205
206         context->sk = sk;
207         context->data = data;
208
209         return context;
210 }
211
212 static void execute_context(struct context *context)
213 {
214         g_main_loop_run(context->main_loop);
215
216         g_io_channel_shutdown(context->notif_io, TRUE, NULL);
217         g_io_channel_shutdown(context->cmd_io, TRUE, NULL);
218         g_io_channel_unref(context->cmd_io);
219         g_io_channel_unref(context->notif_io);
220
221         g_source_remove(context->notif_source);
222         g_source_remove(context->cmd_source);
223         g_source_remove(context->source);
224
225         g_main_loop_unref(context->main_loop);
226
227         g_free(context);
228 }
229
230 static void disconnected(void *data)
231 {
232         struct context *context = data;
233
234         g_assert(context->data->disconnect);
235
236         context_quit(context);
237 }
238
239 static void test_init(gconstpointer data)
240 {
241         struct context *context = create_context(data);
242
243         ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
244                                                 true, NULL, NULL);
245
246         g_assert(ipc);
247
248         execute_context(context);
249
250         ipc_cleanup(ipc);
251         ipc = NULL;
252 }
253
254 static gboolean send_cmd(gpointer user_data)
255 {
256         struct context *context = user_data;
257         const struct test_data *test_data = context->data;
258         int sk;
259
260         sk = g_io_channel_unix_get_fd(context->cmd_io);
261         g_assert(sk >= 0);
262
263         g_assert(write(sk, test_data->cmd, test_data->cmd_size) ==
264                                                 test_data->cmd_size);
265
266         return FALSE;
267 }
268
269 static gboolean register_service(gpointer user_data)
270 {
271         struct context *context = user_data;
272         const struct test_data *test_data = context->data;
273
274         ipc_register(ipc, test_data->service, test_data->handlers,
275                                                 test_data->handlers_size);
276
277         return FALSE;
278 }
279
280 static gboolean unregister_service(gpointer user_data)
281 {
282         struct context *context = user_data;
283         const struct test_data *test_data = context->data;
284
285         ipc_unregister(ipc, test_data->service);
286
287         return FALSE;
288 }
289
290 static void test_cmd(gconstpointer data)
291 {
292         struct context *context = create_context(data);
293
294         ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
295                                         true, disconnected, context);
296
297         g_assert(ipc);
298
299         g_idle_add(send_cmd, context);
300
301         execute_context(context);
302
303         ipc_cleanup(ipc);
304         ipc = NULL;
305 }
306
307 static void test_cmd_reg(gconstpointer data)
308 {
309         struct context *context = create_context(data);
310         const struct test_data *test_data = context->data;
311
312         ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
313                                         true, disconnected, context);
314
315         g_assert(ipc);
316
317         g_idle_add(register_service, context);
318         g_idle_add(send_cmd, context);
319
320         execute_context(context);
321
322         ipc_unregister(ipc, test_data->service);
323
324         ipc_cleanup(ipc);
325         ipc = NULL;
326 }
327
328 static void test_cmd_reg_1(gconstpointer data)
329 {
330         struct context *context = create_context(data);
331
332         ipc = ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH), SERVICE_ID_MAX,
333                                         true, disconnected, context);
334
335         g_assert(ipc);
336
337         g_idle_add(register_service, context);
338         g_idle_add(unregister_service, context);
339         g_idle_add(send_cmd, context);
340
341         execute_context(context);
342
343         ipc_cleanup(ipc);
344         ipc = NULL;
345 }
346
347 static void test_cmd_handler_1(const void *buf, uint16_t len)
348 {
349         ipc_send_rsp(ipc, 0, 1, 0);
350 }
351
352 static void test_cmd_handler_2(const void *buf, uint16_t len)
353 {
354         ipc_send_rsp(ipc, 0, 2, 0);
355 }
356
357 static void test_cmd_handler_invalid(const void *buf, uint16_t len)
358 {
359         g_assert(false);
360 }
361
362 static const struct test_data test_init_1 = {};
363
364 static const struct ipc_hdr test_cmd_1_hdr = {
365         .service_id = 0,
366         .opcode = 1,
367         .len = 0
368 };
369
370 static const struct ipc_hdr test_cmd_2_hdr = {
371         .service_id = 0,
372         .opcode = 2,
373         .len = 0
374 };
375
376 static const struct test_data test_cmd_service_invalid_1 = {
377         .cmd = &test_cmd_1_hdr,
378         .cmd_size = sizeof(test_cmd_1_hdr),
379         .disconnect = true,
380 };
381
382 static const struct ipc_handler cmd_handlers[] = {
383         { test_cmd_handler_1, false, 0 }
384 };
385
386 static const struct test_data test_cmd_service_valid_1 = {
387         .cmd = &test_cmd_1_hdr,
388         .cmd_size = sizeof(test_cmd_1_hdr),
389         .service = 0,
390         .handlers = cmd_handlers,
391         .handlers_size = 1
392 };
393
394 static const struct test_data test_cmd_service_invalid_2 = {
395         .cmd = &test_cmd_1_hdr,
396         .cmd_size = sizeof(test_cmd_1_hdr),
397         .service = 0,
398         .handlers = cmd_handlers,
399         .handlers_size = 1,
400         .disconnect = true,
401 };
402
403 static const struct ipc_handler cmd_handlers_invalid_2[] = {
404         { test_cmd_handler_1, false, 0 },
405         { test_cmd_handler_invalid, false, 0 }
406 };
407
408 static const struct ipc_handler cmd_handlers_invalid_1[] = {
409         { test_cmd_handler_invalid, false, 0 },
410         { test_cmd_handler_2, false, 0 },
411 };
412
413 static const struct test_data test_cmd_opcode_valid_1 = {
414         .cmd = &test_cmd_1_hdr,
415         .cmd_size = sizeof(test_cmd_1_hdr),
416         .service = 0,
417         .handlers = cmd_handlers_invalid_2,
418         .handlers_size = 2,
419 };
420
421 static const struct test_data test_cmd_opcode_valid_2 = {
422         .cmd = &test_cmd_2_hdr,
423         .cmd_size = sizeof(test_cmd_2_hdr),
424         .service = 0,
425         .handlers = cmd_handlers_invalid_1,
426         .handlers_size = 2,
427 };
428
429 static const struct test_data test_cmd_opcode_invalid_1 = {
430         .cmd = &test_cmd_2_hdr,
431         .cmd_size = sizeof(test_cmd_2_hdr),
432         .service = 0,
433         .handlers = cmd_handlers,
434         .handlers_size = 1,
435         .disconnect = true,
436 };
437
438 static const struct test_data test_cmd_hdr_invalid = {
439         .cmd = &test_cmd_1_hdr,
440         .cmd_size = sizeof(test_cmd_1_hdr) - 1,
441         .service = 0,
442         .handlers = cmd_handlers,
443         .handlers_size = 1,
444         .disconnect = true,
445 };
446
447 #define VARDATA_EX1 "some data example"
448
449 struct vardata {
450         struct ipc_hdr hdr;
451         uint8_t data[IPC_MTU - sizeof(struct ipc_hdr)];
452 } __attribute__((packed));
453
454 static const struct vardata test_cmd_vardata = {
455         .hdr.service_id = 0,
456         .hdr.opcode = 1,
457         .hdr.len = sizeof(VARDATA_EX1),
458         .data = VARDATA_EX1,
459 };
460
461 static const struct ipc_handler cmd_vardata_handlers[] = {
462         { test_cmd_handler_1, true, sizeof(VARDATA_EX1) }
463 };
464
465 static const struct test_data test_cmd_vardata_valid = {
466         .cmd = &test_cmd_vardata,
467         .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
468         .service = 0,
469         .handlers = cmd_vardata_handlers,
470         .handlers_size = 1,
471 };
472
473 static const struct ipc_handler cmd_vardata_handlers_valid2[] = {
474         { test_cmd_handler_1, true, sizeof(VARDATA_EX1) - 1 }
475 };
476
477 static const struct test_data test_cmd_vardata_valid_2 = {
478         .cmd = &test_cmd_vardata,
479         .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
480         .service = 0,
481         .handlers = cmd_vardata_handlers_valid2,
482         .handlers_size = 1,
483 };
484
485 static const struct test_data test_cmd_vardata_invalid_1 = {
486         .cmd = &test_cmd_vardata,
487         .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1) - 1,
488         .service = 0,
489         .handlers = cmd_vardata_handlers,
490         .handlers_size = 1,
491         .disconnect = true,
492 };
493
494 static const struct ipc_hdr test_cmd_service_offrange_hdr = {
495         .service_id = SERVICE_ID_MAX + 1,
496         .opcode = 1,
497         .len = 0
498 };
499
500 static const struct test_data test_cmd_service_offrange = {
501         .cmd = &test_cmd_service_offrange_hdr,
502         .cmd_size = sizeof(struct ipc_hdr),
503         .service = 0,
504         .handlers = cmd_handlers,
505         .handlers_size = 1,
506         .disconnect = true,
507 };
508
509 static const struct vardata test_cmd_invalid_data_1 = {
510         .hdr.service_id = 0,
511         .hdr.opcode = 1,
512         .hdr.len = sizeof(VARDATA_EX1),
513         .data = VARDATA_EX1,
514 };
515
516 static const struct test_data test_cmd_msg_invalid_1 = {
517         .cmd = &test_cmd_invalid_data_1,
518         .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1) - 1,
519         .service = 0,
520         .handlers = cmd_handlers,
521         .handlers_size = 1,
522         .disconnect = true,
523 };
524
525 static const struct vardata test_cmd_invalid_data_2 = {
526         .hdr.service_id = 0,
527         .hdr.opcode = 1,
528         .hdr.len = sizeof(VARDATA_EX1) - 1,
529         .data = VARDATA_EX1,
530 };
531
532 static const struct test_data test_cmd_msg_invalid_2 = {
533         .cmd = &test_cmd_invalid_data_2,
534         .cmd_size = sizeof(struct ipc_hdr) + sizeof(VARDATA_EX1),
535         .service = 0,
536         .handlers = cmd_handlers,
537         .handlers_size = 1,
538         .disconnect = true,
539 };
540
541 int main(int argc, char *argv[])
542 {
543         g_test_init(&argc, &argv, NULL);
544
545         if (g_test_verbose())
546                 __btd_log_init("*", 0);
547
548         g_test_add_data_func("/android_ipc/init", &test_init_1, test_init);
549         g_test_add_data_func("/android_ipc/service_invalid_1",
550                                 &test_cmd_service_invalid_1, test_cmd);
551         g_test_add_data_func("/android_ipc/service_valid_1",
552                                 &test_cmd_service_valid_1, test_cmd_reg);
553         g_test_add_data_func("/android_ipc/service_invalid_2",
554                                 &test_cmd_service_invalid_2, test_cmd_reg_1);
555         g_test_add_data_func("/android_ipc/opcode_valid_1",
556                                 &test_cmd_opcode_valid_1, test_cmd_reg);
557         g_test_add_data_func("/android_ipc/opcode_valid_2",
558                                 &test_cmd_opcode_valid_2, test_cmd_reg);
559         g_test_add_data_func("/android_ipc/opcode_invalid_1",
560                                 &test_cmd_opcode_invalid_1, test_cmd_reg);
561         g_test_add_data_func("/android_ipc/vardata_valid",
562                                 &test_cmd_vardata_valid, test_cmd_reg);
563         g_test_add_data_func("/android_ipc/vardata_valid_2",
564                                 &test_cmd_vardata_valid_2, test_cmd_reg);
565         g_test_add_data_func("/android_ipc/vardata_invalid_1",
566                                 &test_cmd_vardata_invalid_1, test_cmd_reg);
567         g_test_add_data_func("/android_ipc/service_offrange",
568                                 &test_cmd_service_offrange, test_cmd_reg);
569         g_test_add_data_func("/android_ipc/hdr_invalid",
570                                 &test_cmd_hdr_invalid, test_cmd_reg);
571         g_test_add_data_func("/android_ipc/msg_invalid_1",
572                                 &test_cmd_msg_invalid_1, test_cmd_reg);
573         g_test_add_data_func("/android_ipc/msg_invalid_2",
574                                 &test_cmd_msg_invalid_2, test_cmd_reg);
575
576         return g_test_run();
577 }