Skip to content

When I use memcached, memcached has a bad effect on pfsockopen function #313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lizhibin205 opened this issue Feb 6, 2017 · 7 comments
Closed

Comments

@lizhibin205
Copy link

lizhibin205 commented Feb 6, 2017

when I use memcached, memcached has an bad effect on pfsockopen function. pfsockopen can't check whether the TCP link is alive.

Here is my php code:

<?php
$num = 1;
while ($num < 5) {
    echo ">>>start {$num}", PHP_EOL;
    $mc = new Memcached();
    $mc->addServer('host.com', 11511);
    $data = $mc->get("freg127.0.0.1");
    $socket = pfsockopen("host2.com", 80, $errno, $errstr, 30);
    echo $socket, PHP_EOL;
    stream_set_write_buffer($socket, 0);
    socket_set_timeout($socket, 30);
    $request = get_post_data();
    $len = fputs($socket, $request, strlen($request));
    echo "send {$len} data", PHP_EOL;
    $read = fgets($socket);
    if (preg_match("/^HTTP/", $read) === 0) {
        echo "Illegal HTTP server.{$read}", PHP_EOL;
        exit;
    }
    $content_length = 0;
    while (!feof($socket)) {
        $read = fgets($socket);
        if (preg_match("/^Content-Length: (\d+)/", $read, $matches) === 1) {
            $content_length = intval($matches[1]);
        }
        if ($read == "\r\n") {
            break;
        }
    }
    $read_len = fread($socket, $content_length);
    echo "read content {$content_length} data", PHP_EOL;
    echo "sleep 120", PHP_EOL;
    sleep(120);
    ++$num;
}

function get_post_data()
{
    return <<<DATA
POST /users/api.php HTTP/1.1
Host: host2.com:80
User-Agent: PHPRPC Client 3.0 for PHP
Connection: Keep-Alive
Cache-Control: no-cache
Accept: */*
Accept-Encoding: gzip,deflate
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 586

_omit rpc data_
DATA;
}

I have used strace command to find the reason:

poll([{fd=5, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=5, revents=POLLIN}])
recvfrom(5, "", 1, MSG_PEEK, NULL, NULL) = 0
write(1, "Resource id #4", 14)          = 14
write(1, "\n", 1)                       = 1
sendto(5, "POST /users/api.php HTTP/1.1\r\nHo"..., 860, MSG_DONTWAIT, NULL, 0) = 860
write(1, "send 860 data", 13)           = 13
write(1, "\n", 1)                       = 1
poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=5, revents=POLLIN|POLLERR|POLLHUP}])
recvfrom(5, "", 8192, MSG_DONTWAIT, NULL, NULL) = 0
write(1, "Illegal HTTP server.", 20)    = 20

if no memcached used,pfsockopen will reconnect:

poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "", 1, MSG_PEEK, NULL, NULL) = 0
close(4)                                = 0

OK, my php version is:
PHP 5.4.41 (cli) (built: Nov 22 2015 21:42:54)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies
with eAccelerator v1.0-dev, Copyright (c) 2004-2012 eAccelerator, by eAccelerator

And memcached version is:
memcached support => enabled
Version => 2.2.0
libmemcached version => 1.0.18

@lizhibin205 lizhibin205 changed the title When I use memcached, memcached has an bad effect on pfsockopen function When I use memcached, memcached has a bad effect on pfsockopen function Feb 6, 2017
@sodabrew
Copy link
Contributor

sodabrew commented Feb 6, 2017

That is a really interesting bug, thank you for the detailed information.

I don't have a version of PHP 5.4 available to test with. I would ask to confirm that the bug still occurs on PHP 5.6 with memcached extension 2.x, or on PHP 7.x with memcached extension 3.x, to make sure that it remains a current bug. I will try your repro script!

@lizhibin205
Copy link
Author

thank you for your reply
well,I have used PHP5.6.30 to test with, it works normally.

@sodabrew
Copy link
Contributor

sodabrew commented Feb 7, 2017

@lizhibin205 Do you mean that the problem only happens with PHP 5.4 and it is fixed in PHP 5.6?

@lizhibin205
Copy link
Author

yes! And I debug with php5.4.41,I found this:
when using memcached:
main/streams/stream.c:1357

PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
{
	int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;

	if (stream->ops->set_option) {
		ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC);
                //here will return PHP_STREAM_OPTION_RETURN_OK
	}

and then
main/streams/xp_socke.c:293

if (sock->socket == -1) {
    alive = 0;
} else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
    if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) {
        alive = 0;
    }
}

so , I think if last errno equal EWOULDBLOCK ,php will judge that socket is alive.
when no memcached use, errno is equal 115(ENETDOWN)

@lizhibin205
Copy link
Author

anyway,i also review php-5.6.30, php_sockop_set_option function in main/streams/xp_socket.c

if (sock->socket == -1) {
    alive = 0;
} else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
#ifdef PHP_WIN32
    int ret;
#else
    ssize_t ret;
#endif
    int err;

    ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK);
    err = php_socket_errno();
    if (0 == ret || /* the counterpart did properly shutdown*/
        (0 > ret && err != EWOULDBLOCK && err != EAGAIN)) { /* there was an unrecoverable error */
        alive = 0;
    }
}

so , it can explain that this bug won't occour in php5.6. when revc return 0 ,php will judge that socket is die

@sodabrew
Copy link
Contributor

Excellent debugging! But do you think there is anything to fix in memcached, or is this a PHP problem only? Since PHP 5.4 is not supported anymore, is it OK to close this bug and to recommend that everyone must upgrade their PHP if they see this problem?

@lizhibin205
Copy link
Author

OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants