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 #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 size_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 size_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 bytes_sent, 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
128 DBG_ENTER("mysqlnd_pfc::send");
129 DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, pfc->data->compressed);
130
131 if (pfc->data->compressed == TRUE) {
132 size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
133 DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
134 compress_buf = mnd_emalloc(comp_buf_size);
135 }
136
137 do {
138 to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
139 DBG_INF_FMT("to_be_sent=%u", to_be_sent);
140 DBG_INF_FMT("packets_sent=%u", packets_sent);
141 DBG_INF_FMT("compressed_envelope_packet_no=%u", pfc->data->compressed_envelope_packet_no);
142 DBG_INF_FMT("packet_no=%u", pfc->data->packet_no);
143 #ifdef MYSQLND_COMPRESSION_ENABLED
144 if (pfc->data->compressed == TRUE) {
145 zend_uchar * uncompressed_payload = p; /* should include the header */
146 STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
147 int3store(uncompressed_payload, to_be_sent);
148 int1store(uncompressed_payload + 3, pfc->data->packet_no);
149 if (to_be_sent <= MYSQLND_MAX_PACKET_SIZE - MYSQLND_HEADER_SIZE) {
150 bytes_sent = write_compressed_packet(
151 pfc, vio, conn_stats, error_info,
152 uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE, compress_buf);
153 } else {
154 /* The uncompressed size including the header would overflow. Split into two
155 * compressed packets. The size of the first one is relatively arbitrary here. */
156 const size_t split_off_bytes = 8192;
157 bytes_sent = write_compressed_packet(
158 pfc, vio, conn_stats, error_info,
159 uncompressed_payload, split_off_bytes, compress_buf);
160 bytes_sent = write_compressed_packet(
161 pfc, vio, conn_stats, error_info,
162 uncompressed_payload + split_off_bytes,
163 to_be_sent + MYSQLND_HEADER_SIZE - split_off_bytes, compress_buf);
164 }
165 RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
166 } else
167 #endif /* MYSQLND_COMPRESSION_ENABLED */
168 {
169 DBG_INF("no compression");
170 STORE_HEADER_SIZE(safe_storage, p);
171 int3store(p, to_be_sent);
172 int1store(p + 3, pfc->data->packet_no);
173 bytes_sent = vio->data->m.network_write(vio, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
174 RESTORE_HEADER_SIZE(p, safe_storage);
175 pfc->data->compressed_envelope_packet_no++;
176 }
177 pfc->data->packet_no++;
178
179 p += to_be_sent;
180 left -= to_be_sent;
181 packets_sent++;
182 /*
183 if left is 0 then there is nothing more to send, but if the last packet was exactly
184 with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
185 empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
186 indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
187 packet will be sent and this loop will end.
188 */
189 } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
190
191 DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, pfc->data->packet_no);
192
193 MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
194 STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
195 STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
196 STAT_PACKETS_SENT, packets_sent);
197
198 if (compress_buf) {
199 mnd_efree(compress_buf);
200 }
201
202 /* Even for zero size payload we have to send a packet */
203 if (!bytes_sent) {
204 DBG_ERR_FMT("Can't %u send bytes", count);
205 SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
206 }
207 DBG_RETURN(bytes_sent);
208 }
209 /* }}} */
210
211
212 #ifdef MYSQLND_COMPRESSION_ENABLED
213
214 /* {{{ mysqlnd_pfc::read_compressed_packet_from_stream_and_fill_read_buffer */
215 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,read_compressed_packet_from_stream_and_fill_read_buffer)216 MYSQLND_METHOD(mysqlnd_pfc, read_compressed_packet_from_stream_and_fill_read_buffer)
217 (MYSQLND_PFC * pfc, MYSQLND_VIO * vio, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
218 {
219 size_t decompressed_size;
220 enum_func_status retval = PASS;
221 zend_uchar * compressed_data = NULL;
222 zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
223 DBG_ENTER("mysqlnd_pfc::read_compressed_packet_from_stream_and_fill_read_buffer");
224
225 /* Read the compressed header */
226 if (FAIL == vio->data->m.network_read(vio, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info)) {
227 DBG_RETURN(FAIL);
228 }
229 decompressed_size = uint3korr(comp_header);
230
231 /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
232 /* we need to decompress the data */
233
234 if (decompressed_size) {
235 compressed_data = mnd_emalloc(net_payload_size);
236 if (FAIL == vio->data->m.network_read(vio, compressed_data, net_payload_size, conn_stats, error_info)) {
237 retval = FAIL;
238 goto end;
239 }
240 pfc->data->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size);
241 retval = pfc->data->m.decode(pfc->data->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size);
242 if (FAIL == retval) {
243 goto end;
244 }
245 } else {
246 DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
247 pfc->data->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size);
248 if (FAIL == vio->data->m.network_read(vio, pfc->data->uncompressed_data->data, net_payload_size, conn_stats, error_info)) {
249 retval = FAIL;
250 goto end;
251 }
252 }
253 end:
254 if (compressed_data) {
255 mnd_efree(compressed_data);
256 }
257 DBG_RETURN(retval);
258 }
259 /* }}} */
260 #endif /* MYSQLND_COMPRESSION_ENABLED */
261
262
263 /* {{{ mysqlnd_pfc::decode */
264 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,decode)265 MYSQLND_METHOD(mysqlnd_pfc, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
266 const zend_uchar * const compressed_data, const size_t compressed_data_len)
267 {
268 #ifdef MYSQLND_COMPRESSION_ENABLED
269 int error;
270 uLongf tmp_complen = uncompressed_data_len;
271 DBG_ENTER("mysqlnd_pfc::decode");
272 error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
273
274 DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
275 if (error != Z_OK) {
276 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);
277 }
278 DBG_RETURN(error == Z_OK? PASS:FAIL);
279 #else
280 DBG_ENTER("mysqlnd_pfc::decode");
281 DBG_RETURN(FAIL);
282 #endif
283 }
284 /* }}} */
285
286
287 /* {{{ mysqlnd_pfc::encode */
288 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,encode)289 MYSQLND_METHOD(mysqlnd_pfc, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
290 const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
291 {
292 #ifdef MYSQLND_COMPRESSION_ENABLED
293 int error;
294 uLongf tmp_complen = *compress_buffer_len;
295 DBG_ENTER("mysqlnd_pfc::encode");
296 error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
297
298 if (error != Z_OK) {
299 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);
300 } else {
301 *compress_buffer_len = tmp_complen;
302 DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
303 }
304
305 DBG_RETURN(error == Z_OK? PASS:FAIL);
306 #else
307 DBG_ENTER("mysqlnd_pfc::encode");
308 DBG_RETURN(FAIL);
309 #endif
310 }
311 /* }}} */
312
313
314 /* {{{ mysqlnd_pfc::receive */
315 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,receive)316 MYSQLND_METHOD(mysqlnd_pfc, receive)(MYSQLND_PFC * const pfc, MYSQLND_VIO * const vio, zend_uchar * const buffer, const size_t count,
317 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
318 {
319 size_t to_read = count;
320 zend_uchar * p = buffer;
321
322 DBG_ENTER("mysqlnd_pfc::receive");
323 #ifdef MYSQLND_COMPRESSION_ENABLED
324 if (pfc->data->compressed) {
325 if (pfc->data->uncompressed_data) {
326 size_t to_read_from_buffer = MIN(pfc->data->uncompressed_data->bytes_left(pfc->data->uncompressed_data), to_read);
327 DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
328 if (to_read_from_buffer) {
329 pfc->data->uncompressed_data->read(pfc->data->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
330 p += to_read_from_buffer;
331 to_read -= to_read_from_buffer;
332 }
333 DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
334 if (TRUE == pfc->data->uncompressed_data->is_empty(pfc->data->uncompressed_data)) {
335 /* Everything was consumed. This should never happen here, but for security */
336 pfc->data->uncompressed_data->free_buffer(&pfc->data->uncompressed_data);
337 }
338 }
339 if (to_read) {
340 zend_uchar net_header[MYSQLND_HEADER_SIZE];
341 size_t net_payload_size;
342 zend_uchar packet_no;
343
344 if (FAIL == vio->data->m.network_read(vio, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
345 DBG_RETURN(FAIL);
346 }
347 net_payload_size = uint3korr(net_header);
348 packet_no = uint1korr(net_header + 3);
349 if (pfc->data->compressed_envelope_packet_no != packet_no) {
350 DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
351 pfc->data->compressed_envelope_packet_no, packet_no, net_payload_size);
352
353 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
354 pfc->data->compressed_envelope_packet_no, packet_no, net_payload_size);
355 DBG_RETURN(FAIL);
356 }
357 pfc->data->compressed_envelope_packet_no++;
358 #ifdef MYSQLND_DUMP_HEADER_N_BODY
359 DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
360 #endif
361 /* Now let's read from the wire, decompress it and fill the read buffer */
362 pfc->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(pfc, vio, net_payload_size, conn_stats, error_info);
363
364 /*
365 Now a bit of recursion - read from the read buffer,
366 if the data which we have just read from the wire
367 is not enough, then the recursive call will try to
368 satisfy it until it is satisfied.
369 */
370 DBG_RETURN(pfc->data->m.receive(pfc, vio, p, to_read, conn_stats, error_info));
371 }
372 DBG_RETURN(PASS);
373 }
374 #endif /* MYSQLND_COMPRESSION_ENABLED */
375 DBG_RETURN(vio->data->m.network_read(vio, p, to_read, conn_stats, error_info));
376 }
377 /* }}} */
378
379
380 /* {{{ mysqlnd_pfc::set_client_option */
381 static enum_func_status
MYSQLND_METHOD(mysqlnd_pfc,set_client_option)382 MYSQLND_METHOD(mysqlnd_pfc, set_client_option)(MYSQLND_PFC * const pfc, enum_mysqlnd_client_option option, const char * const value)
383 {
384 DBG_ENTER("mysqlnd_pfc::set_client_option");
385 DBG_INF_FMT("option=%u", option);
386 switch (option) {
387 case MYSQL_OPT_COMPRESS:
388 pfc->data->flags |= MYSQLND_PROTOCOL_FLAG_USE_COMPRESSION;
389 break;
390 case MYSQL_SERVER_PUBLIC_KEY: {
391 const zend_bool pers = pfc->persistent;
392 if (pfc->data->sha256_server_public_key) {
393 mnd_pefree(pfc->data->sha256_server_public_key, pers);
394 }
395 pfc->data->sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
396 break;
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
524
525 /*
526 * Local variables:
527 * tab-width: 4
528 * c-basic-offset: 4
529 * End:
530 * vim600: noet sw=4 ts=4 fdm=marker
531 * vim<600: noet sw=4 ts=4
532 */
533