char const *sql_info_2_str(struct proto_info const *info_) { struct sql_proto_info const *info = DOWNCAST(info_, info, sql_proto_info); char *str = tempstr(); char const *(*spec_info_2_str)(struct sql_proto_info const *) = NULL; switch (info->msg_type) { case SQL_UNKNOWN: break; case SQL_STARTUP: spec_info_2_str = info->is_query ? startup_query_2_str : startup_reply_2_str; break; case SQL_QUERY: spec_info_2_str = info->is_query ? query_query_2_str : query_reply_2_str; break; case SQL_EXIT: spec_info_2_str = exit_2_str; break; } snprintf(str, TEMPSTR_SIZE, "%s, %s%s, %s%s%s%s%s%s%s%s%s%s", proto_info_2_str(info_), info->is_query ? "Clt->Srv" : "Srv->Clt", version_info_2_str(info), sql_msg_type_2_str(info->msg_type), spec_info_2_str ? spec_info_2_str(info) : "", info->set_values & SQL_REQUEST_STATUS ? ", Status=" : "", info->set_values & SQL_REQUEST_STATUS ? sql_request_status_2_str(info->request_status) : "", info->set_values & SQL_ERROR_SQL_STATUS ? ", SqlCode=" : "", info->set_values & SQL_ERROR_SQL_STATUS ? info->error_sql_status : "", info->set_values & SQL_ERROR_CODE ? ", ErrorCode=" : "", info->set_values & SQL_ERROR_CODE ? info->error_code : "", info->set_values & SQL_ERROR_MESSAGE ? ", ErrorMessage=" : "", info->set_values & SQL_ERROR_MESSAGE ? info->error_message : ""); return str; }
/* * | 2 bytes | 1 byte | Variable | * | Flags | TTC code | TTC body | */ static enum proto_parse_status tns_parse_data(struct tns_parser *tns_parser, struct sql_proto_info *info, struct cursor *cursor, unsigned way) { SLOG(LOG_DEBUG, "Parsing TNS data PDU of size %zu", cursor->cap_len); enum proto_parse_status status = PROTO_OK; // First, read the data flags CHECK(2); unsigned flags = cursor_read_u16n(cursor); SLOG(LOG_DEBUG, "Data flags = 0x%x", flags); if (flags & 0x40) { // End Of File if (cursor->cap_len != 0) return PROTO_PARSE_ERR; // This may be wrong, maybe a command is allowed anyway info->msg_type = SQL_EXIT; sql_set_request_status(info, SQL_REQUEST_COMPLETE); return PROTO_OK; } info->msg_type = tns_parser->msg_type; while (status == PROTO_OK && cursor->cap_len) { CHECK(1); enum ttc_code ttc_code = cursor_read_u8(cursor); SLOG(LOG_DEBUG, "Ttc code = 0x%02x, msg type %s", ttc_code, sql_msg_type_2_str(tns_parser->msg_type)); switch (ttc_code) { case TTC_ROW_PREFIX: status = tns_parse_row_prefix(tns_parser, info, cursor); break; case TTC_ROW_DATA: status = tns_parse_row_data(tns_parser, info, cursor); break; case TTC_ROW_DESCRIPTION_PREFIX: status = tns_parse_row_description_prefix(tns_parser, info, cursor); break; case TTC_ROW_RECAP: status = tns_parse_row_recap(cursor); break; case TTC_ROW_DESCRIPTION: status = tns_parse_row_description(cursor); break; case TTC_LOGIN_PROPERTY: status = tns_parse_login_property(info, cursor); break; case TTC_QUERY: status = tns_parse_query(tns_parser, info, cursor); break; case TTC_END_MESSAGE: status = tns_parse_end(info, cursor); break; case TTC_CLOSE: status = tns_parse_close_statement(cursor); break; default: SLOG(LOG_DEBUG, "Unknown ttc_code = %u", ttc_code); return PROTO_OK; } if (status == PROTO_OK) { enum sql_msg_type ttc_msg_type = ttc_to_msg_type(tns_parser, ttc_code); if (ttc_msg_type != SQL_UNKNOWN) { info->msg_type = ttc_msg_type; tns_parser->msg_type = ttc_msg_type; } // Fix c2s_way bool old_c2s_way = tns_parser->c2s_way; switch (ttc_code) { case TTC_ROW_DESCRIPTION_PREFIX: case TTC_ROW_RECAP: case TTC_ROW_DESCRIPTION: case TTC_END_MESSAGE: tns_parser->c2s_way = !way; break; case TTC_QUERY: case TTC_CLOSE: tns_parser->c2s_way = way; break; default: break; } if (old_c2s_way != tns_parser->c2s_way) { SLOG(LOG_DEBUG, "Fix c2s way from %d to %d", old_c2s_way, tns_parser->c2s_way); } info->is_query = way == tns_parser->c2s_way; } } return status; }