Skip to content

Commit d84f6e0

Browse files
committed
Backport socket pool fix
Avoids using resource ID of 0 if the socket resource is closed before being cleared from the pool.
1 parent e90cda8 commit d84f6e0

1 file changed

Lines changed: 42 additions & 39 deletions

File tree

‎src/BasicSocketPool.php‎

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,21 @@ public function checkout(string $uri, CancellationToken $token = null): Promise
5151
return $this->checkoutNewSocket($uri, $token);
5252
}
5353

54-
foreach ($this->sockets[$uri] as $socketId => $socket) {
55-
if (!$socket->isAvailable) {
54+
foreach ($this->sockets[$uri] as $socketId => $struct) {
55+
if (!$struct->isAvailable) {
5656
continue;
57-
} elseif (!\is_resource($socket->resource) || \feof($socket->resource)) {
58-
$this->clear(new ClientSocket($socket->resource));
57+
} elseif (!\is_resource($struct->resource) || \feof($struct->resource)) {
58+
$this->clear($struct->socket);
5959
continue;
6060
}
6161

62-
$socket->isAvailable = false;
62+
$struct->isAvailable = false;
6363

64-
if ($socket->idleWatcher !== null) {
65-
Loop::disable($socket->idleWatcher);
64+
if ($struct->idleWatcher !== null) {
65+
Loop::disable($struct->idleWatcher);
6666
}
6767

68-
return new Success(new ClientSocket($socket->resource));
68+
return new Success($struct->socket);
6969
}
7070

7171
return $this->checkoutNewSocket($uri, $token);
@@ -76,58 +76,61 @@ private function checkoutNewSocket(string $uri, CancellationToken $token = null)
7676
$this->pendingCount[$uri] = ($this->pendingCount[$uri] ?? 0) + 1;
7777

7878
try {
79-
/** @var ClientSocket $rawSocket */
80-
$rawSocket = yield connect($uri, $this->socketContext, $token);
79+
/** @var ClientSocket $socket */
80+
$socket = yield connect($uri, $this->socketContext, $token);
8181
} finally {
8282
if (--$this->pendingCount[$uri] === 0) {
8383
unset($this->pendingCount[$uri]);
8484
}
8585
}
8686

87-
$socketId = (int) $rawSocket->getResource();
87+
$socketId = (int) $socket->getResource();
8888

89-
$socket = new class {
89+
$struct = new class {
9090
use Struct;
9191

9292
public $id;
9393
public $uri;
9494
public $resource;
9595
public $isAvailable;
96+
public $socket;
9697
public $idleWatcher;
9798
};
9899

99-
$socket->id = $socketId;
100-
$socket->uri = $uri;
101-
$socket->resource = $rawSocket->getResource();
102-
$socket->isAvailable = false;
100+
$struct->id = $socketId;
101+
$struct->uri = $uri;
102+
$struct->resource = $socket->getResource();
103+
$struct->isAvailable = false;
104+
$struct->socket = $socket;
103105

104-
$this->sockets[$uri][$socketId] = $socket;
105-
$this->socketIdUriMap[$socketId] = $uri;
106+
$hash = \spl_object_hash($socket);
107+
$this->sockets[$uri][$hash] = $struct;
108+
$this->socketIdUriMap[$hash] = $uri;
106109

107-
return $rawSocket;
110+
return $socket;
108111
});
109112
}
110113

111114
/** @inheritdoc */
112115
public function clear(ClientSocket $socket) {
113-
$socketId = (int) $socket->getResource();
116+
$hash = \spl_object_hash($socket);
114117

115-
if (!isset($this->socketIdUriMap[$socketId])) {
118+
if (!isset($this->socketIdUriMap[$hash])) {
116119
throw new \Error(
117-
sprintf('Unknown socket: %d', $socketId)
120+
sprintf('Unknown socket: %d', $hash)
118121
);
119122
}
120123

121-
$uri = $this->socketIdUriMap[$socketId];
122-
$socket = $this->sockets[$uri][$socketId];
124+
$uri = $this->socketIdUriMap[$hash];
125+
$struct = $this->sockets[$uri][$hash];
123126

124-
if ($socket->idleWatcher) {
125-
Loop::cancel($socket->idleWatcher);
127+
if ($struct->idleWatcher) {
128+
Loop::cancel($struct->idleWatcher);
126129
}
127130

128131
unset(
129-
$this->sockets[$uri][$socketId],
130-
$this->socketIdUriMap[$socketId]
132+
$this->sockets[$uri][$hash],
133+
$this->socketIdUriMap[$hash]
131134
);
132135

133136
if (empty($this->sockets[$uri])) {
@@ -137,32 +140,32 @@ public function clear(ClientSocket $socket) {
137140

138141
/** @inheritdoc */
139142
public function checkin(ClientSocket $socket) {
140-
$socketId = (int) $socket->getResource();
143+
$hash = \spl_object_hash($socket);
141144

142-
if (!isset($this->socketIdUriMap[$socketId])) {
145+
if (!isset($this->socketIdUriMap[$hash])) {
143146
throw new \Error(
144-
\sprintf('Unknown socket: %d', $socketId)
147+
\sprintf('Unknown socket: %d', $hash)
145148
);
146149
}
147150

148-
$uri = $this->socketIdUriMap[$socketId];
151+
$uri = $this->socketIdUriMap[$hash];
149152

150153
if (!\is_resource($socket->getResource()) || \feof($socket->getResource())) {
151154
$this->clear($socket);
152155
return;
153156
}
154157

155-
$socket = $this->sockets[$uri][$socketId];
156-
$socket->isAvailable = true;
158+
$struct = $this->sockets[$uri][$hash];
159+
$struct->isAvailable = true;
157160

158-
if (isset($socket->idleWatcher)) {
159-
Loop::enable($socket->idleWatcher);
161+
if (isset($struct->idleWatcher)) {
162+
Loop::enable($struct->idleWatcher);
160163
} else {
161-
$socket->idleWatcher = Loop::delay($this->idleTimeout, function () use ($socket) {
162-
$this->clear(new ClientSocket($socket->resource));
164+
$struct->idleWatcher = Loop::delay($this->idleTimeout, function () use ($struct) {
165+
$this->clear($struct->socket);
163166
});
164167

165-
Loop::unreference($socket->idleWatcher);
168+
Loop::unreference($struct->idleWatcher);
166169
}
167170
}
168171
}

0 commit comments

Comments
 (0)