/*
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;
}