-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathStreamEncryption.php
More file actions
97 lines (78 loc) · 2.63 KB
/
StreamEncryption.php
File metadata and controls
97 lines (78 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php
namespace React\SocketClient;
use React\Promise\ResolverInterface;
use React\Promise\Deferred;
use React\Stream\Stream;
use React\EventLoop\LoopInterface;
use UnexpectedValueException;
/**
* This class is considered internal and its API should not be relied upon
* outside of SocketClient
*/
class StreamEncryption
{
private $loop;
private $method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
private $errstr;
private $errno;
public function __construct(LoopInterface $loop)
{
$this->loop = $loop;
}
public function enable(Stream $stream)
{
return $this->toggle($stream, true);
}
public function disable(Stream $stream)
{
return $this->toggle($stream, false);
}
public function toggle(Stream $stream, $toggle)
{
// pause actual stream instance to continue operation on raw stream socket
$stream->pause();
// TODO: add write() event to make sure we're not sending any excessive data
$deferred = new Deferred();
// get actual stream socket from stream instance
$socket = $stream->stream;
$that = $this;
$toggleCrypto = function () use ($that, $socket, $deferred, $toggle) {
$that->toggleCrypto($socket, $deferred, $toggle);
};
$this->loop->addWriteStream($socket, $toggleCrypto);
$this->loop->addReadStream($socket, $toggleCrypto);
$toggleCrypto();
return $deferred->then(function () use ($stream) {
$stream->resume();
return $stream;
}, function($error) use ($stream) {
$stream->resume();
throw $error;
});
}
public function toggleCrypto($socket, ResolverInterface $resolver, $toggle)
{
set_error_handler(array($this, 'handleError'));
$result = stream_socket_enable_crypto($socket, $toggle, $this->method);
restore_error_handler();
if (true === $result) {
$this->loop->removeWriteStream($socket);
$this->loop->removeReadStream($socket);
$resolver->resolve();
} else if (false === $result) {
$this->loop->removeWriteStream($socket);
$this->loop->removeReadStream($socket);
$resolver->reject(new UnexpectedValueException(
sprintf("Unable to complete SSL/TLS handshake: %s", $this->errstr),
$this->errno
));
} else {
// need more data, will retry
}
}
public function handleError($errno, $errstr)
{
$this->errstr = str_replace(array("\r", "\n"), ' ', $errstr);
$this->errno = $errno;
}
}