This source file includes following definitions.
- mysqlnd_set_sock_no_delay
- mysqlnd_set_sock_keepalive
- php_mysqlnd_read_buffer_is_empty
- php_mysqlnd_read_buffer_read
- php_mysqlnd_read_buffer_bytes_left
- php_mysqlnd_read_buffer_free
- mysqlnd_create_read_buffer
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_CLASS_METHODS_START
- mysqlnd_net_free
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "php.h"
23 #include "php_globals.h"
24 #include "mysqlnd.h"
25 #include "mysqlnd_priv.h"
26 #include "mysqlnd_wireprotocol.h"
27 #include "mysqlnd_statistics.h"
28 #include "mysqlnd_debug.h"
29 #include "mysqlnd_ext_plugin.h"
30 #include "php_network.h"
31 #include "zend_ini.h"
32 #ifdef MYSQLND_COMPRESSION_ENABLED
33 #include <zlib.h>
34 #endif
35
36 #ifndef PHP_WIN32
37 #include <netinet/tcp.h>
38 #else
39 #include <winsock.h>
40 #endif
41
42
43
44 static int
45 mysqlnd_set_sock_no_delay(php_stream * stream)
46 {
47
48 int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
49 int ret = SUCCESS;
50 int flag = 1;
51 int result = setsockopt(socketd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
52
53 DBG_ENTER("mysqlnd_set_sock_no_delay");
54
55 if (result == -1) {
56 ret = FAILURE;
57 }
58
59 DBG_RETURN(ret);
60 }
61
62
63
64
65 static int
66 mysqlnd_set_sock_keepalive(php_stream * stream)
67 {
68
69 int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
70 int ret = SUCCESS;
71 int flag = 1;
72 int result = setsockopt(socketd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int));
73
74 DBG_ENTER("mysqlnd_set_sock_keepalive");
75
76 if (result == -1) {
77 ret = FAILURE;
78 }
79
80 DBG_RETURN(ret);
81 }
82
83
84
85
86 static enum_func_status
87 MYSQLND_METHOD(mysqlnd_net, network_read_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
88 MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
89 {
90 enum_func_status return_value = PASS;
91 php_stream * net_stream = net->data->m.get_stream(net);
92 size_t old_chunk_size = net_stream->chunk_size;
93 size_t to_read = count, ret;
94 zend_uchar * p = buffer;
95
96 DBG_ENTER("mysqlnd_net::network_read_ex");
97 DBG_INF_FMT("count="MYSQLND_SZ_T_SPEC, count);
98
99 net_stream->chunk_size = MIN(to_read, net->data->options.net_read_buffer_size);
100 while (to_read) {
101 if (!(ret = php_stream_read(net_stream, (char *) p, to_read))) {
102 DBG_ERR_FMT("Error while reading header from socket");
103 return_value = FAIL;
104 break;
105 }
106 p += ret;
107 to_read -= ret;
108 }
109 MYSQLND_INC_CONN_STATISTIC_W_VALUE(stats, STAT_BYTES_RECEIVED, count - to_read);
110 net_stream->chunk_size = old_chunk_size;
111 DBG_RETURN(return_value);
112 }
113
114
115
116
117 static size_t
118 MYSQLND_METHOD(mysqlnd_net, network_write_ex)(MYSQLND_NET * const net, const zend_uchar * const buffer, const size_t count,
119 MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
120 {
121 size_t ret;
122 DBG_ENTER("mysqlnd_net::network_write_ex");
123 DBG_INF_FMT("sending %u bytes", count);
124 ret = php_stream_write(net->data->m.get_stream(net), (char *)buffer, count);
125 DBG_RETURN(ret);
126 }
127
128
129
130
131 static php_stream *
132 MYSQLND_METHOD(mysqlnd_net, open_pipe)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
133 const zend_bool persistent,
134 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
135 {
136 #if PHP_API_VERSION < 20100412
137 unsigned int streams_options = ENFORCE_SAFE_MODE;
138 #else
139 unsigned int streams_options = 0;
140 #endif
141 dtor_func_t origin_dtor;
142 php_stream * net_stream = NULL;
143
144 DBG_ENTER("mysqlnd_net::open_pipe");
145 if (persistent) {
146 streams_options |= STREAM_OPEN_PERSISTENT;
147 }
148 streams_options |= IGNORE_URL;
149 net_stream = php_stream_open_wrapper((char*) scheme + sizeof("pipe://") - 1, "r+", streams_options, NULL);
150 if (!net_stream) {
151 SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown errror while connecting");
152 DBG_RETURN(NULL);
153 }
154
155
156
157
158
159 origin_dtor = EG(regular_list).pDestructor;
160 EG(regular_list).pDestructor = NULL;
161 zend_hash_index_del(&EG(regular_list), net_stream->res->handle);
162 EG(regular_list).pDestructor = origin_dtor;
163 net_stream->res = NULL;
164
165 DBG_RETURN(net_stream);
166 }
167
168
169
170
171 static php_stream *
172 MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
173 const zend_bool persistent,
174 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
175 {
176 #if PHP_API_VERSION < 20100412
177 unsigned int streams_options = ENFORCE_SAFE_MODE;
178 #else
179 unsigned int streams_options = 0;
180 #endif
181 unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
182 char * hashed_details = NULL;
183 int hashed_details_len = 0;
184 zend_string *errstr = NULL;
185 int errcode = 0;
186 struct timeval tv;
187 dtor_func_t origin_dtor;
188 php_stream * net_stream = NULL;
189
190 DBG_ENTER("mysqlnd_net::open_tcp_or_unix");
191
192 net->data->stream = NULL;
193
194 if (persistent) {
195 hashed_details_len = mnd_sprintf(&hashed_details, 0, "%p", net);
196 DBG_INF_FMT("hashed_details=%s", hashed_details);
197 }
198
199 if (net->data->options.timeout_connect) {
200 tv.tv_sec = net->data->options.timeout_connect;
201 tv.tv_usec = 0;
202 }
203
204 DBG_INF_FMT("calling php_stream_xport_create");
205 net_stream = php_stream_xport_create(scheme, scheme_len, streams_options, streams_flags,
206 hashed_details, (net->data->options.timeout_connect) ? &tv : NULL,
207 NULL , &errstr, &errcode);
208 if (errstr || !net_stream) {
209 DBG_ERR("Error");
210 if (hashed_details) {
211 mnd_sprintf_free(hashed_details);
212 }
213 errcode = CR_CONNECTION_ERROR;
214 SET_CLIENT_ERROR(*error_info,
215 CR_CONNECTION_ERROR,
216 UNKNOWN_SQLSTATE,
217 errstr? ZSTR_VAL(errstr):"Unknown error while connecting");
218 if (errstr) {
219 zend_string_release(errstr);
220 }
221 DBG_RETURN(NULL);
222 }
223 if (hashed_details) {
224
225
226
227
228
229 zend_resource *le;
230
231 if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) {
232 origin_dtor = EG(persistent_list).pDestructor;
233
234
235
236
237
238 EG(persistent_list).pDestructor = NULL;
239 zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len);
240 EG(persistent_list).pDestructor = origin_dtor;
241 pefree(le, 1);
242 }
243 #if ZEND_DEBUG
244
245 net_stream->__exposed = 1;
246 #endif
247 mnd_sprintf_free(hashed_details);
248 }
249
250
251
252
253
254
255 origin_dtor = EG(regular_list).pDestructor;
256 EG(regular_list).pDestructor = NULL;
257 zend_hash_index_del(&EG(regular_list), net_stream->res->handle);
258 efree(net_stream->res);
259 net_stream->res = NULL;
260 EG(regular_list).pDestructor = origin_dtor;
261 DBG_RETURN(net_stream);
262 }
263
264
265
266
267 static void
268 MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt)(MYSQLND_NET * const net,
269 const char * const scheme, const size_t scheme_len,
270 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
271 {
272 php_stream * net_stream = net->data->m.get_stream(net);
273 DBG_ENTER("mysqlnd_net::post_connect_set_opt");
274 if (net_stream) {
275 if (net->data->options.timeout_read) {
276 struct timeval tv;
277 DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
278 tv.tv_sec = net->data->options.timeout_read;
279 tv.tv_usec = 0;
280 php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
281 }
282
283 if (!memcmp(scheme, "tcp://", sizeof("tcp://") - 1)) {
284
285 mysqlnd_set_sock_no_delay(net_stream);
286
287 mysqlnd_set_sock_keepalive(net_stream);
288 }
289 }
290
291 DBG_VOID_RETURN;
292 }
293
294
295
296
297 static func_mysqlnd_net__open_stream
298 MYSQLND_METHOD(mysqlnd_net, get_open_stream)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
299 MYSQLND_ERROR_INFO * const error_info)
300 {
301 func_mysqlnd_net__open_stream ret = NULL;
302 DBG_ENTER("mysqlnd_net::get_open_stream");
303 if (scheme_len > (sizeof("pipe://") - 1) && !memcmp(scheme, "pipe://", sizeof("pipe://") - 1)) {
304 ret = net->data->m.open_pipe;
305 } else if ((scheme_len > (sizeof("tcp://") - 1) && !memcmp(scheme, "tcp://", sizeof("tcp://") - 1))
306 ||
307 (scheme_len > (sizeof("unix://") - 1) && !memcmp(scheme, "unix://", sizeof("unix://") - 1)))
308 {
309 ret = net->data->m.open_tcp_or_unix;
310 }
311
312 if (!ret) {
313 SET_CLIENT_ERROR(*error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "No handler for this scheme");
314 }
315
316 DBG_RETURN(ret);
317 }
318
319
320
321
322 static enum_func_status
323 MYSQLND_METHOD(mysqlnd_net, connect_ex)(MYSQLND_NET * const net, const char * const scheme, const size_t scheme_len,
324 const zend_bool persistent,
325 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
326 {
327 enum_func_status ret = FAIL;
328 func_mysqlnd_net__open_stream open_stream = NULL;
329 DBG_ENTER("mysqlnd_net::connect_ex");
330
331 net->packet_no = net->compressed_envelope_packet_no = 0;
332
333 net->data->m.close_stream(net, conn_stats, error_info);
334
335 open_stream = net->data->m.get_open_stream(net, scheme, scheme_len, error_info);
336 if (open_stream) {
337 php_stream * net_stream = open_stream(net, scheme, scheme_len, persistent, conn_stats, error_info);
338 if (net_stream) {
339 (void) net->data->m.set_stream(net, net_stream);
340 net->data->m.post_connect_set_opt(net, scheme, scheme_len, conn_stats, error_info);
341 ret = PASS;
342 }
343 }
344
345 DBG_RETURN(ret);
346 }
347
348
349
350
351 #define COPY_HEADER(T,A) do { \
352 *(((char *)(T))) = *(((char *)(A)));\
353 *(((char *)(T))+1) = *(((char *)(A))+1);\
354 *(((char *)(T))+2) = *(((char *)(A))+2);\
355 *(((char *)(T))+3) = *(((char *)(A))+3); } while (0)
356 #define STORE_HEADER_SIZE(safe_storage, buffer) COPY_HEADER((safe_storage), (buffer))
357 #define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
358
359
360
361
362
363
364
365
366
367
368
369
370
371 static size_t
372 MYSQLND_METHOD(mysqlnd_net, send_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
373 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
374 {
375 zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
376 zend_uchar * safe_storage = safe_buf;
377 size_t bytes_sent, packets_sent = 1;
378 size_t left = count;
379 zend_uchar * p = (zend_uchar *) buffer;
380 zend_uchar * compress_buf = NULL;
381 size_t to_be_sent;
382
383 DBG_ENTER("mysqlnd_net::send_ex");
384 DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->data->compressed);
385
386 if (net->data->compressed == TRUE) {
387 size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
388 DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
389 compress_buf = mnd_emalloc(comp_buf_size);
390 }
391
392 do {
393 to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
394 DBG_INF_FMT("to_be_sent=%u", to_be_sent);
395 DBG_INF_FMT("packets_sent=%u", packets_sent);
396 DBG_INF_FMT("compressed_envelope_packet_no=%u", net->compressed_envelope_packet_no);
397 DBG_INF_FMT("packet_no=%u", net->packet_no);
398 #ifdef MYSQLND_COMPRESSION_ENABLED
399 if (net->data->compressed == TRUE) {
400
401 size_t tmp_complen = to_be_sent;
402 size_t payload_size;
403 zend_uchar * uncompressed_payload = p;
404
405 STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
406 int3store(uncompressed_payload, to_be_sent);
407 int1store(uncompressed_payload + 3, net->packet_no);
408 if (PASS == net->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
409 uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE))
410 {
411 int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
412 payload_size = tmp_complen;
413 } else {
414 int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
415 memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
416 payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
417 }
418 RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
419
420 int3store(compress_buf, payload_size);
421 int1store(compress_buf + 3, net->packet_no);
422 DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
423 bytes_sent = net->data->m.network_write_ex(net, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE,
424 conn_stats, error_info);
425 net->compressed_envelope_packet_no++;
426 #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
427 if (res == Z_OK) {
428 size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
429 zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
430 int error = net->data->m.decode(decompressed_data, decompressed_size,
431 compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
432 if (error == Z_OK) {
433 int i;
434 DBG_INF("success decompressing");
435 for (i = 0 ; i < decompressed_size; i++) {
436 if (i && (i % 30 == 0)) {
437 printf("\n\t\t");
438 }
439 printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
440 DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
441 }
442 } else {
443 DBG_INF("error decompressing");
444 }
445 mnd_free(decompressed_data);
446 }
447 #endif
448 } else
449 #endif
450 {
451 DBG_INF("no compression");
452 STORE_HEADER_SIZE(safe_storage, p);
453 int3store(p, to_be_sent);
454 int1store(p + 3, net->packet_no);
455 bytes_sent = net->data->m.network_write_ex(net, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
456 RESTORE_HEADER_SIZE(p, safe_storage);
457 net->compressed_envelope_packet_no++;
458 }
459 net->packet_no++;
460
461 p += to_be_sent;
462 left -= to_be_sent;
463 packets_sent++;
464
465
466
467
468
469
470
471 } while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));
472
473 DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);
474
475 MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
476 STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
477 STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
478 STAT_PACKETS_SENT, packets_sent);
479
480 if (compress_buf) {
481 mnd_efree(compress_buf);
482 }
483
484
485 if (!bytes_sent) {
486 DBG_ERR_FMT("Can't %u send bytes", count);
487 SET_CLIENT_ERROR(*error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
488 }
489 DBG_RETURN(bytes_sent);
490 }
491
492
493
494 #ifdef MYSQLND_COMPRESSION_ENABLED
495
496 static zend_bool
497 php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
498 {
499 return buffer->len? FALSE:TRUE;
500 }
501
502
503
504
505 static void
506 php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
507 {
508 if (buffer->len >= count) {
509 memcpy(dest, buffer->data + buffer->offset, count);
510 buffer->offset += count;
511 buffer->len -= count;
512 }
513 }
514
515
516
517
518 static size_t
519 php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
520 {
521 return buffer->len;
522 }
523
524
525
526
527 static void
528 php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer)
529 {
530 DBG_ENTER("php_mysqlnd_read_buffer_free");
531 if (*buffer) {
532 mnd_efree((*buffer)->data);
533 mnd_efree(*buffer);
534 *buffer = NULL;
535 }
536 DBG_VOID_RETURN;
537 }
538
539
540
541
542 static MYSQLND_READ_BUFFER *
543 mysqlnd_create_read_buffer(size_t count)
544 {
545 MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
546 DBG_ENTER("mysqlnd_create_read_buffer");
547 ret->is_empty = php_mysqlnd_read_buffer_is_empty;
548 ret->read = php_mysqlnd_read_buffer_read;
549 ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
550 ret->free_buffer = php_mysqlnd_read_buffer_free;
551 ret->data = mnd_emalloc(count);
552 ret->size = ret->len = count;
553 ret->offset = 0;
554 DBG_RETURN(ret);
555 }
556
557
558
559
560 static enum_func_status
561 MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer)
562 (MYSQLND_NET * net, size_t net_payload_size, MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
563 {
564 size_t decompressed_size;
565 enum_func_status retval = PASS;
566 zend_uchar * compressed_data = NULL;
567 zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
568 DBG_ENTER("mysqlnd_net::read_compressed_packet_from_stream_and_fill_read_buffer");
569
570
571 if (FAIL == net->data->m.network_read_ex(net, comp_header, COMPRESSED_HEADER_SIZE, conn_stats, error_info)) {
572 DBG_RETURN(FAIL);
573 }
574 decompressed_size = uint3korr(comp_header);
575
576
577
578
579 if (decompressed_size) {
580 compressed_data = mnd_emalloc(net_payload_size);
581 if (FAIL == net->data->m.network_read_ex(net, compressed_data, net_payload_size, conn_stats, error_info)) {
582 retval = FAIL;
583 goto end;
584 }
585 net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size);
586 retval = net->data->m.decode(net->uncompressed_data->data, decompressed_size, compressed_data, net_payload_size);
587 if (FAIL == retval) {
588 goto end;
589 }
590 } else {
591 DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
592 net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size);
593 if (FAIL == net->data->m.network_read_ex(net, net->uncompressed_data->data, net_payload_size, conn_stats, error_info)) {
594 retval = FAIL;
595 goto end;
596 }
597 }
598 end:
599 if (compressed_data) {
600 mnd_efree(compressed_data);
601 }
602 DBG_RETURN(retval);
603 }
604
605 #endif
606
607
608
609 static enum_func_status
610 MYSQLND_METHOD(mysqlnd_net, decode)(zend_uchar * uncompressed_data, const size_t uncompressed_data_len,
611 const zend_uchar * const compressed_data, const size_t compressed_data_len)
612 {
613 #ifdef MYSQLND_COMPRESSION_ENABLED
614 int error;
615 uLongf tmp_complen = uncompressed_data_len;
616 DBG_ENTER("mysqlnd_net::decode");
617 error = uncompress(uncompressed_data, &tmp_complen, compressed_data, compressed_data_len);
618
619 DBG_INF_FMT("compressed data: decomp_len=%lu compressed_size="MYSQLND_SZ_T_SPEC, tmp_complen, compressed_data_len);
620 if (error != Z_OK) {
621 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);
622 }
623 DBG_RETURN(error == Z_OK? PASS:FAIL);
624 #else
625 DBG_ENTER("mysqlnd_net::decode");
626 DBG_RETURN(FAIL);
627 #endif
628 }
629
630
631
632
633 static enum_func_status
634 MYSQLND_METHOD(mysqlnd_net, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
635 const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
636 {
637 #ifdef MYSQLND_COMPRESSION_ENABLED
638 int error;
639 uLongf tmp_complen = *compress_buffer_len;
640 DBG_ENTER("mysqlnd_net::encode");
641 error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
642
643 if (error != Z_OK) {
644 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);
645 } else {
646 *compress_buffer_len = tmp_complen;
647 DBG_INF_FMT("compression successful. compressed size=%lu", tmp_complen);
648 }
649
650 DBG_RETURN(error == Z_OK? PASS:FAIL);
651 #else
652 DBG_ENTER("mysqlnd_net::encode");
653 DBG_RETURN(FAIL);
654 #endif
655 }
656
657
658
659
660 static enum_func_status
661 MYSQLND_METHOD(mysqlnd_net, receive_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
662 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
663 {
664 size_t to_read = count;
665 zend_uchar * p = buffer;
666
667 DBG_ENTER("mysqlnd_net::receive_ex");
668 #ifdef MYSQLND_COMPRESSION_ENABLED
669 if (net->data->compressed) {
670 if (net->uncompressed_data) {
671 size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
672 DBG_INF_FMT("reading "MYSQLND_SZ_T_SPEC" from uncompressed_data buffer", to_read_from_buffer);
673 if (to_read_from_buffer) {
674 net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
675 p += to_read_from_buffer;
676 to_read -= to_read_from_buffer;
677 }
678 DBG_INF_FMT("left "MYSQLND_SZ_T_SPEC" to read", to_read);
679 if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
680
681 net->uncompressed_data->free_buffer(&net->uncompressed_data);
682 }
683 }
684 if (to_read) {
685 zend_uchar net_header[MYSQLND_HEADER_SIZE];
686 size_t net_payload_size;
687 zend_uchar packet_no;
688
689 if (FAIL == net->data->m.network_read_ex(net, net_header, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
690 DBG_RETURN(FAIL);
691 }
692 net_payload_size = uint3korr(net_header);
693 packet_no = uint1korr(net_header + 3);
694 if (net->compressed_envelope_packet_no != packet_no) {
695 DBG_ERR_FMT("Transport level: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
696 net->compressed_envelope_packet_no, packet_no, net_payload_size);
697
698 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
699 net->compressed_envelope_packet_no, packet_no, net_payload_size);
700 DBG_RETURN(FAIL);
701 }
702 net->compressed_envelope_packet_no++;
703 #ifdef MYSQLND_DUMP_HEADER_N_BODY
704 DBG_INF_FMT("HEADER: hwd_packet_no=%u size=%3u", packet_no, (zend_ulong) net_payload_size);
705 #endif
706
707 net->data->m.read_compressed_packet_from_stream_and_fill_read_buffer(net, net_payload_size, conn_stats, error_info);
708
709
710
711
712
713
714
715 DBG_RETURN(net->data->m.receive_ex(net, p, to_read, conn_stats, error_info));
716 }
717 DBG_RETURN(PASS);
718 }
719 #endif
720 DBG_RETURN(net->data->m.network_read_ex(net, p, to_read, conn_stats, error_info));
721 }
722
723
724
725
726 static enum_func_status
727 MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mysqlnd_option option, const char * const value)
728 {
729 DBG_ENTER("mysqlnd_net::set_client_option");
730 DBG_INF_FMT("option=%u", option);
731 switch (option) {
732 case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
733 DBG_INF("MYSQLND_OPT_NET_CMD_BUFFER_SIZE");
734 if (*(unsigned int*) value < MYSQLND_NET_CMD_BUFFER_MIN_SIZE) {
735 DBG_RETURN(FAIL);
736 }
737 net->cmd_buffer.length = *(unsigned int*) value;
738 DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->cmd_buffer.length);
739 if (!net->cmd_buffer.buffer) {
740 net->cmd_buffer.buffer = mnd_pemalloc(net->cmd_buffer.length, net->persistent);
741 } else {
742 net->cmd_buffer.buffer = mnd_perealloc(net->cmd_buffer.buffer, net->cmd_buffer.length, net->persistent);
743 }
744 break;
745 case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
746 DBG_INF("MYSQLND_OPT_NET_READ_BUFFER_SIZE");
747 net->data->options.net_read_buffer_size = *(unsigned int*) value;
748 DBG_INF_FMT("new_length="MYSQLND_SZ_T_SPEC, net->data->options.net_read_buffer_size);
749 break;
750 case MYSQL_OPT_CONNECT_TIMEOUT:
751 DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
752 net->data->options.timeout_connect = *(unsigned int*) value;
753 break;
754 case MYSQLND_OPT_SSL_KEY:
755 {
756 zend_bool pers = net->persistent;
757 if (net->data->options.ssl_key) {
758 mnd_pefree(net->data->options.ssl_key, pers);
759 }
760 net->data->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
761 break;
762 }
763 case MYSQLND_OPT_SSL_CERT:
764 {
765 zend_bool pers = net->persistent;
766 if (net->data->options.ssl_cert) {
767 mnd_pefree(net->data->options.ssl_cert, pers);
768 }
769 net->data->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
770 break;
771 }
772 case MYSQLND_OPT_SSL_CA:
773 {
774 zend_bool pers = net->persistent;
775 if (net->data->options.ssl_ca) {
776 mnd_pefree(net->data->options.ssl_ca, pers);
777 }
778 net->data->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
779 break;
780 }
781 case MYSQLND_OPT_SSL_CAPATH:
782 {
783 zend_bool pers = net->persistent;
784 if (net->data->options.ssl_capath) {
785 mnd_pefree(net->data->options.ssl_capath, pers);
786 }
787 net->data->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
788 break;
789 }
790 case MYSQLND_OPT_SSL_CIPHER:
791 {
792 zend_bool pers = net->persistent;
793 if (net->data->options.ssl_cipher) {
794 mnd_pefree(net->data->options.ssl_cipher, pers);
795 }
796 net->data->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
797 break;
798 }
799 case MYSQLND_OPT_SSL_PASSPHRASE:
800 {
801 zend_bool pers = net->persistent;
802 if (net->data->options.ssl_passphrase) {
803 mnd_pefree(net->data->options.ssl_passphrase, pers);
804 }
805 net->data->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
806 break;
807 }
808 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
809 {
810 enum mysqlnd_ssl_peer val = *((enum mysqlnd_ssl_peer *)value);
811 switch (val) {
812 case MYSQLND_SSL_PEER_VERIFY:
813 DBG_INF("MYSQLND_SSL_PEER_VERIFY");
814 break;
815 case MYSQLND_SSL_PEER_DONT_VERIFY:
816 DBG_INF("MYSQLND_SSL_PEER_DONT_VERIFY");
817 break;
818 case MYSQLND_SSL_PEER_DEFAULT:
819 DBG_INF("MYSQLND_SSL_PEER_DEFAULT");
820 val = MYSQLND_SSL_PEER_DEFAULT;
821 break;
822 default:
823 DBG_INF("default = MYSQLND_SSL_PEER_DEFAULT_ACTION");
824 val = MYSQLND_SSL_PEER_DEFAULT;
825 break;
826 }
827 net->data->options.ssl_verify_peer = val;
828 break;
829 }
830 case MYSQL_OPT_READ_TIMEOUT:
831 net->data->options.timeout_read = *(unsigned int*) value;
832 break;
833 #ifdef WHEN_SUPPORTED_BY_MYSQLI
834 case MYSQL_OPT_WRITE_TIMEOUT:
835 net->data->options.timeout_write = *(unsigned int*) value;
836 break;
837 #endif
838 case MYSQL_OPT_COMPRESS:
839 net->data->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION;
840 break;
841 case MYSQL_SERVER_PUBLIC_KEY:
842 {
843 zend_bool pers = net->persistent;
844 if (net->data->options.sha256_server_public_key) {
845 mnd_pefree(net->data->options.sha256_server_public_key, pers);
846 }
847 net->data->options.sha256_server_public_key = value? mnd_pestrdup(value, pers) : NULL;
848 break;
849 }
850 default:
851 DBG_RETURN(FAIL);
852 }
853 DBG_RETURN(PASS);
854 }
855
856
857
858 size_t
859 MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data)(MYSQLND_NET * const net, enum php_mysqlnd_server_command cmd)
860 {
861 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
862
863
864
865
866
867
868
869 char tmp_buf[256];
870 size_t skipped_bytes = 0;
871 int opt = PHP_STREAM_OPTION_BLOCKING;
872 php_stream * net_stream = net->data->get_stream(net);
873 int was_blocked = net_stream->ops->set_option(net_stream, opt, 0, NULL);
874
875 DBG_ENTER("mysqlnd_net::consume_uneaten_data");
876
877 if (PHP_STREAM_OPTION_RETURN_ERR != was_blocked) {
878
879 int bytes_consumed;
880
881 do {
882 skipped_bytes += (bytes_consumed = php_stream_read(net_stream, tmp_buf, sizeof(tmp_buf)));
883 } while (bytes_consumed == sizeof(tmp_buf));
884
885 if (was_blocked) {
886 net_stream->ops->set_option(net_stream, opt, 1, NULL);
887 }
888
889 if (bytes_consumed) {
890 DBG_ERR_FMT("Skipped %u bytes. Last command %s hasn't consumed all the output from the server",
891 bytes_consumed, mysqlnd_command_to_text[net->last_command]);
892 php_error_docref(NULL, E_WARNING, "Skipped %u bytes. Last command %s hasn't "
893 "consumed all the output from the server",
894 bytes_consumed, mysqlnd_command_to_text[net->last_command]);
895 }
896 }
897 net->last_command = cmd;
898
899 DBG_RETURN(skipped_bytes);
900 #else
901 return 0;
902 #endif
903 }
904
905
906
907
908
909
910 static enum_func_status
911 MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net)
912 {
913 #ifdef MYSQLND_SSL_SUPPORTED
914 php_stream_context * context = php_stream_context_alloc();
915 php_stream * net_stream = net->data->m.get_stream(net);
916 zend_bool any_flag = FALSE;
917
918 DBG_ENTER("mysqlnd_net::enable_ssl");
919 if (!context) {
920 DBG_RETURN(FAIL);
921 }
922
923 if (net->data->options.ssl_key) {
924 zval key_zval;
925 ZVAL_STRING(&key_zval, net->data->options.ssl_key);
926 php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);
927 zval_ptr_dtor(&key_zval);
928 any_flag = TRUE;
929 }
930 if (net->data->options.ssl_cert) {
931 zval cert_zval;
932 ZVAL_STRING(&cert_zval, net->data->options.ssl_cert);
933 php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
934 if (!net->data->options.ssl_key) {
935 php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);
936 }
937 zval_ptr_dtor(&cert_zval);
938 any_flag = TRUE;
939 }
940 if (net->data->options.ssl_ca) {
941 zval cafile_zval;
942 ZVAL_STRING(&cafile_zval, net->data->options.ssl_ca);
943 php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
944 any_flag = TRUE;
945 }
946 if (net->data->options.ssl_capath) {
947 zval capath_zval;
948 ZVAL_STRING(&capath_zval, net->data->options.ssl_capath);
949 php_stream_context_set_option(context, "ssl", "capath", &capath_zval);
950 zval_ptr_dtor(&capath_zval);
951 any_flag = TRUE;
952 }
953 if (net->data->options.ssl_passphrase) {
954 zval passphrase_zval;
955 ZVAL_STRING(&passphrase_zval, net->data->options.ssl_passphrase);
956 php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
957 zval_ptr_dtor(&passphrase_zval);
958 any_flag = TRUE;
959 }
960 if (net->data->options.ssl_cipher) {
961 zval cipher_zval;
962 ZVAL_STRING(&cipher_zval, net->data->options.ssl_cipher);
963 php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
964 zval_ptr_dtor(&cipher_zval);
965 any_flag = TRUE;
966 }
967 {
968 zval verify_peer_zval;
969 zend_bool verify;
970
971 if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DEFAULT) {
972 net->data->options.ssl_verify_peer = any_flag? MYSQLND_SSL_PEER_DEFAULT_ACTION:MYSQLND_SSL_PEER_DONT_VERIFY;
973 }
974
975 verify = net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_VERIFY? TRUE:FALSE;
976
977 DBG_INF_FMT("VERIFY=%d", verify);
978 ZVAL_BOOL(&verify_peer_zval, verify);
979 php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
980 php_stream_context_set_option(context, "ssl", "verify_peer_name", &verify_peer_zval);
981 if (net->data->options.ssl_verify_peer == MYSQLND_SSL_PEER_DONT_VERIFY) {
982 ZVAL_TRUE(&verify_peer_zval);
983 php_stream_context_set_option(context, "ssl", "allow_self_signed", &verify_peer_zval);
984 }
985 }
986 #if PHP_API_VERSION >= 20131106
987 php_stream_context_set(net_stream, context);
988 #else
989 php_stream_context_set(net_stream, context);
990 #endif
991 if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL) < 0 ||
992 php_stream_xport_crypto_enable(net_stream, 1) < 0)
993 {
994 DBG_ERR("Cannot connect to MySQL by using SSL");
995 php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL");
996 DBG_RETURN(FAIL);
997 }
998 net->data->ssl = TRUE;
999
1000
1001
1002
1003
1004
1005
1006 #if PHP_API_VERSION >= 20131106
1007 php_stream_context_set(net_stream, NULL);
1008 #else
1009 php_stream_context_set(net_stream, NULL);
1010 #endif
1011
1012 if (net->data->options.timeout_read) {
1013 struct timeval tv;
1014 DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->data->options.timeout_read);
1015 tv.tv_sec = net->data->options.timeout_read;
1016 tv.tv_usec = 0;
1017 php_stream_set_option(net_stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
1018 }
1019
1020 DBG_RETURN(PASS);
1021 #else
1022 DBG_ENTER("mysqlnd_net::enable_ssl");
1023 DBG_INF("MYSQLND_SSL_SUPPORTED is not defined");
1024 DBG_RETURN(PASS);
1025 #endif
1026 }
1027
1028
1029
1030
1031 static enum_func_status
1032 MYSQLND_METHOD(mysqlnd_net, disable_ssl)(MYSQLND_NET * const net)
1033 {
1034 DBG_ENTER("mysqlnd_net::disable_ssl");
1035 DBG_RETURN(PASS);
1036 }
1037
1038
1039
1040
1041 static void
1042 MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net)
1043 {
1044 zend_bool pers = net->persistent;
1045 DBG_ENTER("mysqlnd_net::free_contents");
1046
1047 #ifdef MYSQLND_COMPRESSION_ENABLED
1048 if (net->uncompressed_data) {
1049 net->uncompressed_data->free_buffer(&net->uncompressed_data);
1050 }
1051 #endif
1052 if (net->data->options.ssl_key) {
1053 mnd_pefree(net->data->options.ssl_key, pers);
1054 net->data->options.ssl_key = NULL;
1055 }
1056 if (net->data->options.ssl_cert) {
1057 mnd_pefree(net->data->options.ssl_cert, pers);
1058 net->data->options.ssl_cert = NULL;
1059 }
1060 if (net->data->options.ssl_ca) {
1061 mnd_pefree(net->data->options.ssl_ca, pers);
1062 net->data->options.ssl_ca = NULL;
1063 }
1064 if (net->data->options.ssl_capath) {
1065 mnd_pefree(net->data->options.ssl_capath, pers);
1066 net->data->options.ssl_capath = NULL;
1067 }
1068 if (net->data->options.ssl_cipher) {
1069 mnd_pefree(net->data->options.ssl_cipher, pers);
1070 net->data->options.ssl_cipher = NULL;
1071 }
1072 if (net->data->options.sha256_server_public_key) {
1073 mnd_pefree(net->data->options.sha256_server_public_key, pers);
1074 net->data->options.sha256_server_public_key = NULL;
1075 }
1076
1077 DBG_VOID_RETURN;
1078 }
1079
1080
1081
1082
1083 static void
1084 MYSQLND_METHOD(mysqlnd_net, close_stream)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
1085 {
1086 php_stream * net_stream;
1087 DBG_ENTER("mysqlnd_net::close_stream");
1088 if (net && (net_stream = net->data->m.get_stream(net))) {
1089 zend_bool pers = net->persistent;
1090 DBG_INF_FMT("Freeing stream. abstract=%p", net_stream->abstract);
1091 if (pers) {
1092 if (EG(active)) {
1093 php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
1094 } else {
1095
1096
1097
1098
1099 php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
1100 }
1101 } else {
1102 php_stream_free(net_stream, PHP_STREAM_FREE_CLOSE);
1103 }
1104 (void) net->data->m.set_stream(net, NULL);
1105 }
1106
1107 DBG_VOID_RETURN;
1108 }
1109
1110
1111
1112
1113 static enum_func_status
1114 MYSQLND_METHOD(mysqlnd_net, init)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
1115 {
1116 unsigned int buf_size;
1117 DBG_ENTER("mysqlnd_net::init");
1118
1119 buf_size = MYSQLND_G(net_cmd_buffer_size);
1120 net->data->m.set_client_option(net, MYSQLND_OPT_NET_CMD_BUFFER_SIZE, (char *) &buf_size);
1121
1122 buf_size = MYSQLND_G(net_read_buffer_size);
1123 net->data->m.set_client_option(net, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size);
1124
1125 buf_size = MYSQLND_G(net_read_timeout);
1126 net->data->m.set_client_option(net, MYSQL_OPT_READ_TIMEOUT, (char *)&buf_size);
1127
1128 DBG_RETURN(PASS);
1129 }
1130
1131
1132
1133
1134 static void
1135 MYSQLND_METHOD(mysqlnd_net, dtor)(MYSQLND_NET * const net, MYSQLND_STATS * const stats, MYSQLND_ERROR_INFO * const error_info)
1136 {
1137 DBG_ENTER("mysqlnd_net::dtor");
1138 if (net) {
1139 net->data->m.free_contents(net);
1140 net->data->m.close_stream(net, stats, error_info);
1141
1142 if (net->cmd_buffer.buffer) {
1143 DBG_INF("Freeing cmd buffer");
1144 mnd_pefree(net->cmd_buffer.buffer, net->persistent);
1145 net->cmd_buffer.buffer = NULL;
1146 }
1147
1148 mnd_pefree(net->data, net->data->persistent);
1149 mnd_pefree(net, net->persistent);
1150 }
1151 DBG_VOID_RETURN;
1152 }
1153
1154
1155
1156
1157 static php_stream *
1158 MYSQLND_METHOD(mysqlnd_net, get_stream)(const MYSQLND_NET * const net)
1159 {
1160 DBG_ENTER("mysqlnd_net::get_stream");
1161 DBG_INF_FMT("%p", net? net->data->stream:NULL);
1162 DBG_RETURN(net? net->data->stream:NULL);
1163 }
1164
1165
1166
1167
1168 static php_stream *
1169 MYSQLND_METHOD(mysqlnd_net, set_stream)(MYSQLND_NET * const net, php_stream * net_stream)
1170 {
1171 php_stream * ret = NULL;
1172 DBG_ENTER("mysqlnd_net::set_stream");
1173 if (net) {
1174 net->data->stream = net_stream;
1175 ret = net->data->stream;
1176 }
1177 DBG_RETURN(ret);
1178 }
1179
1180
1181
1182 MYSQLND_CLASS_METHODS_START(mysqlnd_net)
1183 MYSQLND_METHOD(mysqlnd_net, init),
1184 MYSQLND_METHOD(mysqlnd_net, dtor),
1185 MYSQLND_METHOD(mysqlnd_net, connect_ex),
1186 MYSQLND_METHOD(mysqlnd_net, close_stream),
1187 MYSQLND_METHOD(mysqlnd_net, open_pipe),
1188 MYSQLND_METHOD(mysqlnd_net, open_tcp_or_unix),
1189 MYSQLND_METHOD(mysqlnd_net, get_stream),
1190 MYSQLND_METHOD(mysqlnd_net, set_stream),
1191 MYSQLND_METHOD(mysqlnd_net, get_open_stream),
1192 MYSQLND_METHOD(mysqlnd_net, post_connect_set_opt),
1193 MYSQLND_METHOD(mysqlnd_net, set_client_option),
1194 MYSQLND_METHOD(mysqlnd_net, decode),
1195 MYSQLND_METHOD(mysqlnd_net, encode),
1196 MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data),
1197 MYSQLND_METHOD(mysqlnd_net, free_contents),
1198 MYSQLND_METHOD(mysqlnd_net, enable_ssl),
1199 MYSQLND_METHOD(mysqlnd_net, disable_ssl),
1200 MYSQLND_METHOD(mysqlnd_net, network_read_ex),
1201 MYSQLND_METHOD(mysqlnd_net, network_write_ex),
1202 MYSQLND_METHOD(mysqlnd_net, send_ex),
1203 MYSQLND_METHOD(mysqlnd_net, receive_ex),
1204 #ifdef MYSQLND_COMPRESSION_ENABLED
1205 MYSQLND_METHOD(mysqlnd_net, read_compressed_packet_from_stream_and_fill_read_buffer),
1206 #else
1207 NULL,
1208 #endif
1209 NULL,
1210 NULL,
1211 NULL,
1212 NULL,
1213 NULL
1214 MYSQLND_CLASS_METHODS_END;
1215
1216
1217
1218 PHPAPI MYSQLND_NET *
1219 mysqlnd_net_init(zend_bool persistent, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
1220 {
1221 MYSQLND_NET * net;
1222 DBG_ENTER("mysqlnd_net_init");
1223 net = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_io_channel(persistent, stats, error_info);
1224 DBG_RETURN(net);
1225 }
1226
1227
1228
1229
1230 PHPAPI void
1231 mysqlnd_net_free(MYSQLND_NET * const net, MYSQLND_STATS * stats, MYSQLND_ERROR_INFO * error_info)
1232 {
1233 DBG_ENTER("mysqlnd_net_free");
1234 if (net) {
1235 net->data->m.dtor(net, stats, error_info);
1236 }
1237 DBG_VOID_RETURN;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250