asio: ALPN support

This commit is contained in:
Tatsuhiro Tsujikawa 2015-11-07 10:32:08 +09:00
parent ab1f70dcd7
commit b89f1f5869
7 changed files with 113 additions and 12 deletions

View File

@ -23,6 +23,7 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "asio_client_session_tls_impl.h" #include "asio_client_session_tls_impl.h"
#include "asio_common.h"
namespace nghttp2 { namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
@ -59,6 +60,13 @@ void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) {
not_connected(ec); not_connected(ec);
return; return;
} }
if (!tls_h2_negotiated(socket_)) {
not_connected(
make_error_code(NGHTTP2_ASIO_ERR_TLS_NO_APP_PROTO_NEGOTIATED));
return;
}
connected(endpoint_it); connected(endpoint_it);
}); });
}); });

View File

@ -56,6 +56,12 @@ configure_tls_context(boost::system::error_code &ec,
SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr); SSL_CTX_set_next_proto_select_cb(ctx, client_select_next_proto_cb, nullptr);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
auto proto_list = util::get_default_alpn();
SSL_CTX_set_alpn_protos(ctx, proto_list.data(), proto_list.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ec; return ec;
} }

View File

@ -48,6 +48,31 @@ boost::system::error_code make_error_code(nghttp2_error ev) {
return boost::system::error_code(static_cast<int>(ev), nghttp2_category()); return boost::system::error_code(static_cast<int>(ev), nghttp2_category());
} }
class nghttp2_asio_category_impl : public boost::system::error_category {
public:
const char *name() const noexcept { return "nghttp2_asio"; }
std::string message(int ev) const {
switch (ev) {
case NGHTTP2_ASIO_ERR_NO_ERROR:
return "no error";
case NGHTTP2_ASIO_ERR_TLS_NO_APP_PROTO_NEGOTIATED:
return "tls: no application protocol negotiated";
default:
return "unknown";
}
}
};
const boost::system::error_category &nghttp2_asio_category() noexcept {
static nghttp2_asio_category_impl cat;
return cat;
}
boost::system::error_code make_error_code(nghttp2_asio_error ev) {
return boost::system::error_code(static_cast<int>(ev),
nghttp2_asio_category());
}
generator_cb string_generator(std::string data) { generator_cb string_generator(std::string data) {
auto strio = std::make_shared<std::pair<std::string, size_t>>(std::move(data), auto strio = std::make_shared<std::pair<std::string, size_t>>(std::move(data),
data.size()); data.size());
@ -144,5 +169,23 @@ boost::system::error_code host_service_from_uri(boost::system::error_code &ec,
return ec; return ec;
} }
bool tls_h2_negotiated(ssl_socket &socket) {
auto ssl = socket.native_handle();
const unsigned char *next_proto = nullptr;
unsigned int next_proto_len = 0;
SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
if (next_proto == nullptr) {
SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
}
if (next_proto == nullptr) {
return false;
}
return util::check_h2_is_selected(next_proto, next_proto_len);
}
} // namespace asio_http2 } // namespace asio_http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -39,6 +39,8 @@ namespace asio_http2 {
boost::system::error_code make_error_code(nghttp2_error ev); boost::system::error_code make_error_code(nghttp2_error ev);
boost::system::error_code make_error_code(nghttp2_asio_error ev);
generator_cb string_generator(std::string data); generator_cb string_generator(std::string data);
// Returns generator_cb, which just returns NGHTTP2_ERR_DEFERRED // Returns generator_cb, which just returns NGHTTP2_ERR_DEFERRED
@ -58,6 +60,12 @@ void split_path(uri_ref &dst, InputIt first, InputIt last) {
dst.raw_query.assign(query_first, last); dst.raw_query.assign(query_first, last);
} }
using boost::asio::ip::tcp;
using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
bool tls_h2_negotiated(ssl_socket &socket);
} // namespace asio_http2 } // namespace asio_http2
} // namespace nghttp2 } // namespace nghttp2

View File

@ -37,6 +37,7 @@
#include "asio_server.h" #include "asio_server.h"
#include "asio_server_connection.h" #include "asio_server_connection.h"
#include "asio_common.h"
#include "util.h" #include "util.h"
namespace nghttp2 { namespace nghttp2 {
@ -130,9 +131,15 @@ void server::start_accept(boost::asio::ssl::context &tls_context,
new_connection->socket().async_handshake( new_connection->socket().async_handshake(
boost::asio::ssl::stream_base::server, boost::asio::ssl::stream_base::server,
[new_connection](const boost::system::error_code &e) { [new_connection](const boost::system::error_code &e) {
if (!e) { if (e) {
new_connection->start(); return;
} }
if (!tls_h2_negotiated(new_connection->socket())) {
return;
}
new_connection->start();
}); });
} }

View File

@ -42,6 +42,19 @@ std::vector<unsigned char> &get_alpn_token() {
} }
} // namespace } // namespace
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace {
int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg) {
if (!util::select_h2(out, outlen, in, inlen)) {
return SSL_TLSEXT_ERR_NOACK;
}
return SSL_TLSEXT_ERR_OK;
}
} // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
boost::system::error_code boost::system::error_code
configure_tls_context_easy(boost::system::error_code &ec, configure_tls_context_easy(boost::system::error_code &ec,
boost::asio::ssl::context &tls_context) { boost::asio::ssl::context &tls_context) {
@ -81,6 +94,11 @@ configure_tls_context_easy(boost::system::error_code &ec,
}, },
nullptr); nullptr);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
// ALPN selection callback
SSL_CTX_set_alpn_select_cb(ctx, alpn_select_proto_cb, nullptr);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
return ec; return ec;
} }

View File

@ -38,16 +38,6 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
namespace boost {
namespace system {
template <> struct is_error_code_enum<nghttp2_error> {
BOOST_STATIC_CONSTANT(bool, value = true);
};
} // namespace system
} // namespace boost
namespace nghttp2 { namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
@ -132,8 +122,29 @@ boost::system::error_code host_service_from_uri(boost::system::error_code &ec,
std::string &service, std::string &service,
const std::string &uri); const std::string &uri);
enum nghttp2_asio_error {
NGHTTP2_ASIO_ERR_NO_ERROR = 0,
NGHTTP2_ASIO_ERR_TLS_NO_APP_PROTO_NEGOTIATED = 1,
};
} // namespace asio_http2 } // namespace asio_http2
} // namespace nghttp2 } // namespace nghttp2
namespace boost {
namespace system {
template <> struct is_error_code_enum<nghttp2_error> {
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <> struct is_error_code_enum<nghttp2::asio_http2::nghttp2_asio_error> {
BOOST_STATIC_CONSTANT(bool, value = true);
};
} // namespace system
} // namespace boost
#endif // ASIO_HTTP2_H #endif // ASIO_HTTP2_H