Example #1
0
 /**
  * Retrieve the next frame from the internal buffer.
  *
  * @param string $buffer         Binary data to feed to the parser.
  * @param int    &$requiredBytes The minimum number of bytes that must be
  *                               read to produce the next frame.
  *
  * @return Frame|null        The frame parsed from the start of the buffer.
  * @throws ProtocolException The incoming data does not conform to the AMQP
  *                           specification.
  */
 public function feed(string $buffer, int &$requiredBytes = 0)
 {
     $this->buffer .= $buffer;
     $availableBytes = \strlen($this->buffer);
     // not enough bytes for a frame ...
     if ($availableBytes < $this->requiredBytes) {
         $requiredBytes = $this->requiredBytes;
         return null;
         // we're still looking for the header ...
     } elseif ($this->requiredBytes === self::MINIMUM_FRAME_SIZE) {
         // now that we know the payload size we can add that to the number
         // of required bytes ...
         $this->requiredBytes += \unpack('N', \substr($this->buffer, self::HEADER_TYPE_SIZE + self::HEADER_CHANNEL_SIZE, self::HEADER_PAYLOAD_LENGTH_SIZE))[1];
         // taking the payload into account we still don't have enough bytes
         // for the frame ...
         if ($availableBytes < $this->requiredBytes) {
             $requiredBytes = $this->requiredBytes;
             return null;
         }
     }
     // we've got enough bytes, check that the last byte is the end marker ...
     if (\ord($this->buffer[$this->requiredBytes - 1]) !== Constants::FRAME_END) {
         throw ProtocolException::create(\sprintf('Frame end marker (0x%02x) is invalid.', \ord($this->buffer[$this->requiredBytes - 1])));
     }
     // read the (t)ype and (c)hannel then discard the header ...
     $fields = \unpack('Ct/nc', $this->buffer);
     $this->buffer = \substr($this->buffer, self::HEADER_SIZE);
     $type = $fields['t'];
     // read the frame ...
     if ($type === Constants::FRAME_METHOD) {
         $frame = $this->parseMethodFrame();
     } elseif ($type === Constants::FRAME_HEADER) {
         $frame = $this->parseHeaderFrame();
     } elseif ($type === Constants::FRAME_BODY) {
         $length = $this->requiredBytes - self::MINIMUM_FRAME_SIZE;
         $frame = new BodyFrame();
         $frame->content = \substr($this->buffer, 0, $length);
         $this->buffer = \substr($this->buffer, $length);
     } elseif ($type === Constants::FRAME_HEARTBEAT) {
         if (self::MINIMUM_FRAME_SIZE !== $this->requiredBytes) {
             throw ProtocolException::create(\sprintf('Heartbeat frame payload size (%d) is invalid, must be zero.', $this->requiredBytes - self::MINIMUM_FRAME_SIZE));
         }
         $frame = new HeartbeatFrame();
     } else {
         throw ProtocolException::create(\sprintf('Frame type (0x%02x) is invalid.', $type));
     }
     // discard the end marker ...
     $this->buffer = \substr($this->buffer, 1);
     $consumedBytes = $availableBytes - \strlen($this->buffer);
     // the frame lied about its payload size ...
     if ($consumedBytes !== $this->requiredBytes) {
         throw ProtocolException::create(\sprintf('Mismatch between frame size (%s) and consumed bytes (%s).', $this->requiredBytes, $consumedBytes));
     }
     $this->requiredBytes = $requiredBytes = self::MINIMUM_FRAME_SIZE;
     $frame->frameChannelId = $fields['c'];
     return $frame;
 }
Example #2
0
 /**
  * Parse a table or array field.
  *
  * @return integer|array|boolean|double|string|null
  */
 private function parseField()
 {
     $type = $this->buffer[0];
     $this->buffer = substr($this->buffer, 1);
     // @todo bench switch vs if vs method map
     switch ($type) {
         case 's':
             return $this->parseSignedInt16();
         case 'l':
             return $this->parseSignedInt64();
         case 'x':
             return $this->parseByteArray();
         case 't':
             return $this->parseUnsignedInt8() !== 0;
         case 'b':
             return $this->parseSignedInt8();
         case 'I':
             return $this->parseSignedInt32();
         case 'f':
             return $this->parseFloat();
         case 'd':
             return $this->parseDouble();
         case 'D':
             return $this->parseDecimal();
         case 'S':
             return $this->parseLongString();
         case 'A':
             return $this->parseArray();
         case 'T':
             return $this->parseUnsignedInt64();
         case 'F':
             return $this->parseTable();
         case 'V':
             return null;
     }
     throw ProtocolException::create(\sprintf('table value type (0x%02x) is invalid or unrecognised.', ord($type)));
 }
Example #3
0
 private function readLoop() : Generator
 {
     try {
         while ($this->state === ConnectionState::OPEN) {
             $frame = (yield $this->transport->read());
             $this->heartbeatsSinceFrameReceived = 0;
             if ($frame instanceof HeartbeatFrame) {
                 continue;
             } elseif ($frame->frameChannelId > 0) {
                 $channelManager = $this->channels[$frame->frameChannelId] ?? null;
                 if ($channelManager === null) {
                     throw ProtocolException::unexpectedFrame($frame, \sprintf('channel #%s is closed', $frame->frameChannelId));
                 }
                 (yield $channelManager->dispatch($frame));
             } elseif ($frame instanceof ConnectionCloseFrame) {
                 (yield $this->transport->close());
                 throw AmqpException::create($frame->replyText, $frame->replyCode);
             } else {
                 throw ProtocolException::unexpectedFrame($frame, 'received on channel #0');
             }
         }
         while ($this->state === ConnectionState::CLOSING) {
             $frame = (yield $this->transport->read());
             if ($frame instanceof ConnectionCloseOkFrame) {
                 (yield $this->transport->close());
                 (yield $this->onClose());
             }
         }
     } catch (ChannelClosedException $e) {
         (yield $this->onClose(SingleConnectionException::closedUnexpectedly($this->options, $e)));
     } catch (Throwable $e) {
         assert(Debug::dumpException('read-loop', $e));
         (yield $this->onClose($e));
     }
 }
Example #4
0
 /**
  * Perform the "open" phase of the handshake.
  *
  * @recoil-coroutine
  *
  * @param DuplexChannel     $frames  A channel over which frames are sent
  *                                   and received.
  * @param ConnectionOptions $options The options used when establishing
  *                                   the connection.
  */
 private function open(DuplexChannel $frames, ConnectionOptions $options) : Generator
 {
     (yield $frames->write(ConnectionOpenFrame::create($options->vhost())));
     try {
         $frame = (yield $frames->read());
     } catch (ChannelClosedException $e) {
         throw SingleConnectionException::authorizationFailed($options, $e);
     }
     if ($frame instanceof ConnectionCloseFrame) {
         if ($frame->replyCode === Constants::NOT_ALLOWED && $frame->classId === ConnectionOpenFrame::METHOD_ID >> 16 && $frame->methodId === (ConnectionOpenFrame::METHOD_ID & 0xff)) {
             throw SingleConnectionException::authorizationFailed($options);
         }
         throw SingleConnectionException::closedUnexpectedly($options);
     } elseif (!$frame instanceof ConnectionOpenOkFrame) {
         throw ProtocolException::unexpectedFrame($frame, 'expected ' . ConnectionOpenOkFrame::class);
     }
 }
 private function parseHeaderFrame()
 {
     $fields = \unpack("na/nb/Jc/nd", $this->buffer);
     $this->buffer = \substr($this->buffer, 14);
     $class = $fields["a"];
     $flags = $fields["d"];
     // class "basic"
     if ($class === 60) {
         $frame = new Basic\BasicHeaderFrame();
         $frame->contentLength = $fields["c"];
         // consume "content-type" (shortstr)
         if ($flags & 32768) {
             $length = \ord($this->buffer);
             $frame->contentType = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "content-encoding" (shortstr)
         if ($flags & 16384) {
             $length = \ord($this->buffer);
             $frame->contentEncoding = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "headers" (table)
         if ($flags & 8192) {
             $frame->headers = $this->tableParser->parse($this->buffer);
         }
         // consume "delivery-mode" (octet)
         if ($flags & 4096) {
             list(, $frame->deliveryMode) = \unpack('c', $this->buffer);
             $this->buffer = \substr($this->buffer, 1);
         }
         // consume "priority" (octet)
         if ($flags & 2048) {
             list(, $frame->priority) = \unpack('c', $this->buffer);
             $this->buffer = \substr($this->buffer, 1);
         }
         // consume "correlation-id" (shortstr)
         if ($flags & 1024) {
             $length = \ord($this->buffer);
             $frame->correlationId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "reply-to" (shortstr)
         if ($flags & 512) {
             $length = \ord($this->buffer);
             $frame->replyTo = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "expiration" (shortstr)
         if ($flags & 256) {
             $length = \ord($this->buffer);
             $frame->expiration = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "message-id" (shortstr)
         if ($flags & 128) {
             $length = \ord($this->buffer);
             $frame->messageId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "timestamp" (timestamp)
         if ($flags & 64) {
             list(, $frame->timestamp) = \unpack('J', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
         }
         // consume "type" (shortstr)
         if ($flags & 32) {
             $length = \ord($this->buffer);
             $frame->type = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "user-id" (shortstr)
         if ($flags & 16) {
             $length = \ord($this->buffer);
             $frame->userId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "app-id" (shortstr)
         if ($flags & 8) {
             $length = \ord($this->buffer);
             $frame->appId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         // consume "cluster-id" (shortstr)
         if ($flags & 4) {
             $length = \ord($this->buffer);
             $frame->clusterId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
         }
         return $frame;
     }
     throw ProtocolException::create("Frame class (" . $class . ") is invalid or does not support content frames.");
 }
Example #6
0
 /**
  * Notify the channel of an incoming frame.
  *
  * @recoil-coroutine
  *
  * @param IncomingFrame $frame The received frame.
  *
  * @throws ProtocolException The incoming frame violates the expectations of the AMQP protocol.
  */
 public function dispatch(IncomingFrame $frame) : Generator
 {
     assert($frame->frameChannelId === $this->channelId);
     // Handle frames during normal operation ...
     if ($this->state === ChannelState::OPEN) {
         // The broker has closed the channel ...
         if ($frame instanceof ChannelCloseFrame) {
             (yield $this->onCloseByBroker($frame));
             // The broker has acknowledged a client-side open after already opened ...
         } elseif ($frame instanceof ChannelOpenOkFrame) {
             goto unexpectedFrame;
             // The broker has acknowledged a client-side close that was never made ...
         } elseif ($frame instanceof ChannelCloseOkFrame) {
             goto unexpectedFrame;
             // The broker has requested a client->broker flow start/stop ...
         } elseif ($frame instanceof ChannelFlowFrame) {
             // Not suppported (and unused by RabbitMQ).
             // The AMQP spec dictates that method frames may not be interleaved
             // with content frames, which makes it unclear how the client should
             // respond to a flow frame if it's in the middle of transmitting content
             // We're expecting a method and we got one ...
         } elseif ($this->expectedFrame === Constants::FRAME_METHOD && $frame instanceof MethodFrame) {
             // The frame will be followed by content ...
             if ($frame instanceof ContentPrecursorFrame) {
                 $this->expectedFrame = Constants::FRAME_HEADER;
             }
             $waitMethod = $frame::METHOD_ID;
             // Check if there is a suspended strand waiting for this frame
             // type as a response ...
             ($callers =& $this->callers[$waitMethod]) ?? null;
             if ($callers) {
                 foreach ($callers as $id => $strand) {
                     $sentMethod = $this->callersByWaitMethod[$waitMethod][$id];
                     unset($this->callers[$waitMethod][$id], $this->callersBySentMethod[$sentMethod][$id], $this->callersByWaitMethod[$waitMethod][$id]);
                     $strand->send($frame);
                     break;
                 }
                 // Otherwise dispatch the frame to any listeners ...
             } elseif (isset($this->listeners[$waitMethod])) {
                 assert(false, 'not implemented');
                 // foreach ($this->listeners[$waitMethod] as $callback) {
                 //     $callback(null, $frame);
                 // }
             }
             // We're expecting a content header and we got one ...
         } elseif ($this->expectedFrame === Constants::FRAME_HEADER && $frame instanceof HeaderFrame) {
             // There are no body frames to follow ...
             if ($frame->contentLength === 0) {
                 $this->expectedFrame = Constants::FRAME_METHOD;
                 if ($this->onIncomingContent) {
                     $callback = $this->onIncomingContent;
                     $this->onIncomingContent = null;
                     $callback(null, $frame, true);
                 }
                 // There are body frames to follow ...
             } else {
                 $this->expectedFrame = Constants::FRAME_BODY;
                 $this->incomingBytesRemaining = $frame->contentLength;
                 if ($this->onIncomingContent) {
                     $callback = $this->onIncomingContent;
                     $callback(null, $frame, false);
                 }
             }
             // We're expecting some content and we got some ...
         } elseif ($this->expectedFrame === Constants::FRAME_BODY && $frame instanceof BodyFrame) {
             $this->incomingBytesRemaining -= strlen($frame->content);
             if ($this->incomingBytesRemaining < 0) {
                 throw ProtocolException::create(\sprintf('Expected content length was exceeded on channel #%d by %d byte(s).', $this->channelId, -$this->incomingBytesRemaining));
             } elseif ($this->incomingBytesRemaining === 0) {
                 $this->expectedFrame = Constants::FRAME_METHOD;
                 if ($this->onIncomingContent) {
                     $callback = $this->onIncomingContent;
                     $this->onIncomingContent = null;
                     $callback(null, $frame, true);
                 }
             } elseif ($this->onIncomingContent) {
                 $callback = $this->onIncomingContent;
                 $callback(null, $frame, false);
             }
             // Otherwise, bail with a protocol exception ...
         } else {
             goto unexpectedFrame;
         }
         // The broker has acknowledged our open request ...
     } elseif ($this->state === ChannelState::OPENING && $frame instanceof ChannelOpenOkFrame) {
         $this->state = ChannelState::OPEN;
         $strand = $this->openingStrand;
         $this->openingStrand = null;
         (yield Recoil::resume($strand));
         // We're waiting on a close acknowledgement, blackhole everything else ...
     } elseif ($this->state === ChannelState::CLOSING) {
         if ($frame instanceof ChannelCloseOkFrame) {
             (yield $this->onClose());
         }
     } else {
         unexpectedFrame:
         throw ProtocolException::unexpectedFrame($frame, \sprintf('received on channel #%d, state: %d, expect: %d', $this->channelId, $this->state, $this->expectedFrame));
     }
 }
 private function parseMethodFrame()
 {
     list(, $class, $method) = \unpack("n2", $this->buffer);
     $this->buffer = \substr($this->buffer, 4);
     // class "connection"
     if ($class === 10) {
         // method "connection.start"
         if ($method === 10) {
             $frame = new Connection\ConnectionStartFrame();
             // consume (a) "version-major" (octet)
             // consume (b) "version-minor" (octet)
             $fields = \unpack('ca/cb', $this->buffer);
             $this->buffer = \substr($this->buffer, 2);
             $frame->versionMajor = $fields["a"];
             $frame->versionMinor = $fields["b"];
             // consume "server-properties" (table)
             $frame->serverProperties = $this->tableParser->parse($this->buffer);
             // consume "mechanisms" (longstr)
             list(, $length) = \unpack("N", $this->buffer);
             $frame->mechanisms = \substr($this->buffer, 4, $length);
             $this->buffer = \substr($this->buffer, 4 + $length);
             // consume "locales" (longstr)
             list(, $length) = \unpack("N", $this->buffer);
             $frame->locales = \substr($this->buffer, 4, $length);
             $this->buffer = \substr($this->buffer, 4 + $length);
             return $frame;
             // method "connection.secure"
         } elseif ($method === 20) {
             $frame = new Connection\ConnectionSecureFrame();
             // consume "challenge" (longstr)
             list(, $length) = \unpack("N", $this->buffer);
             $frame->challenge = \substr($this->buffer, 4, $length);
             $this->buffer = \substr($this->buffer, 4 + $length);
             return $frame;
             // method "connection.tune"
         } elseif ($method === 30) {
             $frame = new Connection\ConnectionTuneFrame();
             // consume (a) "channel-max" (short)
             // consume (b) "frame-max" (long)
             // consume (c) "heartbeat" (short)
             $fields = \unpack('na/Nb/nc', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             $frame->channelMax = $fields["a"];
             $frame->frameMax = $fields["b"];
             $frame->heartbeat = $fields["c"];
             return $frame;
             // method "connection.open-ok"
         } elseif ($method === 41) {
             $frame = new Connection\ConnectionOpenOkFrame();
             // consume "known-hosts" (shortstr)
             $length = \ord($this->buffer);
             $frame->knownHosts = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "connection.close"
         } elseif ($method === 50) {
             $frame = new Connection\ConnectionCloseFrame();
             // consume "replyCode" (short)
             list(, $frame->replyCode) = \unpack('n', $this->buffer);
             $this->buffer = \substr($this->buffer, 2);
             // consume "reply-text" (shortstr)
             $length = \ord($this->buffer);
             $frame->replyText = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume (a) "class-id" (short)
             // consume (b) "method-id" (short)
             $fields = \unpack('na/nb', $this->buffer);
             $this->buffer = \substr($this->buffer, 4);
             $frame->classId = $fields["a"];
             $frame->methodId = $fields["b"];
             return $frame;
             // method "connection.close-ok"
         } elseif ($method === 51) {
             return new Connection\ConnectionCloseOkFrame();
             // method "connection.blocked"
         } elseif ($method === 60) {
             $frame = new Connection\ConnectionBlockedFrame();
             // consume "reason" (shortstr)
             $length = \ord($this->buffer);
             $frame->reason = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "connection.unblocked"
         } elseif ($method === 61) {
             return new Connection\ConnectionUnblockedFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"connection\".");
         // class "channel"
     } elseif ($class === 20) {
         // method "channel.open-ok"
         if ($method === 11) {
             $frame = new Channel\ChannelOpenOkFrame();
             // consume "channel-id" (longstr)
             list(, $length) = \unpack("N", $this->buffer);
             $frame->channelId = \substr($this->buffer, 4, $length);
             $this->buffer = \substr($this->buffer, 4 + $length);
             return $frame;
             // method "channel.flow"
         } elseif ($method === 20) {
             $frame = new Channel\ChannelFlowFrame();
             // consume "active" (bit)
             $frame->active = \ord($this->buffer) !== 0;
             $this->buffer = \substr($this->buffer, 1);
             return $frame;
             // method "channel.flow-ok"
         } elseif ($method === 21) {
             $frame = new Channel\ChannelFlowOkFrame();
             // consume "active" (bit)
             $frame->active = \ord($this->buffer) !== 0;
             $this->buffer = \substr($this->buffer, 1);
             return $frame;
             // method "channel.close"
         } elseif ($method === 40) {
             $frame = new Channel\ChannelCloseFrame();
             // consume "replyCode" (short)
             list(, $frame->replyCode) = \unpack('n', $this->buffer);
             $this->buffer = \substr($this->buffer, 2);
             // consume "reply-text" (shortstr)
             $length = \ord($this->buffer);
             $frame->replyText = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume (a) "class-id" (short)
             // consume (b) "method-id" (short)
             $fields = \unpack('na/nb', $this->buffer);
             $this->buffer = \substr($this->buffer, 4);
             $frame->classId = $fields["a"];
             $frame->methodId = $fields["b"];
             return $frame;
             // method "channel.close-ok"
         } elseif ($method === 41) {
             return new Channel\ChannelCloseOkFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"channel\".");
         // class "access"
     } elseif ($class === 30) {
         // method "access.request-ok"
         if ($method === 11) {
             $frame = new Access\AccessRequestOkFrame();
             // consume "reserved1" (short)
             list(, $frame->reserved1) = \unpack('n', $this->buffer);
             $this->buffer = \substr($this->buffer, 2);
             return $frame;
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"access\".");
         // class "exchange"
     } elseif ($class === 40) {
         // method "exchange.declare-ok"
         if ($method === 11) {
             return new Exchange\ExchangeDeclareOkFrame();
             // method "exchange.delete-ok"
         } elseif ($method === 21) {
             return new Exchange\ExchangeDeleteOkFrame();
             // method "exchange.bind-ok"
         } elseif ($method === 31) {
             return new Exchange\ExchangeBindOkFrame();
             // method "exchange.unbind-ok"
         } elseif ($method === 51) {
             return new Exchange\ExchangeUnbindOkFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"exchange\".");
         // class "queue"
     } elseif ($class === 50) {
         // method "queue.declare-ok"
         if ($method === 11) {
             $frame = new Queue\QueueDeclareOkFrame();
             // consume "queue" (shortstr)
             $length = \ord($this->buffer);
             $frame->queue = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume (a) "message-count" (long)
             // consume (b) "consumer-count" (long)
             $fields = \unpack('Na/Nb', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             $frame->messageCount = $fields["a"];
             $frame->consumerCount = $fields["b"];
             return $frame;
             // method "queue.bind-ok"
         } elseif ($method === 21) {
             return new Queue\QueueBindOkFrame();
             // method "queue.purge-ok"
         } elseif ($method === 31) {
             $frame = new Queue\QueuePurgeOkFrame();
             // consume "messageCount" (long)
             list(, $frame->messageCount) = \unpack('N', $this->buffer);
             $this->buffer = \substr($this->buffer, 4);
             return $frame;
             // method "queue.delete-ok"
         } elseif ($method === 41) {
             $frame = new Queue\QueueDeleteOkFrame();
             // consume "messageCount" (long)
             list(, $frame->messageCount) = \unpack('N', $this->buffer);
             $this->buffer = \substr($this->buffer, 4);
             return $frame;
             // method "queue.unbind-ok"
         } elseif ($method === 51) {
             return new Queue\QueueUnbindOkFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"queue\".");
         // class "basic"
     } elseif ($class === 60) {
         // method "basic.qos-ok"
         if ($method === 11) {
             return new Basic\BasicQosOkFrame();
             // method "basic.consume-ok"
         } elseif ($method === 21) {
             $frame = new Basic\BasicConsumeOkFrame();
             // consume "consumer-tag" (shortstr)
             $length = \ord($this->buffer);
             $frame->consumerTag = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "basic.cancel-ok"
         } elseif ($method === 31) {
             $frame = new Basic\BasicCancelOkFrame();
             // consume "consumer-tag" (shortstr)
             $length = \ord($this->buffer);
             $frame->consumerTag = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "basic.return"
         } elseif ($method === 50) {
             $frame = new Basic\BasicReturnFrame();
             // consume "replyCode" (short)
             list(, $frame->replyCode) = \unpack('n', $this->buffer);
             $this->buffer = \substr($this->buffer, 2);
             // consume "reply-text" (shortstr)
             $length = \ord($this->buffer);
             $frame->replyText = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "exchange" (shortstr)
             $length = \ord($this->buffer);
             $frame->exchange = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "routing-key" (shortstr)
             $length = \ord($this->buffer);
             $frame->routingKey = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "basic.deliver"
         } elseif ($method === 60) {
             $frame = new Basic\BasicDeliverFrame();
             // consume "consumer-tag" (shortstr)
             $length = \ord($this->buffer);
             $frame->consumerTag = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "deliveryTag" (longlong)
             list(, $frame->deliveryTag) = \unpack('J', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             // consume "redelivered" (bit)
             $frame->redelivered = \ord($this->buffer) !== 0;
             $this->buffer = \substr($this->buffer, 1);
             // consume "exchange" (shortstr)
             $length = \ord($this->buffer);
             $frame->exchange = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "routing-key" (shortstr)
             $length = \ord($this->buffer);
             $frame->routingKey = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "basic.get-ok"
         } elseif ($method === 71) {
             $frame = new Basic\BasicGetOkFrame();
             // consume "deliveryTag" (longlong)
             list(, $frame->deliveryTag) = \unpack('J', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             // consume "redelivered" (bit)
             $frame->redelivered = \ord($this->buffer) !== 0;
             $this->buffer = \substr($this->buffer, 1);
             // consume "exchange" (shortstr)
             $length = \ord($this->buffer);
             $frame->exchange = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "routing-key" (shortstr)
             $length = \ord($this->buffer);
             $frame->routingKey = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             // consume "messageCount" (long)
             list(, $frame->messageCount) = \unpack('N', $this->buffer);
             $this->buffer = \substr($this->buffer, 4);
             return $frame;
             // method "basic.get-empty"
         } elseif ($method === 72) {
             $frame = new Basic\BasicGetEmptyFrame();
             // consume "cluster-id" (shortstr)
             $length = \ord($this->buffer);
             $frame->clusterId = \substr($this->buffer, 1, $length);
             $this->buffer = \substr($this->buffer, 1 + $length);
             return $frame;
             // method "basic.ack"
         } elseif ($method === 80) {
             $frame = new Basic\BasicAckFrame();
             // consume "deliveryTag" (longlong)
             list(, $frame->deliveryTag) = \unpack('J', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             // consume "multiple" (bit)
             $frame->multiple = \ord($this->buffer) !== 0;
             $this->buffer = \substr($this->buffer, 1);
             return $frame;
             // method "basic.recover-ok"
         } elseif ($method === 111) {
             return new Basic\BasicRecoverOkFrame();
             // method "basic.nack"
         } elseif ($method === 120) {
             $frame = new Basic\BasicNackFrame();
             // consume "deliveryTag" (longlong)
             list(, $frame->deliveryTag) = \unpack('J', $this->buffer);
             $this->buffer = \substr($this->buffer, 8);
             // consume "multiple" (bit)
             // consume "requeue" (bit)
             $octet = \ord($this->buffer);
             $this->buffer = \substr($this->buffer, 1);
             $frame->multiple = $octet & 1 !== 0;
             $frame->requeue = $octet & 2 !== 0;
             return $frame;
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"basic\".");
         // class "tx"
     } elseif ($class === 90) {
         // method "tx.select-ok"
         if ($method === 11) {
             return new Tx\TxSelectOkFrame();
             // method "tx.commit-ok"
         } elseif ($method === 21) {
             return new Tx\TxCommitOkFrame();
             // method "tx.rollback-ok"
         } elseif ($method === 31) {
             return new Tx\TxRollbackOkFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"tx\".");
         // class "confirm"
     } elseif ($class === 85) {
         // method "confirm.select-ok"
         if ($method === 11) {
             return new Confirm\ConfirmSelectOkFrame();
         }
         throw ProtocolException::create("Frame method (" . $method . ") is invalid for class \"confirm\".");
     }
     throw ProtocolException::create("Frame class (" . $class . ") is invalid.");
 }