Beispiel #1
0
 private function onDeadIpcSock()
 {
     $this->isDead = true;
     $this->writeBuffer = "";
     $this->writeQueue = [];
     \Amp\cancel($this->writeWatcherId);
 }
Beispiel #2
0
 private function succeed()
 {
     $this->promisor->succeed();
     if ($this->writeWatcher) {
         \Amp\cancel($this->writeWatcher);
     }
 }
Beispiel #3
0
 protected function doStart(Console $console) : \Generator
 {
     $server = $this->bootstrapper->boot($this->logger, $console);
     (yield $server->start());
     $this->server = $server;
     \Amp\onReadable($this->ipcSock, function ($watcherId) {
         \Amp\cancel($watcherId);
         yield from $this->stop();
     });
 }
Beispiel #4
0
 private function onDeadIpcSock()
 {
     $this->isDead = true;
     $this->writeBuffer = "";
     $this->writeQueue = [];
     \Amp\cancel($this->writeWatcherId);
     if ($this->stopPromisor) {
         $promisor = $this->stopPromisor;
         $this->stopPromisor = null;
         $promisor->succeed();
     }
 }
Beispiel #5
0
 private function failAll()
 {
     if ($this->writeWatcher !== null) {
         \Amp\cancel($this->writeWatcher);
     }
     $this->sock = $this->writeWatcher = null;
     $promisors = $this->promisors;
     $this->promisors = [];
     foreach ($promisors as $deferred) {
         $deferred->fail(new \Exception("Couldn't write command, server failed."));
     }
 }
Beispiel #6
0
 public final function update(\SplSubject $subject) : Promise
 {
     switch ($subject->state()) {
         case Server::STARTED:
             $this->watcherId = \Amp\repeat([$this, "updateTime"], 1000);
             $this->updateTime();
             break;
         case Server::STOPPED:
             \Amp\cancel($this->watcherId);
             $this->watcherId = null;
             break;
     }
     return new Success();
 }
Beispiel #7
0
 protected function doStart(Console $console) : \Generator
 {
     // Shutdown the whole server in case we needed to stop during startup
     register_shutdown_function(function () use($console) {
         if (!$this->server) {
             // ensure a clean reactor for clean shutdown
             $reactor = \Amp\reactor();
             \Amp\reactor(\Amp\driver());
             \Amp\wait((new CommandClient((string) $console->getArg("config")))->stop());
             \Amp\reactor($reactor);
         }
     });
     $server = (yield from $this->bootstrapper->boot($this->logger, $console));
     (yield $server->start());
     $this->server = $server;
     \Amp\onReadable($this->ipcSock, function ($watcherId) {
         \Amp\cancel($watcherId);
         yield from $this->stop();
     });
 }
Beispiel #8
0
 public function __destruct()
 {
     $this->stream = null;
     \Amp\cancel($this->watcher);
     /**
      * pecl/eio has a race condition issue when freeing threaded
      * resources and we can get intermittent segfaults at script
      * shutdown in certain cases if we don't wait for a moment.
      *
      * @TODO see if we can PR a fix for this problem in pecl/eio
      */
     usleep(1000);
 }
Beispiel #9
0
 public function cancel($signal = 9)
 {
     if (!$this->proc) {
         return;
     }
     \Amp\cancel($this->stdout);
     \Amp\cancel($this->stderr);
     \Amp\cancel($this->stdin);
     if (isset($this->exit)) {
         \Amp\cancel($this->exit);
     }
     $deferreds = $this->writeDeferreds;
     $this->writeDeferreds = [];
     $this->kill($signal);
     unset($this->proc);
     $this->deferred->fail(new \RuntimeException("Process watching was cancelled"));
     foreach ($deferreds as $deferred) {
         $deferred->fail(new \Exception("Write could not be completed, process watching was cancelled"));
     }
 }
Beispiel #10
0
 private function parseSocketData(HttpTunnelStruct $struct, $data)
 {
     try {
         $struct->parser->buffer($data);
         if (!($parsedResponseArr = $struct->parser->parse())) {
             return;
         }
         $status = $parsedResponseArr['status'];
         if ($status == 200) {
             // Tunnel connected! We're finished \o/ #WinningAtLife #DealWithIt
             stream_context_set_option($struct->socket, 'artax*', 'is_tunneled', true);
             $struct->promisor->succeed($struct->socket);
             \Amp\cancel($struct->readWatcher);
         } else {
             $struct->promisor->fail(new ClientException(sprintf('Unexpected response status received from proxy: %d', $status)));
             \Amp\cancel($struct->readWatcher);
         }
     } catch (ParseException $e) {
         \Amp\cancel($struct->readWatcher);
         $struct->promisor->fail(new ClientException('Invalid HTTP response received from proxy while establishing tunnel', 0, $e));
     }
 }
Beispiel #11
0
 public function __destruct()
 {
     $this->sharedState->cache = [];
     $this->sharedState->cacheTimeouts = [];
     \Amp\cancel($this->ttlWatcherId);
 }
Beispiel #12
0
 private function clear(Client $client)
 {
     $client->requestParser = null;
     $client->onWriteDrain = null;
     \Amp\cancel($client->readWatcher);
     \Amp\cancel($client->writeWatcher);
     $this->clearKeepAliveTimeout($client);
     unset($this->clients[$client->id]);
     if ($this->stopPromisor && empty($this->clients)) {
         $this->stopPromisor->succeed();
     }
 }
Beispiel #13
0
 public function send($socket)
 {
     $deferred = new Deferred();
     stream_set_blocking($socket, false);
     $data = $this->getRequest();
     \Amp\onWritable($socket, function ($writer, $socket) use($deferred, &$data) {
         if ($bytes = fwrite($socket, $data)) {
             if ($bytes < \strlen($data)) {
                 $data = substr($data, $bytes);
                 return;
             }
             $size = 8192;
             \Amp\onReadable($socket, function ($reader, $socket) use($deferred, &$size) {
                 /* make attention to not read too much data */
                 $data = stream_socket_recvfrom($socket, $size, STREAM_PEEK);
                 if (false === ($pos = strpos($data, "\r\n\r\n"))) {
                     if (\strlen($data) == $size) {
                         $size *= 2;
                         // unbounded??
                     }
                     return;
                 }
                 \Amp\cancel($reader);
                 $deferred->succeed($this->parseResponse(fread($socket, $pos + 4)));
             });
         } else {
             $deferred->succeed(null);
         }
         \Amp\cancel($writer);
     });
     return $deferred->promise();
 }
Beispiel #14
0
 private function proceedFrom100ContinueState(RequestCycle $cycle)
 {
     $continueWatcher = $cycle->continueWatcher;
     $cycle->continueWatcher = null;
     \Amp\cancel($continueWatcher);
     $this->writeBody($cycle);
 }
Beispiel #15
0
 public function __destruct()
 {
     \Amp\cancel($this->watcher);
 }
Beispiel #16
0
 public function update(Server $server) : Promise
 {
     switch ($this->state = $server->state()) {
         case Server::STARTING:
             $result = $this->application->onStart($this->proxy);
             if ($result instanceof \Generator) {
                 return resolve($result);
             }
             break;
         case Server::STARTED:
             $f = (new \ReflectionClass($this))->getMethod("timeout")->getClosure($this);
             $this->timeoutWatcher = \Amp\repeat($f, 1000);
             break;
         case Server::STOPPING:
             $result = $this->application->onStop();
             if ($result instanceof \Generator) {
                 $promise = resolve($result);
             } elseif ($result instanceof Promise) {
                 $promise = $result;
             } else {
                 $promise = new Success();
             }
             $promise->when(function () {
                 $code = Code::GOING_AWAY;
                 $reason = "Server shutting down!";
                 foreach ($this->clients as $client) {
                     $this->close($client->id, $code, $reason);
                 }
             });
             \Amp\cancel($this->timeoutWatcher);
             $this->timeoutWatcher = null;
             return $promise;
         case Server::STOPPED:
             $promises = [];
             // we are not going to wait for a proper self::OP_CLOSE answer (because else we'd need to timeout for 3 seconds, not worth it), but we will ensure to at least *have written* it
             foreach ($this->clients as $client) {
                 // only if we couldn't successfully send it in STOPPING
                 $code = Code::GOING_AWAY;
                 $reason = "Server shutting down!";
                 $result = $this->doClose($client, $code, $reason);
                 if ($result instanceof \Generator) {
                     $promise[] = resolve($result);
                 }
                 if (!empty($client->writeDeferredControlQueue)) {
                     $promise = end($client->writeDeferredControlQueue)->promise();
                     if ($promise) {
                         $promises[] = $promise;
                     }
                 }
             }
             $promise = any($promises);
             $promise->when(function () {
                 foreach ($this->clients as $client) {
                     $this->unloadClient($client);
                 }
             });
             return $promise;
     }
     return new Success();
 }
Beispiel #17
0
 public static function reader($watcher, $socket, $info)
 {
     $buffer =& $info[0];
     $data = @fread($socket, 8192);
     if ($data != "") {
         if ($buffer == "") {
             \Amp\enable($info[1]);
         }
         $buffer .= $data;
         if (\strlen($buffer) > self::MAX_INTERMEDIARY_BUFFER) {
             \Amp\disable($watcher);
         }
     } elseif (!is_resource($socket) || @feof($socket)) {
         \Amp\cancel($watcher);
         if ($buffer == "") {
             \Amp\cancel($info[1]);
         } else {
             $info[2] = true;
         }
     }
 }
Beispiel #18
0
function __onCryptoWatchReadability($watcherId, $socket, $cbData)
{
    list($promisor, $method) = $cbData;
    $result = \stream_socket_enable_crypto($socket, $enable = true, $method);
    if ($result === true) {
        \Amp\cancel($watcherId);
        $promisor->succeed($socket);
    } elseif ($result === false) {
        \Amp\cancel($watcherId);
        $promisor->fail(new CryptoException("Crypto negotiation failed: " . (feof($socket) ? "Connection reset by peer" : \error_get_last()["message"])));
    }
}
Beispiel #19
0
 private function unloadSocket($uri, $socketId)
 {
     if (!isset($this->sockets[$uri][$socketId])) {
         return;
     }
     $poolStruct = $this->sockets[$uri][$socketId];
     if ($poolStruct->idleWatcher) {
         \Amp\cancel($poolStruct->idleWatcher);
     }
     unset($this->sockets[$uri][$socketId], $this->socketIdUriMap[$socketId]);
     if (empty($this->sockets[$uri])) {
         unset($this->sockets[$uri][$socketId]);
     }
     if (!empty($this->queuedSocketRequests[$uri])) {
         $this->dequeueNextWaitingSocket($uri);
     }
 }
Beispiel #20
0
function __unloadServer($state, $serverId, $error = null)
{
    $server = $state->serverIdMap[$serverId];
    \Amp\cancel($server->watcherId);
    unset($state->serverIdMap[$serverId], $state->serverUriMap[$server->uri]);
    if (\is_resource($server->socket)) {
        @\fclose($server->socket);
    }
    if ($error && $server->pendingRequests) {
        foreach (array_keys($server->pendingRequests) as $requestId) {
            list($promisor) = $state->pendingRequests[$requestId];
            $promisor->fail($error);
        }
    }
}
Beispiel #21
0
 private function unloadServer($serverId, $error = null)
 {
     // Might already have been unloaded (especially if multiple requests happen)
     if (!isset($this->serverIdMap[$serverId])) {
         return;
     }
     $server = $this->serverIdMap[$serverId];
     \Amp\cancel($server->watcherId);
     unset($this->serverIdMap[$serverId], $this->serverUriMap[$server->uri]);
     if (\is_resource($server->socket)) {
         @\fclose($server->socket);
     }
     if ($error && $server->pendingRequests) {
         foreach (array_keys($server->pendingRequests) as $requestId) {
             list($promisor) = $this->pendingRequests[$requestId];
             $promisor->fail($error);
         }
     }
 }
Beispiel #22
0
 private function onDeadIpcClient(string $readWatcherId, $ipcClient)
 {
     \Amp\cancel($readWatcherId);
     @fclose($ipcClient);
     unset($this->ipcClients[$readWatcherId]);
     $this->defunctProcessCount++;
     \Amp\enable($this->procGarbageWatcher);
 }
Beispiel #23
0
 public function send($socket)
 {
     $deferred = new Deferred();
     stream_set_blocking($socket, false);
     $data = $this->getRequest();
     \Amp\onWritable($socket, function ($writer, $socket) use($deferred, &$data) {
         if ($bytes = fwrite($socket, $data)) {
             if ($bytes < \strlen($data)) {
                 $data = substr($data, $bytes);
                 return;
             }
             $data = '';
             \Amp\onReadable($socket, function ($reader, $socket) use($deferred, &$data) {
                 $data .= $bytes = fgets($socket);
                 if ($bytes == '' || \strlen($bytes) > 32768) {
                     \Amp\cancel($reader);
                     $deferred->succeed(null);
                 } elseif (substr($data, -4) == "\r\n\r\n") {
                     \Amp\cancel($reader);
                     $deferred->succeed($this->parseResponse($data));
                 }
             });
         } else {
             $deferred->succeed(null);
         }
         \Amp\cancel($writer);
     });
     return $deferred->promise();
 }