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