Created
January 23, 2018 02:24
-
-
Save jymcheong/12d6f98342c5775eb9b76ad233d88f51 to your computer and use it in GitHub Desktop.
Socket Connection Managed Wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Runtime.InteropServices; | |
using System.Linq; | |
using System.Net; | |
using System.Diagnostics; | |
namespace ConsoleApplication2 | |
{ | |
public class SocketConnection | |
{ | |
// The version of IP used by the TCP/UDP endpoint. AF_INET is used for IPv4. | |
private const int AF_INET = 2; | |
// The GetExtendedTcpTable function retrieves a table that contains a list of | |
// TCP endpoints available to the application. Decorating the function with | |
// DllImport attribute indicates that the attributed method is exposed by an | |
// unmanaged dynamic-link library 'iphlpapi.dll' as a static entry point. | |
[DllImport("iphlpapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int pdwSize, | |
bool bOrder, int ulAf, TcpTableClass tableClass, uint reserved = 0); | |
// The GetExtendedUdpTable function retrieves a table that contains a list of | |
// UDP endpoints available to the application. Decorating the function with | |
// DllImport attribute indicates that the attributed method is exposed by an | |
// unmanaged dynamic-link library 'iphlpapi.dll' as a static entry point. | |
[DllImport("iphlpapi.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
private static extern uint GetExtendedUdpTable(IntPtr pUdpTable, ref int pdwSize, | |
bool bOrder, int ulAf, UdpTableClass tableClass, uint reserved = 0); | |
public SocketConnection() | |
{ | |
} | |
/// <summary> | |
/// This function reads and parses the active TCP socket connections available | |
/// and stores them in a list. | |
/// </summary> | |
/// <returns> | |
/// It returns the current set of TCP socket connections which are active. | |
/// </returns> | |
/// <exception cref="OutOfMemoryException"> | |
/// This exception may be thrown by the function Marshal.AllocHGlobal when there | |
/// is insufficient memory to satisfy the request. | |
/// </exception> | |
public static List<TcpProcessRecord> GetAllTcpConnections() | |
{ | |
int bufferSize = 0; | |
List<TcpProcessRecord> tcpTableRecords = new List<TcpProcessRecord>(); | |
// Getting the size of TCP table, that is returned in 'bufferSize' variable. | |
uint result = GetExtendedTcpTable(IntPtr.Zero, ref bufferSize, true, AF_INET, | |
TcpTableClass.TCP_TABLE_OWNER_PID_ALL); | |
// Allocating memory from the unmanaged memory of the process by using the | |
// specified number of bytes in 'bufferSize' variable. | |
IntPtr tcpTableRecordsPtr = Marshal.AllocHGlobal(bufferSize); | |
try | |
{ | |
// The size of the table returned in 'bufferSize' variable in previous | |
// call must be used in this subsequent call to 'GetExtendedTcpTable' | |
// function in order to successfully retrieve the table. | |
result = GetExtendedTcpTable(tcpTableRecordsPtr, ref bufferSize, true, | |
AF_INET, TcpTableClass.TCP_TABLE_OWNER_PID_ALL); | |
// Non-zero value represent the function 'GetExtendedTcpTable' failed, | |
// hence empty list is returned to the caller function. | |
if (result != 0) | |
return new List<TcpProcessRecord>(); | |
// Marshals data from an unmanaged block of memory to a newly allocated | |
// managed object 'tcpRecordsTable' of type 'MIB_TCPTABLE_OWNER_PID' | |
// to get number of entries of the specified TCP table structure. | |
MIB_TCPTABLE_OWNER_PID tcpRecordsTable = (MIB_TCPTABLE_OWNER_PID) | |
Marshal.PtrToStructure(tcpTableRecordsPtr, | |
typeof(MIB_TCPTABLE_OWNER_PID)); | |
IntPtr tableRowPtr = (IntPtr)((long)tcpTableRecordsPtr + | |
Marshal.SizeOf(tcpRecordsTable.dwNumEntries)); | |
// Reading and parsing the TCP records one by one from the table and | |
// storing them in a list of 'TcpProcessRecord' structure type objects. | |
for (int row = 0; row < tcpRecordsTable.dwNumEntries; row++) | |
{ | |
MIB_TCPROW_OWNER_PID tcpRow = (MIB_TCPROW_OWNER_PID)Marshal. | |
PtrToStructure(tableRowPtr, typeof(MIB_TCPROW_OWNER_PID)); | |
tcpTableRecords.Add(new TcpProcessRecord( | |
new IPAddress(tcpRow.localAddr), | |
new IPAddress(tcpRow.remoteAddr), | |
BitConverter.ToUInt16(new byte[2] { | |
tcpRow.localPort[1], | |
tcpRow.localPort[0] }, 0), | |
BitConverter.ToUInt16(new byte[2] { | |
tcpRow.remotePort[1], | |
tcpRow.remotePort[0] }, 0), | |
tcpRow.owningPid, tcpRow.state)); | |
tableRowPtr = (IntPtr)((long)tableRowPtr + Marshal.SizeOf(tcpRow)); | |
} | |
} | |
catch (OutOfMemoryException outOfMemoryException) | |
{ | |
Console.WriteLine(outOfMemoryException.Message, "Out Of Memory"); | |
} | |
catch (Exception exception) | |
{ | |
Console.WriteLine(exception.Message, "Exception"); | |
} | |
finally | |
{ | |
Marshal.FreeHGlobal(tcpTableRecordsPtr); | |
} | |
return tcpTableRecords != null ? tcpTableRecords.Distinct() | |
.ToList<TcpProcessRecord>() : new List<TcpProcessRecord>(); | |
} | |
/// <summary> | |
/// This function reads and parses the active UDP socket connections available | |
/// and stores them in a list. | |
/// </summary> | |
/// <returns> | |
/// It returns the current set of UDP socket connections which are active. | |
/// </returns> | |
/// <exception cref="OutOfMemoryException"> | |
/// This exception may be thrown by the function Marshal.AllocHGlobal when there | |
/// is insufficient memory to satisfy the request. | |
/// </exception> | |
public static List<UdpProcessRecord> GetAllUdpConnections() | |
{ | |
int bufferSize = 0; | |
List<UdpProcessRecord> udpTableRecords = new List<UdpProcessRecord>(); | |
// Getting the size of UDP table, that is returned in 'bufferSize' variable. | |
uint result = GetExtendedUdpTable(IntPtr.Zero, ref bufferSize, true, | |
AF_INET, UdpTableClass.UDP_TABLE_OWNER_PID); | |
// Allocating memory from the unmanaged memory of the process by using the | |
// specified number of bytes in 'bufferSize' variable. | |
IntPtr udpTableRecordPtr = Marshal.AllocHGlobal(bufferSize); | |
try | |
{ | |
// The size of the table returned in 'bufferSize' variable in previous | |
// call must be used in this subsequent call to 'GetExtendedUdpTable' | |
// function in order to successfully retrieve the table. | |
result = GetExtendedUdpTable(udpTableRecordPtr, ref bufferSize, true, | |
AF_INET, UdpTableClass.UDP_TABLE_OWNER_PID); | |
// Non-zero value represent the function 'GetExtendedUdpTable' failed, | |
// hence empty list is returned to the caller function. | |
if (result != 0) | |
return new List<UdpProcessRecord>(); | |
// Marshals data from an unmanaged block of memory to a newly allocated | |
// managed object 'udpRecordsTable' of type 'MIB_UDPTABLE_OWNER_PID' | |
// to get number of entries of the specified TCP table structure. | |
MIB_UDPTABLE_OWNER_PID udpRecordsTable = (MIB_UDPTABLE_OWNER_PID) | |
Marshal.PtrToStructure(udpTableRecordPtr, typeof(MIB_UDPTABLE_OWNER_PID)); | |
IntPtr tableRowPtr = (IntPtr)((long)udpTableRecordPtr + | |
Marshal.SizeOf(udpRecordsTable.dwNumEntries)); | |
// Reading and parsing the UDP records one by one from the table and | |
// storing them in a list of 'UdpProcessRecord' structure type objects. | |
for (int i = 0; i < udpRecordsTable.dwNumEntries; i++) | |
{ | |
MIB_UDPROW_OWNER_PID udpRow = (MIB_UDPROW_OWNER_PID) | |
Marshal.PtrToStructure(tableRowPtr, typeof(MIB_UDPROW_OWNER_PID)); | |
udpTableRecords.Add(new UdpProcessRecord(new IPAddress(udpRow.localAddr), | |
BitConverter.ToUInt16(new byte[2] { udpRow.localPort[1], | |
udpRow.localPort[0] }, 0), udpRow.owningPid)); | |
tableRowPtr = (IntPtr)((long)tableRowPtr + Marshal.SizeOf(udpRow)); | |
} | |
} | |
catch (OutOfMemoryException outOfMemoryException) | |
{ | |
Console.WriteLine(outOfMemoryException.Message, "Out Of Memory"); | |
} | |
catch (Exception exception) | |
{ | |
Console.WriteLine(exception.Message, "Exception"); | |
} | |
finally | |
{ | |
Marshal.FreeHGlobal(udpTableRecordPtr); | |
} | |
return udpTableRecords != null ? udpTableRecords.Distinct() | |
.ToList<UdpProcessRecord>() : new List<UdpProcessRecord>(); | |
} | |
} | |
// Enum for protocol types. | |
public enum Protocol | |
{ | |
TCP, | |
UDP | |
} | |
// Enum to define the set of values used to indicate the type of table returned by | |
// calls made to the function 'GetExtendedTcpTable'. | |
public enum TcpTableClass | |
{ | |
TCP_TABLE_BASIC_LISTENER, | |
TCP_TABLE_BASIC_CONNECTIONS, | |
TCP_TABLE_BASIC_ALL, | |
TCP_TABLE_OWNER_PID_LISTENER, | |
TCP_TABLE_OWNER_PID_CONNECTIONS, | |
TCP_TABLE_OWNER_PID_ALL, | |
TCP_TABLE_OWNER_MODULE_LISTENER, | |
TCP_TABLE_OWNER_MODULE_CONNECTIONS, | |
TCP_TABLE_OWNER_MODULE_ALL | |
} | |
// Enum to define the set of values used to indicate the type of table returned by calls | |
// made to the function GetExtendedUdpTable. | |
public enum UdpTableClass | |
{ | |
UDP_TABLE_BASIC, | |
UDP_TABLE_OWNER_PID, | |
UDP_TABLE_OWNER_MODULE | |
} | |
// Enum for different possible states of TCP connection | |
public enum MibTcpState | |
{ | |
CLOSED = 1, | |
LISTENING = 2, | |
SYN_SENT = 3, | |
SYN_RCVD = 4, | |
ESTABLISHED = 5, | |
FIN_WAIT1 = 6, | |
FIN_WAIT2 = 7, | |
CLOSE_WAIT = 8, | |
CLOSING = 9, | |
LAST_ACK = 10, | |
TIME_WAIT = 11, | |
DELETE_TCB = 12, | |
NONE = 0 | |
} | |
/// <summary> | |
/// The structure contains information that describes an IPv4 TCP connection with | |
/// IPv4 addresses, ports used by the TCP connection, and the specific process ID | |
/// (PID) associated with connection. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct MIB_TCPROW_OWNER_PID | |
{ | |
public MibTcpState state; | |
public uint localAddr; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] | |
public byte[] localPort; | |
public uint remoteAddr; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] | |
public byte[] remotePort; | |
public int owningPid; | |
} | |
/// <summary> | |
/// The structure contains a table of process IDs (PIDs) and the IPv4 TCP links that | |
/// are context bound to these PIDs. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct MIB_TCPTABLE_OWNER_PID | |
{ | |
public uint dwNumEntries; | |
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, | |
SizeConst = 1)] | |
public MIB_TCPROW_OWNER_PID[] table; | |
} | |
/// <summary> | |
/// This class provides access an IPv4 TCP connection addresses and ports and its | |
/// associated Process IDs and names. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public class TcpProcessRecord | |
{ | |
[DisplayName("Local Address")] | |
public IPAddress LocalAddress { get; set; } | |
[DisplayName("Local Port")] | |
public ushort LocalPort { get; set; } | |
[DisplayName("Remote Address")] | |
public IPAddress RemoteAddress { get; set; } | |
[DisplayName("Remote Port")] | |
public ushort RemotePort { get; set; } | |
[DisplayName("State")] | |
public MibTcpState State { get; set; } | |
[DisplayName("Process ID")] | |
public int ProcessId { get; set; } | |
[DisplayName("Process Name")] | |
public string ProcessName { get; set; } | |
public TcpProcessRecord(IPAddress localIp, IPAddress remoteIp, ushort localPort, | |
ushort remotePort, int pId, MibTcpState state) | |
{ | |
LocalAddress = localIp; | |
RemoteAddress = remoteIp; | |
LocalPort = localPort; | |
RemotePort = remotePort; | |
State = state; | |
ProcessId = pId; | |
// Getting the process name associated with a process id. | |
if (Process.GetProcesses().Any(process => process.Id == pId)) | |
{ | |
ProcessName = Process.GetProcessById(ProcessId).ProcessName; | |
} | |
} | |
} | |
/// <summary> | |
/// The structure contains an entry from the User Datagram Protocol (UDP) listener | |
/// table for IPv4 on the local computer. The entry also includes the process ID | |
/// (PID) that issued the call to the bind function for the UDP endpoint. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct MIB_UDPROW_OWNER_PID | |
{ | |
public uint localAddr; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] | |
public byte[] localPort; | |
public int owningPid; | |
} | |
/// <summary> | |
/// The structure contains the User Datagram Protocol (UDP) listener table for IPv4 | |
/// on the local computer. The table also includes the process ID (PID) that issued | |
/// the call to the bind function for each UDP endpoint. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public struct MIB_UDPTABLE_OWNER_PID | |
{ | |
public uint dwNumEntries; | |
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, | |
SizeConst = 1)] | |
public UdpProcessRecord[] table; | |
} | |
/// <summary> | |
/// This class provides access an IPv4 UDP connection addresses and ports and its | |
/// associated Process IDs and names. | |
/// </summary> | |
[StructLayout(LayoutKind.Sequential)] | |
public class UdpProcessRecord | |
{ | |
[DisplayName("Local Address")] | |
public IPAddress LocalAddress { get; set; } | |
[DisplayName("Local Port")] | |
public uint LocalPort { get; set; } | |
[DisplayName("Process ID")] | |
public int ProcessId { get; set; } | |
[DisplayName("Process Name")] | |
public string ProcessName { get; set; } | |
public UdpProcessRecord(IPAddress localAddress, uint localPort, int pId) | |
{ | |
LocalAddress = localAddress; | |
LocalPort = localPort; | |
ProcessId = pId; | |
if (Process.GetProcesses().Any(process => process.Id == pId)) | |
ProcessName = Process.GetProcessById(ProcessId).ProcessName; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
using System;
using System.Collections.Generic;
using System.Timers;
namespace ConsoleApplication2
{
class Program
{
static Dictionary<string, string> listeningPorts = new Dictionary<string, string>();
static Timer timer = new Timer(3000);
}