1 /**************************************************************************
2 *
3 * Copyright (C) 2015 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <sys/un.h>
38 #include <fcntl.h>
39 #include <getopt.h>
40 #include <string.h>
41
42 #include "util.h"
43 #include "util/u_double_list.h"
44 #include "util/u_math.h"
45 #include "util/u_memory.h"
46 #include "vtest.h"
47 #include "vtest_protocol.h"
48 #include "virglrenderer.h"
49 #ifdef HAVE_SYS_SELECT_H
50 #include <sys/select.h>
51 #endif
52
53 enum vtest_client_error {
54 VTEST_CLIENT_ERROR_INPUT_READ = 2, /* for backward compatibility */
55 VTEST_CLIENT_ERROR_CONTEXT_MISSING,
56 VTEST_CLIENT_ERROR_CONTEXT_FAILED,
57 VTEST_CLIENT_ERROR_COMMAND_ID,
58 VTEST_CLIENT_ERROR_COMMAND_UNEXPECTED,
59 VTEST_CLIENT_ERROR_COMMAND_DISPATCH,
60 };
61
62 struct vtest_client
63 {
64 int in_fd;
65 int out_fd;
66 struct vtest_input input;
67
68 struct list_head head;
69
70 bool in_fd_ready;
71 struct vtest_context *context;
72 int context_poll_fd;
73 bool context_need_poll;
74 };
75
76 struct vtest_server
77 {
78 const char *socket_name;
79 int socket;
80 const char *read_file;
81
82 const char *render_device;
83
84 bool main_server;
85 bool do_fork;
86 bool loop;
87 bool multi_clients;
88
89 bool use_glx;
90 bool use_egl_surfaceless;
91 bool use_gles;
92
93 bool venus;
94 bool render_server;
95
96 int ctx_flags;
97
98 struct list_head new_clients;
99 struct list_head active_clients;
100 struct list_head inactive_clients;
101 };
102
103 struct vtest_server server = {
104 .socket_name = VTEST_DEFAULT_SOCKET_NAME,
105 .socket = -1,
106
107 .read_file = NULL,
108
109 .render_device = 0,
110
111 .main_server = true,
112 .do_fork = true,
113 .loop = true,
114 .multi_clients = false,
115
116 .ctx_flags = 0,
117 };
118
119 static void vtest_server_getenv(void);
120 static void vtest_server_parse_args(int argc, char **argv);
121 static void vtest_server_set_signal_child(void);
122 static void vtest_server_set_signal_segv(void);
123 static void vtest_server_open_read_file(void);
124 static void vtest_server_open_socket(void);
125 static void vtest_server_run(void);
126 static void vtest_server_close_socket(void);
127 static int vtest_client_dispatch_commands(struct vtest_client *client);
128
129
main(int argc,char ** argv)130 int main(int argc, char **argv)
131 {
132 #ifdef __AFL_LOOP
133 while (__AFL_LOOP(1000)) {
134 #endif
135
136 vtest_server_getenv();
137 vtest_server_parse_args(argc, argv);
138
139 list_inithead(&server.new_clients);
140 list_inithead(&server.active_clients);
141 list_inithead(&server.inactive_clients);
142
143 if (server.do_fork) {
144 vtest_server_set_signal_child();
145 } else {
146 vtest_server_set_signal_segv();
147 }
148
149 vtest_server_run();
150
151 #ifdef __AFL_LOOP
152 if (!server.main_server) {
153 exit(0);
154 }
155 }
156 #endif
157 }
158
159 #define OPT_NO_FORK 'f'
160 #define OPT_NO_LOOP_OR_FORK 'l'
161 #define OPT_MULTI_CLIENTS 'm'
162 #define OPT_USE_GLX 'x'
163 #define OPT_USE_EGL_SURFACELESS 's'
164 #define OPT_USE_GLES 'e'
165 #define OPT_RENDERNODE 'r'
166 #define OPT_VENUS 'v'
167 #define OPT_RENDER_SERVER 'n'
168 #define OPT_SOCKET_PATH 'p'
169
vtest_server_parse_args(int argc,char ** argv)170 static void vtest_server_parse_args(int argc, char **argv)
171 {
172 int ret;
173
174 static struct option long_options[] = {
175 {"no-fork", no_argument, NULL, OPT_NO_FORK},
176 {"no-loop-or-fork", no_argument, NULL, OPT_NO_LOOP_OR_FORK},
177 {"multi-clients", no_argument, NULL, OPT_MULTI_CLIENTS},
178 {"use-glx", no_argument, NULL, OPT_USE_GLX},
179 {"use-egl-surfaceless", no_argument, NULL, OPT_USE_EGL_SURFACELESS},
180 {"use-gles", no_argument, NULL, OPT_USE_GLES},
181 {"rendernode", required_argument, NULL, OPT_RENDERNODE},
182 {"venus", no_argument, NULL, OPT_VENUS},
183 {"render-server", no_argument, NULL, OPT_RENDER_SERVER},
184 {"socket-path", optional_argument, NULL, OPT_SOCKET_PATH},
185 {0, 0, 0, 0}
186 };
187
188 /* getopt_long stores the option index here. */
189 int option_index = 0;
190
191 do {
192 ret = getopt_long(argc, argv, "", long_options, &option_index);
193
194 switch (ret) {
195 case -1:
196 break;
197 case OPT_NO_FORK:
198 server.do_fork = false;
199 break;
200 case OPT_NO_LOOP_OR_FORK:
201 server.do_fork = false;
202 server.loop = false;
203 break;
204 case OPT_MULTI_CLIENTS:
205 printf("multi-clients enabled: clients must trust each other\n");
206 server.multi_clients = true;
207 break;
208 case OPT_USE_GLX:
209 server.use_glx = true;
210 break;
211 case OPT_USE_EGL_SURFACELESS:
212 server.use_egl_surfaceless = true;
213 break;
214 case OPT_USE_GLES:
215 server.use_gles = true;
216 break;
217 case OPT_RENDERNODE:
218 server.render_device = optarg;
219 break;
220 #ifdef ENABLE_VENUS
221 case OPT_VENUS:
222 server.venus = true;
223 break;
224 #endif
225 #ifdef ENABLE_RENDER_SERVER
226 case OPT_RENDER_SERVER:
227 server.render_server = true;
228 break;
229 #endif
230 case OPT_SOCKET_PATH:
231 server.socket_name = optarg;
232 break;
233 default:
234 printf("Usage: %s [--no-fork] [--no-loop-or-fork] [--multi-clients] "
235 "[--use-glx] [--use-egl-surfaceless] [--use-gles] "
236 "[--rendernode <dev>] [--socket-path <path>] "
237 #ifdef ENABLE_VENUS
238 " [--venus]"
239 #endif
240 #ifdef ENABLE_RENDER_SERVER
241 " [--render-server]"
242 #endif
243 " [file]\n", argv[0]);
244 exit(EXIT_FAILURE);
245 break;
246 }
247
248 } while (ret >= 0);
249
250 if (optind < argc) {
251 server.read_file = argv[optind];
252 server.loop = false;
253 server.do_fork = false;
254 server.multi_clients = false;
255 }
256
257 server.ctx_flags = VIRGL_RENDERER_USE_EGL;
258 if (server.use_glx) {
259 if (server.use_egl_surfaceless || server.use_gles) {
260 fprintf(stderr, "Cannot use surfaceless or GLES with GLX.\n");
261 exit(EXIT_FAILURE);
262 }
263 server.ctx_flags = VIRGL_RENDERER_USE_GLX;
264 } else {
265 if (server.use_egl_surfaceless)
266 server.ctx_flags |= VIRGL_RENDERER_USE_SURFACELESS;
267 if (server.use_gles)
268 server.ctx_flags |= VIRGL_RENDERER_USE_GLES;
269 }
270
271 if (server.venus) {
272 server.ctx_flags |= VIRGL_RENDERER_VENUS;
273 }
274 if (server.render_server) {
275 server.ctx_flags |= VIRGL_RENDERER_RENDER_SERVER;
276 }
277 }
278
vtest_server_getenv(void)279 static void vtest_server_getenv(void)
280 {
281 server.use_glx = getenv("VTEST_USE_GLX") != NULL;
282 server.use_egl_surfaceless = getenv("VTEST_USE_EGL_SURFACELESS") != NULL;
283 server.use_gles = getenv("VTEST_USE_GLES") != NULL;
284 server.render_device = getenv("VTEST_RENDERNODE");
285 }
286
handler(int sig,siginfo_t * si,void * unused)287 static void handler(int sig, siginfo_t *si, void *unused)
288 {
289 (void)sig; (void)si, (void)unused;
290
291 printf("SIGSEGV!\n");
292 exit(EXIT_FAILURE);
293 }
294
vtest_server_set_signal_child(void)295 static void vtest_server_set_signal_child(void)
296 {
297 struct sigaction sa;
298 int ret;
299
300 memset(&sa, 0, sizeof(sa));
301 sigemptyset(&sa.sa_mask);
302 sa.sa_handler = SIG_IGN;
303 sa.sa_flags = 0;
304
305 ret = sigaction(SIGCHLD, &sa, NULL);
306 if (ret == -1) {
307 perror("Failed to set SIGCHLD");
308 exit(1);
309 }
310 }
311
vtest_server_set_signal_segv(void)312 static void vtest_server_set_signal_segv(void)
313 {
314 struct sigaction sa;
315 int ret;
316
317 memset(&sa, 0, sizeof(sa));
318 sigemptyset(&sa.sa_mask);
319 sa.sa_flags = SA_SIGINFO;
320 sa.sa_sigaction = handler;
321
322 ret = sigaction(SIGSEGV, &sa, NULL);
323 if (ret == -1) {
324 perror("Failed to set SIGSEGV");
325 exit(1);
326 }
327 }
328
vtest_server_add_client(int in_fd,int out_fd)329 static int vtest_server_add_client(int in_fd, int out_fd)
330 {
331 struct vtest_client *client;
332
333 client = calloc(1, sizeof(*client));
334 if (!client)
335 return -1;
336
337 client->in_fd = in_fd;
338 client->out_fd = out_fd;
339
340 client->input.data.fd = in_fd;
341 client->input.read = vtest_block_read;
342
343 client->context_poll_fd = -1;
344
345 list_addtail(&client->head, &server.new_clients);
346
347 return 0;
348 }
349
vtest_server_open_read_file(void)350 static void vtest_server_open_read_file(void)
351 {
352 int in_fd;
353 int out_fd;
354
355 in_fd = open(server.read_file, O_RDONLY);
356 if (in_fd == -1) {
357 perror(NULL);
358 exit(1);
359 }
360
361 out_fd = open("/dev/null", O_WRONLY);
362 if (out_fd == -1) {
363 perror(NULL);
364 exit(1);
365 }
366
367 if (vtest_server_add_client(in_fd, out_fd)) {
368 perror(NULL);
369 exit(1);
370 }
371 }
372
vtest_server_open_socket(void)373 static void vtest_server_open_socket(void)
374 {
375 struct sockaddr_un un;
376
377 server.socket = socket(PF_UNIX, SOCK_STREAM, 0);
378 if (server.socket < 0) {
379 goto err;
380 }
381
382 memset(&un, 0, sizeof(un));
383 un.sun_family = AF_UNIX;
384
385 snprintf(un.sun_path, sizeof(un.sun_path), "%s", server.socket_name);
386
387 unlink(un.sun_path);
388
389 if (bind(server.socket, (struct sockaddr *)&un, sizeof(un)) < 0) {
390 goto err;
391 }
392
393 if (listen(server.socket, 1) < 0){
394 goto err;
395 }
396
397 return;
398
399 err:
400 perror("Failed to setup socket.");
401 exit(1);
402 }
403
vtest_server_wait_clients(void)404 static void vtest_server_wait_clients(void)
405 {
406 struct vtest_client *client;
407 fd_set read_fds;
408 int max_fd = -1;
409 int ret;
410
411 FD_ZERO(&read_fds);
412
413 LIST_FOR_EACH_ENTRY(client, &server.active_clients, head) {
414 FD_SET(client->in_fd, &read_fds);
415 max_fd = MAX2(client->in_fd, max_fd);
416
417 if (client->context_poll_fd >= 0) {
418 FD_SET(client->context_poll_fd, &read_fds);
419 max_fd = MAX2(client->context_poll_fd, max_fd);
420 }
421 }
422
423 /* accept new clients when there is none or when multi_clients is set */
424 if (server.socket >= 0 && (max_fd < 0 || server.multi_clients)) {
425 FD_SET(server.socket, &read_fds);
426 max_fd = MAX2(server.socket, max_fd);
427 }
428
429 if (max_fd < 0) {
430 if (!LIST_IS_EMPTY(&server.new_clients)) {
431 return;
432 }
433
434 fprintf(stderr, "server has no fd to wait\n");
435 exit(1);
436 }
437
438 ret = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
439 if (ret < 0) {
440 perror("Failed to select on socket!");
441 exit(1);
442 }
443
444 LIST_FOR_EACH_ENTRY(client, &server.active_clients, head) {
445 if (FD_ISSET(client->in_fd, &read_fds)) {
446 client->in_fd_ready = true;
447 }
448
449 if (client->context_poll_fd >= 0) {
450 if (FD_ISSET(client->context_poll_fd, &read_fds)) {
451 client->context_need_poll = true;
452 }
453 } else if (client->context) {
454 client->context_need_poll = true;
455 }
456 }
457
458 if (server.socket >= 0 && FD_ISSET(server.socket, &read_fds)) {
459 int new_fd = accept(server.socket, NULL, NULL);
460 if (new_fd < 0) {
461 perror("Failed to accept socket.");
462 exit(1);
463 }
464
465 if (vtest_server_add_client(new_fd, new_fd)) {
466 perror("Failed to add client.");
467 exit(1);
468 }
469 }
470 }
471
vtest_client_error_string(enum vtest_client_error err)472 static const char *vtest_client_error_string(enum vtest_client_error err)
473 {
474 switch (err) {
475 #define CASE(e) case e: return #e;
476 CASE(VTEST_CLIENT_ERROR_INPUT_READ)
477 CASE(VTEST_CLIENT_ERROR_CONTEXT_MISSING)
478 CASE(VTEST_CLIENT_ERROR_CONTEXT_FAILED)
479 CASE(VTEST_CLIENT_ERROR_COMMAND_ID)
480 CASE(VTEST_CLIENT_ERROR_COMMAND_UNEXPECTED)
481 CASE(VTEST_CLIENT_ERROR_COMMAND_DISPATCH)
482 #undef CASE
483 default: return "VTEST_CLIENT_ERROR_UNKNOWN";
484 }
485 }
486
vtest_server_dispatch_clients(void)487 static void vtest_server_dispatch_clients(void)
488 {
489 struct vtest_client *client, *tmp;
490
491 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.active_clients, head) {
492 int err;
493
494 if (client->context_need_poll) {
495 vtest_poll_context(client->context);
496 client->context_need_poll = false;
497 }
498
499 if (!client->in_fd_ready)
500 continue;
501 client->in_fd_ready = false;
502
503 err = vtest_client_dispatch_commands(client);
504 if (err) {
505 fprintf(stderr, "client failed: %s\n",
506 vtest_client_error_string(err));
507 list_del(&client->head);
508 list_addtail(&client->head, &server.inactive_clients);
509 }
510 }
511 }
512
vtest_server_fork(void)513 static pid_t vtest_server_fork(void)
514 {
515 pid_t pid = fork();
516
517 if (pid == 0) {
518 /* child */
519 vtest_server_set_signal_segv();
520 vtest_server_close_socket();
521 server.main_server = false;
522 server.do_fork = false;
523 server.loop = false;
524 server.multi_clients = false;
525 }
526
527 return pid;
528 }
529
vtest_server_fork_clients(void)530 static void vtest_server_fork_clients(void)
531 {
532 struct vtest_client *client, *tmp;
533
534 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.new_clients, head) {
535 if (vtest_server_fork()) {
536 /* parent: move new clients to the inactive list */
537 list_del(&client->head);
538 list_addtail(&client->head, &server.inactive_clients);
539 } else {
540 /* child: move the first new client to the active list */
541 list_del(&client->head);
542 list_addtail(&client->head, &server.active_clients);
543
544 /* move the rest new clients to the inactive list */
545 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.new_clients, head) {
546 list_del(&client->head);
547 list_addtail(&client->head, &server.inactive_clients);
548 }
549 }
550 }
551 }
552
vtest_server_activate_clients(void)553 static void vtest_server_activate_clients(void)
554 {
555 struct vtest_client *client, *tmp;
556
557 /* move new clients to the active list */
558 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.new_clients, head) {
559 list_addtail(&client->head, &server.active_clients);
560 }
561 list_inithead(&server.new_clients);
562 }
563
vtest_server_inactivate_clients(void)564 static void vtest_server_inactivate_clients(void)
565 {
566 struct vtest_client *client, *tmp;
567
568 /* move active clients to the inactive list */
569 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.active_clients, head) {
570 list_addtail(&client->head, &server.inactive_clients);
571 }
572 list_inithead(&server.active_clients);
573 }
574
vtest_server_tidy_clients(void)575 static void vtest_server_tidy_clients(void)
576 {
577 struct vtest_client *client, *tmp;
578
579 LIST_FOR_EACH_ENTRY_SAFE(client, tmp, &server.inactive_clients, head) {
580 if (client->context) {
581 vtest_destroy_context(client->context);
582 }
583
584 if (client->in_fd >= 0) {
585 close(client->in_fd);
586 }
587
588 if (client->out_fd >= 0 && client->out_fd != client->in_fd) {
589 close(client->out_fd);
590 }
591
592 free(client);
593 }
594
595 list_inithead(&server.inactive_clients);
596 }
597
vtest_server_run(void)598 static void vtest_server_run(void)
599 {
600 bool run = true;
601
602 if (server.read_file) {
603 vtest_server_open_read_file();
604 } else {
605 vtest_server_open_socket();
606 }
607
608 while (run) {
609 const bool was_empty = LIST_IS_EMPTY(&server.active_clients);
610 bool is_empty;
611
612 vtest_server_wait_clients();
613 vtest_server_dispatch_clients();
614
615 if (server.do_fork) {
616 vtest_server_fork_clients();
617 } else {
618 vtest_server_activate_clients();
619 }
620
621 /* init renderer after the first active client is added */
622 is_empty = LIST_IS_EMPTY(&server.active_clients);
623 if (was_empty && !is_empty) {
624 int ret = vtest_init_renderer(server.multi_clients,
625 server.ctx_flags,
626 server.render_device);
627 if (ret) {
628 vtest_server_inactivate_clients();
629 run = false;
630 }
631 }
632
633 vtest_server_tidy_clients();
634
635 /* clean up renderer after the last active client is removed */
636 if (!was_empty && is_empty) {
637 vtest_cleanup_renderer();
638 if (!server.loop) {
639 run = false;
640 }
641 }
642 }
643
644 vtest_server_close_socket();
645 }
646
647 static const struct vtest_command {
648 int (*dispatch)(uint32_t);
649 bool init_context;
650 } vtest_commands[] = {
651 /* CMD ids starts at 1 */
652 [0] = { NULL, false },
653 [VCMD_GET_CAPS] = { vtest_send_caps, false },
654 [VCMD_RESOURCE_CREATE] = { vtest_create_resource, true },
655 [VCMD_RESOURCE_UNREF] = { vtest_resource_unref, true },
656 [VCMD_TRANSFER_GET] = { vtest_transfer_get, true },
657 [VCMD_TRANSFER_PUT] = { vtest_transfer_put, true },
658 [VCMD_SUBMIT_CMD] = { vtest_submit_cmd, true },
659 [VCMD_RESOURCE_BUSY_WAIT] = { vtest_resource_busy_wait, false },
660 /* VCMD_CREATE_RENDERER is a special case */
661 [VCMD_CREATE_RENDERER] = { NULL, false },
662 [VCMD_GET_CAPS2] = { vtest_send_caps2, false },
663 [VCMD_PING_PROTOCOL_VERSION] = { vtest_ping_protocol_version, false },
664 [VCMD_PROTOCOL_VERSION] = { vtest_protocol_version, false },
665
666 /* since protocol version 2 */
667 [VCMD_RESOURCE_CREATE2] = { vtest_create_resource2, true },
668 [VCMD_TRANSFER_GET2] = { vtest_transfer_get2, true },
669 [VCMD_TRANSFER_PUT2] = { vtest_transfer_put2, true },
670
671 /* since protocol version 3 */
672 [VCMD_GET_PARAM] = { vtest_get_param, false },
673 [VCMD_GET_CAPSET] = { vtest_get_capset, false },
674 [VCMD_CONTEXT_INIT] = { vtest_context_init, false },
675 [VCMD_RESOURCE_CREATE_BLOB] = { vtest_resource_create_blob, true },
676 [VCMD_SYNC_CREATE] = { vtest_sync_create, true },
677 [VCMD_SYNC_UNREF] = { vtest_sync_unref, true },
678 [VCMD_SYNC_READ] = { vtest_sync_read, true },
679 [VCMD_SYNC_WRITE] = { vtest_sync_write, true },
680 [VCMD_SYNC_WAIT] = { vtest_sync_wait, true },
681 [VCMD_SUBMIT_CMD2] = { vtest_submit_cmd2, true },
682 };
683
vtest_client_dispatch_commands(struct vtest_client * client)684 static int vtest_client_dispatch_commands(struct vtest_client *client)
685 {
686 const struct vtest_command *cmd;
687 int ret;
688 uint32_t header[VTEST_HDR_SIZE];
689
690 ret = client->input.read(&client->input, &header, sizeof(header));
691 if (ret < 0 || (size_t)ret < sizeof(header)) {
692 return VTEST_CLIENT_ERROR_INPUT_READ;
693 }
694
695 if (!client->context) {
696 /* The first command MUST be VCMD_CREATE_RENDERER */
697 if (header[1] != VCMD_CREATE_RENDERER) {
698 return VTEST_CLIENT_ERROR_CONTEXT_MISSING;
699 }
700
701 ret = vtest_create_context(&client->input, client->out_fd,
702 header[0], &client->context);
703 if (ret < 0) {
704 return VTEST_CLIENT_ERROR_CONTEXT_FAILED;
705 }
706 printf("%s: client context created.\n", __func__);
707 vtest_poll_resource_busy_wait();
708
709 return 0;
710 }
711
712 vtest_poll_resource_busy_wait();
713 if (header[1] <= 0 || header[1] >= ARRAY_SIZE(vtest_commands)) {
714 return VTEST_CLIENT_ERROR_COMMAND_ID;
715 }
716
717 cmd = &vtest_commands[header[1]];
718 if (cmd->dispatch == NULL) {
719 return VTEST_CLIENT_ERROR_COMMAND_UNEXPECTED;
720 }
721
722 /* we should consider per-context dispatch table to get rid of if's */
723 if (cmd->init_context) {
724 ret = vtest_lazy_init_context(client->context);
725 if (ret) {
726 return VTEST_CLIENT_ERROR_CONTEXT_FAILED;
727 }
728 client->context_poll_fd = vtest_get_context_poll_fd(client->context);
729 }
730
731 vtest_set_current_context(client->context);
732
733 ret = cmd->dispatch(header[0]);
734 if (ret < 0) {
735 return VTEST_CLIENT_ERROR_COMMAND_DISPATCH;
736 }
737
738 return 0;
739 }
740
vtest_server_close_socket(void)741 static void vtest_server_close_socket(void)
742 {
743 if (server.socket != -1) {
744 close(server.socket);
745 server.socket = -1;
746 }
747 }
748