text: /*
      This file is part of libmicrospdy
      Copyright Copyright (C) 2013 Andrey Uzunov
  
      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  /**
   * @file test_proxies.c
   * @brief  test curl > mhd2spdylay > microspdy2http > mhd
   * @author Andrey Uzunov
   */
  
  #include "platform.h"
  #include "microspdy.h"
  #include "common.h"
  #include <sys/wait.h>
  #include <stdio.h>   /* printf, stderr, fprintf */
  #include <sys/types.h> /* pid_t */
  #include <unistd.h>  /* _exit, fork */
  #include <stdlib.h>  /* exit */
  #include <errno.h>   /* errno */
  #include <sys/wait.h> /* pid_t */
  #include "common.h"
  
  #ifdef _WIN32
  #ifndef WIN32_LEAN_AND_MEAN
  #define WIN32_LEAN_AND_MEAN 1
  #endif /* !WIN32_LEAN_AND_MEAN */
  #include <windows.h>
  #endif
  
  #define EXPECTED_BODY "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>"
  
  
  pid_t parent;
  	pid_t child_mhd;
  	pid_t child_spdy2http;
  	pid_t child_mhd2spdy;
  	pid_t child_curl;
  
  	uint16_t mhd_port;
  	uint16_t spdy2http_port;
  	uint16_t mhd2spdy_port;
  
  void
  killproc(int pid, const char *message)
  {
  	printf("%s\nkilling %i\n",message,pid);
  	kill(pid, SIGKILL);
  }
  
  
  void killchildren()
  {
      if(0 != child_mhd)
        killproc(child_mhd,"kill mhd\n");
      if(0 != child_spdy2http)
        killproc(child_spdy2http,"kill spdy2http\n");
      if(0 != child_mhd2spdy)
        killproc(child_mhd2spdy,"kill mhd2spdy\n");
      if(0 != child_curl)
        killproc(child_curl,"kill curl\n");
  }
  
  pid_t au_fork()
  {
    pid_t child = fork();
  	if (child == -1)
  	{
      killchildren();
  
  		killproc(parent,"fork failed\n");
  	}
  
  	return child;
  }
  
  
  int main()
  {
    //pid_t child;
  	int childstatus;
  	pid_t wpid;
  
  	parent = getpid();
  	mhd_port = get_port(4000);
  	spdy2http_port = get_port(4100);
  	mhd2spdy_port = get_port(4200);
  
  	child_mhd = au_fork();
  	if (child_mhd == 0)
  	{
      //run MHD
  		pid_t devnull;
      char *port_s;
  
  		close(1);
  		devnull = open("/dev/null", O_WRONLY);
                  if (-1 == devnull)
                    abort();
  		if (1 != devnull)
  		{
  			dup2(devnull, 1);
  			close(devnull);
  		}
      asprintf(&port_s, "%i", mhd_port);
  		execlp ("../examples/minimal_example", "minimal_example", port_s, NULL);
  		fprintf(stderr, "executing mhd failed\nFor this test 'make' must be run before 'make check'!\n");
      //killchildren();
      _exit(1);
  	}
  
  
  	child_spdy2http = au_fork();
  	if (child_spdy2http == 0)
  	{
      //run spdy2http
  		pid_t devnull;
      char *port_s;
      //char *url;
  
  		close(1);
  		devnull = open("/dev/null", O_WRONLY);
                  if (-1 == devnull)
                    abort();
  		if (1 != devnull)
  		{
  			dup2(devnull, 1);
  			close(devnull);
  		}
      //asprintf(&url, "127.0.0.1:%i", mhd_port);
      asprintf(&port_s, "%i", spdy2http_port);
      sleep(1);
  		execlp ("../spdy2http/microspdy2http", "microspdy2http", "-v4rtT", "10", "-p", port_s, NULL);
  		fprintf(stderr, "executing microspdy2http failed\n");
      //killchildren();
      _exit(1);
  	}
  
  	child_mhd2spdy = au_fork();
  	if (child_mhd2spdy == 0)
  	{
      //run MHD2sdpy
  		pid_t devnull;
      char *port_s;
      char *url;
  
  		close(1);
  		devnull = open("/dev/null", O_WRONLY);
                  if (-1 == devnull)
                    abort();
  		if (1 != devnull)
  		{
  			dup2(devnull, 1);
  			close(devnull);
  		}
      asprintf(&url, "http://127.0.0.1:%i", spdy2http_port);
      asprintf(&port_s, "%i", mhd2spdy_port);
      sleep(2);
  		execlp ("../examples/mhd2spdy", "mhd2spdy", "-vosb", url, "-p", port_s, NULL);
  		fprintf(stderr, "executing mhd2spdy failed\n");
      //killchildren();
      _exit(1);
  	}
  
  	child_curl = au_fork();
  	if (child_curl == 0)
  	{
      //run curl
      FILE *p;
  		pid_t devnull;
  		char *cmd;
      unsigned int i;
      int retc;
      char buf[strlen(EXPECTED_BODY) + 1];
  
  		close(1);
  		devnull = open("/dev/null", O_WRONLY);
                  if (-1 == devnull)
                    abort ();
  		if (1 != devnull)
  		{
  			dup2(devnull, 1);
  			close(devnull);
  		}
  
  		asprintf (&cmd, "curl --proxy http://127.0.0.1:%i http://127.0.0.1:%i/", mhd2spdy_port, mhd_port);
      sleep(3);
      p = popen(cmd, "r");
      if (p != NULL)
      {
        for (i = 0; i < strlen(EXPECTED_BODY) && !feof(p); i++)
        {
            retc = fgetc (p);
            if (EOF == retc)
              abort (); /* what did feof(p) do there!? */
            buf[i] = (char) retc;
        }
  
        pclose(p);
        buf[i] = 0;
        _exit(strcmp(EXPECTED_BODY, buf));
      }
  		fprintf(stderr, "executing curl failed\n");
      //killchildren();
      _exit(1);
  	}
  
    do
    {
      wpid = waitpid(child_mhd,&childstatus,WNOHANG);
      if(wpid == child_mhd)
      {
        fprintf(stderr, "mhd died unexpectedly\n");
        killchildren();
        return 1;
      }
  
      wpid = waitpid(child_spdy2http,&childstatus,WNOHANG);
      if(wpid == child_spdy2http)
      {
        fprintf(stderr, "spdy2http died unexpectedly\n");
        killchildren();
        return 1;
      }
  
      wpid = waitpid(child_mhd2spdy,&childstatus,WNOHANG);
      if(wpid == child_mhd2spdy)
      {
        fprintf(stderr, "mhd2spdy died unexpectedly\n");
        killchildren();
        return 1;
      }
  
      if(waitpid(child_curl,&childstatus,WNOHANG) == child_curl)
      {
        killchildren();
        return WEXITSTATUS(childstatus);
      }
      sleep(1);
    }
  	while(true);
  }
  