1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <errno.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #define __USE_GNU
25 #include <inttypes.h>
26 #include <sys/mman.h>
27 #include <sys/uio.h>
28 #include <time.h>
29 
30 #include <BufferAllocator/BufferAllocatorWrapper.h>
31 
32 #include <trusty/tipc.h>
33 
34 #define TIPC_DEFAULT_DEVNAME "/dev/trusty-ipc-dev0"
35 
36 /* clang-format off */
37 #define BENCH_RESULT_TPL                                    \
38 "{"                                                         \
39 "    \"schema_version\": 3,"                                \
40 "    \"suite_name\": \"tipc\","                           \
41 "    \"bench_name\": \"%s\","                               \
42 "    \"results\": ["                                        \
43 "        {"                                                 \
44 "            \"metric_name\": \"time_micro_sec\","          \
45 "            \"min\": \"%" PRId64 "\","                     \
46 "            \"max\": \"%" PRId64 "\","                     \
47 "            \"avg\": \"%" PRId64 "\","                     \
48 "            \"cold\": \"%" PRId64 "\","                    \
49 "            \"raw_min\": %" PRId64 ","                     \
50 "            \"raw_max\": %" PRId64 ","                     \
51 "            \"raw_avg\": %" PRId64 ","                     \
52 "            \"raw_cold\": %" PRId64 ""                     \
53 "        },"                                                \
54 "    ]"                                                     \
55 "}"
56 /* clang-format on */
57 
58 static const char *uuid_name = "com.android.ipc-unittest.srv.uuid";
59 static const char *echo_name = "com.android.ipc-unittest.srv.echo";
60 static const char *ta_only_name = "com.android.ipc-unittest.srv.ta_only";
61 static const char *ns_only_name = "com.android.ipc-unittest.srv.ns_only";
62 static const char *datasink_name = "com.android.ipc-unittest.srv.datasink";
63 static const char *closer1_name = "com.android.ipc-unittest.srv.closer1";
64 static const char *closer2_name = "com.android.ipc-unittest.srv.closer2";
65 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
66 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
67 static const char* receiver_name = "com.android.trusty.memref.receiver";
68 static const size_t memref_chunk_size = 4096;
69 
70 static const char* _sopts = "hsvDS:t:r:m:b:B:";
71 /* clang-format off */
72 static const struct option _lopts[] =  {
73     {"help",    no_argument,       0, 'h'},
74     {"silent",  no_argument,       0, 's'},
75     {"variable",no_argument,       0, 'v'},
76     {"dev",     required_argument, 0, 'D'},
77     {"srv",     required_argument, 0, 'S'},
78     {"repeat",  required_argument, 0, 'r'},
79     {"burst",   required_argument, 0, 'b'},
80     {"msgsize", required_argument, 0, 'm'},
81     {"test",    required_argument, 0, 't'},
82     {"bench",   required_argument, 0, 'B'},
83     {0, 0, 0, 0}
84 };
85 /* clang-format on */
86 
87 static const char* usage =
88         "Usage: %s [options]\n"
89         "\n"
90         "options:\n"
91         "  -h, --help            prints this message and exit\n"
92         "  -D, --dev name        device name\n"
93         "  -S, --srv name        service name\n"
94         "  -t, --test name       test to run\n"
95         "  -r, --repeat cnt      repeat count\n"
96         "  -b, --burst cnt       burst count\n"
97         "  -m, --msgsize size    max message size\n"
98         "  -v, --variable        variable message size\n"
99         "  -s, --silent          silent\n"
100         "  -B, --bench           Run as Benchmark N times\n"
101         "\n";
102 
103 static const char* usage_long =
104         "\n"
105         "The following tests are available:\n"
106         "   connect      - connect to specified service, defaults to echo+datasink\n"
107         "   connect_foo  - connect to non existing service\n"
108         "   burst_write  - send messages to datasink service\n"
109         "   echo         - send/receive messages to echo service\n"
110         "   select       - test select call\n"
111         "   blocked_read - test blocked read\n"
112         "   closer1      - connection closed by remote (test1)\n"
113         "   closer2      - connection closed by remote (test2)\n"
114         "   closer3      - connection closed by remote (test3)\n"
115         "   ta2ta-ipc    - execute TA to TA unittest\n"
116         "   dev-uuid     - print device uuid\n"
117         "   ta-access    - test ta-access flags\n"
118         "   writev       - writev test\n"
119         "   readv        - readv test\n"
120         "   send-fd      - transmit dma_buf to trusty, use as shm\n"
121         "\n";
122 
123 struct tipc_test_params {
124     uint repeat;
125     uint msgsize;
126     uint msgburst;
127     bool variable;
128     bool silent;
129     uint bench;
130     char* srv_name;
131     char* dev_name;
132     char* test_name;
133 };
134 typedef int (*tipc_test_func_t)(const struct tipc_test_params*);
135 
136 struct tipc_test_def {
137     char* test_name;
138     tipc_test_func_t func;
139 };
140 
init_params(struct tipc_test_params * params)141 static void init_params(struct tipc_test_params* params) {
142     params->repeat = 1;
143     params->msgsize = 32;
144     params->msgburst = 32;
145     params->variable = false;
146     params->silent = false;
147     params->bench = 0;
148     params->srv_name = NULL;
149     params->test_name = NULL;
150 }
151 
print_usage_and_exit(const char * prog,int code,bool verbose)152 static void print_usage_and_exit(const char *prog, int code, bool verbose)
153 {
154     fprintf(stderr, usage, prog);
155     if (verbose) fprintf(stderr, "%s", usage_long);
156     exit(code);
157 }
158 
parse_options(int argc,char ** argv,struct tipc_test_params * params)159 static void parse_options(int argc, char** argv, struct tipc_test_params* params) {
160     int c;
161     int oidx = 0;
162 
163     while (1) {
164         c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
165         if (c == -1) break; /* done */
166 
167         switch (c) {
168             case 'D':
169                 params->dev_name = strdup(optarg);
170                 break;
171 
172             case 'S':
173                 params->srv_name = strdup(optarg);
174                 break;
175 
176             case 't':
177                 params->test_name = strdup(optarg);
178                 break;
179 
180             case 'v':
181                 params->variable = true;
182                 break;
183 
184             case 'r':
185                 params->repeat = atoi(optarg);
186                 break;
187 
188             case 'm':
189                 params->msgsize = atoi(optarg);
190                 break;
191 
192             case 'b':
193                 params->msgburst = atoi(optarg);
194                 break;
195 
196             case 's':
197                 params->silent = true;
198                 break;
199 
200             case 'B':
201                 params->bench = atoi(optarg);
202                 break;
203 
204             case 'h':
205                 print_usage_and_exit(argv[0], EXIT_SUCCESS, true);
206                 break;
207 
208             default:
209                 print_usage_and_exit(argv[0], EXIT_FAILURE, false);
210         }
211     }
212 }
213 
connect_test(const struct tipc_test_params * params)214 static int connect_test(const struct tipc_test_params* params) {
215     uint i;
216     int echo_fd;
217     int dsink_fd;
218     int custom_fd;
219 
220     if (!params->silent) {
221         printf("%s: repeat = %u\n", __func__, params->repeat);
222     }
223 
224     for (i = 0; i < params->repeat; i++) {
225         if (params->srv_name) {
226             custom_fd = tipc_connect(params->dev_name, params->srv_name);
227             if (custom_fd < 0) {
228                 fprintf(stderr, "Failed to connect to '%s' service\n", params->srv_name);
229             }
230             if (custom_fd >= 0) {
231                 tipc_close(custom_fd);
232             }
233         } else {
234             echo_fd = tipc_connect(params->dev_name, echo_name);
235             if (echo_fd < 0) {
236                 fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
237             }
238             dsink_fd = tipc_connect(params->dev_name, datasink_name);
239             if (dsink_fd < 0) {
240                 fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
241             }
242 
243             if (echo_fd >= 0) {
244                 tipc_close(echo_fd);
245             }
246             if (dsink_fd >= 0) {
247                 tipc_close(dsink_fd);
248             }
249         }
250     }
251 
252     if (!params->silent) {
253         printf("%s: done\n", __func__);
254     }
255 
256     return 0;
257 }
258 
connect_foo(const struct tipc_test_params * params)259 static int connect_foo(const struct tipc_test_params* params) {
260     uint i;
261     int fd;
262 
263     if (!params->silent) {
264         printf("%s: repeat = %u\n", __func__, params->repeat);
265     }
266 
267     for (i = 0; i < params->repeat; i++) {
268         fd = tipc_connect(params->dev_name, "foo");
269         if (fd >= 0) {
270             fprintf(stderr, "succeeded to connect to '%s' service\n", "foo");
271             tipc_close(fd);
272         }
273     }
274 
275     if (!params->silent) {
276         printf("%s: done\n", __func__);
277     }
278 
279     return 0;
280 }
281 
closer1_test(const struct tipc_test_params * params)282 static int closer1_test(const struct tipc_test_params* params) {
283     uint i;
284     int fd;
285 
286     if (!params->silent) {
287         printf("%s: repeat = %u\n", __func__, params->repeat);
288     }
289 
290     for (i = 0; i < params->repeat; i++) {
291         fd = tipc_connect(params->dev_name, closer1_name);
292         if (fd < 0) {
293             fprintf(stderr, "Failed to connect to '%s' service\n", "closer1");
294             continue;
295         }
296         if (!params->silent) {
297             printf("%s: connected\n", __func__);
298         }
299         tipc_close(fd);
300     }
301 
302     if (!params->silent) {
303         printf("%s: done\n", __func__);
304     }
305 
306     return 0;
307 }
308 
closer2_test(const struct tipc_test_params * params)309 static int closer2_test(const struct tipc_test_params* params) {
310     uint i;
311     int fd;
312 
313     if (!params->silent) {
314         printf("%s: repeat = %u\n", __func__, params->repeat);
315     }
316 
317     for (i = 0; i < params->repeat; i++) {
318         fd = tipc_connect(params->dev_name, closer2_name);
319         if (fd < 0) {
320             if (!params->silent) {
321                 printf("failed to connect to '%s' service\n", "closer2");
322             }
323         } else {
324             /* this should always fail */
325             fprintf(stderr, "connected to '%s' service\n", "closer2");
326             tipc_close(fd);
327         }
328     }
329 
330     if (!params->silent) {
331         printf("%s: done\n", __func__);
332     }
333 
334     return 0;
335 }
336 
closer3_test(const struct tipc_test_params * params)337 static int closer3_test(const struct tipc_test_params* params) {
338     uint i, j;
339     ssize_t rc;
340     int fd[4];
341     char buf[64];
342 
343     if (!params->silent) {
344         printf("%s: repeat = %u\n", __func__, params->repeat);
345     }
346 
347     for (i = 0; i < params->repeat; i++) {
348         /* open 4 connections to closer3 service */
349         for (j = 0; j < 4; j++) {
350             fd[j] = tipc_connect(params->dev_name, closer3_name);
351             if (fd[j] < 0) {
352                 fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3");
353             } else {
354                 if (!params->silent) {
355                     printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]);
356                 }
357                 memset(buf, i + j, sizeof(buf));
358                 rc = write(fd[j], buf, sizeof(buf));
359                 if (rc != sizeof(buf)) {
360                     if (!params->silent) {
361                         printf("%s: fd[%d]=%d: write returned  = %zd\n", __func__, j, fd[j], rc);
362                     }
363                     perror("closer3_test: write");
364                 }
365             }
366         }
367 
368         /* sleep a bit */
369         sleep(1);
370 
371         /* It is expected that they will be closed by remote */
372         for (j = 0; j < 4; j++) {
373             if (fd[j] < 0) continue;
374             rc = write(fd[j], buf, sizeof(buf));
375             if (rc != sizeof(buf)) {
376                 if (!params->silent) {
377                     printf("%s: fd[%d]=%d: write returned = %zd\n", __func__, j, fd[j], rc);
378                 }
379                 perror("closer3_test: write");
380             }
381         }
382 
383         /* then they have to be closed by remote */
384         for (j = 0; j < 4; j++) {
385             if (fd[j] >= 0) {
386                 tipc_close(fd[j]);
387             }
388         }
389     }
390 
391     if (!params->silent) {
392         printf("%s: done\n", __func__);
393     }
394 
395     return 0;
396 }
397 
echo_test(const struct tipc_test_params * params)398 static int echo_test(const struct tipc_test_params* params) {
399     uint i;
400     ssize_t rc;
401     size_t msg_len;
402     int echo_fd = -1;
403     char tx_buf[params->msgsize];
404     char rx_buf[params->msgsize];
405 
406     if (!params->silent) {
407         printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
408                params->msgsize, params->variable ? "true" : "false");
409     }
410 
411     echo_fd = tipc_connect(params->dev_name, echo_name);
412     if (echo_fd < 0) {
413         fprintf(stderr, "Failed to connect to service\n");
414         return echo_fd;
415     }
416 
417     for (i = 0; i < params->repeat; i++) {
418         msg_len = params->msgsize;
419         if (params->variable && params->msgsize) {
420             msg_len = rand() % params->msgsize;
421         }
422 
423         memset(tx_buf, i + 1, msg_len);
424 
425         rc = write(echo_fd, tx_buf, msg_len);
426         if ((size_t)rc != msg_len) {
427             perror("echo_test: write");
428             break;
429         }
430 
431         rc = read(echo_fd, rx_buf, msg_len);
432         if (rc < 0) {
433             perror("echo_test: read");
434             break;
435         }
436 
437         if ((size_t)rc != msg_len) {
438             fprintf(stderr, "data truncated (%zu vs. %zu)\n", rc, msg_len);
439             continue;
440         }
441 
442         if (memcmp(tx_buf, rx_buf, (size_t)rc)) {
443             fprintf(stderr, "data mismatch\n");
444             continue;
445         }
446     }
447 
448     tipc_close(echo_fd);
449 
450     if (!params->silent) {
451         printf("%s: done\n", __func__);
452     }
453 
454     return 0;
455 }
456 
burst_write_test(const struct tipc_test_params * params)457 static int burst_write_test(const struct tipc_test_params* params) {
458     int fd;
459     uint i, j;
460     ssize_t rc;
461     size_t msg_len;
462     char tx_buf[params->msgsize];
463 
464     if (!params->silent) {
465         printf("%s: repeat %u: burst %u: params->msgsize %u: variable %s\n", __func__,
466                params->repeat, params->msgburst, params->msgsize,
467                params->variable ? "true" : "false");
468     }
469 
470     for (i = 0; i < params->repeat; i++) {
471         fd = tipc_connect(params->dev_name, datasink_name);
472         if (fd < 0) {
473             fprintf(stderr, "Failed to connect to '%s' service\n", "datasink");
474             break;
475         }
476 
477         for (j = 0; j < params->msgburst; j++) {
478             msg_len = params->msgsize;
479             if (params->variable && params->msgsize) {
480                 msg_len = rand() % params->msgsize;
481             }
482 
483             memset(tx_buf, i + 1, msg_len);
484             rc = write(fd, tx_buf, msg_len);
485             if ((size_t)rc != msg_len) {
486                 perror("burst_test: write");
487                 break;
488             }
489         }
490 
491         tipc_close(fd);
492     }
493 
494     if (!params->silent) {
495         printf("%s: done\n", __func__);
496     }
497 
498     return 0;
499 }
500 
_wait_for_msg(int fd,int timeout,const struct tipc_test_params * params)501 static int _wait_for_msg(int fd, int timeout, const struct tipc_test_params* params) {
502     int rc;
503     fd_set rfds;
504     uint msgcnt = 0;
505     char rx_buf[params->msgsize];
506     struct timeval tv;
507 
508     if (!params->silent) {
509         printf("waiting (%d) for msg\n", timeout);
510     }
511 
512     FD_ZERO(&rfds);
513     FD_SET(fd, &rfds);
514 
515     tv.tv_sec = timeout;
516     tv.tv_usec = 0;
517 
518     for (;;) {
519         rc = select(fd + 1, &rfds, NULL, NULL, &tv);
520 
521         if (rc == 0) {
522             if (!params->silent) {
523                 printf("select timedout\n");
524             }
525             break;
526         }
527 
528         if (rc == -1) {
529             perror("select_test: select");
530             return rc;
531         }
532 
533         rc = read(fd, rx_buf, sizeof(rx_buf));
534         if (rc < 0) {
535             perror("select_test: read");
536             return rc;
537         } else {
538             if (rc > 0) {
539                 msgcnt++;
540             }
541         }
542     }
543 
544     if (!params->silent) {
545         printf("got %u messages\n", msgcnt);
546     }
547 
548     return 0;
549 }
550 
select_test(const struct tipc_test_params * params)551 static int select_test(const struct tipc_test_params* params) {
552     int fd;
553     uint i, j;
554     ssize_t rc;
555     char tx_buf[params->msgsize];
556 
557     if (!params->silent) {
558         printf("%s: repeat %u\n", __func__, params->repeat);
559     }
560 
561     fd = tipc_connect(params->dev_name, echo_name);
562     if (fd < 0) {
563         fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
564         return fd;
565     }
566 
567     for (i = 0; i < params->repeat; i++) {
568         _wait_for_msg(fd, 1, params);
569 
570         if (!params->silent) {
571             printf("sending burst: %u msg\n", params->msgburst);
572         }
573 
574         for (j = 0; j < params->msgburst; j++) {
575             memset(tx_buf, i + j, params->msgsize);
576             rc = write(fd, tx_buf, params->msgsize);
577             if ((size_t)rc != params->msgsize) {
578                 perror("burst_test: write");
579                 break;
580             }
581         }
582     }
583 
584     tipc_close(fd);
585 
586     if (!params->silent) {
587         printf("%s: done\n", __func__);
588     }
589 
590     return 0;
591 }
592 
blocked_read_test(const struct tipc_test_params * params)593 static int blocked_read_test(const struct tipc_test_params* params) {
594     int fd;
595     uint i;
596     ssize_t rc;
597     char rx_buf[512];
598 
599     if (!params->silent) {
600         printf("%s: repeat %u\n", __func__, params->repeat);
601     }
602 
603     fd = tipc_connect(params->dev_name, echo_name);
604     if (fd < 0) {
605         fprintf(stderr, "Failed to connect to '%s' service\n", "echo");
606         return fd;
607     }
608 
609     for (i = 0; i < params->repeat; i++) {
610         rc = read(fd, rx_buf, sizeof(rx_buf));
611         if (rc < 0) {
612             perror("select_test: read");
613             break;
614         } else {
615             if (!params->silent) {
616                 printf("got %zd bytes\n", rc);
617             }
618         }
619     }
620 
621     tipc_close(fd);
622 
623     if (!params->silent) {
624         printf("%s: done\n", __func__);
625     }
626 
627     return 0;
628 }
629 
ta2ta_ipc_test(const struct tipc_test_params * params)630 static int ta2ta_ipc_test(const struct tipc_test_params* params) {
631     enum test_message_header {
632         TEST_PASSED = 0,
633         TEST_FAILED = 1,
634         TEST_MESSAGE = 2,
635         TEST_TEXT = 3,
636     };
637 
638     int fd;
639     int ret;
640     unsigned char rx_buf[256];
641 
642     if (!params->silent) {
643         printf("%s:\n", __func__);
644     }
645 
646     fd = tipc_connect(params->dev_name, main_ctrl_name);
647     if (fd < 0) {
648         fprintf(stderr, "Failed to connect to '%s' service\n", "main_ctrl");
649         return fd;
650     }
651 
652     /* Wait for tests to complete and read status */
653     while (true) {
654         ret = read(fd, rx_buf, sizeof(rx_buf));
655         if (ret <= 0 || ret >= (int)sizeof(rx_buf)) {
656             fprintf(stderr, "%s: Read failed: %d\n", __func__, ret);
657             tipc_close(fd);
658             return -1;
659         }
660 
661         if (rx_buf[0] == TEST_PASSED) {
662             break;
663         } else if (rx_buf[0] == TEST_FAILED) {
664             break;
665         } else if (rx_buf[0] == TEST_MESSAGE || rx_buf[0] == TEST_TEXT) {
666             write(STDOUT_FILENO, rx_buf + 1, ret - 1);
667         } else {
668             fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]);
669             break;
670         }
671     }
672 
673     tipc_close(fd);
674 
675     return rx_buf[0] == TEST_PASSED ? 0 : -1;
676 }
677 
678 typedef struct uuid
679 {
680     uint32_t time_low;
681     uint16_t time_mid;
682     uint16_t time_hi_and_version;
683     uint8_t clock_seq_and_node[8];
684 } uuid_t;
685 
print_uuid(const char * dev,uuid_t * uuid)686 static void print_uuid(const char *dev, uuid_t *uuid)
687 {
688     printf("%s:", dev);
689     printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", uuid->time_low,
690            uuid->time_mid, uuid->time_hi_and_version, uuid->clock_seq_and_node[0],
691            uuid->clock_seq_and_node[1], uuid->clock_seq_and_node[2], uuid->clock_seq_and_node[3],
692            uuid->clock_seq_and_node[4], uuid->clock_seq_and_node[5], uuid->clock_seq_and_node[6],
693            uuid->clock_seq_and_node[7]);
694 }
695 
dev_uuid_test(const struct tipc_test_params * params)696 static int dev_uuid_test(const struct tipc_test_params* params) {
697     int fd;
698     ssize_t rc;
699     uuid_t uuid;
700 
701     fd = tipc_connect(params->dev_name, uuid_name);
702     if (fd < 0) {
703         fprintf(stderr, "Failed to connect to '%s' service\n", "uuid");
704         return fd;
705     }
706 
707     /* wait for test to complete */
708     rc = read(fd, &uuid, sizeof(uuid));
709     if (rc < 0) {
710         perror("dev_uuid_test: read");
711     } else if (rc != sizeof(uuid)) {
712         fprintf(stderr, "unexpected uuid size (%d vs. %d)\n", (int)rc, (int)sizeof(uuid));
713     } else {
714         print_uuid(params->dev_name, &uuid);
715     }
716 
717     tipc_close(fd);
718 
719     return 0;
720 }
721 
ta_access_test(const struct tipc_test_params * params)722 static int ta_access_test(const struct tipc_test_params* params) {
723     int fd;
724 
725     if (!params->silent) {
726         printf("%s:\n", __func__);
727     }
728 
729     fd = tipc_connect(params->dev_name, ta_only_name);
730     if (fd >= 0) {
731         fprintf(stderr, "Succeed to connect to '%s' service\n", "ta_only");
732         tipc_close(fd);
733     }
734 
735     fd = tipc_connect(params->dev_name, ns_only_name);
736     if (fd < 0) {
737         fprintf(stderr, "Failed to connect to '%s' service\n", "ns_only");
738         return fd;
739     }
740     tipc_close(fd);
741 
742     if (!params->silent) {
743         printf("%s: done\n", __func__);
744     }
745 
746     return 0;
747 }
748 
writev_test(const struct tipc_test_params * params)749 static int writev_test(const struct tipc_test_params* params) {
750     uint i;
751     ssize_t rc;
752     size_t msg_len;
753     int echo_fd = -1;
754     char tx0_buf[params->msgsize];
755     char tx1_buf[params->msgsize];
756     char rx_buf[params->msgsize];
757     struct iovec iovs[2] = {{tx0_buf, 0}, {tx1_buf, 0}};
758 
759     if (!params->silent) {
760         printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
761                params->msgsize, params->variable ? "true" : "false");
762     }
763 
764     echo_fd = tipc_connect(params->dev_name, echo_name);
765     if (echo_fd < 0) {
766         fprintf(stderr, "Failed to connect to service\n");
767         return echo_fd;
768     }
769 
770     for (i = 0; i < params->repeat; i++) {
771         msg_len = params->msgsize;
772         if (params->variable && params->msgsize) {
773             msg_len = rand() % params->msgsize;
774         }
775 
776         iovs[0].iov_len = msg_len / 3;
777         iovs[1].iov_len = msg_len - iovs[0].iov_len;
778 
779         memset(tx0_buf, i + 1, iovs[0].iov_len);
780         memset(tx1_buf, i + 2, iovs[1].iov_len);
781         memset(rx_buf, i + 3, sizeof(rx_buf));
782 
783         rc = writev(echo_fd, iovs, 2);
784         if (rc < 0) {
785             perror("writev_test: writev");
786             break;
787         }
788 
789         if ((size_t)rc != msg_len) {
790             fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "writev",
791                     (size_t)rc, msg_len);
792             break;
793         }
794 
795         rc = read(echo_fd, rx_buf, sizeof(rx_buf));
796         if (rc < 0) {
797             perror("writev_test: read");
798             break;
799         }
800 
801         if ((size_t)rc != msg_len) {
802             fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "read",
803                     (size_t)rc, msg_len);
804             break;
805         }
806 
807         if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
808             fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
809             break;
810         }
811 
812         if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
813             fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
814             break;
815         }
816     }
817 
818     tipc_close(echo_fd);
819 
820     if (!params->silent) {
821         printf("%s: done\n", __func__);
822     }
823 
824     return 0;
825 }
826 
readv_test(const struct tipc_test_params * params)827 static int readv_test(const struct tipc_test_params* params) {
828     uint i;
829     ssize_t rc;
830     size_t msg_len;
831     int echo_fd = -1;
832     char tx_buf[params->msgsize];
833     char rx0_buf[params->msgsize];
834     char rx1_buf[params->msgsize];
835     struct iovec iovs[2] = {{rx0_buf, 0}, {rx1_buf, 0}};
836 
837     if (!params->silent) {
838         printf("%s: repeat %u: params->msgsize %u: variable %s\n", __func__, params->repeat,
839                params->msgsize, params->variable ? "true" : "false");
840     }
841 
842     echo_fd = tipc_connect(params->dev_name, echo_name);
843     if (echo_fd < 0) {
844         fprintf(stderr, "Failed to connect to service\n");
845         return echo_fd;
846     }
847 
848     for (i = 0; i < params->repeat; i++) {
849         msg_len = params->msgsize;
850         if (params->variable && params->msgsize) {
851             msg_len = rand() % params->msgsize;
852         }
853 
854         iovs[0].iov_len = msg_len / 3;
855         iovs[1].iov_len = msg_len - iovs[0].iov_len;
856 
857         memset(tx_buf, i + 1, sizeof(tx_buf));
858         memset(rx0_buf, i + 2, iovs[0].iov_len);
859         memset(rx1_buf, i + 3, iovs[1].iov_len);
860 
861         rc = write(echo_fd, tx_buf, msg_len);
862         if (rc < 0) {
863             perror("readv_test: write");
864             break;
865         }
866 
867         if ((size_t)rc != msg_len) {
868             fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
869                     (size_t)rc, msg_len);
870             break;
871         }
872 
873         rc = readv(echo_fd, iovs, 2);
874         if (rc < 0) {
875             perror("readv_test: readv");
876             break;
877         }
878 
879         if ((size_t)rc != msg_len) {
880             fprintf(stderr, "%s: %s: data size mismatch (%zd vs. %zd)\n", __func__, "write",
881                     (size_t)rc, msg_len);
882             break;
883         }
884 
885         if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
886             fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
887             break;
888         }
889 
890         if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
891             fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
892             break;
893         }
894     }
895 
896     tipc_close(echo_fd);
897 
898     if (!params->silent) {
899         printf("%s: done\n", __func__);
900     }
901 
902     return 0;
903 }
904 
send_fd_test(const struct tipc_test_params * params)905 static int send_fd_test(const struct tipc_test_params* params) {
906     int ret;
907     int dma_buf = -1;
908     int fd = -1;
909     volatile char* buf = MAP_FAILED;
910     BufferAllocator* allocator = NULL;
911 
912     const size_t num_chunks = 10;
913 
914     fd = tipc_connect(params->dev_name, receiver_name);
915     if (fd < 0) {
916         fprintf(stderr, "Failed to connect to test support TA - is it missing?\n");
917         ret = -1;
918         goto cleanup;
919     }
920 
921     allocator = CreateDmabufHeapBufferAllocator();
922     if (!allocator) {
923         fprintf(stderr, "Failed to create dma-buf allocator.\n");
924         ret = -1;
925         goto cleanup;
926     }
927 
928     size_t buf_size = memref_chunk_size * num_chunks;
929     dma_buf = DmabufHeapAlloc(allocator, "system", buf_size, 0, 0 /* legacy align */);
930     if (dma_buf < 0) {
931         ret = dma_buf;
932         fprintf(stderr, "Failed to create dma-buf fd of size %zu err (%d)\n", buf_size, ret);
933         goto cleanup;
934     }
935 
936     buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
937     if (buf == MAP_FAILED) {
938         fprintf(stderr, "Failed to map dma-buf: %s\n", strerror(errno));
939         ret = -1;
940         goto cleanup;
941     }
942 
943     strcpy((char*)buf, "From NS");
944 
945     struct trusty_shm shm = {
946             .fd = dma_buf,
947             .transfer = TRUSTY_SHARE,
948     };
949 
950     ssize_t rc = tipc_send(fd, NULL, 0, &shm, 1);
951     if (rc < 0) {
952         fprintf(stderr, "tipc_send failed: %zd\n", rc);
953         ret = rc;
954         goto cleanup;
955     }
956     char c;
957     read(fd, &c, 1);
958     tipc_close(fd);
959 
960     ret = 0;
961     for (size_t skip = 0; skip < num_chunks; skip++) {
962         int cmp = strcmp("Hello from Trusty!",
963                          (const char*)&buf[skip * memref_chunk_size]) ? (-1) : 0;
964         if (cmp)
965             fprintf(stderr, "Failed: Unexpected content at page %zu in dmabuf\n", skip);
966         ret |= cmp;
967     }
968 
969 cleanup:
970     if (buf != MAP_FAILED) {
971         munmap((char*)buf, buf_size);
972     }
973     close(dma_buf);
974     if (allocator) {
975         FreeDmabufHeapBufferAllocator(allocator);
976     }
977     tipc_close(fd);
978     return ret;
979 }
980 
get_time_us(void)981 uint64_t get_time_us(void) {
982     struct timespec spec;
983 
984     clock_gettime(CLOCK_MONOTONIC, &spec);
985     return spec.tv_sec * 1000000 + spec.tv_nsec / 1000;
986 }
987 
988 static const struct tipc_test_def tipc_tests[] = {
989         {"connect", connect_test},
990         {"connect_foo", connect_foo},
991         {"burst_write", burst_write_test},
992         {"select", select_test},
993         {"blocked_read", blocked_read_test},
994         {"closer1", closer1_test},
995         {"closer2", closer2_test},
996         {"closer3", closer3_test},
997         {"echo", echo_test},
998         {"ta2ta-ipc", ta2ta_ipc_test},
999         {"dev-uuid", dev_uuid_test},
1000         {"ta-access", ta_access_test},
1001         {"writev", writev_test},
1002         {"readv", readv_test},
1003         {"send-fd", send_fd_test},
1004 };
1005 
get_test_function(const struct tipc_test_params * params)1006 tipc_test_func_t get_test_function(const struct tipc_test_params* params) {
1007     for (size_t i = 0; i < sizeof(tipc_tests) / sizeof(tipc_tests[0]); i++) {
1008         if (strcmp(params->test_name, tipc_tests[i].test_name) == 0) {
1009             return tipc_tests[i].func;
1010         }
1011     }
1012     fprintf(stderr, "Unrecognized test name '%s'\n", params->test_name);
1013     exit(1);
1014 }
1015 
run_as_bench(const struct tipc_test_params * params)1016 static int run_as_bench(const struct tipc_test_params* params) {
1017     int rc = 0;
1018     int64_t min = INT64_MAX;
1019     int64_t max = 0;
1020     int64_t avg = 0;
1021     int64_t cold = 0;
1022 
1023     uint64_t start;
1024     uint64_t end;
1025 
1026     tipc_test_func_t test = get_test_function(params);
1027 
1028     for (size_t i = 0; (i < params->bench + 1) && rc == 0; ++i) {
1029         start = get_time_us();
1030         rc |= test(params);
1031         end = get_time_us();
1032         int64_t t = end - start;
1033 
1034         if (i == 0) {
1035             cold = t;
1036         } else {
1037             min = (t < min) ? t : min;
1038             max = (t > max) ? t : max;
1039             avg += t;
1040         }
1041     }
1042     avg /= params->bench;
1043 
1044     printf(BENCH_RESULT_TPL, params->test_name, min, max, avg, cold, min, max, avg, cold);
1045     return rc;
1046 }
1047 
main(int argc,char ** argv)1048 int main(int argc, char **argv)
1049 {
1050     int rc = 0;
1051 
1052     if (argc <= 1) {
1053         print_usage_and_exit(argv[0], EXIT_FAILURE, false);
1054     }
1055     struct tipc_test_params params;
1056     init_params(&params);
1057     parse_options(argc, argv, &params);
1058 
1059     if (!params.dev_name) {
1060         params.dev_name = TIPC_DEFAULT_DEVNAME;
1061     }
1062 
1063     if (!params.test_name) {
1064         fprintf(stderr, "need a Test to run\n");
1065         print_usage_and_exit(argv[0], EXIT_FAILURE, true);
1066     }
1067 
1068     if (params.bench > 0) {
1069         rc = run_as_bench(&params);
1070         params.bench = 0;
1071     } else {
1072         tipc_test_func_t test = get_test_function(&params);
1073         rc = test(&params);
1074     }
1075     return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1076 }
1077