Пример #1
0
 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;
     }
 }
Пример #2
0
 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);
 }
Пример #3
0
 protected function connectSocket(Uri $uri) : Awaitable
 {
     return new Coroutine(function () {
         list($a, $b) = Socket::createPair();
         $this->socket = new SocketStream($b);
         return new SocketStream($a);
     });
 }
Пример #4
0
 /**
  * {@inheritdoc}
  */
 public function close()
 {
     if ($this->socket !== null) {
         try {
             $this->reader->dispose();
             Socket::shutdown($this->socket);
         } finally {
             $this->socket = null;
         }
     }
 }
Пример #5
0
 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);
     }
 }
Пример #6
0
 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);
 }
Пример #7
0
 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;
 }
Пример #8
0
 /**
  * {@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)));
     });
 }
Пример #9
0
 /**
  * {@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);
     }
 }
Пример #10
0
 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;
 }
Пример #11
0
 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];
 }
Пример #12
0
 /**
  * {@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);
 }
Пример #13
0
 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');
 }
Пример #14
0
 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);
         }
     }
 }
Пример #15
0
 /**
  * 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)));
 }