From 171bede1fadf8ed3dde42386c4c3903eeb0d5edc Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 9 May 2012 21:55:21 +0900 Subject: [PATCH] Added spdylay_session_on_ctrl_recv_parse_error_callback. This callback function is invoked when the received frame data could not be parsed correctly. Added debug output using this callback to spdycat. --- examples/spdycat.cc | 2 ++ examples/spdylay_ssl.cc | 28 ++++++++++++++++++++++++++++ examples/spdylay_ssl.h | 8 ++++++++ lib/includes/spdylay/spdylay.h | 29 +++++++++++++++++++++++++++++ lib/spdylay_session.c | 26 ++++++++++++++++++++++++++ 5 files changed, 93 insertions(+) diff --git a/examples/spdycat.cc b/examples/spdycat.cc index aabecc75..ac8718f0 100644 --- a/examples/spdycat.cc +++ b/examples/spdycat.cc @@ -348,6 +348,8 @@ int run(char **uris, int n) callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback3; callbacks.on_data_recv_callback = on_data_recv_callback; callbacks.on_ctrl_send_callback = on_ctrl_send_callback3; + callbacks.on_ctrl_recv_parse_error_callback = + on_ctrl_recv_parse_error_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 c565ea46..fe5ad23d 100644 --- a/examples/spdylay_ssl.cc +++ b/examples/spdylay_ssl.cc @@ -407,6 +407,34 @@ void on_ctrl_recv_callback fflush(stdout); } +namespace { +const char* spdylay_strerror(int error_code) +{ + return "UNKNOWN"; +}; +} // namespace + +void on_ctrl_recv_parse_error_callback(spdylay_session *session, + spdylay_frame_type type, + const uint8_t *head, + size_t headlen, + const uint8_t *payload, + 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"); + fflush(stdout); +} + void on_ctrl_send_callback (spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame, void *user_data) diff --git a/examples/spdylay_ssl.h b/examples/spdylay_ssl.h index 5d44ff23..00664c58 100644 --- a/examples/spdylay_ssl.h +++ b/examples/spdylay_ssl.h @@ -85,6 +85,14 @@ void on_ctrl_recv_callback (spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame, void *user_data); +void on_ctrl_recv_parse_error_callback(spdylay_session *session, + spdylay_frame_type type, + const uint8_t *head, + size_t headlen, + const uint8_t *payload, + size_t payloadlen, + int error_code, 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 3c7d260e..8ef664ed 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -957,6 +957,27 @@ typedef void (*spdylay_on_stream_close_callback) typedef void (*spdylay_on_request_recv_callback) (spdylay_session *session, int32_t stream_id, void *user_data); +/** + * @functypedef + * + * Callback function invoked when the received control frame octets + * could not be parsed correctly. The |type| indicates the type of + * received control frame. 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. The |error_code| is one of the + * error code defined in :enum:`spdylay_error` and indicates the + * error. + */ +typedef void (*spdylay_on_ctrl_recv_parse_error_callback) +(spdylay_session *session, spdylay_frame_type type, + const uint8_t *head, size_t headlen, + const uint8_t *payload, size_t payloadlen, + int error_code, void *user_data); + #define SPDYLAY_MAX_SCHEME 255 #define SPDYLAY_MAX_HOSTNAME 255 @@ -1117,6 +1138,11 @@ typedef struct { * certificate. */ spdylay_get_credential_cert get_credential_cert; + /** + * Callback function invoked when the received control frame octets + * could not be parsed correctly. + */ + spdylay_on_ctrl_recv_parse_error_callback on_ctrl_recv_parse_error_callback; } spdylay_session_callbacks; /** @@ -1375,6 +1401,9 @@ int spdylay_session_send(spdylay_session *session); * invalid, * :member:`spdylay_session_callbacks.on_invalid_ctrl_recv_callback` * is invoked. + * 3.4. If the received frame could not be unpacked correctly, + * :member:`spdylay_session_callbacks.on_ctrl_recv_parse_error_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 fcb80402..e1fdc175 100644 --- a/lib/spdylay_session.c +++ b/lib/spdylay_session.c @@ -2004,6 +2004,23 @@ int spdylay_session_on_headers_received(spdylay_session *session, return r; } +static void spdylay_session_handle_parse_error(spdylay_session *session, + spdylay_frame_type type, + int error_code) +{ + if(session->callbacks.on_ctrl_recv_parse_error_callback) { + session->callbacks.on_ctrl_recv_parse_error_callback + (session, + type, + session->iframe.headbuf, + sizeof(session->iframe.headbuf), + session->iframe.buf, + session->iframe.len, + error_code, + session->user_data); + } +} + /* For errors, this function only returns FATAL error. */ static int spdylay_session_process_ctrl_frame(spdylay_session *session) { @@ -2038,6 +2055,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) SPDYLAY_PROTOCOL_ERROR); spdylay_frame_syn_stream_free(&frame.syn_stream); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2064,6 +2082,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) SPDYLAY_PROTOCOL_ERROR); spdylay_frame_syn_reply_free(&frame.syn_reply); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2077,6 +2096,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_rst_stream_received(session, &frame); spdylay_frame_rst_stream_free(&frame.rst_stream); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2090,6 +2110,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_settings_received(session, &frame); spdylay_frame_settings_free(&frame.settings); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2105,6 +2126,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_ping_received(session, &frame); spdylay_frame_ping_free(&frame.ping); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2118,6 +2140,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_goaway_received(session, &frame); spdylay_frame_goaway_free(&frame.goaway); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2144,6 +2167,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) SPDYLAY_PROTOCOL_ERROR); spdylay_frame_headers_free(&frame.headers); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2157,6 +2181,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_window_update_received(session, &frame); spdylay_frame_window_update_free(&frame.window_update); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break; @@ -2170,6 +2195,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session) r = spdylay_session_on_credential_received(session, &frame); spdylay_frame_credential_free(&frame.credential); } else if(spdylay_is_non_fatal(r)) { + spdylay_session_handle_parse_error(session, type, r); r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR); } break;