1748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 2748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat This file is part of libmicrospdy 3748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat Copyright Copyright (C) 2012 Andrey Uzunov 4748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 5748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat This program is free software: you can redistribute it and/or modify 6748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat it under the terms of the GNU General Public License as published by 7748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat the Free Software Foundation, either version 3 of the License, or 8748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (at your option) any later version. 9748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 10748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat This program is distributed in the hope that it will be useful, 11748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat but WITHOUT ANY WARRANTY; without even the implied warranty of 12748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat GNU General Public License for more details. 14748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 15748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat You should have received a copy of the GNU General Public License 16748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat along with this program. If not, see <http://www.gnu.org/licenses/>. 17748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat*/ 18748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 19748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/** 20748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @file request_response.c 21748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @brief tests receiving request and sending response. spdycli.c (spdylay) 22748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * code is reused here 23748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @author Andrey Uzunov 24748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @author Tatsuhiro Tsujikawa 25748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 26748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 27748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "platform.h" 28748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "microspdy.h" 29748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <sys/wait.h> 30748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "common.h" 31748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 32748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#define RESPONSE_BODY "<html><body><b>Hi, this is libmicrospdy!</b></body></html>" 33748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 34748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#define CLS "anything" 35748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 36748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratpid_t parent; 37748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratpid_t child; 38748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratchar *rcvbuf; 39748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint rcvbuf_c = 0; 40748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 41748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint session_closed_called = 0; 42748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 43748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid 44748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratkillchild(int pid, char *message) 45748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 46748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("%s\n",message); 47748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat kill(pid, SIGKILL); 48748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(1); 49748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 50748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 51748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid 52748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratkillparent(int pid, char *message) 53748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 54748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("%s\n",message); 55748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat kill(pid, SIGKILL); 56748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat _exit(1); 57748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 58748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 59748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 60748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/***** 61748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * start of code needed to utilize spdylay 62748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 63748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 64748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdint.h> 65748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdlib.h> 66748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <unistd.h> 67748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <fcntl.h> 68748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <sys/types.h> 69748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <sys/socket.h> 70748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <netdb.h> 71748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <netinet/in.h> 72748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <netinet/tcp.h> 73748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <poll.h> 74748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <signal.h> 75748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <stdio.h> 76748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <assert.h> 77748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 78748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <spdylay/spdylay.h> 79748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 80748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <openssl/ssl.h> 81748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <openssl/err.h> 82748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 83748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratenum { 84748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat IO_NONE, 85748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat WANT_READ, 86748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat WANT_WRITE 87748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}; 88748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 89748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct Connection { 90748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL *ssl; 91748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_session *session; 92748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it 93748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat needs more output; or IO_NONE. This is necessary because SSL/TLS 94748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat re-negotiation is possible at any time. Spdylay API offers 95748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat similar functions like spdylay_session_want_read() and 96748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_session_want_write() but they do not take into account 97748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL connection. */ 98748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int want_io; 99748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}; 100748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 101748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct Request { 102748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char *host; 103748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint16_t port; 104748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* In this program, path contains query component as well. */ 105748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char *path; 106748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* This is the concatenation of host and port with ":" in 107748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat between. */ 108748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char *hostport; 109748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Stream ID for this request. */ 110748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int32_t stream_id; 111748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* The gzip stream inflater for the compressed response. */ 112748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_gzip *inflater; 113748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}; 114748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 115748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstruct URI { 116748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *host; 117748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t hostlen; 118748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint16_t port; 119748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* In this program, path contains query component as well. */ 120748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *path; 121748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t pathlen; 122748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *hostport; 123748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t hostportlen; 124748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}; 125748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 126748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 127748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Returns copy of string |s| with the length |len|. The returned 128748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * string is NULL-terminated. 129748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 130748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic char* strcopy(const char *s, size_t len) 131748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 132748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char *dst; 133748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dst = malloc(len+1); 134748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if (NULL == dst) 135748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat abort (); 136748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat memcpy(dst, s, len); 137748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dst[len] = '\0'; 138748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return dst; 139748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 140748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 141748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 142748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Prints error message |msg| and exit. 143748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 144748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void die(const char *msg) 145748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 146748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stderr, "FATAL: %s\n", msg); 147748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(EXIT_FAILURE); 148748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 149748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 150748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 151748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Prints error containing the function name |func| and message |msg| 152748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * and exit. 153748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 154748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void dief(const char *func, const char *msg) 155748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 156748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stderr, "FATAL: %s: %s\n", func, msg); 157748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(EXIT_FAILURE); 158748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 159748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 160748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 161748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Prints error containing the function name |func| and error code 162748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * |error_code| and exit. 163748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 164748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void diec(const char *func, int error_code) 165748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 166748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code, 167748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_strerror(error_code)); 168748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(EXIT_FAILURE); 169748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 170748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 171748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 172748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Check response is content-encoding: gzip. We need this because SPDY 173748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * client is required to support gzip. 174748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 175748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void check_gzip(struct Request *req, char **nv) 176748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 177748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int gzip = 0; 178748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t i; 179748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = 0; nv[i]; i += 2) { 180748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strcmp("content-encoding", nv[i]) == 0) { 181748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat gzip = strcmp("gzip", nv[i+1]) == 0; 182748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 183748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 184748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 185748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(gzip) { 186748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 187748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req->inflater) { 188748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return; 189748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 190748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_gzip_inflate_new(&req->inflater); 191748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 192748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat die("Can't allocate inflate stream."); 193748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 194748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 195748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 196748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 197748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 198748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The implementation of spdylay_send_callback type. Here we write 199748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * |data| with size |length| to the network and return the number of 200748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * bytes actually written. See the documentation of 201748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * spdylay_send_callback for the details. 202748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 203748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic ssize_t send_callback(spdylay_session *session, 204748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const uint8_t *data, size_t length, int flags, 205748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *user_data) 206748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 207748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)session; 208748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)flags; 209748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 210748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Connection *connection; 211748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ssize_t rv; 212748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection = (struct Connection*)user_data; 213748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io = IO_NONE; 214748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ERR_clear_error(); 215748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SSL_write(connection->ssl, data, length); 216748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv < 0) { 217748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int err = SSL_get_error(connection->ssl, rv); 218748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { 219748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io = (err == SSL_ERROR_WANT_READ ? 220748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat WANT_READ : WANT_WRITE); 221748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SPDYLAY_ERR_WOULDBLOCK; 222748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 223748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SPDYLAY_ERR_CALLBACK_FAILURE; 224748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 225748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 226748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return rv; 227748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 228748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 229748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 230748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The implementation of spdylay_recv_callback type. Here we read data 231748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * from the network and write them in |buf|. The capacity of |buf| is 232748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * |length| bytes. Returns the number of bytes stored in |buf|. See 233748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * the documentation of spdylay_recv_callback for the details. 234748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 235748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic ssize_t recv_callback(spdylay_session *session, 236748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint8_t *buf, size_t length, int flags, 237748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *user_data) 238748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 239748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)session; 240748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)flags; 241748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 242748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Connection *connection; 243748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ssize_t rv; 244748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection = (struct Connection*)user_data; 245748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io = IO_NONE; 246748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ERR_clear_error(); 247748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SSL_read(connection->ssl, buf, length); 248748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv < 0) { 249748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int err = SSL_get_error(connection->ssl, rv); 250748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { 251748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io = (err == SSL_ERROR_WANT_READ ? 252748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat WANT_READ : WANT_WRITE); 253748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SPDYLAY_ERR_WOULDBLOCK; 254748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 255748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SPDYLAY_ERR_CALLBACK_FAILURE; 256748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 257748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else if(rv == 0) { 258748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SPDYLAY_ERR_EOF; 259748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 260748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return rv; 261748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 262748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 263748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 264748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The implementation of spdylay_before_ctrl_send_callback type. We 265748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * use this function to get stream ID of the request. This is because 266748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * stream ID is not known when we submit the request 267748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * (spdylay_submit_request). 268748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 269748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void before_ctrl_send_callback(spdylay_session *session, 270748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame_type type, 271748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame *frame, 272748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *user_data) 273748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 274748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)user_data; 275748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 276748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(type == SPDYLAY_SYN_STREAM) { 277748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Request *req; 278748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int stream_id = frame->syn_stream.stream_id; 279748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req = spdylay_session_get_stream_user_data(session, stream_id); 280748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req && req->stream_id == -1) { 281748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->stream_id = stream_id; 282748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("[INFO] Stream ID = %d\n", stream_id); 283748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 284748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 285748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 286748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 287748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void on_ctrl_send_callback(spdylay_session *session, 288748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame_type type, 289748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame *frame, void *user_data) 290748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 291748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)user_data; 292748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 293748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char **nv; 294748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *name = NULL; 295748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int32_t stream_id; 296748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t i; 297748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat switch(type) { 298748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat case SPDYLAY_SYN_STREAM: 299748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv = frame->syn_stream.nv; 300748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat name = "SYN_STREAM"; 301748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat stream_id = frame->syn_stream.stream_id; 302748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 303748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat default: 304748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 305748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 306748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(name && spdylay_session_get_stream_user_data(session, stream_id)) { 307748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("[INFO] C ----------------------------> S (%s)\n", name); 308748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = 0; nv[i]; i += 2) { 309748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf(" %s: %s\n", nv[i], nv[i+1]); 310748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 311748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 312748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 313748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 314748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void on_ctrl_recv_callback(spdylay_session *session, 315748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame_type type, 316748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_frame *frame, void *user_data) 317748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 318748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)user_data; 319748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 320748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Request *req; 321748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char **nv; 322748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *name = NULL; 323748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int32_t stream_id; 324748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t i; 325748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat switch(type) { 326748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat case SPDYLAY_SYN_REPLY: 327748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv = frame->syn_reply.nv; 328748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat name = "SYN_REPLY"; 329748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat stream_id = frame->syn_reply.stream_id; 330748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 331748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat case SPDYLAY_HEADERS: 332748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv = frame->headers.nv; 333748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat name = "HEADERS"; 334748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat stream_id = frame->headers.stream_id; 335748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 336748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat default: 337748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 338748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 339748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(!name) { 340748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return; 341748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 342748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req = spdylay_session_get_stream_user_data(session, stream_id); 343748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req) { 344748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat check_gzip(req, nv); 345748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("[INFO] C <---------------------------- S (%s)\n", name); 346748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = 0; nv[i]; i += 2) { 347748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf(" %s: %s\n", nv[i], nv[i+1]); 348748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 349748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 350748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 351748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 352748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 353748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The implementation of spdylay_on_stream_close_callback type. We use 354748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * this function to know the response is fully received. Since we just 355748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * fetch 1 resource in this program, after reception of the response, 356748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * we submit GOAWAY and close the session. 357748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 358748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void on_stream_close_callback(spdylay_session *session, 359748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int32_t stream_id, 360748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_status_code status_code, 361748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *user_data) 362748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 363748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)user_data; 364748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)status_code; 365748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 366748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Request *req; 367748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req = spdylay_session_get_stream_user_data(session, stream_id); 368748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req) { 369748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 370748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK); 371748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 372748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat diec("spdylay_submit_goaway", rv); 373748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 374748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 375748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 376748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 377748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#define MAX_OUTLEN 4096 378748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 379748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 380748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * The implementation of spdylay_on_data_chunk_recv_callback type. We 381748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * use this function to print the received response body. 382748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 383748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags, 384748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int32_t stream_id, 385748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const uint8_t *data, size_t len, 386748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *user_data) 387748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 388748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)user_data; 389748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)flags; 390748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 391748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Request *req; 392748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req = spdylay_session_get_stream_user_data(session, stream_id); 393748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req) { 394748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("[INFO] C <---------------------------- S (DATA)\n"); 395748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf(" %lu bytes\n", (unsigned long int)len); 396748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(req->inflater) { 397748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while(len > 0) { 398748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint8_t out[MAX_OUTLEN]; 399748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t outlen = MAX_OUTLEN; 400748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t tlen = len; 401748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 402748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen); 403748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv == -1) { 404748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); 405748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 406748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 407748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fwrite(out, 1, outlen, stdout); 408748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat data += tlen; 409748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat len -= tlen; 410748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 411748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 412748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* TODO add support gzip */ 413748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fwrite(data, 1, len, stdout); 414748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 415748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat //check if the data is correct 416748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat //if(strcmp(RESPONSE_BODY, data) != 0) 417748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat //killparent(parent, "\nreceived data is not the same"); 418748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(len + rcvbuf_c > strlen(RESPONSE_BODY)) 419748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killparent(parent, "\nreceived data is not the same"); 420748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 421748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat strcpy(rcvbuf + rcvbuf_c,(char*)data); 422748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rcvbuf_c+=len; 423748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 424748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("\n"); 425748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 426748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 427748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 428748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 429748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Setup callback functions. Spdylay API offers many callback 430748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * functions, but most of them are optional. The send_callback is 431748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * always required. Since we use spdylay_session_recv(), the 432748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * recv_callback is also required. 433748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 434748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void setup_spdylay_callbacks(spdylay_session_callbacks *callbacks) 435748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 436748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat memset(callbacks, 0, sizeof(spdylay_session_callbacks)); 437748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->send_callback = send_callback; 438748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->recv_callback = recv_callback; 439748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->before_ctrl_send_callback = before_ctrl_send_callback; 440748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->on_ctrl_send_callback = on_ctrl_send_callback; 441748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback; 442748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->on_stream_close_callback = on_stream_close_callback; 443748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback; 444748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 445748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 446748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 447748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Callback function for SSL/TLS NPN. Since this program only supports 448748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * SPDY protocol, if server does not offer SPDY protocol the Spdylay 449748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * library supports, we terminate program. 450748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 451748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic int select_next_proto_cb(SSL* ssl, 452748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat unsigned char **out, unsigned char *outlen, 453748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const unsigned char *in, unsigned int inlen, 454748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat void *arg) 455748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 456748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)ssl; 457748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 458748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 459748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint16_t *spdy_proto_version; 460748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* spdylay_select_next_protocol() selects SPDY protocol version the 461748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat Spdylay library supports. */ 462748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_select_next_protocol(out, outlen, in, inlen); 463748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv <= 0) { 464748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat die("Server did not advertise spdy/2 or spdy/3 protocol."); 465748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 466748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdy_proto_version = (uint16_t*)arg; 467748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat *spdy_proto_version = rv; 468748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return SSL_TLSEXT_ERR_OK; 469748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 470748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 471748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 472748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Setup SSL context. We pass |spdy_proto_version| to get negotiated 473748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * SPDY protocol version in NPN callback. 474748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 475748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version) 476748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 477748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Disable SSLv2 and enable all workarounds for buggy servers */ 478748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2); 479748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); 480748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); 481748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Set NPN callback */ 482748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, 483748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdy_proto_version); 484748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 485748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 486748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void ssl_handshake(SSL *ssl, int fd) 487748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 488748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 489748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(SSL_set_fd(ssl, fd) == 0) { 490748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL)); 491748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 492748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ERR_clear_error(); 493748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = SSL_connect(ssl); 494748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv <= 0) { 495748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL)); 496748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 497748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 498748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 499748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 500748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Connects to the host |host| and port |port|. This function returns 501748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * the file descriptor of the client socket. 502748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 503748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic int connect_to(const char *host, uint16_t port) 504748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 505748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct addrinfo hints; 506748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int fd = -1; 507748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 508748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char service[NI_MAXSERV]; 509748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct addrinfo *res, *rp; 510748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat snprintf(service, sizeof(service), "%u", port); 511748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat memset(&hints, 0, sizeof(struct addrinfo)); 512748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat hints.ai_family = AF_UNSPEC; 513748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat hints.ai_socktype = SOCK_STREAM; 514748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = getaddrinfo(host, service, &hints, &res); 515748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 516748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("getaddrinfo", gai_strerror(rv)); 517748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 518748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(rp = res; rp; rp = rp->ai_next) { 519748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 520748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(fd == -1) { 521748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat continue; 522748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 523748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && 524748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat errno == EINTR); 525748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv == 0) { 526748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 527748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 528748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat close(fd); 529748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd = -1; 530748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 531748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat freeaddrinfo(res); 532748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return fd; 533748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 534748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 535748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void make_non_block(int fd) 536748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 537748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int flags, rv; 538748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR); 539748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(flags == -1) { 540748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("fcntl", strerror(errno)); 541748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 542748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR); 543748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv == -1) { 544748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("fcntl", strerror(errno)); 545748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 546748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 547748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 548748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 549748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Setting TCP_NODELAY is not mandatory for the SPDY protocol. 550748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 551748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void set_tcp_nodelay(int fd) 552748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 553748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int val = 1; 554748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 555748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); 556748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv == -1) { 557748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("setsockopt", strerror(errno)); 558748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 559748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 560748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 561748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 562748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Update |pollfd| based on the state of |connection|. 563748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 564748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void ctl_poll(struct pollfd *pollfd, struct Connection *connection) 565748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 566748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat pollfd->events = 0; 567748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(spdylay_session_want_read(connection->session) || 568748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io == WANT_READ) { 569748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat pollfd->events |= POLLIN; 570748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 571748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(spdylay_session_want_write(connection->session) || 572748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection->want_io == WANT_WRITE) { 573748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat pollfd->events |= POLLOUT; 574748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 575748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 576748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 577748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 578748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Submits the request |req| to the connection |connection|. This 579748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * function does not send packets; just append the request to the 580748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * internal queue in |connection->session|. 581748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 582748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void submit_request(struct Connection *connection, struct Request *req) 583748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 584748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int pri = 0; 585748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 586748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *nv[15]; 587748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* We always use SPDY/3 style header even if the negotiated protocol 588748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat version is SPDY/2. The library translates the header name as 589748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat necessary. Make sure that the last item is NULL! */ 590748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[0] = ":method"; nv[1] = "GET"; 591748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[2] = ":path"; nv[3] = req->path; 592748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[4] = ":version"; nv[5] = "HTTP/1.1"; 593748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[6] = ":scheme"; nv[7] = "https"; 594748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[8] = ":host"; nv[9] = req->hostport; 595748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[10] = "accept"; nv[11] = "*/*"; 596748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION; 597748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nv[14] = NULL; 598748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_submit_request(connection->session, pri, nv, NULL, req); 599748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 600748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat diec("spdylay_submit_request", rv); 601748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 602748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 603748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 604748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 605748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Performs the network I/O. 606748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 607748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void exec_io(struct Connection *connection) 608748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 609748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 610748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_session_recv(connection->session); 611748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 612748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat diec("spdylay_session_recv", rv); 613748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 614748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_session_send(connection->session); 615748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 616748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat diec("spdylay_session_send", rv); 617748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 618748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 619748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 620748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void request_init(struct Request *req, const struct URI *uri) 621748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 622748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->host = strcopy(uri->host, uri->hostlen); 623748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->port = uri->port; 624748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->path = strcopy(uri->path, uri->pathlen); 625748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->hostport = strcopy(uri->hostport, uri->hostportlen); 626748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->stream_id = -1; 627748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat req->inflater = NULL; 628748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 629748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 630748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void request_free(struct Request *req) 631748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 632748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat free(req->host); 633748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat free(req->path); 634748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat free(req->hostport); 635748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_gzip_inflate_del(req->inflater); 636748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 637748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 638748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/* 639748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * Fetches the resource denoted by |uri|. 640748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 641748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic void fetch_uri(const struct URI *uri) 642748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 643748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_session_callbacks callbacks; 644748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int fd; 645748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX *ssl_ctx; 646748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL *ssl; 647748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Request req; 648748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct Connection connection; 649748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 650748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat nfds_t npollfds = 1; 651748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct pollfd pollfds[1]; 652748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint16_t spdy_proto_version; 653748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 654748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat request_init(&req, uri); 655748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 656748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat setup_spdylay_callbacks(&callbacks); 657748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 658748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Establish connection and setup SSL */ 659748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd = connect_to(req.host, req.port); 660748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if (-1 == fd) 661748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat abort (); 662748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ssl_ctx = SSL_CTX_new(SSLv23_client_method()); 663748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(ssl_ctx == NULL) { 664748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL)); 665748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 666748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat init_ssl_ctx(ssl_ctx, &spdy_proto_version); 667748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ssl = SSL_new(ssl_ctx); 668748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(ssl == NULL) { 669748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); 670748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 671748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* To simplify the program, we perform SSL/TLS handshake in blocking 672748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat I/O. */ 673748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ssl_handshake(ssl, fd); 674748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 675748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection.ssl = ssl; 676748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat connection.want_io = IO_NONE; 677748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 678748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Here make file descriptor non-block */ 679748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat make_non_block(fd); 680748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat set_tcp_nodelay(fd); 681748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 682748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version); 683748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = spdylay_session_client_new(&connection.session, spdy_proto_version, 684748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat &callbacks, &connection); 685748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 686748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat diec("spdylay_session_client_new", rv); 687748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 688748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 689748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Submit the HTTP request to the outbound queue. */ 690748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat submit_request(&connection, &req); 691748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 692748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat pollfds[0].fd = fd; 693748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ctl_poll(pollfds, &connection); 694748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 695748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Event loop */ 696748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while(spdylay_session_want_read(connection.session) || 697748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_session_want_write(connection.session)) { 698748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int nfds = poll(pollfds, npollfds, -1); 699748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(nfds == -1) { 700748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat dief("poll", strerror(errno)); 701748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 702748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(pollfds[0].revents & (POLLIN | POLLOUT)) { 703748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exec_io(&connection); 704748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 705748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { 706748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat die("Connection error"); 707748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 708748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ctl_poll(pollfds, &connection); 709748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 710748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 711748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Resource cleanup */ 712748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat spdylay_session_del(connection.session); 713748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_shutdown(ssl); 714748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_free(ssl); 715748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_CTX_free(ssl_ctx); 716748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat shutdown(fd, SHUT_WR); 717748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat close(fd); 718748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat request_free(&req); 719748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 720748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 721748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstatic int parse_uri(struct URI *res, const char *uri) 722748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 723748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* We only interested in https */ 724748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat size_t len, i, offset; 725748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat memset(res, 0, sizeof(struct URI)); 726748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat len = strlen(uri); 727748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(len < 9 || memcmp("https://", uri, 8) != 0) { 728748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return -1; 729748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 730748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat offset = 8; 731748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->host = res->hostport = &uri[offset]; 732748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->hostlen = 0; 733748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(uri[offset] == '[') { 734748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* IPv6 literal address */ 735748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ++offset; 736748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ++res->host; 737748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = offset; i < len; ++i) { 738748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(uri[i] == ']') { 739748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->hostlen = i-offset; 740748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat offset = i+1; 741748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 742748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 743748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 744748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 745748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char delims[] = ":/?#"; 746748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = offset; i < len; ++i) { 747748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strchr(delims, uri[i]) != NULL) { 748748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 749748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 750748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 751748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->hostlen = i-offset; 752748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat offset = i; 753748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 754748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(res->hostlen == 0) { 755748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return -1; 756748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 757748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* Assuming https */ 758748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->port = 443; 759748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(offset < len) { 760748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(uri[offset] == ':') { 761748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat /* port */ 762748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char delims[] = "/?#"; 763748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int port = 0; 764748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ++offset; 765748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = offset; i < len; ++i) { 766748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strchr(delims, uri[i]) != NULL) { 767748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 768748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 769748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if('0' <= uri[i] && uri[i] <= '9') { 770748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat port *= 10; 771748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat port += uri[i]-'0'; 772748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(port > 65535) { 773748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return -1; 774748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 775748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 776748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return -1; 777748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 778748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 779748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(port == 0) { 780748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return -1; 781748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 782748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat offset = i; 783748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->port = port; 784748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 785748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 786748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->hostportlen = uri+offset-res->host; 787748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat for(i = offset; i < len; ++i) { 788748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(uri[i] == '#') { 789748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 790748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 791748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 792748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(i-offset == 0) { 793748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->path = "/"; 794748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->pathlen = 1; 795748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } else { 796748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->path = &uri[offset]; 797748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat res->pathlen = i-offset; 798748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 799748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return 0; 800748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 801748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 802748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 803748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/***** 804748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * end of code needed to utilize spdylay 805748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 806748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 807748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 808748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/***** 809748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * start of code needed to utilize microspdy 810748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 811748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 812748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 813748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid 814748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratstandard_request_handler(void *cls, 815748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct SPDY_Request * request, 816748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat uint8_t priority, 817748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *method, 818748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *path, 819748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *version, 820748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *host, 821748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat const char *scheme, 822748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct SPDY_NameValue * headers, 823748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat bool more) 824748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 825748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)cls; 826748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)request; 827748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)priority; 828748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)host; 829748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)scheme; 830748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)headers; 831748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)method; 832748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat (void)version; 833748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 834748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct SPDY_Response *response=NULL; 835748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 836748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strcmp(CLS,cls)!=0) 837748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 838748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killchild(child,"wrong cls"); 839748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 840748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 841748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(false != more){ 842748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stdout,"more has wrong value\n"); 843748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(5); 844748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 845748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 846748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,RESPONSE_BODY,strlen(RESPONSE_BODY)); 847748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 848748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(NULL==response){ 849748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stdout,"no response obj\n"); 850748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(3); 851748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 852748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 853748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(SPDY_queue_response(request,response,true,false,NULL,(void*)strdup(path))!=SPDY_YES) 854748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 855748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stdout,"queue\n"); 856748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(4); 857748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 858748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 859748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 860748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid 861748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratsession_closed_handler (void *cls, 862748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct SPDY_Session * session, 863748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int by_client) 864748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 865748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("session_closed_handler called\n"); 866748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 867748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strcmp(CLS,cls)!=0) 868748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 869748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killchild(child,"wrong cls"); 870748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 871748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 872748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(SPDY_YES != by_client) 873748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 874748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat //killchild(child,"wrong by_client"); 875748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("session closed by server\n"); 876748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 877748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat else 878748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 879748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("session closed by client\n"); 880748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 881748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 882748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(NULL == session) 883748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 884748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killchild(child,"session is NULL"); 885748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 886748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 887748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat session_closed_called = 1; 888748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 889748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 890748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 891748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/***** 892748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * end of code needed to utilize microspdy 893748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */ 894748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 895748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat//child process 896748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid 897748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratchildproc(int port) 898748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 899748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct URI uri; 900748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct sigaction act; 901748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int rv; 902748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat char *uristr; 903748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 904748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat memset(&act, 0, sizeof(struct sigaction)); 905748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat act.sa_handler = SIG_IGN; 906748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat sigaction(SIGPIPE, &act, 0); 907748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 908748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat asprintf(&uristr, "https://127.0.0.1:%i/",port); 909748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(NULL == (rcvbuf = malloc(strlen(RESPONSE_BODY)+1))) 910748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killparent(parent,"no memory"); 911748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 912748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_load_error_strings(); 913748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SSL_library_init(); 914748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 915748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat rv = parse_uri(&uri, uristr); 916748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(rv != 0) { 917748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killparent(parent,"parse_uri failed"); 918748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 919748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fetch_uri(&uri); 920748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 921748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(strcmp(rcvbuf, RESPONSE_BODY)) 922748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killparent(parent,"received data is different"); 923748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 924748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 925748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat//parent proc 926748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint 927748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratparentproc( int port) 928748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 929748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int childstatus; 930748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat unsigned long long timeoutlong=0; 931748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct timeval timeout; 932748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int ret; 933748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd_set read_fd_set; 934748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd_set write_fd_set; 935748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fd_set except_fd_set; 936748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int maxfd = -1; 937748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat struct SPDY_Daemon *daemon; 938748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 939748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SPDY_init(); 940748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 941748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat daemon = SPDY_start_daemon(port, 942748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat DATA_DIR "cert-and-key.pem", 943748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat DATA_DIR "cert-and-key.pem", 944748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat NULL,&session_closed_handler,&standard_request_handler,NULL,CLS,SPDY_DAEMON_OPTION_END); 945748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 946748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(NULL==daemon){ 947748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("no daemon\n"); 948748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return 1; 949748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 950748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 951748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat do 952748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 953748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat FD_ZERO(&read_fd_set); 954748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat FD_ZERO(&write_fd_set); 955748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat FD_ZERO(&except_fd_set); 956748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 957748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ret = SPDY_get_timeout(daemon, &timeoutlong); 958748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(SPDY_NO == ret || timeoutlong > 1000) 959748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 960748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat timeout.tv_sec = 1; 961748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat timeout.tv_usec = 0; 962748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 963748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat else 964748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 965748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat timeout.tv_sec = timeoutlong / 1000; 966748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat timeout.tv_usec = (timeoutlong % 1000) * 1000; 967748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 968748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 969748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat maxfd = SPDY_get_fdset (daemon, 970748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat &read_fd_set, 971748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat &write_fd_set, 972748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat &except_fd_set); 973748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 974748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout); 975748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 976748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat switch(ret) { 977748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat case -1: 978748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat printf("select error: %i\n", errno); 979748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat killchild(child, "select error"); 980748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 981748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat case 0: 982748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 983748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 984748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat default: 985748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SPDY_run(daemon); 986748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 987748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat break; 988748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 989748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 990748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat while(waitpid(child,&childstatus,WNOHANG) != child); 991748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 992748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat //give chance to the client to close socket and handle this in run 993748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat usleep(100000); 994748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SPDY_run(daemon); 995748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 996748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SPDY_stop_daemon(daemon); 997748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 998748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat SPDY_deinit(); 999748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 1000748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return WEXITSTATUS(childstatus); 1001748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 1002748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 1003748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint main() 1004748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{ 1005748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int port = get_port(12123); 1006748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat parent = getpid(); 1007748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 1008748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat child = fork(); 1009748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if (child == -1) 1010748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 1011748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat fprintf(stderr, "can't fork, error %d\n", errno); 1012748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(EXIT_FAILURE); 1013748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 1014748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat 1015748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if (child == 0) 1016748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 1017748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat childproc(port); 1018748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat _exit(0); 1019748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 1020748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat else 1021748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat { 1022748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat int ret = parentproc(port); 1023748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat if(1 == session_closed_called && 0 == ret) 1024748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(0); 1025748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat else 1026748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat exit(ret ? ret : 21); 1027748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat } 1028748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat return 1; 1029748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat} 1030