~ruther/NosSmooth

ref: de0af0c3f6152efd9be9b110eb628e05db03f202 NosSmooth/Pcap/NosSmooth.Pcap/ProcessTcpManager.cs -rw-r--r-- 3.5 KiB
de0af0c3 — František Boháček feat(pcap): pass ethernet packet to OnPacketArrival 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//
//  ProcessTcpManager.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics;
using Microsoft.Extensions.Options;

namespace NosSmooth.Pcap;

/// <summary>
/// A manager containing tcp connections, allowing notifications
/// to <see cref="PcapNostaleClient"/> to know about any new connections.
/// </summary>
public class ProcessTcpManager
{
    private readonly PcapNostaleOptions _options;

    private readonly SemaphoreSlim _semaphore;
    private readonly List<int> _processes;
    private DateTimeOffset _lastRefresh;
    private IReadOnlyDictionary<int, List<TcpConnection>> _connections;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProcessTcpManager"/> class.
    /// </summary>
    /// <param name="options">The options.</param>
    public ProcessTcpManager(IOptions<PcapNostaleOptions> options)
    {
        _options = options.Value;
        _lastRefresh = DateTimeOffset.MinValue;
        _semaphore = new SemaphoreSlim(1, 1);
        _processes = new List<int>();
        _connections = new Dictionary<int, List<TcpConnection>>();
    }

    /// <summary>
    /// Register the given process to refreshing list to allow calling <see cref="GetConnectionsAsync"/>
    /// with that process.
    /// </summary>
    /// <param name="processId">The id of the process to register.</param>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    public async Task RegisterProcess(int processId)
    {
        await _semaphore.WaitAsync();
        try
        {
            _processes.Add(processId);
        }
        finally
        {
            _semaphore.Release();
        }
    }

    /// <summary>
    /// Unregister the given process from refreshing list, <see cref="GetConnectionsAsync"/> won't
    /// work for that process anymore.
    /// </summary>
    /// <param name="processId">The process to unregister.</param>
    /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
    public async Task UnregisterProcess(int processId)
    {
        await _semaphore.WaitAsync();
        try
        {
            _processes.Remove(processId);
        }
        finally
        {
            _semaphore.Release();
        }
    }

    /// <summary>
    /// Get connections established by the given process.
    /// </summary>
    /// <remarks>
    /// Works only for processes registered using <see cref="RegisterProcess"/>.
    /// </remarks>
    /// <param name="processId">The id of process to retrieve connections for.</param>
    /// <returns>The list of process connections.</returns>
    public async Task<IReadOnlyList<TcpConnection>> GetConnectionsAsync(int processId)
    {
        await Refresh();

        if (!_connections.ContainsKey(processId))
        {
            return Array.Empty<TcpConnection>();
        }

        return _connections[processId];
    }

    private async Task Refresh()
    {
        if (_lastRefresh.AddMilliseconds(_options.ProcessRefreshInterval) >= DateTimeOffset.Now)
        {
            return;
        }

        _lastRefresh = DateTimeOffset.Now;
        if (_processes.Count == 0)
        {
            if (_connections.Count > 0)
            {
                _connections = new Dictionary<int, List<TcpConnection>>();
            }
        }

        await _semaphore.WaitAsync();
        _connections = TcpConnectionHelper.GetConnections(_processes);
        _semaphore.Release();
    }
}
Do not follow this link