Blame gnulib-tests/test-select.h

Packit Service fdd496
/* Test of select() substitute.
Packit Service fdd496
   Copyright (C) 2008-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation; either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
/* Written by Paolo Bonzini, 2008.  */
Packit Service fdd496
Packit Service fdd496
#include <stdio.h>
Packit Service fdd496
#include <string.h>
Packit Service fdd496
#include <netinet/in.h>
Packit Service fdd496
#include <arpa/inet.h>
Packit Service fdd496
#include <unistd.h>
Packit Service fdd496
#include <fcntl.h>
Packit Service fdd496
#include <stdlib.h>
Packit Service fdd496
#include <stdbool.h>
Packit Service fdd496
#include <sys/ioctl.h>
Packit Service fdd496
#include <errno.h>
Packit Service fdd496
Packit Service fdd496
#include "macros.h"
Packit Service fdd496
Packit Service fdd496
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit Service fdd496
# define WINDOWS_NATIVE
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifdef HAVE_SYS_WAIT_H
Packit Service fdd496
# include <sys/wait.h>
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifndef SO_REUSEPORT
Packit Service fdd496
# define SO_REUSEPORT    SO_REUSEADDR
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#define TEST_PORT       12345
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
typedef int (*select_fn) (int, fd_set *, fd_set *, fd_set *, struct timeval *);
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Minimal testing infrastructure.  */
Packit Service fdd496
Packit Service fdd496
static int failures;
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
failed (const char *reason)
Packit Service fdd496
{
Packit Service fdd496
  if (++failures > 1)
Packit Service fdd496
    printf ("  ");
Packit Service fdd496
  printf ("failed (%s)\n", reason);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
test (void (*fn) (select_fn), select_fn my_select, const char *msg)
Packit Service fdd496
{
Packit Service fdd496
  failures = 0;
Packit Service fdd496
  printf ("%s... ", msg);
Packit Service fdd496
  fflush (stdout);
Packit Service fdd496
  fn (my_select);
Packit Service fdd496
Packit Service fdd496
  if (!failures)
Packit Service fdd496
    printf ("passed\n");
Packit Service fdd496
Packit Service fdd496
  return failures;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Funny socket code.  */
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
open_server_socket (void)
Packit Service fdd496
{
Packit Service fdd496
  int s, x;
Packit Service fdd496
  struct sockaddr_in ia;
Packit Service fdd496
Packit Service fdd496
  s = socket (AF_INET, SOCK_STREAM, 0);
Packit Service fdd496
Packit Service fdd496
  x = 1;
Packit Service fdd496
  setsockopt (s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
Packit Service fdd496
Packit Service fdd496
  memset (&ia, 0, sizeof (ia));
Packit Service fdd496
  ia.sin_family = AF_INET;
Packit Service fdd496
  inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
Packit Service fdd496
  ia.sin_port = htons (TEST_PORT);
Packit Service fdd496
  if (bind (s, (struct sockaddr *) &ia, sizeof (ia)) < 0)
Packit Service fdd496
    {
Packit Service fdd496
      perror ("bind");
Packit Service fdd496
      exit (77);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (listen (s, 1) < 0)
Packit Service fdd496
    {
Packit Service fdd496
      perror ("listen");
Packit Service fdd496
      exit (77);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return s;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
connect_to_socket (bool blocking)
Packit Service fdd496
{
Packit Service fdd496
  int s;
Packit Service fdd496
  struct sockaddr_in ia;
Packit Service fdd496
Packit Service fdd496
  s = socket (AF_INET, SOCK_STREAM, 0);
Packit Service fdd496
Packit Service fdd496
  memset (&ia, 0, sizeof (ia));
Packit Service fdd496
  ia.sin_family = AF_INET;
Packit Service fdd496
  inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
Packit Service fdd496
  ia.sin_port = htons (TEST_PORT);
Packit Service fdd496
Packit Service fdd496
  if (!blocking)
Packit Service fdd496
    {
Packit Service fdd496
#ifdef WINDOWS_NATIVE
Packit Service fdd496
      unsigned long iMode = 1;
Packit Service fdd496
      ioctl (s, FIONBIO, (char *) &iMode);
Packit Service fdd496
Packit Service fdd496
#elif defined F_GETFL
Packit Service fdd496
      int oldflags = fcntl (s, F_GETFL, NULL);
Packit Service fdd496
Packit Service fdd496
      if (!(oldflags & O_NONBLOCK))
Packit Service fdd496
        fcntl (s, F_SETFL, oldflags | O_NONBLOCK);
Packit Service fdd496
#endif
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (connect (s, (struct sockaddr *) &ia, sizeof (ia)) < 0
Packit Service fdd496
      && (blocking || errno != EINPROGRESS))
Packit Service fdd496
    {
Packit Service fdd496
      perror ("connect");
Packit Service fdd496
      exit (77);
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return s;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* A slightly more convenient interface to select(2).
Packit Service fdd496
   Waits until a specific event occurs on a file descriptor FD.
Packit Service fdd496
   EV is a bit mask of events to look for:
Packit Service fdd496
     SEL_IN - input can be polled without blocking,
Packit Service fdd496
     SEL_OUT - output can be provided without blocking,
Packit Service fdd496
     SEL_EXC - an exception occurred,
Packit Service fdd496
   A maximum wait time is specified by TIMEOUT.
Packit Service fdd496
   *TIMEOUT = { 0, 0 } means to return immediately,
Packit Service fdd496
   TIMEOUT = NULL means to wait indefinitely.  */
Packit Service fdd496
Packit Service fdd496
enum { SEL_IN = 1, SEL_OUT = 2, SEL_EXC = 4 };
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select (int fd, int ev, struct timeval *timeout, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  fd_set rfds, wfds, xfds;
Packit Service fdd496
  int r, rev;
Packit Service fdd496
Packit Service fdd496
  FD_ZERO (&rfds);
Packit Service fdd496
  FD_ZERO (&wfds);
Packit Service fdd496
  FD_ZERO (&xfds);
Packit Service fdd496
  if (ev & SEL_IN)
Packit Service fdd496
    FD_SET (fd, &rfds);
Packit Service fdd496
  if (ev & SEL_OUT)
Packit Service fdd496
    FD_SET (fd, &wfds);
Packit Service fdd496
  if (ev & SEL_EXC)
Packit Service fdd496
    FD_SET (fd, &xfds);
Packit Service fdd496
  r = my_select (fd + 1, &rfds, &wfds, &xfds, timeout);
Packit Service fdd496
  if (r < 0)
Packit Service fdd496
    return r;
Packit Service fdd496
Packit Service fdd496
  rev = 0;
Packit Service fdd496
  if (FD_ISSET (fd, &rfds))
Packit Service fdd496
    rev |= SEL_IN;
Packit Service fdd496
  if (FD_ISSET (fd, &wfds))
Packit Service fdd496
    rev |= SEL_OUT;
Packit Service fdd496
  if (FD_ISSET (fd, &xfds))
Packit Service fdd496
    rev |= SEL_EXC;
Packit Service fdd496
  if (rev && r == 0)
Packit Service fdd496
    failed ("select returned 0");
Packit Service fdd496
  if (rev & ~ev)
Packit Service fdd496
    failed ("select returned unrequested events");
Packit Service fdd496
Packit Service fdd496
  return rev;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select_nowait (int fd, int ev, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  struct timeval tv0;
Packit Service fdd496
  tv0.tv_sec = 0;
Packit Service fdd496
  tv0.tv_usec = 0;
Packit Service fdd496
  return do_select (fd, ev, &tv0, my_select);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select_wait (int fd, int ev, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  return do_select (fd, ev, NULL, my_select);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Test select(2) for TTYs.  */
Packit Service fdd496
Packit Service fdd496
#ifdef INTERACTIVE
Packit Service fdd496
static void
Packit Service fdd496
test_tty (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  if (do_select_nowait (0, SEL_IN, my_select) != 0)
Packit Service fdd496
    failed ("can read");
Packit Service fdd496
  if (do_select_nowait (0, SEL_OUT, my_select) == 0)
Packit Service fdd496
    failed ("cannot write");
Packit Service fdd496
Packit Service fdd496
  if (do_select_wait (0, SEL_IN, my_select) == 0)
Packit Service fdd496
    failed ("return with infinite timeout");
Packit Service fdd496
Packit Service fdd496
  getchar ();
Packit Service fdd496
  if (do_select_nowait (0, SEL_IN, my_select) != 0)
Packit Service fdd496
    failed ("can read after getc");
Packit Service fdd496
}
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select_bad_nfd_nowait (int nfd, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  struct timeval tv0;
Packit Service fdd496
  tv0.tv_sec = 0;
Packit Service fdd496
  tv0.tv_usec = 0;
Packit Service fdd496
  errno = 0;
Packit Service fdd496
  return my_select (nfd, NULL, NULL, NULL, &tv0);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_bad_nfd (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  if (do_select_bad_nfd_nowait (-1, my_select) != -1 || errno != EINVAL)
Packit Service fdd496
    failed ("invalid errno after negative nfds");
Packit Service fdd496
  /* Can't test FD_SETSIZE + 1 for EINVAL, since some systems allow
Packit Service fdd496
     dynamically larger set size by redefining FD_SETSIZE anywhere up
Packit Service fdd496
     to the actual maximum fd.  */
Packit Service fdd496
  /* if (do_select_bad_nfd_nowait (FD_SETSIZE + 1, my_select) != -1 */
Packit Service fdd496
  /*     || errno != EINVAL) */
Packit Service fdd496
  /*   failed ("invalid errno after bogus nfds"); */
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Test select(2) on invalid file descriptors.  */
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select_bad_fd (int fd, int ev, struct timeval *timeout, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  fd_set rfds, wfds, xfds;
Packit Service fdd496
Packit Service fdd496
  FD_ZERO (&rfds);
Packit Service fdd496
  FD_ZERO (&wfds);
Packit Service fdd496
  FD_ZERO (&xfds);
Packit Service fdd496
  if (ev & SEL_IN)
Packit Service fdd496
    FD_SET (fd, &rfds);
Packit Service fdd496
  if (ev & SEL_OUT)
Packit Service fdd496
    FD_SET (fd, &wfds);
Packit Service fdd496
  if (ev & SEL_EXC)
Packit Service fdd496
    FD_SET (fd, &xfds);
Packit Service fdd496
  errno = 0;
Packit Service fdd496
  return my_select (fd + 1, &rfds, &wfds, &xfds, timeout);
Packit Service fdd496
  /* In this case, when fd is invalid, on some platforms, the bit for fd
Packit Service fdd496
     is left alone in the fd_set, whereas on other platforms it is cleared.
Packit Service fdd496
     So, don't check the bit for fd here.  */
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
do_select_bad_fd_nowait (int fd, int ev, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  struct timeval tv0;
Packit Service fdd496
  tv0.tv_sec = 0;
Packit Service fdd496
  tv0.tv_usec = 0;
Packit Service fdd496
  return do_select_bad_fd (fd, ev, &tv0, my_select);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_bad_fd (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  /* This tests fails on OSF/1 and native Windows, even with fd = 16.  */
Packit Service fdd496
#if !(defined __osf__ || defined WINDOWS_NATIVE)
Packit Service fdd496
  int fd;
Packit Service fdd496
Packit Service fdd496
  /* On Linux, Mac OS X, *BSD, values of fd like 99 or 399 are discarded
Packit Service fdd496
     by the kernel early and therefore do *not* lead to EBADF, as required
Packit Service fdd496
     by POSIX.  */
Packit Service fdd496
# if defined __linux__ || (defined __APPLE__ && defined __MACH__) || (defined __FreeBSD__ || defined __DragonFly__) || defined __OpenBSD__ || defined __NetBSD__
Packit Service fdd496
  fd = 14;
Packit Service fdd496
# else
Packit Service fdd496
  fd = 99;
Packit Service fdd496
# endif
Packit Service fdd496
  close (fd);
Packit Service fdd496
Packit Service fdd496
  if (do_select_bad_fd_nowait (fd, SEL_IN, my_select) == 0 || errno != EBADF)
Packit Service fdd496
    failed ("invalid fd among rfds");
Packit Service fdd496
  if (do_select_bad_fd_nowait (fd, SEL_OUT, my_select) == 0 || errno != EBADF)
Packit Service fdd496
    failed ("invalid fd among wfds");
Packit Service fdd496
  if (do_select_bad_fd_nowait (fd, SEL_EXC, my_select) == 0 || errno != EBADF)
Packit Service fdd496
    failed ("invalid fd among xfds");
Packit Service fdd496
#endif
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Test select(2) for unconnected nonblocking sockets.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_connect_first (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  int s = open_server_socket ();
Packit Service fdd496
  struct sockaddr_in ia;
Packit Service fdd496
  socklen_t addrlen;
Packit Service fdd496
Packit Service fdd496
  int c1, c2;
Packit Service fdd496
Packit Service fdd496
  if (do_select_nowait (s, SEL_IN | SEL_EXC, my_select) != 0)
Packit Service fdd496
    failed ("can read, socket not connected");
Packit Service fdd496
Packit Service fdd496
  c1 = connect_to_socket (false);
Packit Service fdd496
Packit Service fdd496
  if (do_select_wait (s, SEL_IN | SEL_EXC, my_select) != SEL_IN)
Packit Service fdd496
    failed ("expecting readability on passive socket");
Packit Service fdd496
  if (do_select_nowait (s, SEL_IN | SEL_EXC, my_select) != SEL_IN)
Packit Service fdd496
    failed ("expecting readability on passive socket");
Packit Service fdd496
Packit Service fdd496
  addrlen = sizeof (ia);
Packit Service fdd496
  c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
Packit Service fdd496
  ASSERT (close (s) == 0);
Packit Service fdd496
  ASSERT (close (c1) == 0);
Packit Service fdd496
  ASSERT (close (c2) == 0);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Test select(2) for unconnected blocking sockets.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_accept_first (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
#ifndef WINDOWS_NATIVE
Packit Service fdd496
  int s = open_server_socket ();
Packit Service fdd496
  struct sockaddr_in ia;
Packit Service fdd496
  socklen_t addrlen;
Packit Service fdd496
  char buf[3];
Packit Service fdd496
  int c, pid;
Packit Service fdd496
Packit Service fdd496
  pid = fork ();
Packit Service fdd496
  if (pid < 0)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  if (pid == 0)
Packit Service fdd496
    {
Packit Service fdd496
      addrlen = sizeof (ia);
Packit Service fdd496
      c = accept (s, (struct sockaddr *) &ia, &addrlen);
Packit Service fdd496
      ASSERT (close (s) == 0);
Packit Service fdd496
      ASSERT (write (c, "foo", 3) == 3);
Packit Service fdd496
      ASSERT (read (c, buf, 3) == 3);
Packit Service fdd496
      shutdown (c, SHUT_RD);
Packit Service fdd496
      ASSERT (close (c) == 0);
Packit Service fdd496
      exit (0);
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      ASSERT (close (s) == 0);
Packit Service fdd496
      c = connect_to_socket (true);
Packit Service fdd496
      if (do_select_nowait (c, SEL_OUT, my_select) != SEL_OUT)
Packit Service fdd496
        failed ("cannot write after blocking connect");
Packit Service fdd496
      ASSERT (write (c, "foo", 3) == 3);
Packit Service fdd496
      wait (&pid;;
Packit Service fdd496
      if (do_select_wait (c, SEL_IN, my_select) != SEL_IN)
Packit Service fdd496
        failed ("cannot read data left in the socket by closed process");
Packit Service fdd496
      ASSERT (read (c, buf, 3) == 3);
Packit Service fdd496
      ASSERT (write (c, "foo", 3) == 3);
Packit Service fdd496
      (void) close (c); /* may fail with errno = ECONNRESET */
Packit Service fdd496
    }
Packit Service fdd496
#endif
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Common code for pipes and connected sockets.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_pair (int rd, int wd, select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  char buf[3];
Packit Service fdd496
  if (do_select_wait (wd, SEL_IN | SEL_OUT | SEL_EXC, my_select) != SEL_OUT)
Packit Service fdd496
    failed ("expecting writability before writing");
Packit Service fdd496
  if (do_select_nowait (wd, SEL_IN | SEL_OUT | SEL_EXC, my_select) != SEL_OUT)
Packit Service fdd496
    failed ("expecting writability before writing");
Packit Service fdd496
Packit Service fdd496
  ASSERT (write (wd, "foo", 3) == 3);
Packit Service fdd496
  if (do_select_wait (rd, SEL_IN, my_select) != SEL_IN)
Packit Service fdd496
    failed ("expecting readability after writing");
Packit Service fdd496
  if (do_select_nowait (rd, SEL_IN, my_select) != SEL_IN)
Packit Service fdd496
    failed ("expecting readability after writing");
Packit Service fdd496
Packit Service fdd496
  ASSERT (read (rd, buf, 3) == 3);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Test select(2) on connected sockets.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_socket_pair (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  struct sockaddr_in ia;
Packit Service fdd496
Packit Service fdd496
  socklen_t addrlen = sizeof (ia);
Packit Service fdd496
  int s = open_server_socket ();
Packit Service fdd496
  int c1 = connect_to_socket (false);
Packit Service fdd496
  int c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
Packit Service fdd496
Packit Service fdd496
  ASSERT (close (s) == 0);
Packit Service fdd496
Packit Service fdd496
  test_pair (c1, c2, my_select);
Packit Service fdd496
  ASSERT (close (c1) == 0);
Packit Service fdd496
  ASSERT (write (c2, "foo", 3) == 3);
Packit Service fdd496
  (void) close (c2); /* may fail with errno = ECONNRESET */
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Test select(2) on pipes.  */
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_pipe (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  int fd[2];
Packit Service fdd496
Packit Service fdd496
  ASSERT (pipe (fd) == 0);
Packit Service fdd496
  test_pair (fd[0], fd[1], my_select);
Packit Service fdd496
  ASSERT (close (fd[0]) == 0);
Packit Service fdd496
  ASSERT (close (fd[1]) == 0);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
Packit Service fdd496
/* Do them all.  */
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
test_function (select_fn my_select)
Packit Service fdd496
{
Packit Service fdd496
  int result = 0;
Packit Service fdd496
Packit Service fdd496
#ifdef INTERACTIVE
Packit Service fdd496
  printf ("Please press Enter\n");
Packit Service fdd496
  test (test_tty, "TTY", my_select);
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  result += test (test_bad_nfd, my_select, "Invalid nfd test");
Packit Service fdd496
  result += test (test_bad_fd, my_select, "Invalid fd test");
Packit Service fdd496
  result += test (test_connect_first, my_select, "Unconnected socket test");
Packit Service fdd496
  result += test (test_socket_pair, my_select, "Connected sockets test");
Packit Service fdd496
  result += test (test_accept_first, my_select, "General socket test with fork");
Packit Service fdd496
  result += test (test_pipe, my_select, "Pipe test");
Packit Service fdd496
Packit Service fdd496
  return result;
Packit Service fdd496
}