protected function connectToAddress(string $address, float $timeout, bool $encrypt) { $url = \sprintf('%s://%s', $this->protocol, $address); $errno = null; $errstr = null; $context = \stream_context_create(\array_replace_recursive($this->options, ['socket' => ['connect' => $address]])); $socket = @\stream_socket_client($url, $errno, $errstr, $timeout ?: null, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT, $context); if (!\is_resource($socket)) { throw new SocketException(\sprintf('Could not connect to "%s" (%s): [%s] %s', $url, $this->peer, $errno, \trim($errstr))); } try { \stream_set_blocking($socket, false); \stream_set_read_buffer($socket, 0); \stream_set_write_buffer($socket, 0); if ($this->tcpNoDelay) { Socket::setTcpNoDelay($socket, true); } if ($encrypt) { yield from $this->encryptSocketClient($socket, $timeout); } else { (yield new AwaitWrite($socket, $timeout)); } return $socket; } catch (\Throwable $e) { Socket::shutdown($socket); throw $e; } }
public function __construct($source, $destination, bool $closeSource = true, int $length = null, int $chunkSize = 4096, callable $transform = null) { $this->transform = $transform; if ($source instanceof ReadableStream) { $channel = $source->channel($chunkSize, $length); } elseif (!\is_resource($source)) { throw new \InvalidArgumentException(\sprintf('Expecting streamable source, given %s', \is_object($source) ? \get_class($source) : \gettype($source))); } else { $channel = $this->createSocketChannel($source, $chunkSize, $length); } if ($destination instanceof WritableStream) { $writer = $this->streamWriter($destination, $channel, $transform); } elseif (!\is_resource($destination)) { $channel->close(); throw new \InvalidArgumentException(\sprintf('Expecting streamable destination, given %s', \is_object($destination) ? \get_class($destination) : \gettype($destination))); } else { $writer = $this->socketWriter($destination, $channel, $transform); } $this->copy = new Coroutine($writer); if ($closeSource) { $this->copy->when(function () use($source) { if (\is_resource($source)) { Socket::shutdown($source); } else { $source->close(); } }); } $this->resolve($this->copy); }
protected function connectSocket(Uri $uri) : Awaitable { return new Coroutine(function () { list($a, $b) = Socket::createPair(); $this->socket = new SocketStream($b); return new SocketStream($a); }); }
/** * {@inheritdoc} */ public function close() { if ($this->socket !== null) { try { $this->reader->dispose(); Socket::shutdown($this->socket); } finally { $this->socket = null; } } }
protected function runServer($socket, callable $server) : \Generator { try { $result = $server($socket); if ($result instanceof \Generator) { $result = (yield from $result); } return $result; } finally { Socket::shutdown($socket); } }
public static function create(string $bootstrap, int $workerCount = null) : ProcessManager { if (Socket::isUnixSocketSupported()) { $url = \sprintf('unix://%s/k1_ipc_%s.sock', \sys_get_temp_dir(), \md5((string) \microtime(true))); } else { $port = Socket::findUnusedPort('tcp', '127.0.0.1'); $url = \sprintf('tcp://127.0.0.1:%u', $port); } $errno = null; $errstr = null; $server = @\stream_socket_server($url, $errno, $errstr, \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN); if ($server === false) { throw new \RuntimeException(\sprintf('Failed to create IPC server "%s" [%s]: "%s"', $url, $errno, $errstr)); } return new static($url, $server, $bootstrap, $workerCount); }
protected function socketReader($socket) : \Generator { $reader = new SocketReader($socket); $remaining = $this->length ?? \PHP_INT_MAX; $contents = ''; try { while ($remaining && null !== ($chunk = (yield $reader->read($remaining)))) { $contents .= $chunk; $remaining -= \strlen($chunk); } } finally { $reader->dispose(); if ($this->closeSource) { Socket::shutdown($socket); } } return $contents; }
/** * {@inheritdoc} */ public function listen(callable $action) : Awaitable { return new Coroutine(function () use($action) { $factory = clone $this->factory; $factory->setTcpNoDelay(true); if ($factory->isEncrypted() && Socket::isAlpnSupported()) { $protocols = []; foreach ($this->drivers as $driver) { foreach ($driver->getProtocols() as $protocol) { $protocols[$protocol] = true; } } $factory->setOption('ssl', 'alpn_protocols', implode(',', \array_keys($protocols))); } $this->server = (yield $factory->createSocketServer()); $port = $this->server->getPort(); $peer = $this->server->getAddress() . ($port ? ':' . $port : ''); $context = new HttpDriverContext($peer, $factory->getPeerName(), $factory->isEncrypted(), $this->middlewares, $this->responders, $this->proxySettings); return new HttpServer($this, $this->server, new Coroutine($this->runServer($context, $action))); }); }
/** * {@inheritdoc} */ protected function spawnWorker() : Awaitable { if (self::$sharedWorkers === null) { self::$sharedWorkers = []; \register_shutdown_function(function () { self::shutdownPool(); }); } $index = self::$allocated++ % self::getMaxSize(); if (isset(self::$sharedWorkers[$index])) { return new Success(self::$sharedWorkers[$index]); } try { list($a, $b) = Socket::createPair(); $thread = new Thread($b, self::getComposerAutoloader()); $thread->start(\PTHREADS_INHERIT_INI); return new Success(self::$sharedWorkers[$index] = new ThreadWorker($index, $a, $thread)); } catch (\Throwable $e) { self::$allocated--; return new Failure($e); } }
public static function connect(string $dsn, string $username, string $password, LoggerInterface $logger = NULL) : \Generator { if ('mysql:' !== substr($dsn, 0, 6)) { throw new \InvalidArgumentException(sprintf('Invalid MySQL DSN: "%s"', $dsn)); } $settings = []; foreach (explode(';', substr($dsn, 6)) as $part) { list($k, $v) = array_map('trim', explode('=', $part)); switch ($k) { case 'host': case 'dbname': case 'unix_socket': $settings[$k] = $v; break; case 'port': $settings[$k] = (int) $v; break; default: throw new \InvalidArgumentException(sprintf('Unknown MySQL DSN param: "%s"', $k)); } } if (empty($settings['host']) && empty($settings['unix_socket'])) { throw new \InvalidArgumentException('Neighter MySQL host nor Unix domain socket specified in MySQL DSN'); } if (!empty($settings['unix_socket'])) { if (!Socket::isUnixSocketSupported()) { throw new \RuntimeException(sprintf('Cannot connect to MySQL socket "%s", PHP was not compiled with support for Unix domain sockets', $settings['unix_socket'])); } $client = new Client(yield from SocketStream::fromUrl('unix://' . $settings['unix_socket']), $logger); } else { $client = new Client(yield from SocketStream::connect($settings['host'], $settings['port'] ?? 3306), $logger); } yield from $client->handleHandshake($username, $password); $conn = new static($client, (yield currentExecutor()), $logger); if (!empty($settings['dbname'])) { yield from $conn->changeDefaultSchema($settings['dbname']); } return $conn; }
private static function createServerSocket() : array { if (Socket::isUnixSocketSupported()) { $uri = $connectUri = \sprintf('unix://%s/kk_pool_%s.sock', \sys_get_temp_dir(), \md5((string) \microtime(true))); } else { $uri = 'tcp://127.0.0.1:0'; } $errno = null; $errstr = null; $context = \stream_context_create(['socket' => ['backlog' => 128]]); $server = @\stream_socket_server($uri, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); if ($server === false) { throw new \RuntimeException(\sprintf('Failed to start IPC socket "%s": [%s] %s', $uri, $errno, $errstr)); } if (!isset($connectUri)) { $connectUri = 'tcp://' . \stream_socket_get_name($server, false); } return [$server, $connectUri]; }
/** * {@inheritdoc} */ public function close() : Awaitable { if ($this->socket !== null) { $this->disposeWriter(); $this->disposeReader(); try { Socket::shutdown($this->socket); } finally { $this->socket = null; } } return new Success($this->readBuffer); }
protected function connectSocket(Uri $uri) : Awaitable { $host = $uri->getHost(); if (Address::isResolved($host)) { $factory = new SocketFactory(new Address($host) . ':' . $uri->getPort(), 'tcp'); } else { $factory = new SocketFactory($uri->getHostWithPort(true), 'tcp'); } $factory->setTcpNoDelay(true); if ($this->protocols && Socket::isAlpnSupported()) { $factory->setOption('ssl', 'alpn_protocols', \implode(',', $this->protocols)); } return $factory->createSocketStream(5, $uri->getScheme() === 'https'); }
protected function listenLoop(callable $callback, float $timeout) : \Generator { while (true) { try { (yield $this->waiting = new AwaitRead($this->socket)); } finally { $this->waiting = null; } $socket = @\stream_socket_accept($this->socket, 0); if (false !== $socket) { \stream_set_blocking($socket, false); \stream_set_read_buffer($socket, 0); \stream_set_write_buffer($socket, 0); if ($this->tcpNoDelay) { Socket::setTcpNoDelay($socket, true); } // Offload handling the client to another coroutine keeping the listen loop running. new Coroutine($this->handleClient($callback, $socket, $timeout), true); } } }
/** * Create a transport that is used to read / write DNS messages. * * @param string $server * @return Transport */ protected function createTransport(string $server) : \Generator { return $this->transport !== null ? clone $this->transport : new SocketTransport((yield Socket::connectClient('udp://' . $server))); }