Hoa central
Server.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Socket;
38 
39 use Hoa\Stream;
40 
49 class Server extends Connection
50 {
56  const BIND = STREAM_SERVER_BIND;
57 
63  const LISTEN = STREAM_SERVER_LISTEN;
64 
70  const ENCRYPTION_SSLv2 = STREAM_CRYPTO_METHOD_SSLv2_SERVER;
71 
77  const ENCRYPTION_SSLv3 = STREAM_CRYPTO_METHOD_SSLv3_SERVER;
78 
84  const ENCRYPTION_SSLv23 = STREAM_CRYPTO_METHOD_SSLv23_SERVER;
85 
91  const ENCRYPTION_TLS = STREAM_CRYPTO_METHOD_TLS_SERVER;
92 
98  protected $_master = null;
99 
105  protected $_servers = [];
106 
112  protected $_masters = [];
113 
119  protected $_stack = [];
120 
121 
122 
133  public function __construct(
134  $socket,
135  $timeout = 30,
136  $flag = -1,
137  $context = null
138  ) {
139  $this->setSocket($socket);
140  $socket = $this->getSocket();
141 
142  if ($flag == -1) {
143  switch ($socket->getTransport()) {
144  case 'tcp':
145  $flag = self::BIND | self::LISTEN;
146 
147  break;
148 
149  case 'udp':
150  $flag = self::BIND;
151 
152  break;
153  }
154  } else {
155  switch ($socket->getTransport()) {
156  case 'tcp':
157  $flag &= self::LISTEN;
158 
159  break;
160 
161  case 'udp':
162  if ($flag & self::LISTEN) {
163  throw new Exception(
164  'Cannot use the flag ' .
165  '\Hoa\Socket\Server::LISTEN ' .
166  'for connect-less transports (such as UDP).',
167  0
168  );
169  }
170 
171  $flag = self::BIND;
172 
173  break;
174  }
175  }
176 
177  parent::__construct(null, $timeout, $flag, $context);
178 
179  return;
180  }
181 
190  protected function &_open($streamName, Stream\Context $context = null)
191  {
192  if (null === $context) {
193  $this->_master = @stream_socket_server(
194  $streamName,
195  $errno,
196  $errstr,
197  $this->getFlag()
198  );
199  } else {
200  $this->_master = @stream_socket_server(
201  $streamName,
202  $errno,
203  $errstr,
204  $this->getFlag(),
205  $context->getContext()
206  );
207  }
208 
209  if (false === $this->_master) {
210  throw new Exception(
211  'Server cannot join %s and returns an error (number %d): %s.',
212  1,
213  [$streamName, $errno, $errstr]
214  );
215  }
216 
217  $i = count($this->_masters);
218  $this->_masters[$i] = $this->_master;
219  $this->_servers[$i] = $this;
220  $this->_stack[] = $this->_masters[$i];
221 
222  return $this->_master;
223  }
224 
230  protected function _close()
231  {
232  $current = $this->getStream();
233 
234  if (false === in_array($current, $this->_masters, true)) {
235  $i = array_search($current, $this->_stack);
236 
237  if (false !== $i) {
238  unset($this->_stack[$i]);
239  }
240 
241  // $this->_node is voluntary kept in memory until a new node will be
242  // used.
243 
244  unset($this->_nodes[$this->getNodeId($current)]);
245 
246  @fclose($current);
247 
248  // Closing slave does not have the same effect that closing master.
249  return false;
250  }
251 
252  return (bool) (@fclose($this->_master) + @fclose($this->getStream()));
253  }
254 
261  public function connect()
262  {
263  parent::connect();
264 
265  $client = @stream_socket_accept($this->_master);
266 
267  if (false === $client) {
268  throw new Exception(
269  'Operation timed out (nothing to accept).',
270  2
271  );
272  }
273 
274  $this->_setStream($client);
275 
276  return $this;
277  }
278 
284  public function connectAndWait()
285  {
286  return parent::connect();
287  }
288 
295  public function select()
296  {
297  $read = $this->_stack;
298  $write = null;
299  $except = null;
300 
301  @stream_select($read, $write, $except, $this->getTimeout(), 0);
302 
303  foreach ($read as $socket) {
304  if (true === in_array($socket, $this->_masters, true)) {
305  $client = @stream_socket_accept($socket);
306 
307  if (false === $client) {
308  throw new Exception(
309  'Operation timed out (nothing to accept).',
310  3
311  );
312  }
313 
314  $m = array_search($socket, $this->_masters, true);
315  $server = $this->_servers[$m];
316  $id = $this->getNodeId($client);
317  $node = dnew(
318  $server->getNodeName(),
319  [$id, $client, $server]
320  );
321  $this->_nodes[$id] = $node;
322  $this->_stack[] = $client;
323  } else {
324  $this->_iterator[] = $socket;
325  }
326  }
327 
328  return $this;
329  }
330 
337  public function consider(Connection $other)
338  {
339  if ($other instanceof Client) {
340  if (true === $other->isDisconnected()) {
341  $other->connect();
342  }
343 
344  $this->_stack[] = $other->getStream();
345 
346  return $this;
347  }
348 
349  if (true === $other->isDisconnected()) {
350  $other->connectAndWait();
351  }
352 
353  $i = count($this->_masters);
354  $this->_masters[$i] = $other->_master;
355  $this->_servers[$i] = $other;
356  $this->_stack[] = $this->_masters[$i];
357 
358  return $this;
359  }
360 
367  public function is(Connection $server)
368  {
369  return $this->_node->getConnection() === $server;
370  }
371 
377  public function current()
378  {
379  $current = parent::_current();
380  $id = $this->getNodeId($current);
381 
382  if (!isset($this->_nodes[$id])) {
383  return $current;
384  }
385 
386  return $this->_node = $this->_nodes[$this->getNodeId($current)];
387  }
388 
394  public function isBinding()
395  {
396  return (bool) $this->getFlag() & self::BIND;
397  }
398 
404  public function isListening()
405  {
406  return (bool) $this->getFlag() & self::LISTEN;
407  }
408 }
__construct($socket, $timeout=30, $flag=-1, $context=null)
Definition: Server.php:133
is(Connection $server)
Definition: Server.php:367
const ENCRYPTION_SSLv3
Definition: Server.php:77
& _open($streamName, Stream\Context $context=null)
Definition: Server.php:190
const ENCRYPTION_SSLv2
Definition: Server.php:70
const ENCRYPTION_TLS
Definition: Server.php:91
consider(Connection $other)
Definition: Server.php:337
const ENCRYPTION_SSLv23
Definition: Server.php:84