- Add code for prevention from IMAP connection hangs when server closes socket unexpectedly

release-0.6
alecpl 13 years ago
parent 4cfe66f42f
commit 3e39818221

@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- Add code for prevention from IMAP connection hangs when server closes socket unexpectedly
- Remove redundant DELETE query (for old session deletion) on login - Remove redundant DELETE query (for old session deletion) on login
- Get around unreliable rand() and mt_rand() in session ID generation (#1486281) - Get around unreliable rand() and mt_rand() in session ID generation (#1486281)
- Fix some emails are not shown using Cyrus IMAP (#1487820) - Fix some emails are not shown using Cyrus IMAP (#1487820)

@ -213,31 +213,26 @@ class rcube_imap_generic
{ {
$line = ''; $line = '';
if (!$this->fp) {
return NULL;
}
if (!$size) { if (!$size) {
$size = 1024; $size = 1024;
} }
do { do {
if (feof($this->fp)) { if ($this->eof()) {
return $line ? $line : NULL; return $line ? $line : NULL;
} }
$buffer = fgets($this->fp, $size); $buffer = fgets($this->fp, $size);
if ($buffer === false) { if ($buffer === false) {
@fclose($this->fp); $this->closeSocket();
$this->fp = null;
break; break;
} }
if ($this->_debug) { if ($this->_debug) {
$this->debug('S: '. rtrim($buffer)); $this->debug('S: '. rtrim($buffer));
} }
$line .= $buffer; $line .= $buffer;
} while ($buffer[strlen($buffer)-1] != "\n"); } while (substr($buffer, -1) != "\n");
return $line; return $line;
} }
@ -267,7 +262,7 @@ class rcube_imap_generic
{ {
$data = ''; $data = '';
$len = 0; $len = 0;
while ($len < $bytes && !feof($this->fp)) while ($len < $bytes && !$this->eof())
{ {
$d = fread($this->fp, $bytes-$len); $d = fread($this->fp, $bytes-$len);
if ($this->_debug) { if ($this->_debug) {
@ -312,8 +307,7 @@ class rcube_imap_generic
} else if ($res == 'BAD') { } else if ($res == 'BAD') {
$this->errornum = self::ERROR_BAD; $this->errornum = self::ERROR_BAD;
} else if ($res == 'BYE') { } else if ($res == 'BYE') {
@fclose($this->fp); $this->closeSocket();
$this->fp = null;
$this->errornum = self::ERROR_BYE; $this->errornum = self::ERROR_BYE;
} }
@ -339,6 +333,32 @@ class rcube_imap_generic
return self::ERROR_UNKNOWN; return self::ERROR_UNKNOWN;
} }
private function eof()
{
if (!is_resource($this->fp)) {
return true;
}
// If a connection opened by fsockopen() wasn't closed
// by the server, feof() will hang.
$start = microtime(true);
if (feof($this->fp) ||
($this->prefs['timeout'] && (microtime(true) - $start > $this->prefs['timeout']))
) {
$this->closeSocket();
return true;
}
return false;
}
private function closeSocket()
{
@fclose($this->fp);
$this->fp = null;
}
function setError($code, $msg='') function setError($code, $msg='')
{ {
$this->errornum = $code; $this->errornum = $code;
@ -360,8 +380,7 @@ class rcube_imap_generic
} }
if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) {
if (strtoupper($m[1]) == 'BYE') { if (strtoupper($m[1]) == 'BYE') {
@fclose($this->fp); $this->closeSocket();
$this->fp = null;
} }
return true; return true;
} }
@ -701,11 +720,12 @@ class rcube_imap_generic
$host = $this->prefs['ssl_mode'] . '://' . $host; $host = $this->prefs['ssl_mode'] . '://' . $host;
} }
if ($this->prefs['timeout'] <= 0) {
$this->prefs['timeout'] = ini_get('default_socket_timeout');
}
// Connect // Connect
if ($this->prefs['timeout'] > 0) $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
$this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
else
$this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr);
if (!$this->fp) { if (!$this->fp) {
$this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
@ -848,8 +868,7 @@ class rcube_imap_generic
$this->readReply(); $this->readReply();
} }
@fclose($this->fp); $this->closeSocket();
$this->fp = false;
} }
/** /**

Loading…
Cancel
Save