1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2015 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
1576 /* {{{ php_mysqlnd_rowp_read_text_protocol */
1577 enum_func_status
php_mysqlnd_rowp_read_text_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)1578 php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
1579 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1580 zend_bool as_int_or_float, MYSQLND_STATS * stats TSRMLS_DC)
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
1589 DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
1590
1591 if (!fields) {
1592 DBG_RETURN(FAIL);
1593 }
1594
1595 end_field = (start_field = fields) + field_count;
1596
1597 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1598 DBG_INF("Directly creating zval");
1599 MAKE_STD_ZVAL(*current_field);
1600 if (!*current_field) {
1601 DBG_RETURN(FAIL);
1602 }
1603 }
1604
1605 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1606 /* Don't reverse the order. It is significant!*/
1607 zend_uchar *this_field_len_pos = p;
1608 /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
1609 unsigned long len = php_mysqlnd_net_field_length(&p);
1610
1611 if (current_field > start_field && last_field_was_string) {
1612 /*
1613 Normal queries:
1614 We have to put \0 now to the end of the previous field, if it was
1615 a string. IS_NULL doesn't matter. Because we have already read our
1616 length, then we can overwrite it in the row buffer.
1617 This statement terminates the previous field, not the current one.
1618
1619 NULL_LENGTH is encoded in one byte, so we can stick a \0 there.
1620 Any string's length is encoded in at least one byte, so we can stick
1621 a \0 there.
1622 */
1623
1624 *this_field_len_pos = '\0';
1625 }
1626
1627 /* NULL or NOT NULL, this is the question! */
1628 if (len == MYSQLND_NULL_LENGTH) {
1629 ZVAL_NULL(*current_field);
1630 last_field_was_string = FALSE;
1631 } else {
1632 #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
1633 struct st_mysqlnd_perm_bind perm_bind =
1634 mysqlnd_ps_fetch_functions[fields_metadata[i].type];
1635 #endif
1636 if (MYSQLND_G(collect_statistics)) {
1637 enum_mysqlnd_collected_stats statistic;
1638 switch (fields_metadata[i].type) {
1639 case MYSQL_TYPE_DECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
1640 case MYSQL_TYPE_TINY: statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
1641 case MYSQL_TYPE_SHORT: statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
1642 case MYSQL_TYPE_LONG: statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
1643 case MYSQL_TYPE_FLOAT: statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
1644 case MYSQL_TYPE_DOUBLE: statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
1645 case MYSQL_TYPE_NULL: statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
1646 case MYSQL_TYPE_TIMESTAMP: statistic = STAT_TEXT_TYPE_FETCHED_TIMESTAMP; break;
1647 case MYSQL_TYPE_LONGLONG: statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
1648 case MYSQL_TYPE_INT24: statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
1649 case MYSQL_TYPE_DATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1650 case MYSQL_TYPE_TIME: statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
1651 case MYSQL_TYPE_DATETIME: statistic = STAT_TEXT_TYPE_FETCHED_DATETIME; break;
1652 case MYSQL_TYPE_YEAR: statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
1653 case MYSQL_TYPE_NEWDATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1654 case MYSQL_TYPE_VARCHAR: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1655 case MYSQL_TYPE_BIT: statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
1656 case MYSQL_TYPE_NEWDECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
1657 case MYSQL_TYPE_ENUM: statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
1658 case MYSQL_TYPE_SET: statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
1659 case MYSQL_TYPE_TINY_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1660 case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1661 case MYSQL_TYPE_LONG_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1662 case MYSQL_TYPE_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1663 case MYSQL_TYPE_VAR_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1664 case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1665 case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
1666 default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
1667 }
1668 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
1669 }
1670 #ifdef MYSQLND_STRING_TO_INT_CONVERSION
1671 if (as_int_or_float && perm_bind.php_type == IS_LONG) {
1672 zend_uchar save = *(p + len);
1673 /* We have to make it ASCIIZ temporarily */
1674 *(p + len) = '\0';
1675 if (perm_bind.pack_len < SIZEOF_LONG) {
1676 /* direct conversion */
1677 int64_t v =
1678 #ifndef PHP_WIN32
1679 atoll((char *) p);
1680 #else
1681 _atoi64((char *) p);
1682 #endif
1683 ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
1684 } else {
1685 uint64_t v =
1686 #ifndef PHP_WIN32
1687 (uint64_t) atoll((char *) p);
1688 #else
1689 (uint64_t) _atoi64((char *) p);
1690 #endif
1691 zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
1692 /* We have to make it ASCIIZ temporarily */
1693 #if SIZEOF_LONG==8
1694 if (uns == TRUE && v > 9223372036854775807L)
1695 #elif SIZEOF_LONG==4
1696 if ((uns == TRUE && v > L64(2147483647)) ||
1697 (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
1698 (L64(-2147483648) > (int64_t) v))))
1699 #else
1700 #error Need fix for this architecture
1701 #endif /* SIZEOF */
1702 {
1703 ZVAL_STRINGL(*current_field, (char *)p, len, 0);
1704 } else {
1705 ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
1706 }
1707 }
1708 *(p + len) = save;
1709 } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
1710 zend_uchar save = *(p + len);
1711 /* We have to make it ASCIIZ temporarily */
1712 *(p + len) = '\0';
1713 ZVAL_DOUBLE(*current_field, atof((char *) p));
1714 *(p + len) = save;
1715 } else
1716 #endif /* MYSQLND_STRING_TO_INT_CONVERSION */
1717 if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
1718 /*
1719 BIT fields are specially handled. As they come as bit mask, we have
1720 to convert it to human-readable representation. As the bits take
1721 less space in the protocol than the numbers they represent, we don't
1722 have enough space in the packet buffer to overwrite inside.
1723 Thus, a bit more space is pre-allocated at the end of the buffer,
1724 see php_mysqlnd_rowp_read(). And we add the strings at the end.
1725 Definitely not nice, _hackish_ :(, but works.
1726 */
1727 zend_uchar *start = bit_area;
1728 ps_fetch_from_1_to_8_bytes(*current_field, &(fields_metadata[i]), 0, &p, len TSRMLS_CC);
1729 /*
1730 We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
1731 later in this function there will be an advancement.
1732 */
1733 p -= len;
1734 if (Z_TYPE_PP(current_field) == IS_LONG) {
1735 bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_PP(current_field));
1736 ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
1737 } else if (Z_TYPE_PP(current_field) == IS_STRING){
1738 memcpy(bit_area, Z_STRVAL_PP(current_field), Z_STRLEN_PP(current_field));
1739 bit_area += Z_STRLEN_PP(current_field);
1740 *bit_area++ = '\0';
1741 zval_dtor(*current_field);
1742 ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
1743 }
1744 } else {
1745 ZVAL_STRINGL(*current_field, (char *)p, len, 0);
1746 }
1747 p += len;
1748 last_field_was_string = TRUE;
1749 }
1750 }
1751 if (last_field_was_string) {
1752 /* Normal queries: The buffer has one more byte at the end, because we need it */
1753 row_buffer->ptr[data_size] = '\0';
1754 }
1755
1756 DBG_RETURN(PASS);
1757 }
1758 /* }}} */
1759
1760
1761 /* {{{ php_mysqlnd_rowp_read */
1762 /*
1763 if normal statements => packet->fields is created by this function,
1764 if PS => packet->fields is passed from outside
1765 */
1766 static enum_func_status
php_mysqlnd_rowp_read(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)1767 php_mysqlnd_rowp_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
1768 {
1769 zend_uchar *p;
1770 enum_func_status ret = PASS;
1771 MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
1772 size_t post_alloc_for_bit_fields = 0;
1773 size_t data_size = 0;
1774
1775 DBG_ENTER("php_mysqlnd_rowp_read");
1776
1777 if (!packet->binary_protocol && packet->bit_fields_count) {
1778 /* For every field we need terminating \0 */
1779 post_alloc_for_bit_fields = packet->bit_fields_total_len + packet->bit_fields_count;
1780 }
1781
1782 ret = php_mysqlnd_read_row_ex(conn, packet->result_set_memory_pool, &packet->row_buffer, &data_size,
1783 packet->persistent_alloc, post_alloc_for_bit_fields
1784 TSRMLS_CC);
1785 if (FAIL == ret) {
1786 goto end;
1787 }
1788 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
1789 MYSQLND_HEADER_SIZE + packet->header.size,
1790 packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
1791 1);
1792
1793 /* packet->row_buffer->ptr is of size 'data_size + 1' */
1794 packet->header.size = data_size;
1795 packet->row_buffer->app = data_size;
1796
1797 if (ERROR_MARKER == (*(p = packet->row_buffer->ptr))) {
1798 /*
1799 Error message as part of the result set,
1800 not good but we should not hang. See:
1801 Bug #27876 : SF with cyrillic variable name fails during execution
1802 */
1803 ret = FAIL;
1804 php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
1805 packet->error_info.error,
1806 sizeof(packet->error_info.error),
1807 &packet->error_info.error_no,
1808 packet->error_info.sqlstate
1809 TSRMLS_CC);
1810 } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
1811 packet->eof = TRUE;
1812 p++;
1813 if (data_size > 1) {
1814 packet->warning_count = uint2korr(p);
1815 p += 2;
1816 packet->server_status = uint2korr(p);
1817 /* Seems we have 3 bytes reserved for future use */
1818 DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
1819 }
1820 } else {
1821 MYSQLND_INC_CONN_STATISTIC(conn->stats,
1822 packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
1823 STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
1824
1825 packet->eof = FALSE;
1826 /* packet->field_count is set by the user of the packet */
1827
1828 if (!packet->skip_extraction) {
1829 if (!packet->fields) {
1830 DBG_INF("Allocating packet->fields");
1831 /*
1832 old-API will probably set packet->fields to NULL every time, though for
1833 unbuffered sets it makes not much sense as the zvals in this buffer matter,
1834 not the buffer. Constantly allocating and deallocating brings nothing.
1835
1836 For PS - if stmt_store() is performed, thus we don't have a cursor, it will
1837 behave just like old-API buffered. Cursors will behave like a bit different,
1838 but mostly like old-API unbuffered and thus will populate this array with
1839 value.
1840 */
1841 packet->fields = (zval **) mnd_pecalloc(packet->field_count, sizeof(zval *),
1842 packet->persistent_alloc);
1843 }
1844 } else {
1845 MYSQLND_INC_CONN_STATISTIC(conn->stats,
1846 packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
1847 STAT_ROWS_SKIPPED_NORMAL);
1848 }
1849 }
1850
1851 end:
1852 DBG_RETURN(ret);
1853 }
1854 /* }}} */
1855
1856
1857 /* {{{ php_mysqlnd_rowp_free_mem */
1858 static void
php_mysqlnd_rowp_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)1859 php_mysqlnd_rowp_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
1860 {
1861 MYSQLND_PACKET_ROW *p;
1862
1863 DBG_ENTER("php_mysqlnd_rowp_free_mem");
1864 p = (MYSQLND_PACKET_ROW *) _packet;
1865 if (p->row_buffer) {
1866 p->row_buffer->free_chunk(p->row_buffer TSRMLS_CC);
1867 p->row_buffer = NULL;
1868 }
1869 DBG_INF_FMT("stack_allocation=%u persistent=%u", (int)stack_allocation, (int)p->header.persistent);
1870 /*
1871 Don't free packet->fields :
1872 - normal queries -> store_result() | fetch_row_unbuffered() will transfer
1873 the ownership and NULL it.
1874 - PS will pass in it the bound variables, we have to use them! and of course
1875 not free the array. As it is passed to us, we should not clean it ourselves.
1876 */
1877 if (!stack_allocation) {
1878 mnd_pefree(p, p->header.persistent);
1879 }
1880 DBG_VOID_RETURN;
1881 }
1882 /* }}} */
1883
1884
1885 /* {{{ php_mysqlnd_stats_read */
1886 static enum_func_status
php_mysqlnd_stats_read(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)1887 php_mysqlnd_stats_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
1888 {
1889 MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
1890 size_t buf_len = conn->net->cmd_buffer.length;
1891 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1892
1893 DBG_ENTER("php_mysqlnd_stats_read");
1894
1895 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "statistics", PROT_STATS_PACKET);
1896
1897 packet->message = mnd_emalloc(packet->header.size + 1);
1898 memcpy(packet->message, buf, packet->header.size);
1899 packet->message[packet->header.size] = '\0';
1900 packet->message_len = packet->header.size;
1901
1902 DBG_RETURN(PASS);
1903 }
1904 /* }}} */
1905
1906
1907 /* {{{ php_mysqlnd_stats_free_mem */
1908 static
php_mysqlnd_stats_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)1909 void php_mysqlnd_stats_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
1910 {
1911 MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet;
1912 if (p->message) {
1913 mnd_efree(p->message);
1914 p->message = NULL;
1915 }
1916 if (!stack_allocation) {
1917 mnd_pefree(p, p->header.persistent);
1918 }
1919 }
1920 /* }}} */
1921
1922
1923 /* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
1924 #define PREPARE_RESPONSE_SIZE_41 9
1925 #define PREPARE_RESPONSE_SIZE_50 12
1926
1927 /* {{{ php_mysqlnd_prepare_read */
1928 static enum_func_status
php_mysqlnd_prepare_read(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)1929 php_mysqlnd_prepare_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
1930 {
1931 /* In case of an error, we should have place to put it */
1932 size_t buf_len = conn->net->cmd_buffer.length;
1933 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
1934 zend_uchar *p = buf;
1935 zend_uchar *begin = buf;
1936 unsigned int data_size;
1937 MYSQLND_PACKET_PREPARE_RESPONSE *packet= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
1938
1939 DBG_ENTER("php_mysqlnd_prepare_read");
1940
1941 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET);
1942 BAIL_IF_NO_MORE_DATA;
1943
1944 data_size = packet->header.size;
1945 packet->error_code = uint1korr(p);
1946 p++;
1947 BAIL_IF_NO_MORE_DATA;
1948
1949 if (ERROR_MARKER == packet->error_code) {
1950 php_mysqlnd_read_error_from_line(p, data_size - 1,
1951 packet->error_info.error,
1952 sizeof(packet->error_info.error),
1953 &packet->error_info.error_no,
1954 packet->error_info.sqlstate
1955 TSRMLS_CC);
1956 DBG_RETURN(PASS);
1957 }
1958
1959 if (data_size != PREPARE_RESPONSE_SIZE_41 &&
1960 data_size != PREPARE_RESPONSE_SIZE_50 &&
1961 !(data_size > PREPARE_RESPONSE_SIZE_50)) {
1962 DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
1963 php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
1964 DBG_RETURN(FAIL);
1965 }
1966
1967 packet->stmt_id = uint4korr(p);
1968 p += 4;
1969 BAIL_IF_NO_MORE_DATA;
1970
1971 /* Number of columns in result set */
1972 packet->field_count = uint2korr(p);
1973 p += 2;
1974 BAIL_IF_NO_MORE_DATA;
1975
1976 packet->param_count = uint2korr(p);
1977 p += 2;
1978 BAIL_IF_NO_MORE_DATA;
1979
1980 if (data_size > 9) {
1981 /* 0x0 filler sent by the server for 5.0+ clients */
1982 p++;
1983 BAIL_IF_NO_MORE_DATA;
1984
1985 packet->warning_count = uint2korr(p);
1986 }
1987
1988 DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u",
1989 packet->stmt_id, packet->field_count, packet->param_count);
1990
1991 BAIL_IF_NO_MORE_DATA;
1992
1993 DBG_RETURN(PASS);
1994 premature_end:
1995 DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
1996 php_error_docref(NULL TSRMLS_CC, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
1997 p - begin - packet->header.size);
1998 DBG_RETURN(FAIL);
1999 }
2000 /* }}} */
2001
2002
2003 /* {{{ php_mysqlnd_prepare_free_mem */
2004 static void
php_mysqlnd_prepare_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)2005 php_mysqlnd_prepare_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
2006 {
2007 MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
2008 if (!stack_allocation) {
2009 mnd_pefree(p, p->header.persistent);
2010 }
2011 }
2012 /* }}} */
2013
2014
2015 /* {{{ php_mysqlnd_chg_user_read */
2016 static enum_func_status
php_mysqlnd_chg_user_read(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)2017 php_mysqlnd_chg_user_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
2018 {
2019 /* There could be an error message */
2020 size_t buf_len = conn->net->cmd_buffer.length;
2021 zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
2022 zend_uchar *p = buf;
2023 zend_uchar *begin = buf;
2024 MYSQLND_PACKET_CHG_USER_RESPONSE *packet= (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
2025
2026 DBG_ENTER("php_mysqlnd_chg_user_read");
2027
2028 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET);
2029 BAIL_IF_NO_MORE_DATA;
2030
2031 /*
2032 Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
2033 of encoded sequence for length.
2034 */
2035
2036 /* Should be always 0x0 or ERROR_MARKER for error */
2037 packet->response_code = uint1korr(p);
2038 p++;
2039
2040 if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
2041 /* We don't handle 3.23 authentication */
2042 packet->server_asked_323_auth = TRUE;
2043 DBG_RETURN(FAIL);
2044 }
2045
2046 if (ERROR_MARKER == packet->response_code) {
2047 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
2048 packet->error_info.error,
2049 sizeof(packet->error_info.error),
2050 &packet->error_info.error_no,
2051 packet->error_info.sqlstate
2052 TSRMLS_CC);
2053 }
2054 BAIL_IF_NO_MORE_DATA;
2055 if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
2056 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
2057 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
2058 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
2059 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
2060 if (packet->new_auth_protocol_data_len) {
2061 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
2062 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
2063 }
2064 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
2065 DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
2066 }
2067
2068 DBG_RETURN(PASS);
2069 premature_end:
2070 DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
2071 php_error_docref(NULL TSRMLS_CC, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
2072 p - begin - packet->header.size);
2073 DBG_RETURN(FAIL);
2074 }
2075 /* }}} */
2076
2077
2078 /* {{{ php_mysqlnd_chg_user_free_mem */
2079 static void
php_mysqlnd_chg_user_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)2080 php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
2081 {
2082 MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
2083
2084 if (p->new_auth_protocol) {
2085 mnd_efree(p->new_auth_protocol);
2086 p->new_auth_protocol = NULL;
2087 }
2088 p->new_auth_protocol_len = 0;
2089
2090 if (p->new_auth_protocol_data) {
2091 mnd_efree(p->new_auth_protocol_data);
2092 p->new_auth_protocol_data = NULL;
2093 }
2094 p->new_auth_protocol_data_len = 0;
2095
2096 if (!stack_allocation) {
2097 mnd_pefree(p, p->header.persistent);
2098 }
2099 }
2100 /* }}} */
2101
2102
2103 /* {{{ php_mysqlnd_sha256_pk_request_write */
2104 static
php_mysqlnd_sha256_pk_request_write(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)2105 size_t php_mysqlnd_sha256_pk_request_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
2106 {
2107 zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
2108 size_t sent;
2109
2110 DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
2111
2112 int1store(buffer + MYSQLND_HEADER_SIZE, '\1');
2113 sent = conn->net->data->m.send_ex(conn->net, buffer, 1, conn->stats, conn->error_info TSRMLS_CC);
2114
2115 DBG_RETURN(sent);
2116 }
2117 /* }}} */
2118
2119
2120 /* {{{ php_mysqlnd_sha256_pk_request_free_mem */
2121 static
php_mysqlnd_sha256_pk_request_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)2122 void php_mysqlnd_sha256_pk_request_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
2123 {
2124 if (!stack_allocation) {
2125 MYSQLND_PACKET_SHA256_PK_REQUEST * p = (MYSQLND_PACKET_SHA256_PK_REQUEST *) _packet;
2126 mnd_pefree(p, p->header.persistent);
2127 }
2128 }
2129 /* }}} */
2130
2131
2132 #define SHA256_PK_REQUEST_RESP_BUFFER_SIZE 2048
2133
2134 /* {{{ php_mysqlnd_sha256_pk_request_response_read */
2135 static enum_func_status
php_mysqlnd_sha256_pk_request_response_read(void * _packet,MYSQLND_CONN_DATA * conn TSRMLS_DC)2136 php_mysqlnd_sha256_pk_request_response_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
2137 {
2138 zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
2139 zend_uchar *p = buf;
2140 zend_uchar *begin = buf;
2141 MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * packet= (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
2142
2143 DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
2144
2145 /* leave space for terminating safety \0 */
2146 PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET);
2147 BAIL_IF_NO_MORE_DATA;
2148
2149 p++;
2150 BAIL_IF_NO_MORE_DATA;
2151
2152 packet->public_key_len = packet->header.size - (p - buf);
2153 packet->public_key = mnd_emalloc(packet->public_key_len + 1);
2154 memcpy(packet->public_key, p, packet->public_key_len);
2155 packet->public_key[packet->public_key_len] = '\0';
2156
2157 DBG_RETURN(PASS);
2158
2159 premature_end:
2160 DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
2161 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
2162 p - begin - packet->header.size);
2163 DBG_RETURN(FAIL);
2164 }
2165 /* }}} */
2166
2167
2168 /* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
2169 static void
php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet,zend_bool stack_allocation TSRMLS_DC)2170 php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
2171 {
2172 MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * p = (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
2173 if (p->public_key) {
2174 mnd_efree(p->public_key);
2175 p->public_key = NULL;
2176 }
2177 p->public_key_len = 0;
2178
2179 if (!stack_allocation) {
2180 mnd_pefree(p, p->header.persistent);
2181 }
2182 }
2183 /* }}} */
2184
2185
2186 /* {{{ packet_methods */
2187 static
2188 mysqlnd_packet_methods packet_methods[PROT_LAST] =
2189 {
2190 {
2191 sizeof(MYSQLND_PACKET_GREET),
2192 php_mysqlnd_greet_read,
2193 NULL, /* write */
2194 php_mysqlnd_greet_free_mem,
2195 }, /* PROT_GREET_PACKET */
2196 {
2197 sizeof(MYSQLND_PACKET_AUTH),
2198 NULL, /* read */
2199 php_mysqlnd_auth_write,
2200 php_mysqlnd_auth_free_mem,
2201 }, /* PROT_AUTH_PACKET */
2202 {
2203 sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
2204 php_mysqlnd_auth_response_read, /* read */
2205 NULL, /* write */
2206 php_mysqlnd_auth_response_free_mem,
2207 }, /* PROT_AUTH_RESP_PACKET */
2208 {
2209 sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
2210 NULL, /* read */
2211 php_mysqlnd_change_auth_response_write, /* write */
2212 php_mysqlnd_change_auth_response_free_mem,
2213 }, /* PROT_CHANGE_AUTH_RESP_PACKET */
2214 {
2215 sizeof(MYSQLND_PACKET_OK),
2216 php_mysqlnd_ok_read, /* read */
2217 NULL, /* write */
2218 php_mysqlnd_ok_free_mem,
2219 }, /* PROT_OK_PACKET */
2220 {
2221 sizeof(MYSQLND_PACKET_EOF),
2222 php_mysqlnd_eof_read, /* read */
2223 NULL, /* write */
2224 php_mysqlnd_eof_free_mem,
2225 }, /* PROT_EOF_PACKET */
2226 {
2227 sizeof(MYSQLND_PACKET_COMMAND),
2228 NULL, /* read */
2229 php_mysqlnd_cmd_write, /* write */
2230 php_mysqlnd_cmd_free_mem,
2231 }, /* PROT_CMD_PACKET */
2232 {
2233 sizeof(MYSQLND_PACKET_RSET_HEADER),
2234 php_mysqlnd_rset_header_read, /* read */
2235 NULL, /* write */
2236 php_mysqlnd_rset_header_free_mem,
2237 }, /* PROT_RSET_HEADER_PACKET */
2238 {
2239 sizeof(MYSQLND_PACKET_RES_FIELD),
2240 php_mysqlnd_rset_field_read, /* read */
2241 NULL, /* write */
2242 php_mysqlnd_rset_field_free_mem,
2243 }, /* PROT_RSET_FLD_PACKET */
2244 {
2245 sizeof(MYSQLND_PACKET_ROW),
2246 php_mysqlnd_rowp_read, /* read */
2247 NULL, /* write */
2248 php_mysqlnd_rowp_free_mem,
2249 }, /* PROT_ROW_PACKET */
2250 {
2251 sizeof(MYSQLND_PACKET_STATS),
2252 php_mysqlnd_stats_read, /* read */
2253 NULL, /* write */
2254 php_mysqlnd_stats_free_mem,
2255 }, /* PROT_STATS_PACKET */
2256 {
2257 sizeof(MYSQLND_PACKET_PREPARE_RESPONSE),
2258 php_mysqlnd_prepare_read, /* read */
2259 NULL, /* write */
2260 php_mysqlnd_prepare_free_mem,
2261 }, /* PROT_PREPARE_RESP_PACKET */
2262 {
2263 sizeof(MYSQLND_PACKET_CHG_USER_RESPONSE),
2264 php_mysqlnd_chg_user_read, /* read */
2265 NULL, /* write */
2266 php_mysqlnd_chg_user_free_mem,
2267 }, /* PROT_CHG_USER_RESP_PACKET */
2268 {
2269 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST),
2270 NULL, /* read */
2271 php_mysqlnd_sha256_pk_request_write,
2272 php_mysqlnd_sha256_pk_request_free_mem,
2273 }, /* PROT_SHA256_PK_REQUEST_PACKET */
2274 {
2275 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE),
2276 php_mysqlnd_sha256_pk_request_response_read,
2277 NULL, /* write */
2278 php_mysqlnd_sha256_pk_request_response_free_mem,
2279 } /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
2280 };
2281 /* }}} */
2282
2283
2284 /* {{{ mysqlnd_protocol::get_greet_packet */
2285 static struct st_mysqlnd_packet_greet *
MYSQLND_METHOD(mysqlnd_protocol,get_greet_packet)2286 MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2287 {
2288 struct st_mysqlnd_packet_greet * packet = mnd_pecalloc(1, packet_methods[PROT_GREET_PACKET].struct_size, persistent);
2289 DBG_ENTER("mysqlnd_protocol::get_greet_packet");
2290 if (packet) {
2291 packet->header.m = &packet_methods[PROT_GREET_PACKET];
2292 packet->header.persistent = persistent;
2293 }
2294 DBG_RETURN(packet);
2295 }
2296 /* }}} */
2297
2298
2299 /* {{{ mysqlnd_protocol::get_auth_packet */
2300 static struct st_mysqlnd_packet_auth *
MYSQLND_METHOD(mysqlnd_protocol,get_auth_packet)2301 MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2302 {
2303 struct st_mysqlnd_packet_auth * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_PACKET].struct_size, persistent);
2304 DBG_ENTER("mysqlnd_protocol::get_auth_packet");
2305 if (packet) {
2306 packet->header.m = &packet_methods[PROT_AUTH_PACKET];
2307 packet->header.persistent = persistent;
2308 }
2309 DBG_RETURN(packet);
2310 }
2311 /* }}} */
2312
2313
2314 /* {{{ mysqlnd_protocol::get_auth_response_packet */
2315 static struct st_mysqlnd_packet_auth_response *
MYSQLND_METHOD(mysqlnd_protocol,get_auth_response_packet)2316 MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2317 {
2318 struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
2319 DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
2320 if (packet) {
2321 packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
2322 packet->header.persistent = persistent;
2323 }
2324 DBG_RETURN(packet);
2325 }
2326 /* }}} */
2327
2328
2329 /* {{{ mysqlnd_protocol::get_change_auth_response_packet */
2330 static struct st_mysqlnd_packet_change_auth_response *
MYSQLND_METHOD(mysqlnd_protocol,get_change_auth_response_packet)2331 MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2332 {
2333 struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
2334 DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
2335 if (packet) {
2336 packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
2337 packet->header.persistent = persistent;
2338 }
2339 DBG_RETURN(packet);
2340 }
2341 /* }}} */
2342
2343
2344 /* {{{ mysqlnd_protocol::get_ok_packet */
2345 static struct st_mysqlnd_packet_ok *
MYSQLND_METHOD(mysqlnd_protocol,get_ok_packet)2346 MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2347 {
2348 struct st_mysqlnd_packet_ok * packet = mnd_pecalloc(1, packet_methods[PROT_OK_PACKET].struct_size, persistent);
2349 DBG_ENTER("mysqlnd_protocol::get_ok_packet");
2350 if (packet) {
2351 packet->header.m = &packet_methods[PROT_OK_PACKET];
2352 packet->header.persistent = persistent;
2353 }
2354 DBG_RETURN(packet);
2355 }
2356 /* }}} */
2357
2358
2359 /* {{{ mysqlnd_protocol::get_eof_packet */
2360 static struct st_mysqlnd_packet_eof *
MYSQLND_METHOD(mysqlnd_protocol,get_eof_packet)2361 MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2362 {
2363 struct st_mysqlnd_packet_eof * packet = mnd_pecalloc(1, packet_methods[PROT_EOF_PACKET].struct_size, persistent);
2364 DBG_ENTER("mysqlnd_protocol::get_eof_packet");
2365 if (packet) {
2366 packet->header.m = &packet_methods[PROT_EOF_PACKET];
2367 packet->header.persistent = persistent;
2368 }
2369 DBG_RETURN(packet);
2370 }
2371 /* }}} */
2372
2373
2374 /* {{{ mysqlnd_protocol::get_command_packet */
2375 static struct st_mysqlnd_packet_command *
MYSQLND_METHOD(mysqlnd_protocol,get_command_packet)2376 MYSQLND_METHOD(mysqlnd_protocol, get_command_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2377 {
2378 struct st_mysqlnd_packet_command * packet = mnd_pecalloc(1, packet_methods[PROT_CMD_PACKET].struct_size, persistent);
2379 DBG_ENTER("mysqlnd_protocol::get_command_packet");
2380 if (packet) {
2381 packet->header.m = &packet_methods[PROT_CMD_PACKET];
2382 packet->header.persistent = persistent;
2383 }
2384 DBG_RETURN(packet);
2385 }
2386 /* }}} */
2387
2388
2389 /* {{{ mysqlnd_protocol::get_rset_packet */
2390 static struct st_mysqlnd_packet_rset_header *
MYSQLND_METHOD(mysqlnd_protocol,get_rset_header_packet)2391 MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2392 {
2393 struct st_mysqlnd_packet_rset_header * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_HEADER_PACKET].struct_size, persistent);
2394 DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
2395 if (packet) {
2396 packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
2397 packet->header.persistent = persistent;
2398 }
2399 DBG_RETURN(packet);
2400 }
2401 /* }}} */
2402
2403
2404 /* {{{ mysqlnd_protocol::get_result_field_packet */
2405 static struct st_mysqlnd_packet_res_field *
MYSQLND_METHOD(mysqlnd_protocol,get_result_field_packet)2406 MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2407 {
2408 struct st_mysqlnd_packet_res_field * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_FLD_PACKET].struct_size, persistent);
2409 DBG_ENTER("mysqlnd_protocol::get_result_field_packet");
2410 if (packet) {
2411 packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
2412 packet->header.persistent = persistent;
2413 }
2414 DBG_RETURN(packet);
2415 }
2416 /* }}} */
2417
2418
2419 /* {{{ mysqlnd_protocol::get_row_packet */
2420 static struct st_mysqlnd_packet_row *
MYSQLND_METHOD(mysqlnd_protocol,get_row_packet)2421 MYSQLND_METHOD(mysqlnd_protocol, get_row_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2422 {
2423 struct st_mysqlnd_packet_row * packet = mnd_pecalloc(1, packet_methods[PROT_ROW_PACKET].struct_size, persistent);
2424 DBG_ENTER("mysqlnd_protocol::get_row_packet");
2425 if (packet) {
2426 packet->header.m = &packet_methods[PROT_ROW_PACKET];
2427 packet->header.persistent = persistent;
2428 }
2429 DBG_RETURN(packet);
2430 }
2431 /* }}} */
2432
2433
2434 /* {{{ mysqlnd_protocol::get_stats_packet */
2435 static struct st_mysqlnd_packet_stats *
MYSQLND_METHOD(mysqlnd_protocol,get_stats_packet)2436 MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2437 {
2438 struct st_mysqlnd_packet_stats * packet = mnd_pecalloc(1, packet_methods[PROT_STATS_PACKET].struct_size, persistent);
2439 DBG_ENTER("mysqlnd_protocol::get_stats_packet");
2440 if (packet) {
2441 packet->header.m = &packet_methods[PROT_STATS_PACKET];
2442 packet->header.persistent = persistent;
2443 }
2444 DBG_RETURN(packet);
2445 }
2446 /* }}} */
2447
2448
2449 /* {{{ mysqlnd_protocol::get_prepare_response_packet */
2450 static struct st_mysqlnd_packet_prepare_response *
MYSQLND_METHOD(mysqlnd_protocol,get_prepare_response_packet)2451 MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2452 {
2453 struct st_mysqlnd_packet_prepare_response * packet = mnd_pecalloc(1, packet_methods[PROT_PREPARE_RESP_PACKET].struct_size, persistent);
2454 DBG_ENTER("mysqlnd_protocol::get_prepare_response_packet");
2455 if (packet) {
2456 packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
2457 packet->header.persistent = persistent;
2458 }
2459 DBG_RETURN(packet);
2460 }
2461 /* }}} */
2462
2463
2464 /* {{{ mysqlnd_protocol::get_change_user_response_packet */
2465 static struct st_mysqlnd_packet_chg_user_resp*
MYSQLND_METHOD(mysqlnd_protocol,get_change_user_response_packet)2466 MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2467 {
2468 struct st_mysqlnd_packet_chg_user_resp * packet = mnd_pecalloc(1, packet_methods[PROT_CHG_USER_RESP_PACKET].struct_size, persistent);
2469 DBG_ENTER("mysqlnd_protocol::get_change_user_response_packet");
2470 if (packet) {
2471 packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
2472 packet->header.persistent = persistent;
2473 }
2474 DBG_RETURN(packet);
2475 }
2476 /* }}} */
2477
2478
2479 /* {{{ mysqlnd_protocol::get_sha256_pk_request_packet */
2480 static struct st_mysqlnd_packet_sha256_pk_request *
MYSQLND_METHOD(mysqlnd_protocol,get_sha256_pk_request_packet)2481 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2482 {
2483 struct st_mysqlnd_packet_sha256_pk_request * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_PACKET].struct_size, persistent);
2484 DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_packet");
2485 if (packet) {
2486 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
2487 packet->header.persistent = persistent;
2488 }
2489 DBG_RETURN(packet);
2490 }
2491 /* }}} */
2492
2493
2494 /* {{{ mysqlnd_protocol::get_sha256_pk_request_response_packet */
2495 static struct st_mysqlnd_packet_sha256_pk_request_response *
MYSQLND_METHOD(mysqlnd_protocol,get_sha256_pk_request_response_packet)2496 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
2497 {
2498 struct st_mysqlnd_packet_sha256_pk_request_response * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET].struct_size, persistent);
2499 DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_response_packet");
2500 if (packet) {
2501 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
2502 packet->header.persistent = persistent;
2503 }
2504 DBG_RETURN(packet);
2505 }
2506 /* }}} */
2507
2508
2509
2510 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
2511 MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
2512 MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
2513 MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
2514 MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
2515 MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
2516 MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
2517 MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
2518 MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet),
2519 MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet),
2520 MYSQLND_METHOD(mysqlnd_protocol, get_row_packet),
2521 MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet),
2522 MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet),
2523 MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet),
2524 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet),
2525 MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)
2526 MYSQLND_CLASS_METHODS_END;
2527
2528
2529 /* {{{ mysqlnd_protocol_init */
2530 PHPAPI MYSQLND_PROTOCOL *
mysqlnd_protocol_init(zend_bool persistent TSRMLS_DC)2531 mysqlnd_protocol_init(zend_bool persistent TSRMLS_DC)
2532 {
2533 MYSQLND_PROTOCOL * ret;
2534 DBG_ENTER("mysqlnd_protocol_init");
2535 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_decoder(persistent TSRMLS_CC);
2536 DBG_RETURN(ret);
2537 }
2538 /* }}} */
2539
2540
2541 /* {{{ mysqlnd_protocol_free */
2542 PHPAPI void
mysqlnd_protocol_free(MYSQLND_PROTOCOL * const protocol TSRMLS_DC)2543 mysqlnd_protocol_free(MYSQLND_PROTOCOL * const protocol TSRMLS_DC)
2544 {
2545 DBG_ENTER("mysqlnd_protocol_free");
2546
2547 if (protocol) {
2548 zend_bool pers = protocol->persistent;
2549 mnd_pefree(protocol, pers);
2550 }
2551 DBG_VOID_RETURN;
2552 }
2553 /* }}} */
2554
2555
2556 /*
2557 * Local variables:
2558 * tab-width: 4
2559 * c-basic-offset: 4
2560 * End:
2561 * vim600: noet sw=4 ts=4 fdm=marker
2562 * vim<600: noet sw=4 ts=4
2563 */
2564