PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/mysqlnd/mysqlnd_wireprotocol.c

http://github.com/php/php-src
C | 2758 lines | 2052 code | 372 blank | 334 comment | 319 complexity | c2f1c1b708b937bd170e81ac9bc39817 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Andrey Hristov <andrey@php.net> |
  14. | Ulf Wendel <uw@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "php.h"
  18. #include "mysqlnd.h"
  19. #include "mysqlnd_connection.h"
  20. #include "mysqlnd_ps.h"
  21. #include "mysqlnd_priv.h"
  22. #include "mysqlnd_wireprotocol.h"
  23. #include "mysqlnd_statistics.h"
  24. #include "mysqlnd_debug.h"
  25. #define BAIL_IF_NO_MORE_DATA \
  26. if (UNEXPECTED((size_t)(p - begin) > packet->header.size)) { \
  27. php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
  28. goto premature_end; \
  29. } \
  30. static const char *unknown_sqlstate= "HY000";
  31. const char * const mysqlnd_empty_string = "";
  32. /* Used in mysqlnd_debug.c */
  33. const char mysqlnd_read_header_name[] = "mysqlnd_read_header";
  34. const char mysqlnd_read_body_name[] = "mysqlnd_read_body";
  35. #define ERROR_MARKER 0xFF
  36. #define EODATA_MARKER 0xFE
  37. /* {{{ mysqlnd_command_to_text
  38. */
  39. const char * const mysqlnd_command_to_text[COM_END] =
  40. {
  41. "SLEEP", "QUIT", "INIT_DB", "QUERY", "FIELD_LIST",
  42. "CREATE_DB", "DROP_DB", "REFRESH", "SHUTDOWN", "STATISTICS",
  43. "PROCESS_INFO", "CONNECT", "PROCESS_KILL", "DEBUG", "PING",
  44. "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP",
  45. "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE",
  46. "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE",
  47. "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID",
  48. "RESET_CONNECTION"
  49. };
  50. /* }}} */
  51. static enum_mysqlnd_collected_stats packet_type_to_statistic_byte_count[PROT_LAST] =
  52. {
  53. STAT_LAST,
  54. STAT_LAST,
  55. STAT_BYTES_RECEIVED_OK,
  56. STAT_BYTES_RECEIVED_EOF,
  57. STAT_LAST,
  58. STAT_BYTES_RECEIVED_RSET_HEADER,
  59. STAT_BYTES_RECEIVED_RSET_FIELD_META,
  60. STAT_BYTES_RECEIVED_RSET_ROW,
  61. STAT_BYTES_RECEIVED_PREPARE_RESPONSE,
  62. STAT_BYTES_RECEIVED_CHANGE_USER,
  63. };
  64. static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_LAST] =
  65. {
  66. STAT_LAST,
  67. STAT_LAST,
  68. STAT_PACKETS_RECEIVED_OK,
  69. STAT_PACKETS_RECEIVED_EOF,
  70. STAT_LAST,
  71. STAT_PACKETS_RECEIVED_RSET_HEADER,
  72. STAT_PACKETS_RECEIVED_RSET_FIELD_META,
  73. STAT_PACKETS_RECEIVED_RSET_ROW,
  74. STAT_PACKETS_RECEIVED_PREPARE_RESPONSE,
  75. STAT_PACKETS_RECEIVED_CHANGE_USER,
  76. };
  77. /* {{{ php_mysqlnd_net_field_length
  78. Get next field's length */
  79. zend_ulong
  80. php_mysqlnd_net_field_length(const zend_uchar **packet)
  81. {
  82. register const zend_uchar *p= (const zend_uchar *)*packet;
  83. if (*p < 251) {
  84. (*packet)++;
  85. return (zend_ulong) *p;
  86. }
  87. switch (*p) {
  88. case 251:
  89. (*packet)++;
  90. return MYSQLND_NULL_LENGTH;
  91. case 252:
  92. (*packet) += 3;
  93. return (zend_ulong) uint2korr(p+1);
  94. case 253:
  95. (*packet) += 4;
  96. return (zend_ulong) uint3korr(p+1);
  97. default:
  98. (*packet) += 9;
  99. return (zend_ulong) uint4korr(p+1);
  100. }
  101. }
  102. /* }}} */
  103. /* {{{ php_mysqlnd_net_field_length_ll
  104. Get next field's length */
  105. uint64_t
  106. php_mysqlnd_net_field_length_ll(const zend_uchar **packet)
  107. {
  108. register const zend_uchar *p = (zend_uchar *)*packet;
  109. if (*p < 251) {
  110. (*packet)++;
  111. return (uint64_t) *p;
  112. }
  113. switch (*p) {
  114. case 251:
  115. (*packet)++;
  116. return (uint64_t) MYSQLND_NULL_LENGTH;
  117. case 252:
  118. (*packet) += 3;
  119. return (uint64_t) uint2korr(p + 1);
  120. case 253:
  121. (*packet) += 4;
  122. return (uint64_t) uint3korr(p + 1);
  123. default:
  124. (*packet) += 9;
  125. return (uint64_t) uint8korr(p + 1);
  126. }
  127. }
  128. /* }}} */
  129. /* {{{ php_mysqlnd_net_store_length */
  130. zend_uchar *
  131. php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length)
  132. {
  133. if (length < (uint64_t) L64(251)) {
  134. *packet = (zend_uchar) length;
  135. return packet + 1;
  136. }
  137. if (length < (uint64_t) L64(65536)) {
  138. *packet++ = 252;
  139. int2store(packet,(unsigned int) length);
  140. return packet + 2;
  141. }
  142. if (length < (uint64_t) L64(16777216)) {
  143. *packet++ = 253;
  144. int3store(packet,(zend_ulong) length);
  145. return packet + 3;
  146. }
  147. *packet++ = 254;
  148. int8store(packet, length);
  149. return packet + 8;
  150. }
  151. /* }}} */
  152. /* {{{ php_mysqlnd_net_store_length_size */
  153. size_t
  154. php_mysqlnd_net_store_length_size(uint64_t length)
  155. {
  156. if (length < (uint64_t) L64(251)) {
  157. return 1;
  158. }
  159. if (length < (uint64_t) L64(65536)) {
  160. return 3;
  161. }
  162. if (length < (uint64_t) L64(16777216)) {
  163. return 4;
  164. }
  165. return 9;
  166. }
  167. /* }}} */
  168. /* {{{ php_mysqlnd_read_error_from_line */
  169. static enum_func_status
  170. php_mysqlnd_read_error_from_line(const zend_uchar * const buf, const size_t buf_len,
  171. char *error, const size_t error_buf_len,
  172. unsigned int *error_no, char *sqlstate)
  173. {
  174. const zend_uchar *p = buf;
  175. size_t error_msg_len = 0;
  176. DBG_ENTER("php_mysqlnd_read_error_from_line");
  177. *error_no = CR_UNKNOWN_ERROR;
  178. memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);
  179. if (buf_len > 2) {
  180. *error_no = uint2korr(p);
  181. p+= 2;
  182. /*
  183. sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
  184. if it was >=2 then we would need a check
  185. */
  186. if (*p == '#') {
  187. ++p;
  188. if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
  189. memcpy(sqlstate, p, MYSQLND_SQLSTATE_LENGTH);
  190. p+= MYSQLND_SQLSTATE_LENGTH;
  191. } else {
  192. goto end;
  193. }
  194. }
  195. if ((buf_len - (p - buf)) > 0) {
  196. error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
  197. memcpy(error, p, error_msg_len);
  198. }
  199. }
  200. end:
  201. sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
  202. error[error_msg_len]= '\0';
  203. DBG_RETURN(FAIL);
  204. }
  205. /* }}} */
  206. /* {{{ mysqlnd_read_header */
  207. static enum_func_status
  208. mysqlnd_read_header(MYSQLND_PFC * pfc, MYSQLND_VIO * vio, MYSQLND_PACKET_HEADER * header,
  209. MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
  210. {
  211. zend_uchar buffer[MYSQLND_HEADER_SIZE];
  212. DBG_ENTER(mysqlnd_read_header_name);
  213. DBG_INF_FMT("compressed=%u", pfc->data->compressed);
  214. if (FAIL == pfc->data->m.receive(pfc, vio, buffer, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
  215. DBG_RETURN(FAIL);
  216. }
  217. header->size = uint3korr(buffer);
  218. header->packet_no = uint1korr(buffer + 3);
  219. DBG_INF_FMT("HEADER: prot_packet_no=%u size=%3u", header->packet_no, header->size);
  220. MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn_stats,
  221. STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
  222. STAT_PACKETS_RECEIVED, 1);
  223. if (pfc->data->compressed || pfc->data->packet_no == header->packet_no) {
  224. /*
  225. Have to increase the number, so we can send correct number back. It will
  226. round at 255 as this is unsigned char. The server needs this for simple
  227. flow control checking.
  228. */
  229. pfc->data->packet_no++;
  230. DBG_RETURN(PASS);
  231. }
  232. DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
  233. pfc->data->packet_no, header->packet_no, header->size);
  234. php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
  235. pfc->data->packet_no, header->packet_no, header->size);
  236. DBG_RETURN(FAIL);
  237. }
  238. /* }}} */
  239. /* {{{ mysqlnd_read_packet_header_and_body */
  240. static enum_func_status
  241. mysqlnd_read_packet_header_and_body(MYSQLND_PACKET_HEADER * packet_header,
  242. MYSQLND_PFC * pfc,
  243. MYSQLND_VIO * vio,
  244. MYSQLND_STATS * stats,
  245. MYSQLND_ERROR_INFO * error_info,
  246. MYSQLND_CONNECTION_STATE * connection_state,
  247. zend_uchar * const buf, const size_t buf_size,
  248. const char * const packet_type_as_text,
  249. enum mysqlnd_packet_type packet_type)
  250. {
  251. DBG_ENTER("mysqlnd_read_packet_header_and_body");
  252. DBG_INF_FMT("buf=%p size=%u", buf, buf_size);
  253. if (FAIL == mysqlnd_read_header(pfc, vio, packet_header, stats, error_info)) {
  254. SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
  255. SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
  256. DBG_ERR_FMT("Can't read %s's header", packet_type_as_text);
  257. DBG_RETURN(FAIL);
  258. }
  259. if (buf_size < packet_header->size) {
  260. DBG_ERR_FMT("Packet buffer %u wasn't big enough %u, %u bytes will be unread",
  261. buf_size, packet_header->size, packet_header->size - buf_size);
  262. DBG_RETURN(FAIL);
  263. }
  264. if (FAIL == pfc->data->m.receive(pfc, vio, buf, packet_header->size, stats, error_info)) {
  265. SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
  266. SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
  267. DBG_ERR_FMT("Empty '%s' packet body", packet_type_as_text);
  268. DBG_RETURN(FAIL);
  269. }
  270. MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[packet_type],
  271. MYSQLND_HEADER_SIZE + packet_header->size,
  272. packet_type_to_statistic_packet_count[packet_type],
  273. 1);
  274. DBG_RETURN(PASS);
  275. }
  276. /* }}} */
  277. /* {{{ php_mysqlnd_greet_read */
  278. static enum_func_status
  279. php_mysqlnd_greet_read(MYSQLND_CONN_DATA * conn, void * _packet)
  280. {
  281. zend_uchar buf[2048];
  282. const zend_uchar * p = buf;
  283. const zend_uchar * const begin = buf;
  284. const zend_uchar * pad_start = NULL;
  285. MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
  286. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  287. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  288. MYSQLND_VIO * vio = conn->vio;
  289. MYSQLND_STATS * stats = conn->stats;
  290. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  291. DBG_ENTER("php_mysqlnd_greet_read");
  292. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "greeting", PROT_GREET_PACKET)) {
  293. DBG_RETURN(FAIL);
  294. }
  295. BAIL_IF_NO_MORE_DATA;
  296. packet->authentication_plugin_data.s = packet->intern_auth_plugin_data;
  297. packet->authentication_plugin_data.l = sizeof(packet->intern_auth_plugin_data);
  298. if (packet->header.size < sizeof(buf)) {
  299. /*
  300. Null-terminate the string, so strdup can work even if the packets have a string at the end,
  301. which is not ASCIIZ
  302. */
  303. buf[packet->header.size] = '\0';
  304. }
  305. packet->protocol_version = uint1korr(p);
  306. p++;
  307. BAIL_IF_NO_MORE_DATA;
  308. if (ERROR_MARKER == packet->protocol_version) {
  309. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  310. packet->error, sizeof(packet->error),
  311. &packet->error_no, packet->sqlstate
  312. );
  313. /*
  314. The server doesn't send sqlstate in the greet packet.
  315. It's a bug#26426 , so we have to set it correctly ourselves.
  316. It's probably "Too many connections, which has SQL state 08004".
  317. */
  318. if (packet->error_no == 1040) {
  319. memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
  320. }
  321. DBG_RETURN(PASS);
  322. }
  323. packet->server_version = estrdup((char *)p);
  324. p+= strlen(packet->server_version) + 1; /* eat the '\0' */
  325. BAIL_IF_NO_MORE_DATA;
  326. packet->thread_id = uint4korr(p);
  327. p+=4;
  328. BAIL_IF_NO_MORE_DATA;
  329. memcpy(packet->authentication_plugin_data.s, p, SCRAMBLE_LENGTH_323);
  330. p+= SCRAMBLE_LENGTH_323;
  331. BAIL_IF_NO_MORE_DATA;
  332. /* pad1 */
  333. p++;
  334. BAIL_IF_NO_MORE_DATA;
  335. packet->server_capabilities = uint2korr(p);
  336. p+= 2;
  337. BAIL_IF_NO_MORE_DATA;
  338. DBG_INF_FMT("4.1 server_caps=%u\n", (uint32_t) packet->server_capabilities);
  339. packet->charset_no = uint1korr(p);
  340. p++;
  341. BAIL_IF_NO_MORE_DATA;
  342. packet->server_status = uint2korr(p);
  343. p+= 2;
  344. BAIL_IF_NO_MORE_DATA;
  345. /* pad2 */
  346. pad_start = p;
  347. p+= 13;
  348. BAIL_IF_NO_MORE_DATA;
  349. if ((size_t) (p - buf) < packet->header.size) {
  350. /* auth_plugin_data is split into two parts */
  351. memcpy(packet->authentication_plugin_data.s + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
  352. p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
  353. p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
  354. } else {
  355. packet->pre41 = TRUE;
  356. }
  357. /* Is this a 5.5+ server ? */
  358. if ((size_t) (p - buf) < packet->header.size) {
  359. /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
  360. p--;
  361. /* Additional 16 bits for server capabilities */
  362. DBG_INF_FMT("additional 5.5+ caps=%u\n", (uint32_t) uint2korr(pad_start));
  363. packet->server_capabilities |= ((uint32_t) uint2korr(pad_start)) << 16;
  364. /* And a length of the server scramble in one byte */
  365. packet->authentication_plugin_data.l = uint1korr(pad_start + 2);
  366. if (packet->authentication_plugin_data.l > SCRAMBLE_LENGTH) {
  367. /* more data*/
  368. char * new_auth_plugin_data = emalloc(packet->authentication_plugin_data.l);
  369. /* copy what we already have */
  370. memcpy(new_auth_plugin_data, packet->authentication_plugin_data.s, SCRAMBLE_LENGTH);
  371. /* add additional scramble data 5.5+ sent us */
  372. memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
  373. p+= (packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
  374. packet->authentication_plugin_data.s = new_auth_plugin_data;
  375. }
  376. }
  377. if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
  378. BAIL_IF_NO_MORE_DATA;
  379. /* The server is 5.5.x and supports authentication plugins */
  380. packet->auth_protocol = estrdup((char *)p);
  381. p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
  382. }
  383. DBG_INF_FMT("proto=%u server=%s thread_id=%u",
  384. packet->protocol_version, packet->server_version, packet->thread_id);
  385. DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u",
  386. packet->server_capabilities, packet->charset_no, packet->server_status,
  387. packet->auth_protocol? packet->auth_protocol:"n/a", packet->authentication_plugin_data.l);
  388. DBG_RETURN(PASS);
  389. premature_end:
  390. DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
  391. php_error_docref(NULL, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  392. p - begin - packet->header.size);
  393. DBG_RETURN(FAIL);
  394. }
  395. /* }}} */
  396. /* {{{ php_mysqlnd_greet_free_mem */
  397. static
  398. void php_mysqlnd_greet_free_mem(void * _packet)
  399. {
  400. MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet;
  401. if (p->server_version) {
  402. efree(p->server_version);
  403. p->server_version = NULL;
  404. }
  405. if (p->authentication_plugin_data.s && p->authentication_plugin_data.s != p->intern_auth_plugin_data) {
  406. efree(p->authentication_plugin_data.s);
  407. p->authentication_plugin_data.s = NULL;
  408. }
  409. if (p->auth_protocol) {
  410. efree(p->auth_protocol);
  411. p->auth_protocol = NULL;
  412. }
  413. }
  414. /* }}} */
  415. #define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 4096)
  416. /* {{{ php_mysqlnd_auth_write */
  417. static
  418. size_t php_mysqlnd_auth_write(MYSQLND_CONN_DATA * conn, void * _packet)
  419. {
  420. zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
  421. zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
  422. size_t len;
  423. MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
  424. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  425. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  426. MYSQLND_VIO * vio = conn->vio;
  427. MYSQLND_STATS * stats = conn->stats;
  428. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  429. DBG_ENTER("php_mysqlnd_auth_write");
  430. if (!packet->is_change_user_packet) {
  431. int4store(p, packet->client_flags);
  432. p+= 4;
  433. int4store(p, packet->max_packet_size);
  434. p+= 4;
  435. int1store(p, packet->charset_no);
  436. p++;
  437. memset(p, 0, 23); /* filler */
  438. p+= 23;
  439. }
  440. if (packet->send_auth_data || packet->is_change_user_packet) {
  441. len = MIN(strlen(packet->user), MYSQLND_MAX_ALLOWED_USER_LEN);
  442. memcpy(p, packet->user, len);
  443. p+= len;
  444. *p++ = '\0';
  445. /* defensive coding */
  446. if (packet->auth_data == NULL) {
  447. packet->auth_data_len = 0;
  448. }
  449. if (packet->auth_data_len > 0xFF) {
  450. const char * const msg = "Authentication data too long. "
  451. "Won't fit into the buffer and will be truncated. Authentication will thus fail";
  452. SET_CLIENT_ERROR(error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, msg);
  453. php_error_docref(NULL, E_WARNING, "%s", msg);
  454. DBG_RETURN(0);
  455. }
  456. int1store(p, (int8_t)packet->auth_data_len);
  457. ++p;
  458. /*!!!!! is the buffer big enough ??? */
  459. if (sizeof(buffer) < (packet->auth_data_len + (p - buffer))) {
  460. DBG_ERR("the stack buffer was not enough!!");
  461. DBG_RETURN(0);
  462. }
  463. if (packet->auth_data_len) {
  464. memcpy(p, packet->auth_data, packet->auth_data_len);
  465. p+= packet->auth_data_len;
  466. }
  467. if (packet->db_len > 0) {
  468. /* CLIENT_CONNECT_WITH_DB should have been set */
  469. size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len);
  470. memcpy(p, packet->db, real_db_len);
  471. p+= real_db_len;
  472. *p++= '\0';
  473. } else if (packet->is_change_user_packet) {
  474. *p++= '\0';
  475. }
  476. /* no \0 for no DB */
  477. if (packet->is_change_user_packet) {
  478. if (packet->charset_no) {
  479. int2store(p, packet->charset_no);
  480. p+= 2;
  481. }
  482. }
  483. if (packet->auth_plugin_name) {
  484. len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
  485. memcpy(p, packet->auth_plugin_name, len);
  486. p+= len;
  487. *p++= '\0';
  488. }
  489. if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) {
  490. size_t ca_payload_len = 0;
  491. {
  492. zend_string * key;
  493. zval * entry_value;
  494. ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
  495. if (key) { /* HASH_KEY_IS_STRING */
  496. size_t value_len = Z_STRLEN_P(entry_value);
  497. ca_payload_len += php_mysqlnd_net_store_length_size(ZSTR_LEN(key));
  498. ca_payload_len += ZSTR_LEN(key);
  499. ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
  500. ca_payload_len += value_len;
  501. }
  502. } ZEND_HASH_FOREACH_END();
  503. }
  504. if (sizeof(buffer) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len) + (p - buffer))) {
  505. p = php_mysqlnd_net_store_length(p, ca_payload_len);
  506. {
  507. zend_string * key;
  508. zval * entry_value;
  509. ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
  510. if (key) { /* HASH_KEY_IS_STRING */
  511. size_t value_len = Z_STRLEN_P(entry_value);
  512. /* copy key */
  513. p = php_mysqlnd_net_store_length(p, ZSTR_LEN(key));
  514. memcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
  515. p+= ZSTR_LEN(key);
  516. /* copy value */
  517. p = php_mysqlnd_net_store_length(p, value_len);
  518. memcpy(p, Z_STRVAL_P(entry_value), value_len);
  519. p+= value_len;
  520. }
  521. } ZEND_HASH_FOREACH_END();
  522. }
  523. } else {
  524. /* cannot put the data - skip */
  525. }
  526. }
  527. }
  528. if (packet->is_change_user_packet) {
  529. enum_func_status ret = FAIL;
  530. const MYSQLND_CSTRING payload = {(char*) buffer + MYSQLND_HEADER_SIZE, p - (buffer + MYSQLND_HEADER_SIZE)};
  531. const unsigned int silent = packet->silent;
  532. ret = conn->command->change_user(conn, payload, silent);
  533. DBG_RETURN(ret == PASS? (p - buffer - MYSQLND_HEADER_SIZE) : 0);
  534. } else {
  535. /*
  536. The auth handshake packet has no command in it. Thus we can't go over conn->command directly.
  537. Well, we can have a command->no_command(conn, payload)
  538. */
  539. const size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
  540. if (!sent) {
  541. SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
  542. }
  543. DBG_RETURN(sent);
  544. }
  545. }
  546. /* }}} */
  547. #define AUTH_RESP_BUFFER_SIZE 2048
  548. /* {{{ php_mysqlnd_auth_response_read */
  549. static enum_func_status
  550. php_mysqlnd_auth_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
  551. {
  552. register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
  553. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  554. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  555. MYSQLND_VIO * vio = conn->vio;
  556. MYSQLND_STATS * stats = conn->stats;
  557. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  558. zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
  559. size_t buf_len = pfc->cmd_buffer.buffer? pfc->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
  560. zend_uchar *buf = pfc->cmd_buffer.buffer? (zend_uchar *) pfc->cmd_buffer.buffer : local_buf;
  561. const zend_uchar * p = buf;
  562. const zend_uchar * const begin = buf;
  563. DBG_ENTER("php_mysqlnd_auth_response_read");
  564. /* leave space for terminating safety \0 */
  565. buf_len--;
  566. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
  567. DBG_RETURN(FAIL);
  568. }
  569. BAIL_IF_NO_MORE_DATA;
  570. /*
  571. zero-terminate the buffer for safety. We are sure there is place for the \0
  572. because buf_len is -1 the size of the buffer pointed
  573. */
  574. buf[packet->header.size] = '\0';
  575. /* Should be always 0x0 or ERROR_MARKER for error */
  576. packet->response_code = uint1korr(p);
  577. p++;
  578. BAIL_IF_NO_MORE_DATA;
  579. if (ERROR_MARKER == packet->response_code) {
  580. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  581. packet->error, sizeof(packet->error),
  582. &packet->error_no, packet->sqlstate
  583. );
  584. DBG_RETURN(PASS);
  585. }
  586. if (0xFE == packet->response_code) {
  587. /* Authentication Switch Response */
  588. if (packet->header.size > (size_t) (p - buf)) {
  589. packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
  590. packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
  591. p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
  592. packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
  593. if (packet->new_auth_protocol_data_len) {
  594. packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
  595. memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
  596. }
  597. DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
  598. DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
  599. }
  600. } else {
  601. zend_ulong net_len;
  602. /* Everything was fine! */
  603. packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
  604. BAIL_IF_NO_MORE_DATA;
  605. packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
  606. BAIL_IF_NO_MORE_DATA;
  607. packet->server_status = uint2korr(p);
  608. p+= 2;
  609. BAIL_IF_NO_MORE_DATA;
  610. packet->warning_count = uint2korr(p);
  611. p+= 2;
  612. BAIL_IF_NO_MORE_DATA;
  613. /* There is a message */
  614. if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
  615. packet->message_len = MIN(net_len, buf_len - (p - begin));
  616. packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
  617. } else {
  618. packet->message = NULL;
  619. packet->message_len = 0;
  620. }
  621. DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%pd server_status=%u warnings=%u",
  622. packet->affected_rows, packet->last_insert_id, packet->server_status,
  623. packet->warning_count);
  624. }
  625. DBG_RETURN(PASS);
  626. premature_end:
  627. DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
  628. php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  629. p - begin - packet->header.size);
  630. DBG_RETURN(FAIL);
  631. }
  632. /* }}} */
  633. /* {{{ php_mysqlnd_auth_response_free_mem */
  634. static void
  635. php_mysqlnd_auth_response_free_mem(void * _packet)
  636. {
  637. MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
  638. if (p->message) {
  639. mnd_efree(p->message);
  640. p->message = NULL;
  641. }
  642. if (p->new_auth_protocol) {
  643. mnd_efree(p->new_auth_protocol);
  644. p->new_auth_protocol = NULL;
  645. }
  646. p->new_auth_protocol_len = 0;
  647. if (p->new_auth_protocol_data) {
  648. mnd_efree(p->new_auth_protocol_data);
  649. p->new_auth_protocol_data = NULL;
  650. }
  651. p->new_auth_protocol_data_len = 0;
  652. }
  653. /* }}} */
  654. /* {{{ php_mysqlnd_change_auth_response_write */
  655. static size_t
  656. php_mysqlnd_change_auth_response_write(MYSQLND_CONN_DATA * conn, void * _packet)
  657. {
  658. MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
  659. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  660. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  661. MYSQLND_VIO * vio = conn->vio;
  662. MYSQLND_STATS * stats = conn->stats;
  663. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  664. zend_uchar * const buffer = pfc->cmd_buffer.length >= packet->auth_data_len? pfc->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
  665. zend_uchar * p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
  666. DBG_ENTER("php_mysqlnd_change_auth_response_write");
  667. if (packet->auth_data_len) {
  668. memcpy(p, packet->auth_data, packet->auth_data_len);
  669. p+= packet->auth_data_len;
  670. }
  671. {
  672. /*
  673. The auth handshake packet has no command in it. Thus we can't go over conn->command directly.
  674. Well, we can have a command->no_command(conn, payload)
  675. */
  676. const size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
  677. if (buffer != pfc->cmd_buffer.buffer) {
  678. mnd_efree(buffer);
  679. }
  680. if (!sent) {
  681. SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
  682. }
  683. DBG_RETURN(sent);
  684. }
  685. }
  686. /* }}} */
  687. #define OK_BUFFER_SIZE 2048
  688. /* {{{ php_mysqlnd_ok_read */
  689. static enum_func_status
  690. php_mysqlnd_ok_read(MYSQLND_CONN_DATA * conn, void * _packet)
  691. {
  692. register MYSQLND_PACKET_OK *packet= (MYSQLND_PACKET_OK *) _packet;
  693. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  694. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  695. MYSQLND_VIO * vio = conn->vio;
  696. MYSQLND_STATS * stats = conn->stats;
  697. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  698. zend_uchar local_buf[OK_BUFFER_SIZE];
  699. const size_t buf_len = pfc->cmd_buffer.buffer? pfc->cmd_buffer.length : OK_BUFFER_SIZE;
  700. zend_uchar * const buf = pfc->cmd_buffer.buffer? (zend_uchar *) pfc->cmd_buffer.buffer : local_buf;
  701. const zend_uchar * p = buf;
  702. const zend_uchar * const begin = buf;
  703. zend_ulong net_len;
  704. DBG_ENTER("php_mysqlnd_ok_read");
  705. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
  706. DBG_RETURN(FAIL);
  707. }
  708. BAIL_IF_NO_MORE_DATA;
  709. /* Should be always 0x0 or ERROR_MARKER for error */
  710. packet->field_count = uint1korr(p);
  711. p++;
  712. BAIL_IF_NO_MORE_DATA;
  713. if (ERROR_MARKER == packet->field_count) {
  714. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  715. packet->error, sizeof(packet->error),
  716. &packet->error_no, packet->sqlstate
  717. );
  718. DBG_RETURN(PASS);
  719. }
  720. /* Everything was fine! */
  721. packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
  722. BAIL_IF_NO_MORE_DATA;
  723. packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
  724. BAIL_IF_NO_MORE_DATA;
  725. packet->server_status = uint2korr(p);
  726. p+= 2;
  727. BAIL_IF_NO_MORE_DATA;
  728. packet->warning_count = uint2korr(p);
  729. p+= 2;
  730. BAIL_IF_NO_MORE_DATA;
  731. /* There is a message */
  732. if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
  733. packet->message_len = MIN(net_len, buf_len - (p - begin));
  734. packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
  735. } else {
  736. packet->message = NULL;
  737. packet->message_len = 0;
  738. }
  739. DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
  740. packet->affected_rows, packet->last_insert_id, packet->server_status,
  741. packet->warning_count);
  742. BAIL_IF_NO_MORE_DATA;
  743. DBG_RETURN(PASS);
  744. premature_end:
  745. DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
  746. php_error_docref(NULL, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  747. p - begin - packet->header.size);
  748. DBG_RETURN(FAIL);
  749. }
  750. /* }}} */
  751. /* {{{ php_mysqlnd_ok_free_mem */
  752. static void
  753. php_mysqlnd_ok_free_mem(void * _packet)
  754. {
  755. MYSQLND_PACKET_OK *p= (MYSQLND_PACKET_OK *) _packet;
  756. if (p->message) {
  757. mnd_efree(p->message);
  758. p->message = NULL;
  759. }
  760. }
  761. /* }}} */
  762. /* {{{ php_mysqlnd_eof_read */
  763. static enum_func_status
  764. php_mysqlnd_eof_read(MYSQLND_CONN_DATA * conn, void * _packet)
  765. {
  766. /*
  767. EOF packet is since 4.1 five bytes long,
  768. but we can get also an error, make it bigger.
  769. Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
  770. */
  771. MYSQLND_PACKET_EOF *packet= (MYSQLND_PACKET_EOF *) _packet;
  772. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  773. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  774. MYSQLND_VIO * vio = conn->vio;
  775. MYSQLND_STATS * stats = conn->stats;
  776. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  777. const size_t buf_len = pfc->cmd_buffer.length;
  778. zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  779. const zend_uchar * p = buf;
  780. const zend_uchar * const begin = buf;
  781. DBG_ENTER("php_mysqlnd_eof_read");
  782. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "EOF", PROT_EOF_PACKET)) {
  783. DBG_RETURN(FAIL);
  784. }
  785. BAIL_IF_NO_MORE_DATA;
  786. /* Should be always EODATA_MARKER */
  787. packet->field_count = uint1korr(p);
  788. p++;
  789. BAIL_IF_NO_MORE_DATA;
  790. if (ERROR_MARKER == packet->field_count) {
  791. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  792. packet->error, sizeof(packet->error),
  793. &packet->error_no, packet->sqlstate
  794. );
  795. DBG_RETURN(PASS);
  796. }
  797. /*
  798. 4.1 sends 1 byte EOF packet after metadata of
  799. PREPARE/EXECUTE but 5 bytes after the result. This is not
  800. according to the Docs@Forge!!!
  801. */
  802. if (packet->header.size > 1) {
  803. packet->warning_count = uint2korr(p);
  804. p+= 2;
  805. BAIL_IF_NO_MORE_DATA;
  806. packet->server_status = uint2korr(p);
  807. p+= 2;
  808. BAIL_IF_NO_MORE_DATA;
  809. } else {
  810. packet->warning_count = 0;
  811. packet->server_status = 0;
  812. }
  813. BAIL_IF_NO_MORE_DATA;
  814. DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u",
  815. packet->field_count, packet->server_status, packet->warning_count);
  816. DBG_RETURN(PASS);
  817. premature_end:
  818. DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size);
  819. php_error_docref(NULL, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  820. p - begin - packet->header.size);
  821. DBG_RETURN(FAIL);
  822. }
  823. /* }}} */
  824. /* {{{ php_mysqlnd_cmd_write */
  825. size_t php_mysqlnd_cmd_write(MYSQLND_CONN_DATA * conn, void * _packet)
  826. {
  827. /* Let's have some space, which we can use, if not enough, we will allocate new buffer */
  828. MYSQLND_PACKET_COMMAND * packet= (MYSQLND_PACKET_COMMAND *) _packet;
  829. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  830. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  831. MYSQLND_VIO * vio = conn->vio;
  832. MYSQLND_STATS * stats = conn->stats;
  833. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  834. const unsigned int error_reporting = EG(error_reporting);
  835. size_t sent = 0;
  836. DBG_ENTER("php_mysqlnd_cmd_write");
  837. /*
  838. Reset packet_no, or we will get bad handshake!
  839. Every command starts a new TX and packet numbers are reset to 0.
  840. */
  841. pfc->data->m.reset(pfc, stats, error_info);
  842. if (error_reporting) {
  843. EG(error_reporting) = 0;
  844. }
  845. MYSQLND_INC_CONN_STATISTIC(stats, STAT_PACKETS_SENT_CMD);
  846. #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
  847. vio->data->m.consume_uneaten_data(vio, packet->command);
  848. #endif
  849. if (!packet->argument.s || !packet->argument.l) {
  850. zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
  851. int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
  852. sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
  853. } else {
  854. size_t tmp_len = packet->argument.l + 1 + MYSQLND_HEADER_SIZE;
  855. zend_uchar *tmp, *p;
  856. tmp = (tmp_len > pfc->cmd_buffer.length)? mnd_emalloc(tmp_len):pfc->cmd_buffer.buffer;
  857. if (!tmp) {
  858. goto end;
  859. }
  860. p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
  861. int1store(p, packet->command);
  862. p++;
  863. memcpy(p, packet->argument.s, packet->argument.l);
  864. sent = pfc->data->m.send(pfc, vio, tmp, tmp_len - MYSQLND_HEADER_SIZE, stats, error_info);
  865. if (tmp != pfc->cmd_buffer.buffer) {
  866. MYSQLND_INC_CONN_STATISTIC(stats, STAT_CMD_BUFFER_TOO_SMALL);
  867. mnd_efree(tmp);
  868. }
  869. }
  870. end:
  871. if (error_reporting) {
  872. /* restore error reporting */
  873. EG(error_reporting) = error_reporting;
  874. }
  875. if (!sent) {
  876. SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
  877. }
  878. DBG_RETURN(sent);
  879. }
  880. /* }}} */
  881. /* {{{ php_mysqlnd_rset_header_read */
  882. static enum_func_status
  883. php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
  884. {
  885. MYSQLND_PACKET_RSET_HEADER * packet= (MYSQLND_PACKET_RSET_HEADER *) _packet;
  886. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  887. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  888. MYSQLND_VIO * vio = conn->vio;
  889. MYSQLND_STATS * stats = conn->stats;
  890. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  891. enum_func_status ret = PASS;
  892. const size_t buf_len = pfc->cmd_buffer.length;
  893. zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  894. const zend_uchar * p = buf;
  895. const zend_uchar * const begin = buf;
  896. size_t len;
  897. DBG_ENTER("php_mysqlnd_rset_header_read");
  898. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET)) {
  899. DBG_RETURN(FAIL);
  900. }
  901. BAIL_IF_NO_MORE_DATA;
  902. /*
  903. Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
  904. of encoded sequence for length.
  905. */
  906. if (ERROR_MARKER == *p) {
  907. /* Error */
  908. p++;
  909. BAIL_IF_NO_MORE_DATA;
  910. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  911. packet->error_info.error, sizeof(packet->error_info.error),
  912. &packet->error_info.error_no, packet->error_info.sqlstate
  913. );
  914. DBG_RETURN(PASS);
  915. }
  916. packet->field_count = php_mysqlnd_net_field_length(&p);
  917. BAIL_IF_NO_MORE_DATA;
  918. switch (packet->field_count) {
  919. case MYSQLND_NULL_LENGTH:
  920. DBG_INF("LOAD LOCAL");
  921. /*
  922. First byte in the packet is the field count.
  923. Thus, the name is size - 1. And we add 1 for a trailing \0.
  924. Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed
  925. that packet->header.size is > 0. Which means that len can't underflow, that
  926. would lead to 0 byte allocation but 2^32 or 2^64 bytes copied.
  927. */
  928. len = packet->header.size - 1;
  929. packet->info_or_local_file.s = mnd_emalloc(len + 1);
  930. if (packet->info_or_local_file.s) {
  931. memcpy(packet->info_or_local_file.s, p, len);
  932. packet->info_or_local_file.s[len] = '\0';
  933. packet->info_or_local_file.l = len;
  934. } else {
  935. SET_OOM_ERROR(error_info);
  936. ret = FAIL;
  937. }
  938. break;
  939. case 0x00:
  940. DBG_INF("UPSERT");
  941. packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
  942. BAIL_IF_NO_MORE_DATA;
  943. packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
  944. BAIL_IF_NO_MORE_DATA;
  945. packet->server_status = uint2korr(p);
  946. p+=2;
  947. BAIL_IF_NO_MORE_DATA;
  948. packet->warning_count = uint2korr(p);
  949. p+=2;
  950. BAIL_IF_NO_MORE_DATA;
  951. /* Check for additional textual data */
  952. if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
  953. packet->info_or_local_file.s = mnd_emalloc(len + 1);
  954. if (packet->info_or_local_file.s) {
  955. memcpy(packet->info_or_local_file.s, p, len);
  956. packet->info_or_local_file.s[len] = '\0';
  957. packet->info_or_local_file.l = len;
  958. } else {
  959. SET_OOM_ERROR(error_info);
  960. ret = FAIL;
  961. }
  962. }
  963. DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%u warning_count=%u",
  964. packet->affected_rows, packet->last_insert_id,
  965. packet->server_status, packet->warning_count);
  966. break;
  967. default:
  968. DBG_INF("SELECT");
  969. /* Result set */
  970. break;
  971. }
  972. BAIL_IF_NO_MORE_DATA;
  973. DBG_RETURN(ret);
  974. premature_end:
  975. DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size);
  976. php_error_docref(NULL, E_WARNING, "RSET_HEADER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  977. p - begin - packet->header.size);
  978. DBG_RETURN(FAIL);
  979. }
  980. /* }}} */
  981. /* {{{ php_mysqlnd_rset_header_free_mem */
  982. static
  983. void php_mysqlnd_rset_header_free_mem(void * _packet)
  984. {
  985. MYSQLND_PACKET_RSET_HEADER *p= (MYSQLND_PACKET_RSET_HEADER *) _packet;
  986. DBG_ENTER("php_mysqlnd_rset_header_free_mem");
  987. if (p->info_or_local_file.s) {
  988. mnd_efree(p->info_or_local_file.s);
  989. p->info_or_local_file.s = NULL;
  990. }
  991. DBG_VOID_RETURN;
  992. }
  993. /* }}} */
  994. #define READ_RSET_FIELD(field_name) do { \
  995. len = php_mysqlnd_net_field_length(&p); \
  996. if (UNEXPECTED(len == MYSQLND_NULL_LENGTH)) { \
  997. goto faulty_or_fake; \
  998. } else if (len != 0) { \
  999. meta->field_name = (const char *)p; \
  1000. meta->field_name ## _length = len; \
  1001. p += len; \
  1002. total_len += len + 1; \
  1003. } else { \
  1004. meta->field_name = mysqlnd_empty_string; \
  1005. meta->field_name ## _length = 0; \
  1006. } \
  1007. } while (0)
  1008. /* {{{ php_mysqlnd_rset_field_read */
  1009. static enum_func_status
  1010. php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1011. {
  1012. /* Should be enough for the metadata of a single row */
  1013. MYSQLND_PACKET_RES_FIELD *packet = (MYSQLND_PACKET_RES_FIELD *) _packet;
  1014. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1015. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1016. MYSQLND_VIO * vio = conn->vio;
  1017. MYSQLND_STATS * stats = conn->stats;
  1018. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1019. const size_t buf_len = pfc->cmd_buffer.length;
  1020. size_t total_len = 0;
  1021. zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  1022. const zend_uchar * p = buf;
  1023. const zend_uchar * const begin = buf;
  1024. char *root_ptr;
  1025. zend_ulong len;
  1026. MYSQLND_FIELD *meta;
  1027. DBG_ENTER("php_mysqlnd_rset_field_read");
  1028. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "field", PROT_RSET_FLD_PACKET)) {
  1029. DBG_RETURN(FAIL);
  1030. }
  1031. if (packet->skip_parsing) {
  1032. DBG_RETURN(PASS);
  1033. }
  1034. BAIL_IF_NO_MORE_DATA;
  1035. if (ERROR_MARKER == *p) {
  1036. /* Error */
  1037. p++;
  1038. BAIL_IF_NO_MORE_DATA;
  1039. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  1040. packet->error_info.error, sizeof(packet->error_info.error),
  1041. &packet->error_info.error_no, packet->error_info.sqlstate
  1042. );
  1043. DBG_ERR_FMT("Server error : (%u) %s", packet->error_info.error_no, packet->error_info.error);
  1044. DBG_RETURN(PASS);
  1045. } else if (EODATA_MARKER == *p && packet->header.size < 8) {
  1046. /* Premature EOF. That should be COM_FIELD_LIST. But we don't support COM_FIELD_LIST anymore, thus this should not happen */
  1047. DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
  1048. DBG_RETURN(PASS);
  1049. }
  1050. meta = packet->metadata;
  1051. READ_RSET_FIELD(catalog);
  1052. READ_RSET_FIELD(db);
  1053. READ_RSET_FIELD(table);
  1054. READ_RSET_FIELD(org_table);
  1055. READ_RSET_FIELD(name);
  1056. READ_RSET_FIELD(org_name);
  1057. /* 1 byte length */
  1058. if (UNEXPECTED(12 != *p)) {
  1059. DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
  1060. php_error_docref(NULL, E_WARNING, "Protocol error. Server sent false length. Expected 12");
  1061. }
  1062. if ((size_t)((p - begin) + 12) > packet->header.size) {
  1063. php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__);
  1064. goto premature_end;
  1065. }
  1066. p++;
  1067. meta->charsetnr = uint2korr(p);
  1068. p += 2;
  1069. meta->length = uint4korr(p);
  1070. p += 4;
  1071. meta->type = uint1korr(p);
  1072. p += 1;
  1073. meta->flags = uint2korr(p);
  1074. p += 2;
  1075. meta->decimals = uint1korr(p);
  1076. p += 1;
  1077. /* 2 byte filler */
  1078. p +=2;
  1079. /* Should we set NUM_FLAG (libmysql does it) ? */
  1080. if (
  1081. (meta->type <= MYSQL_TYPE_INT24 &&
  1082. (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8)
  1083. ) || meta->type == MYSQL_TYPE_YEAR)
  1084. {
  1085. meta->flags |= NUM_FLAG;
  1086. }
  1087. /*
  1088. def could be empty, thus don't allocate on the root.
  1089. NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
  1090. Otherwise the string is length encoded.
  1091. */
  1092. if (packet->header.size > (size_t) (p - buf) &&
  1093. (len = php_mysqlnd_net_field_length(&p)) &&
  1094. len != MYSQLND_NULL_LENGTH)
  1095. {
  1096. BAIL_IF_NO_MORE_DATA;
  1097. DBG_INF_FMT("Def found, length %lu", len);
  1098. meta->def = packet->memory_pool->get_chunk(packet->memory_pool, len + 1);
  1099. memcpy(meta->def, p, len);
  1100. meta->def[len] = '\0';
  1101. meta->def_length = len;
  1102. p += len;
  1103. }
  1104. root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len);
  1105. meta->root_len = total_len;
  1106. if (EXPECTED(meta->name_length != 0)) {
  1107. meta->sname = zend_string_init_interned(meta->name, meta->name_length, 0);
  1108. meta->name = ZSTR_VAL(meta->sname);
  1109. } else {
  1110. meta->sname = ZSTR_EMPTY_ALLOC();
  1111. }
  1112. /* Now do allocs */
  1113. if (meta->catalog_length != 0) {
  1114. len = meta->catalog_length;
  1115. meta->catalog = memcpy(root_ptr, meta->catalog, len);
  1116. *(root_ptr +=len) = '\0';
  1117. root_ptr++;
  1118. }
  1119. if (meta->db_length != 0) {
  1120. len = meta->db_length;
  1121. meta->db = memcpy(root_ptr, meta->db, len);
  1122. *(root_ptr +=len) = '\0';
  1123. root_ptr++;
  1124. }
  1125. if (meta->table_length != 0) {
  1126. len = meta->table_length;
  1127. meta->table = memcpy(root_ptr, meta->table, len);
  1128. *(root_ptr +=len) = '\0';
  1129. root_ptr++;
  1130. }
  1131. if (meta->org_table_length != 0) {
  1132. len = meta->org_table_length;
  1133. meta->org_table = memcpy(root_ptr, meta->org_table, len);
  1134. *(root_ptr +=len) = '\0';
  1135. root_ptr++;
  1136. }
  1137. if (meta->org_name_length != 0) {
  1138. len = meta->org_name_length;
  1139. meta->org_name = memcpy(root_ptr, meta->org_name, len);
  1140. *(root_ptr +=len) = '\0';
  1141. root_ptr++;
  1142. }
  1143. DBG_INF_FMT("allocing root.");
  1144. DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
  1145. meta->name? meta->name:"*NA*");
  1146. DBG_RETURN(PASS);
  1147. faulty_or_fake:
  1148. DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
  1149. php_error_docref(NULL, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
  1150. " The server is faulty");
  1151. DBG_RETURN(FAIL);
  1152. premature_end:
  1153. DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size);
  1154. php_error_docref(NULL, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes "
  1155. "shorter than expected", p - begin - packet->header.size);
  1156. DBG_RETURN(FAIL);
  1157. }
  1158. /* }}} */
  1159. /* {{{ php_mysqlnd_read_row_ex */
  1160. static enum_func_status
  1161. php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
  1162. MYSQLND_VIO * vio,
  1163. MYSQLND_STATS * stats,
  1164. MYSQLND_ERROR_INFO * error_info,
  1165. MYSQLND_MEMORY_POOL * pool,
  1166. MYSQLND_ROW_BUFFER * buffer,
  1167. size_t * const data_size)
  1168. {
  1169. enum_func_status ret = PASS;
  1170. MYSQLND_PACKET_HEADER header;
  1171. zend_uchar * p = NULL;
  1172. size_t prealloc_more_bytes;
  1173. DBG_ENTER("php_mysqlnd_read_row_ex");
  1174. /*
  1175. To ease the process the server splits everything in packets up to 2^24 - 1.
  1176. Even in the case the payload is evenly divisible by this value, the last
  1177. packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
  1178. for next one if they have 2^24 - 1 sizes. But just read the header of a
  1179. zero-length byte, don't read the body, there is no such.
  1180. */
  1181. /*
  1182. We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol_aux
  1183. needs to be able to append a terminating \0 for atoi/atof.
  1184. */
  1185. prealloc_more_bytes = 1;
  1186. *data_size = 0;
  1187. if (UNEXPECTED(FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info))) {
  1188. ret = FAIL;
  1189. } else {
  1190. *data_size += header.size;
  1191. buffer->ptr = pool->get_chunk(pool, *data_size + prealloc_more_bytes);
  1192. p = buffer->ptr;
  1193. if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
  1194. DBG_ERR("Empty row packet body");
  1195. php_error(E_WARNING, "Empty row packet body");
  1196. } else {
  1197. while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
  1198. if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
  1199. ret = FAIL;
  1200. break;
  1201. }
  1202. *data_size += header.size;
  1203. /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
  1204. if (!header.size) {
  1205. break;
  1206. }
  1207. /*
  1208. We have to realloc the buffer.
  1209. */
  1210. buffer->ptr = pool->resize_chunk(pool, buffer->ptr, *data_size - header.size, *data_size + prealloc_more_bytes);
  1211. if (!buffer->ptr) {
  1212. SET_OOM_ERROR(error_info);
  1213. ret = FAIL;
  1214. break;
  1215. }
  1216. /* The position could have changed, recalculate */
  1217. p = (zend_uchar *) buffer->ptr + (*data_size - header.size);
  1218. if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
  1219. DBG_ERR("Empty row packet body");
  1220. php_error(E_WARNING, "Empty row packet body");
  1221. break;
  1222. }
  1223. }
  1224. }
  1225. }
  1226. if (ret == FAIL && buffer->ptr) {
  1227. pool->free_chunk(pool, buffer->ptr);
  1228. buffer->ptr = NULL;
  1229. }
  1230. DBG_RETURN(ret);
  1231. }
  1232. /* }}} */
  1233. /* {{{ php_mysqlnd_rowp_read_binary_protocol */
  1234. enum_func_status
  1235. php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
  1236. const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
  1237. const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
  1238. {
  1239. unsigned int i;
  1240. const zend_uchar * p = row_buffer->ptr;
  1241. const zend_uchar * null_ptr;
  1242. zend_uchar bit;
  1243. zval *current_field, *end_field, *start_field;
  1244. DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
  1245. if (!fields) {
  1246. DBG_RETURN(FAIL);
  1247. }
  1248. end_field = (start_field = fields) + field_count;
  1249. /* skip the first byte, not EODATA_MARKER -> 0x0, status */
  1250. p++;
  1251. null_ptr= p;
  1252. p += (field_count + 9)/8; /* skip null bits */
  1253. bit = 4; /* first 2 bits are reserved */
  1254. for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
  1255. enum_mysqlnd_collected_stats statistic;
  1256. const zend_uchar * orig_p = p;
  1257. DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u",
  1258. current_field, i,
  1259. fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
  1260. fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT);
  1261. if (*null_ptr & bit) {
  1262. DBG_INF("It's null");
  1263. ZVAL_NULL(current_field);
  1264. statistic = STAT_BINARY_TYPE_FETCHED_NULL;
  1265. } else {
  1266. enum_mysqlnd_field_types type = fields_metadata[i].type;
  1267. mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p);
  1268. if (MYSQLND_G(collect_statistics)) {
  1269. switch (fields_metadata[i].type) {
  1270. case MYSQL_TYPE_DECIMAL: statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
  1271. case MYSQL_TYPE_TINY: statistic = STAT_BINARY_TYPE_FETCHED_INT8; break;
  1272. case MYSQL_TYPE_SHORT: statistic = STAT_BINARY_TYPE_FETCHED_INT16; break;
  1273. case MYSQL_TYPE_LONG: statistic = STAT_BINARY_TYPE_FETCHED_INT32; break;
  1274. case MYSQL_TYPE_FLOAT: statistic = STAT_BINARY_TYPE_FETCHED_FLOAT; break;
  1275. case MYSQL_TYPE_DOUBLE: statistic = STAT_BINARY_TYPE_FETCHED_DOUBLE; break;
  1276. case MYSQL_TYPE_NULL: statistic = STAT_BINARY_TYPE_FETCHED_NULL; break;
  1277. case MYSQL_TYPE_TIMESTAMP: statistic = STAT_BINARY_TYPE_FETCHED_TIMESTAMP; break;
  1278. case MYSQL_TYPE_LONGLONG: statistic = STAT_BINARY_TYPE_FETCHED_INT64; break;
  1279. case MYSQL_TYPE_INT24: statistic = STAT_BINARY_TYPE_FETCHED_INT24; break;
  1280. case MYSQL_TYPE_DATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
  1281. case MYSQL_TYPE_TIME: statistic = STAT_BINARY_TYPE_FETCHED_TIME; break;
  1282. case MYSQL_TYPE_DATETIME: statistic = STAT_BINARY_TYPE_FETCHED_DATETIME; break;
  1283. case MYSQL_TYPE_YEAR: statistic = STAT_BINARY_TYPE_FETCHED_YEAR; break;
  1284. case MYSQL_TYPE_NEWDATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
  1285. case MYSQL_TYPE_VARCHAR: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
  1286. case MYSQL_TYPE_BIT: statistic = STAT_BINARY_TYPE_FETCHED_BIT; break;
  1287. case MYSQL_TYPE_NEWDECIMAL: statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
  1288. case MYSQL_TYPE_ENUM: statistic = STAT_BINARY_TYPE_FETCHED_ENUM; break;
  1289. case MYSQL_TYPE_SET: statistic = STAT_BINARY_TYPE_FETCHED_SET; break;
  1290. case MYSQL_TYPE_TINY_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
  1291. case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
  1292. case MYSQL_TYPE_LONG_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
  1293. case MYSQL_TYPE_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
  1294. case MYSQL_TYPE_VAR_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
  1295. case MYSQL_TYPE_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
  1296. case MYSQL_TYPE_GEOMETRY: statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
  1297. default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
  1298. }
  1299. }
  1300. }
  1301. MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
  1302. STAT_BYTES_RECEIVED_PURE_DATA_PS,
  1303. (Z_TYPE_P(current_field) == IS_STRING)?
  1304. Z_STRLEN_P(current_field) : (size_t)(p - orig_p));
  1305. if (!((bit<<=1) & 255)) {
  1306. bit = 1; /* to the following byte */
  1307. null_ptr++;
  1308. }
  1309. }
  1310. DBG_RETURN(PASS);
  1311. }
  1312. /* }}} */
  1313. /* {{{ php_mysqlnd_rowp_read_text_protocol */
  1314. enum_func_status
  1315. php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
  1316. unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
  1317. zend_bool as_int_or_float, MYSQLND_STATS * stats)
  1318. {
  1319. unsigned int i;
  1320. zval *current_field, *end_field, *start_field;
  1321. zend_uchar * p = row_buffer->ptr;
  1322. const size_t data_size = row_buffer->size;
  1323. const zend_uchar * const packet_end = (zend_uchar*) p + data_size;
  1324. DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
  1325. if (!fields) {
  1326. DBG_RETURN(FAIL);
  1327. }
  1328. end_field = (start_field = fields) + field_count;
  1329. for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
  1330. /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
  1331. const zend_ulong len = php_mysqlnd_net_field_length((const zend_uchar **) &p);
  1332. /* NULL or NOT NULL, this is the question! */
  1333. if (len == MYSQLND_NULL_LENGTH) {
  1334. ZVAL_NULL(current_field);
  1335. } else if ((p + len) > packet_end) {
  1336. php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC
  1337. " bytes after end of packet", (p + len) - packet_end - 1);
  1338. DBG_RETURN(FAIL);
  1339. } else {
  1340. #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
  1341. struct st_mysqlnd_perm_bind perm_bind =
  1342. mysqlnd_ps_fetch_functions[fields_metadata[i].type];
  1343. #endif
  1344. if (MYSQLND_G(collect_statistics)) {
  1345. enum_mysqlnd_collected_stats statistic;
  1346. switch (fields_metadata[i].type) {
  1347. case MYSQL_TYPE_DECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
  1348. case MYSQL_TYPE_TINY: statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
  1349. case MYSQL_TYPE_SHORT: statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
  1350. case MYSQL_TYPE_LONG: statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
  1351. case MYSQL_TYPE_FLOAT: statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
  1352. case MYSQL_TYPE_DOUBLE: statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
  1353. case MYSQL_TYPE_NULL: statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
  1354. case MYSQL_TYPE_TIMESTAMP: statistic = STAT_TEXT_TYPE_FETCHED_TIMESTAMP; break;
  1355. case MYSQL_TYPE_LONGLONG: statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
  1356. case MYSQL_TYPE_INT24: statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
  1357. case MYSQL_TYPE_DATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
  1358. case MYSQL_TYPE_TIME: statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
  1359. case MYSQL_TYPE_DATETIME: statistic = STAT_TEXT_TYPE_FETCHED_DATETIME; break;
  1360. case MYSQL_TYPE_YEAR: statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
  1361. case MYSQL_TYPE_NEWDATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
  1362. case MYSQL_TYPE_VARCHAR: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
  1363. case MYSQL_TYPE_BIT: statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
  1364. case MYSQL_TYPE_NEWDECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
  1365. case MYSQL_TYPE_ENUM: statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
  1366. case MYSQL_TYPE_SET: statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
  1367. case MYSQL_TYPE_JSON: statistic = STAT_TEXT_TYPE_FETCHED_JSON; break;
  1368. case MYSQL_TYPE_TINY_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
  1369. case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
  1370. case MYSQL_TYPE_LONG_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
  1371. case MYSQL_TYPE_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
  1372. case MYSQL_TYPE_VAR_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
  1373. case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
  1374. case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
  1375. default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
  1376. }
  1377. MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
  1378. }
  1379. #ifdef MYSQLND_STRING_TO_INT_CONVERSION
  1380. if (as_int_or_float && perm_bind.php_type == IS_LONG) {
  1381. zend_uchar save = *(p + len);
  1382. /* We have to make it ASCIIZ temporarily */
  1383. *(p + len) = '\0';
  1384. if (perm_bind.pack_len < SIZEOF_ZEND_LONG) {
  1385. /* direct conversion */
  1386. int64_t v =
  1387. #ifndef PHP_WIN32
  1388. atoll((char *) p);
  1389. #else
  1390. _atoi64((char *) p);
  1391. #endif
  1392. ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
  1393. } else {
  1394. uint64_t v =
  1395. #ifndef PHP_WIN32
  1396. (uint64_t) atoll((char *) p);
  1397. #else
  1398. (uint64_t) _atoi64((char *) p);
  1399. #endif
  1400. zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
  1401. /* We have to make it ASCIIZ temporarily */
  1402. #if SIZEOF_ZEND_LONG==8
  1403. if (uns == TRUE && v > 9223372036854775807L)
  1404. #elif SIZEOF_ZEND_LONG==4
  1405. if ((uns == TRUE && v > L64(2147483647)) ||
  1406. (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
  1407. (L64(-2147483648) > (int64_t) v))))
  1408. #else
  1409. #error Need fix for this architecture
  1410. #endif /* SIZEOF */
  1411. {
  1412. ZVAL_STRINGL(current_field, (char *)p, len);
  1413. } else {
  1414. ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
  1415. }
  1416. }
  1417. *(p + len) = save;
  1418. } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
  1419. zend_uchar save = *(p + len);
  1420. /* We have to make it ASCIIZ temporarily */
  1421. *(p + len) = '\0';
  1422. ZVAL_DOUBLE(current_field, atof((char *) p));
  1423. *(p + len) = save;
  1424. } else
  1425. #endif /* MYSQLND_STRING_TO_INT_CONVERSION */
  1426. if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
  1427. /*
  1428. BIT fields are specially handled. As they come as bit mask, they have
  1429. to be converted to human-readable representation.
  1430. */
  1431. ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
  1432. /*
  1433. We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
  1434. later in this function there will be an advancement.
  1435. */
  1436. p -= len;
  1437. if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
  1438. /* we are using the text protocol, so convert to string */
  1439. char tmp[22];
  1440. const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
  1441. ZVAL_STRINGL(current_field, tmp, tmp_len);
  1442. } else if (Z_TYPE_P(current_field) == IS_STRING) {
  1443. /* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
  1444. }
  1445. } else if (len == 0) {
  1446. ZVAL_EMPTY_STRING(current_field);
  1447. } else if (len == 1) {
  1448. ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p));
  1449. } else {
  1450. ZVAL_STRINGL(current_field, (char *)p, len);
  1451. }
  1452. p += len;
  1453. }
  1454. }
  1455. DBG_RETURN(PASS);
  1456. }
  1457. /* }}} */
  1458. /* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
  1459. enum_func_status
  1460. php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
  1461. const unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
  1462. const zend_bool as_int_or_float, MYSQLND_STATS * stats)
  1463. {
  1464. enum_func_status ret;
  1465. DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval");
  1466. ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
  1467. DBG_RETURN(ret);
  1468. }
  1469. /* }}} */
  1470. /* {{{ php_mysqlnd_rowp_read_text_protocol_c */
  1471. enum_func_status
  1472. php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_ROW_BUFFER * row_buffer, zval * fields,
  1473. const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
  1474. const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
  1475. {
  1476. enum_func_status ret;
  1477. DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c");
  1478. ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
  1479. DBG_RETURN(ret);
  1480. }
  1481. /* }}} */
  1482. /* {{{ php_mysqlnd_rowp_read */
  1483. /*
  1484. if normal statements => packet->fields is created by this function,
  1485. if PS => packet->fields is passed from outside
  1486. */
  1487. static enum_func_status
  1488. php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1489. {
  1490. MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
  1491. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1492. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1493. MYSQLND_VIO * vio = conn->vio;
  1494. MYSQLND_STATS * stats = conn->stats;
  1495. zend_uchar *p;
  1496. enum_func_status ret = PASS;
  1497. size_t data_size = 0;
  1498. DBG_ENTER("php_mysqlnd_rowp_read");
  1499. ret = php_mysqlnd_read_row_ex(pfc, vio, stats, error_info,
  1500. packet->result_set_memory_pool, &packet->row_buffer, &data_size);
  1501. if (FAIL == ret) {
  1502. goto end;
  1503. }
  1504. MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
  1505. MYSQLND_HEADER_SIZE + packet->header.size,
  1506. packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
  1507. 1);
  1508. /*
  1509. packet->row_buffer->ptr is of size 'data_size'
  1510. in pre-7.0 it was really 'data_size + 1' although it was counted as 'data_size'
  1511. The +1 was for the additional byte needed to \0 terminate the last string in the row.
  1512. This was needed as the zvals of pre-7.0 could use external memory (no copy param to ZVAL_STRINGL).
  1513. However, in 7.0+ the strings always copy. Thus this +1 byte was removed. Also the optimization or \0
  1514. terminating every string, which did overwrite the lengths from the packet. For this reason we needed
  1515. to keep (and copy) the lengths externally.
  1516. */
  1517. packet->header.size = data_size;
  1518. packet->row_buffer.size = data_size;
  1519. if (ERROR_MARKER == (*(p = packet->row_buffer.ptr))) {
  1520. /*
  1521. Error message as part of the result set,
  1522. not good but we should not hang. See:
  1523. Bug #27876 : SF with cyrillic variable name fails during execution
  1524. */
  1525. ret = FAIL;
  1526. php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
  1527. packet->error_info.error,
  1528. sizeof(packet->error_info.error),
  1529. &packet->error_info.error_no,
  1530. packet->error_info.sqlstate
  1531. );
  1532. } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
  1533. packet->eof = TRUE;
  1534. p++;
  1535. if (data_size > 1) {
  1536. packet->warning_count = uint2korr(p);
  1537. p += 2;
  1538. packet->server_status = uint2korr(p);
  1539. /* Seems we have 3 bytes reserved for future use */
  1540. DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
  1541. }
  1542. } else {
  1543. MYSQLND_INC_CONN_STATISTIC(stats,
  1544. packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
  1545. STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
  1546. packet->eof = FALSE;
  1547. /* packet->field_count is set by the user of the packet */
  1548. if (!packet->skip_extraction) {
  1549. if (!packet->fields) {
  1550. DBG_INF("Allocating packet->fields");
  1551. /*
  1552. old-API will probably set packet->fields to NULL every time, though for
  1553. unbuffered sets it makes not much sense as the zvals in this buffer matter,
  1554. not the buffer. Constantly allocating and deallocating brings nothing.
  1555. For PS - if stmt_store() is performed, thus we don't have a cursor, it will
  1556. behave just like old-API buffered. Cursors will behave like a bit different,
  1557. but mostly like old-API unbuffered and thus will populate this array with
  1558. value.
  1559. */
  1560. packet->fields = mnd_ecalloc(packet->field_count, sizeof(zval));
  1561. }
  1562. } else {
  1563. MYSQLND_INC_CONN_STATISTIC(stats,
  1564. packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
  1565. STAT_ROWS_SKIPPED_NORMAL);
  1566. }
  1567. }
  1568. end:
  1569. DBG_RETURN(ret);
  1570. }
  1571. /* }}} */
  1572. /* {{{ php_mysqlnd_rowp_free_mem */
  1573. static void
  1574. php_mysqlnd_rowp_free_mem(void * _packet)
  1575. {
  1576. MYSQLND_PACKET_ROW *p;
  1577. DBG_ENTER("php_mysqlnd_rowp_free_mem");
  1578. p = (MYSQLND_PACKET_ROW *) _packet;
  1579. if (p->row_buffer.ptr) {
  1580. p->result_set_memory_pool->free_chunk(p->result_set_memory_pool, p->row_buffer.ptr);
  1581. p->row_buffer.ptr = NULL;
  1582. }
  1583. /*
  1584. Don't free packet->fields :
  1585. - normal queries -> store_result() | fetch_row_unbuffered() will transfer
  1586. the ownership and NULL it.
  1587. - PS will pass in it the bound variables, we have to use them! and of course
  1588. not free the array. As it is passed to us, we should not clean it ourselves.
  1589. */
  1590. DBG_VOID_RETURN;
  1591. }
  1592. /* }}} */
  1593. /* {{{ php_mysqlnd_stats_read */
  1594. static enum_func_status
  1595. php_mysqlnd_stats_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1596. {
  1597. MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
  1598. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1599. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1600. MYSQLND_VIO * vio = conn->vio;
  1601. MYSQLND_STATS * stats = conn->stats;
  1602. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1603. const size_t buf_len = pfc->cmd_buffer.length;
  1604. zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  1605. DBG_ENTER("php_mysqlnd_stats_read");
  1606. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "statistics", PROT_STATS_PACKET)) {
  1607. DBG_RETURN(FAIL);
  1608. }
  1609. packet->message.s = mnd_emalloc(packet->header.size + 1);
  1610. memcpy(packet->message.s, buf, packet->header.size);
  1611. packet->message.s[packet->header.size] = '\0';
  1612. packet->message.l = packet->header.size;
  1613. DBG_RETURN(PASS);
  1614. }
  1615. /* }}} */
  1616. /* {{{ php_mysqlnd_stats_free_mem */
  1617. static
  1618. void php_mysqlnd_stats_free_mem(void * _packet)
  1619. {
  1620. MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet;
  1621. if (p->message.s) {
  1622. mnd_efree(p->message.s);
  1623. p->message.s = NULL;
  1624. }
  1625. }
  1626. /* }}} */
  1627. /* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
  1628. #define PREPARE_RESPONSE_SIZE_41 9
  1629. #define PREPARE_RESPONSE_SIZE_50 12
  1630. /* {{{ php_mysqlnd_prepare_read */
  1631. static enum_func_status
  1632. php_mysqlnd_prepare_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1633. {
  1634. MYSQLND_PACKET_PREPARE_RESPONSE *packet= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
  1635. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1636. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1637. MYSQLND_VIO * vio = conn->vio;
  1638. MYSQLND_STATS * stats = conn->stats;
  1639. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1640. /* In case of an error, we should have place to put it */
  1641. const size_t buf_len = pfc->cmd_buffer.length;
  1642. zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  1643. zend_uchar *p = buf;
  1644. const zend_uchar * const begin = buf;
  1645. unsigned int data_size;
  1646. DBG_ENTER("php_mysqlnd_prepare_read");
  1647. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET)) {
  1648. DBG_RETURN(FAIL);
  1649. }
  1650. BAIL_IF_NO_MORE_DATA;
  1651. data_size = packet->header.size;
  1652. packet->error_code = uint1korr(p);
  1653. p++;
  1654. BAIL_IF_NO_MORE_DATA;
  1655. if (ERROR_MARKER == packet->error_code) {
  1656. php_mysqlnd_read_error_from_line(p, data_size - 1,
  1657. packet->error_info.error,
  1658. sizeof(packet->error_info.error),
  1659. &packet->error_info.error_no,
  1660. packet->error_info.sqlstate
  1661. );
  1662. DBG_RETURN(PASS);
  1663. }
  1664. if (data_size != PREPARE_RESPONSE_SIZE_41 &&
  1665. data_size != PREPARE_RESPONSE_SIZE_50 &&
  1666. !(data_size > PREPARE_RESPONSE_SIZE_50)) {
  1667. DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
  1668. php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
  1669. DBG_RETURN(FAIL);
  1670. }
  1671. packet->stmt_id = uint4korr(p);
  1672. p += 4;
  1673. BAIL_IF_NO_MORE_DATA;
  1674. /* Number of columns in result set */
  1675. packet->field_count = uint2korr(p);
  1676. p += 2;
  1677. BAIL_IF_NO_MORE_DATA;
  1678. packet->param_count = uint2korr(p);
  1679. p += 2;
  1680. BAIL_IF_NO_MORE_DATA;
  1681. if (data_size > 9) {
  1682. /* 0x0 filler sent by the server for 5.0+ clients */
  1683. p++;
  1684. BAIL_IF_NO_MORE_DATA;
  1685. packet->warning_count = uint2korr(p);
  1686. }
  1687. DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u",
  1688. packet->stmt_id, packet->field_count, packet->param_count);
  1689. BAIL_IF_NO_MORE_DATA;
  1690. DBG_RETURN(PASS);
  1691. premature_end:
  1692. DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
  1693. php_error_docref(NULL, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  1694. p - begin - packet->header.size);
  1695. DBG_RETURN(FAIL);
  1696. }
  1697. /* }}} */
  1698. /* {{{ php_mysqlnd_chg_user_read */
  1699. static enum_func_status
  1700. php_mysqlnd_chg_user_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1701. {
  1702. MYSQLND_PACKET_CHG_USER_RESPONSE *packet= (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
  1703. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1704. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1705. MYSQLND_VIO * vio = conn->vio;
  1706. MYSQLND_STATS * stats = conn->stats;
  1707. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1708. /* There could be an error message */
  1709. const size_t buf_len = pfc->cmd_buffer.length;
  1710. zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
  1711. zend_uchar *p = buf;
  1712. const zend_uchar * const begin = buf;
  1713. DBG_ENTER("php_mysqlnd_chg_user_read");
  1714. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET)) {
  1715. DBG_RETURN(FAIL);
  1716. }
  1717. BAIL_IF_NO_MORE_DATA;
  1718. /*
  1719. Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
  1720. of encoded sequence for length.
  1721. */
  1722. /* Should be always 0x0 or ERROR_MARKER for error */
  1723. packet->response_code = uint1korr(p);
  1724. p++;
  1725. if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
  1726. /* We don't handle 3.23 authentication */
  1727. packet->server_asked_323_auth = TRUE;
  1728. DBG_RETURN(FAIL);
  1729. }
  1730. if (ERROR_MARKER == packet->response_code) {
  1731. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  1732. packet->error_info.error,
  1733. sizeof(packet->error_info.error),
  1734. &packet->error_info.error_no,
  1735. packet->error_info.sqlstate
  1736. );
  1737. }
  1738. BAIL_IF_NO_MORE_DATA;
  1739. if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
  1740. packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
  1741. packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
  1742. p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
  1743. packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
  1744. if (packet->new_auth_protocol_data_len) {
  1745. packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
  1746. memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
  1747. }
  1748. DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
  1749. DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
  1750. }
  1751. DBG_RETURN(PASS);
  1752. premature_end:
  1753. DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
  1754. php_error_docref(NULL, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  1755. p - begin - packet->header.size);
  1756. DBG_RETURN(FAIL);
  1757. }
  1758. /* }}} */
  1759. /* {{{ php_mysqlnd_chg_user_free_mem */
  1760. static void
  1761. php_mysqlnd_chg_user_free_mem(void * _packet)
  1762. {
  1763. MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
  1764. if (p->new_auth_protocol) {
  1765. mnd_efree(p->new_auth_protocol);
  1766. p->new_auth_protocol = NULL;
  1767. }
  1768. p->new_auth_protocol_len = 0;
  1769. if (p->new_auth_protocol_data) {
  1770. mnd_efree(p->new_auth_protocol_data);
  1771. p->new_auth_protocol_data = NULL;
  1772. }
  1773. p->new_auth_protocol_data_len = 0;
  1774. }
  1775. /* }}} */
  1776. /* {{{ php_mysqlnd_sha256_pk_request_write */
  1777. static
  1778. size_t php_mysqlnd_sha256_pk_request_write(MYSQLND_CONN_DATA * conn, void * _packet)
  1779. {
  1780. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1781. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1782. MYSQLND_VIO * vio = conn->vio;
  1783. MYSQLND_STATS * stats = conn->stats;
  1784. zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
  1785. size_t sent;
  1786. DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
  1787. int1store(buffer + MYSQLND_HEADER_SIZE, '\1');
  1788. sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
  1789. DBG_RETURN(sent);
  1790. }
  1791. /* }}} */
  1792. #define SHA256_PK_REQUEST_RESP_BUFFER_SIZE 2048
  1793. /* {{{ php_mysqlnd_sha256_pk_request_response_read */
  1794. static enum_func_status
  1795. php_mysqlnd_sha256_pk_request_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1796. {
  1797. MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * packet= (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
  1798. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1799. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1800. MYSQLND_VIO * vio = conn->vio;
  1801. MYSQLND_STATS * stats = conn->stats;
  1802. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1803. zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
  1804. zend_uchar *p = buf;
  1805. const zend_uchar * const begin = buf;
  1806. DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
  1807. /* leave space for terminating safety \0 */
  1808. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET)) {
  1809. DBG_RETURN(FAIL);
  1810. }
  1811. BAIL_IF_NO_MORE_DATA;
  1812. p++;
  1813. BAIL_IF_NO_MORE_DATA;
  1814. packet->public_key_len = packet->header.size - (p - buf);
  1815. packet->public_key = mnd_emalloc(packet->public_key_len + 1);
  1816. memcpy(packet->public_key, p, packet->public_key_len);
  1817. packet->public_key[packet->public_key_len] = '\0';
  1818. DBG_RETURN(PASS);
  1819. premature_end:
  1820. DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
  1821. php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  1822. p - begin - packet->header.size);
  1823. DBG_RETURN(FAIL);
  1824. }
  1825. /* }}} */
  1826. /* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
  1827. static void
  1828. php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet)
  1829. {
  1830. MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * p = (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
  1831. if (p->public_key) {
  1832. mnd_efree(p->public_key);
  1833. p->public_key = NULL;
  1834. }
  1835. p->public_key_len = 0;
  1836. }
  1837. /* }}} */
  1838. static
  1839. size_t php_mysqlnd_cached_sha2_result_write(MYSQLND_CONN_DATA * conn, void * _packet)
  1840. {
  1841. MYSQLND_PACKET_CACHED_SHA2_RESULT * packet= (MYSQLND_PACKET_CACHED_SHA2_RESULT *) _packet;
  1842. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1843. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1844. MYSQLND_VIO * vio = conn->vio;
  1845. MYSQLND_STATS * stats = conn->stats;
  1846. ALLOCA_FLAG(use_heap)
  1847. zend_uchar *buffer = do_alloca(MYSQLND_HEADER_SIZE + packet->password_len + 1, use_heap);
  1848. size_t sent;
  1849. DBG_ENTER("php_mysqlnd_cached_sha2_result_write");
  1850. if (packet->request == 1) {
  1851. int1store(buffer + MYSQLND_HEADER_SIZE, '\2');
  1852. sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
  1853. } else {
  1854. memcpy(buffer + MYSQLND_HEADER_SIZE, packet->password, packet->password_len);
  1855. sent = pfc->data->m.send(pfc, vio, buffer, packet->password_len, stats, error_info);
  1856. }
  1857. free_alloca(buffer, use_heap);
  1858. DBG_RETURN(sent);
  1859. }
  1860. static enum_func_status
  1861. php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
  1862. {
  1863. MYSQLND_PACKET_CACHED_SHA2_RESULT * packet= (MYSQLND_PACKET_CACHED_SHA2_RESULT *) _packet;
  1864. MYSQLND_ERROR_INFO * error_info = conn->error_info;
  1865. MYSQLND_PFC * pfc = conn->protocol_frame_codec;
  1866. MYSQLND_VIO * vio = conn->vio;
  1867. MYSQLND_STATS * stats = conn->stats;
  1868. MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
  1869. zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
  1870. zend_uchar *p = buf;
  1871. const zend_uchar * const begin = buf;
  1872. DBG_ENTER("php_mysqlnd_cached_sha2_result_read");
  1873. if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "PROT_CACHED_SHA2_RESULT_PACKET", PROT_CACHED_SHA2_RESULT_PACKET)) {
  1874. DBG_RETURN(FAIL);
  1875. }
  1876. BAIL_IF_NO_MORE_DATA;
  1877. packet->response_code = uint1korr(p);
  1878. p++;
  1879. BAIL_IF_NO_MORE_DATA;
  1880. if (ERROR_MARKER == packet->response_code) {
  1881. php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
  1882. packet->error, sizeof(packet->error),
  1883. &packet->error_no, packet->sqlstate
  1884. );
  1885. DBG_RETURN(PASS);
  1886. }
  1887. if (0xFE == packet->response_code) {
  1888. /* Authentication Switch Response */
  1889. if (packet->header.size > (size_t) (p - buf)) {
  1890. packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
  1891. packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
  1892. p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
  1893. packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
  1894. if (packet->new_auth_protocol_data_len) {
  1895. packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
  1896. memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
  1897. }
  1898. DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
  1899. DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
  1900. }
  1901. DBG_RETURN(PASS);
  1902. }
  1903. if (0x1 != packet->response_code) {
  1904. DBG_ERR_FMT("Unexpected response code %d", packet->response_code);
  1905. }
  1906. /* This is not really the response code, but we reuse the field. */
  1907. packet->response_code = uint1korr(p);
  1908. p++;
  1909. BAIL_IF_NO_MORE_DATA;
  1910. packet->result = uint1korr(p);
  1911. BAIL_IF_NO_MORE_DATA;
  1912. DBG_RETURN(PASS);
  1913. premature_end:
  1914. DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
  1915. php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
  1916. p - begin - packet->header.size);
  1917. DBG_RETURN(FAIL);
  1918. }
  1919. /* {{{ packet_methods */
  1920. static
  1921. mysqlnd_packet_methods packet_methods[PROT_LAST] =
  1922. {
  1923. {
  1924. php_mysqlnd_greet_read,
  1925. NULL, /* write */
  1926. php_mysqlnd_greet_free_mem,
  1927. }, /* PROT_GREET_PACKET */
  1928. {
  1929. NULL, /* read */
  1930. php_mysqlnd_auth_write,
  1931. NULL,
  1932. }, /* PROT_AUTH_PACKET */
  1933. {
  1934. php_mysqlnd_auth_response_read, /* read */
  1935. NULL, /* write */
  1936. php_mysqlnd_auth_response_free_mem,
  1937. }, /* PROT_AUTH_RESP_PACKET */
  1938. {
  1939. NULL, /* read */
  1940. php_mysqlnd_change_auth_response_write, /* write */
  1941. NULL,
  1942. }, /* PROT_CHANGE_AUTH_RESP_PACKET */
  1943. {
  1944. php_mysqlnd_ok_read, /* read */
  1945. NULL, /* write */
  1946. php_mysqlnd_ok_free_mem,
  1947. }, /* PROT_OK_PACKET */
  1948. {
  1949. php_mysqlnd_eof_read, /* read */
  1950. NULL, /* write */
  1951. NULL,
  1952. }, /* PROT_EOF_PACKET */
  1953. {
  1954. NULL, /* read */
  1955. php_mysqlnd_cmd_write, /* write */
  1956. NULL,
  1957. }, /* PROT_CMD_PACKET */
  1958. {
  1959. php_mysqlnd_rset_header_read, /* read */
  1960. NULL, /* write */
  1961. php_mysqlnd_rset_header_free_mem,
  1962. }, /* PROT_RSET_HEADER_PACKET */
  1963. {
  1964. php_mysqlnd_rset_field_read, /* read */
  1965. NULL, /* write */
  1966. NULL,
  1967. }, /* PROT_RSET_FLD_PACKET */
  1968. {
  1969. php_mysqlnd_rowp_read, /* read */
  1970. NULL, /* write */
  1971. php_mysqlnd_rowp_free_mem,
  1972. }, /* PROT_ROW_PACKET */
  1973. {
  1974. php_mysqlnd_stats_read, /* read */
  1975. NULL, /* write */
  1976. php_mysqlnd_stats_free_mem,
  1977. }, /* PROT_STATS_PACKET */
  1978. {
  1979. php_mysqlnd_prepare_read, /* read */
  1980. NULL, /* write */
  1981. NULL,
  1982. }, /* PROT_PREPARE_RESP_PACKET */
  1983. {
  1984. php_mysqlnd_chg_user_read, /* read */
  1985. NULL, /* write */
  1986. php_mysqlnd_chg_user_free_mem,
  1987. }, /* PROT_CHG_USER_RESP_PACKET */
  1988. {
  1989. NULL, /* read */
  1990. php_mysqlnd_sha256_pk_request_write,
  1991. NULL,
  1992. }, /* PROT_SHA256_PK_REQUEST_PACKET */
  1993. {
  1994. php_mysqlnd_sha256_pk_request_response_read,
  1995. NULL, /* write */
  1996. php_mysqlnd_sha256_pk_request_response_free_mem,
  1997. }, /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
  1998. {
  1999. php_mysqlnd_cached_sha2_result_read,
  2000. php_mysqlnd_cached_sha2_result_write,
  2001. NULL
  2002. } /* PROT_CACHED_SHA2_RESULT_PACKET */
  2003. };
  2004. /* }}} */
  2005. /* {{{ mysqlnd_protocol::init_greet_packet */
  2006. static void
  2007. MYSQLND_METHOD(mysqlnd_protocol, init_greet_packet)(struct st_mysqlnd_packet_greet *packet)
  2008. {
  2009. DBG_ENTER("mysqlnd_protocol::init_greet_packet");
  2010. memset(packet, 0, sizeof(*packet));
  2011. packet->header.m = &packet_methods[PROT_GREET_PACKET];
  2012. DBG_VOID_RETURN;
  2013. }
  2014. /* }}} */
  2015. /* {{{ mysqlnd_protocol::init_auth_packet */
  2016. static void
  2017. MYSQLND_METHOD(mysqlnd_protocol, init_auth_packet)(struct st_mysqlnd_packet_auth *packet)
  2018. {
  2019. DBG_ENTER("mysqlnd_protocol::init_auth_packet");
  2020. memset(packet, 0, sizeof(*packet));
  2021. packet->header.m = &packet_methods[PROT_AUTH_PACKET];
  2022. DBG_VOID_RETURN;
  2023. }
  2024. /* }}} */
  2025. /* {{{ mysqlnd_protocol::init_auth_response_packet */
  2026. static void
  2027. MYSQLND_METHOD(mysqlnd_protocol, init_auth_response_packet)(struct st_mysqlnd_packet_auth_response *packet)
  2028. {
  2029. DBG_ENTER("mysqlnd_protocol::init_auth_response_packet");
  2030. memset(packet, 0, sizeof(*packet));
  2031. packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
  2032. DBG_VOID_RETURN;
  2033. }
  2034. /* }}} */
  2035. /* {{{ mysqlnd_protocol::init_change_auth_response_packet */
  2036. static void
  2037. MYSQLND_METHOD(mysqlnd_protocol, init_change_auth_response_packet)(struct st_mysqlnd_packet_change_auth_response *packet)
  2038. {
  2039. DBG_ENTER("mysqlnd_protocol::init_change_auth_response_packet");
  2040. memset(packet, 0, sizeof(*packet));
  2041. packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
  2042. DBG_VOID_RETURN;
  2043. }
  2044. /* }}} */
  2045. /* {{{ mysqlnd_protocol::init_ok_packet */
  2046. static void
  2047. MYSQLND_METHOD(mysqlnd_protocol, init_ok_packet)(struct st_mysqlnd_packet_ok *packet)
  2048. {
  2049. DBG_ENTER("mysqlnd_protocol::init_ok_packet");
  2050. memset(packet, 0, sizeof(*packet));
  2051. packet->header.m = &packet_methods[PROT_OK_PACKET];
  2052. DBG_VOID_RETURN;
  2053. }
  2054. /* }}} */
  2055. /* {{{ mysqlnd_protocol::init_eof_packet */
  2056. static void
  2057. MYSQLND_METHOD(mysqlnd_protocol, init_eof_packet)(struct st_mysqlnd_packet_eof *packet)
  2058. {
  2059. DBG_ENTER("mysqlnd_protocol::init_eof_packet");
  2060. memset(packet, 0, sizeof(*packet));
  2061. packet->header.m = &packet_methods[PROT_EOF_PACKET];
  2062. DBG_VOID_RETURN;
  2063. }
  2064. /* }}} */
  2065. /* {{{ mysqlnd_protocol::init_command_packet */
  2066. static void
  2067. MYSQLND_METHOD(mysqlnd_protocol, init_command_packet)(struct st_mysqlnd_packet_command *packet)
  2068. {
  2069. DBG_ENTER("mysqlnd_protocol::init_command_packet");
  2070. memset(packet, 0, sizeof(*packet));
  2071. packet->header.m = &packet_methods[PROT_CMD_PACKET];
  2072. DBG_VOID_RETURN;
  2073. }
  2074. /* }}} */
  2075. /* {{{ mysqlnd_protocol::init_rset_packet */
  2076. static void
  2077. MYSQLND_METHOD(mysqlnd_protocol, init_rset_header_packet)(struct st_mysqlnd_packet_rset_header *packet)
  2078. {
  2079. DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
  2080. memset(packet, 0, sizeof(*packet));
  2081. packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
  2082. DBG_VOID_RETURN;
  2083. }
  2084. /* }}} */
  2085. /* {{{ mysqlnd_protocol::init_result_field_packet */
  2086. static void
  2087. MYSQLND_METHOD(mysqlnd_protocol, init_result_field_packet)(struct st_mysqlnd_packet_res_field *packet)
  2088. {
  2089. DBG_ENTER("mysqlnd_protocol::init_result_field_packet");
  2090. memset(packet, 0, sizeof(*packet));
  2091. packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
  2092. DBG_VOID_RETURN;
  2093. }
  2094. /* }}} */
  2095. /* {{{ mysqlnd_protocol::init_row_packet */
  2096. static void
  2097. MYSQLND_METHOD(mysqlnd_protocol, init_row_packet)(struct st_mysqlnd_packet_row *packet)
  2098. {
  2099. DBG_ENTER("mysqlnd_protocol::init_row_packet");
  2100. memset(packet, 0, sizeof(*packet));
  2101. packet->header.m = &packet_methods[PROT_ROW_PACKET];
  2102. DBG_VOID_RETURN;
  2103. }
  2104. /* }}} */
  2105. /* {{{ mysqlnd_protocol::init_stats_packet */
  2106. static void
  2107. MYSQLND_METHOD(mysqlnd_protocol, init_stats_packet)(struct st_mysqlnd_packet_stats *packet)
  2108. {
  2109. DBG_ENTER("mysqlnd_protocol::init_stats_packet");
  2110. memset(packet, 0, sizeof(*packet));
  2111. packet->header.m = &packet_methods[PROT_STATS_PACKET];
  2112. DBG_VOID_RETURN;
  2113. }
  2114. /* }}} */
  2115. /* {{{ mysqlnd_protocol::init_prepare_response_packet */
  2116. static void
  2117. MYSQLND_METHOD(mysqlnd_protocol, init_prepare_response_packet)(struct st_mysqlnd_packet_prepare_response *packet)
  2118. {
  2119. DBG_ENTER("mysqlnd_protocol::init_prepare_response_packet");
  2120. memset(packet, 0, sizeof(*packet));
  2121. packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
  2122. DBG_VOID_RETURN;
  2123. }
  2124. /* }}} */
  2125. /* {{{ mysqlnd_protocol::init_change_user_response_packet */
  2126. static void
  2127. MYSQLND_METHOD(mysqlnd_protocol, init_change_user_response_packet)(struct st_mysqlnd_packet_chg_user_resp *packet)
  2128. {
  2129. DBG_ENTER("mysqlnd_protocol::init_change_user_response_packet");
  2130. memset(packet, 0, sizeof(*packet));
  2131. packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
  2132. DBG_VOID_RETURN;
  2133. }
  2134. /* }}} */
  2135. /* {{{ mysqlnd_protocol::init_sha256_pk_request_packet */
  2136. static void
  2137. MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_packet)(struct st_mysqlnd_packet_sha256_pk_request *packet)
  2138. {
  2139. DBG_ENTER("mysqlnd_protocol::init_sha256_pk_request_packet");
  2140. memset(packet, 0, sizeof(*packet));
  2141. packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
  2142. DBG_VOID_RETURN;
  2143. }
  2144. /* }}} */
  2145. /* {{{ mysqlnd_protocol::init_sha256_pk_request_response_packet */
  2146. static void
  2147. MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_response_packet)(struct st_mysqlnd_packet_sha256_pk_request_response *packet)
  2148. {
  2149. DBG_ENTER("mysqlnd_protocol::init_sha256_pk_request_response_packet");
  2150. memset(packet, 0, sizeof(*packet));
  2151. packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
  2152. DBG_VOID_RETURN;
  2153. }
  2154. /* }}} */
  2155. /* {{{ mysqlnd_protocol::init_cached_sha2_result_packet */
  2156. static void
  2157. MYSQLND_METHOD(mysqlnd_protocol, init_cached_sha2_result_packet)(struct st_mysqlnd_packet_cached_sha2_result *packet)
  2158. {
  2159. DBG_ENTER("mysqlnd_protocol::init_cached_sha2_result_packet");
  2160. memset(packet, 0, sizeof(*packet));
  2161. packet->header.m = &packet_methods[PROT_CACHED_SHA2_RESULT_PACKET];
  2162. DBG_VOID_RETURN;
  2163. }
  2164. /* }}} */
  2165. /* {{{ mysqlnd_protocol::send_command */
  2166. static enum_func_status
  2167. MYSQLND_METHOD(mysqlnd_protocol, send_command)(
  2168. MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
  2169. const enum php_mysqlnd_server_command command,
  2170. const zend_uchar * const arg, const size_t arg_len,
  2171. const zend_bool silent,
  2172. struct st_mysqlnd_connection_state * connection_state,
  2173. MYSQLND_ERROR_INFO * error_info,
  2174. MYSQLND_UPSERT_STATUS * upsert_status,
  2175. MYSQLND_STATS * stats,
  2176. func_mysqlnd_conn_data__send_close send_close,
  2177. void * send_close_ctx)
  2178. {
  2179. enum_func_status ret = PASS;
  2180. MYSQLND_PACKET_COMMAND cmd_packet;
  2181. enum mysqlnd_connection_state state;
  2182. DBG_ENTER("mysqlnd_protocol::send_command");
  2183. DBG_INF_FMT("command=%s silent=%u", mysqlnd_command_to_text[command], silent);
  2184. DBG_INF_FMT("server_status=%u", UPSERT_STATUS_GET_SERVER_STATUS(upsert_status));
  2185. DBG_INF_FMT("sending %u bytes", arg_len + 1); /* + 1 is for the command */
  2186. state = connection_state->m->get(connection_state);
  2187. switch (state) {
  2188. case CONN_READY:
  2189. break;
  2190. case CONN_QUIT_SENT:
  2191. SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
  2192. DBG_ERR("Server is gone");
  2193. DBG_RETURN(FAIL);
  2194. default:
  2195. SET_CLIENT_ERROR(error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
  2196. DBG_ERR_FMT("Command out of sync. State=%u", state);
  2197. DBG_RETURN(FAIL);
  2198. }
  2199. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
  2200. SET_EMPTY_ERROR(error_info);
  2201. payload_decoder_factory->m.init_command_packet(&cmd_packet);
  2202. cmd_packet.command = command;
  2203. if (arg && arg_len) {
  2204. cmd_packet.argument.s = (char *) arg;
  2205. cmd_packet.argument.l = arg_len;
  2206. }
  2207. MYSQLND_INC_CONN_STATISTIC(stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ );
  2208. if (! PACKET_WRITE(payload_decoder_factory->conn, &cmd_packet)) {
  2209. if (!silent && error_info->error_no != CR_SERVER_GONE_ERROR) {
  2210. DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
  2211. php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
  2212. }
  2213. connection_state->m->set(connection_state, CONN_QUIT_SENT);
  2214. send_close(send_close_ctx);
  2215. DBG_ERR("Server is gone");
  2216. ret = FAIL;
  2217. }
  2218. PACKET_FREE(&cmd_packet);
  2219. DBG_RETURN(ret);
  2220. }
  2221. /* }}} */
  2222. /* {{{ mysqlnd_protocol::send_command_handle_OK */
  2223. static enum_func_status
  2224. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK)(
  2225. MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
  2226. MYSQLND_ERROR_INFO * const error_info,
  2227. MYSQLND_UPSERT_STATUS * const upsert_status,
  2228. const zend_bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
  2229. MYSQLND_STRING * const last_message)
  2230. {
  2231. enum_func_status ret = FAIL;
  2232. MYSQLND_PACKET_OK ok_response;
  2233. payload_decoder_factory->m.init_ok_packet(&ok_response);
  2234. DBG_ENTER("mysqlnd_protocol::send_command_handle_OK");
  2235. if (FAIL == (ret = PACKET_READ(payload_decoder_factory->conn, &ok_response))) {
  2236. DBG_INF("Error while reading OK packet");
  2237. SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
  2238. goto end;
  2239. }
  2240. DBG_INF_FMT("OK from server");
  2241. if (0xFF == ok_response.field_count) {
  2242. /* The server signalled error. Set the error */
  2243. SET_CLIENT_ERROR(error_info, ok_response.error_no, ok_response.sqlstate, ok_response.error);
  2244. ret = FAIL;
  2245. /*
  2246. Cover a protocol design error: error packet does not
  2247. contain the server status. Therefore, the client has no way
  2248. to find out whether there are more result sets of
  2249. a multiple-result-set statement pending. Luckily, in 5.0 an
  2250. error always aborts execution of a statement, wherever it is
  2251. a multi-statement or a stored procedure, so it should be
  2252. safe to unconditionally turn off the flag here.
  2253. */
  2254. upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
  2255. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
  2256. } else {
  2257. SET_NEW_MESSAGE(last_message->s, last_message->l,
  2258. ok_response.message, ok_response.message_len);
  2259. if (!ignore_upsert_status) {
  2260. UPSERT_STATUS_RESET(upsert_status);
  2261. UPSERT_STATUS_SET_WARNINGS(upsert_status, ok_response.warning_count);
  2262. UPSERT_STATUS_SET_SERVER_STATUS(upsert_status, ok_response.server_status);
  2263. UPSERT_STATUS_SET_AFFECTED_ROWS(upsert_status, ok_response.affected_rows);
  2264. UPSERT_STATUS_SET_LAST_INSERT_ID(upsert_status, ok_response.last_insert_id);
  2265. } else {
  2266. /* LOAD DATA */
  2267. }
  2268. }
  2269. end:
  2270. PACKET_FREE(&ok_response);
  2271. DBG_INF(ret == PASS ? "PASS":"FAIL");
  2272. DBG_RETURN(ret);
  2273. }
  2274. /* }}} */
  2275. /* {{{ mysqlnd_protocol::send_command_handle_EOF */
  2276. static enum_func_status
  2277. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF)(
  2278. MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
  2279. MYSQLND_ERROR_INFO * const error_info,
  2280. MYSQLND_UPSERT_STATUS * const upsert_status)
  2281. {
  2282. enum_func_status ret = FAIL;
  2283. MYSQLND_PACKET_EOF response;
  2284. payload_decoder_factory->m.init_eof_packet(&response);
  2285. DBG_ENTER("mysqlnd_protocol::send_command_handle_EOF");
  2286. if (FAIL == (ret = PACKET_READ(payload_decoder_factory->conn, &response))) {
  2287. DBG_INF("Error while reading EOF packet");
  2288. SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
  2289. } else if (0xFF == response.field_count) {
  2290. /* The server signalled error. Set the error */
  2291. DBG_INF_FMT("Error_no=%d SQLstate=%s Error=%s", response.error_no, response.sqlstate, response.error);
  2292. SET_CLIENT_ERROR(error_info, response.error_no, response.sqlstate, response.error);
  2293. UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
  2294. } else if (0xFE != response.field_count) {
  2295. SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
  2296. DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", response.field_count);
  2297. php_error_docref(NULL, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X", response.field_count);
  2298. } else {
  2299. DBG_INF_FMT("EOF from server");
  2300. }
  2301. PACKET_FREE(&response);
  2302. DBG_INF(ret == PASS ? "PASS":"FAIL");
  2303. DBG_RETURN(ret);
  2304. }
  2305. /* }}} */
  2306. /* {{{ send_command_handle_response */
  2307. static enum_func_status
  2308. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response)(
  2309. MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
  2310. const enum mysqlnd_packet_type ok_packet,
  2311. const zend_bool silent,
  2312. const enum php_mysqlnd_server_command command,
  2313. const zend_bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
  2314. MYSQLND_ERROR_INFO * error_info,
  2315. MYSQLND_UPSERT_STATUS * upsert_status,
  2316. MYSQLND_STRING * last_message
  2317. )
  2318. {
  2319. enum_func_status ret = FAIL;
  2320. DBG_ENTER("mysqlnd_protocol::send_command_handle_response");
  2321. DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
  2322. switch (ok_packet) {
  2323. case PROT_OK_PACKET:
  2324. ret = payload_decoder_factory->m.send_command_handle_OK(payload_decoder_factory, error_info, upsert_status, ignore_upsert_status, last_message);
  2325. break;
  2326. case PROT_EOF_PACKET:
  2327. ret = payload_decoder_factory->m.send_command_handle_EOF(payload_decoder_factory, error_info, upsert_status);
  2328. break;
  2329. default:
  2330. SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
  2331. php_error_docref(NULL, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
  2332. break;
  2333. }
  2334. if (!silent && error_info->error_no == CR_MALFORMED_PACKET) {
  2335. php_error_docref(NULL, E_WARNING, "Error while reading %s's response packet. PID=%d", mysqlnd_command_to_text[command], getpid());
  2336. }
  2337. DBG_INF(ret == PASS ? "PASS":"FAIL");
  2338. DBG_RETURN(ret);
  2339. }
  2340. /* }}} */
  2341. MYSQLND_CLASS_METHODS_START(mysqlnd_protocol_payload_decoder_factory)
  2342. MYSQLND_METHOD(mysqlnd_protocol, init_greet_packet),
  2343. MYSQLND_METHOD(mysqlnd_protocol, init_auth_packet),
  2344. MYSQLND_METHOD(mysqlnd_protocol, init_auth_response_packet),
  2345. MYSQLND_METHOD(mysqlnd_protocol, init_change_auth_response_packet),
  2346. MYSQLND_METHOD(mysqlnd_protocol, init_ok_packet),
  2347. MYSQLND_METHOD(mysqlnd_protocol, init_command_packet),
  2348. MYSQLND_METHOD(mysqlnd_protocol, init_eof_packet),
  2349. MYSQLND_METHOD(mysqlnd_protocol, init_rset_header_packet),
  2350. MYSQLND_METHOD(mysqlnd_protocol, init_result_field_packet),
  2351. MYSQLND_METHOD(mysqlnd_protocol, init_row_packet),
  2352. MYSQLND_METHOD(mysqlnd_protocol, init_stats_packet),
  2353. MYSQLND_METHOD(mysqlnd_protocol, init_prepare_response_packet),
  2354. MYSQLND_METHOD(mysqlnd_protocol, init_change_user_response_packet),
  2355. MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_packet),
  2356. MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_response_packet),
  2357. MYSQLND_METHOD(mysqlnd_protocol, init_cached_sha2_result_packet),
  2358. MYSQLND_METHOD(mysqlnd_protocol, send_command),
  2359. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response),
  2360. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK),
  2361. MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF),
  2362. MYSQLND_CLASS_METHODS_END;
  2363. /* {{{ mysqlnd_protocol_payload_decoder_factory_init */
  2364. PHPAPI MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
  2365. mysqlnd_protocol_payload_decoder_factory_init(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
  2366. {
  2367. MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * ret;
  2368. DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_init");
  2369. ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_payload_decoder_factory(conn, persistent);
  2370. DBG_RETURN(ret);
  2371. }
  2372. /* }}} */
  2373. /* {{{ mysqlnd_protocol_payload_decoder_factory_free */
  2374. PHPAPI void
  2375. mysqlnd_protocol_payload_decoder_factory_free(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory)
  2376. {
  2377. DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_free");
  2378. if (factory) {
  2379. zend_bool pers = factory->persistent;
  2380. mnd_pefree(factory, pers);
  2381. }
  2382. DBG_VOID_RETURN;
  2383. }
  2384. /* }}} */