Listing all active connections and selecting ones to kill

Ok, the reason for the low point count on this is that I am just looking for information(although working code would allow me to up the point count).

What I'm trying to do is code a server program that interacts with a bunch of clients(500+). That I am pretty sure I can do, what I can't do is the following:

*Get a list of all active connections on a certain port
*Get rid of(Disconnect) the ones that are not connected with the server as well.

You might understand if I provide an example(Actually what it's going to be used for):

A game server has 500 people on it, the client programs have a hack protection system and I want to make sure it's running. What happens is the active connections on the server(on the game port specifically) are compared with the server hack protection which maintains a list of clients that are running the hack protection. If they are not I want to close the winsock connection that they have made.

For now all I am asking is for information that I can figure out. If someone wants to point out that they have working code I will up the point value depending on how much work I have left to do.

Thanks in advance.
LVL 13
Dagan HooverDeveloperAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Dagan HooverDeveloperAuthor Commented:
Point increase because of membership purchase.
0
ziolkoCommented:
I did it some time ago:
unit uIPHelperAPI;

interface

uses Windows;


resourcestring
  ResTCPStateClosed = 'Closed';
  ResTCPStateListen = 'Listen';
  ResTCPStateSynSent = 'SynSent';
  ResTCPStateSynRcvd = 'SynRcvd';
  ResTCPStateEst = 'Established';
  ResTCPStateFW1 = 'Fin Wait1';
  ResTCPStateFW2 = 'Fin Wait2';
  ResTCPStateCloseWait = 'Close Wait';
  ResTCPStateClosing = 'Closing';
  ResTCPStateLastAck = 'Last ACK';
  ResTCPStateTimeWait = 'Time Wait';
  ResTCPStateDeleteTCB = 'Delete TCB';

const

     TCP_STATES: array[1..12] of string = (ResTCPStateClosed,
                                           ResTCPStateListen,
                                           ResTCPStateSynSent,
                                           ResTCPStateSynRcvd,
                                           ResTCPStateEst,
                                           ResTCPStateFW1,
                                           ResTCPStateFW2,
                                           ResTCPStateCloseWait,
                                           ResTCPStateClosing,
                                           ResTCPStateLastAck,
                                           ResTCPStateTimeWait,
                                           ResTCPStateDeleteTCB);

type
 
    TCP_TABLE_CLASS = (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);

    UDP_TABLE_CLASS = (UDP_TABLE_BASIC, UDP_TABLE_OWNER_PID, UDP_TABLE_OWNER_MODULE);

    PMIB_TCPROW = ^MIB_TCPROW;
    MIB_TCPROW = packed record
      dwState: DWORD;
      dwLocalAddr: DWORD;
      dwLocalPort: DWORD;
      dwRemoteAddr: DWORD;
      dwRemotePort: DWORD;
    end;

    PMIB_TCPROW_OWNER_PID = ^MIB_TCPROW_OWNER_PID;
    MIB_TCPROW_OWNER_PID = packed record
      dwState: DWORD;
      dwLocalAddr: DWORD;
      dwLocalPort: DWORD;
      dwRemoteAddr: DWORD;
      dwRemotePort: DWORD;
      dwOwnerPID: DWORD;
    end;

    PMIB_UDPROW_OWNER_PID = ^MIB_UDPROW_OWNER_PID;
    MIB_UDPROW_OWNER_PID = packed record
      dwLocalAddr: DWORD;
      dwLocalPort: DWORD;
      dwOwnerPID: DWORD;
    end;

    PMIB_TCPTABLE_OWNER_PID = ^MIB_TCPTABLE_OWNER_PID;
    MIB_TCPTABLE_OWNER_PID = packed record
      dwNumEntries: DWORD;
      table: array [0..0] of MIB_TCPROW_OWNER_PID;
    end;

    PMIB_UDPTABLE_OWNER_PID = ^MIB_UDPTABLE_OWNER_PID;
    MIB_UDPTABLE_OWNER_PID = packed record
      dwNumEntries: DWORD;
      table: array [0..0] of MIB_UDPROW_OWNER_PID;
    end;

    TAllocateAndGetTcpExTableFromStack = function (pTcpTable: PMIB_TCPTABLE_OWNER_PID;bOrder: BOOL;heap: THandle;
                                                   zero: DWORD;flags: DWORD):DWORD;stdcall;
    TAllocateAndGetUdpExTableFromStack = function (pTcpTable: PMIB_TCPTABLE_OWNER_PID;bOrder: BOOL;heap: THandle;
                                                   zero: DWORD;flags: DWORD):DWORD;stdcall;
    TSendTcpEntry = function (pTCPRow: PMIB_TCPROW):DWORD;stdcall;
    TGetExtendedTcpTable = function (pTcpTable: PMIB_TCPTABLE_OWNER_PID;pdwSize: PDWORD;bOrder: BOOL;ulAf: ULONG;
                                     TableClass: TCP_TABLE_CLASS;Reserved: ULONG):DWORD;stdcall;
    TGetExtendedUdpTable = function (pTcpTable: PMIB_UDPTABLE_OWNER_PID;pdwSize: PDWORD;bOrder: BOOL;ulAf: ULONG;
                                     TableClass: UDP_TABLE_CLASS;Reserved: ULONG):DWORD;stdcall;

const
  MIB_TCP_STATE_CLOSED = 1;
  MIB_TCP_STATE_LISTEN = 2;
  MIB_TCP_STATE_SYN_SENT = 3;
  MIB_TCP_STATE_SYN_RCVD = 4;
  MIB_TCP_STATE_ESTAB = 5;
  MIB_TCP_STATE_FIN_WAIT1 = 6;
  MIB_TCP_STATE_FIN_WAIT2 = 7;
  MIB_TCP_STATE_CLOSE_WAIT = 8;
  MIB_TCP_STATE_CLOSING = 9;
  MIB_TCP_STATE_LAST_ACK = 10;
  MIB_TCP_STATE_TIME_WAIT = 11;
  MIB_TCP_STATE_DELETE_TCB = 12;

var
   IPHelperLoaded: Boolean;
   IPHelperXPLoaded: Boolean;
   IPHelperVistaLoaded: Boolean;
   AllocateAndGetTcpExTableFromStack: TAllocateAndGetTcpExTableFromStack;
   AllocateAndGetUdpExTableFromStack: TAllocateAndGetUdpExTableFromStack;
   SetTcpEntry: TSendTcpEntry;
   GetExtendedTcpTable: TGetExtendedTcpTable;
   GetExtendedUdpTable: TGetExtendedUdpTable;

implementation

const
     iphelper = 'iphlpapi.dll';
var
   LibHandle: THandle;
   
procedure LoadIPHelper;
begin
  LibHandle := LoadLibrary(iphelper);
  if LibHandle <> INVALID_HANDLE_VALUE then begin
    @AllocateAndGetTcpExTableFromStack := GetProcAddress(LibHandle, 'AllocateAndGetTcpExTableFromStack');
    @AllocateAndGetUdpExTableFromStack := GetProcAddress(LibHandle, 'AllocateAndGetUdpExTableFromStack');
    @SetTcpEntry := GetProcAddress(LibHandle, 'SetTcpEntry');
    @GetExtendedTcpTable := GetProcAddress(LibHandle, 'GetExtendedTcpTable');
    @GetExtendedUdpTable := GetProcAddress(LibHandle, 'GetExtendedUdpTable');
  end;
  IPHelperLoaded := (LibHandle <> INVALID_HANDLE_VALUE) and Assigned(SetTcpEntry);
  IPHelperXPLoaded := IPHelperLoaded and
                      (Assigned(AllocateAndGetTcpExTableFromStack) and Assigned(AllocateAndGetUdpExTableFromStack));
  IPHelperVistaLoaded := IPHelperLoaded and
                         (Assigned(GetExtendedTcpTable) and Assigned(GetExtendedUdpTable));
end;

procedure ReleaseIPHelper;
begin
  if LibHandle <> INVALID_HANDLE_VALUE then
    FreeLibrary(LibHandle);
end;

initialization

  LoadIPHelper;

finalization

  ReleaseIPHelper;

end.

sample usage for TCP:

procedure TExtTCPTable.ReadTCPTable;
var wsadata: TWSAData;
    ret: DWORD;
    dwSize: DWORD;
begin
  if not IPHelperLoaded then
    Exit;
  WSAStartup(2, wsadata);
  try
    if IPHelperVistaLoaded then begin
      dwSize := 0;
      ret := GetExtendedTcpTable(FBufferTCP, @dwSize, True, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
      if ret = ERROR_INSUFFICIENT_BUFFER then begin
        GetMem(FBufferTCP, dwSize);
        GetExtendedTcpTable(FBufferTCP, @dwSize, True, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
      end;
    end else if IPHelperXPLoaded then
      AllocateAndGetTcpExTableFromStack(@FBufferTCP, True, GetProcessHeap, 2, 2);
  finally
    WSACleanup;
  end;
end;

where

FBufferTCP: PMIB_TCPTABLE_OWNER_PID;


FBufferTCP^.dwNumEntries returns number of entries

var item: MIB_TCPROW_OWNER_PID;

item := FBufferTCP^.table[ARow];

GetIP(item.dwLocalAddr);
GetPort(item.dwLocalPort);

function GetIP(AIP: DWORD): WideString;
var bytes: array[0..3] of Byte;
begin
  Move(AIP, bytes[0], SizeOf(AIP));
  Result := IntToStr(bytes[0]) + '.' +
            IntToStr(bytes[1]) + '.' +
            IntToStr(bytes[2]) + '.' +
            IntToStr(bytes[3]);
end;

function GetPort(APort: DWORD): DWORD;
begin
  Result := (APort div 256) + (APort mod 256) * 256;
end;

if you want to try close connection, you should use:
SetTcpEntry and set MIB_TCPROW.dwState to MIB_TCP_STATE_DELETE_TCB

it's a bit messy but I had to retrieve it from bigger project, but should give you enough information to complete your task.


ziolko.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ziolkoCommented:
note. my solution is "low level" one, if you write your own app that maintain connections to clients your task may be acomplished in simpler way. probably you keep some kind of list of clients with connection components (Indy?) then you could simply browse your list and disconnect/delete specific connection.

ziolko.
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

Dagan HooverDeveloperAuthor Commented:
I'm going to take a look at the code you posted. I really don't mind complicated, keeps me from being bored. I'll test it out in a bit. Thanks.
0
Dagan HooverDeveloperAuthor Commented:
Ok I just tested it on the server. And I didn't get any of the connections of the server itself, any reason for that?

Note: I got connections with some other things, but not the game server for which this is intended.
0
ziolkoCommented:
is your game using tcp for transport?

ziolko.
0
Dagan HooverDeveloperAuthor Commented:
Yes its TCP:

ports

TCP: 6000,8900,5100
UDP 7777,7778,8900

The one I want to know is the 6000 port. The code posted didn't show any from it.
0
Dagan HooverDeveloperAuthor Commented:
OK, got the port 6000 to show connections. Only problem is that it is showing the connection IP of the server not the connector. I'm going to see if thats something that can be edited in the code.
0
Dagan HooverDeveloperAuthor Commented:
ListBox1.Items.Add(GetIP(item.dwRemoteAddr) + ' ' + IntToStr(GetPort(item.dwLocalPort)));

Local --> Remote..sometimes I can be blind.
0
Dagan HooverDeveloperAuthor Commented:
Ok Getting Access error but the code works, any ideas?
procedure TForm1.Button1Click(Sender: TObject);
var
item: MIB_TCPROW_OWNER_PID;
I : Integer;
begin
ReadTCPTable;
For I := 0 To FBufferTCP^.dwNumEntries Do
  begin
  item := FBufferTCP^.table[I];
  ListBox1.Items.Add(GetIP(item.dwRemoteAddr) + ' ' + IntToStr(GetPort(item.dwLocalPort)));
end;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
item: PMIB_TCPROW;
item2 : MIB_TCPROW_OWNER_PID;
begin
item2 := FBufferTCP^.table[ListBox1.ItemIndex];
item.dwState := MIB_TCP_STATE_DELETE_TCB;
item.dwLocalAddr := item2.dwLocalAddr;
item.dwLocalPort := item2.dwLocalPort;
item.dwRemoteAddr := item2.dwRemoteAddr;
item.dwRemotePort := item2.dwRemotePort;
SetTCPEntry(item);
end;

Open in new window

0
ziolkoCommented:
first thing, are those connections on ports 6000,8900,5100 persistent or are they open only for duration of communication?

second thing if you want udp you it's pretty same as with tcp you can use appropriate functions/data types

where this error popsup?

ziolko.
0
Dagan HooverDeveloperAuthor Commented:
They are only open for the duration of communication. And the UDP isn't really needed.

I stepped through the code of:

item2 := FBufferTCP^.table[ListBox1.ItemIndex];
item.dwState := MIB_TCP_STATE_DELETE_TCB;
item.dwLocalAddr := item2.dwLocalAddr;
item.dwLocalPort := item2.dwLocalPort;
item.dwRemoteAddr := item2.dwRemoteAddr;
item.dwRemotePort := item2.dwRemotePort;
SetTCPEntry(item);

It completed everything, got to the end of the buttons procedure and then came the access violation.
0
ziolkoCommented:
try this one:

procedure TForm1.Button2Click(Sender: TObject);
var
item: MIB_TCPROW;
item2 : MIB_TCPROW_OWNER_PID;
begin
item2 := FBufferTCP^.table[ListBox1.ItemIndex];
item.dwState := MIB_TCP_STATE_DELETE_TCB;
item.dwLocalAddr := item2.dwLocalAddr;
item.dwLocalPort := item2.dwLocalPort;
item.dwRemoteAddr := item2.dwRemoteAddr;
item.dwRemotePort := item2.dwRemotePort;
SetTCPEntry(@item);
end;

ziolko.
0
Dagan HooverDeveloperAuthor Commented:
I've got to say you were quick to help with full code when I only asked for information to the right path. Thankyou very much for that.
0
ziolkoCommented:
>>I've got to say you were quick to help with full code when I only asked for information to the right path. Thankyou very much for that.

well you were lucky because I did soemthing like this a while ago, and just few weeks ago I used that when building WMI provider:)

ziolko.
0
rionrocCommented:
Yes it's Very Good :)

The GetPort, The GetIP

But i would like to know how to GetState?

Please someone could help me.
I'm so dumd, and just a newbie for the experts.

I did not post a new thread because i know I'm to late to ask for.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.