C++程序  |  488行  |  10.64 KB

/*
    This file is part of libmicrospdy
    Copyright Copyright (C) 2012 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 event_loop.c
 * @brief  shows how to use the daemon. THIS IS MAINLY A TEST AND DEBUG
 * 		 PROGRAM
 * @author Andrey Uzunov
 */

#include "platform.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "microspdy.h"
#include <sys/time.h>
#include <time.h>
#ifndef MINGW
#include <arpa/inet.h>
#endif
//#include "../framinglayer/structures.h"
//#include "../applicationlayer/alstructures.h"

static int run = 1;

static int run2 = 1;

	
static uint64_t loops;

static time_t start;


static void
new_session_callback (void *cls,
						struct SPDY_Session * session)
{
  (void)cls;
  
	char ipstr[1024];
		
	struct sockaddr *addr;
	socklen_t addr_len = SPDY_get_remote_addr(session, &addr);	
	
	if(!addr_len)
	{
		printf("SPDY_get_remote_addr");
		abort();
	}
	
	if(AF_INET == addr->sa_family)
	{
		struct sockaddr_in * addr4 = (struct sockaddr_in *) addr;
		if(NULL == inet_ntop(AF_INET, &(addr4->sin_addr), ipstr, sizeof(ipstr)))
		{
			printf("inet_ntop");
			abort();
		}
		printf("New connection from: %s:%i\n", ipstr, ntohs(addr4->sin_port));
		
	}
	else if(AF_INET6 == addr->sa_family)
	{
		struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *) addr;
		if(NULL == inet_ntop(AF_INET6, &(addr6->sin6_addr), ipstr, sizeof(ipstr)))
		{
			printf("inet_ntop");
			abort();
		}
		printf("New connection from: %s:%i\n", ipstr, ntohs(addr6->sin6_port));
		
	}
}


static void
session_closed_handler (void *cls,
						struct SPDY_Session * session,
						int by_client)
{
  (void)cls;
  (void)session;
  
	//printf("session_closed_handler called\n");
	
	if(SPDY_YES != by_client)
	{
		//killchild(child,"wrong by_client");
		printf("session closed by server\n");
	}
	else
	{
		printf("session closed by client\n");
	}
	
	//session_closed_called = 1;
}


static void
response_done_callback(void *cls,
						struct SPDY_Response *response,
						struct SPDY_Request *request,
						enum SPDY_RESPONSE_RESULT status,
						bool streamopened)
{
	(void)streamopened;
	if(strcmp(cls, "/close (daemon1)") == 0)
		run = 0;
	else {
		if(strcmp(cls, "/close (daemon2)") == 0) run2 = 0;
		loops = 0;
		start = time(NULL);
	}
	if(SPDY_RESPONSE_RESULT_SUCCESS != status)
	{
		printf("not sent frame cause %i", status);
	}
	printf("answer for %s was sent\n", (char*)cls);
	//printf("raw sent headers %s\n", (char *)(response->headers)+8);
	
	SPDY_destroy_request(request);
	SPDY_destroy_response(response);
	free(cls);
}

/*
static int
print_headers (void *cls,
                           const char *name, const char *value)
{
	(void)cls;
	printf("%s: %s\n",name,value);
	return SPDY_YES;
}
 */
 
 
/*       
void
new_request_cb (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)
{
	(void)cls;
	(void)request;
	printf("Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
	SPDY_name_value_iterate(headers, &print_headers, NULL);
}
*/


static int
append_headers_to_data (void *cls,
                           const char *name, const char * const *value, int num_values)
{
	char **data = cls;
	void *tofree = *data;
	int i;
	
	if(num_values)
	for(i=0;i<num_values;++i)
	{
	asprintf(data,"%s%s: %s\n", *data,name,value[i]);
	}
	else
	asprintf(data,"%s%s: \n", *data,name);
	
	free(tofree);
	return SPDY_YES;
}  


static 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)more;
  
	char *html;
	char *data;
	struct SPDY_Response *response=NULL;
	
	printf("received request for '%s %s %s'\n", method, path, version);
	if(strcmp(path,"/main.css")==0)
	{
		if(NULL != cls)
			asprintf(&html,"body{color:green;}");
		else
			asprintf(&html,"body{color:red;}");
				
		//struct SPDY_NameValue *headers=SPDY_name_value_create();
		//SPDY_name_value_add(headers,"content-type","text/css");
		
		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
		free(html);
	}
	else
	{
		asprintf(&data,"Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
		
		SPDY_name_value_iterate(headers, &append_headers_to_data, &data);
		
		if(strcmp(path,"/close")==0)
		{
			asprintf(&html,"<html>"
		"<body><b>Closing now!<br>This is an answer to the following "
		"request:</b><br><br><pre>%s</pre></body></html>",data);
		}
		else
		{
			asprintf(&html,"<html><link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />"
		"<body><b>This is an answer to the following "
		"request:</b><br><br><pre>%s</pre></body></html>",data);
		}
		
		free(data);
		
		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
		free(html);
	}
	
	if(NULL==response){
		fprintf(stdout,"no response obj\n");
		abort();
	}
	
	char *pathcls;
	asprintf(&pathcls, "%s (daemon%i)",path,NULL==cls ? 1 : 2);
	if(SPDY_queue_response(request,response,true,false,&response_done_callback,pathcls)!=SPDY_YES)
	{
		fprintf(stdout,"queue\n");
		abort();
	}
}


static int
new_post_data_cb (void * cls,
					 struct SPDY_Request *request,
					 const void * buf,
					 size_t size,
					 bool more)
{
  (void)cls;
  (void)request;
  (void)more;
  
	printf("DATA:\n===============================\n");
  write(0, buf, size);
	printf("\n===============================\n");
  return SPDY_YES;
}


static void 
sig_handler(int signo)
{
  (void)signo;
  
  printf("received signal\n");
}


int
main (int argc, char *const *argv)
{	
	if(argc != 2) return 1;
	
	#ifndef MINGW
	if (signal(SIGPIPE, sig_handler) == SIG_ERR)
		printf("\ncan't catch SIGPIPE\n");
	#endif
	
	SPDY_init();
	
	/*
  struct sockaddr_in addr4;
	struct in_addr inaddr4;
	inaddr4.s_addr = htonl(INADDR_ANY);
	addr4.sin_family = AF_INET;
	addr4.sin_addr = inaddr4;
	addr4.sin_port = htons(atoi(argv[1]));
	*/
  
	struct SPDY_Daemon *daemon = SPDY_start_daemon(atoi(argv[1]),
	 DATA_DIR "cert-and-key.pem",
	 DATA_DIR "cert-and-key.pem",
	&new_session_callback,&session_closed_handler,&standard_request_handler,&new_post_data_cb,NULL,
	SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 10,
	//SPDY_DAEMON_OPTION_SOCK_ADDR,  (struct sockaddr *)&addr4,
	SPDY_DAEMON_OPTION_END);
	
	if(NULL==daemon){
		printf("no daemon\n");
		return 1;
	}
	
  /*
	struct sockaddr_in6 addr6;
	addr6.sin6_family = AF_INET6;
	addr6.sin6_addr = in6addr_any;
	addr6.sin6_port = htons(atoi(argv[1]) + 1);
	*/
  
	struct SPDY_Daemon *daemon2 = SPDY_start_daemon(atoi(argv[1]) + 1,
	 DATA_DIR "cert-and-key.pem",
	 DATA_DIR "cert-and-key.pem",
	&new_session_callback,NULL,&standard_request_handler,&new_post_data_cb,&main,
	//SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 0,
	//SPDY_DAEMON_OPTION_SOCK_ADDR,  (struct sockaddr *)&addr6,
	//SPDY_DAEMON_OPTION_FLAGS, SPDY_DAEMON_FLAG_ONLY_IPV6,
	SPDY_DAEMON_OPTION_END);
	
	if(NULL==daemon2){
		printf("no daemon\n");
		return 1;
	}
	
	do
	{
	unsigned long long timeoutlong=0;
	struct timeval timeout;
	volatile int rc; /* select() return code */ 
	volatile int ret;

	fd_set read_fd_set;
	fd_set write_fd_set;
	fd_set except_fd_set;
	int maxfd = -1;

	if(run && daemon != NULL)
	{
		loops++;
		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;
		}
    
		printf("ret=%i; timeoutlong=%llu; sec=%llu; usec=%llu\n", ret, timeoutlong, (long long unsigned)timeout.tv_sec, (long long unsigned)timeout.tv_usec);
		//raise(SIGINT);

		/* get file descriptors from the transfers */ 
		maxfd = SPDY_get_fdset (daemon,
		&read_fd_set,
		&write_fd_set, 
		&except_fd_set);

//struct timeval ts1,ts2;
    //gettimeofday(&ts1, NULL);
		rc = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    //gettimeofday(&ts2, NULL);
    printf("rc %i\n",rc);
   // printf("time for select %i\n",ts2.tv_usec - ts1.tv_usec);
   // printf("%i %i %i %i\n",ts1.tv_sec, ts1.tv_usec,ts2.tv_sec, ts2.tv_usec);

		switch(rc) {
			case -1:
				/* select error */ 
				break;
			case 0:

				break;
			default:
				SPDY_run(daemon);

			break;
		}
	}
	else if(daemon != NULL){
	
	printf("%lu loops in %llu secs\n", loops, (long long unsigned)(time(NULL) - start));
		SPDY_stop_daemon(daemon);
		daemon=NULL;
	}

	if(run2)
	{
		FD_ZERO(&read_fd_set);
		FD_ZERO(&write_fd_set);
		FD_ZERO(&except_fd_set);

		ret = SPDY_get_timeout(daemon2, &timeoutlong);
		//printf("tout %i\n",timeoutlong);
		if(SPDY_NO == ret || timeoutlong > 1)
		{ 
			//do sth else
			//sleep(1);

			//try new connection
			timeout.tv_sec = 1;
			timeout.tv_usec = 0;
		}
		else
		{
			timeout.tv_sec = timeoutlong;
			timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
		}

		//printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret, timeoutlong, timeout.tv_sec, timeout.tv_usec);
		//raise(SIGINT);

		/* get file descriptors from the transfers */ 
		maxfd = SPDY_get_fdset (daemon2,
		&read_fd_set,
		&write_fd_set, 
		&except_fd_set);

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

		switch(rc) {
			case -1:
				/* select error */ 
				break;
			case 0:

				break;
			default:
				SPDY_run(daemon2);

				break;
		}
	}
	else if(daemon2 != NULL){
		SPDY_stop_daemon(daemon2);
		daemon2=NULL;
	}
	}
	while(run || run2);

	if(daemon != NULL){
		SPDY_stop_daemon(daemon);
	}
	if(daemon2 != NULL){
		SPDY_stop_daemon(daemon2);
	}
	
	SPDY_deinit();
	
	return 0;
}