示例#1
0
文件: Format.cs 项目: romkatv/ChunkIO
        public static bool VerifyHash(byte[] array, ref int offset)
        {
            ulong expected = SipHash.ComputeHash(array, 0, offset);
            ulong actual   = UInt64LE.Read(array, ref offset);

            return(expected == actual);
        }
示例#2
0
文件: Format.cs 项目: romkatv/ChunkIO
        public bool ReadFrom(byte[] array)
        {
            Debug.Assert(array.Length >= Size);
            int   offset = 0;
            ulong pos    = UInt64LE.Read(array, ref offset);

            if (!Format.IsValidPosition(pos))
            {
                return(false);
            }
            ChunkBeginPosition = (long)pos;
            return(Format.VerifyHash(array, ref offset));
        }
示例#3
0
文件: Format.cs 项目: romkatv/ChunkIO
        public bool ReadFrom(byte[] array)
        {
            Debug.Assert(array.Length >= Size);
            int offset = 0;

            UserData = UserData.ReadFrom(array, ref offset);
            ulong len = UInt64LE.Read(array, ref offset);

            if (!Format.IsValidContentLength(len))
            {
                return(false);
            }
            ContentLength = (int)len;
            ContentHash   = UInt64LE.Read(array, ref offset);
            return(Format.VerifyHash(array, ref offset));
        }
示例#4
0
        // Returns:
        //
        //   * null if there is no listener associated with the file.
        //   * file length immediately after flushing (the flushing and the grabbing of the file length are
        //     done atomically) if there is a listener and the file was successfully flushed.
        //
        // Throws in all other cases. For example:
        //
        //   * The remote writer failed to flush because disk is full.
        //   * The remote writer sent invalid response to our request.
        //   * Pipe permission error.
        public static async Task <long?> FlushAsync(IReadOnlyCollection <byte> fileId, bool flushToDisk)
        {
            if (fileId == null)
            {
                throw new ArgumentNullException(nameof(fileId));
            }
            while (true)
            {
                using (var pipe = new NamedPipeClientStream(".", PipeName(fileId), PipeDirection.InOut,
                                                            PipeOptions.Asynchronous | PipeOptions.WriteThrough)) {
                    await s_connect.LockAsync();

                    try {
                        // NamedPipeClientStream has an awful API. It doesn't allow us to bail early if there is no pipe and
                        // to wait indefinitely if there is (this can be done with Win32 API). So we do it manually with
                        // a mutex existence check and a loop. We create this mutex together with the pipe to serve as
                        // a marker of the pipe's existence. It's difficult to use the pipe itself as such marker because
                        // server pipes disappear after accepting and serving a request and there may be a short gap before
                        // we create new server connections.
                        if (Mutex.TryOpenExisting(MutexName(fileId), MutexRights.Synchronize, out Mutex mutex))
                        {
                            mutex.Dispose();
                        }
                        else
                        {
                            return(null);
                        }
                        // The timeout is meant to avoid waiting forever if the pipe disappears between the moment
                        // we have verified its existence and our attempt to connect to it. We use a mutex to
                        // restrict the number of simultaneous ConnectAsync() because ConnectAsync() blocks a task
                        // thread for the whole duration of its execution. Without the mutex, WaitAsync() calls
                        // could block all task threads.
                        await pipe.ConnectAsync(100);
                    } catch (TimeoutException) {
                        continue;
                    } catch (IOException) {
                        continue;
                    } finally {
                        s_connect.Unlock(runNextSynchronously: false);
                    }
                    var buf = new byte[UInt64LE.Size];
                    if (flushToDisk)
                    {
                        buf[0] = 1;
                    }
                    try {
                        await pipe.WriteAsync(buf, 0, 1);

                        await pipe.FlushAsync();

                        if (await pipe.ReadAsync(buf, 0, UInt64LE.Size) != UInt64LE.Size)
                        {
                            continue;
                        }
                    } catch {
                        continue;
                    }
                    int   offset = 0;
                    ulong res    = UInt64LE.Read(buf, ref offset);
                    if (res < long.MaxValue)
                    {
                        return((long)res);
                    }
                    if (res == ulong.MaxValue)
                    {
                        throw new IOException("Remote writer failed to flush");
                    }
                    throw new Exception($"Invalid Flush response: {res}");
                }
            }
        }