C++程序  |  290行  |  5.89 KB

/*
    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 misc.c
 * @brief  tests a lot of small calls and callbacks. TODO mention what
 * @author Andrey Uzunov
 */

#include "platform.h"
#include "microspdy.h"
#include "stdio.h"
#include <sys/wait.h>
#include "common.h"

int port;

#define HTML "<html><head>\
<link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />\
</head><body>This is libmicrospdy</body></html>"

#define CSS "body{font-size:15px}"

#define SESSION_CLS "1234567890"

#define REQUEST_CLS "1234567890REQ"

pid_t parent;
pid_t child;

struct SPDY_Session *session1;
struct SPDY_Session *session2;

void
killchild()
{
	kill(child, SIGKILL);
	exit(1);
}

void
killparent()
{
	kill(parent, SIGKILL);
	_exit(1);
}


void
create_child()
{
	parent = getpid();

	child = fork();
	if (-1 == child)
	{
		fprintf(stderr, "can't fork, error %d\n", errno);
		exit(EXIT_FAILURE);
	}

	if (child == 0)
	{
		int devnull;
		char *uri;
		fflush(stdout);
		devnull = open("/dev/null", O_WRONLY);
                if (-1 == devnull)
                  abort ();
		if (1 != devnull)
		{
			dup2(devnull, 1);
			close(devnull);
		}
		asprintf(&uri,"https://127.0.0.1:%i/",port);
		execlp("spdycat", "spdycat","-anv",uri,NULL );
		printf("execlp failed\n");
		killparent();
	}
}

void
response_done_callback(void *cls,
								struct SPDY_Response * response,
								struct SPDY_Request * request,
								enum SPDY_RESPONSE_RESULT status,
						bool streamopened)
{
  (void)status;
  (void)streamopened;

	if(strcmp(cls,"/main.css"))
	{
		session1 = SPDY_get_session_for_request(request);
		if(NULL == session1)
		{
			printf("SPDY_get_session_for_request failed\n");
			killchild();
		}

		char *session_cls = strdup(SESSION_CLS);
		SPDY_set_cls_to_session(session1,session_cls);
	}
	else
	{
		session2 = SPDY_get_session_for_request(request);
		if(session1 != session2)
		{
			printf("SPDY_get_session_for_request failed the second time\n");
			killchild();
		}
		printf("SPDY_get_session_for_request tested...\n");

		void *session_cls = SPDY_get_cls_from_session(session2);
		if(NULL == session_cls || strcmp(session_cls, SESSION_CLS))
		{
			printf("SPDY_get_cls_from_session failed\n");
			killchild();
		}
		printf("SPDY_set_cls_to_session tested...\n");
		printf("SPDY_get_cls_from_session tested...\n");

		void *request_cls = SPDY_get_cls_from_request(request);
		if(NULL == request_cls || strcmp(request_cls, REQUEST_CLS))
		{
			printf("SPDY_get_cls_from_request failed\n");
			killchild();
		}
		printf("SPDY_set_cls_to_request tested...\n");
		printf("SPDY_get_cls_from_request tested...\n");
	}

	SPDY_destroy_request(request);
	SPDY_destroy_response(response);
	free(cls);
}

void
standard_request_handler(void *cls,
						struct SPDY_Request * request,
						uint8_t priority,
                        const char *method,
                        const char *path,
                        const char *version,
                        const char *host,
                        const char *scheme,
						struct SPDY_NameValue * headers,
            bool more)
{
	(void)cls;
	(void)request;
	(void)priority;
	(void)host;
	(void)scheme;
	(void)headers;
	(void)method;
	(void)version;
	(void)more;

	struct SPDY_Response *response=NULL;
	char *cls_path = strdup(path);

	if(strcmp(path,"/main.css")==0)
	{
		char *request_cls = strdup(REQUEST_CLS);
		SPDY_set_cls_to_request(request,request_cls);
		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,CSS,strlen(CSS));
	}
	else
	{
		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,HTML,strlen(HTML));
	}

	if(NULL==response){
		fprintf(stdout,"no response obj\n");
		killchild();
	}

	if(SPDY_queue_response(request,response,true,false,&response_done_callback,cls_path)!=SPDY_YES)
	{
		fprintf(stdout,"queue\n");
		killchild();
	}
}

int
parentproc()
{
	int childstatus;
	unsigned long long timeoutlong=0;
	struct timeval timeout;
	int ret;
	fd_set read_fd_set;
	fd_set write_fd_set;
	fd_set except_fd_set;
	int maxfd = -1;
	struct SPDY_Daemon *daemon;

	daemon = SPDY_start_daemon(port,
								DATA_DIR "cert-and-key.pem",
								DATA_DIR "cert-and-key.pem",
								NULL,
								NULL,
								&standard_request_handler,
								NULL,
								NULL,
								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
								1800,
								SPDY_DAEMON_OPTION_END);

	if(NULL==daemon){
		printf("no daemon\n");
		return 1;
	}

	create_child();

	do
	{
		FD_ZERO(&read_fd_set);
		FD_ZERO(&write_fd_set);
		FD_ZERO(&except_fd_set);

		ret = SPDY_get_timeout(daemon, &timeoutlong);
		if(SPDY_NO == ret || timeoutlong > 1000)
		{
			timeout.tv_sec = 1;
      timeout.tv_usec = 0;
		}
		else
		{
			timeout.tv_sec = timeoutlong / 1000;
			timeout.tv_usec = (timeoutlong % 1000) * 1000;
		}

		maxfd = SPDY_get_fdset (daemon,
								&read_fd_set,
								&write_fd_set,
								&except_fd_set);

		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);

		switch(ret) {
			case -1:
				printf("select error: %i\n", errno);
				break;
			case 0:

				break;
			default:
				SPDY_run(daemon);

			break;
		}
	}
	while(waitpid(child,&childstatus,WNOHANG) != child);

	SPDY_stop_daemon(daemon);

	return WEXITSTATUS(childstatus);
}


int
main()
{
	port = get_port(13123);
	SPDY_init();

	int ret = parentproc();

	SPDY_deinit();

	return ret;
}