Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added NetworkStream, plus some forward compatibility stuff.

  • Loading branch information...
commit b7c234be3cce86e6397ad96071ee349af8faaaad 1 parent 70ba257
@boenrobot boenrobot authored
View
7 RELEASE-1.0.0a2
@@ -1,8 +1,11 @@
Lots of reorganization and initial test suite.
-* Added test suite with nearly complete code coverage.
-* Added FilterCollection, in turn allowing for the same filter to be applied more than once.
* Renamed all "Socket*Transmitter" classes to "Tcp*".
+* Added test suite with nearly complete code coverage. Remaining coverage is due to forward compatibility issues.
+* Added FilterCollection, in turn allowing for the same filter to be applied more than once.
+* Added NetworkStream, and made Tpc* classes inherit from it. This new class contains a new method called shutdown().
+* IPv6 addresses must now be written literally, without the surrounding "[" and "]".
+* TcpServerConnection can now accept IPv6 connections.
* Merged sendStream() into send().
* Removed redundant error variables in TcpServerConnection.
* Removed the TcpServerConnection::isServer() function (can't tell apart server and client).
View
83 src/PEAR2/Net/Transmitter/NetworkStream.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * ~~summary~~
+ *
+ * ~~description~~
+ *
+ * PHP version 5
+ *
+ * @category Net
+ * @package PEAR2_Net_Transmitter
+ * @author Vasil Rangelov <boen.robot@gmail.com>
+ * @copyright 2011 Vasil Rangelov
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
+ * @version SVN: $WCREV$
+ * @link http://pear2.php.net/PEAR2_Net_Transmitter
+ */
+/**
+ * The namespace declaration.
+ */
+namespace PEAR2\Net\Transmitter;
+
+/**
+ * A network transmitter.
+ *
+ * This is a convinience wrapper for network streams. Used to ensure data
+ * integrity.
+ *
+ * @category Net
+ * @package PEAR2_Net_Transmitter
+ * @author Vasil Rangelov <boen.robot@gmail.com>
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
+ * @link http://pear2.php.net/PEAR2_Net_Transmitter
+ */
+class NetworkStream extends Stream
+{
+
+ /**
+ * Checks whether there is data to be read from the socket.
+ *
+ * @return bool TRUE if there is data to be read, FALSE otherwise.
+ */
+ public function isDataAwaiting()
+ {
+ if (parent::isDataAwaiting()) {
+ $meta = stream_get_meta_data($this->stream);
+ return!$meta['timed_out'] && !$meta['eof'];
+ }
+ return false;
+ }
+
+ public function setBuffer($size, $direction = self::DIRECTION_ALL)
+ {
+ $result = parent::setBuffer($size, $direction);
+ if (self::DIRECTION_SEND === $direction
+ && function_exists('stream_set_chunk_size') && !$result
+ ) {
+ return is_int(stream_set_chunk_size($this->stream, $size));
+ }
+ return $result;
+ }
+
+ /**
+ * Shutdown a full-duplex connection
+ *
+ * Shutdowns (partially or not) a full-duplex connection.
+ *
+ * @param string $direction The direction for which to disable further
+ * communications.
+ *
+ * @return bool TRUE on success, FALSE on failure.
+ */
+ public function shutdown($direction = self::DIRECTION_ALL)
+ {
+ $directionMap = array(
+ self::DIRECTION_ALL => STREAM_SHUT_RDWR,
+ self::DIRECTION_SEND => STREAM_SHUT_WR,
+ self::DIRECTION_RECEIVE => STREAM_SHUT_RD
+ );
+ return array_key_exists($direction, $directionMap)
+ && stream_socket_shutdown($this->stream, $directionMap[$direction]);
+ }
+}
View
8 src/PEAR2/Net/Transmitter/Stream.php
@@ -142,8 +142,8 @@ public function setBuffer($size, $direction = self::DIRECTION_ALL)
case self::DIRECTION_RECEIVE:
return stream_set_read_buffer($this->stream, $size) === 0;
case self::DIRECTION_ALL:
- return stream_set_read_buffer($this->stream, $size) === 0
- && stream_set_write_buffer($this->stream, $size) === 0;
+ return $this->setBuffer($size, self::DIRECTION_RECEIVE)
+ && $this->setBuffer($size, self::DIRECTION_SEND);
}
return false;
}
@@ -222,7 +222,7 @@ public function send($contents)
$bytes += $bytesNow;
} else {
throw $this->createException(
- 'Failed while sending stream.', 3
+ 'Failed while sending stream.', 2
);
}
}
@@ -240,7 +240,7 @@ public function send($contents)
$bytes += $bytesNow;
} else {
throw $this->createException(
- 'Failed while sending string.', 2
+ 'Failed while sending string.', 3
);
}
}
View
19 src/PEAR2/Net/Transmitter/TcpClient.php
@@ -32,7 +32,7 @@
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
-class TcpClient extends Stream
+class TcpClient extends NetworkStream
{
/**
@@ -60,6 +60,9 @@ class TcpClient extends Stream
public function __construct($host, $port, $persist = false,
$timeout = null, $key = '', $context = null
) {
+ if (strpos($host, ':') !== false) {
+ $host = "[{$host}]";
+ }
$flags = STREAM_CLIENT_CONNECT;
if ($persist) {
$flags |= STREAM_CLIENT_PERSISTENT;
@@ -92,20 +95,6 @@ public function __construct($host, $port, $persist = false,
}
/**
- * Checks whether there is data to be read from the socket.
- *
- * @return bool TRUE if there is data to be read, FALSE otherwise.
- */
- public function isDataAwaiting()
- {
- if (parent::isDataAwaiting()) {
- $meta = stream_get_meta_data($this->stream);
- return!$meta['timed_out'] && !$meta['eof'];
- }
- return false;
- }
-
- /**
* Creates a new exception.
*
* Creates a new exception. Used by the rest of the functions in this class.
View
30 src/PEAR2/Net/Transmitter/TcpServerConnection.php
@@ -34,7 +34,7 @@
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
-class TcpServerConnection extends Stream
+class TcpServerConnection extends NetworkStream
{
/**
@@ -66,9 +66,17 @@ public function __construct($server, $timeout = null)
parent::__construct(
@stream_socket_accept($server, $timeout, $peername)
);
- $hostPortCombo = explode(':', $peername);
- $this->peerIP = $hostPortCombo[0];
- $this->peerPort = (int) $hostPortCombo[1];
+ $portString = strrchr($peername, ':');
+ $this->peerPort = (int) substr($portString, 1);
+ $ipString = substr(
+ $peername, 0, strlen($peername) - strlen($portString)
+ );
+ if (strpos($ipString, '[') === 0
+ && strpos(strrev($ipString), ']') === 0
+ ) {
+ $ipString = substr($ipString, 1, strlen($ipString) - 2);
+ }
+ $this->peerIP = $ipString;
} catch (Exception $e) {
throw $this->createException('Failed to initialize connection.', 9);
}
@@ -95,20 +103,6 @@ public function getPeerPort()
}
/**
- * Checks whether there is data to be read from the socket.
- *
- * @return bool TRUE if there is data to be read, FALSE otherwise.
- */
- public function isDataAwaiting()
- {
- if (parent::isDataAwaiting()) {
- $meta = stream_get_meta_data($this->stream);
- return!$meta['timed_out'] && !$meta['eof'];
- }
- return false;
- }
-
- /**
* Creates a new exception.
*
* Creates a new exception. Used by the rest of the functions in this class.
View
22 tests/ClientTest.php
@@ -148,8 +148,9 @@ public function testClientSendingIncompleteData()
$contents = str_repeat('7', $size);
try {
$this->client->send($contents);
+ $this->fail('Sending had to fail.');
} catch(SocketException $e) {
- $this->assertEquals(2, $e->getCode(), 'Improper exception code.');
+ $this->assertEquals(3, $e->getCode(), 'Improper exception code.');
}
}
@@ -161,8 +162,9 @@ public function testClientSendingIncompleteDataStream()
rewind($stream);
try {
$this->client->send($stream);
+ $this->fail('Sending had to fail.');
} catch(SocketException $e) {
- $this->assertEquals(3, $e->getCode(), 'Improper exception code.');
+ $this->assertEquals(2, $e->getCode(), 'Improper exception code.');
}
}
@@ -170,7 +172,6 @@ public function testClientTimingOut()
{
$this->assertEquals('999', $this->client->receive(3));
$this->client->setTimeout(2);
- //$this->client->setChunk(1);
try {
$this->client->receive(30);
$this->fail('Second receiving had to fail.');
@@ -183,7 +184,6 @@ public function testClientTimingOutStream()
{
$this->assertEquals('aaa', $this->client->receive(3));
$this->client->setTimeout(2);
- //$this->client->setChunk(1);
try {
$this->client->receiveStream(30);
$this->fail('Second receiving had to fail.');
@@ -262,4 +262,18 @@ public function testSetChunk()
$this->client->getChunk()
);
}
+
+ public function testShutdown()
+ {
+ $this->client->send('bbb');
+ $this->assertEquals('bbb', $this->client->receive(3));
+ $this->assertFalse($this->client->shutdown('undefined direction'));
+ $this->assertTrue($this->client->shutdown(Stream::DIRECTION_SEND));
+ try {
+ $this->client->send('b');
+ $this->fail('Sending had to fail.');
+ } catch(SocketException $e) {
+ $this->assertEquals(3, $e->getCode(), 'Improper exception code.');
+ }
+ }
}
View
18 tests/ServerTest.php
@@ -26,8 +26,10 @@ class ServerTest extends \PHPUnit_Framework_TestCase
public static function setUpBeforeClass()
{
+ $hostname = strpos(LOCAL_HOSTNAME, ':') !== false
+ ? '[' . LOCAL_HOSTNAME . ']' : LOCAL_HOSTNAME;
self::$server = stream_socket_server(
- 'tcp://' . LOCAL_HOSTNAME . ':' . LOCAL_PORT,
+ "tcp://{$hostname}:" . LOCAL_PORT,
self::$errorno, self::$errstr
);
}
@@ -260,4 +262,18 @@ public function testSetChunk()
$this->conn->getChunk()
);
}
+
+ public function testShutdown()
+ {
+ $this->assertEquals('bbb', $this->conn->receive(3));
+ $this->conn->send('bbb');
+ $this->assertFalse($this->conn->shutdown('undefined direction'));
+ $this->assertTrue($this->conn->shutdown(Stream::DIRECTION_RECEIVE));
+ try {
+ $this->conn->receive(1);
+ $this->fail('Receiving had to fail.');
+ } catch(SocketException $e) {
+ $this->assertEquals(4, $e->getCode(), 'Improper exception code.');
+ }
+ }
}
View
4 tests/phpunit.xml
@@ -20,12 +20,12 @@
<!--
The hostname and port of secondaryPeer.xml
-->
- <const name="REMOTE_HOSTNAME" value="127.0.0.1" />
+ <const name="REMOTE_HOSTNAME" value="::1" />
<const name="REMOTE_PORT" value="6666" />
<!--
The hostname and port secondaryPeer.xml must use.
-->
- <const name="LOCAL_HOSTNAME" value="127.0.0.1" />
+ <const name="LOCAL_HOSTNAME" value="::1" />
<const name="LOCAL_PORT" value="6667" />
<!--
A hostname which doesn't provide a serive on any port present here.
View
4 tests/secondaryPeer.xml
@@ -20,12 +20,12 @@
<!--
The name and port of phpunit.xml
-->
- <const name="REMOTE_HOSTNAME" value="127.0.0.1" />
+ <const name="REMOTE_HOSTNAME" value="::1" />
<const name="REMOTE_PORT" value="6667" />
<!--
The name and port phpunit.xml must use.
-->
- <const name="LOCAL_HOSTNAME" value="127.0.0.1" />
+ <const name="LOCAL_HOSTNAME" value="::1" />
<const name="LOCAL_PORT" value="6666" />
</php>
<testsuites>
Please sign in to comment.
Something went wrong with that request. Please try again.