/* * Performs the network I/O. */ static void exec_io(struct Connection *connection) { int rv; rv = nghttp2_session_recv(connection->session); if (rv != 0) { diec("nghttp2_session_recv", rv); } rv = nghttp2_session_send(connection->session); if (rv != 0) { diec("nghttp2_session_send", rv); } }
/* * Submits the request |req| to the connection |connection|. This * function does not send packets; just append the request to the * internal queue in |connection->session|. */ static void submit_request(struct Connection *connection, struct Request *req) { int pri = 0; int rv; const char *nv[17]; /* We always use SPDY/3 style header even if the negotiated protocol version is SPDY/2. The library translates the header name as necessary. Make sure that the last item is NULL! */ //nv[0] = ":method"; nv[1] = "GET"; nv[0] = ":method"; nv[1] = "POST"; nv[2] = ":path"; nv[3] = req->path; nv[4] = ":version"; nv[5] = "HTTP/1.1"; nv[6] = ":scheme"; nv[7] = "https"; nv[8] = ":host"; nv[9] = req->hostport; nv[10] = "accept"; nv[11] = "*/*"; nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION; nv[14] = "clientid"; nv[15] = "clientId-1234"; nv[16] = NULL; spdylay_data_provider data_prd; data_prd.source.ptr = "client-1234"; rv = spdylay_submit_request(connection->session, pri, nv, &data_prd, req); //rv = spdylay_submit_request(connection->session, pri, nv, NULL, req); if(rv != 0) { diec("spdylay_submit_request", rv); } }
/* * The implementation of spdylay_on_stream_close_callback type. We use * this function to know the response is fully received. Since we just * fetch 1 resource in this program, after reception of the response, * we submit GOAWAY and close the session. */ static void on_stream_close_callback(spdylay_session *session, int32_t stream_id, spdylay_status_code status_code, void *user_data) { struct Request *req; req = spdylay_session_get_stream_user_data(session, stream_id); if(req) { int rv; rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK); if(rv != 0) { diec("spdylay_submit_goaway", rv); } } }
/* * The implementation of nghttp2_on_stream_close_callback type. We use * this function to know the response is fully received. Since we just * fetch 1 resource in this program, after reception of the response, * we submit GOAWAY and close the session. */ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *user_data) { struct Request *req; (void)error_code; (void)user_data; req = nghttp2_session_get_stream_user_data(session, stream_id); if (req) { int rv; rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR); if (rv != 0) { diec("nghttp2_session_terminate_session", rv); } } return 0; }
/* * Submits the request |req| to the connection |connection|. This * function does not send packets; just append the request to the * internal queue in |connection->session|. */ static void submit_request(struct Connection *connection, struct Request *req) { int32_t stream_id; /* Make sure that the last item is NULL */ const nghttp2_nv nva[] = {MAKE_NV(":method", "GET"), MAKE_NV_CS(":path", req->path), MAKE_NV(":scheme", "https"), MAKE_NV_CS(":authority", req->hostport), MAKE_NV("accept", "*/*"), MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)}; stream_id = nghttp2_submit_request(connection->session, NULL, nva, sizeof(nva) / sizeof(nva[0]), NULL, req); if (stream_id < 0) { diec("nghttp2_submit_request", stream_id); } req->stream_id = stream_id; printf("[INFO] Stream ID = %d\n", stream_id); }
/* * Fetches the resource denoted by |uri|. */ static void fetch_uri(const struct URI *uri) { spdylay_session_callbacks callbacks; int fd; SSL_CTX *ssl_ctx; SSL *ssl; struct Request req; struct Connection connection; int rv; nfds_t npollfds = 1; struct pollfd pollfds[1]; uint16_t spdy_proto_version; request_init(&req, uri); setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ fd = connect_to(req.host, req.port); ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if(ssl_ctx == NULL) { dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL)); } init_ssl_ctx(ssl_ctx, &spdy_proto_version); ssl = SSL_new(ssl_ctx); if(ssl == NULL) { dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); } /* To simplify the program, we perform SSL/TLS handshake in blocking I/O. */ ssl_handshake(ssl, fd); connection.ssl = ssl; connection.want_io = IO_NONE; /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version); rv = spdylay_session_client_new(&connection.session, spdy_proto_version, &callbacks, &connection); if(rv != 0) { diec("spdylay_session_client_new", rv); } /* Submit the HTTP request to the outbound queue. */ submit_request(&connection, &req); pollfds[0].fd = fd; ctl_poll(pollfds, &connection); /* Event loop */ while(spdylay_session_want_read(connection.session) || spdylay_session_want_write(connection.session)) { int nfds = poll(pollfds, npollfds, -1); if(nfds == -1) { dief("poll", strerror(errno)); } if(pollfds[0].revents & (POLLIN | POLLOUT)) { exec_io(&connection); } if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { die("Connection error"); } ctl_poll(pollfds, &connection); } /* Resource cleanup */ spdylay_session_del(connection.session); SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ssl_ctx); shutdown(fd, SHUT_WR); close(fd); request_free(&req); }
/* * Fetches the resource denoted by |uri|. */ static void fetch_uri(const struct URI *uri) { spdylay_session_callbacks callbacks; int fd; struct Request req; struct Connection connection; int rv; nfds_t npollfds = 1; struct pollfd pollfds[1]; uint16_t spdy_proto_version = 3; request_init(&req, uri); setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ fd = connect_to(req.host, req.port); if (-1 == fd) abort (); connection.fd = fd; connection.want_io = IO_NONE; /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version); rv = spdylay_session_client_new(&connection.session, spdy_proto_version, &callbacks, &connection); if(rv != 0) { diec("spdylay_session_client_new", rv); } /* Submit the HTTP request to the outbound queue. */ submit_request(&connection, &req); pollfds[0].fd = fd; ctl_poll(pollfds, &connection); /* Event loop */ while(spdylay_session_want_read(connection.session) || spdylay_session_want_write(connection.session)) { int nfds = poll(pollfds, npollfds, -1); if(nfds == -1) { dief("poll", strerror(errno)); } if(pollfds[0].revents & (POLLIN | POLLOUT)) { exec_io(&connection); } if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { die("Connection error"); } ctl_poll(pollfds, &connection); } /* Resource cleanup */ spdylay_session_del(connection.session); shutdown(fd, SHUT_WR); MHD_socket_close_(fd); request_free(&req); }