Blame src/microhttpd/test_upgrade.c

Packit 875988
/*
Packit 875988
     This file is part of libmicrohttpd
Packit 875988
     Copyright (C) 2016 Christian Grothoff
Packit 875988
Packit 875988
     libmicrohttpd is free software; you can redistribute it and/or modify
Packit 875988
     it under the terms of the GNU General Public License as published
Packit 875988
     by the Free Software Foundation; either version 3, or (at your
Packit 875988
     option) any later version.
Packit 875988
Packit 875988
     libmicrohttpd is distributed in the hope that it will be useful, but
Packit 875988
     WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
     General Public License for more details.
Packit 875988
Packit 875988
     You should have received a copy of the GNU General Public License
Packit 875988
     along with libmicrohttpd; see the file COPYING.  If not, write to the
Packit 875988
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 875988
     Boston, MA 02110-1301, USA.
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file test_upgrade.c
Packit 875988
 * @brief  Testcase for libmicrohttpd upgrading a connection
Packit 875988
 * @author Christian Grothoff
Packit 875988
 * @author Karlson2k (Evgeny Grin)
Packit 875988
 */
Packit 875988
Packit 875988
#include "mhd_options.h"
Packit 875988
#include <stdlib.h>
Packit 875988
#include <string.h>
Packit 875988
#include <stdio.h>
Packit 875988
#include <pthread.h>
Packit 875988
#include <stdlib.h>
Packit 875988
#include <stddef.h>
Packit 875988
#ifndef WINDOWS
Packit 875988
#include <unistd.h>
Packit 875988
#endif
Packit 875988
#ifdef HAVE_STDBOOL_H
Packit 875988
#include <stdbool.h>
Packit 875988
#endif /* HAVE_STDBOOL_H */
Packit 875988
Packit 875988
#include "mhd_sockets.h"
Packit 875988
#ifdef HAVE_NETINET_IP_H
Packit 875988
#include <netinet/ip.h>
Packit 875988
#endif /* HAVE_NETINET_IP_H */
Packit 875988
Packit 875988
#include "platform.h"
Packit 875988
#include "microhttpd.h"
Packit 875988
Packit 875988
#include "test_helpers.h"
Packit 875988
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
#include <gnutls/gnutls.h>
Packit 875988
#include "../testcurl/https/tls_test_keys.h"
Packit 875988
Packit 875988
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
#include <sys/types.h>
Packit 875988
#include <sys/wait.h>
Packit 875988
#endif /* HAVE_FORK && HAVE_WAITPID */
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
Packit 875988
static int verbose = 0;
Packit 875988
Packit 875988
enum tls_tool
Packit 875988
{
Packit 875988
  TLS_CLI_NO_TOOL = 0,
Packit 875988
  TLS_CLI_GNUTLS,
Packit 875988
  TLS_CLI_OPENSSL,
Packit 875988
  TLS_LIB_GNUTLS
Packit 875988
};
Packit 875988
Packit 875988
enum tls_tool use_tls_tool;
Packit 875988
Packit 875988
#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
/**
Packit 875988
 * Fork child that connects via GnuTLS-CLI to our @a port.  Allows us to
Packit 875988
 * talk to our port over a socket in @a sp without having to worry
Packit 875988
 * about TLS.
Packit 875988
 *
Packit 875988
 * @param location where the socket is returned
Packit 875988
 * @return -1 on error, otherwise PID of TLS child process
Packit 875988
 */
Packit 875988
static pid_t
Packit 875988
gnutlscli_connect (int *sock,
Packit 875988
                 uint16_t port)
Packit 875988
{
Packit 875988
  pid_t chld;
Packit 875988
  int sp[2];
Packit 875988
  char destination[30];
Packit 875988
Packit 875988
  if (0 != socketpair (AF_UNIX,
Packit 875988
                       SOCK_STREAM,
Packit 875988
                       0,
Packit 875988
                       sp))
Packit 875988
    return -1;
Packit 875988
  chld = fork ();
Packit 875988
  if (0 != chld)
Packit 875988
    {
Packit 875988
      *sock = sp[1];
Packit 875988
      MHD_socket_close_chk_ (sp[0]);
Packit 875988
      return chld;
Packit 875988
    }
Packit 875988
  MHD_socket_close_chk_ (sp[1]);
Packit 875988
  (void) close (0);
Packit 875988
  (void) close (1);
Packit 875988
  dup2 (sp[0], 0);
Packit 875988
  dup2 (sp[0], 1);
Packit 875988
  MHD_socket_close_chk_ (sp[0]);
Packit 875988
  if (TLS_CLI_GNUTLS == use_tls_tool)
Packit 875988
    {
Packit 875988
      snprintf (destination,
Packit 875988
                sizeof(destination),
Packit 875988
                "%u",
Packit 875988
                (unsigned int) port);
Packit 875988
      execlp ("gnutls-cli",
Packit 875988
              "gnutls-cli",
Packit 875988
              "--insecure",
Packit 875988
              "-p",
Packit 875988
              destination,
Packit 875988
              "127.0.0.1",
Packit 875988
              (char *) NULL);
Packit 875988
    }
Packit 875988
  else if (TLS_CLI_OPENSSL == use_tls_tool)
Packit 875988
    {
Packit 875988
      snprintf (destination,
Packit 875988
                sizeof(destination),
Packit 875988
                "127.0.0.1:%u",
Packit 875988
                (unsigned int) port);
Packit 875988
      execlp ("openssl",
Packit 875988
              "openssl",
Packit 875988
              "s_client",
Packit 875988
              "-connect",
Packit 875988
              destination,
Packit 875988
              "-verify",
Packit 875988
              "1",
Packit 875988
              (char *) NULL);
Packit 875988
    }
Packit 875988
  _exit (1);
Packit 875988
}
Packit 875988
#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Wrapper structure for plain&TLS sockets
Packit 875988
 */
Packit 875988
struct wr_socket_strc
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * Real network socket
Packit 875988
   */
Packit 875988
  MHD_socket fd;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Type of this socket
Packit 875988
   */
Packit 875988
  enum wr_type
Packit 875988
  {
Packit 875988
    wr_invalid = 0,
Packit 875988
    wr_plain = 1,
Packit 875988
    wr_tls = 2
Packit 875988
  } t;
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  /**
Packit 875988
   * TLS credentials
Packit 875988
   */
Packit 875988
  gnutls_certificate_credentials_t tls_crd;
Packit 875988
Packit 875988
  /**
Packit 875988
   * TLS session.
Packit 875988
   */
Packit 875988
  gnutls_session_t tls_s;
Packit 875988
Packit 875988
  /**
Packit 875988
   * TLS handshake already succeed?
Packit 875988
   */
Packit 875988
  bool tls_connected;
Packit 875988
#endif
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Pseudo type for plain&TLS sockets
Packit 875988
 */
Packit 875988
typedef struct wr_socket_strc* wr_socket;
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Invalid value of wr_socket
Packit 875988
 */
Packit 875988
#define WR_BAD (NULL)
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Get underlying real socket.
Packit 875988
 * @return FD of real socket
Packit 875988
 */
Packit 875988
#define wr_fd(s) ((s)->fd)
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create wr_socket with plain TCP underlying socket
Packit 875988
 * @return created socket on success, WR_BAD otherwise
Packit 875988
 */
Packit 875988
static wr_socket
Packit 875988
wr_create_plain_sckt(void)
Packit 875988
{
Packit 875988
  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
Packit 875988
  if (WR_BAD == s)
Packit 875988
    return WR_BAD;
Packit 875988
  s->t = wr_plain;
Packit 875988
  s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
Packit 875988
  if (MHD_INVALID_SOCKET != s->fd)
Packit 875988
    return s;
Packit 875988
  free(s);
Packit 875988
  return WR_BAD;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create wr_socket with TLS TCP underlying socket
Packit 875988
 * @return created socket on success, WR_BAD otherwise
Packit 875988
 */
Packit 875988
static wr_socket
Packit 875988
wr_create_tls_sckt(void)
Packit 875988
{
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
Packit 875988
  if (WR_BAD == s)
Packit 875988
    return WR_BAD;
Packit 875988
  s->t = wr_tls;
Packit 875988
  s->tls_connected = 0;
Packit 875988
  s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
Packit 875988
  if (MHD_INVALID_SOCKET != s->fd)
Packit 875988
    {
Packit 875988
      if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT))
Packit 875988
        {
Packit 875988
          if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s))
Packit 875988
            {
Packit 875988
              if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (&(s->tls_crd)))
Packit 875988
                {
Packit 875988
                  if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, GNUTLS_CRD_CERTIFICATE, s->tls_crd))
Packit 875988
                    {
Packit 875988
#if GNUTLS_VERSION_NUMBER+0 >= 0x030109
Packit 875988
                      gnutls_transport_set_int (s->tls_s, (int)(s->fd));
Packit 875988
#else  /* GnuTLS before 3.1.9 */
Packit 875988
                      gnutls_transport_set_ptr (s->tls_s, (gnutls_transport_ptr_t)(intptr_t)(s->fd));
Packit 875988
#endif /* GnuTLS before 3.1.9 */
Packit 875988
                      return s;
Packit 875988
                    }
Packit 875988
                  gnutls_certificate_free_credentials (s->tls_crd);
Packit 875988
                }
Packit 875988
            }
Packit 875988
          gnutls_deinit (s->tls_s);
Packit 875988
        }
Packit 875988
      (void)MHD_socket_close_ (s->fd);
Packit 875988
    }
Packit 875988
  free(s);
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  return WR_BAD;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create wr_socket with plain TCP underlying socket
Packit 875988
 * from already created TCP socket.
Packit 875988
 * @param plain_sk real TCP socket
Packit 875988
 * @return created socket on success, WR_BAD otherwise
Packit 875988
 */
Packit 875988
static wr_socket
Packit 875988
wr_create_from_plain_sckt(MHD_socket plain_sk)
Packit 875988
{
Packit 875988
  wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc));
Packit 875988
Packit 875988
  if (WR_BAD == s)
Packit 875988
    return WR_BAD;
Packit 875988
  s->t = wr_plain;
Packit 875988
  s->fd = plain_sk;
Packit 875988
  return s;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Connect socket to specified address.
Packit 875988
 * @param s socket to use
Packit 875988
 * @param addr address to connect
Packit 875988
 * @param length of sturcture pointed by @a addr
Packit 875988
 * @return zero on success, -1 otherwise.
Packit 875988
 */
Packit 875988
static int
Packit 875988
wr_connect(wr_socket s,
Packit 875988
           const struct sockaddr *addr,
Packit 875988
           int length)
Packit 875988
{
Packit 875988
  if (0 != connect (s->fd, addr, length))
Packit 875988
    return -1;
Packit 875988
  if (wr_plain == s->t)
Packit 875988
    return 0;
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  if (wr_tls == s->t)
Packit 875988
    {
Packit 875988
      /* Do not try handshake here as
Packit 875988
       * it require processing on MHD side and
Packit 875988
       * when testing with "external" polling,
Packit 875988
       * test will call MHD processing only
Packit 875988
       * after return from wr_connect(). */
Packit 875988
      s->tls_connected = 0;
Packit 875988
      return 0;
Packit 875988
    }
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  return -1;
Packit 875988
}
Packit 875988
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
/* Only to be called from wr_send() and wr_recv() ! */
Packit 875988
static bool wr_handshake(wr_socket s)
Packit 875988
{
Packit 875988
  int res = gnutls_handshake (s->tls_s);
Packit 875988
  if (GNUTLS_E_SUCCESS == res)
Packit 875988
    s->tls_connected = true;
Packit 875988
  else if (GNUTLS_E_AGAIN == res)
Packit 875988
    MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
Packit 875988
  else
Packit 875988
    MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
Packit 875988
  return s->tls_connected;
Packit 875988
}
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Send data to remote by socket.
Packit 875988
 * @param s the socket to use
Packit 875988
 * @param buf the buffer with data to send
Packit 875988
 * @param len the length of data in @a buf
Packit 875988
 * @return number of bytes were sent if succeed,
Packit 875988
 *         -1 if failed. Use #MHD_socket_get_error_()
Packit 875988
 *         to get socket error.
Packit 875988
 */
Packit 875988
static ssize_t
Packit 875988
wr_send (wr_socket s,
Packit 875988
         const void *buf,
Packit 875988
         size_t len)
Packit 875988
{
Packit 875988
  if (wr_plain == s->t)
Packit 875988
    return MHD_send_(s->fd, buf, len);
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  if (wr_tls == s->t)
Packit 875988
    {
Packit 875988
      ssize_t ret;
Packit 875988
      if (!s->tls_connected && !wr_handshake (s))
Packit 875988
        return -1;
Packit 875988
Packit 875988
      ret = gnutls_record_send (s->tls_s, buf, len);
Packit 875988
      if (ret > 0)
Packit 875988
        return ret;
Packit 875988
      if (GNUTLS_E_AGAIN == ret)
Packit 875988
        MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
Packit 875988
      else
Packit 875988
        MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
Packit 875988
    }
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  return -1;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Receive data from remote by socket.
Packit 875988
 * @param s the socket to use
Packit 875988
 * @param buf the buffer to store received data
Packit 875988
 * @param len the length of @a buf
Packit 875988
 * @return number of bytes were received if succeed,
Packit 875988
 *         -1 if failed. Use #MHD_socket_get_error_()
Packit 875988
 *         to get socket error.
Packit 875988
 */
Packit 875988
static ssize_t
Packit 875988
wr_recv (wr_socket s,
Packit 875988
         void *buf,
Packit 875988
         size_t len)
Packit 875988
{
Packit 875988
  if (wr_plain == s->t)
Packit 875988
    return MHD_recv_ (s->fd, buf, len);
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  if (wr_tls == s->t)
Packit 875988
    {
Packit 875988
      ssize_t ret;
Packit 875988
      if (!s->tls_connected && !wr_handshake (s))
Packit 875988
        return -1;
Packit 875988
Packit 875988
      ret = gnutls_record_recv (s->tls_s, buf, len);
Packit 875988
      if (ret > 0)
Packit 875988
        return ret;
Packit 875988
      if (GNUTLS_E_AGAIN == ret)
Packit 875988
        MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
Packit 875988
      else
Packit 875988
        MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
Packit 875988
    }
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  return -1;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Close socket and release allocated resourced
Packit 875988
 * @param s the socket to close
Packit 875988
 * @return zero on succeed, -1 otherwise
Packit 875988
 */
Packit 875988
static int
Packit 875988
wr_close (wr_socket s)
Packit 875988
{
Packit 875988
  int ret = (MHD_socket_close_(s->fd)) ? 0 : -1;
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  if (wr_tls == s->t)
Packit 875988
    {
Packit 875988
      gnutls_deinit (s->tls_s);
Packit 875988
      gnutls_certificate_free_credentials (s->tls_crd);
Packit 875988
    }
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  free(s);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Thread we use to run the interaction with the upgraded socket.
Packit 875988
 */
Packit 875988
static pthread_t pt;
Packit 875988
Packit 875988
/**
Packit 875988
 * Will be set to the upgraded socket.
Packit 875988
 */
Packit 875988
static wr_socket usock;
Packit 875988
Packit 875988
/**
Packit 875988
 * Thread we use to run the interaction with the upgraded socket.
Packit 875988
 */
Packit 875988
static pthread_t pt_client;
Packit 875988
Packit 875988
/**
Packit 875988
 * Flag set to 1 once the test is finished.
Packit 875988
 */
Packit 875988
static volatile bool done;
Packit 875988
Packit 875988
Packit 875988
static void
Packit 875988
notify_completed_cb (void *cls,
Packit 875988
                     struct MHD_Connection *connection,
Packit 875988
                     void **con_cls,
Packit 875988
                     enum MHD_RequestTerminationCode toe)
Packit 875988
{
Packit 875988
  (void)cls; (void)connection;  /* Unused. Silent compiler warning. */
Packit 875988
  if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) &&
Packit 875988
       (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) &&
Packit 875988
       (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) )
Packit 875988
    abort ();
Packit 875988
  if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
Packit 875988
    abort ();
Packit 875988
  free (*con_cls);
Packit 875988
  *con_cls = NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Logging callback.
Packit 875988
 *
Packit 875988
 * @param cls logging closure (NULL)
Packit 875988
 * @param uri access URI
Packit 875988
 * @param connection connection handle
Packit 875988
 * @return #TEST_PTR
Packit 875988
 */
Packit 875988
static void *
Packit 875988
log_cb (void *cls,
Packit 875988
        const char *uri,
Packit 875988
        struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  pthread_t* ppth;
Packit 875988
  (void)cls; (void)connection;  /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (0 != strcmp (uri,
Packit 875988
                   "/"))
Packit 875988
    abort ();
Packit 875988
  ppth = (pthread_t*) malloc (sizeof(pthread_t));
Packit 875988
  if (NULL == ppth)
Packit 875988
    abort();
Packit 875988
  *ppth = pthread_self ();
Packit 875988
  return (void *) ppth;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Function to check that MHD properly notifies about starting
Packit 875988
 * and stopping.
Packit 875988
 *
Packit 875988
 * @param cls client-defined closure
Packit 875988
 * @param connection connection handle
Packit 875988
 * @param socket_context socket-specific pointer where the
Packit 875988
 *                       client can associate some state specific
Packit 875988
 *                       to the TCP connection; note that this is
Packit 875988
 *                       different from the "con_cls" which is per
Packit 875988
 *                       HTTP request.  The client can initialize
Packit 875988
 *                       during #MHD_CONNECTION_NOTIFY_STARTED and
Packit 875988
 *                       cleanup during #MHD_CONNECTION_NOTIFY_CLOSED
Packit 875988
 *                       and access in the meantime using
Packit 875988
 *                       #MHD_CONNECTION_INFO_SOCKET_CONTEXT.
Packit 875988
 * @param toe reason for connection notification
Packit 875988
 * @see #MHD_OPTION_NOTIFY_CONNECTION
Packit 875988
 * @ingroup request
Packit 875988
 */
Packit 875988
static void
Packit 875988
notify_connection_cb (void *cls,
Packit 875988
                      struct MHD_Connection *connection,
Packit 875988
                      void **socket_context,
Packit 875988
                      enum MHD_ConnectionNotificationCode toe)
Packit 875988
{
Packit 875988
  static int started;
Packit 875988
  (void)cls; (void)connection;  /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  switch (toe)
Packit 875988
  {
Packit 875988
  case MHD_CONNECTION_NOTIFY_STARTED:
Packit 875988
    if (MHD_NO != started)
Packit 875988
      abort ();
Packit 875988
    started = MHD_YES;
Packit 875988
    *socket_context = &started;
Packit 875988
    break;
Packit 875988
  case MHD_CONNECTION_NOTIFY_CLOSED:
Packit 875988
    if (MHD_YES != started)
Packit 875988
      abort ();
Packit 875988
    if (&started != *socket_context)
Packit 875988
      abort ();
Packit 875988
    *socket_context = NULL;
Packit 875988
    started = MHD_NO;
Packit 875988
    break;
Packit 875988
  }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Change socket to blocking.
Packit 875988
 *
Packit 875988
 * @param fd the socket to manipulate
Packit 875988
 * @return non-zero if succeeded, zero otherwise
Packit 875988
 */
Packit 875988
static void
Packit 875988
make_blocking (MHD_socket fd)
Packit 875988
{
Packit 875988
#if defined(MHD_POSIX_SOCKETS)
Packit 875988
  int flags;
Packit 875988
Packit 875988
  flags = fcntl (fd, F_GETFL);
Packit 875988
  if (-1 == flags)
Packit 875988
    return;
Packit 875988
  if ((flags & ~O_NONBLOCK) != flags)
Packit 875988
    if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
Packit 875988
      abort ();
Packit 875988
#elif defined(MHD_WINSOCK_SOCKETS)
Packit 875988
  unsigned long flags = 1;
Packit 875988
Packit 875988
  ioctlsocket (fd, FIONBIO, &flags);
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static void
Packit 875988
send_all (wr_socket sock,
Packit 875988
          const char *text)
Packit 875988
{
Packit 875988
  size_t len = strlen (text);
Packit 875988
  ssize_t ret;
Packit 875988
  size_t off;
Packit 875988
Packit 875988
  make_blocking (wr_fd (sock));
Packit 875988
  for (off = 0; off < len; off += ret)
Packit 875988
    {
Packit 875988
      ret = wr_send (sock,
Packit 875988
                       &text[off],
Packit 875988
                       len - off);
Packit 875988
      if (0 > ret)
Packit 875988
        {
Packit 875988
          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
Packit 875988
            {
Packit 875988
              ret = 0;
Packit 875988
              continue;
Packit 875988
            }
Packit 875988
          abort ();
Packit 875988
        }
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Read character-by-character until we
Packit 875988
 * get '\r\n\r\n'.
Packit 875988
 */
Packit 875988
static void
Packit 875988
recv_hdr (wr_socket sock)
Packit 875988
{
Packit 875988
  unsigned int i;
Packit 875988
  char next;
Packit 875988
  char c;
Packit 875988
  ssize_t ret;
Packit 875988
Packit 875988
  make_blocking (wr_fd (sock));
Packit 875988
  next = '\r';
Packit 875988
  i = 0;
Packit 875988
  while (i < 4)
Packit 875988
    {
Packit 875988
      ret = wr_recv (sock,
Packit 875988
                       &c,
Packit 875988
                       1);
Packit 875988
      if (0 > ret)
Packit 875988
        {
Packit 875988
          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
Packit 875988
            continue;
Packit 875988
          abort ();
Packit 875988
        }
Packit 875988
      if (0 == ret)
Packit 875988
        continue;
Packit 875988
      if (c == next)
Packit 875988
        {
Packit 875988
          i++;
Packit 875988
          if (next == '\r')
Packit 875988
            next = '\n';
Packit 875988
          else
Packit 875988
            next = '\r';
Packit 875988
          continue;
Packit 875988
        }
Packit 875988
      if (c == '\r')
Packit 875988
        {
Packit 875988
          i = 1;
Packit 875988
          next = '\n';
Packit 875988
          continue;
Packit 875988
        }
Packit 875988
      i = 0;
Packit 875988
      next = '\r';
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static void
Packit 875988
recv_all (wr_socket sock,
Packit 875988
          const char *text)
Packit 875988
{
Packit 875988
  size_t len = strlen (text);
Packit 875988
  char buf[len];
Packit 875988
  ssize_t ret;
Packit 875988
  size_t off;
Packit 875988
Packit 875988
  make_blocking (wr_fd (sock));
Packit 875988
  for (off = 0; off < len; off += ret)
Packit 875988
    {
Packit 875988
      ret = wr_recv (sock,
Packit 875988
                       &buf[off],
Packit 875988
                       len - off);
Packit 875988
      if (0 > ret)
Packit 875988
        {
Packit 875988
          if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
Packit 875988
            {
Packit 875988
              ret = 0;
Packit 875988
              continue;
Packit 875988
            }
Packit 875988
          abort ();
Packit 875988
        }
Packit 875988
    }
Packit 875988
  if (0 != strncmp (text, buf, len))
Packit 875988
    abort();
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Main function for the thread that runs the interaction with
Packit 875988
 * the upgraded socket.
Packit 875988
 *
Packit 875988
 * @param cls the handle for the upgrade
Packit 875988
 */
Packit 875988
static void *
Packit 875988
run_usock (void *cls)
Packit 875988
{
Packit 875988
  struct MHD_UpgradeResponseHandle *urh = cls;
Packit 875988
Packit 875988
  send_all (usock,
Packit 875988
            "Hello");
Packit 875988
  recv_all (usock,
Packit 875988
            "World");
Packit 875988
  send_all (usock,
Packit 875988
            "Finished");
Packit 875988
  MHD_upgrade_action (urh,
Packit 875988
                      MHD_UPGRADE_ACTION_CLOSE);
Packit 875988
  return NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Main function for the thread that runs the client-side of the
Packit 875988
 * interaction with the upgraded socket.
Packit 875988
 *
Packit 875988
 * @param cls the client socket
Packit 875988
 */
Packit 875988
static void *
Packit 875988
run_usock_client (void *cls)
Packit 875988
{
Packit 875988
  wr_socket *sock = cls;
Packit 875988
Packit 875988
  send_all (*sock,
Packit 875988
            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
Packit 875988
  recv_hdr (*sock);
Packit 875988
  recv_all (*sock,
Packit 875988
            "Hello");
Packit 875988
  send_all (*sock,
Packit 875988
            "World");
Packit 875988
  recv_all (*sock,
Packit 875988
            "Finished");
Packit 875988
  wr_close (*sock);
Packit 875988
  done = true;
Packit 875988
  return NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Function called after a protocol "upgrade" response was sent
Packit 875988
 * successfully and the socket should now be controlled by some
Packit 875988
 * protocol other than HTTP.
Packit 875988
 *
Packit 875988
 * Any data already received on the socket will be made available in
Packit 875988
 * @e extra_in.  This can happen if the application sent extra data
Packit 875988
 * before MHD send the upgrade response.  The application should
Packit 875988
 * treat data from @a extra_in as if it had read it from the socket.
Packit 875988
 *
Packit 875988
 * Note that the application must not close() @a sock directly,
Packit 875988
 * but instead use #MHD_upgrade_action() for special operations
Packit 875988
 * on @a sock.
Packit 875988
 *
Packit 875988
 * Except when in 'thread-per-connection' mode, implementations
Packit 875988
 * of this function should never block (as it will still be called
Packit 875988
 * from within the main event loop).
Packit 875988
 *
Packit 875988
 * @param cls closure, whatever was given to #MHD_create_response_for_upgrade().
Packit 875988
 * @param connection original HTTP connection handle,
Packit 875988
 *                   giving the function a last chance
Packit 875988
 *                   to inspect the original HTTP request
Packit 875988
 * @param con_cls last value left in `con_cls` of the `MHD_AccessHandlerCallback`
Packit 875988
 * @param extra_in if we happened to have read bytes after the
Packit 875988
 *                 HTTP header already (because the client sent
Packit 875988
 *                 more than the HTTP header of the request before
Packit 875988
 *                 we sent the upgrade response),
Packit 875988
 *                 these are the extra bytes already read from @a sock
Packit 875988
 *                 by MHD.  The application should treat these as if
Packit 875988
 *                 it had read them from @a sock.
Packit 875988
 * @param extra_in_size number of bytes in @a extra_in
Packit 875988
 * @param sock socket to use for bi-directional communication
Packit 875988
 *        with the client.  For HTTPS, this may not be a socket
Packit 875988
 *        that is directly connected to the client and thus certain
Packit 875988
 *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
Packit 875988
 *        may not work as expected (as the socket could be from a
Packit 875988
 *        socketpair() or a TCP-loopback).  The application is expected
Packit 875988
 *        to perform read()/recv() and write()/send() calls on the socket.
Packit 875988
 *        The application may also call shutdown(), but must not call
Packit 875988
 *        close() directly.
Packit 875988
 * @param urh argument for #MHD_upgrade_action()s on this @a connection.
Packit 875988
 *        Applications must eventually use this callback to (indirectly)
Packit 875988
 *        perform the close() action on the @a sock.
Packit 875988
 */
Packit 875988
static void
Packit 875988
upgrade_cb (void *cls,
Packit 875988
            struct MHD_Connection *connection,
Packit 875988
            void *con_cls,
Packit 875988
            const char *extra_in,
Packit 875988
            size_t extra_in_size,
Packit 875988
            MHD_socket sock,
Packit 875988
            struct MHD_UpgradeResponseHandle *urh)
Packit 875988
{
Packit 875988
  (void)cls; (void)connection; (void)con_cls; (void)extra_in; /* Unused. Silent compiler warning. */
Packit 875988
  usock = wr_create_from_plain_sckt (sock);
Packit 875988
  if (0 != extra_in_size)
Packit 875988
    abort ();
Packit 875988
  if (0 != pthread_create (&pt,
Packit 875988
                           NULL,
Packit 875988
                           &run_usock,
Packit 875988
                           urh))
Packit 875988
    abort ();
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * A client has requested the given url using the given method
Packit 875988
 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
Packit 875988
 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
Packit 875988
 * must call MHD callbacks to provide content to give back to the
Packit 875988
 * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
Packit 875988
 * #MHD_HTTP_NOT_FOUND, etc.).
Packit 875988
 *
Packit 875988
 * @param cls argument given together with the function
Packit 875988
 *        pointer when the handler was registered with MHD
Packit 875988
 * @param url the requested url
Packit 875988
 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
Packit 875988
 *        #MHD_HTTP_METHOD_PUT, etc.)
Packit 875988
 * @param version the HTTP version string (i.e.
Packit 875988
 *        #MHD_HTTP_VERSION_1_1)
Packit 875988
 * @param upload_data the data being uploaded (excluding HEADERS,
Packit 875988
 *        for a POST that fits into memory and that is encoded
Packit 875988
 *        with a supported encoding, the POST data will NOT be
Packit 875988
 *        given in upload_data and is instead available as
Packit 875988
 *        part of #MHD_get_connection_values; very large POST
Packit 875988
 *        data *will* be made available incrementally in
Packit 875988
 *        @a upload_data)
Packit 875988
 * @param upload_data_size set initially to the size of the
Packit 875988
 *        @a upload_data provided; the method must update this
Packit 875988
 *        value to the number of bytes NOT processed;
Packit 875988
 * @param con_cls pointer that the callback can set to some
Packit 875988
 *        address and that will be preserved by MHD for future
Packit 875988
 *        calls for this request; since the access handler may
Packit 875988
 *        be called many times (i.e., for a PUT/POST operation
Packit 875988
 *        with plenty of upload data) this allows the application
Packit 875988
 *        to easily associate some request-specific state.
Packit 875988
 *        If necessary, this state can be cleaned up in the
Packit 875988
 *        global #MHD_RequestCompletedCallback (which
Packit 875988
 *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
Packit 875988
 *        Initially, `*con_cls` will be NULL.
Packit 875988
 * @return #MHD_YES if the connection was handled successfully,
Packit 875988
 *         #MHD_NO if the socket must be closed due to a serios
Packit 875988
 *         error while handling the request
Packit 875988
 */
Packit 875988
static int
Packit 875988
ahc_upgrade (void *cls,
Packit 875988
             struct MHD_Connection *connection,
Packit 875988
             const char *url,
Packit 875988
             const char *method,
Packit 875988
             const char *version,
Packit 875988
             const char *upload_data,
Packit 875988
             size_t *upload_data_size,
Packit 875988
             void **con_cls)
Packit 875988
{
Packit 875988
  struct MHD_Response *resp;
Packit 875988
  int ret;
Packit 875988
  (void)cls;(void)url;(void)method;                        /* Unused. Silent compiler warning. */
Packit 875988
  (void)version;(void)upload_data;(void)upload_data_size;  /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (NULL == *con_cls)
Packit 875988
    abort ();
Packit 875988
  if (! pthread_equal (**((pthread_t**)con_cls), pthread_self ()))
Packit 875988
    abort ();
Packit 875988
  resp = MHD_create_response_for_upgrade (&upgrade_cb,
Packit 875988
                                          NULL);
Packit 875988
  MHD_add_response_header (resp,
Packit 875988
                           MHD_HTTP_HEADER_UPGRADE,
Packit 875988
                           "Hello World Protocol");
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
                            MHD_HTTP_SWITCHING_PROTOCOLS,
Packit 875988
                            resp);
Packit 875988
  MHD_destroy_response (resp);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Run the MHD external event loop using select.
Packit 875988
 *
Packit 875988
 * @param daemon daemon to run it for
Packit 875988
 */
Packit 875988
static void
Packit 875988
run_mhd_select_loop (struct MHD_Daemon *daemon)
Packit 875988
{
Packit 875988
  fd_set rs;
Packit 875988
  fd_set ws;
Packit 875988
  fd_set es;
Packit 875988
  MHD_socket max_fd;
Packit 875988
  MHD_UNSIGNED_LONG_LONG to;
Packit 875988
  struct timeval tv;
Packit 875988
Packit 875988
  while (! done)
Packit 875988
    {
Packit 875988
      FD_ZERO (&rs);
Packit 875988
      FD_ZERO (&ws);
Packit 875988
      FD_ZERO (&es);
Packit 875988
      max_fd = -1;
Packit 875988
      to = 1000;
Packit 875988
Packit 875988
      if (MHD_YES !=
Packit 875988
          MHD_get_fdset (daemon,
Packit 875988
                         &rs,
Packit 875988
                         &ws,
Packit 875988
                         &es,
Packit 875988
                         &max_fd))
Packit 875988
        abort ();
Packit 875988
      (void) MHD_get_timeout (daemon,
Packit 875988
                              &to);
Packit 875988
      if (1000 < to)
Packit 875988
        to = 1000;
Packit 875988
      tv.tv_sec = to / 1000;
Packit 875988
      tv.tv_usec = 1000 * (to % 1000);
Packit 875988
      if (0 > MHD_SYS_select_ (max_fd + 1,
Packit 875988
                               &rs,
Packit 875988
                               &ws,
Packit 875988
                               &es,
Packit 875988
                               &tv))
Packit 875988
        abort ();
Packit 875988
      MHD_run_from_select (daemon,
Packit 875988
                           &rs,
Packit 875988
                           &ws,
Packit 875988
                           &es);
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
#ifdef HAVE_POLL
Packit 875988
Packit 875988
/**
Packit 875988
 * Run the MHD external event loop using select.
Packit 875988
 *
Packit 875988
 * @param daemon daemon to run it for
Packit 875988
 */
Packit 875988
static void
Packit 875988
run_mhd_poll_loop (struct MHD_Daemon *daemon)
Packit 875988
{
Packit 875988
  (void)daemon; /* Unused. Silent compiler warning. */
Packit 875988
  abort (); /* currently not implementable with existing MHD API */
Packit 875988
}
Packit 875988
#endif /* HAVE_POLL */
Packit 875988
Packit 875988
Packit 875988
#ifdef EPOLL_SUPPORT
Packit 875988
/**
Packit 875988
 * Run the MHD external event loop using select.
Packit 875988
 *
Packit 875988
 * @param daemon daemon to run it for
Packit 875988
 */
Packit 875988
static void
Packit 875988
run_mhd_epoll_loop (struct MHD_Daemon *daemon)
Packit 875988
{
Packit 875988
  const union MHD_DaemonInfo *di;
Packit 875988
  MHD_socket ep;
Packit 875988
  fd_set rs;
Packit 875988
  MHD_UNSIGNED_LONG_LONG to;
Packit 875988
  struct timeval tv;
Packit 875988
Packit 875988
  di = MHD_get_daemon_info (daemon,
Packit 875988
                            MHD_DAEMON_INFO_EPOLL_FD);
Packit 875988
  ep = di->listen_fd;
Packit 875988
  while (! done)
Packit 875988
    {
Packit 875988
      FD_ZERO (&rs);
Packit 875988
      to = 1000;
Packit 875988
Packit 875988
      FD_SET (ep, &rs);
Packit 875988
      (void) MHD_get_timeout (daemon,
Packit 875988
                              &to);
Packit 875988
      if (1000 < to)
Packit 875988
        to = 1000;
Packit 875988
      tv.tv_sec = to / 1000;
Packit 875988
      tv.tv_usec = 1000 * (to % 1000);
Packit 875988
      select (ep + 1,
Packit 875988
              &rs,
Packit 875988
              NULL,
Packit 875988
              NULL,
Packit 875988
              &tv;;
Packit 875988
      MHD_run (daemon);
Packit 875988
    }
Packit 875988
}
Packit 875988
#endif /* EPOLL_SUPPORT */
Packit 875988
Packit 875988
/**
Packit 875988
 * Run the MHD external event loop using select.
Packit 875988
 *
Packit 875988
 * @param daemon daemon to run it for
Packit 875988
 */
Packit 875988
static void
Packit 875988
run_mhd_loop (struct MHD_Daemon *daemon,
Packit 875988
              int flags)
Packit 875988
{
Packit 875988
  if (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL)))
Packit 875988
    run_mhd_select_loop (daemon);
Packit 875988
#ifdef HAVE_POLL
Packit 875988
  else if (0 != (flags & MHD_USE_POLL))
Packit 875988
    run_mhd_poll_loop (daemon);
Packit 875988
#endif /* HAVE_POLL */
Packit 875988
#if EPOLL_SUPPORT
Packit 875988
  else if (0 != (flags & MHD_USE_EPOLL))
Packit 875988
    run_mhd_epoll_loop (daemon);
Packit 875988
#endif
Packit 875988
  else
Packit 875988
    abort ();
Packit 875988
}
Packit 875988
Packit 875988
static bool test_tls;
Packit 875988
Packit 875988
/**
Packit 875988
 * Test upgrading a connection.
Packit 875988
 *
Packit 875988
 * @param flags which event loop style should be tested
Packit 875988
 * @param pool size of the thread pool, 0 to disable
Packit 875988
 */
Packit 875988
static int
Packit 875988
test_upgrade (int flags,
Packit 875988
              unsigned int pool)
Packit 875988
{
Packit 875988
  struct MHD_Daemon *d = NULL;
Packit 875988
  wr_socket sock;
Packit 875988
  struct sockaddr_in sa;
Packit 875988
  const union MHD_DaemonInfo *real_flags;
Packit 875988
  const union MHD_DaemonInfo *dinfo;
Packit 875988
#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
  pid_t pid = -1;
Packit 875988
#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
Packit 875988
Packit 875988
  done = false;
Packit 875988
Packit 875988
  if (!test_tls)
Packit 875988
    d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE,
Packit 875988
			  MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
Packit 875988
			      0 : 1090,
Packit 875988
			  NULL, NULL,
Packit 875988
			  &ahc_upgrade, NULL,
Packit 875988
			  MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
Packit 875988
			  MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
Packit 875988
			  MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
Packit 875988
			  MHD_OPTION_THREAD_POOL_SIZE, pool,
Packit 875988
			  MHD_OPTION_END);
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  else
Packit 875988
    d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE | MHD_USE_TLS,
Packit 875988
                          MHD_is_feature_supported(MHD_FEATURE_AUTODETECT_BIND_PORT) ?
Packit 875988
                              0 : 1090,
Packit 875988
                          NULL, NULL,
Packit 875988
                          &ahc_upgrade, NULL,
Packit 875988
                          MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
Packit 875988
                          MHD_OPTION_NOTIFY_COMPLETED, &notify_completed_cb, NULL,
Packit 875988
                          MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb, NULL,
Packit 875988
                          MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
Packit 875988
                          MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
Packit 875988
                          MHD_OPTION_THREAD_POOL_SIZE, pool,
Packit 875988
                          MHD_OPTION_END);
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  if (NULL == d)
Packit 875988
    return 2;
Packit 875988
  real_flags = MHD_get_daemon_info(d, MHD_DAEMON_INFO_FLAGS);
Packit 875988
  if (NULL == real_flags)
Packit 875988
    abort ();
Packit 875988
  dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
Packit 875988
  if (NULL == dinfo || 0 == dinfo->port)
Packit 875988
    abort ();
Packit 875988
  if (!test_tls || TLS_LIB_GNUTLS == use_tls_tool)
Packit 875988
    {
Packit 875988
      sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt ();
Packit 875988
      if (WR_BAD == sock)
Packit 875988
        abort ();
Packit 875988
      sa.sin_family = AF_INET;
Packit 875988
      sa.sin_port = htons (dinfo->port);
Packit 875988
      sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
Packit 875988
      if (0 != wr_connect (sock,
Packit 875988
                        (struct sockaddr *) &sa,
Packit 875988
                        sizeof (sa)))
Packit 875988
        abort ();
Packit 875988
    }
Packit 875988
  else
Packit 875988
    {
Packit 875988
#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
      MHD_socket tls_fork_sock;
Packit 875988
      if (-1 == (pid = gnutlscli_connect (&tls_fork_sock, dinfo->port)))
Packit 875988
        {
Packit 875988
          MHD_stop_daemon (d);
Packit 875988
          return 4;
Packit 875988
        }
Packit 875988
      sock =  wr_create_from_plain_sckt (tls_fork_sock);
Packit 875988
      if (WR_BAD == sock)
Packit 875988
        abort ();
Packit 875988
#else  /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
Packit 875988
      abort ();
Packit 875988
#endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
Packit 875988
    }
Packit 875988
Packit 875988
  if (0 != pthread_create (&pt_client,
Packit 875988
                           NULL,
Packit 875988
                           &run_usock_client,
Packit 875988
                           &sock))
Packit 875988
    abort ();
Packit 875988
  if (0 == (flags & MHD_USE_INTERNAL_POLLING_THREAD) )
Packit 875988
    run_mhd_loop (d, real_flags->flags);
Packit 875988
  pthread_join (pt_client,
Packit 875988
                NULL);
Packit 875988
  pthread_join (pt,
Packit 875988
                NULL);
Packit 875988
#if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
  if (test_tls && TLS_LIB_GNUTLS != use_tls_tool)
Packit 875988
    waitpid (pid, NULL, 0);
Packit 875988
#endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
Packit 875988
  MHD_stop_daemon (d);
Packit 875988
  return 0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
int
Packit 875988
main (int argc,
Packit 875988
      char *const *argv)
Packit 875988
{
Packit 875988
  int error_count = 0;
Packit 875988
  int res;
Packit 875988
Packit 875988
  use_tls_tool = TLS_CLI_NO_TOOL;
Packit 875988
  test_tls = has_in_name(argv[0], "_tls");
Packit 875988
Packit 875988
  verbose = 1;
Packit 875988
  if (has_param(argc, argv, "-q") || has_param(argc, argv, "--quiet"))
Packit 875988
    verbose = 0;
Packit 875988
Packit 875988
  if (test_tls)
Packit 875988
    {
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
      if (has_param(argc, argv, "--use-gnutls-cli"))
Packit 875988
        use_tls_tool = TLS_CLI_GNUTLS;
Packit 875988
      else if (has_param(argc, argv, "--use-openssl"))
Packit 875988
        use_tls_tool = TLS_CLI_OPENSSL;
Packit 875988
      else if (has_param(argc, argv, "--use-gnutls-lib"))
Packit 875988
        use_tls_tool = TLS_LIB_GNUTLS;
Packit 875988
#if defined(HAVE_FORK) && defined(HAVE_WAITPID)
Packit 875988
      else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null"))
Packit 875988
        use_tls_tool = TLS_CLI_GNUTLS;
Packit 875988
      else if (0 == system ("openssl version 1> /dev/null 2> /dev/null"))
Packit 875988
        use_tls_tool = TLS_CLI_OPENSSL;
Packit 875988
#endif /* HAVE_FORK && HAVE_WAITPID */
Packit 875988
      else
Packit 875988
        use_tls_tool = TLS_LIB_GNUTLS; /* Should be available as MHD use it. */
Packit 875988
      if (verbose)
Packit 875988
        {
Packit 875988
          switch (use_tls_tool)
Packit 875988
          {
Packit 875988
            case TLS_CLI_GNUTLS:
Packit 875988
              printf ("GnuTLS-CLI will be used for testing.\n");
Packit 875988
              break;
Packit 875988
            case TLS_CLI_OPENSSL:
Packit 875988
              printf ("Command line version of OpenSSL will be used for testing.\n");
Packit 875988
              break;
Packit 875988
            case TLS_LIB_GNUTLS:
Packit 875988
              printf ("GnuTLS library will be used for testing.\n");
Packit 875988
              break;
Packit 875988
            default:
Packit 875988
              abort ();
Packit 875988
          }
Packit 875988
        }
Packit 875988
      if ( (TLS_LIB_GNUTLS == use_tls_tool) &&
Packit 875988
           (GNUTLS_E_SUCCESS != gnutls_global_init()) )
Packit 875988
        abort ();
Packit 875988
Packit 875988
#else  /* ! HTTPS_SUPPORT */
Packit 875988
      fprintf (stderr, "HTTPS support was disabled by configure.\n");
Packit 875988
      return 77;
Packit 875988
#endif /* ! HTTPS_SUPPORT */
Packit 875988
    }
Packit 875988
Packit 875988
  /* run tests */
Packit 875988
  if (verbose)
Packit 875988
    printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n", test_tls ? "TLS" : "plain");
Packit 875988
  /* try external select */
Packit 875988
  res = test_upgrade (0,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with external select, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with external select.\n");
Packit 875988
Packit 875988
  /* Try external auto */
Packit 875988
  res = test_upgrade (MHD_USE_AUTO,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with external 'auto', return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with external 'auto'.\n");
Packit 875988
Packit 875988
#ifdef EPOLL_SUPPORT
Packit 875988
  res = test_upgrade (MHD_USE_EPOLL,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with external select with EPOLL, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with external select with EPOLL.\n");
Packit 875988
#endif
Packit 875988
Packit 875988
  /* Test thread-per-connection */
Packit 875988
  res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with thread per connection, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with thread per connection.\n");
Packit 875988
Packit 875988
  res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with thread per connection and 'auto', return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with thread per connection and 'auto'.\n");
Packit 875988
#ifdef HAVE_POLL
Packit 875988
  res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with thread per connection and poll, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with thread per connection and poll.\n");
Packit 875988
#endif /* HAVE_POLL */
Packit 875988
Packit 875988
  /* Test different event loops, with and without thread pool */
Packit 875988
  res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal select, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal select.\n");
Packit 875988
  res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD,
Packit 875988
                      2);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal select with thread pool, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal select with thread pool.\n");
Packit 875988
  res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal 'auto' return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal 'auto'.\n");
Packit 875988
  res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD,
Packit 875988
                      2);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal 'auto' with thread pool, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal 'auto' with thread pool.\n");
Packit 875988
#ifdef HAVE_POLL
Packit 875988
  res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
Packit 875988
                      0);
Packit 875988
  error_count += res;
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal poll, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal poll.\n");
Packit 875988
  res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD,
Packit 875988
                      2);
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal poll with thread pool, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal poll with thread pool.\n");
Packit 875988
#endif
Packit 875988
#ifdef EPOLL_SUPPORT
Packit 875988
  res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
Packit 875988
                      0);
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal epoll, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal epoll.\n");
Packit 875988
  res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD,
Packit 875988
                      2);
Packit 875988
  if (res)
Packit 875988
    fprintf (stderr, "FAILED: Upgrade with internal epoll, return code %d.\n", res);
Packit 875988
  else if (verbose)
Packit 875988
    printf ("PASSED: Upgrade with internal epoll.\n");
Packit 875988
#endif
Packit 875988
  /* report result */
Packit 875988
  if (0 != error_count)
Packit 875988
    fprintf (stderr,
Packit 875988
             "Error (code: %u)\n",
Packit 875988
             error_count);
Packit 875988
#ifdef HTTPS_SUPPORT
Packit 875988
  if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool))
Packit 875988
    gnutls_global_deinit();
Packit 875988
#endif /* HTTPS_SUPPORT */
Packit 875988
  return error_count != 0;       /* 0 == pass */
Packit 875988
}