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