private function acquireCommand(React\Socket\Connection $connection, $name) { if (isset($this->locks[$name])) { if (isset($this->connections[$connection][$name])) { if ($this->connections[$connection][$name]) { $connection->write(self::SUCCESS); return; } else { $connection->write(self::WAIT); return; } } else { $this->locks[$name][] = $connection; $connectionLocks = $this->connections[$connection]; $connectionLocks[$name] = false; $this->connections[$connection] = $connectionLocks; $connection->write(self::WAIT); return; } } else { $this->locks[$name] = new \SplDoublyLinkedList(); $this->locks[$name][] = $connection; $connectionLocks = $this->connections[$connection]; $connectionLocks[$name] = true; $this->connections[$connection] = $connectionLocks; $connection->write(self::SUCCESS); return; } }
/** * Handle process on close transport * * @param \React\Socket\Connection $conn */ public function handleClose(Connection $conn) { Logger::debug($this, "Raw socket closed " . $conn->getRemoteAddress()); $session = $this->sessions[$conn]; $this->sessions->detach($conn); $this->router->getEventDispatcher()->dispatch('connection_close', new ConnectionCloseEvent($session)); }
/** * @covers React\Socket\Connection::end */ public function testEnd() { $socket = fopen('php://temp', 'r+'); $loop = $this->createLoopMock(); $conn = new Connection($socket, $loop); $conn->end(); $this->assertFalse(is_resource($socket)); }
/** * @return Connection */ protected function getConnection() { if ($this->connection) { $this->connection->close(); unset($this->connection); } $client = stream_socket_client($this->getControllerSocket()); $this->connection = new Connection($client, $this->loop); return $this->connection; }
/** * @return \React\Socket\Connection */ protected function getConnection() { if ($this->connection) { $this->connection->close(); unset($this->connection); } $client = stream_socket_client('tcp://127.0.0.1:5500'); $this->connection = new \React\Socket\Connection($client, $this->loop); return $this->connection; }
public function accept(Socket $socket) { if (count($this->connections) >= $this->maxConnections) { $socket->write(['alias' => 'capacity_reached']); $socket->close(); throw new \RuntimeException('Server capacity reached'); } $player = $this->playerFactory->newSocketPlayer(sprintf('PlayerBot%d', ++$this->connectionIndex), null, 5000, $socket); $connection = $player->getConnection(); $this->connections->pushBack($connection); $this->handleSocketEvents($connection); $this->handlePlayerNameChange($connection); $this->handlePlayerConnection($connection); }
/** * Disconnect from server */ public function disconnect() { $this->connected = false; if ($this->socket instanceof Connection) { $this->socket->close(); } }
/** * Connects to ProcessManager, master process. */ public function run() { $this->loop = \React\EventLoop\Factory::create(); $this->errorLogger = BufferingLogger::create(); ErrorHandler::register(new ErrorHandler($this->errorLogger)); $client = stream_socket_client($this->config['controllerHost']); $this->controller = new \React\Socket\Connection($client, $this->loop); $pcntl = new \MKraemer\ReactPCNTL\PCNTL($this->loop); $pcntl->on(SIGTERM, [$this, 'shutdown']); $pcntl->on(SIGINT, [$this, 'shutdown']); register_shutdown_function([$this, 'shutdown']); $this->bindProcessMessage($this->controller); $this->controller->on('close', \Closure::bind(function () { $this->shutdown(); }, $this)); $this->server = new React\Server($this->loop); //our version for now, because of unix socket support $http = new HttpServer($this->server); $http->on('request', array($this, 'onRequest')); //port is only used for tcp connection. If unix socket, 'host' contains the socket path $port = $this->config['port']; $host = $this->config['host']; while (true) { try { $this->server->listen($port, $host); break; } catch (\React\Socket\ConnectionException $e) { usleep(500); } } $this->sendMessage($this->controller, 'register', ['pid' => getmypid(), 'port' => $port]); $this->loop->run(); }
public function bye() { if ($this->connection->isWritable()) { $this->connection->write(json_encode(array('cmd' => 'unregister', 'pid' => getmypid()))); $this->connection->close(); } $this->loop->stop(); }
/** * Apply revoked client connection listeners */ protected function applyListeners() { foreach ($this->listeners as $listenerName => $listeners) { foreach ($listeners as $listener) { $this->conn->on('api-' . $listenerName, $listener); } } $this->listeners = []; }
public function handleData($stream) { if (!$this->secure) { //stream_set_blocking($this->stream, true); $result = stream_socket_enable_crypto($this->stream, true, STREAM_CRYPTO_METHOD_TLS_SERVER); //stream_set_blocking($this->stream, false); if (0 === $result) { return; } if (false === $result) { echo "error\n"; return; } $this->secure = true; $this->emit('connection', array($this)); } parent::handleData($stream); }
/** * Connects to ProcessManager, master process. */ public function run() { $this->loop = \React\EventLoop\Factory::create(); ErrorHandler::register(new ErrorHandler(new BufferingLogger())); $this->client = stream_socket_client('tcp://127.0.0.1:5500'); $this->connection = new \React\Socket\Connection($this->client, $this->loop); $this->connection->on('error', function ($data) { var_dump($data); }); $pcntl = new \MKraemer\ReactPCNTL\PCNTL($this->loop); $pcntl->on(SIGTERM, [$this, 'shutdown']); $pcntl->on(SIGINT, [$this, 'shutdown']); register_shutdown_function([$this, 'shutdown']); $this->bindProcessMessage($this->connection); $this->connection->on('close', \Closure::bind(function () { $this->shutdown(); }, $this)); $this->server = new \React\Socket\Server($this->loop); $this->server->on('error', function ($data) { var_dump($data); }); $http = new HttpServer($this->server); $http->on('request', array($this, 'onRequest')); $http->on('error', function ($data) { var_dump($data); }); $port = $this->config['port']; while (true) { try { $this->server->listen($port); break; } catch (\React\Socket\ConnectionException $e) { usleep(500); } } $this->sendMessage($this->connection, 'register', ['pid' => getmypid(), 'port' => $port]); $this->loop->run(); }
public function onSlaveConnection(\React\Socket\Connection $conn) { $conn->on('data', \Closure::bind(function ($data) use($conn) { $this->onData($data, $conn); }, $this)); $conn->on('close', \Closure::bind(function () use($conn) { foreach ($this->slaves as $idx => $slave) { if ($slave['connection'] === $conn) { unset($this->slaves[$idx]); $this->checkSlaves(); } } }, $this)); }
/** * A slave sent a `status` command. * * @param array $data * @param Connection $conn */ protected function commandStatus(array $data, Connection $conn) { $conn->end(json_encode('todo')); }
/** * Sends a message through $conn. * * @param Connection $conn * @param string $command * @param array $message */ protected function sendMessage(Connection $conn, $command, array $message = []) { $message['cmd'] = $command; $conn->write(json_encode($message) . PHP_EOL); }
/** * Disconnect client */ public function disconnect() { $this->clientConnection->close(); }
public function __construct($connection, LoopInterface $loop, DatabaseAdapter $database) { $this->connection = $connection; $this->database = $database; parent::__construct($connection->stream, $loop); }
public function __construct($socket, LoopInterface $loop, $logger) { parent::__construct($socket, $loop); $this->_lastChanged = time(); $this->logger = $logger; }
/** * Handles incoming connections from $this->port. Basically redirects to a slave. * * @param Connection $incoming incoming connection from react */ public function onWeb(Connection $incoming) { //preload sent data from $incoming to $buffer, otherwise it would be lost, //since getNextSlave is async. $redirectionActive = false; $connectionOpen = true; $incomingBuffer = ''; $incoming->on('data', function ($data) use(&$redirectionActive, &$incomingBuffer) { if (!$redirectionActive) { $incomingBuffer .= $data; } }); $redirectionTries = 0; $incoming->on('close', function () use(&$redirectionActive, &$redirectionTries, &$connectionOpen) { $connectionOpen = false; }); $start = microtime(true); $redirectionTries++; $redirectRequest = function ($id) use(&$redirectRequest, &$incoming, &$incomingBuffer, &$redirectionActive, $start, &$redirectionTries, &$connectionOpen) { if (!$connectionOpen) { //since the initial connection of a client and getting a free worker the client meanwhile closed the connection, //so stop anything here. return; } if (!is_resource($incoming->stream)) { //Firefox closes somehow a connection directly after opening, at this state we need to check //whether the connection is still alive, to keep going. This check prevents the server from crashing return; } $took = microtime(true) - $start; if ($this->output->isVeryVerbose() && $took > 1) { $this->output->writeln(sprintf('<info>took abnormal %f seconds for choosing next free worker</info>', $took)); } $slave =& $this->slaves[$id]; $slave['busy'] = true; $slave['connections']++; $start = microtime(true); $stream = stream_socket_client($slave['host'], $errno, $errstr, $this->timeout); if (!$stream || !is_resource($stream)) { //we failed to connect to the worker. Maybe because of timeouts or it is in a crashed state //and is currently dieing. //since we don't know whether the worker is only very busy or dieing we just //set it back to available worker list. If it is really dying it will be //removed from the available worker list by itself during connection:close event. $slave['busy'] = false; $slave['connections']--; if ($this->output->isVeryVerbose()) { $this->output->writeln(sprintf('<error>Connection to worker %d failed. Try #%d, took %fs. ' . 'Try increasing your timeout of %d. Error message: [%d] %s</error>', $id, $redirectionTries, microtime(true) - $start, $this->timeout, $errno, $errstr)); } //Try next free client. It's important to do this here due to $incomingBuffer. $redirectionTries++; $this->getNextSlave($redirectRequest); return; } $connection = new \React\Socket\Connection($stream, $this->loop); $took = microtime(true) - $start; if ($this->output->isVeryVerbose() && $took > 1) { $this->output->writeln(sprintf('<info>took abnormal %f seconds for connecting to :%d</info>', $took, $slave['port'])); } $start = microtime(true); $headersToReplace = ['X-PHP-PM-Remote-IP' => $incoming->getRemoteAddress()]; $headerRedirected = false; if ($this->isHeaderEnd($incomingBuffer)) { $incomingBuffer = $this->replaceHeader($incomingBuffer, $headersToReplace); $headerRedirected = true; $connection->write($incomingBuffer); } $redirectionActive = true; $connection->on('close', function () use($incoming, &$slave, $start) { $took = microtime(true) - $start; if ($this->output->isVeryVerbose() && $took > 1) { $this->output->writeln(sprintf('<info>took abnormal %f seconds for handling a connection</info>', $took)); } $slave['busy'] = false; $slave['connections']--; $slave['requests']++; $incoming->end(); /** @var Connection $connection */ $connection = $slave['connection']; if ($slave['requests'] >= $this->maxRequests) { $slave['ready'] = false; $this->output->writeln(sprintf('Restart worker #%d because it reached maxRequests of %d', $slave['port'], $this->maxRequests)); $connection->close(); } else { if ($slave['closeWhenFree']) { $connection->close(); } } }); $connection->on('data', function ($buffer) use($incoming) { $incoming->write($buffer); }); $incoming->on('data', function ($buffer) use($connection, &$incomingBuffer, $headersToReplace, &$headerRedirected) { if (!$headerRedirected) { $incomingBuffer .= $buffer; if ($this->isHeaderEnd($incomingBuffer)) { $incomingBuffer = $this->replaceHeader($incomingBuffer, $headersToReplace); $headerRedirected = true; $connection->write($incomingBuffer); } else { //head has not completely received yet, wait } } else { //incomingBuffer has already been redirected, so redirect now buffer per buffer $connection->write($buffer); } }); $incoming->on('close', function () use($connection) { $connection->close(); }); }; $this->getNextSlave($redirectRequest); }
/** * A slave sent a `register` command. * * @param array $data * @param Connection $conn */ protected function commandRegister(array $data, Connection $conn) { $pid = (int) $data['pid']; $port = (int) $data['port']; if (!isset($this->slaves[$port]) || !$this->slaves[$port]['waitForRegister']) { if ($this->output->isVeryVerbose()) { $this->output->writeln(sprintf('<error>Worker #%d wanted to register on master which was not expected.</error>', $port)); } $conn->close(); return; } $this->ports[spl_object_hash($conn)] = $port; if ($this->output->isVeryVerbose()) { $this->output->writeln(sprintf('Worker #%d registered. Waiting for application bootstrap ... ', $port)); } $this->slaves[$port]['pid'] = $pid; $this->slaves[$port]['connection'] = $conn; $this->slaves[$port]['ready'] = false; $this->slaves[$port]['waitForRegister'] = false; $this->slaves[$port]['duringBootstrap'] = true; $this->sendMessage($conn, 'bootstrap'); }
protected function writeBoard() { $ui = Ui::printStatus($this->game); $this->connection->write($ui); echo $ui; }
protected function serve404Error(SocketConnection $conn) { $response = new Response('file not found.', Response::HTTP_NOT_FOUND); $conn->write($response); $conn->end(); }
/** * Handle process on close transport * * @param \React\Socket\Connection $conn */ public function handleClose(Connection $conn) { Logger::debug($this, "Raw socket closed " . $conn->getRemoteAddress()); $transport = $this->transports[$conn]; $this->transports->detach($conn); $this->peer->onClose($transport); }
/** * Disconnect from server */ public function disconnect() { $this->connected = false; $this->socket->close(); }
/** * Override the base end to add encryption if we're in an encypted stage * * @param $data String the data to write on ending * @Override */ public function end($data = null) { //encrypt the data if needed if ($data !== null && $this->secret !== null) { mcrypt_generic_init($this->encryptor, $this->secret, $this->secret); $data = mcrypt_generic($this->encryptor, $data); mcrypt_generic_deinit($this->encryptor); } parent::end($data); }