diff --git a/examples/spdycat.cc b/examples/spdycat.cc index ac8718f0..f0512fdb 100644 --- a/examples/spdycat.cc +++ b/examples/spdycat.cc @@ -350,6 +350,7 @@ int run(char **uris, int n) callbacks.on_ctrl_send_callback = on_ctrl_send_callback3; callbacks.on_ctrl_recv_parse_error_callback = on_ctrl_recv_parse_error_callback; + callbacks.on_unknown_ctrl_recv_callback = on_unknown_ctrl_recv_callback; } else { callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback2; callbacks.on_ctrl_send_callback = on_ctrl_send_callback2; diff --git a/examples/spdylay_ssl.cc b/examples/spdylay_ssl.cc index fe5ad23d..56a57215 100644 --- a/examples/spdylay_ssl.cc +++ b/examples/spdylay_ssl.cc @@ -414,6 +414,19 @@ const char* spdylay_strerror(int error_code) }; } // namespace +namespace { +void dump_header(const uint8_t *head, size_t headlen) +{ + size_t i; + print_frame_attr_indent(); + printf("Header dump: "); + for(i = 0; i < headlen; ++i) { + printf("%02X ", head[i]); + } + printf("\n"); +} +} // namespace + void on_ctrl_recv_parse_error_callback(spdylay_session *session, spdylay_frame_type type, const uint8_t *head, @@ -422,16 +435,23 @@ void on_ctrl_recv_parse_error_callback(spdylay_session *session, size_t payloadlen, int error_code, void *user_data) { - size_t i; print_timer(); printf(" recv %s frame: Parse error [%s]\n", ctrl_names[type-1], spdylay_strerror(error_code)); - print_frame_attr_indent(); - printf("Header dump: "); - for(i = 0; i < headlen; ++i) { - printf("%02X ", head[i]); - } - printf("\n"); + dump_header(head, headlen); + fflush(stdout); +} + +void on_unknown_ctrl_recv_callback(spdylay_session *session, + const uint8_t *head, + size_t headlen, + const uint8_t *payload, + size_t payloadlen, + void *user_data) +{ + print_timer(); + printf(" recv unknown frame\n"); + dump_header(head, headlen); fflush(stdout); } diff --git a/examples/spdylay_ssl.h b/examples/spdylay_ssl.h index 00664c58..e37ff0d4 100644 --- a/examples/spdylay_ssl.h +++ b/examples/spdylay_ssl.h @@ -93,6 +93,13 @@ void on_ctrl_recv_parse_error_callback(spdylay_session *session, size_t payloadlen, int error_code, void *user_data); +void on_unknown_ctrl_recv_callback(spdylay_session *session, + const uint8_t *head, + size_t headlen, + const uint8_t *payload, + size_t payloadlen, + void *user_data); + void on_ctrl_send_callback (spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame, void *user_data); diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 8ef664ed..a5b2967d 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -978,6 +978,24 @@ typedef void (*spdylay_on_ctrl_recv_parse_error_callback) const uint8_t *payload, size_t payloadlen, int error_code, void *user_data); +/** + * @functypedef + * + * Callback function invoked when the received control frame type is + * unknown. The |head| is the pointer to the header of the received + * frame. The |headlen| is the length of the |head|. According to the + * SPDY spec, the |headlen| is always 8. In other words, the |head| is + * the first 8 bytes of the received frame. The |payload| is the + * pointer to the data portion of the received frame. The + * |payloadlen| is the length of the |payload|. This is the data after + * the length field. + */ +typedef void (*spdylay_on_unknown_ctrl_recv_callback) +(spdylay_session *session, + const uint8_t *head, size_t headlen, + const uint8_t *payload, size_t payloadlen, + void *user_data); + #define SPDYLAY_MAX_SCHEME 255 #define SPDYLAY_MAX_HOSTNAME 255 @@ -1143,6 +1161,11 @@ typedef struct { * could not be parsed correctly. */ spdylay_on_ctrl_recv_parse_error_callback on_ctrl_recv_parse_error_callback; + /** + * Callback function invoked when the received control frame type is + * unknown. + */ + spdylay_on_unknown_ctrl_recv_callback on_unknown_ctrl_recv_callback; } spdylay_session_callbacks; /** @@ -1404,6 +1427,9 @@ int spdylay_session_send(spdylay_session *session); * 3.4. If the received frame could not be unpacked correctly, * :member:`spdylay_session_callbacks.on_ctrl_recv_parse_error_callback` * is invoked. + * 3.5. If the received frame type is unknown, + * :member:`spdylay_session_callbacks.on_unknown_ctrl_recv_callback` + * is invoked. * * This function returns 0 if it succeeds, or one of the following * negative error codes: diff --git a/lib/spdylay_session.c b/lib/spdylay_session.c index e1fdc175..7811c78b 100644 --- a/lib/spdylay_session.c +++ b/lib/spdylay_session.c @@ -2199,6 +2199,17 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; + default: + /* Unknown frame */ + if(session->callbacks.on_unknown_ctrl_recv_callback) { + session->callbacks.on_unknown_ctrl_recv_callback + (session, + session->iframe.headbuf, + sizeof(session->iframe.headbuf), + session->iframe.buf, + session->iframe.len, + session->user_data); + } } if(spdylay_is_fatal(r)) { return r;