void InitSocket(IWebSocketConnection socket) { socket.OnOpen = delegate() { KeePassRPCPlugin.AddRPCClientConnection(socket); }; socket.OnClose = delegate() { KeePassRPCPlugin.RemoveRPCClientConnection(socket); }; socket.OnMessage = delegate(string message) { KeePassRPCPlugin.MessageRPCClientConnection(socket, message, Service); }; }
void InitSocket(IWebSocketConnection socket) { socket.OnOpen = delegate() { // Immediately reject connections with unexpected origins if (!ValidateOrigin(socket.ConnectionInfo.Origin)) { if (KeePassRPCPlugin.logger != null) { try { KeePassRPCPlugin.logger.WriteLine(socket.ConnectionInfo.Origin + " is not permitted to access KeePassRPC."); } catch (Exception) { // Don't care } } } else { KeePassRPCPlugin.AddRPCClientConnection(socket); } }; socket.OnClose = delegate() { KeePassRPCPlugin.RemoveRPCClientConnection(socket); }; socket.OnMessage = delegate(string message) { KeePassRPCPlugin.MessageRPCClientConnection(socket, message, Service); }; }
/// <summary> /// Handles the client communication /// </summary> /// <param name="client">The client.</param> private void HandleClientComm(object client) { KeePassRPCClientConnection keePassRPCClient = null; TcpClient tcpClient = null; NetworkStream clientStream = null; SslStream sslStream = null; if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("HandleClientComm: "); } if (_useSSL) { // A client has connected. Create the // SslStream using the client's network stream. ServicePointManager.ServerCertificateValidationCallback = delegate { return(true); }; sslStream = new SslStream(((TcpClient)client).GetStream(), false);//, new RemoteCertificateValidationCallback (ValidateServerCertificate), // new LocalCertificateSelectionCallback(SelectLocalCertificate) // ); } else { tcpClient = (TcpClient)client; clientStream = tcpClient.GetStream(); } if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("stream ready to be authenticated"); } try { if (_useSSL) { // Authenticate the server but don't require the client to // authenticate - we've got our own authentication requirements sslStream.AuthenticateAsServer( _serverCertificate, false, SslProtocols.Ssl3 | SslProtocols.Tls, false); if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("stream authenticated"); } sslStream.ReadTimeout = -1; sslStream.WriteTimeout = -1; } else { clientStream.ReadTimeout = -1; clientStream.WriteTimeout = -1; } byte[] message = new byte[4096]; int bytesRead; //bool authorised = false; //TODO2: creation of this client probably should happen later // but we need to know that this connection needs to be closed // during shutdown, even if the client never // successfully authenticates. keePassRPCClient = _useSSL ? new KeePassRPCClientConnection(sslStream, false) : new KeePassRPCClientConnection(tcpClient, false); KeePassRPCPlugin.AddRPCClientConnection(keePassRPCClient); // send an "invitation to authenticate" to the new RPC client keePassRPCClient.Signal(KeePassRPC.DataExchangeModel.Signal.PLEASE_AUTHENTICATE, "KPRPCListener"); int tokenCurlyCount = 0; int tokenSquareCount = 0; int adjacentBackslashCount = 0; bool parsingStringContents = false; StringBuilder currentJSONPacket = new StringBuilder(50); // Keep reading data from the network stream whenever it's available while (true) { bytesRead = 0; try { //blocks until a client sends a message bytesRead = _useSSL ? sslStream.Read(message, 0, 4096) : clientStream.Read(message, 0, 4096); } catch (Exception ex) { if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("a socket error has occured:" + ex.ToString()); } break; } if (bytesRead == 0) { //the client has disconnected from the server break; } // Can we ever receive a partial UTF8 character? if so, this could go wrong, albeit rarely string receivedData = System.Text.Encoding.UTF8.GetString(message, 0, bytesRead); int jsonPacketStartIndex = 0; for (int i = 0; i < receivedData.Length; i++) { bool incrementAdjacentBackslashCount = false; // Use the simple structure of JSON-RPC to extract // complete messages from the network stream switch (receivedData[i]) { case TOKEN_QUOT: if (adjacentBackslashCount % 2 == 0) { parsingStringContents = parsingStringContents ? false : true; } break; case TOKEN_BACKSLASH: incrementAdjacentBackslashCount = true; break; case TOKEN_CURLY_START: if (!parsingStringContents) { tokenCurlyCount++; } break; case TOKEN_CURLY_END: if (!parsingStringContents) { tokenCurlyCount--; } break; case TOKEN_SQUARE_START: if (!parsingStringContents) { tokenSquareCount++; } break; case TOKEN_SQUARE_END: if (!parsingStringContents) { tokenSquareCount--; } break; } if (incrementAdjacentBackslashCount) { adjacentBackslashCount++; } else { adjacentBackslashCount = 0; } // When both counts are zero, we know we have // reached the end of a JSON-RPC request if (tokenCurlyCount == 0 && tokenSquareCount == 0) { currentJSONPacket.Append(receivedData.Substring( jsonPacketStartIndex, i - jsonPacketStartIndex + 1)); DispatchToRPCService(currentJSONPacket.ToString(), keePassRPCClient); currentJSONPacket = new StringBuilder(50); jsonPacketStartIndex = i + 1; } } // If the JSON request is not complete we store what we have already found if (tokenCurlyCount != 0 || tokenSquareCount != 0) { currentJSONPacket.Append(receivedData); } // http://groups.google.com/group/jayrock/browse_thread/thread/59cf6a58bc63f0df/a7775c3097cf6957?lnk=gst&q=thread+JsonRpcDispatcher+#a7775c3097cf6957 } } catch (AuthorisationException authEx) { // Send a JSON message down the pipe byte[] bytes = System.Text.Encoding.UTF8.GetBytes(authEx.AsJSONResult()); keePassRPCClient.ConnectionStreamWrite(bytes); } catch (AuthenticationException ex) { if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("Authentication exception: " + ex.ToString()); } // Nothing we can do about this since client can't // receive messages over an invalid network stream } catch (Exception e) { if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("Unknown exception: " + e.ToString()); } //TODO2: send a JSON message down the pipe // ex.AsJSONResult(); } finally { if (KeePassRPCPlugin.logger != null) { KeePassRPCPlugin.logger.WriteLine("!!!Hit finally"); } if (keePassRPCClient != null) { KeePassRPCPlugin.RemoveRPCClientConnection(keePassRPCClient); } if (_useSSL) { try { sslStream.Close(); } catch (IOException ioex) { // This is okay } } else { clientStream.Close(); } } }