/// <summary> /// Called when this RpcSession is connected to the socket. /// </summary> protected override void OnConnected() { // If this is a new session on the server, send the welcome message. if (BaseSocket.Mode == SocketMode.Server) { Server.ServerInfo.RequireAuthentication = Config.RequireAuthentication; var serializer = SerializationCache.Get(); serializer.MessageWriter.Write((byte)MqCommandType.RpcCommand); serializer.MessageWriter.Write((byte)RpcCommandType.WelcomeMessage); serializer.SerializeToWriter(Server.ServerInfo); var message = serializer.MessageWriter.ToMessage(true); message[0].FrameType = MqFrameType.Command; // RpcCommand:byte; RpcCommandType:byte; RpcServerInfoDataContract:byte[]; Send(message); } base.OnConnected(); // If the server does not require authentication, alert the server session that it is ready. if (BaseSocket.Mode == SocketMode.Server && Config.RequireAuthentication == false) { Authenticated = true; Ready?.Invoke(this, new SessionEventArgs <TSession, TConfig>((TSession)this)); } }
/// <summary> /// Processes an incoming command frame from the connection. /// Captures the call if it is a Rpc command. /// </summary> /// <param name="frame">Command frame to process.</param> protected override void ProcessCommand(MqFrame frame) { var commandType = (MqCommandType)frame.ReadByte(0); // If this is a base MqCommand, pass this directly on to the base command handler. if (commandType != MqCommandType.RpcCommand) { base.ProcessCommand(frame); return; } try { var rpcCommandType = (RpcCommandType)frame.ReadByte(1); if (rpcCommandType == RpcCommandType.WelcomeMessage) { // RpcCommand:byte; RpcCommandType:byte; RpcServerInfoDataContract:byte[]; // Ensure that this command is running on the client. if (BaseSocket.Mode != SocketMode.Client) { Close(SocketCloseReason.ProtocolError); return; } var serializer = SerializationCache.Get(new MqMessage(frame)); // Forward the reader two bytes to the data. serializer.MessageReader.ReadBytes(2); serializer.PrepareDeserializeReader(); // Try to read the information from the server about the server. Client.ServerInfo = serializer.DeserializeFromReader(typeof(RpcServerInfoDataContract)) as RpcServerInfoDataContract; if (Client.ServerInfo == null) { Close(SocketCloseReason.ProtocolError); return; } // Check to see if the server requires authentication. If so, send a auth check. if (Client.ServerInfo.RequireAuthentication) { var authArgs = new RpcAuthenticateEventArgs <TSession, TConfig>((TSession)this); // Start the authentication event to get the auth data. Authenticate?.Invoke(this, authArgs); serializer.MessageWriter.Write((byte)MqCommandType.RpcCommand); serializer.MessageWriter.Write((byte)RpcCommandType.AuthenticationRequest); if (authArgs.AuthData == null) { authArgs.AuthData = new byte[] { 0 }; } serializer.MessageWriter.Write(authArgs.AuthData, 0, authArgs.AuthData.Length); var authMessage = serializer.MessageWriter.ToMessage(true); authMessage[0].FrameType = MqFrameType.Command; _authTimeout = new Task(async() => { try { await Task.Delay(Config.ConnectionTimeout, _authTimeoutCancel.Token); } catch { return; } if (!_authTimeoutCancel.IsCancellationRequested) { Close(SocketCloseReason.TimeOut); } }); // RpcCommand:byte; RpcCommandType:byte; AuthData:byte[]; Send(authMessage); _authTimeout.Start(); } else { // If no authentication is required, set this client to authenticated. Authenticated = true; // Alert the server that this session is ready for usage. Task.Run( () => { Ready?.Invoke(this, new SessionEventArgs <TSession, TConfig>((TSession)this)); }); } SerializationCache.Put(serializer); } else if (rpcCommandType == RpcCommandType.AuthenticationRequest) { // RpcCommand:byte; RpcCommandType:byte; AuthData:byte[]; // If this is not run on the server, quit. if (BaseSocket.Mode != SocketMode.Server) { Close(SocketCloseReason.ProtocolError); return; } // Ensure that the server requires authentication. if (Server.Config.RequireAuthentication == false) { Close(SocketCloseReason.ProtocolError); return; } byte[] authBytes = new byte[frame.DataLength - 2]; frame.Read(2, authBytes, 0, authBytes.Length); var authArgs = new RpcAuthenticateEventArgs <TSession, TConfig>((TSession)this) { AuthData = authBytes }; Authenticate?.Invoke(this, authArgs); Authenticated = authArgs.Authenticated; if (Authenticated == false) { Close(SocketCloseReason.AuthenticationFailure); } else { var authFrame = CreateFrame(new byte[authArgs.AuthData.Length + 2], MqFrameType.Command); authFrame.Write(0, (byte)MqCommandType.RpcCommand); authFrame.Write(1, (byte)RpcCommandType.AuthenticationResult); // State of the authentication authFrame.Write(2, Authenticated); // RpcCommand:byte; RpcCommandType:byte; AuthResult:bool; Send(authFrame); // Alert the server that this session is ready for usage. Task.Run( () => { Ready?.Invoke(this, new SessionEventArgs <TSession, TConfig>((TSession)this)); }); } } else if (rpcCommandType == RpcCommandType.AuthenticationResult) { // RpcCommand:byte; RpcCommandType:byte; AuthResult:bool; // Cancel the timeout request. _authTimeoutCancel.Cancel(); // Ensure that this command is running on the client. if (BaseSocket.Mode != SocketMode.Client) { Close(SocketCloseReason.ProtocolError); return; } if (Client.Config.RequireAuthentication == false) { Close(SocketCloseReason.ProtocolError); return; } Authenticated = true; var authArgs = new RpcAuthenticateEventArgs <TSession, TConfig>((TSession)this) { Authenticated = frame.ReadBoolean(2) }; // Alert the client that the sesion has been authenticated. AuthenticationSuccess?.Invoke(this, authArgs); // Alert the client that this session is ready for usage. Task.Run(() => { Ready?.Invoke(this, new SessionEventArgs <TSession, TConfig>((TSession)this)); }); } else { Close(SocketCloseReason.ProtocolError); } } catch (Exception) { Close(SocketCloseReason.ProtocolError); } }