#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

char output[1048576];

static int
_connect (const char *host, const char *port)
  {
  struct addrinfo  hints = { .ai_family   = AF_INET,
                             .ai_socktype = SOCK_STREAM },
                  *result;

  int gai_errno = 0;
  if ((gai_errno = getaddrinfo (host, port, &hints, &result)))
    {
    fprintf (stderr, "_connect: getaddrinfo failed: %s\n",
      gai_strerror (gai_errno));
    return -1;
    }

  int sock = -1;

  if ((sock = socket (result->ai_family,
                      result->ai_socktype,
                      result->ai_protocol)) < 0)
    {
    fprintf (stderr, "_connect: socket failed: %s\n", strerror (errno));
    }
  else if (connect (sock, result->ai_addr, result->ai_addrlen) < 0)
    {
    fprintf (stderr, "_connect: connect failed: %s\n", strerror (errno));
    close (sock);
    sock = -1;
    }

  freeaddrinfo (result);

  if (sock != -1)
    {
    fprintf (stderr, "_connect: connected to %s:%s.\n", host, port);

    int flags;
    if ((flags = fcntl (sock, F_GETFL, 0)) == -1)
      fprintf (stderr, "_connect: fcntl (F_GETFL) failed: %s\n",
        strerror (errno));
    else if (fcntl (sock, F_SETFL, flags | O_NONBLOCK) == -1)
      fprintf (stderr, "_connect: fcntl (F_SETFL) failed: %s\n",
        strerror (errno));
    else
      return sock;

    close (sock);
    }

  exit (EXIT_FAILURE);
  }

static void
_select (int sock)
  {
  fd_set wfds;
  FD_ZERO (&wfds);
  FD_SET (sock, &wfds);

  int rv;
  if ((rv = select (sock + 1,
                    NULL,
                    &wfds,
                    NULL,
                    &(struct timeval) { .tv_sec = 1 })) < 0)
    {
    fprintf (stderr, "_select: select failed: %s\n", strerror (errno));
    exit (EXIT_FAILURE);
    }

  fprintf (stderr, "_select: select = %d, FD_ISSET (%d, &wfds) == %d.\n",
    rv, sock, FD_ISSET (sock, &wfds));
  }

static void
_send (int sock)
  {
  struct iovec  vec  = { .iov_base = output, .iov_len    = sizeof output };
  struct msghdr mhdr = { .msg_iov  = &vec,   .msg_iovlen = 1 };

  for (int i = 0; ; ++i)
    {
    ssize_t rv;
    if ((rv = sendmsg (sock, &mhdr, 0)) < 0)
      {
      fprintf (stderr, "_send: sendmsg %d failed: %s\n",
        i, strerror (errno));

      break;
      }
    else
      fprintf (stderr, "_send: sendmsg %d returned: %zd\n",
        i, rv);
    }
  }

static void
_system (const char *fmt, ...)
  {
  char cmdbuf[64];

  va_list ap;
  va_start (ap, fmt);
  vsprintf (cmdbuf, fmt, ap);
  va_end (ap);

  fprintf (stderr, "_system: %s\n", cmdbuf);
  system (cmdbuf);
  }

int
main (int argc, char **argv)
  {
  if (argc != 4)
    exit (EXIT_FAILURE);

  const char *host   = argv[1],
             *port   = argv[2],
             *netcat = argv[3];

  _system ("%s -l %s & sleep 1", netcat, port);

  signal (SIGPIPE, SIG_IGN);

  int sock = _connect (host, port);

  _select (sock);

  _system ("pkill -x %s; sleep 1", netcat);

  _select (sock);

  _send (sock);

  _select (sock);

  exit (EXIT_SUCCESS);
  }
