/** * process error * * @param \Thruway\Message\ErrorMessage $msg */ protected function processError(ErrorMessage $msg) { if (isset($this->publishRequests[$msg->getRequestId()])) { /* @var $futureResult Deferred */ $futureResult = $this->publishRequests[$msg->getRequestId()]["future_result"]; $futureResult->reject($msg); unset($this->publishRequests[$msg->getRequestId()]); } }
/** * @param ClientSession $session * @param ErrorMessage $msg */ public function processError(ClientSession $session, ErrorMessage $msg) { if (isset($this->publishRequests[$msg->getRequestId()])) { /* @var $futureResult Deferred */ $futureResult = $this->publishRequests[$msg->getRequestId()]["future_result"]; $futureResult->reject($msg->getErrorMsgCode()); unset($this->publishRequests[$msg->getRequestId()]); } }
/** * Process subscribe error * * @param \Thruway\AbstractSession $session * @param \Thruway\Message\ErrorMessage $msg */ protected function processSubscribeError(AbstractSession $session, ErrorMessage $msg) { foreach ($this->subscriptions as $key => $subscription) { if ($subscription["request_id"] === $msg->getErrorRequestId()) { // reject the promise $this->subscriptions[$key]['deferred']->reject($msg); unset($this->subscriptions[$key]); break; } } }
/** * Process ErrorMessage * * @param \Thruway\Message\ErrorMessage $msg */ protected function processError(ErrorMessage $msg) { switch ($msg->getErrorMsgCode()) { case Message::MSG_CALL: if (isset($this->callRequests[$msg->getRequestId()])) { /* @var $futureResult Deferred */ $futureResult = $this->callRequests[$msg->getRequestId()]['future_result']; $futureResult->reject($msg); unset($this->callRequests[$msg->getRequestId()]); } break; } }
/** * @param \Thruway\Event\MessageEvent $messageEvent */ public function handleMessage(MessageEvent $messageEvent) { if (!$this->isAuthorizedTo($messageEvent->session, $messageEvent->message)) { $messageEvent->session->sendMessage(ErrorMessage::createErrorMessageFromMessage($messageEvent->message, "wamp.error.not_authorized")); $messageEvent->stopPropagation(); } }
/** * @param Session $session * @param Message $msg */ public function onMessage(Session $session, Message $msg) { if (!$session->isAuthenticated()) { if ($msg instanceof HelloMessage) { $this->manager->debug("got hello"); // send welcome message if ($this->sessions->contains($session)) { $this->manager->error("Connection tried to rejoin realm when it is already joined to the realm."); $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg)); // TODO should shut down session here } else { $this->sessions->attach($session); $session->setRealm($this); $session->setState(Session::STATE_UP); // this should probably be after authentication if ($this->getAuthenticationManager() !== null) { $this->getAuthenticationManager()->onAuthenticationMessage($this, $session, $msg); } else { $session->setAuthenticated(true); $session->setAuthenticationDetails(AuthenticationDetails::createAnonymous()); // the broker and dealer should give us this information $roles = array("broker" => new \stdClass(), "dealer" => new \stdClass()); $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("roles" => $roles))); } } } else { if ($msg instanceof AuthenticateMessage) { if ($this->getAuthenticationManager() !== null) { $this->getAuthenticationManager()->onAuthenticationMessage($this, $session, $msg); } else { // TODO: should shut down here probably $this->manager->error("Authenticate sent to realm without auth manager."); } } else { $this->manager->error("Unhandled message sent to unauthenticated realm: " . $msg->getMsgCode()); $session->sendMessage(new AbortMessage(new \stdClass(), "wamp.error.not_authorized")); $session->shutdown(); } } } else { $handled = false; /* @var $role AbstractRole */ foreach ($this->roles as $role) { if ($role->handlesMessage($msg)) { $role->onMessage($session, $msg); $handled = true; break; } } if (!$handled) { $this->manager->warning("Unhandled message sent to \"{$this->getRealmName()}\": {$msg->getSerializedMessage()}"); } } }
/** * @param AbstractSession $session * @param Message $msg * @return mixed */ public function onMessage(AbstractSession $session, Message $msg) { if ($msg instanceof SubscribedMessage) { $this->processSubscribed($session, $msg); } elseif ($msg instanceof UnsubscribedMessage) { $this->processUnsubscribed($session, $msg); } elseif ($msg instanceof EventMessage) { $this->processEvent($session, $msg); } else { $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg)); } }
/** * @param Session $session * @param ErrorMessage $msg */ private function processInterruptError(Session $session, ErrorMessage $msg) { $call = isset($this->callInterruptIndex[$msg->getRequestId()]) ? $this->callInterruptIndex[$msg->getRequestId()] : null; if (!$call) { Logger::warning($this, "Interrupt error with no corresponding interrupt index"); return; } $errorMsgToCaller = ErrorMessage::createErrorMessageFromMessage($call->getCancelMessage()); $errorMsgToCaller->setErrorURI($msg->getErrorURI()); $callerSession = $call->getCallerSession(); $callerSession->sendMessage($errorMsgToCaller); $call->getRegistration()->removeCall($call); $this->removeCall($call); }
/** * processCancel processes cancel message from the caller. * Return true if the Call should be removed from active calls * * @param Session $session * @param CancelMessage $msg * @return bool */ public function processCancel(Session $session, CancelMessage $msg) { if ($this->getCallerSession() !== $session) { Logger::warning($this, "session attempted to cancel call they did not own."); return false; } if ($this->getCalleeSession() === null) { // this call has not been sent to a callee yet (it is in a queue) // we can just kill it and say it was canceled $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled"); $details = $errorMsg->getDetails() ?: (object) []; $details->_thruway_removed_from_queue = true; $session->sendMessage($errorMsg); return true; } $details = (object) []; if ($this->getCalleeSession()->getHelloMessage() instanceof HelloMessage) { $details = $this->getCalleeSession()->getHelloMessage()->getDetails(); } $calleeSupportsCancel = false; if (isset($details->roles->callee->features->call_canceling) && is_scalar($details->roles->callee->features->call_canceling)) { $calleeSupportsCancel = (bool) $details->roles->callee->features->call_canceling; } if (!$calleeSupportsCancel) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $errorMsg->setErrorURI('wamp.error.not_supported'); $session->sendMessage($errorMsg); return false; } $this->setCancelMessage($msg); $this->canceling = true; $calleeSession = $this->getCalleeSession(); $interruptMessage = new InterruptMessage($this->getInvocationRequestId(), (object) []); $calleeSession->sendMessage($interruptMessage); $this->setInterruptMessage($interruptMessage); if (isset($msg->getOptions()->mode) && is_scalar($msg->getOptions()->mode) && $msg->getOptions()->mode == "killnowait") { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled"); $session->sendMessage($errorMsg); return true; } return false; }
public function testInvocationError() { $dealer = new \Thruway\Role\Dealer(); $callerTransport = new \Thruway\Transport\DummyTransport(); $callerSession = new Session($callerTransport); $calleeTransport = new \Thruway\Transport\DummyTransport(); $calleeSession = new Session($calleeTransport); // register from callee $registerMsg = new \Thruway\Message\RegisterMessage(1, new stdClass(), 'test_proc_name'); $dealer->handleRegisterMessage(new \Thruway\Event\MessageEvent($calleeSession, $registerMsg)); $this->assertInstanceOf('\\Thruway\\Message\\RegisteredMessage', $calleeTransport->getLastMessageSent()); // call from one session $callRequestId = \Thruway\Common\Utils::getUniqueId(); $callMsg = new \Thruway\Message\CallMessage($callRequestId, new stdClass(), 'test_proc_name'); $dealer->handleCallMessage(new \Thruway\Event\MessageEvent($callerSession, $callMsg)); $this->assertInstanceOf('\\Thruway\\Message\\InvocationMessage', $calleeTransport->getLastMessageSent()); $errorMsg = \Thruway\Message\ErrorMessage::createErrorMessageFromMessage($calleeTransport->getLastMessageSent(), 'the.error.uri'); $dealer->handleErrorMessage(new \Thruway\Event\MessageEvent($calleeSession, $errorMsg)); /** @var \Thruway\Message\ErrorMessage $returnedError */ $returnedError = $callerTransport->getLastMessageSent(); $this->assertInstanceOf('\\Thruway\\Message\\ErrorMessage', $returnedError); $this->assertEquals(Message::MSG_CALL, $returnedError->getErrorMsgCode()); $this->assertEquals($callRequestId, $returnedError->getErrorRequestId()); $this->assertEquals('the.error.uri', $returnedError->getErrorURI()); }
/** * Process call * * @param \Thruway\Session $session * @param Call $call * @throws \Exception * @return bool | Call */ public function processCall(Session $session, Call $call) { // find a registration to call if (count($this->registrations) == 0) { $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($call->getCallMessage(), 'wamp.error.no_such_procedure')); return false; } // just send it to the first one if we don't allow multiple registrations if (!$this->getAllowMultipleRegistrations()) { $this->registrations[0]->processCall($call); } else { $this->callQueue->enqueue($call); $this->processQueue(); } return true; }
/** * Process Unsubscribe message * * @param \Thruway\Session $session * @param \Thruway\Message\UnsubscribeMessage $msg */ protected function processUnsubscribe(Session $session, UnsubscribeMessage $msg) { $subscription = false; // should probably be more efficient about this - maybe later /** @var SubscriptionGroup $subscriptionGroup */ foreach ($this->subscriptionGroups as $subscriptionGroup) { $result = $subscriptionGroup->processUnsubscribe($session, $msg); if ($result !== false) { $subscription = $result; } } if ($subscription === false) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $session->sendMessage($errorMsg->setErrorURI('wamp.error.no_such_subscription')); return; } }
/** * This will send error messages on all pending calls * This is used when a session disconnects before completing a call */ public function errorAllPendingCalls() { foreach ($this->calls as $call) { $call->getCallerSession()->sendMessage(ErrorMessage::createErrorMessageFromMessage($call->getCallMessage(), 'wamp.error.canceled')); } }
public function __construct(ErrorMessage $error, \Exception $previous = null) { $this->errorUri = $error->getErrorURI(); $this->errorMessage = ucfirst(implode(': ', $error->getArguments())); parent::__construct($this->errorMessage, $error->getMsgCode(), $previous); }
/** * Process All Messages if the session has been authenticated * * @param \Thruway\Session $session * @param \Thruway\Message\Message $msg */ private function processAuthenticated(Session $session, Message $msg) { // authorization stuff here if ($msg instanceof ActionMessageInterface) { if (!$this->getAuthorizationManager()->isAuthorizedTo($session, $msg)) { Logger::alert($this, "Permission denied: " . $msg->getActionName() . " " . $msg->getUri() . " for " . $session->getAuthenticationDetails()->getAuthId()); $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.not_authorized")); return; } } $handled = false; foreach ($this->roles as $role) { if ($role->handlesMessage($msg)) { $role->onMessage($session, $msg); $handled = true; break; } } if (!$handled) { Logger::warning($this, "Unhandled message sent to \"{$this->getRealmName()}\""); } }
private function processInvocationError(Session $session, ErrorMessage $msg) { $call = $this->getCallByRequestId($msg->getRequestId()); if (!$call) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $this->manager->error('No call for invocation error message: ' . $msg->getRequestId()); // TODO: do we send a message back to the callee? $errorMsg->setErrorURI('wamp.error.no_such_procedure'); $session->sendMessage($errorMsg); return false; } $this->calls->detach($call); $errorMsg = ErrorMessage::createErrorMessageFromMessage($call->getCallMessage()); $errorMsg->setErrorURI($msg->getErrorURI()); $errorMsg->setArguments($msg->getArguments()); $errorMsg->setArgumentsKw($msg->getArgumentsKw()); $call->getCallerSession()->sendMessage($errorMsg); }
/** * @param Session $session * @param UnsubscribeMessage $msg * @return UnsubscribedMessage */ public function processUnsubscribe(Session $session, UnsubscribeMessage $msg) { $subscription = $this->getSubscriptionById($msg->getSubscriptionId()); if (!$subscription || !isset($this->topics[$subscription->getTopic()])) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $session->sendMessage($errorMsg->setErrorURI('wamp.error.no_such_subscription')); } $topicName = $subscription->getTopic(); $subscribers = $this->topics[$topicName]; /* @var $subscriber Session */ foreach ($this->topics[$topicName] as $key => $subscriber) { if ($subscriber == $session) { unset($subscribers[$key]); } } $this->subscriptions->detach($subscription); $session->sendMessage(new UnsubscribedMessage($msg->getRequestId())); }
/** * Handle error when unregister * * @param \Thruway\ClientSession $session * @param \Thruway\Message\ErrorMessage $msg */ public function handleErrorUnregister(ClientSession $session, ErrorMessage $msg) { foreach ($this->registrations as $key => $registration) { if (isset($registration['unregister_request_id'])) { if ($registration["unregister_request_id"] === $msg->getRequestId()) { /** @var Deferred $deferred */ $deferred = $registration['unregister_deferred']; $deferred->reject($msg); // I guess we get rid of the registration now? unset($this->registrations[$key]); break; } } } }
public function handleHelloMessage(Realm $realm, Session $session, HelloMessage $msg) { $requestedMethods = $msg->getAuthMethods(); $sentMessage = false; // go through our authMethods and see which one matches first foreach ($this->authMethods as $authMethod => $authMethodInfo) { if (in_array($authMethod, $requestedMethods) && (in_array($realm->getRealmName(), $authMethodInfo['auth_realms']) || in_array("*", $authMethodInfo['auth_realms']))) { // we can agree on something $authDetails = new AuthenticationDetails(); $authDetails->setAuthMethod($authMethod); $helloDetails = $msg->getDetails(); if (isset($helloDetails['authid'])) { $authDetails->setAuthId($helloDetails['authid']); } $session->setAuthenticationDetails($authDetails); $sessionInfo = array("sessionId" => $session->getSessionId(), "realm" => $realm->getRealmName()); $this->session->call($authMethodInfo['handlers']['onhello'], array($msg, $sessionInfo))->then(function ($res) use($session, $msg) { // this is handling the return of the onhello RPC call if (!is_array($res)) { $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg)); return; } if (count($res) < 2) { $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($msg)); return; } if ($res[0] == "CHALLENGE") { // TODO: validate challenge message $authMethod = $res[1]['challenge_method']; $challenge = $res[1]['challenge']; $session->getAuthenticationDetails()->setChallenge($challenge); $session->getAuthenticationDetails()->setChallengeDetails($res[1]); $session->sendMessage(new ChallengeMessage($authMethod, $session->getAuthenticationDetails()->getChallengeDetails())); } else { if ($res[0] == "NOCHALLENGE") { $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("authid" => $res[1]["authid"], "authmethod" => $session->getAuthenticationDetails()->getAuthMethod()))); } else { if ($res[0] == "ERROR") { $session->sendMessage(new AbortMessage(new \stdClass(), "authentication_failure")); } else { $session->sendMessage(new AbortMessage(new \stdClass(), "authentication_failure")); } } } }); $sentMessage = true; } } /* * If we've gotten this far without sending a message, it means that no auth methods were sent by the client or the auth method sent * by the client hasn't been registered for this realm, so we need to check if there are any auth providers registered for the realm. * If there are auth provides registered then Abort. Otherwise we can send a welcome message. */ if (!$sentMessage) { if ($this->realmHasAuthProvider($realm->getRealmName())) { $session->sendMessage(new AbortMessage(new \stdClass(), "realm_authorization_failure")); } else { //Logged in as anonymous $session->setAuthenticationDetails(AuthenticationDetails::createAnonymous()); $roles = array("broker" => new \stdClass(), "dealer" => new \stdClass()); $session->sendMessage(new WelcomeMessage($session->getSessionId(), array("roles" => $roles))); $session->setAuthenticated(true); } } }