xref: /openbmc/qemu/tests/unit/test-io-channel-socket.c (revision 7e3b6d8063f245d27eecce5aabe624b5785f2a77)
1  /*
2   * QEMU I/O channel sockets test
3   *
4   * Copyright (c) 2015-2016 Red Hat, Inc.
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public
8   * License as published by the Free Software Foundation; either
9   * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18   *
19   */
20  
21  #include "qemu/osdep.h"
22  #include "io/channel-socket.h"
23  #include "io/channel-util.h"
24  #include "io-channel-helpers.h"
25  #include "socket-helpers.h"
26  #include "qapi/error.h"
27  #include "qemu/module.h"
28  #include "qemu/main-loop.h"
29  
30  
test_io_channel_set_socket_bufs(QIOChannel * src,QIOChannel * dst)31  static void test_io_channel_set_socket_bufs(QIOChannel *src,
32                                              QIOChannel *dst)
33  {
34      int buflen = 64 * 1024;
35  
36      /*
37       * Make the socket buffers small so that we see
38       * the effects of partial reads/writes
39       */
40      setsockopt(((QIOChannelSocket *)src)->fd,
41                 SOL_SOCKET, SO_SNDBUF,
42                 (char *)&buflen,
43                 sizeof(buflen));
44  
45      setsockopt(((QIOChannelSocket *)dst)->fd,
46                 SOL_SOCKET, SO_SNDBUF,
47                 (char *)&buflen,
48                 sizeof(buflen));
49  }
50  
51  
test_io_channel_setup_sync(SocketAddress * listen_addr,SocketAddress * connect_addr,QIOChannel ** srv,QIOChannel ** src,QIOChannel ** dst)52  static void test_io_channel_setup_sync(SocketAddress *listen_addr,
53                                         SocketAddress *connect_addr,
54                                         QIOChannel **srv,
55                                         QIOChannel **src,
56                                         QIOChannel **dst)
57  {
58      QIOChannelSocket *lioc;
59  
60      lioc = qio_channel_socket_new();
61      qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort);
62  
63      if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
64          SocketAddress *laddr = qio_channel_socket_get_local_address(
65              lioc, &error_abort);
66  
67          g_free(connect_addr->u.inet.port);
68          connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
69  
70          qapi_free_SocketAddress(laddr);
71      }
72  
73      *src = QIO_CHANNEL(qio_channel_socket_new());
74      qio_channel_socket_connect_sync(
75          QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort);
76      qio_channel_set_delay(*src, false);
77  
78      qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
79      *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
80      g_assert(*dst);
81  
82      test_io_channel_set_socket_bufs(*src, *dst);
83  
84      *srv = QIO_CHANNEL(lioc);
85  }
86  
87  
88  struct TestIOChannelData {
89      bool err;
90      GMainLoop *loop;
91  };
92  
93  
test_io_channel_complete(QIOTask * task,gpointer opaque)94  static void test_io_channel_complete(QIOTask *task,
95                                       gpointer opaque)
96  {
97      struct TestIOChannelData *data = opaque;
98      data->err = qio_task_propagate_error(task, NULL);
99      g_main_loop_quit(data->loop);
100  }
101  
102  
test_io_channel_setup_async(SocketAddress * listen_addr,SocketAddress * connect_addr,QIOChannel ** srv,QIOChannel ** src,QIOChannel ** dst)103  static void test_io_channel_setup_async(SocketAddress *listen_addr,
104                                          SocketAddress *connect_addr,
105                                          QIOChannel **srv,
106                                          QIOChannel **src,
107                                          QIOChannel **dst)
108  {
109      QIOChannelSocket *lioc;
110      struct TestIOChannelData data;
111  
112      data.loop = g_main_loop_new(g_main_context_default(),
113                                  TRUE);
114  
115      lioc = qio_channel_socket_new();
116      qio_channel_socket_listen_async(
117          lioc, listen_addr, 1,
118          test_io_channel_complete, &data, NULL, NULL);
119  
120      g_main_loop_run(data.loop);
121      g_main_context_iteration(g_main_context_default(), FALSE);
122  
123      g_assert(!data.err);
124  
125      if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
126          SocketAddress *laddr = qio_channel_socket_get_local_address(
127              lioc, &error_abort);
128  
129          g_free(connect_addr->u.inet.port);
130          connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
131  
132          qapi_free_SocketAddress(laddr);
133      }
134  
135      *src = QIO_CHANNEL(qio_channel_socket_new());
136  
137      qio_channel_socket_connect_async(
138          QIO_CHANNEL_SOCKET(*src), connect_addr,
139          test_io_channel_complete, &data, NULL, NULL);
140  
141      g_main_loop_run(data.loop);
142      g_main_context_iteration(g_main_context_default(), FALSE);
143  
144      g_assert(!data.err);
145  
146      qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);
147      *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));
148      g_assert(*dst);
149  
150      qio_channel_set_delay(*src, false);
151      test_io_channel_set_socket_bufs(*src, *dst);
152  
153      *srv = QIO_CHANNEL(lioc);
154  
155      g_main_loop_unref(data.loop);
156  }
157  
158  
test_io_channel_socket_path_exists(SocketAddress * addr,bool expectExists)159  static void test_io_channel_socket_path_exists(SocketAddress *addr,
160                                                 bool expectExists)
161  {
162      if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
163          return;
164      }
165  
166      g_assert(g_file_test(addr->u.q_unix.path,
167                           G_FILE_TEST_EXISTS) == expectExists);
168  }
169  
170  
test_io_channel(bool async,SocketAddress * listen_addr,SocketAddress * connect_addr,bool passFD)171  static void test_io_channel(bool async,
172                              SocketAddress *listen_addr,
173                              SocketAddress *connect_addr,
174                              bool passFD)
175  {
176      QIOChannel *src, *dst, *srv;
177      QIOChannelTest *test;
178      if (async) {
179          test_io_channel_setup_async(listen_addr, connect_addr,
180                                      &srv, &src, &dst);
181  
182  #ifndef _WIN32
183          g_assert(!passFD ||
184                   qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
185          g_assert(!passFD ||
186                   qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
187  #endif
188          g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
189          g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
190  
191          test_io_channel_socket_path_exists(listen_addr, true);
192  
193          test = qio_channel_test_new();
194          qio_channel_test_run_threads(test, true, src, dst);
195          qio_channel_test_validate(test);
196  
197          test_io_channel_socket_path_exists(listen_addr, true);
198  
199          /* unref without close, to ensure finalize() cleans up */
200  
201          object_unref(OBJECT(src));
202          object_unref(OBJECT(dst));
203          test_io_channel_socket_path_exists(listen_addr, true);
204  
205          object_unref(OBJECT(srv));
206          test_io_channel_socket_path_exists(listen_addr, false);
207  
208          test_io_channel_setup_async(listen_addr, connect_addr,
209                                      &srv, &src, &dst);
210  
211  #ifndef _WIN32
212          g_assert(!passFD ||
213                   qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
214          g_assert(!passFD ||
215                   qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
216  #endif
217          g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
218          g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
219  
220          test = qio_channel_test_new();
221          qio_channel_test_run_threads(test, false, src, dst);
222          qio_channel_test_validate(test);
223  
224          /* close before unref, to ensure finalize copes with already closed */
225  
226          qio_channel_close(src, &error_abort);
227          qio_channel_close(dst, &error_abort);
228          test_io_channel_socket_path_exists(listen_addr, true);
229  
230          object_unref(OBJECT(src));
231          object_unref(OBJECT(dst));
232          test_io_channel_socket_path_exists(listen_addr, true);
233  
234          qio_channel_close(srv, &error_abort);
235          test_io_channel_socket_path_exists(listen_addr, false);
236  
237          object_unref(OBJECT(srv));
238          test_io_channel_socket_path_exists(listen_addr, false);
239      } else {
240          test_io_channel_setup_sync(listen_addr, connect_addr,
241                                     &srv, &src, &dst);
242  
243  #ifndef _WIN32
244          g_assert(!passFD ||
245                   qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
246          g_assert(!passFD ||
247                   qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
248  #endif
249          g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
250          g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
251  
252          test_io_channel_socket_path_exists(listen_addr, true);
253  
254          test = qio_channel_test_new();
255          qio_channel_test_run_threads(test, true, src, dst);
256          qio_channel_test_validate(test);
257  
258          test_io_channel_socket_path_exists(listen_addr, true);
259  
260          /* unref without close, to ensure finalize() cleans up */
261  
262          object_unref(OBJECT(src));
263          object_unref(OBJECT(dst));
264          test_io_channel_socket_path_exists(listen_addr, true);
265  
266          object_unref(OBJECT(srv));
267          test_io_channel_socket_path_exists(listen_addr, false);
268  
269          test_io_channel_setup_sync(listen_addr, connect_addr,
270                                     &srv, &src, &dst);
271  
272  #ifndef _WIN32
273          g_assert(!passFD ||
274                   qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
275          g_assert(!passFD ||
276                   qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
277  #endif
278          g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
279          g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
280  
281          test = qio_channel_test_new();
282          qio_channel_test_run_threads(test, false, src, dst);
283          qio_channel_test_validate(test);
284  
285          test_io_channel_socket_path_exists(listen_addr, true);
286  
287          /* close before unref, to ensure finalize copes with already closed */
288  
289          qio_channel_close(src, &error_abort);
290          qio_channel_close(dst, &error_abort);
291          test_io_channel_socket_path_exists(listen_addr, true);
292  
293          object_unref(OBJECT(src));
294          object_unref(OBJECT(dst));
295          test_io_channel_socket_path_exists(listen_addr, true);
296  
297          qio_channel_close(srv, &error_abort);
298          test_io_channel_socket_path_exists(listen_addr, false);
299  
300          object_unref(OBJECT(srv));
301          test_io_channel_socket_path_exists(listen_addr, false);
302      }
303  }
304  
305  
test_io_channel_ipv4(bool async)306  static void test_io_channel_ipv4(bool async)
307  {
308      SocketAddress *listen_addr = g_new0(SocketAddress, 1);
309      SocketAddress *connect_addr = g_new0(SocketAddress, 1);
310  
311      listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
312      listen_addr->u.inet = (InetSocketAddress) {
313          .host = g_strdup("127.0.0.1"),
314          .port = NULL, /* Auto-select */
315      };
316  
317      connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
318      connect_addr->u.inet = (InetSocketAddress) {
319          .host = g_strdup("127.0.0.1"),
320          .port = NULL, /* Filled in later */
321      };
322  
323      test_io_channel(async, listen_addr, connect_addr, false);
324  
325      qapi_free_SocketAddress(listen_addr);
326      qapi_free_SocketAddress(connect_addr);
327  }
328  
329  
test_io_channel_ipv4_sync(void)330  static void test_io_channel_ipv4_sync(void)
331  {
332      return test_io_channel_ipv4(false);
333  }
334  
335  
test_io_channel_ipv4_async(void)336  static void test_io_channel_ipv4_async(void)
337  {
338      return test_io_channel_ipv4(true);
339  }
340  
341  
test_io_channel_ipv6(bool async)342  static void test_io_channel_ipv6(bool async)
343  {
344      SocketAddress *listen_addr = g_new0(SocketAddress, 1);
345      SocketAddress *connect_addr = g_new0(SocketAddress, 1);
346  
347      listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
348      listen_addr->u.inet = (InetSocketAddress) {
349          .host = g_strdup("::1"),
350          .port = NULL, /* Auto-select */
351      };
352  
353      connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
354      connect_addr->u.inet = (InetSocketAddress) {
355          .host = g_strdup("::1"),
356          .port = NULL, /* Filled in later */
357      };
358  
359      test_io_channel(async, listen_addr, connect_addr, false);
360  
361      qapi_free_SocketAddress(listen_addr);
362      qapi_free_SocketAddress(connect_addr);
363  }
364  
365  
test_io_channel_ipv6_sync(void)366  static void test_io_channel_ipv6_sync(void)
367  {
368      return test_io_channel_ipv6(false);
369  }
370  
371  
test_io_channel_ipv6_async(void)372  static void test_io_channel_ipv6_async(void)
373  {
374      return test_io_channel_ipv6(true);
375  }
376  
377  
test_io_channel_unix(bool async)378  static void test_io_channel_unix(bool async)
379  {
380      SocketAddress *listen_addr = g_new0(SocketAddress, 1);
381      SocketAddress *connect_addr = g_new0(SocketAddress, 1);
382  
383  #define TEST_SOCKET "test-io-channel-socket.sock"
384      listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
385      listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
386  
387      connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
388      connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
389  
390      test_io_channel(async, listen_addr, connect_addr, true);
391  
392      qapi_free_SocketAddress(listen_addr);
393      qapi_free_SocketAddress(connect_addr);
394  }
395  
396  
test_io_channel_unix_sync(void)397  static void test_io_channel_unix_sync(void)
398  {
399      return test_io_channel_unix(false);
400  }
401  
402  
test_io_channel_unix_async(void)403  static void test_io_channel_unix_async(void)
404  {
405      return test_io_channel_unix(true);
406  }
407  
408  #ifndef _WIN32
test_io_channel_unix_fd_pass(void)409  static void test_io_channel_unix_fd_pass(void)
410  {
411      SocketAddress *listen_addr = g_new0(SocketAddress, 1);
412      SocketAddress *connect_addr = g_new0(SocketAddress, 1);
413      QIOChannel *src, *dst, *srv;
414      int testfd;
415      int fdsend[3];
416      int *fdrecv = NULL;
417      size_t nfdrecv = 0;
418      size_t i;
419      char bufsend[12], bufrecv[12];
420      struct iovec iosend[1], iorecv[1];
421  
422  #define TEST_SOCKET "test-io-channel-socket.sock"
423  #define TEST_FILE "test-io-channel-socket.txt"
424  
425      testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700);
426      g_assert(testfd != -1);
427      fdsend[0] = testfd;
428      fdsend[1] = testfd;
429      fdsend[2] = testfd;
430  
431      listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
432      listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
433  
434      connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
435      connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
436  
437      test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst);
438  
439      memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
440  
441      iosend[0].iov_base = bufsend;
442      iosend[0].iov_len = G_N_ELEMENTS(bufsend);
443  
444      iorecv[0].iov_base = bufrecv;
445      iorecv[0].iov_len = G_N_ELEMENTS(bufrecv);
446  
447      g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
448      g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
449  
450      qio_channel_writev_full(src,
451                              iosend,
452                              G_N_ELEMENTS(iosend),
453                              fdsend,
454                              G_N_ELEMENTS(fdsend),
455                              0,
456                              &error_abort);
457  
458      qio_channel_readv_full(dst,
459                             iorecv,
460                             G_N_ELEMENTS(iorecv),
461                             &fdrecv,
462                             &nfdrecv,
463                             0,
464                             &error_abort);
465  
466      g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
467      /* Each recvd FD should be different from sent FD */
468      for (i = 0; i < nfdrecv; i++) {
469          g_assert_cmpint(fdrecv[i], !=, testfd);
470      }
471      /* Each recvd FD should be different from each other */
472      g_assert_cmpint(fdrecv[0], !=, fdrecv[1]);
473      g_assert_cmpint(fdrecv[0], !=, fdrecv[2]);
474      g_assert_cmpint(fdrecv[1], !=, fdrecv[2]);
475  
476      /* Check the I/O buf we sent at the same time matches */
477      g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
478  
479      /* Write some data into the FD we received */
480      g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) ==
481               G_N_ELEMENTS(bufsend));
482  
483      /* Read data from the original FD and make sure it matches */
484      memset(bufrecv, 0, G_N_ELEMENTS(bufrecv));
485      g_assert(lseek(testfd, 0, SEEK_SET) == 0);
486      g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) ==
487               G_N_ELEMENTS(bufrecv));
488      g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0);
489  
490      object_unref(OBJECT(src));
491      object_unref(OBJECT(dst));
492      object_unref(OBJECT(srv));
493      qapi_free_SocketAddress(listen_addr);
494      qapi_free_SocketAddress(connect_addr);
495      unlink(TEST_SOCKET);
496      unlink(TEST_FILE);
497      close(testfd);
498      for (i = 0; i < nfdrecv; i++) {
499          close(fdrecv[i]);
500      }
501      g_free(fdrecv);
502  }
503  #endif /* _WIN32 */
504  
test_io_channel_unix_listen_cleanup(void)505  static void test_io_channel_unix_listen_cleanup(void)
506  {
507      QIOChannelSocket *ioc;
508      struct sockaddr_un un;
509      int sock, ret = 0;
510  
511  #define TEST_SOCKET "test-io-channel-socket.sock"
512  
513      ioc = qio_channel_socket_new();
514  
515      /* Manually bind ioc without calling the qio api to avoid setting
516       * the LISTEN feature */
517      sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
518      memset(&un, 0, sizeof(un));
519      un.sun_family = AF_UNIX;
520      snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
521      unlink(TEST_SOCKET);
522      ret = bind(sock, (struct sockaddr *)&un, sizeof(un));
523      g_assert_cmpint(ret, ==, 0);
524  
525      ioc->fd = sock;
526      ioc->localAddrLen = sizeof(ioc->localAddr);
527      getsockname(sock, (struct sockaddr *)&ioc->localAddr,
528                  &ioc->localAddrLen);
529  
530      g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
531      object_unref(OBJECT(ioc));
532      g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS));
533  
534      unlink(TEST_SOCKET);
535  }
536  
test_io_channel_ipv4_fd(void)537  static void test_io_channel_ipv4_fd(void)
538  {
539      QIOChannel *ioc;
540      int fd = -1;
541      struct sockaddr_in sa = {
542          .sin_family = AF_INET,
543          .sin_addr = {
544              .s_addr =  htonl(INADDR_LOOPBACK),
545          }
546          /* Leave port unset for auto-assign */
547      };
548      socklen_t salen = sizeof(sa);
549  
550      fd = socket(AF_INET, SOCK_STREAM, 0);
551      g_assert_cmpint(fd, >, -1);
552  
553      g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0);
554  
555      ioc = qio_channel_new_fd(fd, &error_abort);
556  
557      g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
558                      ==,
559                      TYPE_QIO_CHANNEL_SOCKET);
560  
561      object_unref(OBJECT(ioc));
562  }
563  
564  
main(int argc,char ** argv)565  int main(int argc, char **argv)
566  {
567      bool has_ipv4, has_ipv6, has_afunix;
568  
569      module_call_init(MODULE_INIT_QOM);
570      qemu_init_main_loop(&error_abort);
571      socket_init();
572  
573      g_test_init(&argc, &argv, NULL);
574  
575      /* We're creating actual IPv4/6 sockets, so we should
576       * check if the host running tests actually supports
577       * each protocol to avoid breaking tests on machines
578       * with either IPv4 or IPv6 disabled.
579       */
580      if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
581          g_printerr("socket_check_protocol_support() failed\n");
582          goto end;
583      }
584  
585      if (has_ipv4) {
586          g_test_add_func("/io/channel/socket/ipv4-sync",
587                          test_io_channel_ipv4_sync);
588          g_test_add_func("/io/channel/socket/ipv4-async",
589                          test_io_channel_ipv4_async);
590          g_test_add_func("/io/channel/socket/ipv4-fd",
591                          test_io_channel_ipv4_fd);
592      }
593      if (has_ipv6) {
594          g_test_add_func("/io/channel/socket/ipv6-sync",
595                          test_io_channel_ipv6_sync);
596          g_test_add_func("/io/channel/socket/ipv6-async",
597                          test_io_channel_ipv6_async);
598      }
599  
600      socket_check_afunix_support(&has_afunix);
601      if (has_afunix) {
602          g_test_add_func("/io/channel/socket/unix-sync",
603                          test_io_channel_unix_sync);
604          g_test_add_func("/io/channel/socket/unix-async",
605                          test_io_channel_unix_async);
606  #ifndef _WIN32
607          g_test_add_func("/io/channel/socket/unix-fd-pass",
608                          test_io_channel_unix_fd_pass);
609  #endif
610          g_test_add_func("/io/channel/socket/unix-listen-cleanup",
611                          test_io_channel_unix_listen_cleanup);
612      }
613  
614  end:
615      return g_test_run();
616  }
617