1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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@php.net> |
16 | Ulf Wendel <uw@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 #include "php.h"
21 #include "mysqlnd.h"
22 #include "mysqlnd_connection.h"
23 #include "mysqlnd_priv.h"
24 #include "mysqlnd_read_buffer.h"
25 #include "mysqlnd_wireprotocol.h"
26 #include "mysqlnd_statistics.h"
27 #include "mysqlnd_debug.h"
28 #ifdef MYSQLND_COMPRESSION_ENABLED
29 #include <zlib.h>
30 #endif
31
32
33 /* {{{ mysqlnd_pfc::reset */
34 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,reset)35 MYSQLND_METHOD(mysqlnd_pfc, reset)(MYSQLND_PFC * const pfc, MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
36 {
37 DBG_ENTER("mysqlnd_pfc::reset");
38 pfc->data->packet_no = pfc->data->compressed_envelope_packet_no = 0;
39 DBG_RETURN(PASS);
40 }
41 /* }}} */
42
43
44 /* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
45 #define COPY_HEADER(T,A) do { \
46 *(((char *)(T))) = *(((char *)(A)));\
47 *(((char *)(T))+1) = *(((char *)(A))+1);\
48 *(((char *)(T))+2) = *(((char *)(A))+2);\
49 *(((char *)(T))+3) = *(((char *)(A))+3); } while (0)
50 #define STORE_HEADER_SIZE(safe_storage, buffer) COPY_HEADER((safe_storage), (buffer))
51 #define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
52
53 #ifdef MYSQLND_COMPRESSION_ENABLED
write_compressed_packet(const MYSQLND_PFC * pfc,MYSQLND_VIO * vio,MYSQLND_STATS * conn_stats,MYSQLND_ERROR_INFO * error_info,zend_uchar * uncompressed_payload,size_t to_be_sent,zend_uchar * compress_buf)54 static ssize_t write_compressed_packet(
55 const MYSQLND_PFC *pfc, MYSQLND_VIO *vio,
56 MYSQLND_STATS *conn_stats, MYSQLND_ERROR_INFO *error_info,
57 zend_uchar *uncompressed_payload, size_t to_be_sent, zend_uchar *compress_buf) {
58 DBG_ENTER("write_compressed_packet");
59 /* here we need to compress the data and then write it, first comes the compressed header */
60 size_t tmp_complen = to_be_sent;
61 size_t payload_size;
62 if (PASS == pfc->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
63 uncompressed_payload, to_be_sent))
64 {
65 int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent);
66 payload_size = tmp_complen;
67 } else {
68 int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
69 memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent);
70 payload_size = to_be_sent;
71 }
72
73 int3store(compress_buf, payload_size);
74 int1store(compress_buf + 3, pfc->data->compressed_envelope_packet_no);
75 DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
76
77 ssize_t bytes_sent = vio->data->m.network_write(vio, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, conn_stats, error_info);
78 pfc->data->compressed_envelope_packet_no++;
79 #ifdef WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
80 if (res == Z_OK) {
81 size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
82 zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
83 int error = pfc->data->m.decode(decompressed_data, decompressed_size,
84 compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
85 if (error == Z_OK) {
86 int i;
87 DBG_INF("success decompressing");
88 for (i = 0 ; i < decompressed_size; i++) {
89 if (i && (i % 30 == 0)) {
90 printf("\n\t\t");
91 }
92 printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
93 DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
94 }
95 } else {
96 DBG_INF("error decompressing");
97 }
98 mnd_free(decompressed_data);
99 }
100 #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
101 DBG_RETURN(bytes_sent);
102 }
103 #endif
104
105 /* {{{ mysqlnd_pfc::send */
106 /*
107 IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
108 This is done for performance reasons in the caller of this function.
109 Otherwise we will have to do send two TCP packets, or do new alloc and memcpy.
110 Neither are quick, thus the clients of this function are obligated to do
111 what they are asked for.
112
113 `count` is actually the length of the payload data. Thus :
114 count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
115 */
116 static size_t
MYSQLND_METHOD(mysqlnd_pfc,send)117 MYSQLND_METHOD(mysqlnd_pfc, send)(MYSQLND_PFC * const pfc, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
118 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
119 {
120 zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
121 zend_uchar * safe_storage = safe_buf;
122 size_t packets_sent = 1;
123 size_t left = count;
124 zend_uchar * p = (zend_uchar *) buffer;
125 zend_uchar * compress_buf = NULL;
126 size_t to_be_sent;
127 ssize_t bytes_sent;
128
129 DBG_ENTER("mysqlnd_pfc::send");
130 DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, pfc->data->compressed);
131
132 if (pfc->data->compressed == TRUE) {
133 size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
134 DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
135 compress_buf = mnd_emalloc(comp_buf_size);
136 }
137
138 do {
139 to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
140 DBG_INF_FMT("to_be_sent=%u", to_be_sent);
141 DBG_INF_FMT("packets_sent=%u", packets_sent);
142 DBG_INF_FMT("compressed_envelope_packet_no=%u", pfc->data->compressed_envelope_packet_no);
143 DBG_INF_FMT("packet_no=%u", pfc->data->packet_no);
144 #ifdef MYSQLND_COMPRESSION_ENABLED
145 if (pfc->data->compressed == TRUE) {
146 zend_uchar * uncompressed_payload = p; /* should include the header */
147 STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
148 int3store(uncompressed_payload, to_be_sent);
149 int1store(uncompressed_payload + 3, pfc->data->packet_no);
150 if (to_be_sent <= MYSQLND_MAX_PACKET_SIZE - MYSQLND_HEADER_SIZE) {
151 bytes_sent = write_compressed_packet(
152 pfc, vio, conn_stats, error_info,
153 uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE, compress_buf);
154 } else {
155 /* The uncompressed size including the header would overflow. Split into two
156 * compressed packets. The size of the first one is relatively arbitrary here. */
157 const size_t split_off_bytes = 8192;
158 bytes_sent = write_compressed_packet(
159 pfc, vio, conn_stats, error_info,
160 uncompressed_payload, split_off_bytes, compress_buf);
161 bytes_sent = write_compressed_packet(
162 pfc, vio, conn_stats, error_info,
163 uncompressed_payload + split_off_bytes,
164 to_be_sent + MYSQLND_HEADER_SIZE - split_off_bytes, compress_buf);
165 }
166 RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
167 } else
168 #endif /* MYSQLND_COMPRESSION_ENABLED */
169 {
170 DBG_INF("no compression");
171 STORE_HEADER_SIZE(safe_storage, p);
172 int3store(p, to_be_sent);
173 int1store(p + 3, pfc->data->packet_no);
174 bytes_sent = vio->data->m.network_write(vio, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
175 RESTORE_HEADER_SIZE(p, safe_storage);
176 pfc->data->compressed_envelope_packet_no++;
177 }
178 pfc->data->packet_no++;
179
180 p += to_be_sent;
181 left -= to_be_sent;
182 packets_sent++;
183 /*
184 if left is 0 then there is nothing more to send, but if the last packet was exactly
185 with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
186 empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
187 indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
188 packet will be sent and this loop will end.
189 */
190 } while (bytes_sent > 0 && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
191
192 DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, pfc->data->packet_no);
193
194 MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
195 STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
196 STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
197 STAT_PACKETS_SENT, packets_sent);
198
199 if (compress_buf) {
200 mnd_efree(compress_buf);
201 }
202
203 /* Even for zero size payload we have to send a packet */
204 if (bytes_sent <= 0) {
205 DBG_ERR_FMT("Can't %u send bytes", count);
206 SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
207 }
208 DBG_RETURN(bytes_sent);
209 }
210 /* }}} */
211
212
213 #ifdef MYSQLND_COMPRESSION_ENABLED
214
215 /* {{{ mysqlnd_pfc::read_compressed_packet_from_stream_and_fill_read_buffer */
216 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,read_compressed_packet_from_stream_and_fill_read_buffer)217 MYSQLND_METHOD(mysqlnd_pfc, read_compressed_packet_from_stream_and_fill_read_buffer)
218 (MYSQLND_PFC * pfc, MYSQLND_VIO * vio, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
219 {
220 size_t decompressed_size;
221 enum_func_status retval = PASS;
222 zend_uchar * compressed_data = NULL;
223 zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
224 DBG_ENTER("mysqlnd_pfc::read_compressed_packet_from_stream_and_fill_read_buffer");
225
226 /* Read the compressed header */
227 if (FAIL == vio->data->m.network_read(vio, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info)) {
228 DBG_RETURN(FAIL);
229 }
230 decompressed_size = uint3korr(comp_header);
231
232 /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
233 /* we need to decompress the data */
234
235 if (decompressed_size) {
236 compressed_data = mnd_emalloc(net_payload_size);
237 if (FAIL == vio->data->m.network_read(vio, compressed_data, net_payload_size, conn_stats, error_info)) {
238 retval = FAIL;
239 goto end;
240 }
241 pfc->data->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size);
242 retval = pfc->data->m.decode(pfc->data->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size);
243 if (FAIL == retval) {
244 goto end;
245 }
246 } else {
247 DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
248 pfc->data->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size);
249 if (FAIL == vio->data->m.network_read(vio, pfc->data->uncompressed_data->data, net_payload_size, conn_stats, error_info)) {
250 retval = FAIL;
251 goto end;
252 }
253 }
254 end:
255 if (compressed_data) {
256 mnd_efree(compressed_data);
257 }
258 DBG_RETURN(retval);
259 }
260 /* }}} */
261 #endif /* MYSQLND_COMPRESSION_ENABLED */
262
263
264 /* {{{ mysqlnd_pfc::decode */
265 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,decode)266 MYSQLND_METHOD(mysqlnd_pfc, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
267 const zend_uchar * const compressed_data, const size_t compressed_data_len)
268 {
269 #ifdef MYSQLND_COMPRESSION_ENABLED
270 int error;
271 uLongf tmp_complen = uncompressed_data_len;
272 DBG_ENTER("mysqlnd_pfc::decode");
273 error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
274
275 DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
276 if (error != Z_OK) {
277 DBG_INF_FMT("decompression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", error, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
278 }
279 DBG_RETURN(error == Z_OK? PASS:FAIL);
280 #else
281 DBG_ENTER("mysqlnd_pfc::decode");
282 DBG_RETURN(FAIL);
283 #endif
284 }
285 /* }}} */
286
287
288 /* {{{ mysqlnd_pfc::encode */
289 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,encode)290 MYSQLND_METHOD(mysqlnd_pfc, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
291 const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
292 {
293 #ifdef MYSQLND_COMPRESSION_ENABLED
294 int error;
295 uLongf tmp_complen = *compress_buffer_len;
296 DBG_ENTER("mysqlnd_pfc::encode");
297 error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
298
299 if (error != Z_OK) {
300 DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", error, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
301 } else {
302 *compress_buffer_len = tmp_complen;
303 DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
304 }
305
306 DBG_RETURN(error == Z_OK? PASS:FAIL);
307 #else
308 DBG_ENTER("mysqlnd_pfc::encode");
309 DBG_RETURN(FAIL);
310 #endif
311 }
312 /* }}} */
313
314
315 /* {{{ mysqlnd_pfc::receive */
316 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,receive)317 MYSQLND_METHOD(mysqlnd_pfc, receive)(MYSQLND_PFC * const pfc, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
318 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
319 {
320 size_t to_read = count;
321 zend_uchar * p = buffer;
322
323 DBG_ENTER("mysqlnd_pfc::receive");
324 #ifdef MYSQLND_COMPRESSION_ENABLED
325 if (pfc->data->compressed) {
326 if (pfc->data->uncompressed_data) {
327 size_t to_read_from_buffer = MIN(pfc->data->uncompressed_data->bytes_left(pfc->data->uncompressed_data), to_read);
328 DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
329 if (to_read_from_buffer) {
330 pfc->data->uncompressed_data->read(pfc->data->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
331 p += to_read_from_buffer;
332 to_read -= to_read_from_buffer;
333 }
334 DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
335 if (TRUE == pfc->data->uncompressed_data->is_empty(pfc->data->uncompressed_data)) {
336 /* Everything was consumed. This should never happen here, but for security */
337 pfc->data->uncompressed_data->free_buffer(&pfc->data->uncompressed_data);
338 }
339 }
340 if (to_read) {
341 zend_uchar net_header[MYSQLND_HEADER_SIZE];
342 size_t net_payload_size;
343 zend_uchar packet_no;
344
345 if (FAIL == vio->data->m.network_read(vio, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
346 DBG_RETURN(FAIL);
347 }
348 net_payload_size = uint3korr(net_header);
349 packet_no = uint1korr(net_header + 3);
350 if (pfc->data->compressed_envelope_packet_no != packet_no) {
351 DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
352 pfc->data->compressed_envelope_packet_no, packet_no, net_payload_size);
353
354 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
355 pfc->data->compressed_envelope_packet_no, packet_no, net_payload_size);
356 DBG_RETURN(FAIL);
357 }
358 pfc->data->compressed_envelope_packet_no++;
359 #ifdef MYSQLND_DUMP_HEADER_N_BODY
360 DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
361 #endif
362 /* Now let's read from the wire, decompress it and fill the read buffer */
363 pfc->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(pfc, vio, net_payload_size, conn_stats, error_info);
364
365 /*
366 Now a bit of recursion - read from the read buffer,
367 if the data which we have just read from the wire
368 is not enough, then the recursive call will try to
369 satisfy it until it is satisfied.
370 */
371 DBG_RETURN(pfc->data->m.receive(pfc, vio, p, to_read, conn_stats, error_info));
372 }
373 DBG_RETURN(PASS);
374 }
375 #endif /* MYSQLND_COMPRESSION_ENABLED */
376 DBG_RETURN(vio->data->m.network_read(vio, p, to_read, conn_stats, error_info));
377 }
378 /* }}} */
379
380
381 /* {{{ mysqlnd_pfc::set_client_option */
382 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,set_client_option)383 MYSQLND_METHOD(mysqlnd_pfc, set_client_option)(MYSQLND_PFC * const pfc, enum_mysqlnd_client_option option, const char * const value)
384 {
385 DBG_ENTER("mysqlnd_pfc::set_client_option");
386 DBG_INF_FMT("option=%u", option);
387 switch (option) {
388 case MYSQL_OPT_COMPRESS:
389 pfc->data->flags |= MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION;
390 break;
391 case MYSQL_SERVER_PUBLIC_KEY: {
392 const zend_bool pers = pfc->persistent;
393 if (pfc->data->sha256_server_public_key) {
394 mnd_pefree(pfc->data->sha256_server_public_key, pers);
395 }
396 pfc->data->sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
397 break;
398 case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
399 DBG_INF("MYSQLND_OPT_NET_CMD_BUFFER_SIZE");
400 if (*(unsigned int*) value < MYSQLND_NET_CMD_BUFFER_MIN_SIZE) {
401 DBG_RETURN(FAIL);
402 }
403 pfc->cmd_buffer.length = *(unsigned int*) value;
404 DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, pfc->cmd_buffer.length);
405 if (!pfc->cmd_buffer.buffer) {
406 pfc->cmd_buffer.buffer = mnd_pemalloc(pfc->cmd_buffer.length, pfc->persistent);
407 } else {
408 pfc->cmd_buffer.buffer = mnd_perealloc(pfc->cmd_buffer.buffer, pfc->cmd_buffer.length, pfc->persistent);
409 }
410 break;
411 }
412 default:
413 DBG_RETURN(FAIL);
414 }
415 DBG_RETURN(PASS);
416 }
417 /* }}} */
418
419
420 /* {{{ mysqlnd_pfc::free_contents */
421 static void
MYSQLND_METHOD(mysqlnd_pfc,free_contents)422 MYSQLND_METHOD(mysqlnd_pfc, free_contents)(MYSQLND_PFC * pfc)
423 {
424 DBG_ENTER("mysqlnd_pfc::free_contents");
425
426 #ifdef MYSQLND_COMPRESSION_ENABLED
427 if (pfc->data->uncompressed_data) {
428 pfc->data->uncompressed_data->free_buffer(&pfc->data->uncompressed_data);
429 }
430 #endif
431 if (pfc->data->sha256_server_public_key) {
432 mnd_pefree(pfc->data->sha256_server_public_key, pfc->persistent);
433 pfc->data->sha256_server_public_key = NULL;
434 }
435
436 DBG_VOID_RETURN;
437 }
438 /* }}} */
439
440
441 /* {{{ mysqlnd_pfc::init */
442 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,init)443 MYSQLND_METHOD(mysqlnd_pfc, init)(MYSQLND_PFC * const pfc, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
444 {
445 unsigned int buf_size;
446 DBG_ENTER("mysqlnd_pfc::init");
447
448 buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/
449 pfc->data->m.set_client_option(pfc, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size);
450
451 DBG_RETURN(PASS);
452 }
453 /* }}} */
454
455
456 /* {{{ mysqlnd_pfc::dtor */
457 static void
MYSQLND_METHOD(mysqlnd_pfc,dtor)458 MYSQLND_METHOD(mysqlnd_pfc, dtor)(MYSQLND_PFC * const pfc, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
459 {
460 DBG_ENTER("mysqlnd_pfc::dtor");
461 if (pfc) {
462 pfc->data->m.free_contents(pfc);
463
464 if (pfc->cmd_buffer.buffer) {
465 DBG_INF("Freeing cmd buffer");
466 mnd_pefree(pfc->cmd_buffer.buffer, pfc->persistent);
467 pfc->cmd_buffer.buffer = NULL;
468 }
469
470 mnd_pefree(pfc, pfc->persistent);
471 }
472 DBG_VOID_RETURN;
473 }
474 /* }}} */
475
476
477 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol_packet_frame_codec)
478 MYSQLND_METHOD(mysqlnd_pfc, init),
479 MYSQLND_METHOD(mysqlnd_pfc, dtor),
480 MYSQLND_METHOD(mysqlnd_pfc, reset),
481
482 MYSQLND_METHOD(mysqlnd_pfc, set_client_option),
483
484 MYSQLND_METHOD(mysqlnd_pfc, decode),
485 MYSQLND_METHOD(mysqlnd_pfc, encode),
486
487 MYSQLND_METHOD(mysqlnd_pfc, send),
488 MYSQLND_METHOD(mysqlnd_pfc, receive),
489
490 #ifdef MYSQLND_COMPRESSION_ENABLED
491 MYSQLND_METHOD(mysqlnd_pfc, read_compressed_packet_from_stream_and_fill_read_buffer),
492 #else
493 NULL,
494 #endif
495
496 MYSQLND_METHOD(mysqlnd_pfc, free_contents),
497 MYSQLND_CLASS_METHODS_END;
498
499
500 /* {{{ mysqlnd_pfc_init */
501 PHPAPI MYSQLND_PFC *
mysqlnd_pfc_init(const zend_bool persistent,MYSQLND_CLASS_METHODS_TYPE (mysqlnd_object_factory)* object_factory,MYSQLND_STATS * stats,MYSQLND_ERROR_INFO * error_info)502 mysqlnd_pfc_init(const zend_bool persistent, MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *object_factory, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
503 {
504 MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) *factory = object_factory? object_factory : &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory);
505 MYSQLND_PFC * pfc;
506 DBG_ENTER("mysqlnd_pfc_init");
507 pfc = factory->get_protocol_frame_codec(persistent, stats, error_info);
508 DBG_RETURN(pfc);
509 }
510 /* }}} */
511
512
513 /* {{{ mysqlnd_pfc_free */
514 PHPAPI void
mysqlnd_pfc_free(MYSQLND_PFC * const pfc,MYSQLND_STATS * stats,MYSQLND_ERROR_INFO * error_info)515 mysqlnd_pfc_free(MYSQLND_PFC * const pfc, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
516 {
517 DBG_ENTER("mysqlnd_pfc_free");
518 if (pfc) {
519 pfc->data->m.dtor(pfc, stats, error_info);
520 }
521 DBG_VOID_RETURN;
522 }
523 /* }}} */
524