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