?? idtunnelmaster.pas
字號:
break;
end;
if user.receiver.NewMessage then begin
if user.Receiver.CRCFailed then begin
Thread.Connection.Disconnect;
break;
end;
// Custom data transformation
try
DoTransformRead(Thread);
except
Thread.Connection.Disconnect;
Break;
end;
// Action
case user.Receiver.Header.MsgType of
// transformation of data failed, disconnect the tunnel
tmError: begin
try
Thread.Connection.Disconnect;
break;
except
;
end;
end; // Failure END
// Data
tmData: begin
try
SetString(s, user.Receiver.Msg, user.Receiver.MsgLen);
ClientOperation(tmData, user.Receiver.Header.UserId, s);
except
;
end;
end; // Data END
// Disconnect
tmDisconnect: begin
try
ClientOperation(tmDisconnect, user.Receiver.Header.UserId, ''); {Do not Localize}
except
;
end;
end; // Disconnect END
// Connect
tmConnect: begin
// Connection should be done synchroneusly
// because more data could arrive before client
// connects asyncroneusly
try
clientThread := MClientThread.Create(self);
try
ErrorConnecting := False;
with clientThread do begin
UserId := user.Receiver.Header.UserId;
MasterThread := Thread;
OutboundClient := TIdTCPClient.Create(nil);
sIP := GStack.TInAddrToString(user.Receiver.Header.IpAddr);
if fbLockDestinationHost then begin
OutboundClient.Host := fsMappedHost;
if fbLockDestinationPort then
OutboundClient.Port := fiMappedPort
else
OutboundClient.Port := user.Receiver.Header.Port;
end
else begin
// do we tunnel all connections from the slave to the specified host
if sIP = '0.0.0.0' then begin {Do not Localize}
OutboundClient.Host := fsMappedHost;
OutboundClient.Port := user.Receiver.Header.Port; //fiMappedPort;
end
else begin
OutboundClient.Host := sIP;
OutboundClient.Port := user.Receiver.Header.Port;
end;
end;
OutboundClient.Connect;
end;
except
ErrorConnecting := True;
end;
if ErrorConnecting then begin
clientThread.Destroy;
end
else begin
clientThread.Resume;
end;
except
;
end;
end; // Connect END
// Custom data interpretation
tmCustom: begin
CustomMsg := ''; {Do not Localize}
DoInterpretMsg(Thread, CustomMsg);
if Length(CustomMsg) > 0 then begin
Header.MsgType := tmCustom;
Header.UserId := 0;
SendMsg(Thread, Header, CustomMsg);
end;
end;
end; // case
// Shift of data
user.Receiver.ShiftData;
end
else
break; // break the loop
end; // end while
end; // readable
end;
procedure TIdTunnelMaster.DoTransformRead(Thread: TIdPeerThread);
begin
if Assigned(fOnTransformRead) then
fOnTransformRead(Thread);
end;
procedure TIdTunnelMaster.DoTransformSend(Thread: TIdPeerThread; var Header: TIdHeader; var CustomMsg: String);
begin
if Assigned(fOnTransformSend) then
fOnTransformSend(Thread, Header, CustomMsg);
end;
procedure TIdTunnelMaster.DoInterpretMsg(Thread: TIdPeerThread; var CustomMsg: String);
begin
if Assigned(fOnInterpretMsg) then
fOnInterpretMsg(Thread, CustomMsg);
end;
// Disconnect all services owned by tunnel thread
procedure TIdTunnelMaster.DisconnectAllSubThreads(TunnelThread: TIdPeerThread);
var
Thread: MClientThread;
i: integer;
listTemp: TList;
begin
OnlyOneThread.Enter; // for now it is done with locking
listTemp := Clients.LockList;
try
for i := 0 to listTemp.count - 1 do begin
if Assigned(listTemp[i]) then begin
Thread := MClientThread(listTemp[i]);
if Thread.MasterThread = TunnelThread then begin
Thread.DisconnectedOnRequest := True;
Thread.OutboundClient.Disconnect;
end;
end;
end;
finally
Clients.UnlockList;
OnlyOneThread.Leave;
end;
end;
procedure TIdTunnelMaster.SendMsg(MasterThread: TIdPeerThread; var Header: TIdHeader; s: String);
var
user: TSlaveData;
tmpString: String;
begin
if Assigned(MasterThread.Data) then begin
TSlaveData(MasterThread.Data).Locker.Enter;
try
user := TSlaveData(MasterThread.Data);
try
// Custom data transformation before send
tmpString := s;
try
DoTransformSend(MasterThread, Header, tmpString);
except
on E: Exception do begin
raise EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
end;
end;
if Header.MsgType = tmError then begin // error ocured in transformation
raise EIdTunnelTransformErrorBeforeSend.Create(RSTunnelTransformErrorBS);
end;
user.Sender.PrepareMsg(Header, PChar(@tmpString[1]), Length(tmpString));
MasterThread.Connection.Write(user.Sender.Msg);
except
raise;
end;
finally
TSlaveData(MasterThread.Data).Locker.Leave;
end;
end;
end;
function TIdTunnelMaster.GetClientThread(UserID: Integer): MClientThread;
var
Thread: MClientThread;
i: integer;
begin
Result := nil;
with Clients.LockList do
try
for i := 0 to Count-1 do begin
try
if Assigned(Items[i]) then begin
Thread := MClientThread(Items[i]);
if Thread.UserId = UserID then begin
Result := Thread;
break;
end;
end;
except
Result := nil;
end;
end;
finally
Clients.UnlockList;
end;
end;
procedure TIdTunnelMaster.DisconectAllUsers;
begin
TerminateAllThreads;
end;
procedure TIdTunnelMaster.ClientOperation(Operation: Integer; UserId: Integer; s: String);
var
Thread: MClientThread;
begin
Thread := GetClientThread(UserID);
if Assigned(Thread) then begin
Thread.Locker.Enter;
try
if not Thread.SelfDisconnected then begin
case Operation of
tmData: begin
try
Thread.OutboundClient.CheckForDisconnect;
if Thread.OutboundClient.Connected then
Thread.OutboundClient.Write(s);
except
try
Thread.OutboundClient.Disconnect;
except
;
end;
end;
end;
tmDisconnect: begin
Thread.DisconnectedOnRequest := True;
try
Thread.OutboundClient.Disconnect;
except
;
end;
end;
end;
end;
finally
Thread.Locker.Leave;
end;
end; // Assigned
end;
/////////////////////////////////////////////////////////////////
//
// MClientThread thread, talks to the service
//
/////////////////////////////////////////////////////////////////
constructor MClientThread.Create(AMaster: TIdTunnelMaster);
begin
MasterParent := AMaster;
FreeOnTerminate := True;
DisconnectedOnRequest := False;
SelfDisconnected := False;
Locker := TCriticalSection.Create;
MasterParent.Clients.Add(self);
AMaster.SetStatistics(NumberOfServicesType, Integer(soIncrease));
inherited Create(True);
end;
destructor MClientThread.Destroy;
var
Header: TIdHeader;
begin
MasterParent.SetStatistics(NumberOfServicesType, Integer(soDecrease));
MasterParent.Clients.Remove(self);
try
if not DisconnectedOnRequest then begin
// service disconnected the thread
try
Header.MsgType := tmDisconnect;
Header.UserId := UserId;
MasterParent.SendMsg(MasterThread, Header, RSTunnelDisconnectMsg);
except
end;
end;
if OutboundClient.Connected then
begin
OutboundClient.Disconnect;
end;
except
end;
MasterThread := nil;
try
OutboundClient.Free;
except
end;
Locker.Free;
Terminate; // dodano
inherited Destroy;
end;
// thread which talks to the service
procedure MClientThread.Execute;
var
s: String;
Header: TIdHeader;
begin
try
while not Terminated do begin
if OutboundClient.Connected then begin
if OutboundClient.IOHandler.Readable(IdTimeoutInfinite) then begin
s := OutboundClient.CurrentReadBuffer;
try
Header.MsgType := tmData;
Header.UserId := UserId;
MasterParent.SendMsg(MasterThread, Header, s);
except
Terminate;
break;
end;
end;
end
else begin
Terminate;
break;
end;
end;
except
;
end;
Locker.Enter;
try
SelfDisconnected := True;
finally
Locker.Leave;
end;
end;
end.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -