setSocket($socket); $socket = $this->getSocket(); if ($flag == -1) { switch ($socket->getTransport()) { case 'tcp': $flag = self::BIND | self::LISTEN; break; case 'udp': $flag = self::BIND; break; } } else { switch ($socket->getTransport()) { case 'tcp': $flag |= self::LISTEN; break; case 'udp': if ($flag & self::LISTEN) { throw new Exception( 'Cannot use the flag ' . '\Hoa\Socket\Server::LISTEN ' . 'for connect-less transports (such as UDP).', 0 ); } $flag = self::BIND; break; } } parent::__construct(null, $timeout, $flag, $context); return; } /** * Open the stream and return the associated resource. * * @param string $streamName Socket URI. * @param \Hoa\Stream\Context $context Context. * @return resource * @throws \Hoa\Socket\Exception */ protected function &_open($streamName, Stream\Context $context = null) { if (null === $context) { $this->_master = @stream_socket_server( $streamName, $errno, $errstr, $this->getFlag() ); } else { $this->_master = @stream_socket_server( $streamName, $errno, $errstr, $this->getFlag(), $context->getContext() ); } if (false === $this->_master) { throw new Exception( 'Server cannot join %s and returns an error (number %d): %s.', 1, [$streamName, $errno, $errstr] ); } $i = count($this->_masters); $this->_masters[$i] = $this->_master; $this->_servers[$i] = $this; $this->_stack[] = $this->_masters[$i]; return $this->_master; } /** * Close the current stream. * * @return bool */ protected function _close() { $current = $this->getStream(); if (false === in_array($current, $this->getMasters(), true)) { $stack = &$this->getStack(); $i = array_search($current, $stack); if (false !== $i) { unset($stack[$i]); } // $this->_node is voluntary kept in memory until a new node will be // used. unset($this->_nodes[$this->getNodeId($current)]); @fclose($current); // Closing slave does not have the same effect that closing master. return false; } return (bool) (@fclose($this->_master) + @fclose($this->getStream())); } /** * Connect and accept the first connection. * * @return \Hoa\Socket\Server * @throws \Hoa\Socket\Exception */ public function connect() { parent::connect(); $client = @stream_socket_accept($this->_master); if (false === $client) { throw new Exception( 'Operation timed out (nothing to accept).', 2 ); } $this->_setStream($client); return $this; } /** * Connect but wait for select and accept new connections. * * @return \Hoa\Socket\Server */ public function connectAndWait() { return parent::connect(); } /** * Select connections. * * @return \Hoa\Socket\Server * @throws \Hoa\Socket\Exception */ public function select() { $read = $this->getStack(); $write = null; $except = null; @stream_select($read, $write, $except, $this->getTimeout(), 0); foreach ($read as $socket) { $masters = $this->getMasters(); if (true === in_array($socket, $masters, true)) { $client = @stream_socket_accept($socket); if (false === $client) { throw new Exception( 'Operation timed out (nothing to accept).', 3 ); } $m = array_search($socket, $masters, true); $server = $this->_servers[$m]; $id = $this->getNodeId($client); $node = Consistency\Autoloader::dnew( $server->getNodeName(), [$id, $client, $server] ); $this->_nodes[$id] = $node; $this->_stack[] = $client; } else { $this->_iterator[] = $socket; } } return $this; } /** * Consider another server when selecting connection. * * @param \Hoa\Socket\Connection $other Other server. * @return \Hoa\Socket\Server */ public function consider(Connection $other) { if ($other instanceof Client) { if (true === $other->isDisconnected()) { $other->connect(); } $this->_stack[] = $other->getStream(); return $this; } if (true === $other->isDisconnected()) { $other->connectAndWait(); } $i = count($this->_masters); $this->_masters[$i] = $other->_master; $this->_servers[$i] = $other; $this->_stack[] = $this->_masters[$i]; return $this; } /** * Check if the current node belongs to a specific server. * * @param \Hoa\Socket\Connection $server Server. * @return bool */ public function is(Connection $server) { return $this->getCurrentNode()->getConnection() === $server; } /** * Set and get the current selected connection. * * @return \Hoa\Socket\Node */ public function current() { $current = parent::_current(); $id = $this->getNodeId($current); if (!isset($this->_nodes[$id])) { return $current; } return $this->_node = $this->_nodes[$this->getNodeId($current)]; } /** * Check if the server bind or not. * * @return bool */ public function isBinding() { return (bool) ($this->getFlag() & self::BIND); } /** * Check if the server is listening or not. * * @return bool */ public function isListening() { return (bool) ($this->getFlag() & self::LISTEN); } /** * Return internal considered servers. * * @return array */ protected function getServers() { return $this->_servers; } /** * Return internal master connections. * * @return array */ protected function getMasters() { return $this->_masters; } /** * Return internal node stack. * * @return array */ protected function &getStack() { return $this->_stack; } }