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