Пример #1
0
 private static bool ImportVersions(Area ws, ClientStateInfo clientInfo)
 {
     lock (ws)
     {
         var versionsToImport = clientInfo.SharedInfo.PushedVersions.OrderBy(x => x.Version.Timestamp).ToArray();
         Dictionary<Guid, bool> importList = new Dictionary<Guid, bool>();
         foreach (var x in versionsToImport)
             importList[x.Version.ID] = false;
         int importCount = versionsToImport.Length;
         var orderedImports = versionsToImport.OrderBy(x => x.Version.Revision).ToList();
         while (importCount > 0)
         {
             foreach (var x in orderedImports)
             {
                 if (importList[x.Version.ID] != true)
                 {
                     bool accept;
                     if (!x.Version.Parent.HasValue || !importList.TryGetValue(x.Version.Parent.Value, out accept))
                         accept = true;
                     if (accept)
                     {
                         ws.ImportVersionNoCommit(clientInfo.SharedInfo, x, true);
                         importList[x.Version.ID] = true;
                         importCount--;
                     }
                 }
             }
         }
         foreach (var x in clientInfo.MergeVersions)
             ws.ImportVersionNoCommit(clientInfo.SharedInfo, x, false);
         foreach (var x in clientInfo.UpdatedHeads)
             ws.ImportHeadNoCommit(x);
         return true;
     }
 }
Пример #2
0
 private static bool AcceptHeads(ClientStateInfo clientInfo, Area ws, out string errorData)
 {
     SharedNetwork.ImportBranches(clientInfo.SharedInfo);
     Dictionary<Guid, Head> temporaryHeads = new Dictionary<Guid, Head>();
     Dictionary<Guid, Guid> pendingMerges = new Dictionary<Guid, Guid>();
     Dictionary<Guid, HashSet<Guid>> headAncestry = new Dictionary<Guid, HashSet<Guid>>();
     foreach (var x in clientInfo.SharedInfo.PushedVersions)
     {
         Branch branch = ws.GetBranch(x.Version.Branch);
         Head head;
         if (!temporaryHeads.TryGetValue(branch.ID, out head))
         {
             var heads = ws.GetBranchHeads(branch);
             if (heads.Count == 0)
                 head = new Head() { Branch = branch.ID, Version = x.Version.ID };
             else if (heads.Count == 1)
                 head = heads[0];
             else
             {
                 // ???
                 Printer.PrintError("OMG 1");
                 errorData = string.Format("Multiple ({0}) heads for branch {1}", heads.Count, branch.ID);
                 return false;
             }
             temporaryHeads[branch.ID] = head;
         }
         if (head.Version != x.Version.ID)
         {
             HashSet<Guid> headAncestors = null;
             if (!headAncestry.TryGetValue(head.Version, out headAncestors))
             {
                 headAncestors = SharedNetwork.GetAncestry(head.Version, clientInfo.SharedInfo);
                 headAncestry[head.Version] = headAncestors;
             }
             if (headAncestors.Contains(x.Version.ID))
             {
                 // all best
             }
             else if (SharedNetwork.IsAncestor(head.Version, x.Version.ID, clientInfo.SharedInfo))
             {
                 headAncestry.Remove(head.Version);
                 pendingMerges[branch.ID] = Guid.Empty;
                 head.Version = x.Version.ID;
             }
             else if (!SharedNetwork.IsAncestor(x.Version.ID, head.Version, clientInfo.SharedInfo))
             {
                 headAncestry.Remove(head.Version);
                 pendingMerges[branch.ID] = head.Version;
                 head.Version = x.Version.ID;
             }
         }
     }
     foreach (var x in pendingMerges)
     {
         if (x.Value == Guid.Empty)
         {
             Printer.PrintDiagnostics("Uncontested head update for branch \"{0}\".", ws.GetBranch(x.Key).Name);
             Printer.PrintDiagnostics(" - Head updated to {0}", temporaryHeads[x.Key].Version);
             continue;
         }
         Branch branch = ws.GetBranch(x.Key);
         VersionInfo result;
         string error;
         result = ws.MergeRemote(ws.GetLocalOrRemoteVersion(x.Value, clientInfo.SharedInfo), temporaryHeads[x.Key].Version, clientInfo.SharedInfo, out error);
         if (result == null)
         {
             // safe merge?
             Printer.PrintError("OMG 2");
             errorData = string.Format("Can't automatically merge data - multiple heads in branch \'{0}\'.\nAttempted merge result: {1}", branch.Name, error);
             return false;
         }
         else
         {
             clientInfo.MergeVersions.Add(result);
             Printer.PrintMessage("Resolved incoming merge for branch \"{0}\".", branch.Name);
             Printer.PrintDiagnostics(" - Merge local input {0}", x.Value);
             Printer.PrintDiagnostics(" - Merge remote input {0}", temporaryHeads[x.Key].Version);
             Printer.PrintDiagnostics(" - Head updated to {0}", result.Version.ID);
             temporaryHeads[x.Key].Version = result.Version.ID;
         }
     }
     // theoretically best
     clientInfo.UpdatedHeads = temporaryHeads;
     errorData = string.Empty;
     return true;
 }
Пример #3
0
        static void HandleConnection(System.IO.DirectoryInfo info, TcpClient client)
        {
            Area ws = null;
            ClientStateInfo clientInfo = new ClientStateInfo();
            using (client)
            using (SharedNetwork.SharedNetworkInfo sharedInfo = new SharedNetwork.SharedNetworkInfo())
            {
                try
                {
                    var stream = client.GetStream();
                    Handshake hs = ProtoBuf.Serializer.DeserializeWithLengthPrefix<Handshake>(stream, ProtoBuf.PrefixStyle.Fixed32);
                    DomainInfo domainInfo = null;
                    lock (SyncObject)
                    {
                        if (hs.RequestedModule == null)
                            hs.RequestedModule = string.Empty;
                        if (!Domains.TryGetValue(hs.RequestedModule, out domainInfo))
                        {
                            domainInfo = Domains.Where(x => x.Key.Equals(hs.RequestedModule, StringComparison.OrdinalIgnoreCase)).Select(x => x.Value).FirstOrDefault();
                        }
                        if (domainInfo == null)
                        {
                            if (!Config.AllowVaultCreation || !Config.RequiresAuthentication || string.IsNullOrEmpty(hs.RequestedModule) || System.IO.Directory.Exists(System.IO.Path.Combine(info.FullName, hs.RequestedModule)))
                            {
                                Network.StartTransaction startSequence = Network.StartTransaction.CreateRejection();
                                Printer.PrintDiagnostics("Rejecting client due to invalid domain: \"{0}\".", hs.RequestedModule);
                                ProtoBuf.Serializer.SerializeWithLengthPrefix<Network.StartTransaction>(stream, startSequence, ProtoBuf.PrefixStyle.Fixed32);
                                return;
                            }
                            domainInfo = new DomainInfo()
                            {
                                Bare = true,
                                Directory = null
                            };
                        }
                    }
                    try
                    {
                        ws = Area.Load(domainInfo.Directory, true, true);
                        if (domainInfo.Bare)
                            throw new Exception("Domain is bare, but workspace could be loaded!");
                    }
                    catch
                    {
                        if (!domainInfo.Bare)
                            throw new Exception("Domain not bare, but couldn't load workspace!");
                    }
                    Printer.PrintDiagnostics("Received handshake - protocol: {0}", hs.VersionrProtocol);
                    SharedNetwork.Protocol? clientProtocol = hs.CheckProtocol();
                    bool valid = true;
                    if (clientProtocol == null)
                        valid = false;
                    else
                    {
                        valid = SharedNetwork.AllowedProtocols.Contains(clientProtocol.Value);
                        if (Config.RequiresAuthentication && !SharedNetwork.SupportsAuthentication(clientProtocol.Value))
                            valid = false;
                    }
                    if (valid)
                    {
                        sharedInfo.CommunicationProtocol = clientProtocol.Value;
                        Network.StartTransaction startSequence = null;
                        clientInfo.Access = Rights.Read | Rights.Write;
                        clientInfo.BareAccessRequired = domainInfo.Bare;
                        if (PrivateKey != null)
                        {
                            startSequence = Network.StartTransaction.Create(domainInfo.Bare ? string.Empty : ws.Domain.ToString(), PublicKey, clientProtocol.Value);
                            Printer.PrintDiagnostics("Sending RSA key...");
                            ProtoBuf.Serializer.SerializeWithLengthPrefix<Network.StartTransaction>(stream, startSequence, ProtoBuf.PrefixStyle.Fixed32);
                            if (!HandleAuthentication(clientInfo, client, sharedInfo))
                                throw new Exception("Authentication failed.");
                            StartClientTransaction clientKey = ProtoBuf.Serializer.DeserializeWithLengthPrefix<StartClientTransaction>(stream, ProtoBuf.PrefixStyle.Fixed32);
                            System.Security.Cryptography.RSAOAEPKeyExchangeDeformatter exch = new System.Security.Cryptography.RSAOAEPKeyExchangeDeformatter(PrivateKey);
                            byte[] aesKey = exch.DecryptKeyExchange(clientKey.Key);
                            byte[] aesIV = exch.DecryptKeyExchange(clientKey.IV);
                            Printer.PrintDiagnostics("Got client key: {0}", System.Convert.ToBase64String(aesKey));

                            var aesCSP = System.Security.Cryptography.AesManaged.Create();

                            sharedInfo.DecryptorFunction = () => { return aesCSP.CreateDecryptor(aesKey, aesIV); };
                            sharedInfo.EncryptorFunction = () => { return aesCSP.CreateEncryptor(aesKey, aesIV); };
                        }
                        else
                        {
                            startSequence = Network.StartTransaction.Create(domainInfo.Bare ? string.Empty : ws.Domain.ToString(), clientProtocol.Value);
                            ProtoBuf.Serializer.SerializeWithLengthPrefix<Network.StartTransaction>(stream, startSequence, ProtoBuf.PrefixStyle.Fixed32);
                            if (!HandleAuthentication(clientInfo, client, sharedInfo))
                                throw new Exception("Authentication failed.");
                            StartClientTransaction clientKey = ProtoBuf.Serializer.DeserializeWithLengthPrefix<StartClientTransaction>(stream, ProtoBuf.PrefixStyle.Fixed32);
                        }
                        sharedInfo.Stream = stream;
                        sharedInfo.Workspace = ws;
                        sharedInfo.ChecksumType = Config.ChecksumType;

                        clientInfo.SharedInfo = sharedInfo;

                        while (true)
                        {
                            NetCommand command = ProtoBuf.Serializer.DeserializeWithLengthPrefix<NetCommand>(stream, ProtoBuf.PrefixStyle.Fixed32);
                            if (command.Type == NetCommandType.Close)
                            {
                                Printer.PrintDiagnostics("Client closing connection.");
                                break;
                            }
                            else if (command.Type == NetCommandType.PushInitialVersion)
                            {
                                bool fresh = false;
                                if (domainInfo.Directory == null)
                                {
                                    if (!clientInfo.Access.HasFlag(Rights.Create))
                                        throw new Exception("Access denied.");
                                    fresh = true;
                                    System.IO.DirectoryInfo newDirectory = new System.IO.DirectoryInfo(System.IO.Path.Combine(info.FullName, hs.RequestedModule));
                                    newDirectory.Create();
                                    domainInfo.Directory = newDirectory;
                                    if (!newDirectory.Exists)
                                        throw new Exception("Access denied.");
                                }
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                lock (SyncObject)
                                {
                                    ws = Area.InitRemote(domainInfo.Directory, Utilities.ReceiveEncrypted<ClonePayload>(clientInfo.SharedInfo));
                                    clientInfo.SharedInfo.Workspace = ws;
                                    domainInfo.Bare = false;
                                    if (fresh)
                                        Domains[hs.RequestedModule] = domainInfo;
                                }
                            }
                            else if (command.Type == NetCommandType.PushBranchJournal)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                SharedNetwork.ReceiveBranchJournal(sharedInfo);
                            }
                            else if (command.Type == NetCommandType.QueryBranchID)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client is requesting a branch info for {0}", string.IsNullOrEmpty(command.AdditionalPayload) ? "<root>" : "\"" + command.AdditionalPayload + "\"");
                                bool multiple = false;
                                Objects.Branch branch = string.IsNullOrEmpty(command.AdditionalPayload) ? ws.RootBranch : ws.GetBranchByPartialName(command.AdditionalPayload, out multiple);
                                if (branch != null)
                                {
                                    ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Acknowledge, AdditionalPayload = branch.ID.ToString() }, ProtoBuf.PrefixStyle.Fixed32);
                                }
                                else if (!multiple)
                                {
                                    ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Error, AdditionalPayload = "branch not recognized" }, ProtoBuf.PrefixStyle.Fixed32);
                                }
                                else
                                {
                                    ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Error, AdditionalPayload = "multiple branches with that name!" }, ProtoBuf.PrefixStyle.Fixed32);
                                }
                            }
                            else if (command.Type == NetCommandType.ListBranches)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client is requesting a branch list.");
                                ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Acknowledge }, ProtoBuf.PrefixStyle.Fixed32);
                                if (command.Identifier == 1) // send extra data
                                {
                                    BranchList bl = new BranchList();
                                    bl.Branches = clientInfo.SharedInfo.Workspace.Branches.ToArray();
                                    Dictionary<Guid, Objects.Version> importantVersions = new Dictionary<Guid, Objects.Version>();
                                    List<KeyValuePair<Guid, Guid>> allHeads = new List<KeyValuePair<Guid, Guid>>();
                                    foreach (var x in bl.Branches)
                                    {
                                        if (x.Terminus.HasValue && !importantVersions.ContainsKey(x.Terminus.Value))
                                        {
                                            importantVersions[x.Terminus.Value] = clientInfo.SharedInfo.Workspace.GetVersion(x.Terminus.Value);
                                            continue;
                                        }
                                        var heads = clientInfo.SharedInfo.Workspace.GetBranchHeads(x);
                                        foreach (var head in heads)
                                        {
                                            if (!importantVersions.ContainsKey(head.Version))
                                                importantVersions[head.Version] = clientInfo.SharedInfo.Workspace.GetVersion(head.Version);
                                        }
                                        allHeads.AddRange(heads.Select(y => new KeyValuePair<Guid, Guid>(y.Branch, y.Version)));
                                    }
                                    bl.Heads = allHeads.ToArray();
                                    bl.ImportantVersions = importantVersions.Values.ToArray();
                                    Utilities.SendEncrypted<BranchList>(clientInfo.SharedInfo, bl);
                                }
                                else
                                {
                                    BranchList bl = new BranchList();
                                    bl.Branches = clientInfo.SharedInfo.Workspace.Branches.ToArray();
                                    List<KeyValuePair<Guid, Guid>> allHeads = new List<KeyValuePair<Guid, Guid>>();
                                    foreach (var x in bl.Branches)
                                    {
                                        if (x.Terminus.HasValue)
                                            continue;
                                        var heads = clientInfo.SharedInfo.Workspace.GetBranchHeads(x);
                                        if (heads.Count == 1)
                                            allHeads.Add(new KeyValuePair<Guid, Guid>(x.ID, heads[0].Version));
                                    }
                                    bl.Heads = allHeads.ToArray();
                                    Utilities.SendEncrypted<BranchList>(clientInfo.SharedInfo, bl);
                                }
                            }
                            else if (command.Type == NetCommandType.RequestRecordUnmapped)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client is requesting specific record data blobs.");
                                SharedNetwork.SendRecordDataUnmapped(sharedInfo);
                            }
                            else if (command.Type == NetCommandType.Clone)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client is requesting to clone the vault.");
                                Objects.Version initialRevision = ws.GetVersion(ws.Domain);
                                Objects.Branch initialBranch = ws.GetBranch(initialRevision.Branch);
                                Utilities.SendEncrypted<ClonePayload>(sharedInfo, new ClonePayload() { InitialBranch = initialBranch, RootVersion = initialRevision });
                            }
                            else if (command.Type == NetCommandType.PullVersions)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client asking for remote version information.");
                                Branch branch = ws.GetBranch(new Guid(command.AdditionalPayload));
                                if (branch == null)
                                    ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Error, AdditionalPayload = string.Format("Unknown branch {0}", command.AdditionalPayload) }, ProtoBuf.PrefixStyle.Fixed32);
                                else
                                    ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Acknowledge }, ProtoBuf.PrefixStyle.Fixed32);
                                Stack<Objects.Branch> branchesToSend = new Stack<Branch>();
                                Stack<Objects.Version> versionsToSend = new Stack<Objects.Version>();
                                if (!SharedNetwork.SendBranchJournal(sharedInfo))
                                    throw new Exception();
                                if (!SharedNetwork.GetVersionList(sharedInfo, sharedInfo.Workspace.GetBranchHeadVersion(branch), out branchesToSend, out versionsToSend))
                                    throw new Exception();
                                if (!SharedNetwork.SendBranches(sharedInfo, branchesToSend))
                                    throw new Exception();
                                if (!SharedNetwork.SendVersions(sharedInfo, versionsToSend))
                                    throw new Exception();
                            }
                            else if (command.Type == NetCommandType.PushObjectQuery)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client asking about objects on the server...");
                                SharedNetwork.ProcesPushObjectQuery(sharedInfo);
                            }
                            else if (command.Type == NetCommandType.PushBranch)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client attempting to send branch data...");
                                SharedNetwork.ReceiveBranches(sharedInfo);
                            }
                            else if (command.Type == NetCommandType.PushVersions)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Client attempting to send version data...");
                                SharedNetwork.ReceiveVersions(sharedInfo);
                            }
                            else if (command.Type == NetCommandType.PushHead)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Write))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Determining head information.");
                                string errorData;
                                lock (ws)
                                {
                                    clientInfo.SharedInfo.Workspace.RunLocked(() =>
                                    {
                                        try
                                        {
                                            clientInfo.SharedInfo.Workspace.BeginDatabaseTransaction();
                                            if (!SharedNetwork.ImportBranchJournal(clientInfo.SharedInfo, false))
                                            {
                                                clientInfo.SharedInfo.Workspace.RollbackDatabaseTransaction();
                                                return false;
                                            }
                                            if (AcceptHeads(clientInfo, ws, out errorData))
                                            {
                                                ImportVersions(ws, clientInfo);
                                                clientInfo.SharedInfo.Workspace.CommitDatabaseTransaction();
                                                ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.AcceptPush }, ProtoBuf.PrefixStyle.Fixed32);
                                                return true;
                                            }
                                            else
                                                ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.RejectPush, AdditionalPayload = errorData }, ProtoBuf.PrefixStyle.Fixed32);
                                            clientInfo.SharedInfo.Workspace.RollbackDatabaseTransaction();
                                            return false;
                                        }
                                        catch
                                        {
                                            clientInfo.SharedInfo.Workspace.RollbackDatabaseTransaction();
                                            return false;
                                        }
                                    }, false);
                                }
                            }
                            else if (command.Type == NetCommandType.SynchronizeRecords)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                Printer.PrintDiagnostics("Received {0} versions in version pack, but need {1} records to commit data.", sharedInfo.PushedVersions.Count, sharedInfo.UnknownRecords.Count);
                                Printer.PrintDiagnostics("Beginning record synchronization...");
                                if (sharedInfo.UnknownRecords.Count > 0)
                                {
                                    Printer.PrintDiagnostics("Requesting record metadata...");
                                    SharedNetwork.RequestRecordMetadata(clientInfo.SharedInfo);
                                    Printer.PrintDiagnostics("Requesting record data...");
                                    SharedNetwork.RequestRecordData(sharedInfo);
                                    if (!sharedInfo.Workspace.RunLocked(() =>
                                    {
                                        return SharedNetwork.ImportRecords(sharedInfo);
                                    }, false))
                                    {
                                        throw new Exception("Unable to import records!");
                                    }
                                }
                                ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Synchronized }, ProtoBuf.PrefixStyle.Fixed32);
                            }
                            else if (command.Type == NetCommandType.FullClone)
                            {
                                if (!clientInfo.Access.HasFlag(Rights.Read))
                                    throw new Exception("Access denied.");
                                ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Acknowledge, Identifier = (int)ws.DatabaseVersion }, ProtoBuf.PrefixStyle.Fixed32);
                                command = ProtoBuf.Serializer.DeserializeWithLengthPrefix<NetCommand>(stream, ProtoBuf.PrefixStyle.Fixed32);
                                if (command.Type == NetCommandType.Acknowledge)
                                {
                                    bool accept = false;
                                    BackupInfo backupInfo = null;
                                    lock (domainInfo)
                                    {
                                        string backupKey = ws.LastVersion + "-" + ws.LastBranch + "-" + ws.BranchJournalTipID.ToString();
                                        backupInfo = domainInfo.Backup;
                                        if (backupKey != backupInfo.Key)
                                        {
                                            Printer.PrintMessage("Backup key out of date for domain DB[{0}] - {1}", domainInfo.Directory, backupKey);
                                            if (System.Threading.Interlocked.Decrement(ref backupInfo.Refs) == 0)
                                                backupInfo.Backup.Delete();
                                            backupInfo = new BackupInfo();
                                            domainInfo.Backup = backupInfo;
                                            var directory = new System.IO.DirectoryInfo(System.IO.Path.Combine(ws.AdministrationFolder.FullName, "backups"));
                                            directory.Create();
                                            backupInfo.Backup = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, System.IO.Path.GetRandomFileName()));
                                            if (ws.BackupDB(backupInfo.Backup))
                                            {
                                                System.Threading.Interlocked.Increment(ref backupInfo.Refs);
                                                accept = true;
                                                backupInfo.Key = backupKey;
                                            }
                                        }
                                        else
                                        {
                                            accept = true;
                                        }

                                        if (accept)
                                            System.Threading.Interlocked.Increment(ref backupInfo.Refs);
                                    }
                                    if (accept)
                                    {
                                        Printer.PrintDiagnostics("Backup complete. Sending data.");
                                        byte[] blob = new byte[256 * 1024];
                                        long filesize = backupInfo.Backup.Length;
                                        long position = 0;
                                        using (System.IO.FileStream reader = backupInfo.Backup.OpenRead())
                                        {
                                            while (true)
                                            {
                                                long remainder = filesize - position;
                                                int count = blob.Length;
                                                if (count > remainder)
                                                    count = (int)remainder;
                                                reader.Read(blob, 0, count);
                                                position += count;
                                                Printer.PrintDiagnostics("Sent {0}/{1} bytes.", position, filesize);
                                                if (count == remainder)
                                                {
                                                    Utilities.SendEncrypted(sharedInfo, new DataPayload()
                                                    {
                                                        Data = blob.Take(count).ToArray(),
                                                        EndOfStream = true
                                                    });
                                                    break;
                                                }
                                                else
                                                {
                                                    Utilities.SendEncrypted(sharedInfo, new DataPayload()
                                                    {
                                                        Data = blob,
                                                        EndOfStream = false
                                                    });
                                                }
                                            }
                                        }
                                        ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Acknowledge }, ProtoBuf.PrefixStyle.Fixed32);
                                        lock (domainInfo)
                                        {
                                            if (System.Threading.Interlocked.Decrement(ref backupInfo.Refs) == 0)
                                                backupInfo.Backup.Delete();
                                        }
                                    }
                                    else
                                    {
                                        Utilities.SendEncrypted<DataPayload>(sharedInfo, new DataPayload() { Data = new byte[0], EndOfStream = true });
                                        ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(stream, new NetCommand() { Type = NetCommandType.Error }, ProtoBuf.PrefixStyle.Fixed32);
                                    }
                                }
                            }
                            else
                            {
                                Printer.PrintDiagnostics("Client sent invalid command: {0}", command.Type);
                                throw new Exception();
                            }
                        }
                    }
                    else
                    {
                        Network.StartTransaction startSequence = Network.StartTransaction.CreateRejection();
                        Printer.PrintDiagnostics("Rejecting client due to protocol mismatch.");
                        ProtoBuf.Serializer.SerializeWithLengthPrefix<Network.StartTransaction>(stream, startSequence, ProtoBuf.PrefixStyle.Fixed32);
                        return;
                    }
                }
                catch (Exception e)
                {
                    Printer.PrintDiagnostics("Client was a terrible person, because: {0}", e);
                }
                finally
                {
                    if (ws != null)
                        ws.Dispose();
                }
            }

            Printer.PrintDiagnostics("Ended client processor task!");
        }
Пример #4
0
 private static bool HandleAuthentication(ClientStateInfo clientInfo, TcpClient client, SharedNetwork.SharedNetworkInfo sharedInfo)
 {
     if (Config.RequiresAuthentication)
     {
         int flags = ((Config.AllowUnauthenticatedWrite ? 2 : 0) | (Config.AllowUnauthenticatedRead ? 1 : 0));
         if (clientInfo.BareAccessRequired)
             flags = 0;
         ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.Authenticate, Identifier = flags }, ProtoBuf.PrefixStyle.Fixed32);
         AuthenticationChallenge challenge = new AuthenticationChallenge();
         challenge.AvailableModes = new List<AuthenticationMode>();
         if (Config.SupportsSimpleAuthentication)
             challenge.AvailableModes.Add(AuthenticationMode.Simple);
         challenge.Salt = BCrypt.Net.BCrypt.GenerateSalt();
         ProtoBuf.Serializer.SerializeWithLengthPrefix(client.GetStream(), challenge, ProtoBuf.PrefixStyle.Fixed32);
         int retries = Config.AuthenticationAttempts;
         bool success = false;
         while (true)
         {
             var response = ProtoBuf.Serializer.DeserializeWithLengthPrefix<AuthenticationResponse>(client.GetStream(), ProtoBuf.PrefixStyle.Fixed32);
             Rights accessRights;
             if (CheckAuthentication(response, challenge.Salt, out accessRights))
             {
                 clientInfo.Access = accessRights;
                 success = true;
                 break;
             }
             else
             {
                 if (--retries == 0)
                     break;
                 ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.AuthRetry }, ProtoBuf.PrefixStyle.Fixed32);
             }
         }
         if (success)
             ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.Acknowledge }, ProtoBuf.PrefixStyle.Fixed32);
         else
         {
             ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.AuthFail }, ProtoBuf.PrefixStyle.Fixed32);
             return false;
         }
     }
     else
     {
         ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.SkipAuthentication }, ProtoBuf.PrefixStyle.Fixed32);
     }
     return true;
 }
Пример #5
0
 public static ClientState Create(ClientStateInfo state)
 {
     return(new ClientState(state.Id, state.Status, state.StatusDate, state.EncounterId, state.IndexClientId));
 }