aboutsummaryrefslogtreecommitdiff
path: root/src/examples/spdy_event_loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples/spdy_event_loop.c')
-rw-r--r--src/examples/spdy_event_loop.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/src/examples/spdy_event_loop.c b/src/examples/spdy_event_loop.c
new file mode 100644
index 00000000..6b7192c3
--- /dev/null
+++ b/src/examples/spdy_event_loop.c
@@ -0,0 +1,487 @@
+/*
+ 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;
+}
+