diff --git a/.gitignore b/.gitignore index 8aa755ba..c95b9e71 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ ltmain.sh stamp-h1 .deps/ INSTALL +.DS_STORE +tests/main diff --git a/examples/spdylay_ssl.cc b/examples/spdylay_ssl.cc index dbfab616..587f0569 100644 --- a/examples/spdylay_ssl.cc +++ b/examples/spdylay_ssl.cc @@ -346,8 +346,6 @@ 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(ssl_debug) { print_timer(); std::cout << " NPN select next protocol: the remote server offers:" @@ -359,10 +357,15 @@ int select_next_proto_cb(SSL* ssl, 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]; - } + } + if(spdylay_select_next_protocol(out, outlen, in, inlen) == -1) { + std::cerr << "Invalid protocol: " + << std::string((const char*)*out, (size_t)*outlen) << std::endl; + abort(); + } + if(ssl_debug) { + 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 d57c46f9..24ea437a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -33,11 +33,12 @@ 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 \ - spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h + spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h \ + spdylay_npn.h libspdylay_la_SOURCES = $(HFILES) $(OBJECTS) libspdylay_la_LDFLAGS = -no-undefined \ diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 117d48cd..c4e0a74c 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -414,6 +414,27 @@ int spdylay_submit_ping(spdylay_session *session); */ int spdylay_submit_goaway(spdylay_session *session); +/* + * A helper function for dealing with NPN. This function returns the + * version of spdy that was negotiated, or -1. 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 00000000..28158bfd --- /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 "spdylay_npn.h" + +#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 -1; +} diff --git a/lib/spdylay_npn.h b/lib/spdylay_npn.h new file mode 100644 index 00000000..8d60c9d8 --- /dev/null +++ b/lib/spdylay_npn.h @@ -0,0 +1,34 @@ +/* + * 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. + */ +#ifndef SPDYLAY_NPN_H +#define SPDYLAY_NPN_H + +#ifdef HAVE_CONFIG +# include +#endif /* HAVE_CONFIG */ + +#include + +#endif /* SPDYLAY_NPN_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index dc9f084a..18b4a779 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -27,17 +27,18 @@ 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_stream_test.c + spdylay_frame_test.c spdylay_stream_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_stream_test.h + spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h main_SOURCES = $(HFILES) $(OBJECTS) -main_LDADD = ${top_builddir}/lib/libspdylay.la -lcunit -main_LDFLAGS = -static +main_LDADD = ${top_builddir}/lib/libspdylay.la +main_LDFLAGS = -static -lcunit -lncurses AM_CFLAGS = -Wall -g -O2 -I${top_srcdir}/lib -I${top_srcdir}/lib/includes + TESTS = main endif # HAVE_CUNIT diff --git a/tests/main.c b/tests/main.c index b3c72bc4..7a8fe9ca 100644 --- a/tests/main.c +++ b/tests/main.c @@ -34,6 +34,7 @@ #include "spdylay_session_test.h" #include "spdylay_frame_test.h" #include "spdylay_stream_test.h" +#include "spdylay_npn_test.h" int init_suite1(void) { @@ -46,7 +47,7 @@ int clean_suite1(void) } -int main() +int main(int argc, char* argv[]) { CU_pSuite pSuite = NULL; @@ -67,6 +68,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 00000000..1a358a37 --- /dev/null +++ b/tests/spdylay_npn_test.c @@ -0,0 +1,64 @@ +/* + * 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(-1 == 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 00000000..59a6c454 --- /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