315 lines
7.4 KiB
ObjectPascal
315 lines
7.4 KiB
ObjectPascal
unit PointerscanConnector;
|
|
|
|
//thread that will constantly check if it has a connection queue and if so try to connect it and initiate a connection
|
|
//it also sets up the basic connection type
|
|
|
|
{$mode delphi}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, sockets, resolve, syncobjs, math, winsock2, CELazySocket,
|
|
PointerscanNetworkCommands;
|
|
|
|
|
|
type
|
|
TConnectEntry=record
|
|
id: integer;
|
|
deleted: boolean; //when set this entry should get deleted
|
|
ip: pchar;
|
|
port: word;
|
|
password: pchar;
|
|
becomeparent: boolean;
|
|
trusted: boolean;
|
|
end;
|
|
PConnectentry=^TConnectentry;
|
|
|
|
TConnectEntryArray=array of TConnectentry;
|
|
|
|
TPointerscanConnectEvent=procedure(sender: TObject; sockethandle: TSocket; IBecameAParent: boolean; entry: PConnectEntry) of object;
|
|
TPointerScanConnectorLogEvent=procedure(sender: TObject; message: string) of object;
|
|
|
|
TPointerscanConnector=class(TThread)
|
|
private
|
|
fOnConnected: TPointerscanConnectEvent;
|
|
fOnLog: TPointerScanConnectorLogEvent;
|
|
|
|
nextid: integer; //id to pass on to the next added entry
|
|
lastlog: string; //debug only
|
|
list: TList;
|
|
listcs: TCriticalSection;
|
|
|
|
hr: THostResolver;
|
|
procedure Log(msg: string);
|
|
procedure FreeEntry(entry: PConnectEntry);
|
|
procedure RemoveDeletedEntries; //only called by the thread.
|
|
public
|
|
function AddConnection(ip: string; port: word; password: string; becomeparent: boolean; trusted: boolean=false): integer;
|
|
procedure MarkEntryForDeletion(id: integer); //marks for deletion
|
|
procedure GetList(var l: TConnectEntryArray);
|
|
|
|
procedure execute; override;
|
|
constructor create(onconnect: TPointerscanConnectEvent=nil);
|
|
destructor destroy; override;
|
|
|
|
property OnConnected: TPointerscanConnectEvent read fOnConnected write fOnConnected;
|
|
end;
|
|
|
|
implementation
|
|
|
|
procedure TPointerscanConnector.GetList(var l: TConnectEntryArray);
|
|
{
|
|
Passes a copy of the list of entries to the caller
|
|
}
|
|
var i: integer;
|
|
begin
|
|
listcs.enter;
|
|
try
|
|
setlength(l, list.count);
|
|
for i:=0 to list.count-1 do
|
|
l[i]:=PConnectEntry(list[i])^;
|
|
finally
|
|
listcs.leave;
|
|
end;
|
|
end;
|
|
|
|
procedure TPointerscanConnector.FreeEntry(entry: PConnectEntry);
|
|
begin
|
|
if (entry.ip<>nil) then
|
|
StrDispose(entry.ip);
|
|
|
|
if entry.password<>nil then
|
|
StrDispose(entry.password);
|
|
|
|
Freemem(entry);
|
|
end;
|
|
|
|
procedure TPointerscanConnector.RemoveDeletedEntries;
|
|
var
|
|
i: integer;
|
|
entry: PConnectentry;
|
|
begin
|
|
listcs.enter;
|
|
try
|
|
i:=0;
|
|
while i<list.count do
|
|
begin
|
|
entry:=list[i];
|
|
if entry.deleted then
|
|
begin
|
|
freeEntry(entry);
|
|
list.Delete(i);
|
|
end
|
|
else
|
|
inc(i);
|
|
end;
|
|
finally
|
|
listcs.leave;
|
|
end;
|
|
end;
|
|
|
|
procedure TPointerscanConnector.MarkEntryForDeletion(id: integer);
|
|
var i: integer;
|
|
begin
|
|
listcs.enter;
|
|
try
|
|
for i:=0 to list.count-1 do
|
|
if PConnectentry(list[i]).id=id then
|
|
PConnectentry(list[i]).deleted:=true;
|
|
finally
|
|
listcs.leave;
|
|
end;
|
|
end;
|
|
|
|
function TPointerscanConnector.AddConnection(ip: string; port: word; password: string; becomeparent: boolean; trusted: boolean=false): integer;
|
|
var
|
|
i: integer;
|
|
entry: PConnectentry;
|
|
begin
|
|
if port=0 then exit; //do not allow port 0
|
|
|
|
getmem(entry, sizeof(TConnectEntry));
|
|
entry.ip:=strnew(pchar(ip));
|
|
entry.port:=port;
|
|
entry.password:=strnew(pchar(password));
|
|
entry.becomeparent:=becomeparent;
|
|
entry.trusted:=trusted;
|
|
|
|
entry.deleted:=false;
|
|
entry.id:=nextid;
|
|
inc(nextid);
|
|
|
|
listcs.enter;
|
|
try
|
|
list.Add(entry);
|
|
finally
|
|
listcs.leave;
|
|
end;
|
|
end;
|
|
|
|
procedure TPointerscanConnector.Log(msg: string);
|
|
begin
|
|
lastlog:=msg;
|
|
if assigned(fOnLog) then
|
|
fOnLog(self, msg);
|
|
end;
|
|
|
|
procedure TPointerscanConnector.execute;
|
|
var
|
|
i: integer;
|
|
entry: PConnectentry;
|
|
|
|
|
|
sockaddr: TInetSockAddr;
|
|
sockethandle: TSocket;
|
|
ss: TSocketStream;
|
|
result: byte;
|
|
|
|
|
|
wait: boolean;
|
|
begin
|
|
i:=0;
|
|
while not terminated do
|
|
begin
|
|
RemoveDeletedEntries;
|
|
|
|
sockethandle:=INVALID_SOCKET;
|
|
entry:=nil;
|
|
|
|
try
|
|
|
|
wait:=false;
|
|
listcs.enter;
|
|
|
|
//check the list
|
|
try
|
|
if i>=list.count then //start from the beginning
|
|
begin
|
|
wait:=true; //end of the list, wait a bit to prevent hammering
|
|
i:=0;
|
|
end;
|
|
|
|
if i<list.count then
|
|
entry:=list[i];
|
|
|
|
finally
|
|
listcs.leave;
|
|
end;
|
|
|
|
|
|
if wait then sleep(1000);
|
|
|
|
if terminated then exit;
|
|
|
|
if entry<>nil then
|
|
begin
|
|
//connect to this entry
|
|
//first resolve the ip
|
|
if entry.deleted then
|
|
begin
|
|
inc(i);
|
|
continue;
|
|
end;
|
|
|
|
sockaddr.sin_addr:=StrToNetAddr(entry.ip);
|
|
|
|
if sockaddr.sin_addr.s_bytes[4]=0 then
|
|
begin
|
|
if hr.NameLookup(entry.ip) then
|
|
sockaddr.sin_addr:=hr.NetHostAddress
|
|
else
|
|
raise exception.create('host:'+entry.ip+' could not be resolved');
|
|
end;
|
|
|
|
if sockaddr.sin_addr.s_bytes[4]<>0 then
|
|
begin
|
|
//connect
|
|
sockethandle:=socket(AF_INET, SOCK_STREAM, 0);
|
|
if sockethandle=INVALID_SOCKET then
|
|
raise exception.create('Failure creating socket');
|
|
|
|
sockaddr.sin_family:=AF_INET;
|
|
sockaddr.sin_port:=htons(entry.port);
|
|
|
|
if fpconnect(sockethandle, @SockAddr, sizeof(SockAddr))=0 then
|
|
begin
|
|
//connected, do the initial handshake
|
|
//build the message
|
|
|
|
|
|
ss:=TSocketStream.Create(sockethandle, false); //don't take ownership of this socket
|
|
|
|
try
|
|
ss.WriteByte(PSCONNECT_INIT);
|
|
ss.WriteAnsiString8(entry.password);
|
|
ss.WriteByte(ifthen(entry.becomeparent, 0, 1));
|
|
|
|
//send it
|
|
ss.flushWrites;
|
|
|
|
result:=ss.ReadByte;
|
|
finally
|
|
ss.free;
|
|
end;
|
|
|
|
if result<>0 then
|
|
raise exception.create('invalid response from '+entry.ip)
|
|
else
|
|
begin
|
|
if Assigned(fOnConnected) then
|
|
begin
|
|
fOnConnected(self, sockethandle, entry.becomeparent, entry);
|
|
|
|
//remove this from the list
|
|
MarkEntryForDeletion(entry.id);
|
|
continue;
|
|
end
|
|
else
|
|
raise exception.create('Someone forgot to give this connector an OnConnected event...');
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
closeSocket(sockethandle);
|
|
sockethandle:=INVALID_SOCKET;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
except
|
|
on e: exception do
|
|
begin
|
|
if sockethandle<>INVALID_SOCKET then
|
|
closesocket(sockethandle);
|
|
|
|
log(e.message);
|
|
sleep(1000);
|
|
end;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
destructor TPointerscanConnector.destroy;
|
|
begin
|
|
listcs.free;
|
|
list.free;
|
|
hr.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
constructor TPointerscanConnector.create(onconnect: TPointerscanConnectEvent=nil);
|
|
begin
|
|
hr:=THostResolver.Create(nil);
|
|
list:=tlist.create;
|
|
listcs:=tcriticalsection.Create;
|
|
fOnConnected:=onconnect;
|
|
inherited create(false);
|
|
end;
|
|
|
|
|
|
end.
|
|
|