Home | History | Annotate | Download | only in testspdy
      1 /*
      2     This file is part of libmicrospdy
      3     Copyright Copyright (C) 2012 Andrey Uzunov
      4 
      5     This program is free software: you can redistribute it and/or modify
      6     it under the terms of the GNU General Public License as published by
      7     the Free Software Foundation, either version 3 of the License, or
      8     (at your option) any later version.
      9 
     10     This program is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13     GNU General Public License for more details.
     14 
     15     You should have received a copy of the GNU General Public License
     16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 
     19 /**
     20  * @file request_response.c
     21  * @brief  tests new connection callback. spdycli.c
     22  * 			code is reused here
     23  * @author Andrey Uzunov
     24  * @author Tatsuhiro Tsujikawa
     25  */
     26 
     27 //TODO child exits with ret val 1 sometimes
     28 
     29 #include "platform.h"
     30 #include "microspdy.h"
     31 #include <sys/wait.h>
     32 #include "common.h"
     33 
     34 #define RESPONSE_BODY "<html><body><b>Hi, this is libmicrospdy!</b></body></html>"
     35 
     36 #define CLS "anything"
     37 
     38 int port;
     39 int loop = 1;
     40 
     41 pid_t parent;
     42 pid_t child;
     43 
     44 int
     45 spdylay_printf(const char *format, ...)
     46 {
     47   (void)format;
     48 
     49 	return 0;
     50 }
     51 
     52 int
     53 spdylay_fprintf(FILE *stream, const char *format, ...)
     54 {
     55   (void)stream;
     56   (void)format;
     57 
     58 	return 0;
     59 }
     60 
     61 void
     62 killchild(int pid, char *message)
     63 {
     64 	printf("%s\n",message);
     65 	kill(pid, SIGKILL);
     66 	exit(1);
     67 }
     68 
     69 void
     70 killparent(int pid, char *message)
     71 {
     72 	printf("%s\n",message);
     73 	kill(pid, SIGKILL);
     74 	_exit(2);
     75 }
     76 
     77 
     78 /*****
     79  * start of code needed to utilize spdylay
     80  */
     81 
     82 #include <stdint.h>
     83 #include <stdlib.h>
     84 #include <unistd.h>
     85 #include <fcntl.h>
     86 #include <sys/types.h>
     87 #include <sys/socket.h>
     88 #include <netdb.h>
     89 #include <netinet/in.h>
     90 #include <netinet/tcp.h>
     91 #include <poll.h>
     92 #include <signal.h>
     93 #include <stdio.h>
     94 #include <assert.h>
     95 
     96 #include <spdylay/spdylay.h>
     97 
     98 #include <openssl/ssl.h>
     99 #include <openssl/err.h>
    100 
    101 enum {
    102   IO_NONE,
    103   WANT_READ,
    104   WANT_WRITE
    105 };
    106 
    107 struct Connection {
    108   SSL *ssl;
    109   spdylay_session *session;
    110   /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
    111      needs more output; or IO_NONE. This is necessary because SSL/TLS
    112      re-negotiation is possible at any time. Spdylay API offers
    113      similar functions like spdylay_session_want_read() and
    114      spdylay_session_want_write() but they do not take into account
    115      SSL connection. */
    116   int want_io;
    117 };
    118 
    119 struct Request {
    120   char *host;
    121   uint16_t port;
    122   /* In this program, path contains query component as well. */
    123   char *path;
    124   /* This is the concatenation of host and port with ":" in
    125      between. */
    126   char *hostport;
    127   /* Stream ID for this request. */
    128   int32_t stream_id;
    129   /* The gzip stream inflater for the compressed response. */
    130   spdylay_gzip *inflater;
    131 };
    132 
    133 struct URI {
    134   const char *host;
    135   size_t hostlen;
    136   uint16_t port;
    137   /* In this program, path contains query component as well. */
    138   const char *path;
    139   size_t pathlen;
    140   const char *hostport;
    141   size_t hostportlen;
    142 };
    143 
    144 /*
    145  * Returns copy of string |s| with the length |len|. The returned
    146  * string is NULL-terminated.
    147  */
    148 static char* strcopy(const char *s, size_t len)
    149 {
    150   char *dst;
    151   dst = malloc(len+1);
    152   if (NULL == dst)
    153     abort ();
    154   memcpy(dst, s, len);
    155   dst[len] = '\0';
    156   return dst;
    157 }
    158 
    159 /*
    160  * Prints error message |msg| and exit.
    161  */
    162 static void die(const char *msg)
    163 {
    164   fprintf(stderr, "FATAL: %s\n", msg);
    165   exit(EXIT_FAILURE);
    166 }
    167 
    168 /*
    169  * Prints error containing the function name |func| and message |msg|
    170  * and exit.
    171  */
    172 static void dief(const char *func, const char *msg)
    173 {
    174   fprintf(stderr, "FATAL: %s: %s\n", func, msg);
    175   exit(EXIT_FAILURE);
    176 }
    177 
    178 /*
    179  * Prints error containing the function name |func| and error code
    180  * |error_code| and exit.
    181  */
    182 static void diec(const char *func, int error_code)
    183 {
    184   fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
    185           spdylay_strerror(error_code));
    186   exit(EXIT_FAILURE);
    187 }
    188 
    189 /*
    190  * Check response is content-encoding: gzip. We need this because SPDY
    191  * client is required to support gzip.
    192  */
    193 static void check_gzip(struct Request *req, char **nv)
    194 {
    195   int gzip = 0;
    196   size_t i;
    197   for(i = 0; nv[i]; i += 2) {
    198     if(strcmp("content-encoding", nv[i]) == 0) {
    199       gzip = strcmp("gzip", nv[i+1]) == 0;
    200       break;
    201     }
    202   }
    203   if(gzip) {
    204     int rv;
    205     if(req->inflater) {
    206       return;
    207     }
    208     rv = spdylay_gzip_inflate_new(&req->inflater);
    209     if(rv != 0) {
    210       die("Can't allocate inflate stream.");
    211     }
    212   }
    213 }
    214 
    215 /*
    216  * The implementation of spdylay_send_callback type. Here we write
    217  * |data| with size |length| to the network and return the number of
    218  * bytes actually written. See the documentation of
    219  * spdylay_send_callback for the details.
    220  */
    221 static ssize_t send_callback(spdylay_session *session,
    222                              const uint8_t *data, size_t length, int flags,
    223                              void *user_data)
    224 {
    225   (void)session;
    226   (void)flags;
    227 
    228   struct Connection *connection;
    229   ssize_t rv;
    230   connection = (struct Connection*)user_data;
    231   connection->want_io = IO_NONE;
    232   ERR_clear_error();
    233   rv = SSL_write(connection->ssl, data, length);
    234   if(rv < 0) {
    235     int err = SSL_get_error(connection->ssl, rv);
    236     if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
    237       connection->want_io = (err == SSL_ERROR_WANT_READ ?
    238                              WANT_READ : WANT_WRITE);
    239       rv = SPDYLAY_ERR_WOULDBLOCK;
    240     } else {
    241       rv = SPDYLAY_ERR_CALLBACK_FAILURE;
    242     }
    243   }
    244   return rv;
    245 }
    246 
    247 /*
    248  * The implementation of spdylay_recv_callback type. Here we read data
    249  * from the network and write them in |buf|. The capacity of |buf| is
    250  * |length| bytes. Returns the number of bytes stored in |buf|. See
    251  * the documentation of spdylay_recv_callback for the details.
    252  */
    253 static ssize_t recv_callback(spdylay_session *session,
    254                              uint8_t *buf, size_t length, int flags,
    255                              void *user_data)
    256 {
    257   (void)session;
    258   (void)flags;
    259 
    260   struct Connection *connection;
    261   ssize_t rv;
    262   connection = (struct Connection*)user_data;
    263   connection->want_io = IO_NONE;
    264   ERR_clear_error();
    265   rv = SSL_read(connection->ssl, buf, length);
    266   if(rv < 0) {
    267     int err = SSL_get_error(connection->ssl, rv);
    268     if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
    269       connection->want_io = (err == SSL_ERROR_WANT_READ ?
    270                              WANT_READ : WANT_WRITE);
    271       rv = SPDYLAY_ERR_WOULDBLOCK;
    272     } else {
    273       rv = SPDYLAY_ERR_CALLBACK_FAILURE;
    274     }
    275   } else if(rv == 0) {
    276     rv = SPDYLAY_ERR_EOF;
    277   }
    278   return rv;
    279 }
    280 
    281 /*
    282  * The implementation of spdylay_before_ctrl_send_callback type.  We
    283  * use this function to get stream ID of the request. This is because
    284  * stream ID is not known when we submit the request
    285  * (spdylay_submit_request).
    286  */
    287 static void before_ctrl_send_callback(spdylay_session *session,
    288                                       spdylay_frame_type type,
    289                                       spdylay_frame *frame,
    290                                       void *user_data)
    291 {
    292   (void)user_data;
    293 
    294   if(type == SPDYLAY_SYN_STREAM) {
    295     struct Request *req;
    296     int stream_id = frame->syn_stream.stream_id;
    297     req = spdylay_session_get_stream_user_data(session, stream_id);
    298     if(req && req->stream_id == -1) {
    299       req->stream_id = stream_id;
    300       spdylay_printf("[INFO] Stream ID = %d\n", stream_id);
    301     }
    302   }
    303 }
    304 
    305 static void on_ctrl_send_callback(spdylay_session *session,
    306                                   spdylay_frame_type type,
    307                                   spdylay_frame *frame, void *user_data)
    308 {
    309   (void)user_data;
    310 
    311   char **nv;
    312   const char *name = NULL;
    313   int32_t stream_id;
    314   size_t i;
    315   switch(type) {
    316   case SPDYLAY_SYN_STREAM:
    317     nv = frame->syn_stream.nv;
    318     name = "SYN_STREAM";
    319     stream_id = frame->syn_stream.stream_id;
    320     break;
    321   default:
    322     break;
    323   }
    324   if(name && spdylay_session_get_stream_user_data(session, stream_id)) {
    325     spdylay_printf("[INFO] C ----------------------------> S (%s)\n", name);
    326     for(i = 0; nv[i]; i += 2) {
    327       spdylay_printf("       %s: %s\n", nv[i], nv[i+1]);
    328     }
    329   }
    330 }
    331 
    332 static void on_ctrl_recv_callback(spdylay_session *session,
    333                                   spdylay_frame_type type,
    334                                   spdylay_frame *frame, void *user_data)
    335 {
    336   (void)user_data;
    337 
    338   struct Request *req;
    339   char **nv;
    340   const char *name = NULL;
    341   int32_t stream_id;
    342   size_t i;
    343   switch(type) {
    344   case SPDYLAY_SYN_REPLY:
    345     nv = frame->syn_reply.nv;
    346     name = "SYN_REPLY";
    347     stream_id = frame->syn_reply.stream_id;
    348     break;
    349   case SPDYLAY_HEADERS:
    350     nv = frame->headers.nv;
    351     name = "HEADERS";
    352     stream_id = frame->headers.stream_id;
    353     break;
    354   default:
    355     break;
    356   }
    357   if(!name) {
    358     return;
    359   }
    360   req = spdylay_session_get_stream_user_data(session, stream_id);
    361   if(req) {
    362     check_gzip(req, nv);
    363     spdylay_printf("[INFO] C <---------------------------- S (%s)\n", name);
    364     for(i = 0; nv[i]; i += 2) {
    365       spdylay_printf("       %s: %s\n", nv[i], nv[i+1]);
    366     }
    367   }
    368 }
    369 
    370 /*
    371  * The implementation of spdylay_on_stream_close_callback type. We use
    372  * this function to know the response is fully received. Since we just
    373  * fetch 1 resource in this program, after reception of the response,
    374  * we submit GOAWAY and close the session.
    375  */
    376 static void on_stream_close_callback(spdylay_session *session,
    377                                      int32_t stream_id,
    378                                      spdylay_status_code status_code,
    379                                      void *user_data)
    380 {
    381   (void)user_data;
    382   (void)status_code;
    383   struct Request *req;
    384   req = spdylay_session_get_stream_user_data(session, stream_id);
    385   if(req) {
    386     int rv;
    387     rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
    388     if(rv != 0) {
    389       diec("spdylay_submit_goaway", rv);
    390     }
    391   }
    392 }
    393 
    394 #define MAX_OUTLEN 4096
    395 
    396 /*
    397  * The implementation of spdylay_on_data_chunk_recv_callback type. We
    398  * use this function to print the received response body.
    399  */
    400 static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
    401                                         int32_t stream_id,
    402                                         const uint8_t *data, size_t len,
    403                                         void *user_data)
    404 {
    405   (void)user_data;
    406   (void)flags;
    407 
    408   struct Request *req;
    409   req = spdylay_session_get_stream_user_data(session, stream_id);
    410   if(req) {
    411     spdylay_printf("[INFO] C <---------------------------- S (DATA)\n");
    412     spdylay_printf("       %lu bytes\n", (unsigned long int)len);
    413     if(req->inflater) {
    414       while(len > 0) {
    415         uint8_t out[MAX_OUTLEN];
    416         size_t outlen = MAX_OUTLEN;
    417         size_t tlen = len;
    418         int rv;
    419         rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
    420         if(rv == -1) {
    421           spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
    422           break;
    423         }
    424         fwrite(out, 1, outlen, stdout);
    425         data += tlen;
    426         len -= tlen;
    427       }
    428     } else {
    429       /* TODO add support gzip */
    430       fwrite(data, 1, len, stdout);
    431 
    432       //check if the data is correct
    433       if(strcmp(RESPONSE_BODY, (char *)data) != 0)
    434 		killparent(parent, "\nreceived data is not the same");
    435     }
    436     spdylay_printf("\n");
    437   }
    438 }
    439 
    440 /*
    441  * Setup callback functions. Spdylay API offers many callback
    442  * functions, but most of them are optional. The send_callback is
    443  * always required. Since we use spdylay_session_recv(), the
    444  * recv_callback is also required.
    445  */
    446 static void setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
    447 {
    448   memset(callbacks, 0, sizeof(spdylay_session_callbacks));
    449   callbacks->send_callback = send_callback;
    450   callbacks->recv_callback = recv_callback;
    451   callbacks->before_ctrl_send_callback = before_ctrl_send_callback;
    452   callbacks->on_ctrl_send_callback = on_ctrl_send_callback;
    453   callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback;
    454   callbacks->on_stream_close_callback = on_stream_close_callback;
    455   callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
    456 }
    457 
    458 /*
    459  * Callback function for SSL/TLS NPN. Since this program only supports
    460  * SPDY protocol, if server does not offer SPDY protocol the Spdylay
    461  * library supports, we terminate program.
    462  */
    463 static int select_next_proto_cb(SSL* ssl,
    464                                 unsigned char **out, unsigned char *outlen,
    465                                 const unsigned char *in, unsigned int inlen,
    466                                 void *arg)
    467 {
    468   (void)ssl;
    469 
    470   int rv;
    471   uint16_t *spdy_proto_version;
    472   /* spdylay_select_next_protocol() selects SPDY protocol version the
    473      Spdylay library supports. */
    474   rv = spdylay_select_next_protocol(out, outlen, in, inlen);
    475   if(rv <= 0) {
    476     die("Server did not advertise spdy/2 or spdy/3 protocol.");
    477   }
    478   spdy_proto_version = (uint16_t*)arg;
    479   *spdy_proto_version = rv;
    480   return SSL_TLSEXT_ERR_OK;
    481 }
    482 
    483 /*
    484  * Setup SSL context. We pass |spdy_proto_version| to get negotiated
    485  * SPDY protocol version in NPN callback.
    486  */
    487 static void init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version)
    488 {
    489   /* Disable SSLv2 and enable all workarounds for buggy servers */
    490   SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
    491   SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
    492   SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
    493   /* Set NPN callback */
    494   SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb,
    495                                    spdy_proto_version);
    496 }
    497 
    498 static void ssl_handshake(SSL *ssl, int fd)
    499 {
    500   int rv;
    501   if(SSL_set_fd(ssl, fd) == 0) {
    502     dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
    503   }
    504   ERR_clear_error();
    505   rv = SSL_connect(ssl);
    506   if(rv <= 0) {
    507     dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
    508   }
    509 }
    510 
    511 /*
    512  * Connects to the host |host| and port |port|.  This function returns
    513  * the file descriptor of the client socket.
    514  */
    515 static int connect_to(const char *host, uint16_t port)
    516 {
    517   struct addrinfo hints;
    518   int fd = -1;
    519   int rv;
    520   char service[NI_MAXSERV];
    521   struct addrinfo *res, *rp;
    522   snprintf(service, sizeof(service), "%u", port);
    523   memset(&hints, 0, sizeof(struct addrinfo));
    524   hints.ai_family = AF_UNSPEC;
    525   hints.ai_socktype = SOCK_STREAM;
    526   rv = getaddrinfo(host, service, &hints, &res);
    527   if(rv != 0) {
    528     dief("getaddrinfo", gai_strerror(rv));
    529   }
    530   for(rp = res; rp; rp = rp->ai_next) {
    531     fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
    532     if(fd == -1) {
    533       continue;
    534     }
    535     while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
    536           errno == EINTR);
    537     if(rv == 0) {
    538       break;
    539     }
    540     close(fd);
    541     fd = -1;
    542   }
    543   freeaddrinfo(res);
    544   return fd;
    545 }
    546 
    547 static void make_non_block(int fd)
    548 {
    549   int flags, rv;
    550   while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
    551   if(flags == -1) {
    552     dief("fcntl", strerror(errno));
    553   }
    554   while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
    555   if(rv == -1) {
    556     dief("fcntl", strerror(errno));
    557   }
    558 }
    559 
    560 /*
    561  * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
    562  */
    563 static void set_tcp_nodelay(int fd)
    564 {
    565   int val = 1;
    566   int rv;
    567   rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
    568   if(rv == -1) {
    569     dief("setsockopt", strerror(errno));
    570   }
    571 }
    572 
    573 /*
    574  * Update |pollfd| based on the state of |connection|.
    575  */
    576 static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
    577 {
    578   pollfd->events = 0;
    579   if(spdylay_session_want_read(connection->session) ||
    580      connection->want_io == WANT_READ) {
    581     pollfd->events |= POLLIN;
    582   }
    583   if(spdylay_session_want_write(connection->session) ||
    584      connection->want_io == WANT_WRITE) {
    585     pollfd->events |= POLLOUT;
    586   }
    587 }
    588 
    589 /*
    590  * Submits the request |req| to the connection |connection|.  This
    591  * function does not send packets; just append the request to the
    592  * internal queue in |connection->session|.
    593  */
    594 static void submit_request(struct Connection *connection, struct Request *req)
    595 {
    596   int pri = 0;
    597   int rv;
    598   const char *nv[15];
    599   /* We always use SPDY/3 style header even if the negotiated protocol
    600      version is SPDY/2. The library translates the header name as
    601      necessary. Make sure that the last item is NULL! */
    602   nv[0] = ":method";     nv[1] = "GET";
    603   nv[2] = ":path";       nv[3] = req->path;
    604   nv[4] = ":version";    nv[5] = "HTTP/1.1";
    605   nv[6] = ":scheme";     nv[7] = "https";
    606   nv[8] = ":host";       nv[9] = req->hostport;
    607   nv[10] = "accept";     nv[11] = "*/*";
    608   nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION;
    609   nv[14] = NULL;
    610   rv = spdylay_submit_request(connection->session, pri, nv, NULL, req);
    611   if(rv != 0) {
    612     diec("spdylay_submit_request", rv);
    613   }
    614 }
    615 
    616 /*
    617  * Performs the network I/O.
    618  */
    619 static void exec_io(struct Connection *connection)
    620 {
    621   int rv;
    622   rv = spdylay_session_recv(connection->session);
    623   if(rv != 0) {
    624     diec("spdylay_session_recv", rv);
    625   }
    626   rv = spdylay_session_send(connection->session);
    627   if(rv != 0) {
    628     diec("spdylay_session_send", rv);
    629   }
    630 }
    631 
    632 static void request_init(struct Request *req, const struct URI *uri)
    633 {
    634   req->host = strcopy(uri->host, uri->hostlen);
    635   req->port = uri->port;
    636   req->path = strcopy(uri->path, uri->pathlen);
    637   req->hostport = strcopy(uri->hostport, uri->hostportlen);
    638   req->stream_id = -1;
    639   req->inflater = NULL;
    640 }
    641 
    642 static void request_free(struct Request *req)
    643 {
    644   free(req->host);
    645   free(req->path);
    646   free(req->hostport);
    647   spdylay_gzip_inflate_del(req->inflater);
    648 }
    649 
    650 /*
    651  * Fetches the resource denoted by |uri|.
    652  */
    653 static void fetch_uri(const struct URI *uri)
    654 {
    655   spdylay_session_callbacks callbacks;
    656   int fd;
    657   SSL_CTX *ssl_ctx;
    658   SSL *ssl;
    659   struct Request req;
    660   struct Connection connection;
    661   int rv;
    662   nfds_t npollfds = 1;
    663   struct pollfd pollfds[1];
    664   uint16_t spdy_proto_version;
    665 
    666   request_init(&req, uri);
    667 
    668   setup_spdylay_callbacks(&callbacks);
    669 
    670   /* Establish connection and setup SSL */
    671   fd = connect_to(req.host, req.port);
    672   if (-1 == fd)
    673     abort ();
    674   ssl_ctx = SSL_CTX_new(SSLv23_client_method());
    675   if(ssl_ctx == NULL) {
    676     dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
    677   }
    678   init_ssl_ctx(ssl_ctx, &spdy_proto_version);
    679   ssl = SSL_new(ssl_ctx);
    680   if(ssl == NULL) {
    681     dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
    682   }
    683   /* To simplify the program, we perform SSL/TLS handshake in blocking
    684      I/O. */
    685   ssl_handshake(ssl, fd);
    686 
    687   connection.ssl = ssl;
    688   connection.want_io = IO_NONE;
    689 
    690   /* Here make file descriptor non-block */
    691   make_non_block(fd);
    692   set_tcp_nodelay(fd);
    693 
    694   spdylay_printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version);
    695   rv = spdylay_session_client_new(&connection.session, spdy_proto_version,
    696                                   &callbacks, &connection);
    697   if(rv != 0) {
    698     diec("spdylay_session_client_new", rv);
    699   }
    700 
    701   /* Submit the HTTP request to the outbound queue. */
    702   submit_request(&connection, &req);
    703 
    704   pollfds[0].fd = fd;
    705   ctl_poll(pollfds, &connection);
    706 
    707   /* Event loop */
    708   while(spdylay_session_want_read(connection.session) ||
    709         spdylay_session_want_write(connection.session)) {
    710     int nfds = poll(pollfds, npollfds, -1);
    711     if(nfds == -1) {
    712       dief("poll", strerror(errno));
    713     }
    714     if(pollfds[0].revents & (POLLIN | POLLOUT)) {
    715       exec_io(&connection);
    716     }
    717     if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
    718       die("Connection error");
    719     }
    720     ctl_poll(pollfds, &connection);
    721   }
    722 
    723   /* Resource cleanup */
    724   spdylay_session_del(connection.session);
    725   SSL_shutdown(ssl);
    726   SSL_free(ssl);
    727   SSL_CTX_free(ssl_ctx);
    728   shutdown(fd, SHUT_WR);
    729   close(fd);
    730   request_free(&req);
    731 }
    732 
    733 static int parse_uri(struct URI *res, const char *uri)
    734 {
    735   /* We only interested in https */
    736   size_t len, i, offset;
    737   memset(res, 0, sizeof(struct URI));
    738   len = strlen(uri);
    739   if(len < 9 || memcmp("https://", uri, 8) != 0) {
    740     return -1;
    741   }
    742   offset = 8;
    743   res->host = res->hostport = &uri[offset];
    744   res->hostlen = 0;
    745   if(uri[offset] == '[') {
    746     /* IPv6 literal address */
    747     ++offset;
    748     ++res->host;
    749     for(i = offset; i < len; ++i) {
    750       if(uri[i] == ']') {
    751         res->hostlen = i-offset;
    752         offset = i+1;
    753         break;
    754       }
    755     }
    756   } else {
    757     const char delims[] = ":/?#";
    758     for(i = offset; i < len; ++i) {
    759       if(strchr(delims, uri[i]) != NULL) {
    760         break;
    761       }
    762     }
    763     res->hostlen = i-offset;
    764     offset = i;
    765   }
    766   if(res->hostlen == 0) {
    767     return -1;
    768   }
    769   /* Assuming https */
    770   res->port = 443;
    771   if(offset < len) {
    772     if(uri[offset] == ':') {
    773       /* port */
    774       const char delims[] = "/?#";
    775       int port = 0;
    776       ++offset;
    777       for(i = offset; i < len; ++i) {
    778         if(strchr(delims, uri[i]) != NULL) {
    779           break;
    780         }
    781         if('0' <= uri[i] && uri[i] <= '9') {
    782           port *= 10;
    783           port += uri[i]-'0';
    784           if(port > 65535) {
    785             return -1;
    786           }
    787         } else {
    788           return -1;
    789         }
    790       }
    791       if(port == 0) {
    792         return -1;
    793       }
    794       offset = i;
    795       res->port = port;
    796     }
    797   }
    798   res->hostportlen = uri+offset-res->host;
    799   for(i = offset; i < len; ++i) {
    800     if(uri[i] == '#') {
    801       break;
    802     }
    803   }
    804   if(i-offset == 0) {
    805     res->path = "/";
    806     res->pathlen = 1;
    807   } else {
    808     res->path = &uri[offset];
    809     res->pathlen = i-offset;
    810   }
    811   return 0;
    812 }
    813 
    814 
    815 /*****
    816  * end of code needed to utilize spdylay
    817  */
    818 
    819 
    820 /*****
    821  * start of code needed to utilize microspdy
    822  */
    823 
    824 void
    825 new_session_callback (void *cls,
    826 						struct SPDY_Session * session)
    827 {
    828 	char ipstr[1024];
    829 
    830 	struct sockaddr *addr;
    831 	socklen_t addr_len = SPDY_get_remote_addr(session, &addr);
    832 
    833 	if(!addr_len)
    834 	{
    835 		printf("SPDY_get_remote_addr");
    836 		abort();
    837 	}
    838 
    839 	if(strcmp(CLS,cls)!=0)
    840 	{
    841 		killchild(child,"wrong cls");
    842 	}
    843 
    844 	if(AF_INET == addr->sa_family)
    845 	{
    846 		struct sockaddr_in * addr4 = (struct sockaddr_in *) addr;
    847 		if(NULL == inet_ntop(AF_INET, &(addr4->sin_addr), ipstr, sizeof(ipstr)))
    848 		{
    849 			killchild(child,"inet_ntop");
    850 		}
    851 		printf("New connection from: %s:%i\n", ipstr, ntohs(addr4->sin_port));
    852 
    853 		loop = 0;
    854 	}
    855 #if HAVE_INET6
    856 	else if(AF_INET6 == addr->sa_family)
    857 	{
    858 		struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *) addr;
    859 		if(NULL == inet_ntop(AF_INET6, &(addr6->sin6_addr), ipstr, sizeof(ipstr)))
    860 		{
    861 			killchild(child,"inet_ntop");
    862 		}
    863 		printf("New connection from: %s:%i\n", ipstr, ntohs(addr6->sin6_port));
    864 
    865 		loop = 0;
    866 	}
    867 #endif
    868 	else
    869 	{
    870 		killchild(child,"wrong family");
    871 	}
    872 }
    873 
    874 /*****
    875  * end of code needed to utilize microspdy
    876  */
    877 
    878 //child process
    879 void
    880 childproc(int parent)
    881 {
    882   struct URI uri;
    883   struct sigaction act;
    884   int rv;
    885   char *uristr;
    886 
    887   memset(&act, 0, sizeof(struct sigaction));
    888   act.sa_handler = SIG_IGN;
    889   sigaction(SIGPIPE, &act, 0);
    890 
    891 	asprintf(&uristr, "https://127.0.0.1:%i/",port);
    892 
    893   SSL_load_error_strings();
    894   SSL_library_init();
    895 
    896   rv = parse_uri(&uri, uristr);
    897   if(rv != 0) {
    898     killparent(parent,"parse_uri failed");
    899   }
    900   fetch_uri(&uri);
    901 }
    902 
    903 //parent proc
    904 int
    905 parentproc(int child)
    906 {
    907 	int childstatus = 0;
    908 	unsigned long long timeoutlong=0;
    909 	struct timeval timeout;
    910 	int ret;
    911 	fd_set read_fd_set;
    912 	fd_set write_fd_set;
    913 	fd_set except_fd_set;
    914 	int maxfd = -1;
    915 	struct SPDY_Daemon *daemon;
    916 
    917 	SPDY_init();
    918 
    919 	daemon = SPDY_start_daemon(port,
    920 								DATA_DIR "cert-and-key.pem",
    921 								DATA_DIR "cert-and-key.pem",
    922 								&new_session_callback,NULL,NULL,NULL,CLS,SPDY_DAEMON_OPTION_END);
    923 
    924 	if(NULL==daemon){
    925 		printf("no daemon\n");
    926 		return 1;
    927 	}
    928 
    929 	do
    930 	{
    931 		FD_ZERO(&read_fd_set);
    932 		FD_ZERO(&write_fd_set);
    933 		FD_ZERO(&except_fd_set);
    934 
    935 		ret = SPDY_get_timeout(daemon, &timeoutlong);
    936 		if(SPDY_NO == ret || timeoutlong > 1000)
    937 		{
    938 			timeout.tv_sec = 1;
    939       timeout.tv_usec = 0;
    940 		}
    941 		else
    942 		{
    943 			timeout.tv_sec = timeoutlong / 1000;
    944 			timeout.tv_usec = (timeoutlong % 1000) * 1000;
    945 		}
    946 
    947 		maxfd = SPDY_get_fdset (daemon,
    948 								&read_fd_set,
    949 								&write_fd_set,
    950 								&except_fd_set);
    951 
    952 		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
    953 
    954 		switch(ret) {
    955 			case -1:
    956 				printf("select error: %i\n", errno);
    957 				killchild(child, "select error");
    958 				break;
    959 			case 0:
    960 
    961 				break;
    962 			default:
    963 				SPDY_run(daemon);
    964 
    965 			break;
    966 		}
    967 	}
    968 	while(loop && waitpid(child,&childstatus,WNOHANG) != child);
    969 
    970 	SPDY_stop_daemon(daemon);
    971 
    972 	SPDY_deinit();
    973 
    974 	if(loop)
    975 		return WEXITSTATUS(childstatus);
    976 	if(waitpid(child,&childstatus,WNOHANG) == child)
    977 		return WEXITSTATUS(childstatus);
    978 
    979 	kill(child,SIGKILL);
    980 
    981 	waitpid(child,&childstatus,0);
    982 
    983 	return 0;
    984 }
    985 
    986 int main()
    987 {
    988 	port = get_port(14123);
    989 	parent = getpid();
    990 
    991    child = fork();
    992    if (child == -1)
    993    {
    994       fprintf(stderr, "can't fork, error %d\n", errno);
    995       exit(EXIT_FAILURE);
    996    }
    997 
    998    if (child == 0)
    999    {
   1000       childproc(parent);
   1001       _exit(0);
   1002    }
   1003    else
   1004    {
   1005 	   int ret = parentproc(child);
   1006       exit(ret);
   1007    }
   1008    return 1;
   1009 }
   1010