// Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
namespace OpenTap.Package.Ipc
{
///
/// Used for sharing state information between processes. The data generated here is cleaned up automatically when all the processes uses it stops.
///
internal class SharedState : IDisposable
{
protected MemoryMappedFile share;
private Mutex appstateMutex;
private string filename;
public SharedState(string name, string dir)
{
if (dir == null)
throw new ArgumentNullException(nameof(dir));
filename = Path.GetFullPath(Path.Combine(dir, name)).Replace('\\', '/');
var hasher = SHA256.Create();
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(filename));
string mutexName = "OpenTap.Package " + BitConverter.ToString(hash).Replace("-", "");
appstateMutex = new Mutex(true, mutexName, out bool mutexCreated);
// if mutexCreated is true, it means that this was the first application to open it.
// Mutexes are automatically deleted when no application uses them anymore.
// when this happens, the state file is cleared by writing 0's to it.
// For AppState, this means that PID is 0 for the first application using it.
// the PID is used to block other applications from using it, for example by opening two package managers.
if (!mutexCreated)
appstateMutex.WaitOne();
var stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
share = MemoryMappedFile.CreateFromFile(stream, null, 1024, MemoryMappedFileAccess.ReadWrite, HandleInheritability.None, false);
if (mutexCreated)
using (var view = share.CreateViewAccessor())
view.WriteArray(0, new byte[1024], 0, 1024);
appstateMutex.ReleaseMutex();
}
public void Dispose()
{
if (share != null)
share.Dispose();
share = null;
if (appstateMutex != null)
appstateMutex.Dispose();
appstateMutex = null;
}
protected T Read(long position) where T : struct
{
T result = default(T);
using (var access = share.CreateViewAccessor())
access.Read(position, out result);
return result;
}
protected void Write(long position, T value) where T : struct
{
using (var access = share.CreateViewAccessor())
access.Write(position, ref value);
}
}
}