From ea60bd8c6e64eee6971e2de61d83d50249d4698f Mon Sep 17 00:00:00 2001 From: Jim Morrison Date: Thu, 2 Feb 2012 16:31:11 -0800 Subject: [PATCH] Add an NPN callback helper that finds the correct version of spdy --- .gitignore | 1 + examples/spdylay_ssl.cc | 22 ++++-------- lib/Makefile.am | 2 +- lib/includes/spdylay/spdylay.h | 18 ++++++++++ lib/spdylay_npn.c | 42 ++++++++++++++++++++++ tests/Makefile.am | 10 +++--- tests/main.c | 4 ++- tests/spdylay_npn_test.c | 65 ++++++++++++++++++++++++++++++++++ tests/spdylay_npn_test.h | 30 ++++++++++++++++ 9 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 lib/spdylay_npn.c create mode 100644 tests/spdylay_npn_test.c create mode 100644 tests/spdylay_npn_test.h diff --git a/.gitignore b/.gitignore index 8148a19..c95b9e7 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ stamp-h1 .deps/ INSTALL .DS_STORE +tests/main diff --git a/examples/spdylay_ssl.cc b/examples/spdylay_ssl.cc index aef167d..f20cdbf 100644 --- a/examples/spdylay_ssl.cc +++ b/examples/spdylay_ssl.cc @@ -328,23 +328,15 @@ int select_next_proto_cb(SSL* ssl, const unsigned char *in, unsigned int inlen, void *arg) { - *out = (unsigned char*)in+1; - *outlen = in[0]; + if (spdylay_select_next_protocol(out, outlen, in, inlen) == 0) { + std::cerr << "Invalid protocol: " + << std::string((const char*)*out, (size_t)*outlen) << std::endl; + abort(); + } if(ssl_debug) { print_timer(); - std::cout << " NPN select next protocol: the remote server offers:" - << std::endl; - } - for(unsigned int i = 0; i < inlen; i += in[i]+1) { - if(ssl_debug) { - std::cout << " * "; - std::cout.write(reinterpret_cast(&in[i+1]), in[i]); - std::cout << std::endl; - } - if(in[i] == 6 && memcmp(&in[i+1], "spdy/2", in[i]) == 0) { - *out = (unsigned char*)in+i+1; - *outlen = in[i]; - } + std::cout << " NPN selected the protocol: " + << std::string((const char*)*out, (size_t)*outlen) << std::endl; } return SSL_TLSEXT_ERR_OK; } diff --git a/lib/Makefile.am b/lib/Makefile.am index d57c46f..aa3069f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -33,7 +33,7 @@ lib_LTLIBRARIES = libspdylay.la OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \ spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \ - spdylay_session.c spdylay_helper.c spdylay_stream.c + spdylay_session.c spdylay_helper.c spdylay_stream.c spdylay_npn.c HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \ spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \ diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 36074e6..6cb4840 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -406,6 +406,24 @@ int spdylay_submit_ping(spdylay_session *session); */ int spdylay_submit_goaway(spdylay_session *session); +/* A helper function for dealing with NPN. Returns the version of spdy that + * was negotiated. To use this method you should do something like: + * static int select_next_proto_cb(SSL* ssl, + * unsigned char **out, unsigned char *outlen, + * const unsigned char *in, unsigned int inlen, + * void *arg) + * { + * if (spdylay_select_next_protocol(out, outlen, in, inlen) > 0) { + * ((MyType*)arg)->spdy = 1; + * } + * return SSL_TLSEXT_ERR_OK; + * } + * ... + * SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj); + */ +int spdylay_select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen); + #ifdef __cplusplus } #endif diff --git a/lib/spdylay_npn.c b/lib/spdylay_npn.c new file mode 100644 index 0000000..3bd43c6 --- /dev/null +++ b/lib/spdylay_npn.c @@ -0,0 +1,42 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +int spdylay_select_next_protocol(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen) +{ + unsigned int i = 0; + for(; i < inlen; i += in[i]+1) { + /* Always assign to *out so that the last one is picked. */ + *out = (unsigned char*)in+i+1; + *outlen = in[i]; + if(in[i] == 6 && memcmp(&in[i+1], "spdy/2", in[i]) == 0) { + return 2; + } + } + return 0; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 5f2884d..c77a8f7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -27,17 +27,17 @@ check_PROGRAMS = main OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \ spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \ - spdylay_frame_test.c + spdylay_frame_test.c spdylay_npn_test.c HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \ spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \ - spdylay_frame_test.h + spdylay_frame_test.h spdylay_npn_test.h main_SOURCES = $(HFILES) $(OBJECTS) -main_LDADD = ${top_builddir}/lib/libspdylay.la -lcunit -main_LDFLAGS = -static -AM_CFLAGS = -Wall -g -O2 -I${top_srcdir}/lib -I${top_srcdir}/lib/includes +main_LDADD = ${top_builddir}/lib/libspdylay.la +main_LDFLAGS = -static `pkg-config --libs cunit` -lncurses +AM_CFLAGS = -Wall -g -O2 -I${top_srcdir}/lib -I${top_srcdir}/lib/includes `pkg-config --cflags cunit` TESTS = main endif # HAVE_CUNIT diff --git a/tests/main.c b/tests/main.c index 76d199f..1046cf0 100644 --- a/tests/main.c +++ b/tests/main.c @@ -33,6 +33,7 @@ #include "spdylay_zlib_test.h" #include "spdylay_session_test.h" #include "spdylay_frame_test.h" +#include "spdylay_npn_test.h" int init_suite1(void) { @@ -45,7 +46,7 @@ int clean_suite1(void) } -int main() +int main(int argc, char* argv[]) { CU_pSuite pSuite = NULL; @@ -66,6 +67,7 @@ int main() !CU_add_test(pSuite, "queue", test_spdylay_queue) || !CU_add_test(pSuite, "buffer", test_spdylay_buffer) || !CU_add_test(pSuite, "zlib", test_spdylay_zlib) || + !CU_add_test(pSuite, "npn", test_spdylay_npn) || !CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) || !CU_add_test(pSuite, "session_recv_invalid_stream_id", test_spdylay_session_recv_invalid_stream_id) || diff --git a/tests/spdylay_npn_test.c b/tests/spdylay_npn_test.c new file mode 100644 index 0000000..e262855 --- /dev/null +++ b/tests/spdylay_npn_test.c @@ -0,0 +1,65 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Twist Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +static void spdy2() +{ + const unsigned char spdy[] = { + 8, 'h', 't', 't', 'p', '/', '1', '.', '0', + 6, 's', 'p', 'd', 'y', '/', '2', + 6, 's', 'p', 'd', 'y', '/', '3' + }; + unsigned char outlen; + unsigned char* out; + CU_ASSERT(2 == spdylay_select_next_protocol(&out, &outlen, + spdy, sizeof(spdy))); + CU_ASSERT(6 == outlen); + CU_ASSERT(memcmp("spdy/2", out, 6) == 0); +} + +static void spdy4() +{ + const unsigned char spdy[] = { + 6, 's', 'p', 'd', 'y', '/', '4', + 8, 's', 'p', 'd', 'y', '/', '2', '.', '1', + 8, 'h', 't', 't', 'p', '/', '1', '.', '0', + }; + unsigned char outlen; + unsigned char* out; + CU_ASSERT(0 == spdylay_select_next_protocol(&out, &outlen, + spdy, sizeof(spdy))); + CU_ASSERT(8 == outlen); + CU_ASSERT(memcmp("http/1.0", out, outlen) == 0); +} + +void test_spdylay_npn() +{ + spdy2(); + spdy4(); +} + diff --git a/tests/spdylay_npn_test.h b/tests/spdylay_npn_test.h new file mode 100644 index 0000000..59a6c45 --- /dev/null +++ b/tests/spdylay_npn_test.h @@ -0,0 +1,30 @@ +/* + * Spdylay - SPDY Library + * + * Copyright (c) 2012 Twist Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SPDYLAY_NPN_TEST_H +#define SPDYLAY_NPN_TEST_H + +void test_spdylay_npn(); + +#endif // SPDYLAY_NPN_TEST_H