diff --git a/include/maxscale/mysql_utils.hh b/include/maxscale/mysql_utils.hh index 39777bff2..bdb925bf5 100644 --- a/include/maxscale/mysql_utils.hh +++ b/include/maxscale/mysql_utils.hh @@ -19,17 +19,6 @@ #include #include -MXS_BEGIN_DECLS - -/** Length-encoded integers */ -size_t mxs_leint_bytes(const uint8_t* ptr); -uint64_t mxs_leint_value(const uint8_t* c); -uint64_t mxs_leint_consume(uint8_t** c); - -/** Length-encoded strings */ -char* mxs_lestr_consume_dup(uint8_t** c); -char* mxs_lestr_consume(uint8_t** c, size_t* size); - /** * Creates a connection to a MySQL database engine. If necessary, initializes SSL. * @@ -141,5 +130,3 @@ std::unique_ptr execute_query(MYSQL* conn, const std::string& std::string* errmsg_out = nullptr, unsigned int* errno_out = nullptr); } - -MXS_END_DECLS diff --git a/maxutils/maxsql/include/maxsql/mariadb.hh b/maxutils/maxsql/include/maxsql/mariadb.hh index 15b1113f4..ebdda1bf5 100644 --- a/maxutils/maxsql/include/maxsql/mariadb.hh +++ b/maxutils/maxsql/include/maxsql/mariadb.hh @@ -211,4 +211,14 @@ private: mutable ConversionError m_error; /**< Error information */ std::unordered_map m_col_indexes; /**< Map of column name -> index */ }; + +/** Length-encoded integers */ +size_t leint_bytes(const uint8_t* ptr); +uint64_t leint_value(const uint8_t* c); +uint64_t leint_consume(uint8_t** c); + +/** Length-encoded strings */ +char* lestr_consume_dup(uint8_t** c); +char* lestr_consume(uint8_t** c, size_t* size); + } diff --git a/maxutils/maxsql/include/maxsql/mysql_plus.hh b/maxutils/maxsql/include/maxsql/mysql_plus.hh index 43b61a996..1e04de183 100644 --- a/maxutils/maxsql/include/maxsql/mysql_plus.hh +++ b/maxutils/maxsql/include/maxsql/mysql_plus.hh @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ public: */ LEncInt(uint8_t* pData) { - m_value = mxs_leint_value(pData); + m_value = leint_value(pData); } /** @@ -52,8 +53,8 @@ public: */ LEncInt(uint8_t** ppData) { - size_t nBytes = mxs_leint_bytes(*ppData); - m_value = mxs_leint_value(*ppData); + size_t nBytes = leint_bytes(*ppData); + m_value = leint_value(*ppData); *ppData += nBytes; } @@ -229,7 +230,7 @@ public: // NULL is sent as 0xfb. See https://dev.mysql.com/doc/internals/en/com-query-response.html if (*pData != 0xfb) { - m_pString = mxs_lestr_consume(&pData, &m_length); + m_pString = lestr_consume(&pData, &m_length); } else { @@ -250,7 +251,7 @@ public: // NULL is sent as 0xfb. See https://dev.mysql.com/doc/internals/en/com-query-response.html if (**ppData != 0xfb) { - m_pString = mxs_lestr_consume(ppData, &m_length); + m_pString = lestr_consume(ppData, &m_length); } else { diff --git a/maxutils/maxsql/src/mariadb.cc b/maxutils/maxsql/src/mariadb.cc index e3bd86e56..fe7c3e6e9 100644 --- a/maxutils/maxsql/src/mariadb.cc +++ b/maxutils/maxsql/src/mariadb.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -333,4 +334,121 @@ bool QueryResult::ConversionError::error() const { return !m_target_type.empty(); } + + +/** + * @brief Calculate the length of a length-encoded integer in bytes + * + * @param ptr Start of the length encoded value + * @return Number of bytes before the actual value + */ +size_t leint_bytes(const uint8_t* ptr) +{ + uint8_t val = *ptr; + if (val < 0xfb) + { + return 1; + } + else if (val == 0xfc) + { + return 3; + } + else if (val == 0xfd) + { + return 4; + } + else + { + return 9; + } +} + +/** + * @brief Converts a length-encoded integer to @c uint64_t + * + * @see https://dev.mysql.com/doc/internals/en/integer.html + * @param c Pointer to the first byte of a length-encoded integer + * @return The value converted to a standard unsigned integer + */ +uint64_t leint_value(const uint8_t* c) +{ + uint64_t sz = 0; + if (*c < 0xfb) + { + sz = *c; + } + else if (*c == 0xfc) + { + memcpy(&sz, c + 1, 2); + } + else if (*c == 0xfd) + { + memcpy(&sz, c + 1, 3); + } + else if (*c == 0xfe) + { + memcpy(&sz, c + 1, 8); + } + else + { + mxb_assert(*c == 0xff); + MXB_ERROR("Unexpected length encoding '%x' encountered when reading length-encoded integer.", *c); + } + return sz; +} + +/** + * Converts a length-encoded integer into a standard unsigned integer + * and advances the pointer to the next unrelated byte. + * + * @param c Pointer to the first byte of a length-encoded integer + */ +uint64_t leint_consume(uint8_t** c) +{ + uint64_t rval = leint_value(*c); + *c += leint_bytes(*c); + return rval; +} + +/** + * @brief Consume and duplicate a length-encoded string + * + * Converts a length-encoded string to a C string and advances the pointer to + * the first byte after the string. The caller is responsible for freeing + * the returned string. + * @param c Pointer to the first byte of a valid packet. + * @return The newly allocated string or NULL if memory allocation failed + */ +char* lestr_consume_dup(uint8_t** c) +{ + uint64_t slen = leint_consume(c); + char* str = (char*)MXS_MALLOC((slen + 1) * sizeof(char)); + + if (str) + { + memcpy(str, *c, slen); + str[slen] = '\0'; + *c += slen; + } + + return str; +} + +/** + * @brief Consume a length-encoded string + * + * Converts length-encoded strings to character strings and advanced + * the pointer to the next unrelated byte. + * @param c Pointer to the start of the length-encoded string + * @param size Pointer to a variable where the size of the string is stored + * @return Pointer to the start of the string + */ +char* lestr_consume(uint8_t** c, size_t* size) +{ + uint64_t slen = leint_consume(c); + *size = slen; + char* start = (char*) *c; + *c += slen; + return start; +} } diff --git a/server/core/modutil.cc b/server/core/modutil.cc index b88d372f9..94ffff475 100644 --- a/server/core/modutil.cc +++ b/server/core/modutil.cc @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -730,8 +731,8 @@ int modutil_count_signal_packets(GWBUF* reply, int n_found, bool* more_out, modu gwbuf_copy_data(reply, offset + MYSQL_HEADER_LEN + 1, sizeof(data), data); uint8_t* ptr = data; - ptr += mxs_leint_bytes(ptr); - ptr += mxs_leint_bytes(ptr); + ptr += mxq::leint_bytes(ptr); + ptr += mxq::leint_bytes(ptr); uint16_t* status = (uint16_t*)ptr; more = (*status) & SERVER_MORE_RESULTS_EXIST; diff --git a/server/core/mysql_utils.cc b/server/core/mysql_utils.cc index 0f4c1be53..beb97ffa9 100644 --- a/server/core/mysql_utils.cc +++ b/server/core/mysql_utils.cc @@ -33,126 +33,6 @@ #include #include -/** - * @brief Calculate the length of a length-encoded integer in bytes - * - * @param ptr Start of the length encoded value - * @return Number of bytes before the actual value - */ -size_t mxs_leint_bytes(const uint8_t* ptr) -{ - uint8_t val = *ptr; - if (val < 0xfb) - { - return 1; - } - else if (val == 0xfc) - { - return 3; - } - else if (val == 0xfd) - { - return 4; - } - else - { - return 9; - } -} - -/** - * @brief Converts a length-encoded integer to @c uint64_t - * - * @see https://dev.mysql.com/doc/internals/en/integer.html - * @param c Pointer to the first byte of a length-encoded integer - * @return The value converted to a standard unsigned integer - */ -uint64_t mxs_leint_value(const uint8_t* c) -{ - uint64_t sz = 0; - - if (*c < 0xfb) - { - sz = *c; - } - else if (*c == 0xfc) - { - memcpy(&sz, c + 1, 2); - } - else if (*c == 0xfd) - { - memcpy(&sz, c + 1, 3); - } - else if (*c == 0xfe) - { - memcpy(&sz, c + 1, 8); - } - else - { - mxb_assert(*c == 0xff); - MXS_ERROR("Unexpected length encoding '%x' encountered when reading " - "length-encoded integer.", - *c); - } - - return sz; -} - -/** - * Converts a length-encoded integer into a standard unsigned integer - * and advances the pointer to the next unrelated byte. - * - * @param c Pointer to the first byte of a length-encoded integer - */ -uint64_t mxs_leint_consume(uint8_t** c) -{ - uint64_t rval = mxs_leint_value(*c); - *c += mxs_leint_bytes(*c); - return rval; -} - -/** - * @brief Consume and duplicate a length-encoded string - * - * Converts a length-encoded string to a C string and advances the pointer to - * the first byte after the string. The caller is responsible for freeing - * the returned string. - * @param c Pointer to the first byte of a valid packet. - * @return The newly allocated string or NULL if memory allocation failed - */ -char* mxs_lestr_consume_dup(uint8_t** c) -{ - uint64_t slen = mxs_leint_consume(c); - char* str = (char*)MXS_MALLOC((slen + 1) * sizeof(char)); - - if (str) - { - memcpy(str, *c, slen); - str[slen] = '\0'; - *c += slen; - } - - return str; -} - -/** - * @brief Consume a length-encoded string - * - * Converts length-encoded strings to character strings and advanced - * the pointer to the next unrelated byte. - * @param c Pointer to the start of the length-encoded string - * @param size Pointer to a variable where the size of the string is stored - * @return Pointer to the start of the string - */ -char* mxs_lestr_consume(uint8_t** c, size_t* size) -{ - uint64_t slen = mxs_leint_consume(c); - *size = slen; - char* start = (char*) *c; - *c += slen; - return start; -} - MYSQL* mxs_mysql_real_connect(MYSQL* con, SERVER* server, const char* user, const char* passwd) { auto ssl = server->ssl().config(); diff --git a/server/modules/filter/cache/cachefiltersession.cc b/server/modules/filter/cache/cachefiltersession.cc index 7270a83e7..897a7f553 100644 --- a/server/modules/filter/cache/cachefiltersession.cc +++ b/server/modules/filter/cache/cachefiltersession.cc @@ -573,7 +573,7 @@ int CacheFilterSession::handle_expecting_response() { // mxs_leint_bytes() returns the length of the int type field + the size of the // integer. - size_t n_bytes = mxs_leint_bytes(&header[4]); + size_t n_bytes = mxq::leint_bytes(&header[4]); if (MYSQL_HEADER_LEN + n_bytes <= buflen) { @@ -581,7 +581,7 @@ int CacheFilterSession::handle_expecting_response() // need to copy some more data. copy_data(MYSQL_HEADER_LEN + 1, n_bytes - 1, &header[MYSQL_HEADER_LEN + 1]); - m_res.nTotalFields = mxs_leint_value(&header[4]); + m_res.nTotalFields = mxq::leint_value(&header[4]); m_res.offset = MYSQL_HEADER_LEN + n_bytes; m_state = CACHE_EXPECTING_FIELDS; diff --git a/server/modules/filter/masking/mysql.hh b/server/modules/filter/masking/mysql.hh index 0dbea0cc2..6a2bff141 100644 --- a/server/modules/filter/masking/mysql.hh +++ b/server/modules/filter/masking/mysql.hh @@ -37,7 +37,7 @@ public: */ LEncInt(uint8_t* pData) { - m_value = mxs_leint_value(pData); + m_value = mxq::leint_value(pData); } /** @@ -49,8 +49,8 @@ public: */ LEncInt(uint8_t** ppData) { - size_t nBytes = mxs_leint_bytes(*ppData); - m_value = mxs_leint_value(*ppData); + size_t nBytes = mxq::leint_bytes(*ppData); + m_value = mxq::leint_value(*ppData); *ppData += nBytes; } @@ -226,7 +226,7 @@ public: // NULL is sent as 0xfb. See https://dev.mysql.com/doc/internals/en/com-query-response.html if (*pData != 0xfb) { - m_pString = mxs_lestr_consume(&pData, &m_length); + m_pString = mxq::lestr_consume(&pData, &m_length); } else { @@ -247,7 +247,7 @@ public: // NULL is sent as 0xfb. See https://dev.mysql.com/doc/internals/en/com-query-response.html if (**ppData != 0xfb) { - m_pString = mxs_lestr_consume(ppData, &m_length); + m_pString = mxq::lestr_consume(ppData, &m_length); } else { diff --git a/server/modules/filter/maxrows/maxrows.cc b/server/modules/filter/maxrows/maxrows.cc index a8965c0cc..cafa456bd 100644 --- a/server/modules/filter/maxrows/maxrows.cc +++ b/server/modules/filter/maxrows/maxrows.cc @@ -768,7 +768,7 @@ static int handle_expecting_response(MAXROWS_SESSION_DATA* csdata) { // mxs_leint_bytes() returns the length of the int type field + the size of the // integer. - size_t n_bytes = mxs_leint_bytes(&header[4]); + size_t n_bytes = mxq::leint_bytes(&header[4]); if (MYSQL_HEADER_LEN + n_bytes <= buflen) { @@ -779,7 +779,7 @@ static int handle_expecting_response(MAXROWS_SESSION_DATA* csdata) n_bytes - 1, &header[MYSQL_HEADER_LEN + 1]); - csdata->res.n_totalfields = mxs_leint_value(&header[4]); + csdata->res.n_totalfields = mxq::leint_value(&header[4]); csdata->res.offset += MYSQL_HEADER_LEN + n_bytes; csdata->state = MAXROWS_EXPECTING_FIELDS; diff --git a/server/modules/protocol/MySQL/mysql_common.cc b/server/modules/protocol/MySQL/mysql_common.cc index ae30e575e..a364242b3 100644 --- a/server/modules/protocol/MySQL/mysql_common.cc +++ b/server/modules/protocol/MySQL/mysql_common.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -1245,8 +1246,8 @@ bool mxs_mysql_more_results_after_ok(GWBUF* buffer) gwbuf_copy_data(buffer, MYSQL_HEADER_LEN + 1, sizeof(data), data); uint8_t* ptr = data; - ptr += mxs_leint_bytes(ptr); - ptr += mxs_leint_bytes(ptr); + ptr += mxq::leint_bytes(ptr); + ptr += mxq::leint_bytes(ptr); uint16_t* status = (uint16_t*)ptr; rval = (*status) & SERVER_MORE_RESULTS_EXIST; } @@ -1482,8 +1483,8 @@ void mxs_mysql_parse_ok_packet(GWBUF* buff, size_t packet_offset, size_t packet_ gwbuf_copy_data(buff, packet_offset, packet_len, local_buf); ptr += (MYSQL_HEADER_LEN + 1); // Header and Command type - mxs_leint_consume(&ptr); // Affected rows - mxs_leint_consume(&ptr); // Last insert-id + mxq::leint_consume(&ptr); // Affected rows + mxq::leint_consume(&ptr); // Last insert-id uint16_t server_status = gw_mysql_get_byte2(ptr); ptr += 2; // status ptr += 2; // number of warnings @@ -1491,19 +1492,18 @@ void mxs_mysql_parse_ok_packet(GWBUF* buff, size_t packet_offset, size_t packet_ if (ptr < (local_buf + packet_len)) { size_t size; - mxs_lestr_consume(&ptr, &size); // info + mxq::lestr_consume(&ptr, &size); // info if (server_status & SERVER_SESSION_STATE_CHANGED) { - MXB_AT_DEBUG(uint64_t data_size = ) mxs_leint_consume(&ptr); // total + MXB_AT_DEBUG(uint64_t data_size = ) mxq::leint_consume(&ptr); // total // SERVER_SESSION_STATE_CHANGED // length mxb_assert(data_size == packet_len - (ptr - local_buf)); while (ptr < (local_buf + packet_len)) { - enum_session_state_type type = - (enum enum_session_state_type)mxs_leint_consume(&ptr); + enum_session_state_type type = (enum enum_session_state_type)mxq::leint_consume(&ptr); #if defined (SS_DEBUG) mxb_assert(type <= SESSION_TRACK_TRANSACTION_TYPE); #endif @@ -1511,30 +1511,30 @@ void mxs_mysql_parse_ok_packet(GWBUF* buff, size_t packet_offset, size_t packet_ { case SESSION_TRACK_STATE_CHANGE: case SESSION_TRACK_SCHEMA: - size = mxs_leint_consume(&ptr); // Length of the overall entity. + size = mxq::leint_consume(&ptr); // Length of the overall entity. ptr += size; break; case SESSION_TRACK_GTIDS: - mxs_leint_consume(&ptr); // Length of the overall entity. - mxs_leint_consume(&ptr); // encoding specification - var_value = mxs_lestr_consume_dup(&ptr); + mxq::leint_consume(&ptr); // Length of the overall entity. + mxq::leint_consume(&ptr); // encoding specification + var_value = mxq::lestr_consume_dup(&ptr); gwbuf_add_property(buff, MXS_LAST_GTID, var_value); MXS_FREE(var_value); break; case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: - mxs_leint_consume(&ptr); // length - var_value = mxs_lestr_consume_dup(&ptr); + mxq::leint_consume(&ptr); // length + var_value = mxq::lestr_consume_dup(&ptr); gwbuf_add_property(buff, "trx_characteristics", var_value); MXS_FREE(var_value); break; case SESSION_TRACK_SYSTEM_VARIABLES: - mxs_leint_consume(&ptr); // lenth + mxq::leint_consume(&ptr); // lenth // system variables like autocommit, schema, charset ... - var_name = mxs_lestr_consume_dup(&ptr); - var_value = mxs_lestr_consume_dup(&ptr); + var_name = mxq::lestr_consume_dup(&ptr); + var_value = mxq::lestr_consume_dup(&ptr); gwbuf_add_property(buff, var_name, var_value); MXS_DEBUG("SESSION_TRACK_SYSTEM_VARIABLES, name:%s, value:%s", var_name, var_value); MXS_FREE(var_name); @@ -1542,15 +1542,15 @@ void mxs_mysql_parse_ok_packet(GWBUF* buff, size_t packet_offset, size_t packet_ break; case SESSION_TRACK_TRANSACTION_TYPE: - mxs_leint_consume(&ptr); // length - trx_info = mxs_lestr_consume_dup(&ptr); + mxq::leint_consume(&ptr); // length + trx_info = mxq::lestr_consume_dup(&ptr); MXS_DEBUG("get trx_info:%s", trx_info); gwbuf_add_property(buff, (char*)"trx_state", trx_info); MXS_FREE(trx_info); break; default: - mxs_lestr_consume(&ptr, &size); + mxq::lestr_consume(&ptr, &size); MXS_WARNING("recieved unexpecting session track type:%d", type); break; } diff --git a/server/modules/routing/avrorouter/avro_rbr.cc b/server/modules/routing/avrorouter/avro_rbr.cc index e07d3a97e..2589b2a2f 100644 --- a/server/modules/routing/avrorouter/avro_rbr.cc +++ b/server/modules/routing/avrorouter/avro_rbr.cc @@ -588,7 +588,7 @@ bool Rpl::handle_row_event(REP_HEADER* hdr, uint8_t* ptr) } /** Number of columns in the table */ - uint64_t ncolumns = mxs_leint_consume(&ptr); + uint64_t ncolumns = mxq::leint_consume(&ptr); /** If full row image is used, all columns are present. Currently only full * row image is supported and thus the bitfield should be all ones. In diff --git a/server/modules/routing/avrorouter/rpl.cc b/server/modules/routing/avrorouter/rpl.cc index 1155dd5b3..55355ac1c 100644 --- a/server/modules/routing/avrorouter/rpl.cc +++ b/server/modules/routing/avrorouter/rpl.cc @@ -585,15 +585,15 @@ TableMapEvent* table_map_alloc(uint8_t* ptr, uint8_t hdr_len, TableCreateEvent* memcpy(table_name, ptr, table_name_len + 1); ptr += table_name_len + 1; - uint64_t column_count = mxs_leint_value(ptr); - ptr += mxs_leint_bytes(ptr); + uint64_t column_count = mxq::leint_value(ptr); + ptr += mxq::leint_bytes(ptr); /** Column types */ uint8_t* column_types = ptr; ptr += column_count; size_t metadata_size = 0; - uint8_t* metadata = (uint8_t*)mxs_lestr_consume(&ptr, &metadata_size); + uint8_t* metadata = (uint8_t*) mxq::lestr_consume(&ptr, &metadata_size); uint8_t* nullmap = ptr; size_t nullmap_size = (column_count + 7) / 8;