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